Compare commits

..

215 Commits

Author SHA1 Message Date
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
Vaxry
84ab8d11e8 props: bump ver to 0.35.0 2024-02-05 01:59:02 +00:00
Vaxry
60bda7ee3d pluginapi: allow registering hyprctl commands
closes #4616
2024-02-05 01:57:29 +00:00
Vaxry
939696f97e hyprctl: move to a class and unify commands 2024-02-05 01:56:49 +00:00
MightyPlaza
cbadf3e3f3 input: focus window on mouse down on decoration (#4514)
Also unifies vectorToWindow funcs
2024-02-04 15:40:20 +00:00
JManch
1ed4f1cb25 screenshader: rename output uniform to wl_output (#4606)
* screenshader: rename output uniform to monitor

* rename to wl_output
2024-02-04 02:30:00 +00:00
Vaxry
5d4ff60f53 hyprpm: fix invalid pkg-config path env in build
ref #4573
2024-02-03 18:32:59 +00:00
Vaxry
504ebe1b37 box: add missing include 2024-02-03 01:31:52 +00:00
Vaxry
cf1886ca44 renderer: avoid unnecessary gpu resource deletions
fixes #4594
2024-02-02 15:36:13 +00:00
Vaxry
341e04a36c dwindle: avoid sending negative sizes to wlr
fixes #4591
2024-02-02 15:04:04 +00:00
Vaxry
d7514412d8 renderer: reset fb pointers after render pass
fixes #4590
2024-02-02 14:56:04 +00:00
Vaxry
7447be8220 hyprpm: fix crash on add plugin
ref #4563
2024-02-02 01:51:14 +00:00
Vaxry
4644de2269 keybinds: fix ignoremods with release 2024-02-02 01:09:57 +00:00
Vaxry
3656045ad8 hyprpm: install headers locally (#4585)
* hyprpm: install headers locally

* oopsie
2024-02-01 19:38:43 +00:00
Abílio Costa
15316aaa31 subsurfaceTree: Fix nullptr crash when disconnecting a monitor (#4577)
I was able to reproduce this frequently by having a kitty terminal on an
monitor running the following command and then unplugging that monitor:

`while true; do echo "" && sleep 0.02; done`
2024-02-01 03:09:31 +00:00
Vaxry
cfd68af5b6 tearing-control: handle unmapped surfaces for hints
fixes #4570
2024-02-01 00:55:29 +00:00
Roger Roger
4f804d5f96 Makefile: remove hyprland symlink on uninstall 2024-01-31 19:34:16 +02:00
Mihai Fufezan
e6f7724ab0 subprojects: remove wlroots.wrap 2024-01-31 14:04:30 +02:00
Mihai Fufezan
e65f52bf2d Makefile: pass PREFIX to CMake 2024-01-30 22:22:06 +02:00
Vaxry
c51b3fb06f events: ignore sending mouse enter to focused if a constraint is active
fixes #4186
2024-01-30 16:24:41 +00:00
Vaxry
3ff59e7e1d hyprpm: update global state on plugin recompile not header update
ref #4547
2024-01-29 23:37:05 +00:00
Mihai Fufezan
3d0d3b6343 Meson: fix wallpaper installation 2024-01-30 01:28:07 +02:00
Vaxry
2e3f0d5991 renderer: Add new background infrastructure
Adds new backgrounds from the winners of the contest
Rewrites how it works
Allows high color precision PNGs (RGB32F precisely)
Fixes a small bug in renderTextureInternalWithDamage
Nukes misc:force_hypr_chan
2024-01-29 23:11:00 +00:00
Vaxry
91e8c42843 hyprpm: don't update headers if they are up-to-date, only recompile
will not update headers if plugins are compiled for different ones, and instead only compile.

ref #4284
2024-01-29 10:30:31 +00:00
Vaxry
4b4bd90b14 renderer: fixup misaligned fsv1 surfaces with uv
fixes #4548
2024-01-28 23:42:49 +00:00
GrizzlT
7009dc9184 nix: fix overlay composition 2024-01-29 00:27:51 +02:00
Vaxry
b7840c6461 xwayland: remove delta from pos sets in configureX11
ref #4536
2024-01-28 20:13:44 +00:00
Vaxry
5a90911b70 hyprpm: verify headersHashCompiled as well in headersValid()
ref #4547
2024-01-28 20:01:46 +00:00
Epilepsy Gatherings
0e5f14d8d2 xwayland: remove reportedsize set in unmanagedSetGeometry (#4539) 2024-01-28 19:22:02 +00:00
Vaxry
df990c80e2 hyprpm: log verbose return of cmake and meson in update 2024-01-28 03:00:05 +00:00
Vaxry
352574d862 hyprpm: add --force for update
closes #4547
2024-01-28 02:04:35 +00:00
Vaxry
bfcc2adbda monitor: wrap usage of wlr_output_state
for better control and convenience in usage.

fixes #4546
2024-01-28 01:57:13 +00:00
Vaxry
9002657bcc monitor: don't call output_state_finish on buffer-less state clears
ref #4546
2024-01-28 00:41:54 +00:00
Vaxry
3e93fdf779 opengl: use texBox for rendering background texture
fixes #4543
2024-01-28 00:32:54 +00:00
Vaxry
bc7e488a4c monitor: clear output state after usage
fixes massive lag
2024-01-27 19:11:14 +00:00
Mihai Fufezan
8b1069b330 flake.lock: update 2024-01-27 17:31:39 +02:00
vaxerski
61fd75b55e [gha] Nix: update wlroots 2024-01-27 13:59:16 +00:00
Vaxry
7b3d039388 deps: update wlroots
drops requirement for WLR_DRM_NO_ATOMIC provided kernel >= 6.8
2024-01-27 13:58:28 +00:00
rszyma
12d79d6342 dwindle: fix windows being created at incorrect position when cursor is over reserved area (#4520)
* fix: smart_split not working correctly when creating a window with cursor over reserved area

* use getClosestNodeOnWorkspace instead of getFirstNodeOnWorkspace when hovering over reserved area

* optimize `getClosestNodeOnWorkspace`

* remove unused methods
2024-01-26 22:30:36 +00:00
bvr-yr
08e3519747 layout: save float props before setting fs state (#4537)
fixes #4388
2024-01-26 17:24:00 +00:00
Epilepsy Gatherings
5cd7e4587e compositor: don't close special on focus on pinned (#4533) 2024-01-26 12:24:52 +00:00
Vaxry
72987dee88 opengl: rassert false on lost context
we do not have infra to deal with this. It will cause hyprland to freeze rendering, we might as well die.
2024-01-26 02:26:10 +00:00
Vaxry
754eaf5b8b pluginapi: fix hooks with negative rip offsets
fixes #4484
2024-01-24 13:53:18 +00:00
Zach DeCook
df17991b1c input: Allow disabling touchscreen input (#4517)
* enable/disable touch device

* ConfigManager: update documentation of 'enabled'
2024-01-24 00:15:01 +00:00
Vaxry
791e1b96b3 internal: minor header cleanup 2024-01-23 01:32:34 +00:00
vaxerski
02b4a9bded compositor: clarify common errors at launch 2024-01-22 09:46:47 +01:00
Sean McGovern
4d403dac32 build: protocols: require wayland-protocols >= 1.32
The cursor-shape-v1 protocol was not available until this release.
2024-01-20 22:33:12 +02:00
vaxerski
f40e382fc6 crashreporter: skip first possibly cut off line in log tail 2024-01-20 09:16:27 +01:00
vaxerski
b86ed02d8a keybinds: avoid duplicated held keys, only use last, remove all
ref #4471
2024-01-19 19:09:32 +01:00
vaxerski
17339e0ae9 input: track exclusive LSes
ref #4465
2024-01-19 16:45:34 +01:00
vaxerski
5eeec8860e core: improve cleanup logic 2024-01-19 16:20:30 +01:00
Epilepsy Gatherings
9f20a15955 input: remove animate checks on resize limiter (#4480) 2024-01-19 15:45:51 +01:00
vaxerski
c4365f20ed damage: use buffer_damage instead of effective_damage 2024-01-17 16:01:20 +01:00
vaxerski
307dd8f511 input: partially revert #4401
ref #4465
2024-01-17 14:43:38 +01:00
Huy Nguyen
8342bac697 Nix: disable fortify for devshell (#4463)
This disables '_FORTIFY_SOURCE' Werrors trying to compile wlroots.
Long standing issue in https://github.com/NixOS/nixpkgs/issues/60919
afaik.

After this change you should be able to:
```
nix develop
mmeson setup build -Dbuildtype=debug
ninja -C build
```
2024-01-17 14:27:35 +02:00
virchau13
3c964a9fdc keybinds: Add dispatcher for xmonad/qtile-style workspace switching (#4439)
* feat: implement xmonad/qtile-style workspace switching

Implements the focusWorkspaceOnCurrentMonitor dispatcher and function,
which implements XMonad/Qtile-style workspace switching.

When called, focusWorkspaceOnCurrentMonitor will:
1. Send the requested workspace to the current monitor,
2. If the workspace was previously active on a different monitor,
   replace it with the workspace that was previously active on the
   current monitor,
3. Focus the workspace on the current monitor.

* fix: address PR comments
2024-01-15 16:30:46 +01:00
MightyPlaza
f14c5ea5c5 groupbar: separate gradients from title (#4444)
* separate gradients from title logic
modified:   src/config/ConfigManager.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* fix disabled extents
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* fix disabled height
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
2024-01-15 16:17:42 +01:00
fufexan
dcd7a92b01 [gha] Nix: update inputs 2024-01-15 00:03:29 +00:00
Isaac Myhal
b6516bad02 config: Add border gradients to windowrulev2 (#4335)
* Add border gradients to windowrulev2

* windowrule border gradient: Use CVarList to parse

* windowrule border gradient: No {} around short ifs
2024-01-14 18:27:32 +01:00
dranull
13d9a637d6 hyprctl: screen_shader config fixes (#4102)
* Allow "/" in values of requests

* Don't tick on empty value
2024-01-14 18:12:52 +01:00
1over137
4cee94b91c fractional: Set preferred scale on monitor config reload (#4406) 2024-01-14 14:56:35 +01:00
Zach DeCook
c4da4b026d layershell: Fix greedy mouse grab from keyboard_interactive layer (#4401)
* Layer: Don't allow a keyboard-layer to steal focus from other layers

* Input: Don't change keyboard focus on click if focus is locked
2024-01-12 15:43:16 +01:00
scorpion-26
babb9c07b0 swipe: Prevent hiding current workspace when swiping (#4417)
When workspace_swipe_use_r is enabled, swiping from WS 1 to a non-empty WS 2 would
hide WS 1 (Similar effect to issue #4076). This is caused by a faulty
check which doesn't consider, that workspaceIDLeft could be the current
workspace.
This bug is only a problem for r, because m wraps around on WS 1 m-1, whereas r stays on WS 1.
2024-01-11 19:22:40 +01:00
vaxerski
6b92144f15 surface: avoid spam of window surfaces with scale and transform events
fixes #4408
2024-01-11 14:07:28 +01:00
Clyybber
8d31c84483 layout: Round window pos and size on togglefloating (#4407)
Also restore the behaviour introduced in bc4a51dbbb
2024-01-10 18:08:58 +01:00
vaxerski
d484506600 keybinds: fix tracking of sent key states 2024-01-10 18:06:38 +01:00
vaxerski
b240704bee renderer: allow rendering multiple fullscreen windows in third fs pass
something might be fading out, sliding out, etc. We handle it before, why not use it?

fixes #4076
2024-01-09 20:42:07 +01:00
vaxerski
71166ef40b subsurfaceTree: update surface tree protocol feedback on map 2024-01-09 18:14:08 +01:00
vaxerski
252aaaecfa input: add special_fallthrough
fixes #4323
2024-01-09 13:17:55 +01:00
vaxerski
f92a86af53 renderer: ignore box offsets for fullscreen windows 2024-01-08 19:58:15 +01:00
MightyPlaza
2ba2c8aeee groupbar: improve gradient handling (#4390)
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
2024-01-08 19:38:22 +01:00
Piroro-hs
955009655d cmake: Propagate NO_XWAYLAND to wlroots building setup (#4385) 2024-01-08 19:24:52 +01:00
vaxerski
d7d333d162 opengl: apply box rot to projections 2024-01-07 18:51:08 +01:00
vaxerski
f5b2fd2bc3 opengl: add renderdata.forceIntrospection 2024-01-07 18:37:02 +01:00
vaxerski
44ee9915e3 renderer: overhaul renderModifData 2024-01-07 18:35:44 +01:00
vaxerski
9f2bde925b hyprpm: handle failed compilations gracefully 2024-01-07 18:15:51 +01:00
vaxerski
7904188de9 input: allow focusSurface when locked if surfase is sessionLock 2024-01-07 14:04:32 +01:00
Epilepsy Gatherings
666ee61c13 input: leave special on focus (#4358) 2024-01-07 12:06:33 +01:00
Jan Beich
7e033e48ac make: unbreak with non-GNU ln(1) after 78f9ba9fdd
ln -s -r -f /usr/local/bin/Hyprland /usr/local/bin/hyprland
ln: illegal option -- r
usage: ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file [target_file]
       ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file ... target_dir
       link source_file target_file
*** Error code 1
2024-01-05 19:22:43 +02:00
Naksu
d8dbdc4a01 main: Fix typo in std::cerr (#4359) 2024-01-05 12:45:49 +01:00
vaxerski
d3acf8da3b CI: don't close stale issues 2024-01-05 12:40:18 +01:00
Mihai Fufezan
aeeeace102 flake.lock: update 2024-01-04 22:52:03 +02:00
thejch
880996b053 master: Add more null checks for rollnext (#4343)
* add more null check for rollnext

* remove pwindow check
2024-01-04 16:17:17 +01:00
rszyma
4d6d662c67 Makefile: force ln command to overwrite symlink (#4347)
When running `make install` twice ln shows an error:
```
ln -s -r /usr/local/bin/Hyprland /usr/local/bin/hyprland
ln: failed to create symbolic link '/usr/local/bin/hyprland': File exists
```
2024-01-04 10:20:17 +01:00
vaxerski
1512b81126 master: guard PNODE in roll*
fixes #4331
2024-01-02 22:18:38 +01:00
flicko
4f26c4e1eb config: variables update their value when set again (#4263)
* variables update their value when set again

* only sort if new variable is found

* clang-format
2024-01-02 16:38:30 +01:00
dranull
3c33d4b9dd keybinds: Refocus only if the silently moved window had the focus (#4328) 2024-01-02 14:50:30 +01:00
vaxerski
bd3ea8dcb5 examples: remove example plugin
closes #4329
2024-01-02 14:25:18 +01:00
vaxerski
813af393f1 layout: update rules before applying fullscreen nodes in layouts 2024-01-02 14:21:36 +01:00
dranull
583b05a8c6 groupbar: Drag single window instead of destroying group (#4327) 2024-01-02 13:37:03 +01:00
Zach DeCook
1607e96704 HookSystem: rename PAGESIZE_VAR from PAGESIZE to avoid conflict (#4321) 2024-01-01 23:05:26 +01:00
q234rty
1a4f23eb2f renderer: Only force nearest neighbor when the sizes are off by one or two (#4325)
Fixes rendering issues in arch's extra/telegram-desktop
2024-01-01 20:20:27 +01:00
bvr-yr
42ab06e7c8 meson: fix wlroots patch (#4324) 2024-01-01 19:58:01 +01:00
vaxerski
46753b1f22 CI: limit stalebot ops per run 2024-01-01 18:37:49 +01:00
Vaxry
d4e68ab602 CI: allow manual stale execution 2024-01-01 18:34:15 +01:00
rszyma
37b76cd1ca keybinds: fix keys getting stuck + minor refactor & optimizations to keybind handling (#4304) 2024-01-01 18:29:51 +01:00
vaxerski
0be36cd02d cmakelists: fix wlroots patch sed 2024-01-01 18:29:10 +01:00
Vaxry
4e0e8d933e CI: add stalebot 2024-01-01 18:26:48 +01:00
vaxerski
c7ba460687 wlroots: update version patches 2024-01-01 18:19:22 +01:00
vaxerski
3a189c265d issue templates: make versions spoiler'd 2024-01-01 18:05:49 +01:00
vaxerski
069880e374 hyprctl: add systeminfo 2024-01-01 17:53:03 +01:00
vaxerski
fa5e812304 [gha] Nix: update wlroots 2024-01-01 15:48:37 +00:00
vaxerski
33444e1e5e deps: update wlroots 2024-01-01 16:47:54 +01:00
125 changed files with 4975 additions and 4228 deletions

View File

@@ -9,12 +9,23 @@ body:
---
- type: input
- type: textarea
id: ver
attributes:
label: Hyprland Version
description: "Paste here the output of `hyprctl version`."
placeholder: Hyprland, built from branch main at commit...
description: "Paste here the output of `hyprctl version`. For hyprland after 0.34.0, paste `hyprctl systeminfo` instead."
value: "<details>
<summary>System/Version info</summary>
```sh
<Paste the output of the command here>
```
</details>"
validations:
required: true

View File

@@ -23,6 +23,7 @@ runs:
glm \
glslang \
go \
hyprlang \
jq \
libc++ \
libdisplay-info \

28
.github/workflows/stale.yml vendored Normal file
View File

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

2
.gitignore vendored
View File

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

View File

@@ -57,8 +57,8 @@ ExternalProject_Add(
wlroots
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
PATCH_COMMAND sed -E -i -e "s/(soversion = 13)([^032]|$$)/soversion = 13032/g" meson.build
CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> --reconfigure
PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build
CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$<IF:$<BOOL:${NO_XWAYLAND}>,disabled,enabled> -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none>
BUILD_COMMAND ninja -C build
BUILD_ALWAYS true
BUILD_IN_SOURCE true
@@ -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) # we do not check for wlroots, as we provide it ourselves
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")

View File

@@ -1,22 +1,22 @@
PREFIX = /usr/local
legacyrenderer:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
legacyrendererdebug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
release:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
debug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -S . -B ./build -G Ninja
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
@@ -42,10 +42,10 @@ install:
chmod 755 ${PREFIX}/bin/Hyprland
chmod 755 ${PREFIX}/bin/hyprctl
chmod 755 ${PREFIX}/bin/hyprpm
ln -s -r ${PREFIX}/bin/Hyprland ${PREFIX}/bin/hyprland
cd ${PREFIX}/bin && ln -sf Hyprland hyprland
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
mkdir -p ${PREFIX}/share/hyprland
cp ./assets/wall_* ${PREFIX}/share/hyprland
cp ./assets/wall* ${PREFIX}/share/hyprland
mkdir -p ${PREFIX}/share/xdg-desktop-portal
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
@@ -60,6 +60,7 @@ install:
uninstall:
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
rm -f ${PREFIX}/bin/Hyprland
rm -f ${PREFIX}/bin/hyprland
rm -f ${PREFIX}/bin/hyprctl
rm -f ${PREFIX}/bin/hyprpm
rm -f ${PREFIX}/lib/libwlroots.so.13032

View File

@@ -1,9 +1,7 @@
wallpaper_types = ['', 'anime_', 'anime2_']
wallpapers = ['0', '1', '2']
foreach type : wallpaper_types
foreach size : [2, 4, 8]
install_data(f'wall_@type@@size@K.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
endforeach
foreach type : wallpapers
install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
endforeach
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')

BIN
assets/wall0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

BIN
assets/wall1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

BIN
assets/wall2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 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

@@ -1,8 +0,0 @@
# compile with HYPRLAND_HEADERS=<path_to_hl> make all
# make sure that the path above is to the root hl repo directory, NOT src/
# and that you have ran `make protocols` in the hl dir.
all:
$(CXX) -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g `pkg-config --cflags pixman-1 libdrm hyprland` -std=c++2b
clean:
rm ./examplePlugin.so

View File

@@ -1,74 +0,0 @@
#include "customDecoration.hpp"
#include <hyprland/src/Window.hpp>
#include <hyprland/src/Compositor.hpp>
#include "globals.hpp"
CCustomDecoration::CCustomDecoration(CWindow* pWindow) {
m_pWindow = pWindow;
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
m_vLastWindowSize = pWindow->m_vRealSize.vec();
}
CCustomDecoration::~CCustomDecoration() {
damageEntire();
}
SWindowDecorationExtents CCustomDecoration::getWindowDecorationExtents() {
return m_seExtents;
}
void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
if (!g_pCompositor->windowValidMapped(m_pWindow))
return;
if (!m_pWindow->m_sSpecialRenderData.decorate)
return;
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color")->intValue;
static auto* const PROUNDING = &HyprlandAPI::getConfigValue(PHANDLE, "decoration:rounding")->intValue;
static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ?
0 :
(m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
// draw the border
CBox fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE),
(int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
fullBox.x -= pMonitor->vecPosition.x;
fullBox.y -= pMonitor->vecPosition.y;
m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2},
{fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2,
fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}};
fullBox.x += offset.x;
fullBox.y += offset.y;
if (fullBox.width < 1 || fullBox.height < 1)
return; // don't draw invisible shadows
g_pHyprOpenGL->scissor((CBox*)nullptr);
fullBox.scale(pMonitor->scale);
g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
}
eDecorationType CCustomDecoration::getDecorationType() {
return DECORATION_CUSTOM;
}
void CCustomDecoration::updateWindow(CWindow* pWindow) {
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
m_vLastWindowSize = pWindow->m_vRealSize.vec();
damageEntire();
}
void CCustomDecoration::damageEntire() {
CBox dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y),
(int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
g_pHyprRenderer->damageBox(&dm);
}

View File

@@ -1,29 +0,0 @@
#pragma once
#define WLR_USE_UNSTABLE
#include <hyprland/src/render/decorations/IHyprWindowDecoration.hpp>
class CCustomDecoration : public IHyprWindowDecoration {
public:
CCustomDecoration(CWindow*);
virtual ~CCustomDecoration();
virtual SWindowDecorationExtents getWindowDecorationExtents();
virtual void draw(CMonitor*, float a, const Vector2D& offset);
virtual eDecorationType getDecorationType();
virtual void updateWindow(CWindow*);
virtual void damageEntire();
private:
SWindowDecorationExtents m_seExtents;
CWindow* m_pWindow = nullptr;
Vector2D m_vLastWindowPos;
Vector2D m_vLastWindowSize;
};

View File

@@ -1,80 +0,0 @@
#include "customLayout.hpp"
#include <hyprland/src/Compositor.hpp>
#include "globals.hpp"
void CHyprCustomLayout::onWindowCreatedTiling(CWindow* pWindow) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto SIZE = PMONITOR->vecSize;
// these are used for focus and move calculations, and are *required* to touch for moving focus to work properly.
pWindow->m_vPosition = Vector2D{(SIZE.x / 2.0) * (m_vWindowData.size() % 2), (SIZE.y / 2.0) * (int)(m_vWindowData.size() > 1)};
pWindow->m_vSize = SIZE / 2.0;
// this is the actual pos and size of the window (where it's rendered)
pWindow->m_vRealPosition = pWindow->m_vPosition + Vector2D{10, 10};
pWindow->m_vRealSize = pWindow->m_vSize - Vector2D{20, 20};
const auto PDATA = &m_vWindowData.emplace_back();
PDATA->pWindow = pWindow;
}
void CHyprCustomLayout::onWindowRemovedTiling(CWindow* pWindow) {
std::erase_if(m_vWindowData, [&](const auto& other) { return other.pWindow == pWindow; });
}
bool CHyprCustomLayout::isWindowTiled(CWindow* pWindow) {
return std::find_if(m_vWindowData.begin(), m_vWindowData.end(), [&](const auto& other) { return other.pWindow == pWindow; }) != m_vWindowData.end();
}
void CHyprCustomLayout::recalculateMonitor(const int& eIdleInhibitMode) {
; // empty
}
void CHyprCustomLayout::recalculateWindow(CWindow* pWindow) {
; // empty
}
void CHyprCustomLayout::resizeActiveWindow(const Vector2D& delta, CWindow* pWindow) {
; // empty
}
void CHyprCustomLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mode, bool on) {
; // empty
}
std::any CHyprCustomLayout::layoutMessage(SLayoutMessageHeader header, std::string content) {
return "";
}
SWindowRenderLayoutHints CHyprCustomLayout::requestRenderHints(CWindow* pWindow) {
return {};
}
void CHyprCustomLayout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
; // empty
}
void CHyprCustomLayout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
; // empty
}
std::string CHyprCustomLayout::getLayoutName() {
return "custom";
}
void CHyprCustomLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
; // empty
}
void CHyprCustomLayout::onEnable() {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || w->m_bIsFloating)
continue;
onWindowCreatedTiling(w.get());
}
}
void CHyprCustomLayout::onDisable() {
m_vWindowData.clear();
}

View File

@@ -1,32 +0,0 @@
#pragma once
#define WLR_USE_UNSTABLE
#include <hyprland/src/layout/IHyprLayout.hpp>
struct SWindowData {
CWindow* pWindow = nullptr;
};
class CHyprCustomLayout : public IHyprLayout {
public:
virtual void onWindowCreatedTiling(CWindow*);
virtual void onWindowRemovedTiling(CWindow*);
virtual bool isWindowTiled(CWindow*);
virtual void recalculateMonitor(const int&);
virtual void recalculateWindow(CWindow*);
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
virtual void switchWindows(CWindow*, CWindow*);
virtual void alterSplitRatio(CWindow*, float, bool);
virtual std::string getLayoutName();
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
virtual void onEnable();
virtual void onDisable();
private:
std::vector<SWindowData> m_vWindowData;
};

View File

@@ -1,5 +0,0 @@
#pragma once
#include <hyprland/src/plugins/PluginAPI.hpp>
inline HANDLE PHANDLE = nullptr;

View File

@@ -1,99 +0,0 @@
#define WLR_USE_UNSTABLE
#include "globals.hpp"
#include <hyprland/src/Window.hpp>
#include <hyprland/src/Compositor.hpp>
#include "customLayout.hpp"
#include "customDecoration.hpp"
#include <unistd.h>
#include <thread>
// Methods
inline std::unique_ptr<CHyprCustomLayout> g_pCustomLayout;
inline CFunctionHook* g_pFocusHook = nullptr;
inline CFunctionHook* g_pMotionHook = nullptr;
inline CFunctionHook* g_pMouseDownHook = nullptr;
typedef void (*origFocusWindow)(void*, CWindow*, wlr_surface*);
typedef void (*origMotion)(wlr_seat*, uint32_t, double, double);
typedef void (*origMouseDownNormal)(void*, wlr_pointer_button_event*);
// Do NOT change this function.
APICALL EXPORT std::string PLUGIN_API_VERSION() {
return HYPRLAND_API_VERSION;
}
static void onActiveWindowChange(void* self, std::any data) {
try {
auto* const PWINDOW = std::any_cast<CWindow*>(data);
HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: " + (PWINDOW ? PWINDOW->m_szTitle : "None"), CColor{0.f, 0.5f, 1.f, 1.f}, 5000);
} catch (std::bad_any_cast& e) { HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: None", CColor{0.f, 0.5f, 1.f, 1.f}, 5000); }
}
static void onNewWindow(void* self, std::any data) {
auto* const PWINDOW = std::any_cast<CWindow*>(data);
HyprlandAPI::addWindowDecoration(PHANDLE, PWINDOW, new CCustomDecoration(PWINDOW));
}
void hkFocusWindow(void* thisptr, CWindow* pWindow, wlr_surface* pSurface) {
// HyprlandAPI::addNotification(PHANDLE, getFormat("FocusWindow with %lx %lx", pWindow, pSurface), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
(*(origFocusWindow)g_pFocusHook->m_pOriginal)(thisptr, pWindow, pSurface);
}
void hkNotifyMotion(wlr_seat* wlr_seat, uint32_t time_msec, double sx, double sy) {
// HyprlandAPI::addNotification(PHANDLE, getFormat("NotifyMotion with %lf %lf", sx, sy), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
(*(origMotion)g_pMotionHook->m_pOriginal)(wlr_seat, time_msec, sx, sy);
}
void hkProcessMouseDownNormal(void* thisptr, wlr_pointer_button_event* e) {
// HyprlandAPI::addNotification(PHANDLE, "Mouse down normal!", CColor{0.8f, 0.2f, 0.5f, 1.0f}, 5000);
(*(origMouseDownNormal)g_pMouseDownHook->m_pOriginal)(thisptr, e);
}
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
PHANDLE = handle;
HyprlandAPI::addNotification(PHANDLE, "Hello World from an example plugin!", CColor{0.f, 1.f, 1.f, 1.f}, 5000);
HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, SCallbackInfo& info, std::any data) { onActiveWindowChange(self, data); });
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, SCallbackInfo& info, std::any data) { onNewWindow(self, data); });
g_pCustomLayout = std::make_unique<CHyprCustomLayout>();
HyprlandAPI::addLayout(PHANDLE, "custom", g_pCustomLayout.get());
HyprlandAPI::addConfigValue(PHANDLE, "plugin:example:border_color", SConfigValue{.intValue = configStringToInt("rgb(44ee44)")});
HyprlandAPI::addDispatcher(PHANDLE, "example", [](std::string arg) { HyprlandAPI::addNotification(PHANDLE, "Arg passed: " + arg, CColor{0.5f, 0.5f, 0.7f, 1.0f}, 5000); });
// Hook a public member
g_pFocusHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CCompositor::focusWindow, (void*)&hkFocusWindow);
// Hook a public non-member
g_pMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion);
// Hook a private member
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "processMouseDownNormal");
g_pMouseDownHook = HyprlandAPI::createFunctionHook(PHANDLE, METHODS[0].address, (void*)&hkProcessMouseDownNormal);
static auto* const PBORDERCOLOR = HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color");
// fancy notifications
HyprlandAPI::addNotificationV2(
PHANDLE,
{{"text", "Example hint, color " + std::to_string(PBORDERCOLOR->intValue)}, {"time", (uint64_t)10000}, {"color", CColor{PBORDERCOLOR->intValue}}, {"icon", ICON_HINT}});
// Enable our hooks
g_pFocusHook->hook();
g_pMotionHook->hook();
g_pMouseDownHook->hook();
HyprlandAPI::reloadConfig();
return {"ExamplePlugin", "An example plugin", "Vaxry", "1.0"};
}
APICALL EXPORT void PLUGIN_EXIT() {
HyprlandAPI::invokeHyprctlCommand("seterror", "disable");
}

View File

@@ -112,12 +112,13 @@ gestures {
misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
}
# 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

47
flake.lock generated
View File

@@ -23,13 +23,36 @@
"type": "github"
}
},
"hyprlang": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1708787654,
"narHash": "sha256-7ACgM3ZuAhPqurXHUvR2nWMRcnmzGGPjLK6q4DSTelI=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "0fce791ba2334aca183f2ed42399518947550d0d",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprlang",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1703438236,
"narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
"lastModified": 1708807242,
"narHash": "sha256-sRTRkhMD4delO/hPxxi+XwLqPn8BuUq6nnj4JqLwOu0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
"rev": "73de017ef2d18a04ac4bfd0c02650007ccb31c2a",
"type": "github"
},
"original": {
@@ -42,6 +65,7 @@
"root": {
"inputs": {
"hyprland-protocols": "hyprland-protocols",
"hyprlang": "hyprlang",
"nixpkgs": "nixpkgs",
"systems": "systems",
"wlroots": "wlroots",
@@ -67,18 +91,18 @@
"flake": false,
"locked": {
"host": "gitlab.freedesktop.org",
"lastModified": 1701368958,
"narHash": "sha256-7kvyoA91etzVEl9mkA/EJfB6z/PltxX7Xc4gcr7/xlo=",
"lastModified": 1708558866,
"narHash": "sha256-Mz6hCtommq7RQfcPnxLINigO4RYSNt23HeJHC6mVmWI=",
"owner": "wlroots",
"repo": "wlroots",
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
"rev": "0cb091f1a2d345f37d2ee445f4ffd04f7f4ec9e5",
"type": "gitlab"
},
"original": {
"host": "gitlab.freedesktop.org",
"owner": "wlroots",
"repo": "wlroots",
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
"rev": "0cb091f1a2d345f37d2ee445f4ffd04f7f4ec9e5",
"type": "gitlab"
}
},
@@ -87,6 +111,9 @@
"hyprland-protocols": [
"hyprland-protocols"
],
"hyprlang": [
"hyprlang"
],
"nixpkgs": [
"nixpkgs"
],
@@ -95,11 +122,11 @@
]
},
"locked": {
"lastModified": 1703514399,
"narHash": "sha256-VRr5Xc4S/VPr/gU3fiOD3vSIL2+GJ+LUrmFTWTwnTz4=",
"lastModified": 1708696469,
"narHash": "sha256-shh5wmpeYy3MmsBfkm4f76yPsBDGk6OLYRVG+ARy2F0=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "0a318a7a217a6402b0b705837cd5b50b0e94b31b",
"rev": "1b713911c2f12b96c2574474686e4027ac4bf826",
"type": "github"
},
"original": {

View File

@@ -12,7 +12,7 @@
host = "gitlab.freedesktop.org";
owner = "wlroots";
repo = "wlroots";
rev = "5d639394f3e83b01596dcd166a44a9a1a2583350";
rev = "0cb091f1a2d345f37d2ee445f4ffd04f7f4ec9e5";
flake = false;
};
@@ -22,11 +22,18 @@
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";
};
};
@@ -86,6 +93,7 @@
name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
buildInputs = [self.packages.${system}.wlroots-hyprland];
hardeningDisable = ["fortify"];
inputsFrom = [
self.packages.${system}.wlroots-hyprland
self.packages.${system}.hyprland

View File

@@ -51,12 +51,14 @@ commands:
setprop
splash
switchxkblayout
systeminfo
version
workspacerules
workspaces
flags:
-j -> output in JSON
-r -> refresh state after issuing command (e.g. for updating variables)
--batch -> execute a batch of commands, separated by ';'
--instance (-i) -> use a specific instance. Can be either signature or index in hyprctl instances (0, 1, etc)
)#";
@@ -77,7 +79,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
@@ -85,7 +87,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);
data->time = std::stoull(data->id.substr(data->id.find_first_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());
@@ -93,7 +97,9 @@ std::vector<SInstanceData> instances() {
int i = 0;
for (std::string line; std::getline(ifs, line); ++i) {
if (i == 0) {
data->pid = std::stoull(line);
try {
data->pid = std::stoull(line);
} catch (std::exception& e) { continue; }
} else if (i == 1) {
data->wlSocket = line;
} else
@@ -300,6 +306,8 @@ 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] == "--batch") {
fullRequest = "--batch ";
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
@@ -359,7 +367,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,42 +378,8 @@ int main(int argc, char** argv) {
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("/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);
else if (fullRequest.contains("/hyprpaper"))
requestHyprpaper(fullRequest);
else if (fullRequest.contains("/switchxkblayout"))
request(fullRequest, 2);
else if (fullRequest.contains("/seterror"))
@@ -426,15 +400,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

@@ -20,11 +20,18 @@ std::string DataState::getDataStatePath() {
return std::string{HOME} + "/.local/share/hyprpm";
}
std::string DataState::getHeadersPath() {
return getDataStatePath() + "/headersRoot";
}
void DataState::ensureStateStoreExists() {
const auto PATH = getDataStatePath();
if (!std::filesystem::exists(PATH))
std::filesystem::create_directories(PATH);
if (!std::filesystem::exists(getHeadersPath()))
std::filesystem::create_directories(getHeadersPath());
}
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
@@ -47,7 +54,8 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
DATA.emplace(p.name, toml::table{
{"filename", p.name + ".so"},
{"enabled", p.enabled}
{"enabled", p.enabled},
{"failed", p.failed}
});
}
// clang-format on
@@ -63,7 +71,10 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
const auto PATH = getDataStatePath();
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
if (!entry.is_directory())
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@@ -84,7 +95,10 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
const auto PATH = getDataStatePath();
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
if (!entry.is_directory())
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@@ -153,7 +167,10 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
std::vector<SPluginRepository> repos;
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
if (!entry.is_directory())
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@@ -172,9 +189,10 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
continue;
const auto ENABLED = STATE[key]["enabled"].value_or(false);
const auto FAILED = STATE[key]["failed"].value_or(false);
const auto FILENAME = STATE[key]["filename"].value_or("");
repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED});
repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED, FAILED});
}
repos.push_back(repo);
@@ -189,7 +207,10 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
const auto PATH = getDataStatePath();
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
if (!entry.is_directory())
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@@ -201,6 +222,11 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
if (key.str() != name)
continue;
const auto FAILED = STATE[key]["failed"].value_or(false);
if (FAILED)
return false;
(*STATE[key].as_table()).insert_or_assign("enabled", enabled);
std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);

View File

@@ -10,6 +10,7 @@ struct SGlobalState {
namespace DataState {
std::string getDataStatePath();
std::string getHeadersPath();
void ensureStateStoreExists();
void addNewPluginRepo(const SPluginRepository& repo);
void removePluginRepo(const std::string& urlOrName);

View File

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

View File

@@ -6,7 +6,8 @@
struct SPlugin {
std::string name;
std::string filename;
bool enabled;
bool enabled = false;
bool failed = false;
};
struct SPluginRepository {

View File

@@ -10,6 +10,7 @@
#include <thread>
#include <fstream>
#include <algorithm>
#include <format>
#include <toml++/toml.hpp>
@@ -78,6 +79,8 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
bool CPluginManager::addNewPluginRepo(const std::string& url) {
const auto HLVER = getHyprlandVersion();
if (DataState::pluginRepoExists(url)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
return false;
@@ -170,6 +173,22 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
message += " version " + pl.version;
progress.printMessageAbove(message);
}
if (!pManifest->m_sRepository.commitPins.empty()) {
// check commit pins
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash)
continue;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
execAndGet("cd /tmp/hyprpm/new/ && git reset --hard --recurse-submodules " + plugin);
}
}
progress.m_szCurrentMessage = "Verifying headers";
progress.print();
@@ -191,16 +210,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) {
out += execAndGet("cd /tmp/hyprpm/new && " + bs) + "\n";
std::string cmd = std::format("cd /tmp/hyprpm/new && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
}
if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Plugin " << p.name << " failed to build.\n";
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";
return false;
p.failed = true;
continue;
}
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output);
@@ -220,7 +242,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
repo.url = url;
repo.hash = repohash;
for (auto& p : pManifest->m_vPlugins) {
repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false});
repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false, p.failed});
}
DataState::addNewPluginRepo(repo);
@@ -263,8 +285,12 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
eHeadersErrors CPluginManager::headersValid() {
const auto HLVER = getHyprlandVersion();
if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc"))
return HEADERS_MISSING;
// find headers commit
auto headers = execAndGet("pkg-config --cflags --keep-system-cflags hyprland");
std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkg-config --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
auto headers = execAndGet(cmd.c_str());
if (!headers.contains("-I/"))
return HEADERS_MISSING;
@@ -296,10 +322,6 @@ eHeadersErrors CPluginManager::headersValid() {
if (!ifs.good())
return HEADERS_CORRUPTED;
if ((std::filesystem::exists("/usr/include/hyprland/src/version.h") && verHeader != "/usr/include/hyprland/src/version.h") ||
(std::filesystem::exists("/usr/local/include/hyprland/src/version.h") && verHeader != "/usr/local/include/hyprland/src/version.h"))
return HEADERS_DUPLICATED;
std::string verHeaderContent((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
ifs.close();
@@ -314,7 +336,9 @@ eHeadersErrors CPluginManager::headersValid() {
return HEADERS_OK;
}
bool CPluginManager::updateHeaders() {
bool CPluginManager::updateHeaders(bool force) {
DataState::ensureStateStoreExists();
const auto HLVER = getHyprlandVersion();
@@ -323,11 +347,8 @@ bool CPluginManager::updateHeaders() {
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
}
if (headersValid() == HEADERS_OK) {
std::cout << "\n" << std::string{Colors::GREEN} + "" + Colors::RESET + " Your headers are already up-to-date.\n";
auto GLOBALSTATE = DataState::getGlobalState();
GLOBALSTATE.headersHashCompiled = HLVER.hash;
DataState::updateGlobalState(GLOBALSTATE);
if (!force && headersValid() == HEADERS_OK) {
std::cout << "\n" << std::string{Colors::GREEN} + "" + Colors::RESET + " Headers up to date.\n";
return true;
}
@@ -369,23 +390,38 @@ bool CPluginManager::updateHeaders() {
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland");
ret = execAndGet("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja");
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath());
ret = execAndGet(
std::format("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja",
DataState::getHeadersPath()));
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
// le hack. Wlroots has to generate its build/include
ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots && meson setup -Drenderers=gles2 -Dexamples=false build");
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland");
progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources";
progress.print();
progress.printMessageAbove(
std::string{Colors::YELLOW} + "!" + Colors::RESET +
" in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
// progress.printMessageAbove(
// std::string{Colors::YELLOW} + "!" + Colors::RESET +
// " in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
ret = execAndGet("pkexec sh \"-c\" \"cd /tmp/hyprpm/hyprland && make installheaders\"");
std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" /tmp/hyprpm/hyprland/Makefile && cd /tmp/hyprpm/hyprland && make installheaders",
DataState::getHeadersPath());
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd);
ret = execAndGet(cmd);
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "pkexec returned: " << ret << "\n";
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n";
// remove build files
std::filesystem::remove_all("/tmp/hyprpm/hyprland");
@@ -397,10 +433,6 @@ bool CPluginManager::updateHeaders() {
progress.m_szCurrentMessage = "Done!";
progress.print();
auto GLOBALSTATE = DataState::getGlobalState();
GLOBALSTATE.headersHashCompiled = HLVER.hash;
DataState::updateGlobalState(GLOBALSTATE);
std::cout << "\n";
} else {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID));
@@ -434,7 +466,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
const auto HLVER = getHyprlandVersion();
CProgressBar progress;
progress.m_iMaxSteps = REPOS.size() * 2 + 1;
progress.m_iMaxSteps = REPOS.size() * 2 + 2;
progress.m_iSteps = 0;
progress.m_szCurrentMessage = "Updating repositories";
progress.print();
@@ -528,7 +560,8 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) {
out += execAndGet("cd /tmp/hyprpm/update && " + bs) + "\n";
std::string cmd = std::format("cd /tmp/hyprpm/update && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
}
if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) {
@@ -566,6 +599,14 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " updated " + repo.name);
}
progress.m_iSteps++;
progress.m_szCurrentMessage = "Updating global state...";
progress.print();
auto GLOBALSTATE = DataState::getGlobalState();
GLOBALSTATE.headersHashCompiled = HLVER.hash;
DataState::updateGlobalState(GLOBALSTATE);
progress.m_iSteps++;
progress.m_szCurrentMessage = "Done!";
progress.print();
@@ -696,8 +737,13 @@ void CPluginManager::listAllPlugins() {
std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n";
for (auto& p : r.plugins) {
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name + "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false")
<< Colors::RESET << "\n";
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
if (!p.failed)
std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n";
else
std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n";
}
}
}

View File

@@ -40,7 +40,7 @@ class CPluginManager {
bool removePluginRepo(const std::string& urlOrName);
eHeadersErrors headersValid();
bool updateHeaders();
bool updateHeaders(bool force = false);
bool updatePlugins(bool forceUpdateAll);
void listAllPlugins();

View File

@@ -1,6 +1,7 @@
#include "progress/CProgressBar.hpp"
#include "helpers/Colors.hpp"
#include "core/PluginManager.hpp"
#include "core/DataState.hpp"
#include <iostream>
#include <vector>
@@ -23,6 +24,7 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
--notify | -n Send a hyprland notification for important events (e.g. load fail)
--help | -h Show this menu
--verbose | -v Enable too much logging
--force | -f Force an operation ignoring checks (e.g. update -f)
)#";
@@ -38,7 +40,7 @@ int main(int argc, char** argv, char** envp) {
}
std::vector<std::string> command;
bool notify = false, verbose = false;
bool notify = false, verbose = false, force = false;
for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) {
@@ -49,6 +51,9 @@ int main(int argc, char** argv, char** envp) {
notify = true;
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
verbose = true;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true;
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
} else {
std::cerr << "Unrecognized option " << ARGS[i];
return 1;
@@ -82,9 +87,13 @@ int main(int argc, char** argv, char** envp) {
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
} else if (command[0] == "update") {
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
bool headers = g_pPluginManager->updateHeaders();
bool headers = g_pPluginManager->updateHeaders(force);
if (headers) {
bool ret1 = g_pPluginManager->updatePlugins(!headersValid);
const auto HLVER = g_pPluginManager->getHyprlandVersion();
auto GLOBALSTATE = DataState::getGlobalState();
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
bool ret1 = g_pPluginManager->updatePlugins(!headersValid || force || COMPILEDOUTDATED);
if (!ret1)
return 1;

View File

@@ -9,6 +9,7 @@
cairo,
git,
hyprland-protocols,
hyprlang,
jq,
libGL,
libdrm,
@@ -75,6 +76,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
cairo
git
hyprland-protocols
hyprlang
libdrm
libGL
libinput

View File

@@ -10,21 +10,19 @@
(builtins.substring 4 2 longDate)
(builtins.substring 6 2 longDate)
]);
mkJoinedOverlays = overlays: final: prev:
lib.foldl' (attrs: overlay: attrs // (overlay final prev)) {} overlays;
in {
# Contains what a user is most likely to care about:
# Hyprland itself, XDPH and the Share Picker.
default = mkJoinedOverlays (with self.overlays; [
default = lib.composeManyExtensions (with self.overlays; [
hyprland-packages
hyprland-extras
]);
# Packages for variations of Hyprland, dependencies included.
hyprland-packages = mkJoinedOverlays [
hyprland-packages = lib.composeManyExtensions [
# Dependencies
inputs.hyprland-protocols.overlays.default
inputs.hyprlang.overlays.default
self.overlays.wlroots-hyprland
self.overlays.udis86
# Hyprland packages themselves
@@ -34,9 +32,9 @@ in {
hyprland = final.callPackage ./default.nix {
stdenv = final.gcc13Stdenv;
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
wlroots = final.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;};
@@ -59,12 +57,12 @@ in {
# Packages for extra software recommended for usage with Hyprland,
# including forked or patched packages for compatibility.
hyprland-extras = mkJoinedOverlays [
hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.xdg-desktop-portal-hyprland
];
udis86 = final: prev: {
udis86 = final.callPackage ./udis86.nix {};
udis86-hyprland = final.callPackage ./udis86.nix {};
};
# Patched version of wlroots for Hyprland.

View File

@@ -34,16 +34,17 @@ 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,17 +9,17 @@ executable('Hyprland', src,
server_protos,
dependency('wayland-server'),
dependency('wayland-client'),
- wlroots.get_variable('wlroots'),
+ dependency('wlroots'),
dependency('cairo'),
dependency('hyprlang', version: '>= 0.3.2'),
dependency('libdrm'),
dependency('egl'),
dependency('xkbcommon'),

View File

@@ -8,7 +8,7 @@ CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }')
if [ "$SUB_REV" != "$CRT_REV" ]; then
echo "Updating wlroots..."
# update wlroots to submodule revision
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix subprojects/wlroots.wrap
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix
nix flake lock
echo "wlroots: $CRT_REV -> $SUB_REV"

View File

@@ -1,3 +1,3 @@
{
"version": "0.34.0"
"version": "0.36.0"
}

View File

@@ -1,5 +1,5 @@
wayland_protos = dependency('wayland-protocols',
version: '>=1.25',
version: '>=1.32',
fallback: 'wayland-protocols',
default_options: ['tests=false'],
)

View File

@@ -81,26 +81,6 @@ CCompositor::CCompositor() {
CCompositor::~CCompositor() {
cleanup();
g_pDecorationPositioner.reset();
g_pPluginSystem.reset();
g_pHyprNotificationOverlay.reset();
g_pDebugOverlay.reset();
g_pEventManager.reset();
g_pSessionLockManager.reset();
g_pProtocolManager.reset();
g_pXWaylandManager.reset();
g_pHyprRenderer.reset();
g_pHyprOpenGL.reset();
g_pInputManager.reset();
g_pThreadManager.reset();
g_pConfigManager.reset();
g_pLayoutManager.reset();
g_pHyprError.reset();
g_pConfigManager.reset();
g_pAnimationManager.reset();
g_pKeybindManager.reset();
g_pHookSystem.reset();
g_pWatchdog.reset();
}
void CCompositor::setRandomSplash() {
@@ -119,8 +99,11 @@ void CCompositor::initServer() {
// register crit signal handler
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
signal(SIGSEGV, handleUnrecoverableSignal);
signal(SIGABRT, handleUnrecoverableSignal);
if (!envEnabled("HYPRLAND_NO_CRASHREPORTER")) {
signal(SIGSEGV, handleUnrecoverableSignal);
signal(SIGABRT, handleUnrecoverableSignal);
}
signal(SIGUSR1, handleUserSignal);
initManagers(STAGE_PRIORITY);
@@ -135,10 +118,10 @@ void CCompositor::initServer() {
else
wlr_log_init(WLR_ERROR, Debug::wlrLog);
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay, &m_sWLRSession);
m_sWLRBackend = wlr_backend_autocreate(m_sWLEventLoop, &m_sWLRSession);
if (!m_sWLRBackend) {
Debug::log(CRIT, "m_sWLRBackend was NULL!");
Debug::log(CRIT, "m_sWLRBackend was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
throwError("wlr_backend_autocreate() failed!");
}
@@ -151,7 +134,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!");
Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
throwError("wlr_gles2_renderer_create_with_drm_fd() failed!");
}
@@ -259,7 +242,7 @@ void CCompositor::initServer() {
m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay);
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLDisplay);
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop);
m_sWLRSessionLockMgr = wlr_session_lock_manager_v1_create(m_sWLDisplay);
@@ -324,6 +307,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");
@@ -332,10 +316,67 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
}
void CCompositor::removeAllSignals() {
removeWLSignal(&Events::listen_newOutput);
removeWLSignal(&Events::listen_newXDGToplevel);
removeWLSignal(&Events::listen_mouseMove);
removeWLSignal(&Events::listen_mouseMoveAbsolute);
removeWLSignal(&Events::listen_mouseButton);
removeWLSignal(&Events::listen_mouseAxis);
removeWLSignal(&Events::listen_mouseFrame);
removeWLSignal(&Events::listen_swipeBegin);
removeWLSignal(&Events::listen_swipeUpdate);
removeWLSignal(&Events::listen_swipeEnd);
removeWLSignal(&Events::listen_pinchBegin);
removeWLSignal(&Events::listen_pinchUpdate);
removeWLSignal(&Events::listen_pinchEnd);
removeWLSignal(&Events::listen_touchBegin);
removeWLSignal(&Events::listen_touchEnd);
removeWLSignal(&Events::listen_touchUpdate);
removeWLSignal(&Events::listen_touchFrame);
removeWLSignal(&Events::listen_holdBegin);
removeWLSignal(&Events::listen_holdEnd);
removeWLSignal(&Events::listen_newInput);
removeWLSignal(&Events::listen_requestMouse);
removeWLSignal(&Events::listen_requestSetSel);
removeWLSignal(&Events::listen_requestDrag);
removeWLSignal(&Events::listen_startDrag);
removeWLSignal(&Events::listen_requestSetSel);
removeWLSignal(&Events::listen_requestSetPrimarySel);
removeWLSignal(&Events::listen_newLayerSurface);
removeWLSignal(&Events::listen_change);
removeWLSignal(&Events::listen_outputMgrApply);
removeWLSignal(&Events::listen_outputMgrTest);
removeWLSignal(&Events::listen_newConstraint);
removeWLSignal(&Events::listen_NewXDGDeco);
removeWLSignal(&Events::listen_newVirtPtr);
removeWLSignal(&Events::listen_newVirtualKeyboard);
removeWLSignal(&Events::listen_RendererDestroy);
removeWLSignal(&Events::listen_newIdleInhibitor);
removeWLSignal(&Events::listen_powerMgrSetMode);
removeWLSignal(&Events::listen_newIME);
removeWLSignal(&Events::listen_newTextInput);
removeWLSignal(&Events::listen_activateXDG);
removeWLSignal(&Events::listen_newSessionLock);
removeWLSignal(&Events::listen_setGamma);
removeWLSignal(&Events::listen_setCursorShape);
removeWLSignal(&Events::listen_newTearingHint);
removeWLSignal(&Events::listen_newShortcutInhibitor);
if (m_sWRLDRMLeaseMgr)
removeWLSignal(&Events::listen_leaseRequest);
if (m_sWLRSession)
removeWLSignal(&Events::listen_sessionActive);
}
void CCompositor::cleanup() {
if (!m_sWLDisplay || m_bIsShuttingDown)
return;
signal(SIGABRT, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
removeLockFile();
m_bIsShuttingDown = true;
@@ -362,8 +403,8 @@ void CCompositor::cleanup() {
for (auto& m : m_vMonitors) {
g_pHyprOpenGL->destroyMonitorResources(m.get());
wlr_output_enable(m->output, false);
wlr_output_commit(m->output);
wlr_output_state_set_enabled(m->state.wlr(), false);
m->state.commit();
}
m_vMonitors.clear();
@@ -373,8 +414,32 @@ void CCompositor::cleanup() {
g_pXWaylandManager->m_sWLRXWayland = nullptr;
}
removeAllSignals();
g_pInputManager.reset();
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
g_pDecorationPositioner.reset();
g_pPluginSystem.reset();
g_pHyprNotificationOverlay.reset();
g_pDebugOverlay.reset();
g_pEventManager.reset();
g_pSessionLockManager.reset();
g_pProtocolManager.reset();
g_pHyprRenderer.reset();
g_pHyprOpenGL.reset();
g_pThreadManager.reset();
g_pConfigManager.reset();
g_pLayoutManager.reset();
g_pHyprError.reset();
g_pConfigManager.reset();
g_pAnimationManager.reset();
g_pKeybindManager.reset();
g_pHookSystem.reset();
g_pWatchdog.reset();
g_pXWaylandManager.reset();
wl_display_terminate(m_sWLDisplay);
m_sWLDisplay = nullptr;
@@ -408,6 +473,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the ThreadManager!");
g_pThreadManager = std::make_unique<CThreadManager>();
Debug::log(LOG, "Creating CHyprCtl");
g_pHyprCtl = std::make_unique<CHyprCtl>();
Debug::log(LOG, "Creating the InputManager!");
g_pInputManager = std::make_unique<CInputManager>();
@@ -629,72 +697,32 @@ bool CCompositor::windowExists(CWindow* pWindow) {
return false;
}
CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
const auto PMONITOR = getMonitorFromVector(pos);
if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows) {
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint(pos) && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
bool CCompositor::monitorExists(CMonitor* pMonitor) {
for (auto& m : m_vRealMonitors) {
if (m.get() == pMonitor)
return true;
}
for (auto& w : m_vWindows) {
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
return nullptr;
return false;
}
CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreWindow) {
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;
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
static auto* const PRESIZEONBORDER = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:resize_on_border");
static auto* const PBORDERSIZE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:border_size");
static auto* const PBORDERGRABEXTEND = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area");
static auto* const PSPECIALFALLTHRU = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:special_fallthrough");
const auto BORDER_GRAB_AREA = **PRESIZEONBORDER ? **PBORDERSIZE + **PBORDERGRABEXTEND : 0;
// pinned windows on top of floating regardless
for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowInputBox();
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 (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
return w.get();
if (!w->m_bIsX11) {
if (w->hasPopupAt(pos))
return w.get();
}
}
}
auto windowForWorkspace = [&](bool special) -> CWindow* {
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
if (properties & ALLOW_FLOATING) {
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->getWindowInputBox();
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 && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
// OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
continue;
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
// Override Redirect
return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
}
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();
}
if (!w->m_bIsX11) {
if (w->hasPopupAt(pos))
@@ -702,6 +730,53 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
}
}
}
}
auto windowForWorkspace = [&](bool special) -> CWindow* {
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);
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus &&
w.get() != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
// OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
continue;
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
// Override Redirect
return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
}
return w.get();
}
if (!w->m_bIsX11) {
if (w->hasPopupAt(pos))
return w.get();
}
}
}
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 floating(false);
const int64_t WORKSPACEID = special ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID);
@@ -709,13 +784,17 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
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();
}
@@ -725,9 +804,9 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
if (special != isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
CBox box = {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)
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_sAdditionalConfigData.noFocus && w.get() != pIgnoreWindow)
return w.get();
}
@@ -735,68 +814,17 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
};
// special workspace
if (PMONITOR->specialWorkspaceID)
if (PMONITOR->specialWorkspaceID && !**PSPECIALFALLTHRU)
return windowForWorkspace(true);
return windowForWorkspace(false);
}
CWindow* CCompositor::windowFromCursor() {
const auto PMONITOR = getMonitorFromCursor();
if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows | std::views::reverse) {
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) &&
!w->isHidden() && !w->m_bNoFocus)
return w.get();
}
const auto PWINDOW = windowForWorkspace(true);
for (auto& w : m_vWindows) {
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && !w->m_bNoFocus)
return w.get();
}
if (PWINDOW)
return PWINDOW;
}
// pinned
for (auto& w : m_vWindows | std::views::reverse) {
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto& w : m_vWindows | std::views::reverse) {
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bNoFocus)
return w.get();
}
return nullptr;
}
CWindow* CCompositor::windowFloatingFromCursor() {
for (auto& w : m_vWindows | std::views::reverse) {
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows | std::views::reverse) {
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() &&
!w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
return nullptr;
return windowForWorkspace(false);
}
wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pWindow, Vector2D& sl) {
@@ -874,15 +902,31 @@ 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 PFOLLOWMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:follow_mouse");
static auto* const PSPECIALFALLTHROUGH = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("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.");
return;
}
if (!g_pInputManager->m_dExclusiveLSes.empty()) {
Debug::log(LOG, "Refusing a keyboard focus to a window because of an exclusive ls");
return;
}
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
if (!pWindow || !windowValidMapped(pWindow)) {
@@ -917,7 +961,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;
}
@@ -928,12 +972,13 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
if (pWindow->m_bPinned)
pWindow->m_iWorkspaceID = m_pLastMonitor->activeWorkspace;
const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID);
if (!isWorkspaceVisible(pWindow->m_iWorkspaceID)) {
const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID);
// This is to fix incorrect feedback on the focus history.
const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID);
PWORKSPACE->m_pLastFocusedWindow = pWindow;
PWORKSPACE->rememberPrevWorkspace(getWorkspaceByID(m_pLastMonitor->activeWorkspace));
const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID);
PMONITOR->changeWorkspace(PWORKSPACE, false, true);
// changeworkspace already calls focusWindow
return;
@@ -942,6 +987,11 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
const auto PLASTWINDOW = m_pLastWindow;
m_pLastWindow = pWindow;
/* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which
window focuses are "via keybinds" and which ones aren't. */
if (PMONITOR->specialWorkspaceID && PMONITOR->specialWorkspaceID != pWindow->m_iWorkspaceID && !pWindow->m_bPinned && !**PSPECIALFALLTHROUGH)
PMONITOR->setSpecialWorkspace(nullptr);
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
if (windowValidMapped(PLASTWINDOW)) {
PLASTWINDOW->updateDynamicRules();
@@ -1006,7 +1056,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1);
}
if (*PFOLLOWMOUSE == 0)
if (**PFOLLOWMOUSE == 0)
g_pInputManager->sendMotionEventsToFocused();
}
@@ -1015,10 +1065,8 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
if (m_sSeat.seat->keyboard_state.focused_surface == pSurface || (pWindowOwner && m_sSeat.seat->keyboard_state.focused_surface == pWindowOwner->m_pWLSurface.wlr()))
return; // Don't focus when already focused on this.
if (g_pSessionLockManager->isSessionLocked()) {
wlr_seat_keyboard_clear_focus(m_sSeat.seat);
m_pLastFocus = nullptr;
}
if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface))
return;
// Unfocus last surface if should
if (m_pLastFocus && !pWindowOwner)
@@ -1089,14 +1137,6 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
auto SURFACEAT = wlr_layer_surface_v1_surface_at(ls->layerSurface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y);
if (ls->layerSurface->current.keyboard_interactive && ls->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
if (!SURFACEAT)
SURFACEAT = ls->layerSurface->surface;
*ppLayerSurfaceFound = ls.get();
return SURFACEAT;
}
if (SURFACEAT) {
if (!pixman_region32_not_empty(&SURFACEAT->input_region))
continue;
@@ -1483,7 +1523,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* const PMETHOD = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:focus_preferred_method");
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -1545,7 +1585,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
break;
}
if (*PMETHOD == 0 /* history */) {
if (**PMETHOD == 0 /* history */) {
if (intersectLength > 0) {
// get idx
@@ -1639,7 +1679,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();
}
@@ -1647,7 +1687,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();
}
@@ -1668,7 +1708,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();
}
@@ -1676,7 +1716,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();
}
@@ -1764,8 +1804,15 @@ CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) {
}
CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
const auto POSA = m_pLastMonitor->vecPosition;
const auto SIZEA = m_pLastMonitor->vecSize;
return this->getMonitorInDirection(m_pLastMonitor, dir);
}
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;
@@ -1844,21 +1891,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* const PACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:col.active_border");
static auto* const PINACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border");
static auto* const PNOGROUPACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border_active");
static auto* const PNOGROUPINACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border");
static auto* const PGROUPACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("group:col.border_active");
static auto* const PGROUPINACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("group:col.border_inactive");
static auto* const PGROUPACTIVELOCKEDCOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_active");
static auto* const PGROUPINACTIVELOCKEDCOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_inactive");
static auto* const PINACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity");
static auto* const PACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:active_opacity");
static auto* const PFULLSCREENALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity");
static auto* const PSHADOWCOL = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:col.shadow");
static auto* const PSHADOWCOLINACTIVE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive");
static auto* const PDIMSTRENGTH = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:dim_strength");
static auto* const PDIMENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:dim_inactive");
auto* const ACTIVECOL = (CGradientValueData*)(*PACTIVECOL)->getData();
auto* const INACTIVECOL = (CGradientValueData*)(*PINACTIVECOL)->getData();
auto* const NOGROUPACTIVECOL = (CGradientValueData*)(*PNOGROUPACTIVECOL)->getData();
auto* const NOGROUPINACTIVECOL = (CGradientValueData*)(*PNOGROUPINACTIVECOL)->getData();
auto* const GROUPACTIVECOL = (CGradientValueData*)(*PGROUPACTIVECOL)->getData();
auto* const GROUPINACTIVECOL = (CGradientValueData*)(*PGROUPINACTIVECOL)->getData();
auto* const GROUPACTIVELOCKEDCOL = (CGradientValueData*)(*PGROUPACTIVELOCKEDCOL)->getData();
auto* const GROUPINACTIVELOCKEDCOL = (CGradientValueData*)(*PGROUPINACTIVELOCKEDCOL)->getData();
auto setBorderColor = [&](CGradientValueData grad) -> void {
if (grad == pWindow->m_cRealBorderColor)
@@ -1879,15 +1935,13 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
if (pWindow == m_pLastWindow) {
const auto* const ACTIVECOLOR =
!pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying() >= 0 ?
CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying())) :
*ACTIVECOLOR);
setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying().m_vColors.empty() ? *ACTIVECOLOR :
pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying());
} else {
const auto* const INACTIVECOLOR =
!pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying() >= 0 ?
CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying())) :
*INACTIVECOLOR);
setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying().m_vColors.empty() ? *INACTIVECOLOR :
pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying());
}
}
@@ -1898,31 +1952,31 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
// opacity
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
pWindow->m_fActiveInactiveAlpha = *PFULLSCREENALPHA;
pWindow->m_fActiveInactiveAlpha = **PFULLSCREENALPHA;
} else {
if (pWindow == m_pLastWindow)
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alpha.toUnderlying() :
pWindow->m_sSpecialRenderData.alpha.toUnderlying() * *PACTIVEALPHA;
pWindow->m_sSpecialRenderData.alpha.toUnderlying() * **PACTIVEALPHA;
else
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() != -1 ?
(pWindow->m_sSpecialRenderData.alphaInactiveOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() :
pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() * *PINACTIVEALPHA) :
*PINACTIVEALPHA;
pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() * **PINACTIVEALPHA) :
**PINACTIVEALPHA;
}
// dim
if (pWindow == m_pLastWindow || pWindow->m_sAdditionalConfigData.forceNoDim || !*PDIMENABLED) {
if (pWindow == m_pLastWindow || pWindow->m_sAdditionalConfigData.forceNoDim || !**PDIMENABLED) {
pWindow->m_fDimPercent = 0;
} else {
pWindow->m_fDimPercent = *PDIMSTRENGTH;
pWindow->m_fDimPercent = **PDIMSTRENGTH;
}
// shadow
if (pWindow->m_iX11Type != 2 && !pWindow->m_bX11DoesntWantBorders) {
if (pWindow == m_pLastWindow) {
pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL);
pWindow->m_cRealShadowColor = CColor(**PSHADOWCOL);
} else {
pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
pWindow->m_cRealShadowColor = CColor(**PSHADOWCOLINACTIVE != INT_MAX ? **PSHADOWCOLINACTIVE : **PSHADOWCOL);
}
} else {
pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow
@@ -2014,7 +2068,11 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
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)));
}
// event
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName});
@@ -2024,7 +2082,11 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
}
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)
@@ -2079,39 +2141,21 @@ 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;
}
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor) {
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor, bool noWarpCursor) {
// We trust the workspace and monitor to be correct.
@@ -2126,7 +2170,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
// fix old mon
int nextWorkspaceOnMonitorID = -1;
if (!SWITCHINGISACTIVE)
if (!SWITCHINGISACTIVE || !POLDMON)
nextWorkspaceOnMonitorID = pWorkspace->m_iID;
else {
for (auto& w : m_vWorkspaces) {
@@ -2151,7 +2195,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
@@ -2192,12 +2236,14 @@ 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);
pWorkspace->startAnim(true, true, true);
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
if (!noWarpCursor)
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
g_pInputManager->sendMotionEventsToFocused();
}
@@ -2284,7 +2330,6 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->shouldSendFullscreenState());
pWindow->updateDynamicRules();
updateWindowAnimatedDecorationValues(pWindow);
// make all windows on the same workspace under the fullscreen window
@@ -2417,9 +2462,9 @@ 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* const PNOWARPS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:no_cursor_warps");
if (*PNOWARPS && !force)
if (**PNOWARPS && !force)
return;
if (!m_sSeat.mouse)
@@ -2585,7 +2630,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;
}
@@ -2606,11 +2651,7 @@ int CCompositor::getNewSpecialID() {
}
void CCompositor::performUserChecks() {
if (g_pConfigManager->getInt("general:allow_tearing") == 1 && !envEnabled("WLR_DRM_NO_ATOMIC")) {
g_pHyprNotificationOverlay->addNotification("You have enabled tearing, but immediate presentations are not available on your configuration. Try adding "
"env = WLR_DRM_NO_ATOMIC,1 to your config.",
CColor(0), 15000, ICON_WARNING);
}
; // intentional
}
void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) {
@@ -2686,7 +2727,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;
@@ -2735,9 +2776,9 @@ void CCompositor::arrangeMonitors() {
for (auto& m : m_vMonitors) {
Debug::log(LOG, "arrangeMonitors: {} xwayland [{}, {:.2f}]", m->szName, maxOffset, 0.f);
m->vecXWaylandPosition = {maxOffset, 0};
maxOffset += (*PXWLFORCESCALEZERO ? m->vecTransformedSize.x : m->vecSize.x);
maxOffset += (**PXWLFORCESCALEZERO ? m->vecTransformedSize.x : m->vecSize.x);
if (*PXWLFORCESCALEZERO)
if (**PXWLFORCESCALEZERO)
m->xwaylandScale = m->scale;
else
m->xwaylandScale = 1.f;
@@ -2785,10 +2826,27 @@ void CCompositor::leaveUnsafeState() {
void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) {
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(pSurface, scale);
wlr_surface_set_preferred_buffer_scale(pSurface, static_cast<int32_t>(std::ceil(scale)));
const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
if (!PSURFACE) {
Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface);
return;
}
PSURFACE->m_fLastScale = scale;
PSURFACE->m_iLastScale = static_cast<int32_t>(std::ceil(scale));
}
void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) {
wlr_surface_set_preferred_buffer_transform(pSurface, transform);
const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
if (!PSURFACE) {
Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface);
return;
}
PSURFACE->m_eLastTransform = transform;
}
void CCompositor::updateSuspendedStates() {

View File

@@ -135,15 +135,14 @@ class CCompositor {
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
bool windowExists(CWindow*);
bool windowValidMapped(CWindow*);
CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow"
CWindow* vectorToWindowTiled(const Vector2D&);
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* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
CWindow* windowFromCursor();
CWindow* windowFloatingFromCursor();
CMonitor* getMonitorFromOutput(wlr_output*);
CMonitor* getRealMonitorFromOutput(wlr_output*);
CWindow* getWindowForPopup(wlr_xdg_popup*);
CWindow* getWindowFromSurface(wlr_surface*);
CWindow* getWindowFromHandle(uint32_t);
@@ -172,11 +171,12 @@ class CCompositor {
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*);
int getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&);
@@ -214,6 +214,7 @@ class CCompositor {
private:
void initAllSignals();
void removeAllSignals();
void setRandomSplash();
void initManagers(eManagersInitStage stage);
void prepareFallbackOutput();

View File

@@ -1,6 +1,7 @@
#pragma once
#include "helpers/Vector2D.hpp"
#include <functional>
enum eIcons {
ICON_WARNING = 0,
@@ -52,4 +53,20 @@ struct SWindowDecorationExtents {
bool operator==(const SWindowDecorationExtents& other) const {
return topLeft == other.topLeft && bottomRight == other.bottomRight;
}
};
void addExtents(const SWindowDecorationExtents& other) {
topLeft = topLeft.getComponentMax(other.topLeft);
bottomRight = bottomRight.getComponentMax(other.bottomRight);
}
};
enum eHyprCtlOutputFormat {
FORMAT_NORMAL = 0,
FORMAT_JSON
};
struct SHyprCtlCommand {
std::string name = "";
bool exact = true;
std::function<std::string(eHyprCtlOutputFormat, std::string)> fn;
};

View File

@@ -139,35 +139,25 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
}
CBox CWindow::getWindowInputBox() {
const int BORDERSIZE = getRealBorderSize();
CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_sAdditionalConfigData.dimAround) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
}
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
SWindowDecorationExtents EXTENTS = {{0, 0}, {0, 0}};
if (properties & RESERVED_EXTENTS)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(this));
if (properties & INPUT_EXTENTS)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, true));
if (properties & FULL_EXTENTS)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, false));
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
CBox box = {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
box.addExtents(EXTENTS);
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
// Add extents to the real base BB and return
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};
return finalBox;
return box;
}
CBox CWindow::getWindowMainSurfaceBox() {
@@ -318,7 +308,7 @@ void CWindow::destroyToplevelHandle() {
}
void CWindow::updateToplevel() {
updateSurfaceOutputs();
updateSurfaceScaleTransformDetails();
if (!m_phForeignToplevel)
return;
@@ -345,8 +335,8 @@ void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
wlr_surface_send_leave(pSurface, OUTPUT);
}
void CWindow::updateSurfaceOutputs() {
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden)
void CWindow::updateSurfaceScaleTransformDetails() {
if (!m_bIsMapped || m_bHidden)
return;
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
@@ -355,16 +345,23 @@ void CWindow::updateSurfaceOutputs() {
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
if (PNEWMONITOR != PLASTMONITOR) {
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
}
wlr_surface_for_each_surface(
m_pWLSurface.wlr(),
[](wlr_surface* surf, int x, int y, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
const auto PSURFACE = CWLSurface::surfaceFromWlr(surf);
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
return;
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
},
this);
@@ -374,7 +371,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* const PCLOSEONLASTSPECIAL = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty");
const int OLDWORKSPACE = m_iWorkspaceID;
@@ -397,7 +394,7 @@ void CWindow::moveToWorkspace(int workspaceID) {
// update xwayland coords
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec());
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) {
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && **PCLOSEONLASTSPECIAL) {
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE);
if (PWS) {
@@ -440,7 +437,7 @@ void unregisterVar(void* ptr) {
}
void CWindow::onUnmap() {
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
static auto* const PCLOSEONLASTSPECIAL = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty");
if (g_pCompositor->m_pLastWindow == this)
g_pCompositor->m_pLastWindow = nullptr;
@@ -462,7 +459,7 @@ void CWindow::onUnmap() {
hyprListener_unmapWindow.removeCallback();
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(m_iWorkspaceID) == 0 && g_pCompositor->isWorkspaceSpecial(m_iWorkspaceID)) {
if (**PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(m_iWorkspaceID) == 0 && g_pCompositor->isWorkspaceSpecial(m_iWorkspaceID)) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
PMONITOR->setSpecialWorkspace(nullptr);
@@ -511,6 +508,14 @@ void CWindow::onMap() {
"CWindow");
m_vReportedSize = m_vPendingReportedSize;
for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) {
if (ctrl->pWlrHint->surface != m_pWLSurface.wlr())
continue;
m_bTearingHint = ctrl->pWlrHint->current;
break;
}
}
void CWindow::onBorderAngleAnimEnd(void* ptr) {
@@ -607,14 +612,42 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
m_sAdditionalConfigData.animationStyle = STYLE;
} else if (r.szRule.starts_with("bordercolor")) {
try {
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
// Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {};
bool active = true;
CVarList colorsAndAngles = CVarList(removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
if (colorPart.contains(' ')) {
// we have a space, 2 values
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart.substr(0, colorPart.find_first_of(' ')));
m_sSpecialRenderData.inactiveBorderColor = configStringToInt(colorPart.substr(colorPart.find_first_of(' ') + 1));
} else {
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
// Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0])));
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1])));
return;
}
for (auto& token : colorsAndAngles) {
// The first angle, or an explicit "0deg", splits the two gradients
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false;
} else if (token.contains("deg"))
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
else if (active)
activeBorderGradient.m_vColors.push_back(configStringToInt(token));
else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
}
// Includes sanity checks for the number of colors in each gradient
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
else if (inactiveBorderGradient.m_vColors.empty())
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
else {
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient;
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "dimaround") {
@@ -644,8 +677,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
}
void CWindow::updateDynamicRules() {
m_sSpecialRenderData.activeBorderColor = -1;
m_sSpecialRenderData.inactiveBorderColor = -1;
m_sSpecialRenderData.activeBorderColor = CGradientValueData();
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData();
m_sSpecialRenderData.alpha = 1.f;
m_sSpecialRenderData.alphaInactive = -1.f;
m_sAdditionalConfigData.forceNoBlur = false;
@@ -990,19 +1023,21 @@ bool CWindow::opaque() {
}
float CWindow::rounding() {
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
static auto* const PROUNDING = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:rounding");
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? **PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
return m_sSpecialRenderData.rounding ? rounding : 0;
}
void CWindow::updateSpecialRenderData() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
bool border = true;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
bool border = true;
if (m_bIsFloating && g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue == 1)
static auto* const* PNOBORDERONFLOATING = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:no_border_on_floating");
if (m_bIsFloating && **PNOBORDERONFLOATING == 1)
border = false;
m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(border);
@@ -1022,16 +1057,18 @@ int CWindow::getRealBorderSize() {
if (m_sSpecialRenderData.borderSize.toUnderlying() != -1)
return m_sSpecialRenderData.borderSize.toUnderlying();
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto* const* PBORDERSIZE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:border_size");
return **PBORDERSIZE;
}
bool CWindow::canBeTorn() {
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint);
}
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) {

View File

@@ -30,6 +30,24 @@ enum eGroupRules {
GROUP_OVERRIDE = 1 << 6, // Override other rules
};
enum eGetWindowProperties {
WINDOW_ONLY = 0,
RESERVED_EXTENTS = 1 << 0,
INPUT_EXTENTS = 1 << 1,
FULL_EXTENTS = 1 << 2,
FLOATING_ONLY = 1 << 3,
ALLOW_FLOATING = 1 << 4,
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;
template <typename T>
@@ -106,13 +124,13 @@ class CWindowOverridableVar {
};
struct SWindowSpecialRenderData {
CWindowOverridableVar<bool> alphaOverride = false;
CWindowOverridableVar<float> alpha = 1.f;
CWindowOverridableVar<bool> alphaInactiveOverride = false;
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
CWindowOverridableVar<bool> alphaOverride = false;
CWindowOverridableVar<float> alpha = 1.f;
CWindowOverridableVar<bool> alphaInactiveOverride = false;
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
CWindowOverridableVar<int64_t> activeBorderColor = -1; // -1 means unset
CWindowOverridableVar<int64_t> inactiveBorderColor = -1; // -1 means unset
CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset
CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset
// set by the layout
CWindowOverridableVar<int> borderSize = -1; // -1 means unset
@@ -133,6 +151,7 @@ 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<bool> dimAround = false;
@@ -221,16 +240,17 @@ class CWindow {
bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(0, 0);
bool m_bFirstMap = false; // for layouts
bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bIsFullscreen = false;
bool m_bWasMaximized = false;
uint64_t m_iMonitorID = -1;
std::string m_szTitle = "";
std::string m_szInitialTitle = "";
std::string m_szInitialClass = "";
int m_iWorkspaceID = -1;
bool m_bFirstMap = false; // for layouts
bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bIsFullscreen = false;
bool m_bDontSendFullscreen = false;
bool m_bWasMaximized = false;
uint64_t m_iMonitorID = -1;
std::string m_szTitle = "";
std::string m_szInitialTitle = "";
std::string m_szInitialClass = "";
int m_iWorkspaceID = -1;
bool m_bIsMapped = false;
@@ -250,13 +270,13 @@ 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;
bool m_bWantsInitialFullscreen = false;
// bitfield eSuppressEvents
uint64_t m_eSuppressedEvents = SUPPRESS_NONE;
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
@@ -342,7 +362,7 @@ class CWindow {
// methods
CBox getFullWindowBoundingBox();
SWindowDecorationExtents getFullWindowExtents();
CBox getWindowInputBox();
CBox getWindowBoxUnified(uint64_t props);
CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
@@ -356,7 +376,7 @@ class CWindow {
void createToplevelHandle();
void destroyToplevelHandle();
void updateToplevel();
void updateSurfaceOutputs();
void updateSurfaceScaleTransformDetails();
void moveToWorkspace(int);
CWindow* X11TransientFor();
void onUnmap();

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_INVALID = -1,
CVD_TYPE_GRADIENT = 0,
CVD_TYPE_CSS_VALUE = 1
};
class ICustomConfigValueData {
@@ -16,6 +18,7 @@ class ICustomConfigValueData {
class CGradientValueData : public ICustomConfigValueData {
public:
CGradientValueData(){};
CGradientValueData(CColor col) {
m_vColors.push_back(col);
};
@@ -49,3 +52,55 @@ class CGradientValueData : public ICustomConfigValueData {
return true;
}
};
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;
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -21,21 +21,13 @@
#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
};
struct SWorkspaceRule {
std::string monitor = "";
std::string workspaceString = "";
@@ -43,14 +35,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;
};
@@ -74,9 +67,14 @@ struct SAnimationPropertyConfig {
};
struct SPluginKeyword {
HANDLE handle = 0;
std::string name = "";
std::function<void(const std::string&, const std::string&)> fn;
HANDLE handle = 0;
std::string name = "";
Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
};
struct SPluginVariable {
HANDLE handle = 0;
std::string name = "";
};
struct SExecRequestedRule {
@@ -91,28 +89,21 @@ 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 = "");
SMonitorRule getMonitorRuleFor(const CMonitor&);
SWorkspaceRule getWorkspaceRuleFor(CWorkspace*);
std::string getDefaultWorkspaceFor(const std::string&);
@@ -120,15 +111,15 @@ class CConfigManager {
std::string getBoundMonitorStringForWS(const std::string&);
const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
std::vector<SWindowRule> getMatchingRules(CWindow*);
std::vector<SWindowRule> getMatchingRules(CWindow*, bool dynamic = true);
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 +132,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&);
@@ -151,77 +142,65 @@ class CConfigManager {
void handlePluginLoads();
std::string configCurrentPath;
// 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::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::unique_ptr<Hyprlang::CConfig> m_pConfig;
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
std::string currentCategory = ""; // For storing the category of the current item
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
std::string parseError = ""; // For storing a parse error to display later
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
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<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
std::vector<std::string> m_vDeclaredPlugins;
std::vector<SPluginKeyword> pluginKeywords;
std::vector<SPluginVariable> pluginVariables;
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;
bool isFirstLaunch = true; // For exec-once
bool isFirstLaunch = true; // For exec-once
std::deque<SMonitorRule> m_dMonitorRules;
std::deque<SWorkspaceRule> m_dWorkspaceRules;
std::deque<SWindowRule> m_dWindowRules;
std::deque<SLayerRule> m_dLayerRules;
std::deque<std::string> m_dBlurLSNamespaces;
std::deque<SMonitorRule> m_dMonitorRules;
std::deque<SWorkspaceRule> m_dWorkspaceRules;
std::deque<SWindowRule> m_dWindowRules;
std::deque<SLayerRule> m_dLayerRules;
std::deque<std::string> m_dBlurLSNamespaces;
bool firstExecDispatched = false;
bool m_bManualCrashInitiated = false;
std::deque<std::string> firstExecRequests;
bool firstExecDispatched = false;
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::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
// 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 setAnimForChildren(SAnimationPropertyConfig* const);
void updateBlurredLS(const std::string&, const bool);
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

@@ -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 {
@@ -119,12 +119,13 @@ gestures {
misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
}
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
device:epic-mouse-v1 {
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,21 +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);
// 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;
addrs += std::format("0x{:x} ", vmaAddr);
}
#ifdef __clang__
const auto CMD = std::format("llvm-addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
const auto CMD = std::format("llvm-addr2line -e {} -Cf {}", FPATH.c_str(), addrs);
#else
const auto CMD = std::format("addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
const auto CMD = std::format("addr2line -e {} -Cf {}", FPATH.c_str(), addrs);
#endif
const auto ADDR2LINE = replaceInString(execAndGet(CMD.c_str()), "\n", "\n\t\t");
finalCrashReport += "\t\t" + ADDR2LINE.substr(0, ADDR2LINE.length() - 2);
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";
finalCrashReport += Debug::rollingLog;
finalCrashReport += Debug::rollingLog.substr(Debug::rollingLog.find("\n") + 1);
const auto HOME = getenv("HOME");
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
@@ -128,21 +146,18 @@ 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;
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc);
if (!CACHE_HOME || std::string(CACHE_HOME).empty())
reportDir = std::string(HOME) + "/.cache/hyprland";
else
reportDir = std::string(CACHE_HOME) + "/hyprland";
} else {
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland"))
std::filesystem::create_directory(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(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc);
}
ofs.open(path, std::ios::trunc);
ofs << finalCrashReport;

View File

@@ -7,12 +7,13 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <sstream>
#include <string>
#include <typeindex>
static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',')
@@ -28,7 +29,7 @@ static std::string getWorkspaceNameFromSpecialID(const int workspaceID) {
return workspace->m_szName;
}
std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
auto allMonitors = false;
@@ -39,7 +40,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
allMonitors = true;
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
@@ -75,7 +76,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
"vrr": {},
"activelyTearing": {}
}},)#",
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,
@@ -97,7 +98,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
"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,
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,
@@ -109,8 +110,8 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
return result;
}
static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
const bool isJson = format == HyprCtl::FORMAT_JSON;
static std::string getGroupedData(CWindow* w, eHyprCtlOutputFormat format) {
const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON;
if (!w->m_sGroupData.pNextWindow)
return isJson ? "" : "0";
@@ -133,7 +134,7 @@ static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat form
return result.str();
}
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
static std::string getWindowData(CWindow* w, eHyprCtlOutputFormat format) {
auto getFocusHistoryID = [](CWindow* wnd) -> int {
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) {
if (g_pCompositor->m_vWindowFocusHistory[i] == wnd)
@@ -142,7 +143,7 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
return -1;
};
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
return std::format(
R"#({{
"address": "0x{:x}",
@@ -198,9 +199,9 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
}
}
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& w : g_pCompositor->m_vWindows) {
@@ -218,10 +219,10 @@ std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
static std::string getWorkspaceData(CWorkspace* w, HyprCtl::eHyprCtlOutputFormat format) {
static std::string getWorkspaceData(CWorkspace* w, eHyprCtlOutputFormat format) {
const auto PLASTW = w->getLastFocusedWindow();
const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID);
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
return std::format(R"#({{
"id": {},
"name": "{}",
@@ -242,14 +243,18 @@ static std::string getWorkspaceData(CWorkspace* w, HyprCtl::eHyprCtlOutputFormat
}
}
static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprCtlOutputFormat format) {
static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputFormat format) {
const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; };
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
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())) : "";
@@ -266,8 +271,12 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
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>");
@@ -280,7 +289,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
return result;
}
}
std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
if (!g_pCompositor->m_pLastMonitor)
return "unsafe state";
@@ -293,10 +302,10 @@ std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
return getWorkspaceData(w, format);
}
std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getWorkspaceData(w.get(), format);
@@ -314,9 +323,9 @@ std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& r : g_pConfigManager->getAllWorkspaceRules()) {
result += getWorkspaceRuleData(r, format);
@@ -334,24 +343,24 @@ std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid";
return format == eHyprCtlOutputFormat::FORMAT_JSON ? "{}" : "Invalid";
auto result = getWindowData(PWINDOW, format);
if (format == HyprCtl::FORMAT_JSON)
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
result.pop_back();
return result;
}
std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n";
for (auto& mon : g_pCompositor->m_vMonitors) {
@@ -422,9 +431,9 @@ std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& m : g_pLayoutManager->getAllLayoutNames()) {
@@ -444,10 +453,10 @@ std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n";
result += "\"mice\": [\n";
@@ -603,9 +612,9 @@ std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
ret += "animations:\n";
for (auto& ac : g_pConfigManager->getAnimationConfig()) {
@@ -656,10 +665,10 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret;
}
std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[\n\"log\":\"";
result += escapeJSONStrings(Debug::rollingLog);
result += "\"]";
@@ -670,10 +679,10 @@ std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts();
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto& sh : SHORTCUTS)
ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description);
} else {
@@ -693,9 +702,9 @@ std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret;
}
std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto& kb : g_pKeybindManager->m_lKeybinds) {
ret += "bind";
if (kb.locked)
@@ -741,12 +750,12 @@ std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret;
}
std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
auto commitMsg = removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE);
std::replace(commitMsg.begin(), commitMsg.end(), '#', ' ');
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg +
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + "\n\nflags: (if any)\n";
@@ -793,7 +802,40 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ""; // make the compiler happy
}
std::string dispatchRequest(std::string in) {
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "");
result += "\n\nSystem Information:\n";
struct utsname unameInfo;
uname(&unameInfo);
result += "System name: " + std::string{unameInfo.sysname} + "\n";
result += "Node name: " + std::string{unameInfo.nodename} + "\n";
result += "Release: " + std::string{unameInfo.release} + "\n";
result += "Version: " + std::string{unameInfo.version} + "\n";
result += "\n\n";
#if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
#else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif
result += "GPU information: \n" + GPUINFO + "\n\n";
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
result += "plugins:\n";
for (auto& pl : g_pPluginSystem->getAllPlugins()) {
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
}
return result;
}
std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) {
// get rid of the dispatch keyword
in = in.substr(in.find_first_of(' ') + 1);
@@ -814,7 +856,7 @@ std::string dispatchRequest(std::string in) {
return "ok";
}
std::string dispatchKeyword(std::string in) {
std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
// get rid of the keyword keyword
in = in.substr(in.find_first_of(' ') + 1);
@@ -822,32 +864,35 @@ std::string dispatchKeyword(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* const PLAYOUT = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("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);
@@ -862,7 +907,7 @@ std::string dispatchKeyword(std::string in) {
return retval;
}
std::string reloadRequest(const std::string& request) {
std::string reloadRequest(eHyprCtlOutputFormat format, std::string request) {
const auto REQMODE = request.substr(request.find_last_of(' ') + 1);
@@ -877,20 +922,20 @@ std::string reloadRequest(const std::string& request) {
return "ok";
}
std::string killRequest() {
std::string killRequest(eHyprCtlOutputFormat format, std::string request) {
g_pInputManager->setClickMode(CLICKMODE_KILL);
return "ok";
}
std::string splashRequest() {
std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
return g_pCompositor->m_szCurrentSplash;
}
std::string cursorPosRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) {
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal().floor();
if (format == HyprCtl::FORMAT_NORMAL) {
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
return std::format("{}, {}", (int)CURSORPOS.x, (int)CURSORPOS.y);
} else {
return std::format(R"#(
@@ -905,9 +950,7 @@ std::string cursorPosRequest(HyprCtl::eHyprCtlOutputFormat format) {
return "error";
}
std::string getReply(std::string);
std::string dispatchBatch(std::string request) {
std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
// split by ;
request = request.substr(9);
@@ -930,8 +973,8 @@ std::string dispatchBatch(std::string request) {
nextItem();
while (curitem != "") {
reply += getReply(curitem);
while (curitem != "" || request != "") {
reply += g_pHyprCtl->getReply(curitem);
nextItem();
}
@@ -939,7 +982,7 @@ std::string dispatchBatch(std::string request) {
return reply;
}
std::string dispatchSetCursor(std::string request) {
std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
const auto SIZESTR = vars[vars.size() - 1];
@@ -971,7 +1014,7 @@ std::string dispatchSetCursor(std::string request) {
return "ok";
}
std::string switchXKBLayoutRequest(const std::string& request) {
std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
const auto KB = vars[1];
@@ -1017,7 +1060,7 @@ std::string switchXKBLayoutRequest(const std::string& request) {
return "ok";
}
std::string dispatchSeterror(std::string request) {
std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
std::string errorMessage = "";
@@ -1046,13 +1089,14 @@ std::string dispatchSeterror(std::string request) {
return "ok";
}
std::string dispatchSetProp(std::string request) {
std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
if (vars.size() < 4)
return "not enough args";
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
if (!PWINDOW)
return "window not found";
@@ -1060,6 +1104,8 @@ std::string dispatchSetProp(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) {
@@ -1089,6 +1135,8 @@ std::string dispatchSetProp(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") {
@@ -1104,9 +1152,9 @@ std::string dispatchSetProp(std::string request) {
} else if (PROP == "alphainactive") {
PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock);
} else if (PROP == "activebordercolor") {
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock);
} else if (PROP == "inactivebordercolor") {
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock);
} else if (PROP == "forcergbx") {
PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "bordersize") {
@@ -1124,13 +1172,19 @@ std::string dispatchSetProp(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);
return "ok";
}
std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
std::string curitem = "";
auto nextItem = [&]() {
@@ -1150,31 +1204,43 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
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 == HyprCtl::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(Hyprlang::CUSTOMTYPE*))
return std::format("custom type at: {:x}\nset: {}", (uintptr_t)std::any_cast<Hyprlang::CUSTOMTYPE*>(VAL), 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(Hyprlang::CUSTOMTYPE*))
return std::format("{{\"option\": \"{}\", \"custom\": \"{:x}\", \"set\": {} }}", curitem, (uintptr_t)std::any_cast<Hyprlang::CUSTOMTYPE*>(VAL), VAR->m_bSetByUser);
}
return "invalid type (internal error)";
}
std::string decorationRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
@@ -1182,7 +1248,7 @@ std::string decorationRequest(std::string request, HyprCtl::eHyprCtlOutputFormat
return "none";
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& wd : PWINDOW->m_dWindowDecorations) {
result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},";
@@ -1231,7 +1297,7 @@ void createOutputIter(wlr_backend* backend, void* data) {
}
}
std::string dispatchOutput(std::string request) {
std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
std::string curitem = "";
auto nextItem = [&]() {
@@ -1280,7 +1346,7 @@ std::string dispatchOutput(std::string request) {
return "ok";
}
std::string dispatchPlugin(std::string request) {
std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
if (vars.size() < 2)
@@ -1323,7 +1389,7 @@ std::string dispatchPlugin(std::string request) {
return "ok";
}
std::string dispatchNotify(std::string request) {
std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
if (vars.size() < 5)
@@ -1364,92 +1430,137 @@ std::string dispatchNotify(std::string request) {
return "ok";
}
std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL;
CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
registerCommand(SHyprCtlCommand{"activeworkspace", true, activeWorkspaceRequest});
registerCommand(SHyprCtlCommand{"clients", true, clientsRequest});
registerCommand(SHyprCtlCommand{"kill", true, killRequest});
registerCommand(SHyprCtlCommand{"activewindow", true, activeWindowRequest});
registerCommand(SHyprCtlCommand{"layers", true, layersRequest});
registerCommand(SHyprCtlCommand{"version", true, versionRequest});
registerCommand(SHyprCtlCommand{"devices", true, devicesRequest});
registerCommand(SHyprCtlCommand{"splash", true, splashRequest});
registerCommand(SHyprCtlCommand{"cursorpos", true, cursorPosRequest});
registerCommand(SHyprCtlCommand{"binds", true, bindsRequest});
registerCommand(SHyprCtlCommand{"globalshortcuts", true, globalShortcutsRequest});
registerCommand(SHyprCtlCommand{"systeminfo", true, systemInfoRequest});
registerCommand(SHyprCtlCommand{"animations", true, animationsRequest});
registerCommand(SHyprCtlCommand{"rollinglog", true, rollinglogRequest});
registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
registerCommand(SHyprCtlCommand{"plugin", false, dispatchPlugin});
registerCommand(SHyprCtlCommand{"notify", false, dispatchNotify});
registerCommand(SHyprCtlCommand{"setprop", false, dispatchSetProp});
registerCommand(SHyprCtlCommand{"seterror", false, dispatchSeterror});
registerCommand(SHyprCtlCommand{"switchxkblayout", false, switchXKBLayoutRequest});
registerCommand(SHyprCtlCommand{"output", false, dispatchOutput});
registerCommand(SHyprCtlCommand{"dispatch", false, dispatchRequest});
registerCommand(SHyprCtlCommand{"keyword", false, dispatchKeyword});
registerCommand(SHyprCtlCommand{"setcursor", false, dispatchSetCursor});
registerCommand(SHyprCtlCommand{"getoption", false, dispatchGetOption});
registerCommand(SHyprCtlCommand{"decorations", false, decorationRequest});
registerCommand(SHyprCtlCommand{"[[BATCH]]", false, dispatchBatch});
startHyprCtlSocket();
}
std::shared_ptr<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) {
return m_vCommands.emplace_back(std::make_shared<SHyprCtlCommand>(cmd));
}
void CHyprCtl::unregisterCommand(const std::shared_ptr<SHyprCtlCommand>& cmd) {
std::erase(m_vCommands, cmd);
}
std::string CHyprCtl::getReply(std::string request) {
auto format = eHyprCtlOutputFormat::FORMAT_NORMAL;
bool reloadAll = false;
// process flags for non-batch requests
if (!request.contains("[[BATCH]]") && request.contains("/")) {
if (!request.starts_with("[[BATCH]]") && request.contains("/")) {
long unsigned int sepIndex = 0;
for (const auto& c : request) {
if (c == '/') { // stop at separator
break;
}
// after whitespace assume the first word as a keyword,
// so its value can have slashes (e.g., a path)
if (c == ' ') {
sepIndex = request.size();
break;
}
sepIndex++;
if (c == 'j')
format = HyprCtl::FORMAT_JSON;
format = eHyprCtlOutputFormat::FORMAT_JSON;
if (c == 'r')
reloadAll = true;
}
if (sepIndex < request.size())
request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string
}
if (request.starts_with("monitors"))
return monitorsRequest(request, format);
else if (request == "workspaces")
return workspacesRequest(format);
else if (request == "workspacerules")
return workspaceRulesRequest(format);
else if (request == "activeworkspace")
return activeWorkspaceRequest(format);
else if (request == "clients")
return clientsRequest(format);
else if (request == "kill")
return killRequest();
else if (request == "activewindow")
return activeWindowRequest(format);
else if (request == "layers")
return layersRequest(format);
else if (request == "version")
return versionRequest(format);
else if (request.starts_with("reload"))
return reloadRequest(request);
else if (request == "devices")
return devicesRequest(format);
else if (request == "splash")
return splashRequest();
else if (request == "cursorpos")
return cursorPosRequest(format);
else if (request == "binds")
return bindsRequest(format);
else if (request == "globalshortcuts")
return globalShortcutsRequest(format);
else if (request == "animations")
return animationsRequest(format);
else if (request == "rollinglog")
return rollinglogRequest(format);
else if (request == "layouts")
return layoutsRequest(format);
else if (request.starts_with("plugin"))
return dispatchPlugin(request);
else if (request.starts_with("notify"))
return dispatchNotify(request);
else if (request.starts_with("setprop"))
return dispatchSetProp(request);
else if (request.starts_with("seterror"))
return dispatchSeterror(request);
else if (request.starts_with("switchxkblayout"))
return switchXKBLayoutRequest(request);
else if (request.starts_with("output"))
return dispatchOutput(request);
else if (request.starts_with("dispatch"))
return dispatchRequest(request);
else if (request.starts_with("keyword"))
return dispatchKeyword(request);
else if (request.starts_with("setcursor"))
return dispatchSetCursor(request);
else if (request.starts_with("getoption"))
return dispatchGetOption(request, format);
else if (request.starts_with("decorations"))
return decorationRequest(request, format);
else if (request.starts_with("[[BATCH]]"))
return dispatchBatch(request);
std::string result = "";
return "unknown request";
// parse exact cmds first, then non-exact.
for (auto& cmd : m_vCommands) {
if (!cmd->exact)
continue;
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)) {
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* const PLAYOUT = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("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 HyprCtl::makeDynamicCall(const std::string& input) {
std::string CHyprCtl::makeDynamicCall(const std::string& input) {
return getReply(input);
}
@@ -1460,7 +1571,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress);
const auto ACCEPTEDCONNECTION = accept4(HyprCtl::iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
std::array<char, 1024> readBuffer;
@@ -1490,7 +1601,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
std::string reply = "";
try {
reply = getReply(request);
reply = g_pHyprCtl->getReply(request);
} catch (std::exception& e) {
Debug::log(ERR, "Error in request: {}", e.what());
reply = "Err: " + std::string(e.what());
@@ -1500,18 +1611,17 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
close(ACCEPTEDCONNECTION);
if (g_pConfigManager->m_bWantsMonitorReload) {
if (g_pConfigManager->m_bWantsMonitorReload)
g_pConfigManager->ensureMonitorStatus();
}
return 0;
}
void HyprCtl::startHyprCtlSocket() {
void CHyprCtl::startHyprCtlSocket() {
iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (iSocketFD < 0) {
if (m_iSocketFD < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
return;
}
@@ -1522,15 +1632,15 @@ void HyprCtl::startHyprCtlSocket() {
strcpy(SERVERADDRESS.sun_path, socketPath.c_str());
if (bind(iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work.");
return;
}
// 10 max queued.
listen(iSocketFD, 10);
listen(m_iSocketFD, 10);
Debug::log(LOG, "Hypr socket started at {}", socketPath);
wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
}

View File

@@ -3,24 +3,23 @@
#include "../Compositor.hpp"
#include <fstream>
#include "../helpers/MiscFunctions.hpp"
#include <functional>
namespace HyprCtl {
void startHyprCtlSocket();
std::string makeDynamicCall(const std::string& input);
class CHyprCtl {
public:
CHyprCtl();
// very simple thread-safe request method
inline bool requestMade = false;
inline bool requestReady = false;
inline std::string request = "";
std::string makeDynamicCall(const std::string& input);
std::shared_ptr<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd);
void unregisterCommand(const std::shared_ptr<SHyprCtlCommand>& cmd);
std::string getReply(std::string);
inline std::ifstream requestStream;
int m_iSocketFD = -1;
inline wl_event_source* hyprCtlTickSource = nullptr;
private:
void startHyprCtlSocket();
inline int iSocketFD = -1;
std::vector<std::shared_ptr<SHyprCtlCommand>> m_vCommands;
};
enum eHyprCtlOutputFormat {
FORMAT_NORMAL = 0,
FORMAT_JSON
};
};
inline std::unique_ptr<CHyprCtl> g_pHyprCtl;

View File

@@ -226,4 +226,8 @@ 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

@@ -41,6 +41,7 @@ class CHyprNotificationOverlay {
void draw(CMonitor* pMonitor);
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
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

@@ -21,16 +21,16 @@ enum LogLevel {
};
namespace Debug {
inline std::string logFile;
inline int64_t* disableLogs = nullptr;
inline int64_t* disableTime = nullptr;
inline bool disableStdout = false;
inline bool trace = false;
inline bool shuttingDown = false;
inline std::string logFile;
inline int64_t* const* disableLogs = nullptr;
inline int64_t* const* disableTime = nullptr;
inline bool disableStdout = false;
inline bool trace = false;
inline bool shuttingDown = false;
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
void init(const std::string& IS);
void init(const std::string& IS);
template <typename... Args>
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
if (level == TRACE && !trace)
@@ -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);

View File

@@ -174,4 +174,7 @@ namespace Events {
// Tearing hints
LISTENER(newTearingHint);
// Shortcut inhibitor
LISTENER(newShortcutInhibitor);
};

View File

@@ -142,6 +142,9 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
if (layersurface->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(layersurface);
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);
@@ -183,6 +186,11 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
EMIT_HOOK_EVENT("closeLayer", layersurface);
std::erase(g_pInputManager->m_dExclusiveLSes, layersurface);
if (!g_pInputManager->m_dExclusiveLSes.empty())
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface);
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");

View File

@@ -128,6 +128,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) {
@@ -175,11 +177,17 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
Debug::log(LOG, "PowerMgr set mode!");
const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(EVENT->output);
wlr_output_enable(EVENT->output, EVENT->mode == 1);
if (!PMONITOR) {
Debug::log(ERR, "Invalid powerMgrSetMode output");
return;
}
if (!wlr_output_commit(EVENT->output))
wlr_output_state_set_enabled(PMONITOR->state.wlr(), EVENT->mode == 1);
if (!PMONITOR->state.commit())
Debug::log(ERR, "Couldn't set power mode");
}
@@ -225,16 +233,7 @@ 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;
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface);
if (!PWINDOW) {
Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
return;
}
Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)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();
NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
@@ -242,7 +241,7 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
NEWCTRL->hyprListener_destroy.initCallback(
&NEWCTRL->pWlrHint->events.destroy,
[&](void* owner, void* data) {
Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
Debug::log(LOG, "Destroyed {:x} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
},
@@ -256,10 +255,27 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
if (PWINDOW) {
PWINDOW->m_bTearingHint = TEARINGHINT->pWlrHint->hint;
PWINDOW->m_bTearingHint = (bool)TEARINGHINT->pWlrHint->current;
Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->hint);
Debug::log(LOG, "Hint {:x} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->current);
}
},
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

@@ -109,7 +109,7 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) {
w->m_iLastSurfaceMonitorID = -1;
w->updateSurfaceOutputs();
w->updateSurfaceScaleTransformDetails();
}
}
}
@@ -147,12 +147,12 @@ 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* const PENABLERAT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time");
static auto* const PRATSAFE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone");
PMONITOR->lastPresentationTimer.reset();
if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
if (**PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
if (!PMONITOR->RATScheduled) {
// render
g_pHyprRenderer->renderMonitor(PMONITOR);
@@ -162,14 +162,14 @@ void Events::listener_monitorFrame(void* owner, void* data) {
const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR);
if (max + *PRATSAFE > 1000.0 / PMONITOR->refreshRate)
if (max + **PRATSAFE > 1000.0 / PMONITOR->refreshRate)
return;
const auto MSLEFT = 1000.0 / PMONITOR->refreshRate - PMONITOR->lastPresentationTimer.getMillis();
PMONITOR->RATScheduled = true;
const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE);
const auto ESTRENDERTIME = std::ceil(avg + **PRATSAFE);
const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1)
@@ -212,7 +212,17 @@ void Events::listener_monitorStateRequest(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_request_state*)data;
wlr_output_commit_state(PMONITOR->output, E->state);
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

@@ -55,7 +55,7 @@ void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
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_destroyPopupXDG.initCallback(&popup->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");
@@ -228,6 +228,11 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
void Events::listener_commitPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
if (PPOPUP->popup->base->initial_commit) {
wlr_xdg_surface_schedule_configure(PPOPUP->popup->base);
return;
}
if (g_pCompositor->windowValidMapped(PPOPUP->parentWindow)) {
PPOPUP->lx = PPOPUP->parentWindow->m_vRealPosition.vec().x;
PPOPUP->ly = PPOPUP->parentWindow->m_vRealPosition.vec().y;

View File

@@ -40,17 +40,16 @@ void setAnimToMove(void* data) {
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* const PINACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity");
static auto* const PACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:active_opacity");
static auto* const PDIMSTRENGTH = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:dim_strength");
static auto* const PSWALLOW = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:enable_swallow");
static auto* const PSWALLOWREGEX = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("misc:swallow_regex");
static auto* const PSWALLOWEXREGEX = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex");
static auto* const PNEWTAKESOVERFS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("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);
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 +100,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 +172,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;
@@ -270,6 +279,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;
@@ -443,9 +454,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow;
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) {
PWINDOW->m_bNoFocus = false;
PWINDOW->m_bNoInitialFocus = false;
PWINDOW->m_bX11ShouldntFocus = false;
PWINDOW->m_sAdditionalConfigData.noFocus = false;
PWINDOW->m_bNoInitialFocus = false;
PWINDOW->m_bX11ShouldntFocus = false;
}
// check LS focus grab
@@ -454,9 +465,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
PWINDOW->m_bNoInitialFocus = true;
if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
if (*PNEWTAKESOVERFS == 0)
if (**PNEWTAKESOVERFS == 0)
PWINDOW->m_bNoInitialFocus = true;
else if (*PNEWTAKESOVERFS == 2)
else if (**PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID);
else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
requestsMaximize = true;
@@ -464,14 +475,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
requestsFullscreen = true;
}
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus &&
if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus &&
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
(!PFORCEFOCUS || PFORCEFOCUS == PWINDOW)) {
g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(**PACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : **PDIMSTRENGTH);
} else {
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(**PINACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(0);
}
@@ -504,8 +515,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);
@@ -540,7 +551,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 +598,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);
@@ -639,7 +650,8 @@ 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);
g_pInputManager->sendMotionEventsToFocused();
if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->constraintActive)
g_pInputManager->sendMotionEventsToFocused();
// fix some xwayland apps that don't behave nicely
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
@@ -793,6 +805,11 @@ 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) {
wlr_xdg_toplevel_set_size(PWINDOW->m_uSurface.xdg->toplevel, 0, 0);
return;
}
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
return;
@@ -803,8 +820,6 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_pPendingSizeAck.reset();
}
PWINDOW->updateSurfaceOutputs();
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
@@ -906,7 +921,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;
@@ -960,7 +975,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* const PFOCUSONACTIVATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:focus_on_activate");
Debug::log(LOG, "Activate request for surface at {:x}", (uintptr_t)E->surface);
@@ -969,7 +984,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)});
@@ -977,7 +992,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)
@@ -990,7 +1005,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* const PFOCUSONACTIVATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:focus_on_activate");
Debug::log(LOG, "X11 Activate request for window {}", PWINDOW);
@@ -1001,17 +1016,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)
@@ -1052,13 +1070,10 @@ 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;
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;
static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("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);
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
}
}
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
@@ -1106,7 +1121,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
return;
}
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");
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y});
@@ -1121,7 +1136,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
if (abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2)
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height));
if (*PXWLFORCESCALEZERO) {
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);
@@ -1139,8 +1154,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goalv();
PWINDOW->m_vReportedSize = PWINDOW->m_vRealSize.goalv();
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vReportedSize;
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goalv();
}
}
@@ -1211,7 +1225,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

@@ -75,6 +75,9 @@ float CAnimatedVariable::getPercent() {
}
float CAnimatedVariable::getCurveValue() {
if (!m_bIsBeingAnimated)
return 1.f;
const auto SPENT = getPercent();
if (SPENT >= 1.f)

View File

@@ -1,4 +1,8 @@
#include "Box.hpp"
#include <limits>
#include <algorithm>
wlr_box CBox::wlr() {
CBox rounded = roundInternal();
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
@@ -105,6 +109,13 @@ CBox& CBox::expand(const double& value) {
return *this;
}
CBox& CBox::noNegativeSize() {
std::clamp(w, 0.0, std::numeric_limits<double>::infinity());
std::clamp(h, 0.0, std::numeric_limits<double>::infinity());
return *this;
}
CBox CBox::roundInternal() {
float newW = x + w - std::floor(x);
float newH = y + h - std::floor(y);

View File

@@ -51,6 +51,7 @@ class CBox {
CBox& transform(const wl_output_transform t, double w, double h);
CBox& addExtents(const SWindowDecorationExtents& e);
CBox& expand(const double& value);
CBox& noNegativeSize();
CBox copy() const;
@@ -73,6 +74,8 @@ class CBox {
double height;
};
double rot = 0; /* rad, ccw */
//
bool operator==(const CBox& rhs) const {
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;

View File

@@ -159,6 +159,13 @@ void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, const
Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString);
}
void removeWLSignal(wl_listener* pListener) {
wl_list_remove(&pListener->link);
wl_list_init(&pListener->link);
Debug::log(LOG, "Removed listener {:x}", (uintptr_t)pListener);
}
void handleNoop(struct wl_listener* listener, void* data) {
// Do nothing
}

View File

@@ -15,6 +15,7 @@ struct SCallstackFrameInfo {
std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
void removeWLSignal(wl_listener*);
std::string escapeJSONStrings(const std::string& str);
std::string removeBeginEndSpacesTabs(std::string);
bool isNumber(const std::string&, bool allowfloat = false);

View File

@@ -1,5 +1,7 @@
#include "Monitor.hpp"
#include "MiscFunctions.hpp"
#include "../Compositor.hpp"
int ratHandler(void* data) {
@@ -8,7 +10,7 @@ int ratHandler(void* data) {
return 1;
}
CMonitor::CMonitor() {
CMonitor::CMonitor() : state(this) {
wlr_damage_ring_init(&damage);
}
@@ -43,8 +45,8 @@ void CMonitor::onConnect(bool noRule) {
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
if (m_bEnabled) {
wlr_output_enable(output, 1);
wlr_output_commit(output);
wlr_output_state_set_enabled(state.wlr(), true);
state.commit();
return;
}
@@ -54,17 +56,21 @@ void CMonitor::onConnect(bool noRule) {
// 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());
// 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 : ""));
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) {
wlr_output_set_scale(output, 1);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
wlr_output_state_set_scale(state.wlr(), 1);
wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
auto PREFSTATE = wlr_output_preferred_mode(output);
@@ -72,9 +78,9 @@ void CMonitor::onConnect(bool noRule) {
wlr_output_mode* mode;
wl_list_for_each(mode, &output->modes, link) {
wlr_output_set_mode(output, PREFSTATE);
wlr_output_state_set_mode(state.wlr(), mode);
if (!wlr_output_test(output))
if (!wlr_output_test_state(output, state.wlr()))
continue;
PREFSTATE = mode;
@@ -83,13 +89,13 @@ void CMonitor::onConnect(bool noRule) {
}
if (PREFSTATE)
wlr_output_set_mode(output, PREFSTATE);
wlr_output_state_set_mode(state.wlr(), PREFSTATE);
else
Debug::log(WARN, "No mode found for disabled output {}", output->name);
wlr_output_enable(output, 0);
wlr_output_state_set_enabled(state.wlr(), 0);
if (!wlr_output_commit(output))
if (!state.commit())
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
m_bEnabled = false;
@@ -130,13 +136,28 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true;
wlr_output_enable(output, 1);
wlr_output_state_set_enabled(state.wlr(), 1);
// set mode, also applies
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
wlr_output_commit(output);
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);
@@ -162,6 +183,7 @@ 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
@@ -283,9 +305,10 @@ void CMonitor::onDisconnect(bool destroy) {
if (!destroy)
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
wlr_output_enable(output, false);
wlr_output_state_set_enabled(state.wlr(), false);
wlr_output_commit(output);
if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor == this)
g_pCompositor->setActiveMonitor(BACKUPMON);
@@ -307,13 +330,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;
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
static auto* const PZOOMFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("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);
}
@@ -322,8 +343,8 @@ void CMonitor::addDamage(const CRegion* rg) {
}
void CMonitor::addDamage(const CBox* box) {
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
static auto* const PZOOMFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor");
if (**PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
wlr_damage_ring_add_whole(&damage);
g_pCompositor->scheduleFrameForMonitor(this);
}
@@ -336,6 +357,19 @@ 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);
const auto DESCRIPTION = removeBeginEndSpacesTabs(szDescription.substr(0, szDescription.find_first_of('(')));
return DESCRIPTIONSELECTOR == szDescription || DESCRIPTIONSELECTOR == DESCRIPTION;
} else {
// match by selector
return szName == selector;
}
}
int CMonitor::findAvailableDefaultWS() {
for (size_t i = 1; i < INT32_MAX; ++i) {
if (g_pCompositor->getWorkspaceByID(i))
@@ -415,7 +449,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;
@@ -502,7 +536,7 @@ float CMonitor::getDefaultScale() {
return 1;
}
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove) {
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove, bool noFocus) {
if (!pWorkspace)
return;
@@ -533,13 +567,13 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
}
}
if (!g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
if (!noFocus && !g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
static auto* const PFOLLOWMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:follow_mouse");
CWindow* pWindow = pWorkspace->getLastFocusedWindow();
if (!pWindow) {
if (*PFOLLOWMOUSE == 1)
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
if (**PFOLLOWMOUSE == 1)
pWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!pWindow)
pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
@@ -569,8 +603,8 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
g_pCompositor->updateSuspendedStates();
}
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) {
@@ -621,7 +655,7 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
w->m_iMonitorID = ID;
w->updateSurfaceOutputs();
w->updateSurfaceScaleTransformDetails();
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) {
@@ -678,3 +712,32 @@ void CMonitor::updateMatrix() {
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
}
}
CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
wlr_output_state_init(&m_state);
}
CMonitorState::~CMonitorState() {
wlr_output_state_finish(&m_state);
}
wlr_output_state* CMonitorState::wlr() {
return &m_state;
}
void CMonitorState::clear() {
wlr_output_state_finish(&m_state);
m_state = {0};
wlr_output_state_init(&m_state);
}
bool CMonitorState::commit() {
bool ret = wlr_output_commit_state(m_pOwner->output, &m_state);
clear();
return ret;
}
bool CMonitorState::test() {
return wlr_output_test_state(m_pOwner->output, &m_state);
}

View File

@@ -25,6 +25,25 @@ struct SMonitorRule {
std::optional<int> vrr;
};
class CMonitor;
// Class for wrapping the wlr state
class CMonitorState {
public:
CMonitorState(CMonitor* owner);
~CMonitorState();
wlr_output_state* wlr();
void clear();
// commit() will also clear()
bool commit();
bool test();
private:
wlr_output_state m_state = {0};
CMonitor* m_pOwner;
};
class CMonitor {
public:
CMonitor();
@@ -43,49 +62,51 @@ class CMonitor {
float setScale = 1; // scale set by cfg
float scale = 1; // real scale
std::string szName = "";
std::string szDescription = "";
std::string szName = "";
std::string szDescription = "";
std::string szShortDescription = "";
Vector2D vecReservedTopLeft = Vector2D(0, 0);
Vector2D vecReservedBottomRight = Vector2D(0, 0);
drmModeModeInfo customDrmMode = {};
CMonitorState state;
// WLR stuff
wlr_damage_ring damage;
wlr_output* output = nullptr;
float refreshRate = 60;
int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
bool gammaChanged = false;
float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0};
wlr_damage_ring damage;
wlr_output* output = nullptr;
float refreshRate = 60;
int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
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.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
uint32_t drmFormat = DRM_FORMAT_INVALID;
bool isUnsafeFallback = false;
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.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
uint32_t drmFormat = DRM_FORMAT_INVALID;
bool isUnsafeFallback = false;
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false;
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false;
wl_event_source* renderTimer = nullptr; // for RAT
bool RATScheduled = false;
CTimer lastPresentationTimer;
wl_event_source* renderTimer = nullptr; // for RAT
bool RATScheduled = false;
CTimer lastPresentationTimer;
SMonitorRule activeMonitorRule;
SMonitorRule activeMonitorRule;
// mirroring
CMonitor* pMirrorOf = nullptr;
std::vector<CMonitor*> mirrors;
CRegion lastFrameDamage; // stores last frame damage
// for tearing
CWindow* solitaryClient = nullptr;
@@ -119,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);
void changeWorkspace(const int& id, bool internal = false);
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void 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,7 +58,8 @@ class CRegion {
std::vector<pixman_box32_t> getRects() const;
pixman_region32_t* pixman() {
//
pixman_region32_t* pixman() {
return &m_rRegion;
}

View File

@@ -19,6 +19,21 @@ inline const std::vector<std::string> SPLASHES = {
"Compile, wait for 20 minutes, notice a new commit, compile again.",
"To rice, or not to rice, that is the question.",
"Now available on Fedora!",
"\"Hyprland is so good it starts with a capital letter\" - Hazel",
"\"please make this message a splash\" - eriedaberrie",
"\"the only wayland compositor powered by fried chicken\" - raf",
"\"This will never get into Hyprland\" - Flafy",
"\"Hyprland only gives you up on -git\" - fazzi",
"Segmentation fault (core dumped)",
"\"disabling hyprland logo is a war crime\" - vaxry",
"some basic startup code",
"\"I think I am addicted to hyprland\" - mathisbuilder",
"\"hyprland is the most important package in the arch repos\" - jacekpoz",
"Thanks Brodie!",
"Thanks fufexan!",
"Thanks raf!",
"You can't use --splash to change this message :)",
"Hyprland will overtake Gnome in popularity by [insert year]",
// music reference / quote section
"J'remue le ciel, le jour, la nuit.",
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",

View File

@@ -178,6 +178,9 @@ void Events::listener_mapSubsurface(void* owner, void* data) {
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) {
@@ -222,8 +225,8 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
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)
static auto* const PLOGDAMAGE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("debug:log_damage");
if (**PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner);
return;
}
@@ -259,13 +262,11 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
// 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->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
if (PMONITOR && PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
CRegion damageBox;
wlr_surface_get_effective_damage(pNode->pSurface->wlr(), damageBox.pixman());
CRegion damageBox{&pNode->pSurface->wlr()->buffer_damage};
if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) {
PMONITOR->tearingState.frameScheduledWhileBusy = true;
} else {

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() {
@@ -42,14 +47,10 @@ double Vector2D::distance(const Vector2D& other) const {
return std::sqrt(dx * dx + dy * dy);
}
bool Vector2D::inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const {
const auto a = ((p2.y - p3.y) * (x - p3.x) + (p3.x - p2.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
const auto b = ((p3.y - p1.y) * (x - p3.x) + (p1.x - p3.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
const auto c = 1 - a - b;
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
}
double Vector2D::size() const {
return std::sqrt(x * x + y * y);
}
Vector2D Vector2D::getComponentMax(const Vector2D& other) const {
return Vector2D(std::max(this->x, other.x), std::max(this->y, other.y));
}

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,12 +90,12 @@ 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;
bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const;
Vector2D getComponentMax(const Vector2D& other) const;
};
/**

View File

@@ -127,15 +127,17 @@ struct SKeyboard {
bool active = false;
bool enabled = true;
xkb_layout_index_t activeLayout = 0;
xkb_layout_index_t activeLayout = 0;
xkb_state* xkbTranslationState = nullptr;
std::string name = "";
std::string xkbFilePath = "";
SStringRuleNames currentRules;
int repeatRate = 0;
int repeatDelay = 0;
int numlockOn = -1;
int repeatRate = 0;
int repeatDelay = 0;
int numlockOn = -1;
bool resolveBindsBySym = false;
// For the list lookup
bool operator==(const SKeyboard& rhs) const {
@@ -259,6 +261,8 @@ struct STablet {
std::string name = "";
std::string boundOutput = "";
//
bool operator==(const STablet& b) const {
return wlrDevice == b.wlrDevice;
@@ -410,3 +414,13 @@ struct STearingController {
return pWlrHint == other.pWlrHint;
}
};
struct SShortcutInhibitor {
wlr_keyboard_shortcuts_inhibitor_v1* pWlrInhibitor = nullptr;
DYNLISTENER(destroy);
bool operator==(const SShortcutInhibitor& other) {
return pWlrInhibitor == other.pWlrInhibitor;
}
};

View File

@@ -7,13 +7,15 @@
void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
g_pWatchdog->startWatching();
if (g_pWatchdog)
g_pWatchdog->startWatching();
try {
pWrap->m_pSelf->emit(data);
} catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); }
g_pWatchdog->endWatching();
if (g_pWatchdog)
g_pWatchdog->endWatching();
}
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {

View File

@@ -52,6 +52,29 @@ Vector2D CWLSurface::getViewporterCorrectedSize() const {
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;
@@ -60,11 +83,11 @@ void CWLSurface::destroy() {
m_pWLRSurface->data = nullptr;
m_pOwner = nullptr;
if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
if (g_pCompositor && g_pCompositor->m_pLastFocus == m_pWLRSurface)
g_pCompositor->m_pLastFocus = nullptr;
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
if (g_pInputManager && g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_pWLRSurface = nullptr;

View File

@@ -1,6 +1,7 @@
#pragma once
#include "../defines.hpp"
#include "Region.hpp"
class CWindow;
@@ -23,13 +24,20 @@ 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;
// 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;
CWindow* m_pOwner = nullptr;
// track surface data and avoid dupes
float m_fLastScale = 0;
int m_iLastScale = 0;
wl_output_transform m_eLastTransform = (wl_output_transform)-1;
//
CWLSurface& operator=(wlr_surface* pSurface) {
destroy();
m_pWLRSurface = pSurface;

View File

@@ -13,7 +13,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* const PTIMEOUT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout");
while (1337) {
std::unique_lock lk(m_mWatchdogMutex);
@@ -21,7 +21,7 @@ CWatchdog::CWatchdog() {
if (!m_bWillWatch)
m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified; });
else {
if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false)
if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(**PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false)
pthread_kill(m_iMainThreadPID, SIGUSR1);
}
@@ -37,9 +37,9 @@ CWatchdog::CWatchdog() {
}
void CWatchdog::startWatching() {
static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
static auto* const PTIMEOUT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout");
if (*PTIMEOUT == 0)
if (**PTIMEOUT == 0)
return;
m_tTriggered = std::chrono::high_resolution_clock::now();

View File

@@ -24,6 +24,10 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
m_vRenderOffset.registerVar();
m_fAlpha.registerVar();
const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(this);
if (RULEFORTHIS.defaultName.has_value())
m_szName = RULEFORTHIS.defaultName.value();
g_pEventManager->postEvent({"createworkspace", m_szName});
EMIT_HOOK_EVENT("createWorkspace", this);
}
@@ -38,8 +42,8 @@ CWorkspace::~CWorkspace() {
}
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;
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
static auto* const PWORKSPACEGAP = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:gaps_workspaces");
if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
@@ -91,7 +95,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} else if (ANIMSTYLE == "slidevert") {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
const auto YDISTANCE = PMONITOR->vecSize.y + **PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
@@ -104,7 +108,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} else {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
const auto XDISTANCE = PMONITOR->vecSize.x + **PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.

View File

@@ -4,13 +4,12 @@
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* const PSMARTSPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:smart_split");
static auto* const PPRESERVESPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:preserve_split");
static auto* const PFLMULT = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier");
if (*PPRESERVESPLIT == 0 && *PSMARTSPLIT == 0) {
splitTop = box.h * *PFLMULT > box.w;
}
if (**PPRESERVESPLIT == 0 && **PSMARTSPLIT == 0)
splitTop = box.h * **PFLMULT > box.w;
if (verticalOverride == true)
splitTop = true;
@@ -22,13 +21,13 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
if (SPLITSIDE) {
// split left/right
const float FIRSTSIZE = box.w / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h};
children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h};
children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h}.noNegativeSize();
children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h}.noNegativeSize();
} else {
// split top/bottom
const float FIRSTSIZE = box.h / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE};
children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE};
children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE}.noNegativeSize();
children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE}.noNegativeSize();
}
children[0]->recalcSizePosRecursive(force);
@@ -64,6 +63,21 @@ SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) {
return nullptr;
}
SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const int& id, const Vector2D& point) {
SDwindleNodeData* res = nullptr;
double distClosest = -1;
for (auto& n : m_lDwindleNodesData) {
if (n.workspaceID == id && n.pWindow && g_pCompositor->windowValidMapped(n.pWindow)) {
auto distAnother = vecToRectDistanceSquared(point, n.box.pos(), n.box.pos() + n.box.size());
if (!res || distAnother < distClosest) {
res = &n;
distClosest = distAnother;
}
}
}
return res;
}
SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(CWindow* pWindow) {
for (auto& n : m_lDwindleNodesData) {
if (n.pWindow == pWindow && !n.isNode)
@@ -120,9 +134,11 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
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* const PNOGAPSWHENONLY = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:no_gaps_when_only");
static auto* const PGAPSINDATA = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:gaps_in");
static auto* const PGAPSOUTDATA = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:gaps_out");
auto* const PGAPSIN = (CCssGapData*)(*PGAPSINDATA)->getData();
auto* const PGAPSOUT = (CCssGapData*)(*PGAPSOUTDATA)->getData();
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
@@ -141,10 +157,10 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID);
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) &&
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.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;
@@ -164,9 +180,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;
@@ -201,9 +217,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
// if special, we adjust the coords a bit
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue;
static auto* const PSCALEFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor");
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
CBox wb = {calcPos + (calcSize - calcSize * **PSCALEFACTOR) / 2.f, calcSize * **PSCALEFACTOR};
wb.round(); // avoid rounding mess
PWINDOW->m_vRealPosition = wb.pos();
@@ -211,10 +227,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) {
@@ -238,8 +257,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* const PUSEACTIVE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:use_active_for_splits");
static auto* const PDEFAULTSPLIT = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("dwindle:default_split_ratio");
if (direction != DIRECTION_DEFAULT && overrideDirection == DIRECTION_DEFAULT)
overrideDirection = direction;
@@ -254,26 +273,25 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);
const auto TARGETCOORDS = PMONITOR->ID == MONFROMCURSOR->ID && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR) ? pWindow->middle() : MOUSECOORDS;
if (PMONITOR->ID == MONFROMCURSOR->ID &&
(PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS));
(PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !**PUSEACTIVE) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS));
// happens on reserved area
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS);
} else if (*PUSEACTIVE) {
} else if (**PUSEACTIVE) {
if (g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow &&
g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) {
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
} else {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS));
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS));
}
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS);
} else
OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID);
@@ -325,8 +343,8 @@ 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;
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
static const auto* USECURRPOS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("group:insert_after_current");
(**USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
@@ -349,17 +367,17 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
NEWPARENT->workspaceID = OPENINGON->workspaceID;
NEWPARENT->pParent = OPENINGON->pParent;
NEWPARENT->isNode = true; // it is a node
NEWPARENT->splitRatio = std::clamp(*PDEFAULTSPLIT, 0.1f, 1.9f);
NEWPARENT->splitRatio = std::clamp(**PDEFAULTSPLIT, 0.1f, 1.9f);
const auto PWIDTHMULTIPLIER = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
const auto PWIDTHMULTIPLIER = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier");
// if cursor over first child, make it first, etc
const auto SIDEBYSIDE = NEWPARENT->box.w > NEWPARENT->box.h * *PWIDTHMULTIPLIER;
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* const PFORCESPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:force_split");
static auto* const PERMANENTDIRECTIONOVERRIDE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:permanent_direction_override");
static auto* const PSMARTSPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:smart_split");
bool horizontalOverride = false;
bool verticalOverride = false;
@@ -383,37 +401,44 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
}
// whether or not the override persists after opening one window
if (*PERMANENTDIRECTIONOVERRIDE == 0)
if (**PERMANENTDIRECTIONOVERRIDE == 0)
overrideDirection = DIRECTION_DEFAULT;
} else if (*PSMARTSPLIT == 1) {
const auto tl = NEWPARENT->box.pos();
const auto tr = NEWPARENT->box.pos() + Vector2D(NEWPARENT->box.w, 0);
const auto bl = NEWPARENT->box.pos() + Vector2D(0, NEWPARENT->box.h);
const auto br = NEWPARENT->box.pos() + NEWPARENT->box.size();
const auto cc = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
} else if (**PSMARTSPLIT == 1) {
const auto PARENT_CENTER = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
const auto PARENT_PROPORTIONS = NEWPARENT->box.h / NEWPARENT->box.w;
const auto DELTA = MOUSECOORDS - PARENT_CENTER;
const auto DELTA_SLOPE = DELTA.y / DELTA.x;
if (TARGETCOORDS.inTriangle(tl, tr, cc)) {
NEWPARENT->splitTop = true;
NEWPARENT->children[0] = PNODE;
NEWPARENT->children[1] = OPENINGON;
} else if (TARGETCOORDS.inTriangle(tr, cc, br)) {
NEWPARENT->splitTop = false;
NEWPARENT->children[0] = OPENINGON;
NEWPARENT->children[1] = PNODE;
} else if (TARGETCOORDS.inTriangle(br, bl, cc)) {
NEWPARENT->splitTop = true;
NEWPARENT->children[0] = OPENINGON;
NEWPARENT->children[1] = PNODE;
if (abs(DELTA_SLOPE) < PARENT_PROPORTIONS) {
if (DELTA.x > 0) {
// right
NEWPARENT->splitTop = false;
NEWPARENT->children[0] = OPENINGON;
NEWPARENT->children[1] = PNODE;
} else {
// left
NEWPARENT->splitTop = false;
NEWPARENT->children[0] = PNODE;
NEWPARENT->children[1] = OPENINGON;
}
} else {
NEWPARENT->splitTop = false;
NEWPARENT->children[0] = PNODE;
NEWPARENT->children[1] = OPENINGON;
if (DELTA.y > 0) {
// bottom
NEWPARENT->splitTop = true;
NEWPARENT->children[0] = OPENINGON;
NEWPARENT->children[1] = PNODE;
} else {
// top
NEWPARENT->splitTop = true;
NEWPARENT->children[0] = PNODE;
NEWPARENT->children[1] = OPENINGON;
}
}
} else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
} else if (**PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
if ((SIDEBYSIDE &&
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / **PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
(!SIDEBYSIDE &&
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / **PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
// we are hovering over the first node, make PNODE first.
NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[0] = PNODE;
@@ -423,7 +448,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
NEWPARENT->children[1] = PNODE;
}
} else {
if (*PFORCESPLIT == 1) {
if (**PFORCESPLIT == 1) {
NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[0] = PNODE;
} else {
@@ -442,7 +467,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
}
// Update the children
if (!verticalOverride && (NEWPARENT->box.w * *PWIDTHMULTIPLIER > NEWPARENT->box.h || horizontalOverride)) {
if (!verticalOverride && (NEWPARENT->box.w * **PWIDTHMULTIPLIER > NEWPARENT->box.h || horizontalOverride)) {
// split left/right -> forced
OPENINGON->box = {NEWPARENT->box.pos(), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
PNODE->box = {Vector2D(NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
@@ -586,8 +611,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
return;
}
const auto PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
const auto PSMARTRESIZING = &g_pConfigManager->getConfigValuePtr("dwindle:smart_resizing")->intValue;
const auto PANIMATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes");
const auto PSMARTRESIZING = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:smart_resizing");
// get some data about our window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
@@ -624,11 +649,13 @@ 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);
PNODE->recalcSizePosRecursive(**PANIMATE == 0);
return;
}
@@ -642,7 +669,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (DISPLAYBOTTOM && DISPLAYTOP)
allowedMovement.y = 0;
if (*PSMARTRESIZING == 1) {
if (**PSMARTRESIZING == 1) {
// Identify inner and outer nodes for both directions
SDwindleNodeData* PVOUTER = nullptr;
SDwindleNodeData* PVINNER = nullptr;
@@ -676,14 +703,14 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (PHINNER) {
const auto ORIGINAL = PHINNER->box.w;
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
PHOUTER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
if (PHINNER->pParent->children[0] == PHINNER)
PHINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9);
else
PHINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9);
PHINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
PHINNER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
} else
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
PHOUTER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
}
if (PVOUTER) {
@@ -691,14 +718,14 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (PVINNER) {
const auto ORIGINAL = PVINNER->box.h;
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
PVOUTER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
if (PVINNER->pParent->children[0] == PVINNER)
PVINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9);
else
PVINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9);
PVINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
PVINNER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
} else
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
PVOUTER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
}
} else {
// get the correct containers to apply splitratio to
@@ -717,11 +744,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->box.w;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
PPARENT->recalcSizePosRecursive(**PANIMATE == 0);
} else {
allowedMovement.y *= 2.f / PPARENT->box.h;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
PPARENT->recalcSizePosRecursive(**PANIMATE == 0);
}
return;
@@ -736,11 +763,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->box.w;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
PPARENT->recalcSizePosRecursive(**PANIMATE == 0);
} else {
allowedMovement.y *= 2.f / PPARENT->box.h;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
PPARENT->recalcSizePosRecursive(**PANIMATE == 0);
}
return;
@@ -755,8 +782,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, 0.1, 1.9);
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, 0.1, 1.9);
SIDECONTAINER->recalcSizePosRecursive(*PANIMATE == 0);
TOPCONTAINER->recalcSizePosRecursive(*PANIMATE == 0);
SIDECONTAINER->recalcSizePosRecursive(**PANIMATE == 0);
TOPCONTAINER->recalcSizePosRecursive(**PANIMATE == 0);
}
}
@@ -776,10 +803,21 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
return;
}
// 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();
}
// otherwise, accept it.
pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
pWindow->updateDynamicRules();
pWindow->updateWindowDecos();
g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)});
EMIT_HOOK_EVENT("fullscreen", pWindow);
@@ -800,14 +838,6 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
PWORKSPACE->m_efFullscreenMode = fullscreenMode;
// save position and size if floating
if (pWindow->m_bIsFloating) {
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();
}
// apply new pos and size being monitors' box
if (fullscreenMode == FULLSCREEN_FULL) {
pWindow->m_vRealPosition = PMONITOR->vecPosition;
@@ -824,7 +854,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
pWindow->m_vPosition = fakeNode.box.pos();
pWindow->m_vSize = fakeNode.box.size();
applyNodeDataToWindow(&fakeNode);
applyNodeDataToWindow(&fakeNode, true);
}
}
@@ -967,6 +997,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];
@@ -1020,6 +1052,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);

View File

@@ -79,9 +79,11 @@ class CHyprDwindleLayout : public IHyprLayout {
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
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

@@ -87,7 +87,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
desiredGeometry.y = xy.y;
}
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");
if (!PMONITOR) {
Debug::log(ERR, "{:m} has an invalid monitor in onWindowCreatedFloating!!!", pWindow);
@@ -151,7 +151,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
}
}
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11)
if (**PXWLFORCESCALEZERO && pWindow->m_bIsX11)
pWindow->m_vRealSize = pWindow->m_vRealSize.goalv() / PMONITOR->scale;
if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect)) {
@@ -268,15 +268,15 @@ void IHyprLayout::onEndDragWindow() {
} else if (g_pInputManager->dragMode == MBIND_MOVE) {
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS, DRAGGINGWINDOW);
CWindow* pWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING | FLOATING_ONLY, DRAGGINGWINDOW);
if (pWindow && pWindow->m_bIsFloating) {
if (pWindow) {
if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW))
return;
if (pWindow->m_sGroupData.pNextWindow && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) {
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
(*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
static const auto* USECURRPOS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("group:insert_after_current");
(**USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
pWindow->setGroupCurrent(DRAGGINGWINDOW);
DRAGGINGWINDOW->updateWindowDecos();
@@ -309,13 +309,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
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* const PANIMATEMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:animate_mouse_windowdragging");
static auto* const PANIMATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("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 &&
(*PANIMATEMOUSE || *PANIMATE)))
1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate))
return;
TIMER = std::chrono::high_resolution_clock::now();
@@ -329,7 +328,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
CBox wb = {m_vBeginDragPositionXY + DELTA, DRAGGINGWINDOW->m_vRealSize.goalv()};
wb.round();
if (*PANIMATEMOUSE)
if (**PANIMATEMOUSE)
DRAGGINGWINDOW->m_vRealPosition = wb.pos();
else
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos());
@@ -387,7 +386,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
CBox wb = {newPos, newSize};
wb.round();
if (*PANIMATE) {
if (**PANIMATE) {
DRAGGINGWINDOW->m_vRealSize = wb.size();
DRAGGINGWINDOW->m_vRealPosition = wb.pos();
} else {
@@ -469,16 +468,18 @@ 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};
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)) {
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f + Vector2D{10, 10};
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize - Vector2D{20, 20};
wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}};
}
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f;
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
pWindow->m_vRealPosition = wb.pos();
pWindow->m_vRealSize = wb.size();
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vSize = wb.pos();
pWindow->m_vPosition = wb.size();
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
@@ -529,7 +530,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();
@@ -542,13 +543,14 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
return m_pLastTiledWindow;
// if we don't, let's try to find any window that is in the middle
if (const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(pWindow->middle()); PWINDOWCANDIDATE && PWINDOWCANDIDATE != pWindow)
if (const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
PWINDOWCANDIDATE && PWINDOWCANDIDATE != pWindow)
return PWINDOWCANDIDATE;
// 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();
}
@@ -557,7 +559,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
}
// if it was a tiled window, we first try to find the window that will replace it.
auto pWindowCandidate = g_pCompositor->vectorToWindowIdeal(pWindow->middle());
auto pWindowCandidate = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!pWindowCandidate)
pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->m_iWorkspaceID);

View File

@@ -1,6 +1,7 @@
#include "MasterLayout.hpp"
#include "../Compositor.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "config/ConfigDataValues.hpp"
#include <ranges>
SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(CWindow* pWindow) {
@@ -39,11 +40,11 @@ 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;
const auto PWORKSPACEDATA = &m_lMasterWorkspacesData.emplace_back();
PWORKSPACEDATA->workspaceID = ws;
const auto orientation = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("master:orientation");
const auto layoutoptsForWs = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(ws)).layoutopts;
std::string orientationForWs = *orientation;
if (layoutoptsForWs.contains("orientation"))
orientationForWs = layoutoptsForWs.at("orientation");
@@ -80,20 +81,20 @@ 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* const PNEWTOP = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:new_on_top");
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back();
const auto PNODE = **PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back();
PNODE->workspaceID = pWindow->m_iWorkspaceID;
PNODE->pWindow = pWindow;
static auto* const PNEWISMASTER = &g_pConfigManager->getConfigValuePtr("master:new_is_master")->intValue;
static auto* const PNEWISMASTER = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:new_is_master");
const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID);
static auto* const PMFACT = &g_pConfigManager->getConfigValuePtr("master:mfact")->floatValue;
float lastSplitPercent = *PMFACT;
static auto* const PMFACT = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("master:mfact");
float lastSplitPercent = **PMFACT;
auto OPENINGON = isWindowTiled(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID ?
getNodeFromWindow(g_pCompositor->m_pLastWindow) :
@@ -112,8 +113,8 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
m_lMasterNodesData.remove(*PNODE);
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
static const auto* USECURRPOS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("group:insert_after_current");
(**USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
@@ -128,14 +129,14 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
pWindow->applyGroupRules();
static auto* const PDROPATCURSOR = &g_pConfigManager->getConfigValuePtr("master:drop_at_cursor")->intValue;
static auto* const PDROPATCURSOR = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("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);
bool forceDropAsMaster = false;
// if dragging window to move, drop it at the cursor position instead of bottom/top of stack
if (*PDROPATCURSOR && g_pInputManager->dragMode == MBIND_MOVE) {
if (**PDROPATCURSOR && g_pInputManager->dragMode == MBIND_MOVE) {
if (WINDOWSONWORKSPACE > 2) {
for (auto it = m_lMasterNodesData.begin(); it != m_lMasterNodesData.end(); ++it) {
if (it->workspaceID != pWindow->m_iWorkspaceID)
@@ -191,7 +192,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
}
}
if ((*PNEWISMASTER && g_pInputManager->dragMode != MBIND_MOVE) || WINDOWSONWORKSPACE == 1 || (WINDOWSONWORKSPACE > 2 && !pWindow->m_bFirstMap && OPENINGON->isMaster) ||
if ((**PNEWISMASTER && g_pInputManager->dragMode != MBIND_MOVE) || WINDOWSONWORKSPACE == 1 || (WINDOWSONWORKSPACE > 2 && !pWindow->m_bFirstMap && OPENINGON->isMaster) ||
forceDropAsMaster) {
for (auto& nd : m_lMasterNodesData) {
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
@@ -239,14 +240,14 @@ 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 const auto* SMALLSPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:allow_small_split");
pWindow->updateSpecialRenderData();
if (pWindow->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
if (PNODE->isMaster && (MASTERSLEFT <= 1 || *SMALLSPLIT == 1)) {
if (PNODE->isMaster && (MASTERSLEFT <= 1 || **SMALLSPLIT == 1)) {
// find a new master from top of the list
for (auto& nd : m_lMasterNodesData) {
if (!nd.isMaster && nd.workspaceID == WORKSPACEID) {
@@ -338,8 +339,8 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
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* const ALWAYSCENTER = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:always_center_master");
static auto* const PSMARTRESIZING = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:smart_resizing");
const auto MASTERS = getMastersOnWorkspace(PWORKSPACE->m_iID);
const auto WINDOWS = getNodesOnWorkspace(PWORKSPACE->m_iID);
@@ -348,7 +349,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
const auto WSPOS = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
if (orientation == ORIENTATION_CENTER) {
if (STACKWINDOWS >= 2 || (*ALWAYSCENTER == 1)) {
if (STACKWINDOWS >= 2 || (**ALWAYSCENTER == 1)) {
centerMasterWindow = true;
} else {
orientation = ORIENTATION_LEFT;
@@ -361,7 +362,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
float masterAccumulatedSize = 0;
float slaveAccumulatedSize = 0;
if (*PSMARTRESIZING) {
if (**PSMARTRESIZING) {
// check the total width and height so that later
// if larger/smaller than screen size them down/up
for (auto& nd : m_lMasterNodesData) {
@@ -399,7 +400,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (WIDTH > widthLeft * 0.9f && mastersLeft > 1)
WIDTH = widthLeft * 0.9f;
if (*PSMARTRESIZING) {
if (**PSMARTRESIZING) {
nd.percSize *= WSSIZE.x / masterAccumulatedSize;
WIDTH = masterAverageSize * nd.percSize;
}
@@ -436,7 +437,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (HEIGHT > heightLeft * 0.9f && mastersLeft > 1)
HEIGHT = heightLeft * 0.9f;
if (*PSMARTRESIZING) {
if (**PSMARTRESIZING) {
nd.percSize *= WSSIZE.y / masterAccumulatedSize;
HEIGHT = masterAverageSize * nd.percSize;
}
@@ -473,7 +474,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (WIDTH > widthLeft * 0.9f && slavesLeft > 1)
WIDTH = widthLeft * 0.9f;
if (*PSMARTRESIZING) {
if (**PSMARTRESIZING) {
nd.percSize *= WSSIZE.x / slaveAccumulatedSize;
WIDTH = slaveAverageSize * nd.percSize;
}
@@ -503,7 +504,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (HEIGHT > heightLeft * 0.9f && slavesLeft > 1)
HEIGHT = heightLeft * 0.9f;
if (*PSMARTRESIZING) {
if (**PSMARTRESIZING) {
nd.percSize *= WSSIZE.y / slaveAccumulatedSize;
HEIGHT = slaveAverageSize * nd.percSize;
}
@@ -534,7 +535,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
const float slaveAverageHeightR = WSSIZE.y / slavesLeftR;
float slaveAccumulatedHeightL = 0;
float slaveAccumulatedHeightR = 0;
if (*PSMARTRESIZING) {
if (**PSMARTRESIZING) {
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster)
continue;
@@ -569,7 +570,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (HEIGHT > heightLeft * 0.9f && slavesLeft > 1)
HEIGHT = heightLeft * 0.9f;
if (*PSMARTRESIZING) {
if (**PSMARTRESIZING) {
if (onRight) {
nd.percSize *= WSSIZE.y / slaveAccumulatedHeightR;
HEIGHT = slaveAverageHeightR * nd.percSize;
@@ -633,10 +634,12 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
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* const PNOGAPSWHENONLY = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:no_gaps_when_only");
static auto* const PANIMATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes");
static auto* const PGAPSINDATA = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:gaps_in");
static auto* const PGAPSOUTDATA = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:gaps_out");
auto* const PGAPSIN = (CCssGapData*)(*PGAPSINDATA)->getData();
auto* const PGAPSOUT = (CCssGapData*)(*PGAPSOUTDATA)->getData();
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
@@ -649,11 +652,11 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->m_vSize = pNode->size;
PWINDOW->m_vPosition = pNode->position;
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) &&
if (**PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) &&
(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.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;
@@ -673,9 +676,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;
@@ -685,9 +688,9 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
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;
static auto* const PSCALEFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("master:special_scale_factor");
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
CBox wb = {calcPos + (calcSize - calcSize * **PSCALEFACTOR) / 2.f, calcSize * **PSCALEFACTOR};
wb.round(); // avoid rounding mess
PWINDOW->m_vRealPosition = wb.pos();
@@ -736,11 +739,11 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
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;
static auto* const ALWAYSCENTER = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:always_center_master");
static auto* const PSMARTRESIZING = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:smart_resizing");
eOrientation orientation = PWORKSPACEDATA->orientation;
bool centered = orientation == ORIENTATION_CENTER && (*ALWAYSCENTER == 1);
bool centered = orientation == ORIENTATION_CENTER && (**ALWAYSCENTER == 1);
double delta = 0;
const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_vPosition.y + PWINDOW->m_vSize.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
@@ -797,7 +800,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
const auto SIZE = isStackVertical ? WSSIZE.y / nodesInSameColumn : WSSIZE.x / nodesInSameColumn;
if (RESIZEDELTA != 0 && nodesInSameColumn > 1) {
if (!*PSMARTRESIZING) {
if (!**PSMARTRESIZING) {
PNODE->percSize = std::clamp(PNODE->percSize + RESIZEDELTA / SIZE, 0.05, 1.95);
} else {
const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE);
@@ -879,10 +882,21 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
return;
}
// 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();
}
// otherwise, accept it.
pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
pWindow->updateDynamicRules();
pWindow->updateWindowDecos();
g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)});
EMIT_HOOK_EVENT("fullscreen", pWindow);
@@ -903,14 +917,6 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
PWORKSPACE->m_efFullscreenMode = fullscreenMode;
// save position and size if floating
if (pWindow->m_bIsFloating) {
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();
}
// apply new pos and size being monitors' box
if (fullscreenMode == FULLSCREEN_FULL) {
pWindow->m_vRealPosition = PMONITOR->vecPosition;
@@ -1052,8 +1058,8 @@ bool CHyprMasterLayout::prepareLoseFocus(CWindow* pWindow) {
//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;
static auto* const INHERIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:inherit_fullscreen");
return **INHERIT == 1;
}
return false;
@@ -1230,9 +1236,9 @@ 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 const auto* SMALLSPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("master:allow_small_split");
if (MASTERS + 2 > WINDOWS && *SMALLSPLIT == 0)
if (MASTERS + 2 > WINDOWS && **SMALLSPLIT == 0)
return 0;
prepareLoseFocus(header.pWindow);
@@ -1328,7 +1334,13 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PWINDOW = header.pWindow;
const auto PNODE = getNodeFromWindow(PWINDOW);
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
if (!PNODE)
return 0;
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
if (!OLDMASTER)
return 0;
const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER);
for (auto& nd : m_lMasterNodesData) {
@@ -1350,7 +1362,13 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PWINDOW = header.pWindow;
const auto PNODE = getNodeFromWindow(PWINDOW);
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
if (!PNODE)
return 0;
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
if (!OLDMASTER)
return 0;
const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER);
for (auto& nd : m_lMasterNodesData | std::views::reverse) {

View File

@@ -85,7 +85,7 @@ int main(int argc, char** argv) {
}
if (!ignoreSudo && Init::isSudo()) {
std::cerr << "[ ERROR ] Hyprland was launched with superuser priveleges, but the privileges check is not omitted.\n";
std::cerr << "[ ERROR ] Hyprland was launched with superuser privileges, but the privileges check is not omitted.\n";
std::cerr << " Hint: Use the --i-am-really-stupid flag to omit that check.\n";
return 1;

View File

@@ -53,12 +53,12 @@ void CAnimationManager::tick() {
bool animGlobalDisabled = false;
static auto* const PANIMENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue;
static auto* const PANIMENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("animations:enabled");
if (!*PANIMENABLED)
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");
@@ -66,7 +66,7 @@ void CAnimationManager::tick() {
for (auto& av : m_vActiveAnimatedVariables) {
if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) {
if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !**PSHADOWSENABLED) {
av->warp(false);
animationEndedVars.push_back(av);
continue;
@@ -223,6 +223,11 @@ void CAnimationManager::tick() {
} 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 = WLRBOXPREV;
expandBox.expand(5);
g_pHyprRenderer->damageBox(&expandBox);
}
break;
}
@@ -232,9 +237,9 @@ void CAnimationManager::tick() {
// 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();
const auto ROUNDING = PWINDOW->rounding();
const auto ROUNDINGSIZE = ROUNDING + 1;
const auto BORDERSIZE = PWINDOW->getRealBorderSize();
// damage for old box
g_pHyprRenderer->damageBox(WLRBOXPREV.x - BORDERSIZE, WLRBOXPREV.y - BORDERSIZE, WLRBOXPREV.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // top

View File

@@ -19,13 +19,69 @@
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 +114,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();

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

@@ -7,6 +7,7 @@
#include <sys/ioctl.h>
#include <fcntl.h>
#include <vector>
#if defined(__linux__)
#include <linux/vt.h>
#elif defined(__NetBSD__) || defined(__OpenBSD__)
@@ -18,64 +19,66 @@
CKeybindManager::CKeybindManager() {
// initialize all dispatchers
m_mDispatchers["exec"] = spawn;
m_mDispatchers["execr"] = spawnRaw;
m_mDispatchers["killactive"] = killActive;
m_mDispatchers["closewindow"] = kill;
m_mDispatchers["togglefloating"] = toggleActiveFloating;
m_mDispatchers["workspace"] = changeworkspace;
m_mDispatchers["renameworkspace"] = renameWorkspace;
m_mDispatchers["fullscreen"] = fullscreenActive;
m_mDispatchers["fakefullscreen"] = fakeFullscreenActive;
m_mDispatchers["movetoworkspace"] = moveActiveToWorkspace;
m_mDispatchers["movetoworkspacesilent"] = moveActiveToWorkspaceSilent;
m_mDispatchers["pseudo"] = toggleActivePseudo;
m_mDispatchers["movefocus"] = moveFocusTo;
m_mDispatchers["movewindow"] = moveActiveTo;
m_mDispatchers["swapwindow"] = swapActive;
m_mDispatchers["centerwindow"] = centerWindow;
m_mDispatchers["togglegroup"] = toggleGroup;
m_mDispatchers["changegroupactive"] = changeGroupActive;
m_mDispatchers["movegroupwindow"] = moveGroupWindow;
m_mDispatchers["togglesplit"] = toggleSplit;
m_mDispatchers["splitratio"] = alterSplitRatio;
m_mDispatchers["focusmonitor"] = focusMonitor;
m_mDispatchers["movecursortocorner"] = moveCursorToCorner;
m_mDispatchers["movecursor"] = moveCursor;
m_mDispatchers["workspaceopt"] = workspaceOpt;
m_mDispatchers["exit"] = exitHyprland;
m_mDispatchers["movecurrentworkspacetomonitor"] = moveCurrentWorkspaceToMonitor;
m_mDispatchers["moveworkspacetomonitor"] = moveWorkspaceToMonitor;
m_mDispatchers["togglespecialworkspace"] = toggleSpecialWorkspace;
m_mDispatchers["forcerendererreload"] = forceRendererReload;
m_mDispatchers["resizeactive"] = resizeActive;
m_mDispatchers["moveactive"] = moveActive;
m_mDispatchers["cyclenext"] = circleNext;
m_mDispatchers["focuswindowbyclass"] = focusWindow;
m_mDispatchers["focuswindow"] = focusWindow;
m_mDispatchers["submap"] = setSubmap;
m_mDispatchers["pass"] = pass;
m_mDispatchers["layoutmsg"] = layoutmsg;
m_mDispatchers["toggleopaque"] = toggleOpaque;
m_mDispatchers["dpms"] = dpms;
m_mDispatchers["movewindowpixel"] = moveWindow;
m_mDispatchers["resizewindowpixel"] = resizeWindow;
m_mDispatchers["swapnext"] = swapnext;
m_mDispatchers["swapactiveworkspaces"] = swapActiveWorkspaces;
m_mDispatchers["pin"] = pinActive;
m_mDispatchers["mouse"] = mouse;
m_mDispatchers["bringactivetotop"] = bringActiveToTop;
m_mDispatchers["alterzorder"] = alterZOrder;
m_mDispatchers["focusurgentorlast"] = focusUrgentOrLast;
m_mDispatchers["focuscurrentorlast"] = focusCurrentOrLast;
m_mDispatchers["lockgroups"] = lockGroups;
m_mDispatchers["lockactivegroup"] = lockActiveGroup;
m_mDispatchers["moveintogroup"] = moveIntoGroup;
m_mDispatchers["moveoutofgroup"] = moveOutOfGroup;
m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup;
m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock;
m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup;
m_mDispatchers["global"] = global;
m_mDispatchers["exec"] = spawn;
m_mDispatchers["execr"] = spawnRaw;
m_mDispatchers["killactive"] = killActive;
m_mDispatchers["closewindow"] = kill;
m_mDispatchers["togglefloating"] = toggleActiveFloating;
m_mDispatchers["workspace"] = changeworkspace;
m_mDispatchers["renameworkspace"] = renameWorkspace;
m_mDispatchers["fullscreen"] = fullscreenActive;
m_mDispatchers["fakefullscreen"] = fakeFullscreenActive;
m_mDispatchers["movetoworkspace"] = moveActiveToWorkspace;
m_mDispatchers["movetoworkspacesilent"] = moveActiveToWorkspaceSilent;
m_mDispatchers["pseudo"] = toggleActivePseudo;
m_mDispatchers["movefocus"] = moveFocusTo;
m_mDispatchers["movewindow"] = moveActiveTo;
m_mDispatchers["swapwindow"] = swapActive;
m_mDispatchers["centerwindow"] = centerWindow;
m_mDispatchers["togglegroup"] = toggleGroup;
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;
m_mDispatchers["movecursor"] = moveCursor;
m_mDispatchers["workspaceopt"] = workspaceOpt;
m_mDispatchers["exit"] = exitHyprland;
m_mDispatchers["movecurrentworkspacetomonitor"] = moveCurrentWorkspaceToMonitor;
m_mDispatchers["focusworkspaceoncurrentmonitor"] = focusWorkspaceOnCurrentMonitor;
m_mDispatchers["moveworkspacetomonitor"] = moveWorkspaceToMonitor;
m_mDispatchers["togglespecialworkspace"] = toggleSpecialWorkspace;
m_mDispatchers["forcerendererreload"] = forceRendererReload;
m_mDispatchers["resizeactive"] = resizeActive;
m_mDispatchers["moveactive"] = moveActive;
m_mDispatchers["cyclenext"] = circleNext;
m_mDispatchers["focuswindowbyclass"] = focusWindow;
m_mDispatchers["focuswindow"] = focusWindow;
m_mDispatchers["submap"] = setSubmap;
m_mDispatchers["pass"] = pass;
m_mDispatchers["layoutmsg"] = layoutmsg;
m_mDispatchers["toggleopaque"] = toggleOpaque;
m_mDispatchers["dpms"] = dpms;
m_mDispatchers["movewindowpixel"] = moveWindow;
m_mDispatchers["resizewindowpixel"] = resizeWindow;
m_mDispatchers["swapnext"] = swapnext;
m_mDispatchers["swapactiveworkspaces"] = swapActiveWorkspaces;
m_mDispatchers["pin"] = pinActive;
m_mDispatchers["mouse"] = mouse;
m_mDispatchers["bringactivetotop"] = bringActiveToTop;
m_mDispatchers["alterzorder"] = alterZOrder;
m_mDispatchers["focusurgentorlast"] = focusUrgentOrLast;
m_mDispatchers["focuscurrentorlast"] = focusCurrentOrLast;
m_mDispatchers["lockgroups"] = lockGroups;
m_mDispatchers["lockactivegroup"] = lockActiveGroup;
m_mDispatchers["moveintogroup"] = moveIntoGroup;
m_mDispatchers["moveoutofgroup"] = moveOutOfGroup;
m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup;
m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock;
m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup;
m_mDispatchers["global"] = global;
m_tScrollTimer.reset();
@@ -95,7 +98,7 @@ void CKeybindManager::addKeybind(SKeybind kb) {
void CKeybindManager::removeKeybind(uint32_t mod, const std::string& key) {
for (auto it = m_lKeybinds.begin(); it != m_lKeybinds.end(); ++it) {
if (isNumber(key) && std::stoi(key) > 9) {
const auto KEYNUM = std::stoi(key);
const uint32_t KEYNUM = std::stoi(key);
if (it->modmask == mod && it->keycode == KEYNUM) {
it = m_lKeybinds.erase(it);
@@ -137,6 +140,22 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
return modMask;
}
uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) {
switch (keycode - 8) {
case KEY_LEFTMETA: return WLR_MODIFIER_LOGO;
case KEY_RIGHTMETA: return WLR_MODIFIER_LOGO;
case KEY_LEFTSHIFT: return WLR_MODIFIER_SHIFT;
case KEY_RIGHTSHIFT: return WLR_MODIFIER_SHIFT;
case KEY_LEFTCTRL: return WLR_MODIFIER_CTRL;
case KEY_RIGHTCTRL: return WLR_MODIFIER_CTRL;
case KEY_LEFTALT: return WLR_MODIFIER_ALT;
case KEY_RIGHTALT: return WLR_MODIFIER_ALT;
case KEY_CAPSLOCK: return WLR_MODIFIER_CAPS;
case KEY_NUMLOCK: return WLR_MODIFIER_MOD2;
default: return 0;
}
}
void CKeybindManager::updateXKBTranslationState() {
if (m_pXKBTranslationState) {
xkb_keymap_unref(xkb_state_get_keymap(m_pXKBTranslationState));
@@ -145,19 +164,26 @@ 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* const PFILEPATH = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("input:kb_file");
static auto* const PRULES = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("input:kb_rules");
static auto* const PMODEL = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("input:kb_model");
static auto* const PLAYOUT = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("input:kb_layout");
static auto* const PVARIANT = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("input:kb_variant");
static auto* const POPTIONS = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("input:kb_options");
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);
FILE* const KEYMAPFILE = FILEPATH == "" ? NULL : fopen(absolutePath(FILEPATH, g_pConfigManager->configCurrentPath).c_str(), "r");
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;
auto PKEYMAP = KEYMAPFILE ? xkb_keymap_new_from_file(PCONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS) :
xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
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);
FILE* const KEYMAPFILE = FILEPATH == "" ? NULL : fopen(absolutePath(FILEPATH, g_pConfigManager->configCurrentPath).c_str(), "r");
auto PKEYMAP = KEYMAPFILE ? xkb_keymap_new_from_file(PCONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS) :
xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (KEYMAPFILE)
fclose(KEYMAPFILE);
@@ -261,8 +287,7 @@ void CKeybindManager::switchToWindow(CWindow* PWINDOWTOCHANGETO) {
bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
if (!g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
m_dPressedKeycodes.clear();
m_dPressedKeysyms.clear();
m_dPressedKeys.clear();
return true;
}
@@ -279,7 +304,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))
@@ -291,9 +316,16 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
m_uLastCode = KEYCODE;
m_uLastMouseCode = 0;
bool mouseBindWasActive = ensureMouseBindState();
bool mouseBindWasActive = ensureMouseBindState();
bool found = false;
const auto KEY = SPressedKeyWithMods{
.keysym = keysym,
.keycode = KEYCODE,
.modmaskAtPressTime = MODS,
.sent = true,
};
bool suppressEvent = false;
if (e->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
// clean repeat
if (m_pActiveKeybindEventSource) {
@@ -302,16 +334,15 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
m_pActiveKeybind = nullptr;
}
m_dPressedKeycodes.push_back(KEYCODE);
m_dPressedKeysyms.push_back(keysym);
m_dPressedKeys.push_back(KEY);
found = handleKeybinds(MODS, "", keysym, 0, true, e->time_msec) || found;
suppressEvent = handleKeybinds(MODS, KEY, true);
found = handleKeybinds(MODS, "", 0, KEYCODE, true, e->time_msec) || found;
if (found)
if (suppressEvent)
shadowKeybinds(keysym, KEYCODE);
} else if (e->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
m_dPressedKeys.back().sent = !suppressEvent;
} else { // key release
// clean repeat
if (m_pActiveKeybindEventSource) {
wl_event_source_remove(m_pActiveKeybindEventSource);
@@ -319,25 +350,35 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
m_pActiveKeybind = nullptr;
}
m_dPressedKeycodes.erase(std::remove(m_dPressedKeycodes.begin(), m_dPressedKeycodes.end(), KEYCODE), m_dPressedKeycodes.end());
m_dPressedKeysyms.erase(std::remove(m_dPressedKeysyms.begin(), m_dPressedKeysyms.end(), keysym), m_dPressedKeysyms.end());
found = handleKeybinds(MODS, "", keysym, 0, false, e->time_msec) || found;
found = handleKeybinds(MODS, "", 0, KEYCODE, false, e->time_msec) || found;
bool foundInPressedKeys = false;
for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) {
if (it->keycode == KEYCODE) {
suppressEvent = handleKeybinds(MODS, *it, false);
foundInPressedKeys = true;
suppressEvent = !it->sent;
it = m_dPressedKeys.erase(it);
} else {
++it;
}
}
if (!foundInPressedKeys) {
Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys");
// fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy
suppressEvent = handleKeybinds(MODS, KEY, false);
}
shadowKeybinds();
}
return !found && !mouseBindWasActive;
return !suppressEvent && !mouseBindWasActive;
}
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* const PDELAY = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:scroll_event_delay");
if (m_tScrollTimer.getMillis() < *PDELAY) {
if (m_tScrollTimer.getMillis() < **PDELAY) {
m_tScrollTimer.reset();
return true; // timer hasn't passed yet!
}
@@ -347,14 +388,14 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
bool found = false;
if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_VERTICAL) {
if (e->delta < 0)
found = handleKeybinds(MODS, "mouse_down", 0, 0, true, 0);
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true);
else
found = handleKeybinds(MODS, "mouse_up", 0, 0, true, 0);
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true);
} else if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_HORIZONTAL) {
if (e->delta < 0)
found = handleKeybinds(MODS, "mouse_left", 0, 0, true, 0);
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true);
else
found = handleKeybinds(MODS, "mouse_right", 0, 0, true, 0);
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true);
}
if (found)
@@ -366,26 +407,52 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
bool found = false;
bool suppressEvent = false;
m_uLastMouseCode = e->button;
m_uLastCode = 0;
m_uTimeLastMs = e->time_msec;
bool mouseBindWasActive = ensureMouseBindState();
bool mouseBindWasActive = ensureMouseBindState();
const auto KEY_NAME = "mouse:" + std::to_string(e->button);
const auto KEY = SPressedKeyWithMods{
.keyName = KEY_NAME,
.modmaskAtPressTime = MODS,
};
if (e->state == WLR_BUTTON_PRESSED) {
found = handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, true, 0);
m_dPressedKeys.push_back(KEY);
if (found)
suppressEvent = handleKeybinds(MODS, KEY, true);
if (suppressEvent)
shadowKeybinds();
m_dPressedKeys.back().sent = !suppressEvent;
} else {
found = handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, false, 0);
bool foundInPressedKeys = false;
for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) {
if (it->keyName == KEY_NAME) {
suppressEvent = handleKeybinds(MODS, *it, false);
foundInPressedKeys = true;
suppressEvent = !it->sent;
it = m_dPressedKeys.erase(it);
} else {
++it;
}
}
if (!foundInPressedKeys) {
Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys (2)");
// fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy
suppressEvent = handleKeybinds(MODS, KEY, false);
}
shadowKeybinds();
}
return !found && !mouseBindWasActive;
return !suppressEvent && !mouseBindWasActive;
}
void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) {
@@ -397,15 +464,15 @@ void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) {
}
void CKeybindManager::onSwitchEvent(const std::string& switchName) {
handleKeybinds(0, "switch:" + switchName, 0, 0, true, 0);
handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:" + switchName}, true);
}
void CKeybindManager::onSwitchOnEvent(const std::string& switchName) {
handleKeybinds(0, "switch:on:" + switchName, 0, 0, true, 0);
handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:on:" + switchName}, true);
}
void CKeybindManager::onSwitchOffEvent(const std::string& switchName) {
handleKeybinds(0, "switch:off:" + switchName, 0, 0, true, 0);
handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:off:" + switchName}, true);
}
int repeatKeyHandler(void* data) {
@@ -424,12 +491,21 @@ int repeatKeyHandler(void* data) {
return 0;
}
bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string& key, const xkb_keysym_t& keysym, const int& keycode, bool pressed, uint32_t time) {
bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) {
bool found = false;
if (g_pCompositor->m_sSeat.exclusiveClient)
Debug::log(LOG, "Keybind handling only locked (inhibitor)");
if (!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 =
@@ -441,22 +517,31 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
((modmask != k.modmask && !k.ignoreMods) || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap || k.shadowed))
continue;
if (!key.empty()) {
if (key != k.key)
if (!key.keyName.empty()) {
if (key.keyName != k.key)
continue;
} else if (k.keycode != -1) {
if (keycode != k.keycode)
} else if (k.keycode != 0) {
if (key.keycode != k.keycode)
continue;
} else {
if (keysym == 0)
continue; // this is a keycode check run
// 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);
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 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 (keysym != KBKEY && keysym != KBKEYUPPER)
if (key.keysym != KBKEY && key.keysym != KBKEYUPPER)
continue;
}
@@ -468,12 +553,24 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
continue;
}
if (!pressed && !k.release && !SPECIALDISPATCHER) {
if (k.nonConsuming)
continue;
if (!pressed) {
// Require mods to be matching when the key was first pressed.
if (key.modmaskAtPressTime != modmask && !k.ignoreMods) {
// Handle properly `bindr` where a key is itself a bind mod for example:
// "bindr = SUPER, SUPER_L, exec, $launcher".
// This needs to be handled separately for the above case, because `key.modmaskAtPressTime` is set
// from currently pressed keys as programs see them, but it doesn't yet include the currently
// pressed mod key, which is still being handled internally.
if (keycodeToModifier(key.keycode) == key.modmaskAtPressTime)
continue;
found = true; // suppress the event
continue;
} else if (!k.release && !SPECIALDISPATCHER) {
if (k.nonConsuming)
continue;
found = true; // suppress the event
continue;
}
}
const auto DISPATCHER = m_mDispatchers.find(k.mouse ? "mouse" : k.handler);
@@ -488,7 +585,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
Debug::log(ERR, "Invalid handler in a keybind! (handler {} does not exist)", k.handler);
} else {
// call the dispatcher
Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {})", modmask, key, keysym);
Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {})", modmask, key.keyName, key.keysym);
m_iPassPressed = (int)pressed;
@@ -521,7 +618,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
return found;
}
void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const int& doesntHaveCode) {
void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint32_t doesntHaveCode) {
// shadow disables keybinds after one has been triggered
for (auto& k : m_lKeybinds) {
@@ -534,22 +631,20 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const int&
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY);
for (auto& pk : m_dPressedKeysyms) {
if ((pk == KBKEY || pk == KBKEYUPPER)) {
for (auto& pk : m_dPressedKeys) {
if ((pk.keysym != 0 && (pk.keysym == KBKEY || pk.keysym == KBKEYUPPER))) {
shadow = true;
if (pk == doesntHave && doesntHave != 0) {
if (pk.keysym == doesntHave && doesntHave != 0) {
shadow = false;
break;
}
}
}
for (auto& pk : m_dPressedKeycodes) {
if (pk == k.keycode) {
if (pk.keycode != 0 && pk.keycode == k.keycode) {
shadow = true;
if (pk == doesntHaveCode && doesntHaveCode != 0 && doesntHaveCode != -1) {
if (pk.keycode == doesntHaveCode && doesntHaveCode != 0) {
shadow = false;
break;
}
@@ -730,7 +825,7 @@ void CKeybindManager::clearKeybinds() {
void CKeybindManager::toggleActiveFloating(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;
@@ -797,9 +892,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* const PBACKANDFORTH = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:workspace_back_and_forth");
static auto* const PALLOWWORKSPACECYCLES = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles");
static auto* const PWORKSPACECENTERON = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:workspace_center_on");
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
@@ -834,7 +929,7 @@ void CKeybindManager::changeworkspace(std::string args) {
const bool BISWORKSPACECURRENT = workspaceToChangeTo == PCURRENTWORKSPACE->m_iID;
if (BISWORKSPACECURRENT && (!(*PBACKANDFORTH || EXPLICITPREVIOUS) || PCURRENTWORKSPACE->m_sPrevWorkspace.iID == -1))
if (BISWORKSPACECURRENT && (!(**PBACKANDFORTH || EXPLICITPREVIOUS) || PCURRENTWORKSPACE->m_sPrevWorkspace.iID == -1))
return;
g_pInputManager->unconstrainMouse();
@@ -866,14 +961,14 @@ void CKeybindManager::changeworkspace(std::string args) {
Vector2D middle = PMONITORWORKSPACEOWNER->middle();
if (const auto PLAST = pWorkspaceToChangeTo->getLastFocusedWindow(); PLAST) {
g_pCompositor->focusWindow(PLAST);
if (*PWORKSPACECENTERON == 1)
if (**PWORKSPACECENTERON == 1)
middle = PLAST->middle();
}
g_pCompositor->warpCursorTo(middle);
}
if (BISWORKSPACECURRENT) {
if (*PALLOWWORKSPACECYCLES)
if (**PALLOWWORKSPACECYCLES)
pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE);
else if (!EXPLICITPREVIOUS)
pWorkspaceToChangeTo->rememberPrevWorkspace(nullptr);
@@ -897,6 +992,9 @@ void CKeybindManager::fullscreenActive(std::string args) {
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);
}
@@ -931,7 +1029,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* const PALLOWWORKSPACECYCLES = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles");
g_pHyprRenderer->damageWindow(PWINDOW);
@@ -957,7 +1055,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->warpCursorTo(PWINDOW->middle());
if (*PALLOWWORKSPACECYCLES)
if (**PALLOWWORKSPACECYCLES)
pWorkspace->rememberPrevWorkspace(POLDWS);
}
@@ -1000,14 +1098,16 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace);
}
if (const auto PATCOORDS = g_pCompositor->vectorToWindowIdeal(OLDMIDDLE); PATCOORDS && PATCOORDS != PWINDOW)
g_pCompositor->focusWindow(PATCOORDS);
else
g_pInputManager->refocus();
if (PWINDOW == g_pCompositor->m_pLastWindow) {
if (const auto PATCOORDS = g_pCompositor->vectorToWindowUnified(OLDMIDDLE, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING, PWINDOW); PATCOORDS)
g_pCompositor->focusWindow(PATCOORDS);
else
g_pInputManager->refocus();
}
}
void CKeybindManager::moveFocusTo(std::string args) {
static auto* const PFULLCYCLE = &g_pConfigManager->getConfigValuePtr("binds:movefocus_cycles_fullscreen")->intValue;
static auto* const PFULLCYCLE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:movefocus_cycles_fullscreen");
char arg = args[0];
if (!isDirection(args)) {
@@ -1024,7 +1124,7 @@ void CKeybindManager::moveFocusTo(std::string args) {
// remove constraints
g_pInputManager->unconstrainMouse();
const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->m_bIsFullscreen ?
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);
@@ -1039,8 +1139,8 @@ 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;
if (*PNOFALLBACK)
static auto* const PNOFALLBACK = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:no_focus_fallback");
if (**PNOFALLBACK)
return;
Debug::log(LOG, "No monitor found in direction {}, falling back to next window on current workspace", arg);
@@ -1218,6 +1318,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;
@@ -1385,20 +1500,24 @@ void CKeybindManager::renameWorkspace(std::string args) {
}
void CKeybindManager::exitHyprland(std::string argz) {
g_pCompositor->cleanup();
g_pInputManager->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);
}
@@ -1435,9 +1554,51 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PMONITOR);
}
void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
std::string workspaceName;
const int WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
if (WORKSPACEID == WORKSPACE_INVALID) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!");
return;
}
const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor;
if (!PCURRMONITOR) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!");
return;
}
auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
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());
return;
}
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) {
g_pCompositor->swapActiveWorkspaces(POLDMONITOR, PCURRMONITOR);
return;
} else {
g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PCURRMONITOR, true);
}
}
changeworkspace(PWORKSPACE->getConfigName());
}
void CKeybindManager::toggleSpecialWorkspace(std::string args) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
static auto* const PFOLLOWMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:follow_mouse");
std::string workspaceName = "";
int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName);
@@ -1448,7 +1609,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 = **PFOLLOWMOUSE == 1 ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->m_pLastMonitor;
int specialOpenOnMonitor = PMONITOR->specialWorkspaceID;
for (auto& m : g_pCompositor->m_vMonitors) {
@@ -1480,7 +1641,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;
@@ -1596,17 +1757,40 @@ void CKeybindManager::focusWindow(std::string regexp) {
Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle);
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");
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
if (!PWORKSPACE) {
Debug::log(ERR, "BUG THIS: null workspace in focusWindow");
return;
}
changeworkspace(PWORKSPACE->getConfigName());
}
g_pCompositor->focusWindow(PWINDOW);
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());
}
@@ -1742,11 +1926,11 @@ void CKeybindManager::dpms(std::string arg) {
if (!port.empty() && m->szName != port)
continue;
wlr_output_enable(m->output, enable);
wlr_output_state_set_enabled(m->state.wlr(), enable);
m->dpmsStatus = enable;
if (!wlr_output_commit(m->output)) {
if (!m->state.commit()) {
Debug::log(ERR, "Couldn't commit output {}", m->szName);
}
@@ -1808,7 +1992,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;
@@ -1829,7 +2013,7 @@ void CKeybindManager::pinActive(std::string args) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal());
PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS);
}
void CKeybindManager::mouse(std::string args) {
@@ -1841,7 +2025,7 @@ void CKeybindManager::mouse(std::string args) {
g_pKeybindManager->m_bIsMouseBindActive = true;
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
CWindow* pWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (pWindow && !pWindow->m_bIsFullscreen)
pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_START, mouseCoords);
@@ -1864,7 +2048,8 @@ void CKeybindManager::mouse(std::string args) {
if (PRESSED) {
g_pKeybindManager->m_bIsMouseBindActive = true;
g_pInputManager->currentlyDraggedWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
g_pInputManager->currentlyDraggedWindow =
g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
try {
switch (std::stoi(ARGS[1])) {
@@ -1959,8 +2144,8 @@ 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;
pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail();
static const auto* USECURRPOS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("group:insert_after_current");
pWindowInDirection = **USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail();
pWindowInDirection->insertWindowToGroup(pWindow);
pWindowInDirection->setGroupCurrent(pWindow);
@@ -1974,7 +2159,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* const BFOCUSREMOVEDWINDOW = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("group:focus_removed_window");
const auto PWINDOWPREV = pWindow->getGroupPrevious();
eDirection direction;
@@ -2001,7 +2186,7 @@ void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string&
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
}
if (*BFOCUSREMOVEDWINDOW) {
if (**BFOCUSREMOVEDWINDOW) {
g_pCompositor->focusWindow(pWindow);
g_pCompositor->warpCursorTo(pWindow->middle());
} else {
@@ -2013,9 +2198,9 @@ 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* const PIGNOREGROUPLOCK = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock");
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked)
if (!**PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked)
return;
if (!isDirection(args)) {
@@ -2034,19 +2219,24 @@ void CKeybindManager::moveIntoGroup(std::string args) {
return;
// Do not move window into locked group if binds:ignore_group_lock is false
if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->getGroupHead()->m_sGroupData.locked)))
if (!**PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->getGroupHead()->m_sGroupData.locked)))
return;
moveWindowIntoGroup(PWINDOW, PWINDOWINDIR);
}
void CKeybindManager::moveOutOfGroup(std::string args) {
static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue;
static auto* const PIGNOREGROUPLOCK = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock");
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked)
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;
@@ -2057,7 +2247,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* const PIGNOREGROUPLOCK = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("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);
@@ -2068,7 +2258,7 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
if (!PWINDOW || PWINDOW->m_bIsFullscreen)
return;
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) {
if (!**PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
return;
}
@@ -2081,32 +2271,36 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
// note: PWINDOWINDIR is not null implies !PWINDOW->m_bIsFloating
if (PWINDOWINDIR && PWINDOWINDIR->m_sGroupData.pNextWindow) { // target is group
if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || ISWINDOWGROUPLOCKED || PWINDOW->m_sGroupData.deny)) {
if (!**PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || ISWINDOWGROUPLOCKED || PWINDOW->m_sGroupData.deny)) {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
g_pCompositor->warpCursorTo(PWINDOW->middle());
} else
moveWindowIntoGroup(PWINDOW, PWINDOWINDIR);
} else if (PWINDOWINDIR) { // target is regular window
if ((!*PIGNOREGROUPLOCK && ISWINDOWGROUPLOCKED) || !ISWINDOWGROUP || (ISWINDOWGROUPSINGLE && PWINDOW->m_eGroupRules & GROUP_SET_ALWAYS)) {
if ((!**PIGNOREGROUPLOCK && ISWINDOWGROUPLOCKED) || !ISWINDOWGROUP || (ISWINDOWGROUPSINGLE && PWINDOW->m_eGroupRules & GROUP_SET_ALWAYS)) {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, 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* const BIGNOREGROUPLOCK = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock");
if (args == "toggle")
*BIGNOREGROUPLOCK = !*BIGNOREGROUPLOCK;
**BIGNOREGROUPLOCK = !*BIGNOREGROUPLOCK;
else
*BIGNOREGROUPLOCK = args == "on";
**BIGNOREGROUPLOCK = args == "on";
g_pEventManager->postEvent(SHyprIPCEvent{"ignoregrouplock", std::to_string(*BIGNOREGROUPLOCK)});
g_pEventManager->postEvent(SHyprIPCEvent{"ignoregrouplock", std::to_string(**BIGNOREGROUPLOCK)});
}
void CKeybindManager::denyWindowFromGroup(std::string args) {

View File

@@ -12,7 +12,7 @@ class CPluginSystem;
struct SKeybind {
std::string key = "";
int keycode = -1;
uint32_t keycode = 0;
uint32_t modmask = 0;
std::string handler = "";
std::string arg = "";
@@ -36,6 +36,14 @@ enum eFocusWindowMode {
MODE_PID
};
struct SPressedKeyWithMods {
std::string keyName = "";
xkb_keysym_t keysym = 0;
uint32_t keycode = 0;
uint32_t modmaskAtPressTime = 0;
bool sent = false;
};
class CKeybindManager {
public:
CKeybindManager();
@@ -51,8 +59,9 @@ class CKeybindManager {
void addKeybind(SKeybind);
void removeKeybind(uint32_t, const std::string&);
uint32_t stringToModMask(std::string);
uint32_t keycodeToModifier(xkb_keycode_t);
void clearKeybinds();
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const int& doesntHaveCode = 0);
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0);
std::unordered_map<std::string, std::function<void(std::string)>> m_mDispatchers;
@@ -61,40 +70,40 @@ class CKeybindManager {
bool m_bGroupsLocked = false;
std::list<SKeybind> m_lKeybinds;
std::list<SShortcutInhibitor> m_lShortcutInhibitors;
private:
std::deque<xkb_keysym_t> m_dPressedKeysyms;
std::deque<int> m_dPressedKeycodes;
std::deque<SPressedKeyWithMods> m_dPressedKeys;
inline static std::string m_szCurrentSelectedSubmap = "";
inline static std::string m_szCurrentSelectedSubmap = "";
SKeybind* m_pActiveKeybind = nullptr;
SKeybind* m_pActiveKeybind = nullptr;
uint32_t m_uTimeLastMs = 0;
uint32_t m_uLastCode = 0;
uint32_t m_uLastMouseCode = 0;
uint32_t m_uTimeLastMs = 0;
uint32_t m_uLastCode = 0;
uint32_t m_uLastMouseCode = 0;
bool m_bIsMouseBindActive = false;
std::vector<SKeybind*> m_vPressedSpecialBinds;
bool m_bIsMouseBindActive = false;
std::vector<SKeybind*> m_vPressedSpecialBinds;
int m_iPassPressed = -1; // used for pass
int m_iPassPressed = -1; // used for pass
CTimer m_tScrollTimer;
CTimer m_tScrollTimer;
bool handleKeybinds(const uint32_t&, const std::string&, const xkb_keysym_t&, const int&, bool, uint32_t);
bool handleKeybinds(const uint32_t, const SPressedKeyWithMods&, bool);
bool handleInternalKeybinds(xkb_keysym_t);
bool handleVT(xkb_keysym_t);
bool handleInternalKeybinds(xkb_keysym_t);
bool handleVT(xkb_keysym_t);
xkb_state* m_pXKBTranslationState = nullptr;
xkb_state* m_pXKBTranslationState = nullptr;
void updateXKBTranslationState();
bool ensureMouseBindState();
void updateXKBTranslationState();
bool ensureMouseBindState();
static bool tryMoveFocusToMonitor(CMonitor* monitor);
static void moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir = "");
static void moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection);
static void switchToWindow(CWindow* PWINDOWTOCHANGETO);
static bool tryMoveFocusToMonitor(CMonitor* monitor);
static void moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir = "");
static void moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection);
static void switchToWindow(CWindow* PWINDOWTOCHANGETO);
// -------------- Dispatchers -------------- //
static void killActive(std::string);
@@ -119,6 +128,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);
@@ -126,6 +136,7 @@ class CKeybindManager {
static void exitHyprland(std::string);
static void moveCurrentWorkspaceToMonitor(std::string);
static void moveWorkspaceToMonitor(std::string);
static void focusWorkspaceOnCurrentMonitor(std::string);
static void toggleSpecialWorkspace(std::string);
static void forceRendererReload(std::string);
static void resizeActive(std::string);

View File

@@ -44,9 +44,9 @@ 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* const PALLOWRELOCK = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:allow_session_lock_restore");
if (m_sSessionLock.active && (!*PALLOWRELOCK || m_sSessionLock.pWlrLock)) {
if (m_sSessionLock.active && (!**PALLOWRELOCK || m_sSessionLock.pWlrLock)) {
Debug::log(LOG, "Attempted to lock a locked session!");
wlr_session_lock_v1_destroy(pWlrLock);
return;
@@ -75,6 +75,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");

View File

@@ -7,9 +7,9 @@ int slowUpdate = 0;
int handleTimer(void* data) {
const auto PTM = (CThreadManager*)data;
static auto* const PDISABLECFGRELOAD = &g_pConfigManager->getConfigValuePtr("misc:disable_autoreload")->intValue;
static auto* const PDISABLECFGRELOAD = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:disable_autoreload");
if (*PDISABLECFGRELOAD != 1)
if (**PDISABLECFGRELOAD != 1)
g_pConfigManager->tick();
wl_event_source_timer_update(PTM->m_esConfigTimer, 1000);
@@ -18,8 +18,6 @@ int handleTimer(void* data) {
}
CThreadManager::CThreadManager() {
HyprCtl::startHyprCtlSocket();
m_esConfigTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleTimer, this);
wl_event_source_timer_update(m_esConfigTimer, 1000);

View File

@@ -147,17 +147,19 @@ void CHyprXWaylandManager::sendCloseWindow(CWindow* pWindow) {
void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool force) {
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");
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
size = size.clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
// calculate pos
// TODO: this should be decoupled from setWindowSize IMO
Vector2D windowPos = pWindow->m_vRealPosition.vec();
if (pWindow->m_bIsX11 && PMONITOR) {
windowPos = windowPos - PMONITOR->vecPosition; // normalize to monitor
if (*PXWLFORCESCALEZERO)
if (**PXWLFORCESCALEZERO)
windowPos = windowPos * PMONITOR->scale; // scale if applicable
windowPos = windowPos + PMONITOR->vecXWaylandPosition; // move to correct position for xwayland
}
@@ -170,7 +172,7 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f
pWindow->m_fX11SurfaceScaledBy = 1.f;
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11 && PMONITOR) {
if (**PXWLFORCESCALEZERO && pWindow->m_bIsX11 && PMONITOR) {
size = size * PMONITOR->scale;
pWindow->m_fX11SurfaceScaledBy = PMONITOR->scale;
}
@@ -315,12 +317,12 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(CWindow* pWindow) {
Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) {
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");
CMonitor* pMonitor = nullptr;
double bestDistance = __FLT_MAX__;
for (auto& m : g_pCompositor->m_vMonitors) {
const auto SIZ = *PXWLFORCESCALEZERO ? m->vecTransformedSize : m->vecSize;
const auto SIZ = **PXWLFORCESCALEZERO ? m->vecTransformedSize : m->vecSize;
double distance =
vecToRectDistanceSquared(coord, {m->vecXWaylandPosition.x, m->vecXWaylandPosition.y}, {m->vecXWaylandPosition.x + SIZ.x - 1, m->vecXWaylandPosition.y + SIZ.y - 1});
@@ -337,7 +339,7 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) {
// get local coords
Vector2D result = coord - pMonitor->vecXWaylandPosition;
// if scaled, unscale
if (*PXWLFORCESCALEZERO)
if (**PXWLFORCESCALEZERO)
result = result / pMonitor->scale;
// add pos
result = result + pMonitor->vecPosition;

View File

@@ -16,20 +16,20 @@ CInputManager::~CInputManager() {
}
void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) {
static auto* const PSENS = &g_pConfigManager->getConfigValuePtr("general:sensitivity")->floatValue;
static auto* const PNOACCEL = &g_pConfigManager->getConfigValuePtr("input:force_no_accel")->intValue;
static auto* const PSENSTORAW = &g_pConfigManager->getConfigValuePtr("general:apply_sens_to_raw")->intValue;
static auto* const PSENS = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("general:sensitivity");
static auto* const PNOACCEL = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:force_no_accel");
static auto* const PSENSTORAW = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:apply_sens_to_raw");
const auto DELTA = *PNOACCEL == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y);
const auto DELTA = **PNOACCEL == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y);
if (*PSENSTORAW == 1)
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x * *PSENS,
DELTA.y * *PSENS, e->unaccel_dx * *PSENS, e->unaccel_dy * *PSENS);
if (**PSENSTORAW == 1)
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x * **PSENS,
DELTA.y * **PSENS, e->unaccel_dx * **PSENS, e->unaccel_dy * **PSENS);
else
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x, DELTA.y,
e->unaccel_dx, e->unaccel_dy);
wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * *PSENS, DELTA.y * *PSENS);
wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * **PSENS, DELTA.y * **PSENS);
mouseMoveUnified(e->time_msec);
@@ -73,17 +73,17 @@ void CInputManager::sendMotionEventsToFocused() {
}
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
static auto* const PMOUSEREFOCUS = &g_pConfigManager->getConfigValuePtr("input:mouse_refocus")->intValue;
static auto* const PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue;
static auto* const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
static auto* const PFLOATBEHAVIOR = &g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus")->intValue;
static auto* const PMOUSEFOCUSMON = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_focuses_monitor")->intValue;
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
static auto* const PRESIZECURSORICON = &g_pConfigManager->getConfigValuePtr("general:hover_icon_on_border")->intValue;
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
static auto* const PFOLLOWMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:follow_mouse");
static auto* const PMOUSEREFOCUS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:mouse_refocus");
static auto* const PMOUSEDPMS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms");
static auto* const PFOLLOWONDND = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd");
static auto* const PFLOATBEHAVIOR = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus");
static auto* const PMOUSEFOCUSMON = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:mouse_move_focuses_monitor");
static auto* const PRESIZEONBORDER = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:resize_on_border");
static auto* const PRESIZECURSORICON = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:hover_icon_on_border");
static auto* const PZOOMFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor");
const auto FOLLOWMOUSE = *PFOLLOWONDND && m_sDrag.drag ? 1 : *PFOLLOWMOUSE;
const auto FOLLOWMOUSE = **PFOLLOWONDND && m_sDrag.drag ? 1 : **PFOLLOWMOUSE;
m_pFoundSurfaceToFocus = nullptr;
m_pFoundLSToFocus = nullptr;
@@ -97,7 +97,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState)
return;
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) {
if (!g_pCompositor->m_bDPMSStateON && **PMOUSEDPMS) {
// enable dpms
g_pKeybindManager->dpms("on");
}
@@ -121,7 +121,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (PMONITOR == nullptr)
return;
if (*PZOOMFACTOR != 1.f)
if (**PZOOMFACTOR != 1.f)
g_pHyprRenderer->damageMonitor(PMONITOR);
if (!PMONITOR->solitaryClient && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0)
@@ -220,7 +220,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal());
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor && (*PMOUSEFOCUSMON || refocus))
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor && (**PMOUSEFOCUSMON || refocus))
g_pCompositor->setActiveMonitor(PMONITOR);
if (g_pSessionLockManager->isSessionLocked()) {
@@ -261,7 +261,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return;
}
const auto PWINDOWIDEAL = g_pCompositor->vectorToWindowIdeal(mouseCoords);
const auto PWINDOWIDEAL = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (PWINDOWIDEAL &&
((PWINDOWIDEAL->m_bIsFloating && PWINDOWIDEAL->m_bCreatedOverFullscreen) /* floating over fullscreen */
@@ -282,19 +282,19 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
if (PMONITOR->specialWorkspaceID) {
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (pFoundWindow && !g_pCompositor->isWorkspaceSpecial(pFoundWindow->m_iWorkspaceID)) {
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
}
} else {
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen))
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
}
} else {
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
}
if (pFoundWindow) {
@@ -315,11 +315,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
foundSurface =
g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface);
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor);
if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0)
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor);
if (!foundSurface) {
if (!m_bEmptyFocusCursorSet) {
if (*PRESIZEONBORDER && *PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) {
if (**PRESIZEONBORDER && **PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) {
m_eBorderIconDirection = BORDERICON_NONE;
unsetCursorImage();
}
@@ -389,7 +390,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (pFoundWindow) {
// change cursor icon if hovering over border
if (*PRESIZEONBORDER && *PRESIZECURSORICON) {
if (**PRESIZEONBORDER && **PRESIZECURSORICON) {
if (!pFoundWindow->m_bIsFullscreen && !pFoundWindow->hasPopupAt(mouseCoords)) {
setCursorIconOnBorder(pFoundWindow);
} else if (m_eBorderIconDirection != BORDERICON_NONE) {
@@ -399,7 +400,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (FOLLOWMOUSE != 1 && !refocus) {
if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow &&
((pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR == 2) || (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR != 0))) {
((pFoundWindow->m_bIsFloating && **PFLOATBEHAVIOR == 2) || (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && **PFLOATBEHAVIOR != 0))) {
// enter if change floating style
if (FOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
@@ -421,15 +422,23 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
m_bLastFocusOnLS = false;
return; // don't enter any new surfaces
} else {
if (((FOLLOWMOUSE != 3 && allowKeyboardRefocus) && (*PMOUSEREFOCUS || m_pLastMouseFocus != pFoundWindow)) || refocus) {
m_pLastMouseFocus = pFoundWindow;
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
if (allowKeyboardRefocus && ((FOLLOWMOUSE != 3 && (*PMOUSEREFOCUS || m_pLastMouseFocus != pFoundWindow)) || refocus)) {
if (m_pLastMouseFocus != pFoundWindow || g_pCompositor->m_pLastWindow != pFoundWindow || g_pCompositor->m_pLastFocus != foundSurface || refocus) {
m_pLastMouseFocus = pFoundWindow;
// TODO: this looks wrong. When over a popup, it constantly is switching.
// Temp fix until that's figured out. Otherwise spams windowrule lookups and other shit.
if (m_pLastMouseFocus != pFoundWindow || g_pCompositor->m_pLastWindow != pFoundWindow)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
else
g_pCompositor->focusSurface(foundSurface, pFoundWindow);
}
}
}
m_bLastFocusOnLS = false;
} else {
if (*PRESIZEONBORDER && *PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) {
if (**PRESIZEONBORDER && **PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) {
m_eBorderIconDirection = BORDERICON_NONE;
unsetCursorImage();
}
@@ -486,11 +495,18 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
if (!cursorImageUnlocked())
return;
Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e->surface);
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
m_sCursorSurfaceInfo.wlSurface.unassign();
if (e->surface != m_sCursorSurfaceInfo.wlSurface.wlr()) {
m_sCursorSurfaceInfo.wlSurface.unassign();
if (e->surface)
m_sCursorSurfaceInfo.wlSurface.assign(e->surface);
}
if (e->surface) {
m_sCursorSurfaceInfo.wlSurface.assign(e->surface);
m_sCursorSurfaceInfo.vHotspot = {e->hotspot_x, e->hotspot_y};
m_sCursorSurfaceInfo.hidden = false;
} else {
@@ -509,6 +525,8 @@ void CInputManager::processMouseRequest(wlr_cursor_shape_manager_v1_request_set_
if (!cursorImageUnlocked())
return;
Debug::log(LOG, "cursorImage request: shape {}", (uint32_t)e->shape);
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
m_sCursorSurfaceInfo.wlSurface.unassign();
m_sCursorSurfaceInfo.vHotspot = {};
@@ -587,26 +605,26 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
// notify the keybind manager
static auto* const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue;
static auto* const PPASSMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound");
const auto PASS = g_pKeybindManager->onMouseEvent(e);
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
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;
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
static auto* const PFOLLOWMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:follow_mouse");
static auto* const PRESIZEONBORDER = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:resize_on_border");
static auto* const PBORDERSIZE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:border_size");
static auto* const PBORDERGRABEXTEND = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area");
const auto BORDER_GRAB_AREA = **PRESIZEONBORDER ? **PBORDERSIZE + **PBORDERGRABEXTEND : 0;
if (!PASS && !*PPASSMOUSE)
if (!PASS && !**PPASSMOUSE)
return;
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
const auto w = g_pCompositor->vectorToWindowIdeal(mouseCoords);
const auto w = g_pCompositor->vectorToWindowUnified(mouseCoords, ALLOW_FLOATING | RESERVED_EXTENTS | INPUT_EXTENTS);
if (w && !m_bLastFocusOnLS && w->checkInputOnDecos(INPUT_TYPE_BUTTON, mouseCoords, e))
return;
// clicking on border triggers resize
// TODO detect click on LS properly
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e->state == WLR_BUTTON_PRESSED) {
if (**PRESIZEONBORDER && !m_bLastFocusOnLS && e->state == WLR_BUTTON_PRESSED) {
if (w && !w->m_bIsFullscreen) {
const CBox real = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA};
@@ -620,7 +638,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
switch (e->state) {
case WLR_BUTTON_PRESSED:
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
if (**PFOLLOWMOUSE == 3) // don't refocus on full loose
break;
if ((!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) /* No constraints */
@@ -645,15 +663,17 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
}
// notify app if we didnt handle it
if (g_pCompositor->doesSeatAcceptInput(g_pCompositor->m_pLastFocus)) {
if (g_pCompositor->doesSeatAcceptInput(g_pCompositor->m_pLastFocus))
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, e->time_msec, e->button, e->state);
}
if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor && PMON)
g_pCompositor->setActiveMonitor(PMON);
}
void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
switch (e->state) {
case WLR_BUTTON_PRESSED: {
const auto PWINDOW = g_pCompositor->vectorToWindowIdeal(getMouseCoordsInternal());
const auto PWINDOW = g_pCompositor->vectorToWindowUnified(getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!PWINDOW) {
Debug::log(ERR, "Cannot kill invalid window!");
@@ -673,9 +693,9 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
}
void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
static auto* const PSCROLLFACTOR = &g_pConfigManager->getConfigValuePtr("input:touchpad:scroll_factor")->floatValue;
static auto* const PSCROLLFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("input:touchpad:scroll_factor");
auto factor = (*PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : *PSCROLLFACTOR);
auto factor = (**PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : **PSCROLLFACTOR);
const auto EMAP = std::unordered_map<std::string, std::any>{{"event", e}};
EMIT_HOOK_EVENT_CANCELLABLE("mouseAxis", EMAP);
@@ -689,13 +709,14 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
if (!m_bLastFocusOnLS) {
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
const auto PWINDOW = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS);
const auto PWINDOW = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (PWINDOW && PWINDOW->checkInputOnDecos(INPUT_TYPE_AXIS, MOUSECOORDS, e))
return;
}
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source);
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source,
WLR_AXIS_RELATIVE_DIRECTION_IDENTICAL);
}
Vector2D CInputManager::getMouseCoordsInternal() {
@@ -802,7 +823,8 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
const auto REPEATRATE = g_pConfigManager->getDeviceInt(devname, "repeat_rate", "input:repeat_rate");
const auto REPEATDELAY = g_pConfigManager->getDeviceInt(devname, "repeat_delay", "input:repeat_delay");
const auto NUMLOCKON = g_pConfigManager->getDeviceInt(devname, "numlock_by_default", "input:numlock_by_default");
const auto NUMLOCKON = g_pConfigManager->getDeviceInt(devname, "numlock_by_default", "input:numlock_by_default");
const auto RESOLVEBINDSBYSYM = g_pConfigManager->getDeviceInt(devname, "resolve_binds_by_sym", "input:resolve_binds_by_sym");
const auto FILEPATH = g_pConfigManager->getDeviceString(devname, "kb_file", "input:kb_file");
const auto RULES = g_pConfigManager->getDeviceString(devname, "kb_rules", "input:kb_rules");
@@ -813,7 +835,8 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
const auto ENABLED = HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "enabled") : true;
pKeyboard->enabled = ENABLED;
pKeyboard->enabled = ENABLED;
pKeyboard->resolveBindsBySym = RESOLVEBINDSBYSYM;
try {
if (NUMLOCKON == pKeyboard->numlockOn && REPEATDELAY == pKeyboard->repeatDelay && REPEATRATE == pKeyboard->repeatRate && RULES != "" &&
@@ -885,6 +908,9 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
xkb_state_unref(pKeyboard->xkbTranslationState);
pKeyboard->xkbTranslationState = xkb_state_new(KEYMAP);
wlr_keyboard_set_keymap(wlr_keyboard_from_input_device(pKeyboard->keyboard), KEYMAP);
wlr_keyboard_modifiers wlrMods = {0};
@@ -1106,6 +1132,8 @@ void CInputManager::destroyKeyboard(SKeyboard* pKeyboard) {
pKeyboard->hyprListener_keyboardMod.removeCallback();
pKeyboard->hyprListener_keyboardKey.removeCallback();
xkb_state_unref(pKeyboard->xkbTranslationState);
if (pKeyboard->active) {
m_lKeyboards.remove(*pKeyboard);
@@ -1161,8 +1189,8 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
const auto EMAP = std::unordered_map<std::string, std::any>{{"keyboard", pKeyboard}, {"event", e}};
EMIT_HOOK_EVENT_CANCELLABLE("keyPress", EMAP);
static auto* const PDPMS = &g_pConfigManager->getConfigValuePtr("misc:key_press_enables_dpms")->intValue;
if (*PDPMS && !g_pCompositor->m_bDPMSStateON) {
static auto* const PDPMS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:key_press_enables_dpms");
if (**PDPMS && !g_pCompositor->m_bDPMSStateON) {
// enable dpms
g_pKeybindManager->dpms("on");
}
@@ -1185,6 +1213,9 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
updateKeyboardsLeds(pKeyboard->keyboard);
}
if (m_bExitTriggered)
g_pCompositor->cleanup();
}
void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
@@ -1457,20 +1488,37 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
}
void CInputManager::setTouchDeviceConfigs(STouchDevice* dev) {
auto setConfig = [&](STouchDevice* const PTOUCHDEV) -> void {
if (wlr_input_device_is_libinput(PTOUCHDEV->pWlrDevice)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(PTOUCHDEV->pWlrDevice);
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "transform", "input:touchdevice:transform"), 0, 7);
const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "enabled", "input:touchdevice:enabled");
const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
if (libinput_device_config_send_events_get_mode(LIBINPUTDEV) != mode)
libinput_device_config_send_events_set_mode(LIBINPUTDEV, mode);
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "transform", "input:touchdevice:transform"), 0, 7);
Debug::log(LOG, "Setting calibration matrix for device {}", PTOUCHDEV->name);
if (libinput_device_config_calibration_has_matrix(LIBINPUTDEV))
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
const auto OUTPUT = g_pConfigManager->getDeviceString(PTOUCHDEV->name, "output", "input:touchdevice:output");
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY)
PTOUCHDEV->boundOutput = OUTPUT;
else
PTOUCHDEV->boundOutput = "";
auto output = g_pConfigManager->getDeviceString(PTOUCHDEV->name, "output", "input:touchdevice:output");
bool bound = !output.empty() && output != STRVAL_EMPTY;
const bool AUTODETECT = output == "[[Auto]]";
if (!bound && AUTODETECT) {
const auto DEFAULTOUTPUT = wlr_touch_from_input_device(PTOUCHDEV->pWlrDevice)->output_name;
if (DEFAULTOUTPUT) {
output = DEFAULTOUTPUT;
bound = true;
}
}
PTOUCHDEV->boundOutput = bound ? output : "";
const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr;
if (PMONITOR) {
Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->name, PMONITOR->szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTOUCHDEV->pWlrDevice, PMONITOR->output);
} else if (bound)
Debug::log(ERR, "Failed to bind touch device {} to output '{}': monitor not found", PTOUCHDEV->name, output);
}
};
@@ -1501,9 +1549,12 @@ void CInputManager::setTabletConfigs() {
const auto OUTPUT = g_pConfigManager->getDeviceString(t.name, "output", "input:tablet:output");
const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT);
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) {
Debug::log(LOG, "Binding tablet {} to output {}", t.name, PMONITOR->szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output);
wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr);
}
t.boundOutput = OUTPUT;
} else if (!PMONITOR)
Debug::log(ERR, "Failed to bind tablet {} to output '{}': monitor not found", t.name, OUTPUT);
const auto REGION_POS = g_pConfigManager->getDeviceVec(t.name, "region_position", "input:tablet:region_position");
const auto REGION_SIZE = g_pConfigManager->getDeviceVec(t.name, "region_size", "input:tablet:region_size");
@@ -1647,17 +1698,17 @@ void CInputManager::setCursorIconOnBorder(CWindow* w) {
return;
}
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
static const auto* PEXTENDBORDERGRAB = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
static auto* const PEXTENDBORDERGRAB = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area");
const int BORDERSIZE = w->getRealBorderSize();
const int ROUNDING = w->rounding();
// give a small leeway (10 px) for corner icon
const auto CORNER = *PROUNDING + BORDERSIZE + 10;
const auto CORNER = ROUNDING + BORDERSIZE + 10;
const auto mouseCoords = getMouseCoordsInternal();
CBox box = w->getWindowMainSurfaceBox();
eBorderIconDirection direction = BORDERICON_NONE;
CBox boxFullGrabInput = {box.x - *PEXTENDBORDERGRAB - BORDERSIZE, box.y - *PEXTENDBORDERGRAB - BORDERSIZE, box.width + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE),
box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)};
CBox boxFullGrabInput = {box.x - **PEXTENDBORDERGRAB - BORDERSIZE, box.y - **PEXTENDBORDERGRAB - BORDERSIZE, box.width + 2 * (**PEXTENDBORDERGRAB + BORDERSIZE),
box.height + 2 * (**PEXTENDBORDERGRAB + BORDERSIZE)};
if (w->hasPopupAt(mouseCoords))
direction = BORDERICON_NONE;

View File

@@ -142,25 +142,28 @@ class CInputManager {
// Switches
std::list<SSwitchDevice> m_lSwitches;
void newTabletTool(wlr_input_device*);
void newTabletPad(wlr_input_device*);
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
void newIdleInhibitor(wlr_idle_inhibitor_v1*);
void recheckIdleInhibitorStatus();
// Exclusive layer surfaces
std::deque<SLayerSurface*> m_dExclusiveLSes;
void onSwipeBegin(wlr_pointer_swipe_begin_event*);
void onSwipeEnd(wlr_pointer_swipe_end_event*);
void onSwipeUpdate(wlr_pointer_swipe_update_event*);
void newTabletTool(wlr_input_device*);
void newTabletPad(wlr_input_device*);
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
void newIdleInhibitor(wlr_idle_inhibitor_v1*);
void recheckIdleInhibitorStatus();
SSwipeGesture m_sActiveSwipe;
void onSwipeBegin(wlr_pointer_swipe_begin_event*);
void onSwipeEnd(wlr_pointer_swipe_end_event*);
void onSwipeUpdate(wlr_pointer_swipe_update_event*);
SKeyboard* m_pActiveKeyboard = nullptr;
SSwipeGesture m_sActiveSwipe;
CTimer m_tmrLastCursorMovement;
SKeyboard* m_pActiveKeyboard = nullptr;
CInputMethodRelay m_sIMERelay;
CTimer m_tmrLastCursorMovement;
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
CInputMethodRelay m_sIMERelay;
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
// for shared mods
uint32_t accumulateModsFromAllKBs();
@@ -243,6 +246,8 @@ class CInputManager {
void restoreCursorIconToApp(); // no-op if restored
bool m_bExitTriggered = false; // for exit dispatcher
friend class CKeybindManager;
friend class CWLSurface;
};

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