Compare commits

..

205 Commits

Author SHA1 Message Date
vaxerski
12f9a0d0b9 [gha] Nix: update inputs 2024-11-19 21:47:18 +00:00
Vaxry
fab0f426b5 version: bump to 0.45.2 2024-11-19 21:45:40 +00:00
Vaxry
e735eae4ad xdg-shell: don't report invalid min/max sizes on unset
fixes #8522
2024-11-19 21:45:20 +00:00
Aqa-Ib
57cf6d81a9 internal: fix changeWindowZOrder reordering incorrectly (#8494) 2024-11-19 21:45:20 +00:00
Vaxry
77b9d03c3f version: bump to 0.45.1 2024-11-18 14:27:21 +00:00
johannes hanika
53e8513000 constraints: don't warp pointer position on release (#8491)
this was annoying for nuklear properties/ui slider elements that grab
the pointer via GLFW_CURSOR_DISABLE to allow more range and finer control.
upon mouse release, the pointer is reset to the middle of the window
without this patch, making long mouse movements necessary to go back
to the original position for readjustments. fwiw the new behaviour
is consistent with x11 and weston.
2024-11-18 14:26:44 +00:00
Vaxry
7976bfa2df shell: don't use fgrep, prefer grep -F 2024-11-18 14:26:44 +00:00
Vaxry
a77ffa8cb8 windows/xdg: minor cleanup of min/max size calculations
fixes #8495
2024-11-18 14:26:44 +00:00
Vaxry
a4a1ad1f9b hyprpm: fix format crash
ref #8487
2024-11-18 14:26:44 +00:00
Vaxry
737b51d032 renderer: don't render unmapped popups
fixes #8485
2024-11-18 14:26:44 +00:00
staz
b3251f2961 workspacerules: Do not check 'on-created-empty' if using a workspace windowrule (#8486) 2024-11-18 14:26:44 +00:00
Vaxry
c4a77b8da7 core: guard pmonitor in focuswindow
may be null

fixes #8483
2024-11-18 14:26:44 +00:00
sslater11
38b6f3babb workspace: fix missing name via focusworkspaceoncurrentmonitor (#8484) 2024-11-18 14:26:44 +00:00
Vaxry
ace7ece4f2 protocols: mark primarySelection as not privileged
fixes #8479
2024-11-18 14:26:44 +00:00
Tom Englund
0557b2ed8c xcursors: store themes in a std:set to order it (#8474)
using a unordered_set means its store based on a hash_value meaning
currently it can end up loading inherited themes before the actual theme
itself depending on the hash of the theme name used, reason for using
set at all over vector is to keep unique members and not foreverever
looping broken inherit themeing.
2024-11-18 14:26:44 +00:00
Vaxry
9728a39b2e makefile: add stub to discourage direct make 2024-11-18 14:26:44 +00:00
dawsers
7120dde3d1 renderer: scaled surfaces could have zero area (#8423) 2024-11-18 14:26:44 +00:00
Vaxry
e7ab2d8533 defaultConfig: fixup smart gaps rules 2024-11-18 14:26:44 +00:00
Vaxry
a425fbebe4 version: bump to 0.45.0 2024-11-09 14:27:47 +00:00
Vaxry
cca227a53e tablet: use inputMgr unified naming scheme
ref #8301
2024-11-09 02:34:04 +00:00
Vaxry
b9c439a55e compositor: make sure we don't ret early on no surface
if there is no implicit surface passed, make sure the current focus is not null, otherwise we nope early without focusing the window

fixes #8293
2024-11-09 02:27:01 +00:00
Vaxry
726d697821 popup: minor cleanups
don't iterate over unmapped popups in breadthfirst, don't refocus if it wasnt in focus

ref #8293
2024-11-09 02:26:24 +00:00
Vaxry
0ccc0ace88 input: ignore non-kb ls-es in refocusLastWindow
ref #8293
2024-11-09 02:25:54 +00:00
Vaxry
f43d4a8638 layershell: minor cleanups and improvements to focus
ref #8293
2024-11-09 02:25:34 +00:00
Vaxry
4c7a2faf85 input: cleanup device naming logic
ref #8301
2024-11-09 01:53:05 +00:00
nickodei
3b66351eeb input: Refocus window on scrolling if follows mouse (#8361) 2024-11-08 17:25:37 +00:00
Mihai Fufezan
e58e97b0a3 Nix: build aquamarine and hyprutils in debug when using hyprland-debug 2024-11-07 10:54:52 +02:00
Mihai Fufezan
2dd0b2af71 flake.lock: update 2024-11-07 10:54:52 +02:00
dawsers
2ec2b3bfb3 renderer: minor fixup to window rendering logic (#8359)
Don't render animating windows out of their monitor when they are not moving workspaces
2024-11-06 23:30:17 +00:00
Vaxry
0ec128e5ed renderer: don't rely on datarootdir for local share 2024-11-06 22:11:46 +00:00
Mihai Fufezan
083a5cf3c1 CI: update actions 2024-11-06 19:50:01 +02:00
Aqa-Ib
8f42401aa8 groups: add merge_groups_on_groupbar (#8362) 2024-11-06 16:52:10 +00:00
Vaxry
97a309b784 layershell: check if workspace is valid in onMap
ref #8296
2024-11-06 14:02:44 +00:00
izmyname
3bf6f78dad hyprland-systemd.desktop: change name back to Hyprland (#8351) 2024-11-05 20:14:48 +02:00
Kamikadze
e4ab28b1fb defaultConfig: update default config values for shadows (#8360) 2024-11-05 18:03:37 +00:00
Vaxry
81ad218b8b shadow: fix double premultiplication
shader takes straight alpha aaaa
2024-11-05 16:28:55 +00:00
Vaxry
64c46db087 hyprctl: add mirrorOf to hyprctl monitors
fixes #8026
2024-11-05 16:20:04 +00:00
Vaxry
0920572e70 shaders: improve corner AA in borders shader 2024-11-05 16:11:05 +00:00
Vaxry
55ccb1a8cf shaders: fixup jagged edges in texture rounded corners 2024-11-05 16:00:39 +00:00
Vaxry
d1638a09ba shadow: add sharp and refactor options
options moved to decoration:shadow:
2024-11-05 15:44:40 +00:00
Vaxry
e3882b23d0 screencopy: fix build with legacyrenderer
fixes #8355
2024-11-05 09:59:03 +00:00
Vaxry
88e9e03945 renderer: add expand_undersized_textures
adds an option to disable the texture expansion for textures that are smaller while resizing up
2024-11-04 19:45:23 +00:00
Mihai Fufezan
0fb9a04526 flake.lock: update xdph 2024-11-04 20:01:40 +02:00
Mihai Fufezan
44899cd548 nix/overlays: fix xdph overlay
Partial fix for https://github.com/hyprwm/Hyprland/issues/8343
2024-11-04 19:43:25 +02:00
Gliczy
cd0d049126 flake.lock: update xdph 2024-11-03 18:43:08 +02:00
Vaxry
180c26ada6 renderer: safeguard against non-sampleable currentFB in blurMainFb
fixes #8325
2024-11-03 15:16:13 +00:00
trianta
5833abbbd1 xwayland: minor fixups for stability (#8323)
* xwayland: add inline safe closing of fds and fix LOCK_FILE_MODE permissions

* xwayland: auto recreate xwayland instance if it crashes

* xwayland: delay auto-restart until later
2024-11-03 14:59:46 +00:00
diniamo
514e0ff509 flake: update nixpkgs 2024-11-03 12:14:49 +02:00
Vaxry
40081cb330 renderer: improve api around new framebuffer changes
ref #8325
2024-11-02 15:26:45 +00:00
Mihai Fufezan
32b18179dd CMake: systemd fixes 2024-11-02 00:20:52 +02:00
Pavel Solovev
29e7dc6428 Systemd fixes
Fix installation path, install the service only if the systemd option is enabled
2024-11-02 00:20:52 +02:00
izmyname
3c0605c68e hyprland-systemd.desktop improvements (#8318) 2024-11-01 19:21:36 +02:00
Vaxry
d8b865366a renderer: Add a missing texture asset and a user check
When an asset is missing, instead of a black screen, render an obnoxious, yet standard, missing texture.

Additionally, warn the user assets failed to load.

Shoutout to Arch for having their assets broken for months. Fix your shit. I am tired of it, and it's negatively impacting users.
2024-11-01 15:52:09 +00:00
vaxerski
3852418d24 hyprctl: reload windowrules on reloadAll 2024-11-01 13:03:12 +00:00
Ikalco
c4d214c42d monitors: fix vrr breaking monitor disconnect (#8314) 2024-11-01 12:30:26 +00:00
Mike Will
93b4478e70 snap: add option border_overlap and other improvements (#8289)
* snap: add option `border_overlap` and other improvements

I really liked the way borders used to overlap when snapping and how
only the window's main surface would snap to the monitor, so I would
like to bring that behavior back, but in the form of a config option.

Other improvements include:

- reduced the number of snap functions from 4 down to 2, and only
one ever gets called at any given time.

- border size should not be added to gap size. It seemed like the
right thing to do at the time, but it makes snapping feel way
stronger than it actually should.

- all const variables have been given the all-caps naming convention.

- to avoid excessive casting, border size is declared as a double.

- to avoid excessive x + w, y + h calculations. I'm using a struct
called Range and working only with start and end values until the
very end of the function.

- check for both monitor snapping as well as reserved monitor space
snapping in a relatively efficient way.

* snap: always border-align for corners and reserved monitor space

We probably don't want to treat reserved monitor space as if it were just
a smaller monitor. Instead, it should be treated more like a borderless
window, which means our window's border should never encroach upon it.
2024-10-31 11:21:08 +00:00
Tom Englund
7c7a84ff60 internal: more profiling less calls and local copies (#8300)
* compositor: reduce amount of window box copies

mousemoveunified can call this very frequently, the cbox copying
actually shows up as an impact in such cases, move it down in the scope
and only do it when necessery.

* core: constify and reference frequent calls

profiling shows these as frequent called functions try to reduce the
amount of copies with references and const the variables.

* pointermgr: remove not used local copy, const ref

remove unneded local copies and const ref cursorsize.

* inputmgr: reduce amount of calls to vectortowindow

the amount of calls to g_pCompositor->vectorToWindowUnified fast ramps
up in cpu usage with enough windows existing and moving the mouse, move
the PWINDOWIDEAL up and reuse it if its already the same.

* protocol: compositor remove unused local copy

remove unused local copy of accumulateCurrentBufferDamage and const
previousBuffer.

* renderer: reduce scope of variables and refactor

move a few variables down in their scopes to reduce the amount of calls
and copies when not needed, also add one more for loop in
renderWorkspaceWindows and store the windows in a vector with
weakpointers that should be rendered, this adds a loop but reduces the
amount of repeated calls to shouldRenderWindow and also makes the rest
of the loops go over way smaller vector when many windows exist.
2024-10-30 23:20:32 +00:00
Vaxry
a0b2169ed6 input: revert #8279 2024-10-30 22:14:43 +00:00
nickodei
ee91df62f0 input: simulate mouse movement after scroll to refocus window (#8279) 2024-10-30 19:12:16 +00:00
MightyPlaza
12c1bb936d internal: check size limit in layouts (#8298)
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/events/Windows.cpp
modified:   src/helpers/MiscFunctions.cpp
modified:   src/helpers/MiscFunctions.hpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/layout/MasterLayout.cpp
modified:   src/macros.hpp
2024-10-30 18:58:36 +00:00
Aqa-Ib
5f721dce36 group: fix moveWindowIntoGroup (#8297) 2024-10-30 10:00:58 +00:00
staticssleever668
d679d20029 seat: avoid sending pointless 'keymap' and 'repeat_info' events (#8276)
#### Describe your PR, what does it fix/add?

Fix lag spikes when pressing more than 6 keys at the same time.

 #### Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.)

Debugging process:
<details>
This is triggered by typing some applications, like CopyQ or XWayland.
Typing in Firefox doesn't lead to lag, however it itself does lag
handling these events.

Profiling CopyQ shows that paths leading to
`QtWaylandClient::QWaylandInputDevice::Keyboard::keyboard` take over
80% of processing time of an otherwise idle program.

Looking at output of 'wev' even when it's not focused shows same events
received over and over again.

```
[14:     wl_keyboard] repeat_info: rate: 25 keys/sec; delay: 300 ms
[14:     wl_keyboard] keymap: format: 1 (xkb v1), size: 64754
```

Looking at what passes through CInputManager::onKeyboardKey() ->
CSeatManager::setKeyboard() shows Hyprland 'switching' between endpoints
of the same keyboard, one of them being named like the other but with
'-1' suffix.
</details>

Tested changing layouts in Fcitx5 and with following config.

```
input:kb_layout = us,cz
input:kb_variant = ,qwerty
input:kb_options = grp:alt_shift_toggle
```

Also tested changing 'input:repeat_delay' while running.

Curiously, now these events appear in the output of 'wev' only once.
Changing layouts still seems to work fine though.

 #### Is it ready for merging, or does it need work?

Ready for merging.
2024-10-28 19:25:27 +00:00
MightyPlaza
7188ee4f99 hyprctl: move setprop into dispatchers (#8275)
* move setprop into dispatchers
modified:   src/debug/HyprCtl.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/KeybindManager.hpp

* add deprecated
modified:   src/debug/HyprCtl.cpp
2024-10-28 18:18:58 +00:00
Tom Englund
c7315617eb internal: few more marginal optimisations from profiling (#8271)
* deco: reduce local temporars and function calls

profiling shows this is a high used function, reduce the amount of
function calls and local temporar copies and also check if we even need
to add extents at all in the loop.

* popup: optimize bfhelper in popups

pass nodes as const reference and reserve the size of the children node
vector help reduce the reallocations.

* procotol: make compositor bfhelper use const ref

use const ref for nodes and reserve second nodes vector size to reduce
amount of reallocation needed.
2024-10-28 18:02:52 +00:00
Aqa-Ib
d49a1334a8 swallow: check if swallow_regex doesn't exist (#8265)
Avoid to run CWindow::getSwallower() when `swallow_regex` doesn't exist in the user's config file.
2024-10-28 16:52:14 +00:00
Mike Will
2c481202ef layout: slight adjustments to snapping logic (#8273)
fixes some bugs with resizing and corner snapping
2024-10-28 13:39:05 +00:00
Vaxry
6cf193e166 layout: don't snap to self and allow same-pid snaps
fixes #8255
2024-10-27 23:41:22 +00:00
Vaxry
b1120ec433 layout: window snapping cleanup + fixes
way better now heh

fixes #8259 fixes #8267
2024-10-27 23:39:57 +00:00
Vaxry
5d4b54b012 core: move internal structures to monitor pointers (#8266) 2024-10-27 18:45:38 +00:00
Ryan
b6e226c320 groupbar: set locked color when groups are globally locked (#8257) 2024-10-27 18:26:42 +00:00
Tom Englund
f9b52203f5 internal: optimize cursor move a bit (#8264)
* window: inline and const getWindowMainSurfaceBox

getWindowMainSurfaceBox gets called a lot of times from deep down from
mousemoveunified, profiling mousemoveunified it spends quite a lot of
cpu time in here, let the compiler optimize the call to
getWindowMainSurfaceBox by inlining and making it const. reducing the
overhead.

* inputmgr: return early and use std::any_of

return early in mousemoveunified to reduce the amount of unnecessery
calls to various pointers when not needed, also make isconstrained use
std::any_of instead of for loop to use the STL optimized paths with
hopes and dreams marginally faster.

* decoration: return early, reduce temporar copy

return earlier and reduce the temp copies by using one .lock instead of
two
2024-10-27 17:51:26 +00:00
Aqa-Ib
a3d3b4fd64 groups: fix swallowing (#8223)
* fix swallowing for groups

* remove unnecessary check

* clang-format

* clarify comment

* make variables consistent

* make aditional variables consistent
2024-10-27 01:44:55 +01:00
izmyname
f3f7d3629a Build with hyprland-session.service (#8251)
Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-10-26 22:49:00 +03:00
Damianu
c356e42500 misc: Fix bad links to wiki (#8240)
Same as in https://github.com/hyprwm/hyprland-wiki/pull/828
2024-10-26 16:50:31 +01:00
Aqa-Ib
0b29caf9ab core: fix group members disappearing when you move the group to another monitor (#8237)
* fix group members disappearance when you move the group to another monitor

* remove repeated action
2024-10-26 02:22:37 +01:00
Vaxry
3dd8db83f1 pointer: add default auto for no_hw_cursors
auto defaults to off on nvidia, on for everyone else. Gotta wait until we do fucking drm_dumb and it fucking works
2024-10-26 02:12:43 +01:00
Vaxry
d5689bb539 internal: cleanup CMonitor usage and fix a few ref hogs
ref #8221
2024-10-26 02:06:13 +01:00
izmyname
e5384774a8 example/hyprland-session.service: add support for xdg autostart (#8230) 2024-10-25 23:38:59 +03:00
Tom Englund
f0e023bff2 security-context: avoid UB in C macro (#8229)
to safely use wl_container_of with a class the class has to be no
virtual functions, no inheritance, and uniform access control (e.g all
public)

work around this by putting this into a destroywrapper struct.
2024-10-25 11:26:48 +01:00
izmyname
3cec45d821 Improve hyprland-session.service (#8225) 2024-10-24 17:50:53 +03:00
czlabinger
7f46680ab1 hyprctl: add caps/num lock state for keyboards (#8145)
---------

Co-authored-by: Behzad <behzadasbahi@gmail.com>
2024-10-24 14:01:08 +01:00
Honkazel
f603a22af0 internal: Remove some unused lambda captures (#8218) 2024-10-24 13:12:41 +01:00
Honkazel
cdac64970e Makefile: fix legacyrendererdebug typo (#8214) 2024-10-23 23:32:39 +03:00
chitoroagad
6e0aadc585 updated flake.lock 2024-10-23 07:19:55 +03:00
Aqa-Ib
2b6ff6837e groups: add group_on_movetoworkspace (#8159) 2024-10-23 00:51:25 +01:00
Vaxry
29997ef4ba default/config: improve default animations
objectively better
2024-10-22 21:34:21 +01:00
KAGEYAM4
5e96d738e6 hyprpm: Add option to notify on fail and keep original notify (#8167)
* Only generate notification on fail

Hyprpm fail/pass notification are mutually exclusive.

* Add option to notify on fail and keep original notify (#1)

* Add option to notify on fail and keep original notify
---------

Co-authored-by: KAGEYAM4 <75798544+KAGEYAM4@users.noreply.github.com>

---------

Co-authored-by: littleblack111 <littleblack11111@gmail.com>
2024-10-22 00:28:42 +01:00
Ikalco
9df0f0b66c renderer: fix floating window damage (#8182) 2024-10-21 16:09:14 +01:00
Mike Will
4093b993a2 input: add snapping to floating windows (#8088)
* add snapping to floating windows

Works for both moving and resizing of windows.
It comes with 3 options:

`general:snap:enabled` - whether it's enabled, off by default

`general:snap:window_gap` - minimum gap in pixels between windows before
snapping. Setting to 0 effectively turns off this method of snapping.

`general:snap:monitor_gap` - minimum gap in pixels between window and
monitor edges before snapping. Again, setting it to 0 effectively turns
it off.

* snap: add more ignore criteria and change if clause into a guard

* snap: refactor code

* snap: new refactoring approach and account for border size

* snap: do corner snapping after all edge snapping is done

The approach of performing corner snaps after each individual edge snap
results in far fewer scenarios where snapping can occur.

After trying it out for a while, I found that I prefer an approach
that's more prone to snapping.

* snap: combine snapWindows and snapMonitor into a single function

* snap: add forced aspect ratio functionality

* snap: avoid directly referring to border_size config value

* snap: address vaxerski feedback

- add new line between functions
- use std::function typedef for SnapFn and make snap functions static
- avoid uninitialized variable declarations.
- change ignore condition m_bIsX11 to isX11OverrideRedirect()
- use braces for CBox and Vector2D declarations.
- add SNAP_INVALID to eSnapEdge enum
- use bitshift notation for eSnapEdge and eRectCorner
- make performSnap a non-member function.

* snap: add corner-snapping to forced aspect ratio mode
2024-10-21 16:08:25 +01:00
Vaxry
08cc063e17 monitor: avoid crash on released buffer in surf 2024-10-19 23:48:25 +01:00
Vaxry
a17850e41c layersurface: fixup brace style 2024-10-19 23:47:28 +01:00
Vaxry
6a5c342063 layersurface: round geom in arrangeLayerArray
fixes #8171
2024-10-19 23:45:51 +01:00
Vaxry
f044e4c951 internal: Move CMonitor to SP (#8178)
* move monitors to sp

* XD
2024-10-19 23:03:29 +01:00
Vaxry
ce3ba798df defaultConfig: improve smart gaps 2024-10-19 17:03:22 +01:00
Vaxry
0eaf3581a3 window: guard PMONITOR in commit listener
ref #8170
2024-10-19 16:24:03 +01:00
Vaxry
62ee5cc273 monitor: modernize/refactor last legacy-handled events 2024-10-19 16:21:47 +01:00
Vaxry
48bf32c5de foreign-toplevel-wlr: don't send updates to X11 OR windows 2024-10-19 16:09:53 +01:00
Vaxry
904f9b6aee foreign-toplevel: don't send updates to X11 OR windows 2024-10-19 16:09:53 +01:00
Maximilian Seidler
e5d3a71263 config: fix generateConfig loop (#8164)
* config: fix generateConfig loop

* config: cleanup getMainConfigPath
2024-10-19 15:49:56 +01:00
Maximilian Seidler
0e630e9e74 session-lock: reset seat grab on a new session lock (#8147) 2024-10-17 21:05:55 +01:00
MightyPlaza
5f30cb7753 windowrules: allow specifying max size in size window rule (#8021)
* allow specifying max size in size window rule
modified:   src/events/Windows.cpp

* clean up
modified:   src/events/Windows.cpp
2024-10-17 21:03:17 +01:00
Behzad
495b92fb53 makefile: fix typo (#8127) 2024-10-17 15:20:18 +01:00
Vaxry
b57086aa43 window: properly break cycles in X11TransientFor
ref #8045
2024-10-16 22:23:15 +01:00
zakk4223
09581d32fd hyprpm: Fix crashes due to misplaced fmt argument(s) (#8140) 2024-10-16 22:13:59 +01:00
Aqa-Ib
86e9f69a69 layout: move applyGroupRules() to onWindowCreated() (#8139) 2024-10-16 22:13:35 +01:00
Vaxry
781828a56e output: send enter events on late wl_output binds
fixes #6560
2024-10-16 21:59:33 +01:00
vaxerski
0baf166d39 [gha] Nix: update inputs 2024-10-16 10:01:31 +00:00
Aqa-Ib
ace803948a layout: enable group rules for new floating windows (#8122)
* layout: enable group rules for new floating windows

* fix comment

* do not apply group rules to a new floating window if it shouldBeFloated.
fixes child windows

* comment
2024-10-16 10:59:47 +01:00
Aqa-Ib
01c2ff34dd layout: simplify the conditions to autogroup (#8120) 2024-10-14 19:31:17 +01:00
fanlumaster(Fany Full)
22b1370ae5 IME: Fixup IME popup candidate windows position when scale is not 1.0 (#8117) 2024-10-14 18:03:16 +01:00
deadacute
f309681d4a example: update desktop file to include DesktopNames 2024-10-14 18:26:07 +03:00
Ikalco
ce62521883 drm-lease: fix crashes and implementation (#8116) 2024-10-14 11:37:42 +01:00
Aqa-Ib
e7fd0f5aec layout: deny auto-grouping a new floating window into a tiled group (#8108) 2024-10-14 00:25:19 +01:00
Vaxry
abfd550ee2 xwm: avoid infinite parent lookup loop in lookupParentExists
ref #8045
2024-10-14 00:24:32 +01:00
Vaxry
8e51a36c7f config/example: add optional smart gaps to the default config
ref #8106 #8114
2024-10-14 00:19:10 +01:00
Vaxry
5c3bd8e93d notif-overlay: add a bit of padding for icons 2024-10-13 17:26:44 +01:00
Toni500git
05a5e0b4f1 hyprland: convert std::cout and std::cerr to std::println() 2024-10-13 14:13:56 +01:00
Toni500git
b61d4c3636 hyprctl: convert std::cout and std::cerr to std::println() 2024-10-13 14:13:56 +01:00
Toni500git
e79d3cd2ef hyprpm: convert std::cout and std::cerr to std::println() 2024-10-13 14:13:56 +01:00
Vaxry
1822707c7e drm-syncobj: fix crash on missing timelines
fixes #8092
2024-10-12 17:56:46 +01:00
Vaxry
c3f7c9bbb5 xcursor: don't crash on broken permissions in X themes
ref #8079
2024-10-12 15:18:39 +01:00
UjinT34
ee8116ac5d input: Fix VRR for constrained cursors (#6877) 2024-10-12 01:29:51 +01:00
Edgars Cīrulis
f5db483973 drm-timeline: Add check for conflicting acquire and release points (#8083)
Signed-off-by: Edgars Cirulis <edgarsciruliss@gmail.com>
2024-10-12 01:12:07 +01:00
Toni500github
7564b26b7d internal: improve version query and define HYPRLAND_VERSION (#8034) 2024-10-11 12:19:16 +01:00
Jasson
178a300eea xwayland: minor cleanups and fixes (#8076) 2024-10-11 12:07:25 +01:00
Vaxry
d655a10381 config/layout: nuke no_gaps_when_only (#8072) 2024-10-11 10:56:19 +01:00
Vaxry
b65773bea9 hyprpm: disallow shallow on unknown branch 2024-10-10 11:01:13 +01:00
Vaxry
c4eb194033 gammactrl: guard pMonitor in setGamma 2024-10-09 22:00:06 +01:00
Aqa-Ib
6ae89940c7 layout: add merge_floated_into_tiled_on_groupbar (#8042) 2024-10-09 10:58:49 +01:00
JManch
3d28879c26 hyprerror: fix height calc with bottom bar (#8043) 2024-10-09 10:24:35 +01:00
trianta
223dcc8bac output: update state even if no owner exists (#8044) 2024-10-09 10:24:05 +01:00
Mihai Fufezan
6ce07ee864 CI/release: remove script backup line 2024-10-09 12:00:43 +03:00
Vaxry
bc299928ad output/xdg-output: avoid sending events to released globals
ref #6835
2024-10-09 00:26:40 +01:00
Vaxry
ac658500fb keyboard: update group state on change for the sym resolve state
fixes #8038
2024-10-08 23:33:10 +01:00
Vaxry
8cced091f5 renderer: reserve space for error at the bottom if that's set
ref #8040
2024-10-08 21:58:40 +01:00
Vaxry
91299f7039 hyprerror: make hyprerror reserve space (#8040) 2024-10-08 21:20:25 +01:00
Vaxry
60308a2bb5 defaultConfig: add a nofocus rule for weird X windows
ref #6543
2024-10-08 20:28:34 +01:00
Aqa-Ib
613eac4603 layout: remove unnecessary check after 45e8219 (#8037) 2024-10-08 19:31:15 +01:00
JManch
e4a26f4f1d dispatchers: allow leading whitespace in window parameter (#8016) 2024-10-08 17:50:06 +01:00
Vaxry
57b632ead8 pointer: expand sw cursor damage box
fixes #8031

just a bit, rounding errors I guess
2024-10-08 17:03:19 +01:00
Vaxry
1bf63dfdcd protocols: Add support for hyprland-ctm-control-v1 (#8023)
* initial ctm support

* flake.lock: update

* Meson: bump required versions and add ctm proto

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-10-08 16:59:15 +01:00
vaxerski
e0cfbec66b keybinds: fixup xkb_states for resolve_by_sym
fixes #7750
2024-10-08 13:15:58 +01:00
davc0n
b3a7e3109b misc: refactor version command (#8027)
Fixes a minor spacing issue if git status is not dirty.
Additionally now should be easier to extend it eventually.
2024-10-08 11:42:51 +01:00
Aqa-Ib
45e82199fb layout: add drag_into_group to control merging dragging windows (#8004) 2024-10-08 11:20:41 +01:00
Vaxry
4711796d38 config: give simple help for super+q not working
only on default config :P
2024-10-08 09:54:25 +01:00
Ikalco
0d70c44253 screencopy: fix screencopy frames not being cleaned up (#8017)
---------

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

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

* flake.lock: update hyprutils

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-09-25 10:01:13 +01:00
vaxerski
8f5188269b hyprctl: add solitary field to hyprctl monitors 2024-09-25 09:59:18 +01:00
vaxerski
00c8626863 hyprctl: add submap request
fixes #7898
2024-09-24 11:25:05 +01:00
Vaxry
0a211f29f5 hyprctl: add defaultName to workspacerules
fixes #7886
2024-09-24 01:19:05 +01:00
Vaxry
d279d7c4c6 eventloop: dispatch pending in session on start
fixes #7855 #7391
2024-09-24 00:49:29 +01:00
diniamo
6c78b03bb7 flake: update xdph 2024-09-24 00:47:34 +01:00
Vaxry
f79497087b internal: nuke wlsignal and related
old semi-wrappers for wl_signal, they are no longer used
2024-09-24 00:47:34 +01:00
Artur Manuel
508bde1f61 core: add HYPRLAND_CONFIG environment variable (#7851) 2024-09-23 16:40:19 +01:00
diniamo
e5ff19ac0f flake: update xdph 2024-09-22 11:55:13 +03:00
200 changed files with 4723 additions and 2792 deletions

View File

@@ -29,10 +29,10 @@ body:
attributes: attributes:
label: System Info and Version label: System Info and Version
description: | description: |
Paste the output of `hyprctl systeminfo -c` here (If you are on a Paste the output of `hyprctl systeminfo -c` here. If you can't
version that shows you help menu, omit the `-c` and attach config files launch Hyprland, paste the output of `Hyprland --systeminfo`.
to the issue). If you have configs outside of the main config shown If `Hyprland --systeminfo` errors out (added in 0.44.0), find
here, please attach. and paste the Hyprland version manually.
value: "<details> value: "<details>
<summary>System/Version info</summary> <summary>System/Version info</summary>

View File

@@ -39,7 +39,7 @@ jobs:
tar -cvf Hyprland.tar.xz hyprland tar -cvf Hyprland.tar.xz hyprland
- name: Release - name: Release
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: Build archive name: Build archive
path: Hyprland.tar.xz path: Hyprland.tar.xz

View File

@@ -17,14 +17,14 @@ jobs:
run: sudo apt install pandoc run: sudo apt install pandoc
- name: Clone repository - name: Clone repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
token: ${{ secrets.PAT }} token: ${{ secrets.PAT }}
- name: Build man pages - name: Build man pages
run: make man run: make man
- uses: stefanzweifel/git-auto-commit-action@v4 - uses: stefanzweifel/git-auto-commit-action@v5
name: Commit name: Commit
with: with:
commit_message: "[gha] build man pages" commit_message: "[gha] build man pages"

View File

@@ -12,6 +12,7 @@ jobs:
matrix: matrix:
package: package:
- hyprland - hyprland
- hyprland-cross
- xdg-desktop-portal-hyprland - xdg-desktop-portal-hyprland
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -24,4 +25,4 @@ jobs:
name: hyprland name: hyprland
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}&submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" - run: nix build 'github:hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clone repository - name: Clone repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
token: ${{ secrets.PAT }} token: ${{ secrets.PAT }}
@@ -22,6 +22,6 @@ jobs:
run: nix/update-inputs.sh run: nix/update-inputs.sh
- name: Commit - name: Commit
uses: stefanzweifel/git-auto-commit-action@v4 uses: stefanzweifel/git-auto-commit-action@v5
with: with:
commit_message: "[gha] Nix: update inputs" commit_message: "[gha] Nix: update inputs"

View File

@@ -11,7 +11,7 @@ jobs:
steps: steps:
- name: Checkout Hyprland - name: Checkout Hyprland
id: checkout id: checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
@@ -20,7 +20,6 @@ jobs:
run: | run: |
git fetch --unshallow || echo "failed unshallowing" git fetch --unshallow || echo "failed unshallowing"
bash -c scripts/generateVersion.sh bash -c scripts/generateVersion.sh
mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
- name: Create tarball with submodules - name: Create tarball with submodules
id: tar id: tar

View File

@@ -13,7 +13,7 @@ jobs:
security-events: write security-events: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Scan with Flawfinder - name: Scan with Flawfinder
uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c

View File

@@ -19,7 +19,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/stale@v5 - uses: actions/stale@v9
with: with:
repo-token: ${{ secrets.STALEBOT_PAT }} repo-token: ${{ secrets.STALEBOT_PAT }}
stale-issue-label: "stale" stale-issue-label: "stale"

4
.gitignore vendored
View File

@@ -14,6 +14,7 @@ _deps
build/ build/
result* result*
/.pre-commit-config.yaml
/.vscode/ /.vscode/
/.idea/ /.idea/
.envrc .envrc
@@ -39,3 +40,6 @@ PKGBUILD
src/version.h src/version.h
hyprpm/Makefile hyprpm/Makefile
hyprctl/Makefile hyprctl/Makefile
**/.#*.*
**/#*.*#

View File

@@ -15,6 +15,7 @@ include(GNUInstallDirs)
set(HYPRLAND_VERSION ${VER}) set(HYPRLAND_VERSION ${VER})
set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(PREFIX ${CMAKE_INSTALL_PREFIX})
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
set(BINDIR ${CMAKE_INSTALL_BINDIR})
configure_file(hyprland.pc.in hyprland.pc @ONLY) configure_file(hyprland.pc.in hyprland.pc @ONLY)
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
@@ -25,8 +26,18 @@ message(STATUS "Gathering git info")
execute_process(COMMAND ./scripts/generateVersion.sh execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# udis find_package(PkgConfig REQUIRED)
# Try to find canihavesomecoffee's udis86 using pkgconfig vmd/udis86 does not
# provide a .pc file and won't be detected this way
pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2)
# Fallback to subproject
if(NOT udis_dep_FOUND)
add_subdirectory("subprojects/udis86") add_subdirectory("subprojects/udis86")
include_directories("subprojects/udis86")
message(STATUS "udis86 dependency not found, falling back to subproject")
endif()
if(CMAKE_BUILD_TYPE) if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
@@ -47,8 +58,6 @@ else()
set(BUILDTYPE_LOWER "release") set(BUILDTYPE_LOWER "release")
endif() endif()
find_package(PkgConfig REQUIRED)
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
@@ -63,7 +72,10 @@ else()
message(STATUS "Configuring Hyprland in Release with CMake") message(STATUS "Configuring Hyprland in Release with CMake")
endif() endif()
include_directories(. "src/" "subprojects/udis86/" "protocols/") add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}")
include_directories(. "src/" "protocols/")
set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD 26)
add_compile_options( add_compile_options(
-Wall -Wall
@@ -91,7 +103,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1)
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.2)
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
@@ -101,7 +113,7 @@ pkg_check_modules(
IMPORTED_TARGET IMPORTED_TARGET
xkbcommon xkbcommon
uuid uuid
wayland-server wayland-server>=1.22.90
wayland-protocols wayland-protocols
cairo cairo
pango pango
@@ -114,7 +126,7 @@ pkg_check_modules(
gio-2.0 gio-2.0
hyprlang>=0.3.2 hyprlang>=0.3.2
hyprcursor>=0.1.7 hyprcursor>=0.1.7
hyprutils>=0.2.2) hyprutils>=0.2.3)
find_package(hyprwayland-scanner 0.3.10 REQUIRED) find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -210,30 +222,42 @@ if(NO_SYSTEMD)
else() else()
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
add_compile_definitions(USES_SYSTEMD) add_compile_definitions(USES_SYSTEMD)
configure_file(systemd/hyprland-session.service.in
systemd/hyprland-session.service @ONLY)
# session file -systemd
install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-systemd.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
# install systemd service
install(FILES ${CMAKE_BINARY_DIR}/systemd/hyprland-session.service
DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/user)
endif() endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack) include(CPack)
if(CMAKE_DISABLE_PRECOMPILE_HEADERS)
message(STATUS "Not using precompiled headers")
else()
message(STATUS "Setting precompiled headers") message(STATUS "Setting precompiled headers")
target_precompile_headers(Hyprland PRIVATE target_precompile_headers(Hyprland PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>) $<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
endif()
message(STATUS "Setting link libraries") message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps) target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps)
if(udis_dep_FOUND)
target_link_libraries(Hyprland PkgConfig::udis_dep)
else()
target_link_libraries(Hyprland libudis86)
endif()
# used by `make installheaders`, to ensure the headers are generated # used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers) add_custom_target(generate-protocol-headers)
function(protocolnew protoPath protoName external) function(protocolnew protoPath protoName external)
if(external) if(external)
set(path ${CMAKE_SOURCE_DIR}/${protoPath}) set(path ${protoPath})
else() else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif() endif()
@@ -261,14 +285,22 @@ function(protocolWayland)
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
endfunction() endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
libudis86)
protocolnew("subprojects/hyprland-protocols/protocols" pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.4.0)
"hyprland-global-shortcuts-v1" true) if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
else()
set(HYPRLAND_PROTOCOLS "subprojects/hyprland-protocols")
message(STATUS "hyprland-protocols subproject set to ${HYPRLAND_PROTOCOLS}")
endif()
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1"
true)
protocolnew("unstable/text-input" "text-input-unstable-v1" false) protocolnew("unstable/text-input" "text-input-unstable-v1" false)
protocolnew("subprojects/hyprland-protocols/protocols" protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1"
"hyprland-toplevel-export-v1" true) true)
protocolnew("protocols" "wlr-screencopy-unstable-v1" true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) protocolnew("protocols" "wlr-gamma-control-unstable-v1" true)
protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
@@ -279,10 +311,11 @@ protocolnew("protocols" "input-method-unstable-v2" true)
protocolnew("protocols" "wlr-output-management-unstable-v1" true) protocolnew("protocols" "wlr-output-management-unstable-v1" true)
protocolnew("protocols" "kde-server-decoration" true) protocolnew("protocols" "kde-server-decoration" true)
protocolnew("protocols" "wlr-data-control-unstable-v1" true) protocolnew("protocols" "wlr-data-control-unstable-v1" true)
protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true)
true)
protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
protocolnew("protocols" "wayland-drm" true) protocolnew("protocols" "wayland-drm" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true)
protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/tearing-control" "tearing-control-v1" false)
protocolnew("staging/fractional-scale" "fractional-scale-v1" false) protocolnew("staging/fractional-scale" "fractional-scale-v1" false)
protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false) protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false)
@@ -312,6 +345,8 @@ protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
protocolnew("staging/drm-lease" "drm-lease-v1" false) protocolnew("staging/drm-lease" "drm-lease-v1" false)
protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
protocolnew("staging/security-context" "security-context-v1" false)
protocolwayland() protocolwayland()

View File

@@ -1,12 +1,15 @@
PREFIX = /usr/local PREFIX = /usr/local
stub:
@echo "Do not run $(MAKE) directly without any arguments. Please refer to the wiki on how to compile Hyprland."
legacyrenderer: legacyrenderer:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./buildZ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
legacyrendererdebug: legacyrendererdebug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
release: release:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build

View File

@@ -100,7 +100,7 @@ easy IPC, much more QoL stuff than other compositors and more...
<!-----------------------------------------------------------------------------> <!----------------------------------------------------------------------------->
[Configure]: https://wiki.hyprland.org/Configuring/Configuring-Hyprland/ [Configure]: https://wiki.hyprland.org/Configuring/
[Stars]: https://starchart.cc/hyprwm/Hyprland [Stars]: https://starchart.cc/hyprwm/Hyprland
[Hypr]: https://github.com/hyprwm/Hypr [Hypr]: https://github.com/hyprwm/Hypr

View File

@@ -1 +1 @@
0.43.0 0.45.2

View File

@@ -3,7 +3,7 @@
First of all, please remember to: First of all, please remember to:
- Check that your issue is not a duplicate - Check that your issue is not a duplicate
- Read the [FAQ](https://wiki.hyprland.org/FAQ/) - Read the [FAQ](https://wiki.hyprland.org/FAQ/)
- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/Configuring-Hyprland) - Read the [Configuring Page](https://wiki.hyprland.org/Configuring/)
<br/> <br/>

View File

@@ -1,6 +1,6 @@
# This is an example Hyprland config file. # This is an example Hyprland config file.
# Refer to the wiki for more information. # Refer to the wiki for more information.
# https://wiki.hyprland.org/Configuring/Configuring-Hyprland/ # https://wiki.hyprland.org/Configuring/
# Please note not all available settings / options are set here. # Please note not all available settings / options are set here.
# For a full list, see the wiki # For a full list, see the wiki
@@ -86,10 +86,12 @@ decoration {
active_opacity = 1.0 active_opacity = 1.0
inactive_opacity = 1.0 inactive_opacity = 1.0
drop_shadow = true shadow {
shadow_range = 4 enabled = true
shadow_render_power = 3 range = 4
col.shadow = rgba(1a1a1aee) render_power = 3
color = rgba(1a1a1aee)
}
# https://wiki.hyprland.org/Configuring/Variables/#blur # https://wiki.hyprland.org/Configuring/Variables/#blur
blur { blur {
@@ -103,20 +105,44 @@ decoration {
# https://wiki.hyprland.org/Configuring/Variables/#animations # https://wiki.hyprland.org/Configuring/Variables/#animations
animations { animations {
enabled = true enabled = yes, please :)
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = myBezier, 0.05, 0.9, 0.1, 1.05 bezier = easeOutQuint,0.23,1,0.32,1
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = windows, 1, 7, myBezier animation = global, 1, 10, default
animation = windowsOut, 1, 7, default, popin 80% animation = border, 1, 5.39, easeOutQuint
animation = border, 1, 10, default animation = windows, 1, 4.79, easeOutQuint
animation = borderangle, 1, 8, default animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
animation = fade, 1, 7, default animation = windowsOut, 1, 1.49, linear, popin 87%
animation = workspaces, 1, 6, default animation = fadeIn, 1, 1.73, almostLinear
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, fade
animation = workspacesIn, 1, 1.21, almostLinear, fade
animation = workspacesOut, 1, 1.94, almostLinear, fade
} }
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
@@ -255,4 +281,8 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# Example windowrule v2 # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0

View File

@@ -3,3 +3,5 @@ Name=Hyprland
Comment=An intelligent dynamic tiling Wayland compositor Comment=An intelligent dynamic tiling Wayland compositor
Exec=Hyprland Exec=Hyprland
Type=Application Type=Application
DesktopNames=Hyprland
Keywords=tiling;wayland;compositor;

132
flake.lock generated
View File

@@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726665257, "lastModified": 1731959031,
"narHash": "sha256-rEzEZtd3iyVo5RJ1OGujOlnywNf3gsrOnjAn1NLciD4=", "narHash": "sha256-TGcvIjftziC1CjuiHCzrYDwmOoSFYIhdiKmLetzB5L0=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "752d0fbd141fabb5a1e7f865199b80e6e76f8d8e", "rev": "4468981c1c50999f315baa1508f0e53c4ee70c52",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -29,6 +29,43 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"hyprcursor": { "hyprcursor": {
"inputs": { "inputs": {
"hyprlang": [ "hyprlang": [
@@ -42,11 +79,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1722623071, "lastModified": 1728669738,
"narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=", "narHash": "sha256-EDNAU9AYcx8OupUzbTbWE1d3HYdeG0wO6Msg3iL1muk=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "912d56025f03d41b1ad29510c423757b4379eb1c", "rev": "0264e698149fcb857a66a53018157b41f8d97bb0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -58,20 +95,18 @@
"hyprland-protocols": { "hyprland-protocols": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"xdph",
"nixpkgs" "nixpkgs"
], ],
"systems": [ "systems": [
"xdph",
"systems" "systems"
] ]
}, },
"locked": { "locked": {
"lastModified": 1721326555, "lastModified": 1728345020,
"narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", "narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", "rev": "a7c183800e74f337753de186522b9017a07a8cee",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -93,11 +128,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1725997860, "lastModified": 1728168612,
"narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=", "narHash": "sha256-AnB1KfiXINmuiW7BALYrKqcjCnsLZPifhb/7BsfPbns=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876", "rev": "f054f2e44d6a0b74607a6bc0f52dba337a3db38e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -116,11 +151,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726874949, "lastModified": 1731702627,
"narHash": "sha256-PNnIpwGqpTvMU3N2r0wMQwK1E+t4Bb5fbJwblQvr+80=", "narHash": "sha256-+JeO9gevnXannQxMfR5xzZtF4sYmSlWkX/BPmPx0mWk=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "d97af4f6bd068c03a518b597675e598f57ea2291", "rev": "e911361a687753bbbdfe3b6a9eab755ecaf1d9e1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -139,11 +174,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726840673, "lastModified": 1726874836,
"narHash": "sha256-HIPEXyRRVZoqD6U+lFS1B0tsIU7p83FaB9m7KT/x6mQ=", "narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "b68dab23fc922eae99306988133ee80a40b39ca5", "rev": "500c81a9e1a76760371049a8d99e008ea77aa59e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -154,11 +189,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1726755586, "lastModified": 1731676054,
"narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=", "narHash": "sha256-OZiZ3m8SCMfh3B6bfGC/Bm4x3qc1m2SVEAlkV6iY7Yg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e", "rev": "5e4fbfb6b3de1aa2872b76d49fafc942626e2add",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -168,14 +203,55 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-stable": {
"locked": {
"lastModified": 1730741070,
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1732021966,
"narHash": "sha256-mnTbjpdqF0luOkou8ZFi2asa1N3AA2CchR/RqCNmsGE=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "3308484d1a443fc5bc92012435d79e80458fe43c",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"aquamarine": "aquamarine", "aquamarine": "aquamarine",
"hyprcursor": "hyprcursor", "hyprcursor": "hyprcursor",
"hyprland-protocols": "hyprland-protocols",
"hyprlang": "hyprlang", "hyprlang": "hyprlang",
"hyprutils": "hyprutils", "hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner", "hyprwayland-scanner": "hyprwayland-scanner",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks",
"systems": "systems", "systems": "systems",
"xdph": "xdph" "xdph": "xdph"
} }
@@ -197,7 +273,9 @@
}, },
"xdph": { "xdph": {
"inputs": { "inputs": {
"hyprland-protocols": "hyprland-protocols", "hyprland-protocols": [
"hyprland-protocols"
],
"hyprlang": [ "hyprlang": [
"hyprlang" "hyprlang"
], ],
@@ -215,11 +293,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726851729, "lastModified": 1731703417,
"narHash": "sha256-1z0esr5lBeUMlrPZ9gZmqZT8oTQekxJi53HAW4cH0Ms=", "narHash": "sha256-rheDc/7C+yI+QspYr9J2z9kQ5P9F4ATapI7qyFAe1XA=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "73b8c4f1150040644cf678aa8bbf2cec48a433cf", "rev": "8070f36deec723de71e7557441acb17e478204d3",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -22,6 +22,12 @@
inputs.hyprlang.follows = "hyprlang"; inputs.hyprlang.follows = "hyprlang";
}; };
hyprland-protocols = {
url = "github:hyprwm/hyprland-protocols";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
hyprlang = { hyprlang = {
url = "github:hyprwm/hyprlang"; url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@@ -45,10 +51,16 @@
url = "github:hyprwm/xdg-desktop-portal-hyprland"; url = "github:hyprwm/xdg-desktop-portal-hyprland";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
inputs.hyprland-protocols.follows = "hyprland-protocols";
inputs.hyprlang.follows = "hyprlang"; inputs.hyprlang.follows = "hyprlang";
inputs.hyprutils.follows = "hyprutils"; inputs.hyprutils.follows = "hyprutils";
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
}; };
pre-commit-hooks = {
url = "github:cachix/git-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = inputs @ { outputs = inputs @ {
@@ -67,6 +79,15 @@
hyprland-extras hyprland-extras
]; ];
}); });
pkgsCrossFor = eachSystem (system: crossSystem:
import nixpkgs {
localSystem = system;
inherit crossSystem;
overlays = with self.overlays; [
hyprland-packages
hyprland-extras
];
});
in { in {
overlays = import ./nix/overlays.nix {inherit self lib inputs;}; overlays = import ./nix/overlays.nix {inherit self lib inputs;};
@@ -76,6 +97,18 @@
self.packages.${system}) self.packages.${system})
// { // {
inherit (self.packages.${system}) xdg-desktop-portal-hyprland; inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run {
src = ./.;
hooks = {
hyprland-treewide-formatter = {
enable = true;
entry = "${self.formatter.${system}}/bin/hyprland-treewide-formatter";
pass_filenames = false;
excludes = ["subprojects"];
always_run = true;
};
};
};
}); });
packages = eachSystem (system: { packages = eachSystem (system: {
@@ -92,6 +125,7 @@
xdg-desktop-portal-hyprland xdg-desktop-portal-hyprland
; ;
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
}); });
devShells = eachSystem (system: { devShells = eachSystem (system: {
@@ -103,10 +137,11 @@
hardeningDisable = ["fortify"]; hardeningDisable = ["fortify"];
inputsFrom = [pkgsFor.${system}.hyprland]; inputsFrom = [pkgsFor.${system}.hyprland];
packages = [pkgsFor.${system}.clang-tools]; packages = [pkgsFor.${system}.clang-tools];
inherit (self.checks.${system}.pre-commit-check) shellHook;
}; };
}); });
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra); formatter = eachSystem (system: pkgsFor.${system}.callPackage ./nix/formatter.nix {});
nixosModules.default = import ./nix/module.nix inputs; nixosModules.default = import ./nix/module.nix inputs;
homeManagerModules.default = import ./nix/hm-module.nix self; homeManagerModules.default = import ./nix/hm-module.nix self;

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <string_view>
const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help] const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help]
commands: commands:

View File

@@ -17,6 +17,7 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <print>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -44,11 +45,11 @@ struct SInstanceData {
bool valid = true; bool valid = true;
}; };
void log(std::string str) { void log(const std::string& str) {
if (quiet) if (quiet)
return; return;
std::cout << str << "\n"; std::println("{}", str);
} }
std::string getRuntimeDir() { std::string getRuntimeDir() {
@@ -105,7 +106,7 @@ std::vector<SInstanceData> instances() {
static volatile bool sigintReceived = false; static volatile bool sigintReceived = false;
void intHandler(int sig) { void intHandler(int sig) {
sigintReceived = true; sigintReceived = true;
std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl; std::println("[hyprctl] SIGINT received, closing connection");
} }
int rollingRead(const int socket) { int rollingRead(const int socket) {
@@ -115,12 +116,12 @@ int rollingRead(const int socket) {
constexpr size_t BUFFER_SIZE = 8192; constexpr size_t BUFFER_SIZE = 8192;
std::array<char, BUFFER_SIZE> buffer = {0}; std::array<char, BUFFER_SIZE> buffer = {0};
long sizeWritten = 0; long sizeWritten = 0;
std::cout << "[hyprctl] reading from socket following up log:" << std::endl; std::println("[hyprctl] reading from socket following up log:");
while (!sigintReceived) { while (!sigintReceived) {
sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
if (sizeWritten < 0 && errno != EAGAIN) { if (sizeWritten < 0 && errno != EAGAIN) {
if (errno != EINTR) if (errno != EINTR)
std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl; std::println("Couldn't read (5): {}: {}", strerror(errno), errno);
close(socket); close(socket);
return 5; return 5;
} }
@@ -129,7 +130,7 @@ int rollingRead(const int socket) {
break; break;
if (sizeWritten > 0) { if (sizeWritten > 0) {
std::cout << std::string(buffer.data(), sizeWritten); std::println("{}", std::string(buffer.data(), sizeWritten));
buffer.fill('\0'); buffer.fill('\0');
} }
@@ -323,7 +324,7 @@ int main(int argc, char** argv) {
bool parseArgs = true; bool parseArgs = true;
if (argc < 2) { if (argc < 2) {
std::cout << USAGE << std::endl; std::println("{}", USAGE);
return 1; return 1;
} }
@@ -360,7 +361,7 @@ int main(int argc, char** argv) {
++i; ++i;
if (i >= ARGS.size()) { if (i >= ARGS.size()) {
std::cout << USAGE << std::endl; std::println("{}", USAGE);
return 1; return 1;
} }
@@ -371,24 +372,24 @@ int main(int argc, char** argv) {
const std::string& cmd = ARGS[0]; const std::string& cmd = ARGS[0];
if (cmd == "hyprpaper") { if (cmd == "hyprpaper") {
std::cout << HYPRPAPER_HELP << std::endl; std::println("{}", HYPRPAPER_HELP);
} else if (cmd == "notify") { } else if (cmd == "notify") {
std::cout << NOTIFY_HELP << std::endl; std::println("{}", NOTIFY_HELP);
} else if (cmd == "output") { } else if (cmd == "output") {
std::cout << OUTPUT_HELP << std::endl; std::println("{}", OUTPUT_HELP);
} else if (cmd == "plugin") { } else if (cmd == "plugin") {
std::cout << PLUGIN_HELP << std::endl; std::println("{}", PLUGIN_HELP);
} else if (cmd == "setprop") { } else if (cmd == "setprop") {
std::cout << SETPROP_HELP << std::endl; std::println("{}", SETPROP_HELP);
} else if (cmd == "switchxkblayout") { } else if (cmd == "switchxkblayout") {
std::cout << SWITCHXKBLAYOUT_HELP << std::endl; std::println("{}", SWITCHXKBLAYOUT_HELP);
} else { } else {
std::cout << USAGE << std::endl; std::println("{}", USAGE);
} }
return 1; return 1;
} else { } else {
std::cout << USAGE << std::endl; std::println("{}", USAGE);
return 1; return 1;
} }
@@ -399,7 +400,7 @@ int main(int argc, char** argv) {
} }
if (fullRequest.empty()) { if (fullRequest.empty()) {
std::cout << USAGE << std::endl; std::println("{}", USAGE);
return 1; return 1;
} }
@@ -476,7 +477,7 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/decorations")) else if (fullRequest.contains("/decorations"))
exitStatus = request(fullRequest, 1); exitStatus = request(fullRequest, 1);
else if (fullRequest.contains("/--help")) else if (fullRequest.contains("/--help"))
std::cout << USAGE << std::endl; std::println("{}", USAGE);
else if (fullRequest.contains("/rollinglog") && needRoll) else if (fullRequest.contains("/rollinglog") && needRoll)
exitStatus = request(fullRequest, 0, true); exitStatus = request(fullRequest, 0, true);
else { else {

View File

@@ -1,6 +1,6 @@
#include "DataState.hpp" #include "DataState.hpp"
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <iostream> #include <print>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include "PluginManager.hpp" #include "PluginManager.hpp"
@@ -8,7 +8,7 @@
std::string DataState::getDataStatePath() { std::string DataState::getDataStatePath() {
const auto HOME = getenv("HOME"); const auto HOME = getenv("HOME");
if (!HOME) { if (!HOME) {
std::cerr << "DataState: no $HOME\n"; std::println(stderr, "DataState: no $HOME");
throw std::runtime_error("no $HOME"); throw std::runtime_error("no $HOME");
return ""; return "";
} }

View File

@@ -1,12 +1,15 @@
#include "PluginManager.hpp" #include "PluginManager.hpp"
#include "../helpers/Colors.hpp" #include "../helpers/Colors.hpp"
#include "../helpers/StringUtils.hpp"
#include "../progress/CProgressBar.hpp" #include "../progress/CProgressBar.hpp"
#include "Manifest.hpp" #include "Manifest.hpp"
#include "DataState.hpp" #include "DataState.hpp"
#include <cstdio>
#include <iostream> #include <iostream>
#include <array> #include <array>
#include <filesystem> #include <filesystem>
#include <print>
#include <thread> #include <thread>
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
@@ -31,6 +34,7 @@ static std::string execAndGet(std::string cmd) {
if (!pipe) if (!pipe)
return ""; return "";
result.reserve(buffer.size());
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data(); result += buffer.data();
} }
@@ -47,10 +51,10 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
once = true; once = true;
const auto HLVERCALL = execAndGet("hyprctl version"); const auto HLVERCALL = execAndGet("hyprctl version");
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "version returned: " << HLVERCALL << "\n"; std::println("{}", verboseString("version returned: {}", HLVERCALL));
if (!HLVERCALL.contains("Tag:")) { if (!HLVERCALL.contains("Tag:")) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " You don't seem to be running Hyprland."; std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland."));
return SHyprlandVersion{}; return SHyprlandVersion{};
} }
@@ -76,7 +80,7 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
} catch (...) { ; } } catch (...) { ; }
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << " on " << hldate << ", commits " << commits << "\n"; std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits));
ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits}; ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
return ver; return ver;
@@ -102,20 +106,21 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) { if (!hasDeps()) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n"; std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio"));
return false; return false;
} }
if (DataState::pluginRepoExists(url)) { if (DataState::pluginRepoExists(url)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n"; std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Repository already installed."));
return false; return false;
} }
auto GLOBALSTATE = DataState::getGlobalState(); auto GLOBALSTATE = DataState::getGlobalState();
if (!GLOBALSTATE.dontWarnInstall) { if (!GLOBALSTATE.dontWarnInstall) {
std::cout << Colors::YELLOW << "!" << Colors::RED << " Disclaimer:\n " << Colors::RESET std::println("{}!{} Disclaimer: {}", Colors::YELLOW, Colors::RED, Colors::RESET);
<< "plugins, especially not official, have no guarantee of stability, availablity or security.\n Run them at your own risk.\n " std::println("plugins, especially not official, have no guarantee of stability, availablity or security.\n"
<< "This message will not appear again.\n"; "Run them at your own risk.\n"
"This message will not appear again.");
GLOBALSTATE.dontWarnInstall = true; GLOBALSTATE.dontWarnInstall = true;
DataState::updateGlobalState(GLOBALSTATE); DataState::updateGlobalState(GLOBALSTATE);
} }
@@ -129,7 +134,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::getline(std::cin, input); std::getline(std::cin, input);
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
std::cout << "Aborting.\n"; std::println(stderr, "Aborting.");
return false; return false;
} }
@@ -144,7 +149,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::filesystem::create_directory("/tmp/hyprpm"); std::filesystem::create_directory("/tmp/hyprpm");
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace); std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
} else if (!std::filesystem::is_directory("/tmp/hyprpm")) { } else if (!std::filesystem::is_directory("/tmp/hyprpm")) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for hyprpm\n"; std::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm"));
return false; return false;
} }
@@ -153,59 +158,59 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME; m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
if (!createSafeDirectory(m_szWorkingPluginDirectory)) { if (!createSafeDirectory(m_szWorkingPluginDirectory)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for repo\n"; std::println(stderr, "\n{}", failureString("Could not prepare working dir for repo"));
return false; return false;
} }
progress.printMessageAbove(std::string{Colors::RESET} + "Cloning " + url); progress.printMessageAbove(infoString("Cloning {}", url));
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME);
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. shell returned:\n" << ret << "\n"; std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret));
return false; return false;
} }
if (!rev.empty()) { if (!rev.empty()) {
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev); std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev);
if (ret.compare(0, 6, "fatal:") == 0) { if (ret.compare(0, 6, "fatal:") == 0) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n"; std::println(stderr, "\n{}", failureString("Could not check out revision {}. shell returned:\n{}", rev, ret));
return false; return false;
} }
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; std::println("{}", verboseString("git submodule update --init returned: {}", ret));
} }
progress.m_iSteps = 1; progress.m_iSteps = 1;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " cloned"); progress.printMessageAbove(successString("cloned"));
progress.m_szCurrentMessage = "Reading the manifest"; progress.m_szCurrentMessage = "Reading the manifest";
progress.print(); progress.print();
std::unique_ptr<CManifest> pManifest; std::unique_ptr<CManifest> pManifest;
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprpm manifest"); progress.printMessageAbove(successString("found hyprpm manifest"));
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprload manifest"); progress.printMessageAbove(successString("found hyprload manifest"));
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
} }
if (!pManifest) { if (!pManifest) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n"; std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest"));
return false; return false;
} }
if (!pManifest->m_bGood) { if (!pManifest->m_bGood) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n"; std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest"));
return false; return false;
} }
progress.m_iSteps = 2; progress.m_iSteps = 2;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:"); progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:"));
for (auto const& pl : pManifest->m_vPlugins) { for (auto const& pl : pManifest->m_vPlugins) {
std::string message = std::string{Colors::RESET} + " " + pl.name + " by "; std::string message = "" + pl.name + " by ";
for (auto const& a : pl.authors) { for (auto const& a : pl.authors) {
message += a + ", "; message += a + ", ";
} }
@@ -220,19 +225,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
if (!pManifest->m_sRepository.commitPins.empty()) { if (!pManifest->m_sRepository.commitPins.empty()) {
// check commit pins // check commit pins
progress.printMessageAbove(std::string{Colors::RESET} + "Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size()));
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin));
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; std::println("{}", verboseString("git submodule update --init returned: {}", ret));
break; break;
} }
@@ -244,12 +249,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HEADERSSTATUS = headersValid(); const auto HEADERSSTATUS = headersValid();
if (HEADERSSTATUS != HEADERS_OK) { if (HEADERSSTATUS != HEADERS_OK) {
std::cerr << "\n" << headerError(HEADERSSTATUS); std::println("\n{}", headerError(HEADERSSTATUS));
return false; return false;
} }
progress.m_iSteps = 3; progress.m_iSteps = 3;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " Hyprland headers OK"); progress.printMessageAbove(successString("Hyprland headers OK"));
progress.m_szCurrentMessage = "Building plugin(s)"; progress.m_szCurrentMessage = "Building plugin(s)";
progress.print(); progress.print();
@@ -257,35 +262,36 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) { if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n"); progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name));
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(std::string{Colors::RESET} + "Building " + p.name); progress.printMessageAbove(infoString("Building {}", p.name));
for (auto const& bs : p.buildSteps) { for (auto const& bs : p.buildSteps) {
std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n"; std::println("{}", verboseString("shell returned: {}", out));
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Plugin " + p.name + " failed to build.\n" + progress.printMessageAbove(failureString("Plugin {} failed to build.\n"
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update " " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n"
"first.\n Try re-running with -v to see " " If you are on -git, update first\n"
"more verbose output.\n"); " Try re-running with -v to see more verbose output.\n",
p.name));
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output); progress.printMessageAbove(successString("built {} into {}", p.name, p.output));
} }
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " all plugins built"); progress.printMessageAbove(successString("all plugins built"));
progress.m_iSteps = 4; progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing repository"; progress.m_szCurrentMessage = "Installing repository";
progress.print(); progress.print();
@@ -304,13 +310,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
} }
DataState::addNewPluginRepo(repo); DataState::addNewPluginRepo(repo);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " installed repository"); progress.printMessageAbove(successString("installed repository"));
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " you can now enable the plugin(s) with hyprpm enable"); progress.printMessageAbove(successString("you can now enable the plugin(s) with hyprpm enable"));
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
std::cout << "\n"; std::print("\n");
// remove build files // remove build files
std::filesystem::remove_all(m_szWorkingPluginDirectory); std::filesystem::remove_all(m_szWorkingPluginDirectory);
@@ -320,7 +326,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
bool CPluginManager::removePluginRepo(const std::string& urlOrName) { bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
if (!DataState::pluginRepoExists(urlOrName)) { if (!DataState::pluginRepoExists(urlOrName)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not remove the repository. Repository is not installed.\n"; std::println(stderr, "\n{}", failureString("Could not remove the repository. Repository is not installed."));
return false; return false;
} }
@@ -331,7 +337,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
std::getline(std::cin, input); std::getline(std::cin, input);
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
std::cout << "Aborting.\n"; std::println("Aborting.");
return false; return false;
} }
@@ -347,7 +353,7 @@ eHeadersErrors CPluginManager::headersValid() {
return HEADERS_MISSING; return HEADERS_MISSING;
// find headers commit // find headers commit
std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath()); const std::string& cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
auto headers = execAndGet(cmd.c_str()); auto headers = execAndGet(cmd.c_str());
if (!headers.contains("-I/")) if (!headers.contains("-I/"))
@@ -355,7 +361,7 @@ eHeadersErrors CPluginManager::headersValid() {
headers.pop_back(); // pop newline headers.pop_back(); // pop newline
std::string verHeader = ""; std::string verHeader;
while (!headers.empty()) { while (!headers.empty()) {
const auto PATH = headers.substr(0, headers.find(" -I/", 3)); const auto PATH = headers.substr(0, headers.find(" -I/", 3));
@@ -406,7 +412,7 @@ bool CPluginManager::updateHeaders(bool force) {
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) { if (!hasDeps()) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n"; std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio"));
return false; return false;
} }
@@ -416,7 +422,7 @@ bool CPluginManager::updateHeaders(bool force) {
} }
if (!force && headersValid() == HEADERS_OK) { if (!force && headersValid() == HEADERS_OK) {
std::cout << "\n" << std::string{Colors::GREEN} + "" + Colors::RESET + " Headers up to date.\n"; std::println("\n{}", successString("Headers up to date."));
return true; return true;
} }
@@ -430,74 +436,73 @@ bool CPluginManager::updateHeaders(bool force) {
const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME; const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME;
if (!createSafeDirectory(WORKINGDIR)) { if (!createSafeDirectory(WORKINGDIR)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for hl\n"; std::println("\n{}", failureString("Could not prepare working dir for hl"));
return false; return false;
} }
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment."));
const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow; const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow;
// let us give a bit of leg-room for shallowing // let us give a bit of leg-room for shallowing
// due to timezones, etc. // due to timezones, etc.
const std::string SHALLOW_DATE = const std::string SHALLOW_DATE = trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+%a %b %d %H:%M:%S %Y'");
trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'");
if (m_bVerbose && bShallow) if (m_bVerbose && bShallow)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE));
std::string ret = std::string ret =
execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")); execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""));
if (!std::filesystem::exists(WORKINGDIR)) { if (!std::filesystem::exists(WORKINGDIR)) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Clone failed. Retrying without shallow."); progress.printMessageAbove(failureString("Clone failed. Retrying without shallow."));
ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME); ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME);
} }
if (!std::filesystem::exists(WORKINGDIR + "/.git")) { if (!std::filesystem::exists(WORKINGDIR + "/.git")) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n"; std::println(stderr, "\n{}", failureString("Could not clone the Hyprland repository. shell returned:\n{}", ret));
return false; return false;
} }
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " cloned"); progress.printMessageAbove(successString("Hyprland cloned"));
progress.m_iSteps = 2; progress.m_iSteps = 2;
progress.m_szCurrentMessage = "Checking out sources"; progress.m_szCurrentMessage = "Checking out sources";
progress.print(); progress.print();
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); progress.printMessageAbove(verboseString("will run: cd {} && git checkout {} 2>&1", WORKINGDIR, HLVER.hash));
ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
if (ret.contains("fatal: unable to read tree")) { if (ret.contains("fatal: unable to read tree")) {
std::cerr << "\n" std::println(stderr, "\n{}",
<< Colors::RED << "" << Colors::RESET failureString("Could not checkout the running Hyprland commit. If you are on -git, try updating.\n"
<< " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n"; "You can also try re-running hyprpm update with --no-shallow."));
return false; return false;
} }
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret); progress.printMessageAbove(verboseString("git returned (co): {}", ret));
ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash); ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret); progress.printMessageAbove(verboseString("git returned (rs): {}", ret));
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " checked out to running ver"); progress.printMessageAbove(successString("checked out to running ver"));
progress.m_iSteps = 3; progress.m_iSteps = 3;
progress.m_szCurrentMessage = "Building Hyprland"; progress.m_szCurrentMessage = "Building Hyprland";
progress.print(); progress.print();
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland"); progress.printMessageAbove(statusString("!", Colors::YELLOW, "configuring Hyprland"));
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath()); progress.printMessageAbove(verboseString("setting PREFIX for cmake to {}", DataState::getHeadersPath()));
ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR, ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR,
DataState::getHeadersPath())); DataState::getHeadersPath()));
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret); progress.printMessageAbove(verboseString("cmake returned: {}", ret));
if (ret.contains("CMake Error at")) { if (ret.contains("CMake Error at")) {
// missing deps, let the user know. // missing deps, let the user know.
@@ -506,48 +511,46 @@ bool CPluginManager::updateHeaders(bool force) {
missing = missing.substr(0, missing.find("-- Configuring incomplete")); missing = missing.substr(0, missing.find("-- Configuring incomplete"));
missing = missing.substr(0, missing.find_last_of('\n')); missing = missing.substr(0, missing.find_last_of('\n'));
std::cerr << "\n" std::println(stderr, "\n{}",
<< Colors::RED << "" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" failureString("Could not configure the hyprland source, cmake complained:\n{}\n\n"
<< missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n"; "This likely means that you are missing the above dependencies or they are out of date.",
missing));
return false; return false;
} }
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland"); progress.printMessageAbove(successString("configured Hyprland"));
progress.m_iSteps = 4; progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";
progress.print(); progress.print();
std::string cmd = const std::string& cmd =
std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR); std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd); progress.printMessageAbove(verboseString("installation will run: {}", cmd));
ret = execAndGet(cmd); ret = execAndGet(cmd);
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n"; std::println("{}", verboseString("installer returned: {}", ret));
// remove build files // remove build files
std::filesystem::remove_all(WORKINGDIR); std::filesystem::remove_all(WORKINGDIR);
auto HEADERSVALID = headersValid(); auto HEADERSVALID = headersValid();
if (HEADERSVALID == HEADERS_OK) { if (HEADERSVALID == HEADERS_OK) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " installed headers"); progress.printMessageAbove(successString("installed headers"));
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
std::cout << "\n"; std::print("\n");
} else { } else {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" + progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID)));
headerErrorShort(HEADERSVALID) + ")");
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Failed"; progress.m_szCurrentMessage = "Failed";
progress.print(); progress.print();
std::cout << "\n"; std::print(stderr, "\n\n{}", headerError(HEADERSVALID));
std::cerr << "\n" << headerError(HEADERSVALID);
return false; return false;
} }
@@ -557,14 +560,14 @@ bool CPluginManager::updateHeaders(bool force) {
bool CPluginManager::updatePlugins(bool forceUpdateAll) { bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (headersValid() != HEADERS_OK) { if (headersValid() != HEADERS_OK) {
std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n"; std::println("{}", failureString("headers are not up-to-date, please run hyprpm update."));
return false; return false;
} }
const auto REPOS = DataState::getAllRepositories(); const auto REPOS = DataState::getAllRepositories();
if (REPOS.size() < 1) { if (REPOS.size() < 1) {
std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " No repos to update.\n"; std::println("{}", failureString("No repos to update."));
return true; return true;
} }
@@ -586,25 +589,26 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.m_szCurrentMessage = "Updating " + repo.name; progress.m_szCurrentMessage = "Updating " + repo.name;
progress.print(); progress.print();
progress.printMessageAbove(std::string{Colors::RESET} + "checking for updates for " + repo.name); progress.printMessageAbove(infoString("checking for updates for {}", repo.name));
createSafeDirectory(m_szWorkingPluginDirectory); createSafeDirectory(m_szWorkingPluginDirectory);
progress.printMessageAbove(std::string{Colors::RESET} + "Cloning " + repo.url); progress.printMessageAbove(infoString("Cloning {}", repo.url));
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME);
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not clone repo: shell returned:\n" + ret; std::println("{}", failureString("could not clone repo: shell returned: {}", ret));
return false; return false;
} }
if (!repo.rev.empty()) { if (!repo.rev.empty()) {
progress.printMessageAbove(std::string{Colors::RESET} + "Plugin has revision set, resetting: " + repo.rev); progress.printMessageAbove(infoString("Plugin has revision set, resetting: {}", repo.rev));
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev); std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev);
if (ret.compare(0, 6, "fatal:") == 0) { if (ret.compare(0, 6, "fatal:") == 0) {
std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret; std::println(stderr, "\n{}", failureString("could not check out revision {}: shell returned:\n{}", repo.rev, ret));
return false; return false;
} }
} }
@@ -620,7 +624,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (!update) { if (!update) {
std::filesystem::remove_all(m_szWorkingPluginDirectory); std::filesystem::remove_all(m_szWorkingPluginDirectory);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " repository " + repo.name + " is up-to-date."); progress.printMessageAbove(successString("repository {} is up-to-date.", repo.name));
progress.m_iSteps++; progress.m_iSteps++;
progress.print(); progress.print();
continue; continue;
@@ -628,41 +632,41 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
// we need to update // we need to update
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " repository " + repo.name + " has updates."); progress.printMessageAbove(successString("repository {} has updates.", repo.name));
progress.printMessageAbove(std::string{Colors::RESET} + "Building " + repo.name); progress.printMessageAbove(infoString("Building {}", repo.name));
progress.m_iSteps++; progress.m_iSteps++;
progress.print(); progress.print();
std::unique_ptr<CManifest> pManifest; std::unique_ptr<CManifest> pManifest;
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprpm manifest"); progress.printMessageAbove(successString("found hyprpm manifest"));
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprload manifest"); progress.printMessageAbove(successString("found hyprload manifest"));
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
} }
if (!pManifest) { if (!pManifest) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n"; std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest"));
continue; continue;
} }
if (!pManifest->m_bGood) { if (!pManifest->m_bGood) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n"; std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest"));
continue; continue;
} }
if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) { if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) {
// check commit pins unless a revision is specified // check commit pins unless a revision is specified
progress.printMessageAbove(std::string{Colors::RESET} + "Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size()));
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin));
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
} }
@@ -672,32 +676,33 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) { if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n"); progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name));
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(std::string{Colors::RESET} + "Building " + p.name); progress.printMessageAbove(infoString("Building {}", p.name));
for (auto const& bs : p.buildSteps) { for (auto const& bs : p.buildSteps) {
std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n"; std::println("{}", verboseString("shell returned: {}", out));
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
std::cerr << "\n" std::println(stderr,
<< Colors::RED << "" << Colors::RESET << " Plugin " << p.name << " failed to build.\n" "\n{}\n"
<< " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update first.\n Try " " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n"
"re-running with -v to see more verbose " "If you are on -git, update first.\n"
"output.\n"; "Try re-running with -v to see more verbose output.",
failureString("Plugin {} failed to build.", p.name));
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output); progress.printMessageAbove(successString("built {} into {}", p.name, p.output));
} }
// add repo toml to DataState // add repo toml to DataState
@@ -718,7 +723,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
std::filesystem::remove_all(m_szWorkingPluginDirectory); std::filesystem::remove_all(m_szWorkingPluginDirectory);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " updated " + repo.name); progress.printMessageAbove(successString("updated {}", repo.name));
} }
progress.m_iSteps++; progress.m_iSteps++;
@@ -733,7 +738,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
std::cout << "\n"; std::print("\n");
return true; return true;
} }
@@ -741,27 +746,27 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
bool CPluginManager::enablePlugin(const std::string& name) { bool CPluginManager::enablePlugin(const std::string& name) {
bool ret = DataState::setPluginEnabled(name, true); bool ret = DataState::setPluginEnabled(name, true);
if (ret) if (ret)
std::cout << Colors::GREEN << "" << Colors::RESET << " Enabled " << name << "\n"; std::println("{}", successString("Enabled {}", name));
return ret; return ret;
} }
bool CPluginManager::disablePlugin(const std::string& name) { bool CPluginManager::disablePlugin(const std::string& name) {
bool ret = DataState::setPluginEnabled(name, false); bool ret = DataState::setPluginEnabled(name, false);
if (ret) if (ret)
std::cout << Colors::GREEN << "" << Colors::RESET << " Disabled " << name << "\n"; std::println("{}", successString("Disabled {}", name));
return ret; return ret;
} }
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (headersValid() != HEADERS_OK) { if (headersValid() != HEADERS_OK) {
std::cerr << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n"; std::println(stderr, "\n{}", failureString("headers are not up-to-date, please run hyprpm update."));
return LOADSTATE_HEADERS_OUTDATED; return LOADSTATE_HEADERS_OUTDATED;
} }
const auto HOME = getenv("HOME"); const auto HOME = getenv("HOME");
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE"); const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!HOME || !HIS) { if (!HOME || !HIS) {
std::cerr << "PluginManager: no $HOME or HIS\n"; std::println(stderr, "PluginManager: no $HOME or HIS");
return LOADSTATE_FAIL; return LOADSTATE_FAIL;
} }
const auto HYPRPMPATH = DataState::getDataStatePath() + "/"; const auto HYPRPMPATH = DataState::getDataStatePath() + "/";
@@ -770,14 +775,14 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
std::vector<std::string> loadedPlugins; std::vector<std::string> loadedPlugins;
std::cout << Colors::GREEN << "" << Colors::RESET << " Ensuring plugin load state\n"; std::println("{}", successString("Ensuring plugin load state"));
// iterate line by line // iterate line by line
while (!pluginLines.empty()) { while (!pluginLines.empty()) {
auto plLine = pluginLines.substr(0, pluginLines.find("\n")); auto plLine = pluginLines.substr(0, pluginLines.find('\n'));
if (pluginLines.find("\n") != std::string::npos) if (pluginLines.find('\n') != std::string::npos)
pluginLines = pluginLines.substr(pluginLines.find("\n") + 1); pluginLines = pluginLines.substr(pluginLines.find('\n') + 1);
else else
pluginLines = ""; pluginLines = "";
@@ -820,7 +825,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (!enabled(p)) { if (!enabled(p)) {
// unload // unload
loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false); loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false);
std::cout << Colors::GREEN << "" << Colors::RESET << " Unloaded " << p << "\n"; std::println("{}", successString("Unloaded {}", p));
} }
} }
@@ -834,11 +839,11 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
continue; continue;
loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true); loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true);
std::cout << Colors::GREEN << "" << Colors::RESET << " Loaded " << p.name << "\n"; std::println("{}", successString("Loaded {}", p.name));
} }
} }
std::cout << Colors::GREEN << "" << Colors::RESET << " Plugin load state ensured\n"; std::println("{}", successString("Plugin load state ensured"));
return LOADSTATE_OK; return LOADSTATE_OK;
} }
@@ -856,16 +861,17 @@ void CPluginManager::listAllPlugins() {
const auto REPOS = DataState::getAllRepositories(); const auto REPOS = DataState::getAllRepositories();
for (auto const& r : REPOS) { for (auto const& r : REPOS) {
std::cout << std::string{Colors::RESET} + "Repository " + r.name + ":\n"; std::println("{}", infoString("Repository {}:", r.name));
for (auto const& p : r.plugins) { for (auto const& p : r.plugins) {
std::println(" │ Plugin {}", p.name);
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
if (!p.failed) if (!p.failed)
std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n"; std::println(" └─ enabled: {}", (p.enabled ? std::string{Colors::GREEN} + "true" : std::string{Colors::RED} + "false"));
else else
std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n"; std::println(" └─ enabled: {}Plugin failed to build", Colors::RED);
std::println("{}", Colors::RESET);
} }
} }
} }
@@ -876,19 +882,19 @@ void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int duratio
std::string CPluginManager::headerError(const eHeadersErrors err) { std::string CPluginManager::headerError(const eHeadersErrors err) {
switch (err) { switch (err) {
case HEADERS_CORRUPTED: return std::string{Colors::RED} + "" + Colors::RESET + " Headers corrupted. Please run hyprpm update to fix those.\n"; case HEADERS_CORRUPTED: return failureString("Headers corrupted. Please run hyprpm update to fix those.\n");
case HEADERS_MISMATCHED: return std::string{Colors::RED} + "" + Colors::RESET + " Headers version mismatch. Please run hyprpm update to fix those.\n"; case HEADERS_MISMATCHED: return failureString("Headers version mismatch. Please run hyprpm update to fix those.\n");
case HEADERS_NOT_HYPRLAND: return std::string{Colors::RED} + "" + Colors::RESET + " It doesn't seem you are running on hyprland.\n"; case HEADERS_NOT_HYPRLAND: return failureString("It doesn't seem you are running on hyprland.\n");
case HEADERS_MISSING: return std::string{Colors::RED} + "" + Colors::RESET + " Headers missing. Please run hyprpm update to fix those.\n"; case HEADERS_MISSING: return failureString("Headers missing. Please run hyprpm update to fix those.\n");
case HEADERS_DUPLICATED: { case HEADERS_DUPLICATED: {
return std::string{Colors::RED} + "" + Colors::RESET + " Headers duplicated!!! This is a very bad sign.\n" + return failureString("Headers duplicated!!! This is a very bad sign.\n"
" This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" + "This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n"
" If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n"; "If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n");
} }
default: break; default: break;
} }
return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n"; return failureString("Unknown header error. Please run hyprpm update to fix those.\n");
} }
std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {

View File

@@ -2,6 +2,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
enum eHeadersErrors { enum eHeadersErrors {
HEADERS_OK = 0, HEADERS_OK = 0,
@@ -68,7 +69,7 @@ class CPluginManager {
std::string headerError(const eHeadersErrors err); std::string headerError(const eHeadersErrors err);
std::string headerErrorShort(const eHeadersErrors err); std::string headerErrorShort(const eHeadersErrors err);
std::string m_szWorkingPluginDirectory = ""; std::string m_szWorkingPluginDirectory;
}; };
inline std::unique_ptr<CPluginManager> g_pPluginManager; inline std::unique_ptr<CPluginManager> g_pPluginManager;

View File

@@ -0,0 +1,32 @@
#pragma once
#include <format>
#include <string>
#include "Colors.hpp"
template <typename... Args>
std::string statusString(const std::string_view emoji, const std::string_view color, const std::string_view fmt, Args&&... args) {
std::string ret = std::format("{}{}{} ", color, emoji, Colors::RESET);
ret += std::vformat(fmt, std::make_format_args(args...));
return ret;
}
template <typename... Args>
std::string successString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::GREEN, fmt, args...);
}
template <typename... Args>
std::string failureString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::RED, fmt, args...);
}
template <typename... Args>
std::string verboseString(const std::string_view fmt, Args&&... args) {
return statusString("[v]", Colors::BLUE, fmt, args...);
}
template <typename... Args>
std::string infoString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::RESET, fmt, args...);
}

View File

@@ -1,15 +1,16 @@
#include "progress/CProgressBar.hpp"
#include "helpers/Colors.hpp" #include "helpers/Colors.hpp"
#include "helpers/StringUtils.hpp"
#include "core/PluginManager.hpp" #include "core/PluginManager.hpp"
#include "core/DataState.hpp" #include "core/DataState.hpp"
#include <iostream> #include <cstdio>
#include <vector> #include <vector>
#include <string> #include <string>
#include <print>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
add [url] [git rev] Install a new plugin repository from git. Git revision add [url] [git rev] Install a new plugin repository from git. Git revision
is optional, when set, commit locks are ignored. is optional, when set, commit locks are ignored.
@@ -22,7 +23,8 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
Flags: Flags:
--notify | -n Send a hyprland notification for important events (e.g. load fail) --notify | -n Send a hyprland notification for important events (including both successes and fail events)
--notify-fail | -nn Send a hyprland notification for fail events only
--help | -h Show this menu --help | -h Show this menu
--verbose | -v Enable too much logging --verbose | -v Enable too much logging
--force | -f Force an operation ignoring checks (e.g. update -f) --force | -f Force an operation ignoring checks (e.g. update -f)
@@ -37,29 +39,31 @@ int main(int argc, char** argv, char** envp) {
} }
if (ARGS.size() < 2) { if (ARGS.size() < 2) {
std::cout << HELP; std::println(stderr, "{}", HELP);
return 1; return 1;
} }
std::vector<std::string> command; std::vector<std::string> command;
bool notify = false, verbose = false, force = false, noShallow = false; bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) { if (ARGS[i].starts_with("-")) {
if (ARGS[i] == "--help" || ARGS[i] == "-h") { if (ARGS[i] == "--help" || ARGS[i] == "-h") {
std::cout << HELP; std::println("{}", HELP);
return 0; return 0;
} else if (ARGS[i] == "--notify" || ARGS[i] == "-n") { } else if (ARGS[i] == "--notify" || ARGS[i] == "-n") {
notify = true; notify = true;
} else if (ARGS[i] == "--notify-fail" || ARGS[i] == "-nn") {
notifyFail = notify = true;
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") { } else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
verbose = true; verbose = true;
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") { } else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
noShallow = true; noShallow = true;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") { } else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true; force = true;
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n"; std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing."));
} else { } else {
std::cerr << "Unrecognized option " << ARGS[i] << "\n"; std::println(stderr, "Unrecognized option {}", ARGS[i]);
return 1; return 1;
} }
} else { } else {
@@ -68,7 +72,7 @@ int main(int argc, char** argv, char** envp) {
} }
if (command.empty()) { if (command.empty()) {
std::cout << HELP; std::println(stderr, "{}", HELP);
return 0; return 0;
} }
@@ -78,7 +82,7 @@ int main(int argc, char** argv, char** envp) {
if (command[0] == "add") { if (command[0] == "add") {
if (command.size() < 2) { if (command.size() < 2) {
std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for add.\n"; std::println(stderr, "{}", failureString("Not enough args for add."));
return 1; return 1;
} }
@@ -90,7 +94,7 @@ int main(int argc, char** argv, char** envp) {
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1; return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
} else if (command[0] == "remove") { } else if (command[0] == "remove") {
if (ARGS.size() < 2) { if (ARGS.size() < 2) {
std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for remove.\n"; std::println(stderr, "{}", failureString("Not enough args for remove."));
return 1; return 1;
} }
@@ -116,12 +120,12 @@ int main(int argc, char** argv, char** envp) {
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers"); g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers");
} else if (command[0] == "enable") { } else if (command[0] == "enable") {
if (ARGS.size() < 2) { if (ARGS.size() < 2) {
std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for enable.\n"; std::println(stderr, "{}", failureString("Not enough args for enable."));
return 1; return 1;
} }
if (!g_pPluginManager->enablePlugin(command[1])) { if (!g_pPluginManager->enablePlugin(command[1])) {
std::cerr << Colors::RED << "" << Colors::RESET << " Couldn't enable plugin (missing?)\n"; std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)"));
return 1; return 1;
} }
@@ -130,12 +134,12 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} else if (command[0] == "disable") { } else if (command[0] == "disable") {
if (command.size() < 2) { if (command.size() < 2) {
std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for disable.\n"; std::println(stderr, "{}", failureString("Not enough args for disable."));
return 1; return 1;
} }
if (!g_pPluginManager->disablePlugin(command[1])) { if (!g_pPluginManager->disablePlugin(command[1])) {
std::cerr << Colors::RED << "" << Colors::RESET << " Couldn't disable plugin (missing?)\n"; std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)"));
return 1; return 1;
} }
@@ -154,13 +158,13 @@ int main(int argc, char** argv, char** envp) {
break; break;
default: break; default: break;
} }
} else if (notify) { } else if (notify && !notifyFail) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins"); g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
} }
} else if (command[0] == "list") { } else if (command[0] == "list") {
g_pPluginManager->listAllPlugins(); g_pPluginManager->listAllPlugins();
} else { } else {
std::cout << HELP; std::println(stderr, "{}", HELP);
return 1; return 1;
} }

View File

@@ -1,11 +1,11 @@
#include "CProgressBar.hpp" #include "CProgressBar.hpp"
#include <iostream> #include <sys/ioctl.h>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <format> #include <format>
#include <sys/ioctl.h> #include <print>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@@ -16,11 +16,12 @@ void CProgressBar::printMessageAbove(const std::string& msg) {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
std::string spaces; std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) { for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' '; spaces += ' ';
} }
std::cout << "\r" << spaces << "\r" << msg << "\n"; std::println("\r{}\r{}", spaces, msg);
print(); print();
} }
@@ -29,15 +30,16 @@ void CProgressBar::print() {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (m_bFirstPrint) if (m_bFirstPrint)
std::cout << "\n"; std::print("\n");
m_bFirstPrint = false; m_bFirstPrint = false;
std::string spaces; std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) { for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' '; spaces += ' ';
} }
std::cout << "\r" << spaces << "\r"; std::print("\r{}\r", spaces);
std::string message = ""; std::string message = "";
@@ -74,7 +76,7 @@ void CProgressBar::print() {
message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " "; message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " ";
// draw message // draw message
std::cout << message + " " + m_szCurrentMessage; std::print("{} {}", message, m_szCurrentMessage);
std::fflush(stdout); std::fflush(stdout);
} }

View File

@@ -21,6 +21,7 @@ add_project_arguments(
'-Wno-missing-field-initializers', '-Wno-missing-field-initializers',
'-Wno-narrowing', '-Wno-narrowing',
'-Wno-pointer-arith', datarootdir, '-Wno-pointer-arith', datarootdir,
'-DHYPRLAND_VERSION="' + meson.project_version() + '"',
], ],
language: 'cpp', language: 'cpp',
) )
@@ -30,7 +31,7 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif endif
aquamarine = dependency('aquamarine') aquamarine = dependency('aquamarine', version: '>=0.4.2')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_dep = dependency('xcb', required: get_option('xwayland'))
@@ -43,10 +44,6 @@ xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland'))
gio_dep = dependency('gio-2.0', required: true) gio_dep = dependency('gio-2.0', required: true)
cmake = import('cmake')
udis = cmake.subproject('udis86')
udis86 = udis.dependency('libudis86')
if not xcb_dep.found() if not xcb_dep.found()
add_project_arguments('-DNO_XWAYLAND', language: 'cpp') add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif endif
@@ -56,7 +53,9 @@ epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs
# Handle options # Handle options
if get_option('systemd').enabled() if get_option('systemd').enabled()
systemd = dependency('systemd')
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp') add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
subdir('systemd')
endif endif
if get_option('legacy_renderer').enabled() if get_option('legacy_renderer').enabled()
@@ -77,6 +76,14 @@ foreach file : headers
install_headers(file, subdir: 'hyprland', preserve_path: true) install_headers(file, subdir: 'hyprland', preserve_path: true)
endforeach endforeach
tracy = dependency('tracy', static: true, required: get_option('tracy_enable'))
if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized'
warning('Profiling builds should set -- buildtype = debugoptimized')
endif
subdir('protocols') subdir('protocols')
subdir('src') subdir('src')
subdir('hyprctl') subdir('hyprctl')

View File

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

View File

@@ -1,10 +0,0 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6fdf98db..d8424d91 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.30)
+cmake_minimum_required(VERSION 3.27)
# Get version
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)

View File

@@ -5,16 +5,17 @@
pkg-config, pkg-config,
pkgconf, pkgconf,
makeWrapper, makeWrapper,
cmake, meson,
ninja,
aquamarine, aquamarine,
binutils, binutils,
cairo, cairo,
git, git,
hyprcursor, hyprcursor,
hyprland-protocols,
hyprlang, hyprlang,
hyprutils, hyprutils,
hyprwayland-scanner, hyprwayland-scanner,
jq,
libGL, libGL,
libdrm, libdrm,
libexecinfo, libexecinfo,
@@ -24,9 +25,9 @@
mesa, mesa,
pango, pango,
pciutils, pciutils,
python3,
systemd, systemd,
tomlplusplus, tomlplusplus,
udis86-hyprland,
wayland, wayland,
wayland-protocols, wayland-protocols,
wayland-scanner, wayland-scanner,
@@ -51,10 +52,11 @@
inherit (lib.attrsets) mapAttrsToList; inherit (lib.attrsets) mapAttrsToList;
inherit (lib.lists) flatten concatLists optional optionals; inherit (lib.lists) flatten concatLists optional optionals;
inherit (lib.sources) cleanSourceWith cleanSource; inherit (lib.sources) cleanSourceWith cleanSource;
inherit (lib.strings) cmakeBool hasSuffix makeBinPath optionalString; inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable;
adapters = flatten [ adapters = flatten [
stdenvAdapters.useMoldLinker stdenvAdapters.useMoldLinker
(lib.optional debug stdenvAdapters.keepDebugInfo)
]; ];
customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters; customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters;
@@ -67,21 +69,13 @@ in
inherit version; inherit version;
src = cleanSourceWith { src = cleanSourceWith {
filter = name: type: let filter = name: _type: let
baseName = baseNameOf (toString name); baseName = baseNameOf (toString name);
in in
! (hasSuffix ".nix" baseName); ! (hasSuffix ".nix" baseName);
src = cleanSource ../.; src = cleanSource ../.;
}; };
patches = [
# forces GCC to use -std=c++26
./stdcxx.patch
# Nix does not have CMake 3.30 yet, so override the minimum version
./cmake-version.patch
];
postPatch = '' postPatch = ''
# Fix hardcoded paths to /usr installation # Fix hardcoded paths to /usr installation
sed -i "s#/usr#$out#" src/render/OpenGL.cpp sed -i "s#/usr#$out#" src/render/OpenGL.cpp
@@ -101,12 +95,10 @@ in
nativeBuildInputs = [ nativeBuildInputs = [
hyprwayland-scanner hyprwayland-scanner
jq
makeWrapper makeWrapper
cmake meson
ninja
pkg-config pkg-config
python3 # for udis86
wayland-scanner
]; ];
outputs = [ outputs = [
@@ -121,6 +113,7 @@ in
cairo cairo
git git
hyprcursor hyprcursor
hyprland-protocols
hyprlang hyprlang
hyprutils hyprutils
libdrm libdrm
@@ -132,8 +125,10 @@ in
pango pango
pciutils pciutils
tomlplusplus tomlplusplus
udis86-hyprland
wayland wayland
wayland-protocols wayland-protocols
wayland-scanner
xorg.libXcursor xorg.libXcursor
] ]
(optionals customStdenv.hostPlatform.isMusl [libexecinfo]) (optionals customStdenv.hostPlatform.isMusl [libexecinfo])
@@ -148,20 +143,22 @@ in
(optional withSystemd systemd) (optional withSystemd systemd)
]; ];
cmakeBuildType = mesonBuildType =
if debug if debug
then "Debug" then "debugoptimized"
else "RelWithDebInfo"; else "release";
# we want as much debug info as possible mesonFlags = flatten [
dontStrip = debug; (mapAttrsToList mesonEnable {
"xwayland" = enableXWayland;
cmakeFlags = mapAttrsToList cmakeBool { "legacy_renderer" = legacyRenderer;
"NO_XWAYLAND" = !enableXWayland; "systemd" = withSystemd;
"LEGACY_RENDERER" = legacyRenderer; })
"NO_SYSTEMD" = !withSystemd; (mapAttrsToList mesonBool {
"CMAKE_DISABLE_PRECOMPILE_HEADERS" = true; "b_pch" = false;
}; "tracy_enable" = false;
})
];
postInstall = '' postInstall = ''
${optionalString wrapRuntimeDeps '' ${optionalString wrapRuntimeDeps ''

64
nix/formatter.nix Normal file
View File

@@ -0,0 +1,64 @@
{
writeShellApplication,
deadnix,
statix,
alejandra,
llvmPackages_19,
fd,
}:
writeShellApplication {
name = "hyprland-treewide-formatter";
runtimeInputs = [
deadnix
statix
alejandra
llvmPackages_19.clang-tools
fd
];
text = ''
# shellcheck disable=SC2148
# common excludes
excludes="subprojects"
nix_format() {
if [ "$*" = 0 ]; then
fd '.*\.nix' . -E "$excludes" -x statix fix -- {} \;
fd '.*\.nix' . -E "$excludes" -X deadnix -e -- {} \; -X alejandra {} \;
elif [ -d "$1" ]; then
fd '.*\.nix' "$1" -E "$excludes" -i -x statix fix -- {} \;
fd '.*\.nix' "$1" -E "$excludes" -i -X deadnix -e -- {} \; -X alejandra {} \;
else
statix fix -- "$1"
deadnix -e "$1"
alejandra "$1"
fi
}
cpp_format() {
if [ "$*" = 0 ] || [ "$1" = "." ]; then
fd '.*\.cpp' . -E "$excludes" | xargs clang-format --verbose -i
elif [ -d "$1" ]; then
fd '.*\.cpp' "$1" -E "$excludes" | xargs clang-format --verbose -i
else
clang-format --verbose -i "$1"
fi
}
for i in "$@"; do
case ''${i##*.} in
"nix")
nix_format "$i"
;;
"cpp")
cpp_format "$i"
;;
*)
nix_format "$i"
cpp_format "$i"
;;
esac
done
'';
}

View File

@@ -22,12 +22,14 @@ in {
# Dependencies # Dependencies
inputs.aquamarine.overlays.default inputs.aquamarine.overlays.default
inputs.hyprcursor.overlays.default inputs.hyprcursor.overlays.default
inputs.hyprland-protocols.overlays.default
inputs.hyprlang.overlays.default inputs.hyprlang.overlays.default
inputs.hyprutils.overlays.default inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default inputs.hyprwayland-scanner.overlays.default
self.overlays.udis86
# Hyprland packages themselves # Hyprland packages themselves
(final: prev: let (final: _prev: let
date = mkDate (self.lastModifiedDate or "19700101"); date = mkDate (self.lastModifiedDate or "19700101");
in { in {
hyprland = final.callPackage ./default.nix { hyprland = final.callPackage ./default.nix {
@@ -38,7 +40,13 @@ in {
inherit date; inherit date;
}; };
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;}; hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
hyprland-debug = final.hyprland.override {debug = true;};
# Build major libs with debug to get as much info as possible in a stacktrace
hyprland-debug = final.hyprland.override {
aquamarine = final.aquamarine.override {debug = true;};
hyprutils = final.hyprutils.override {debug = true;};
debug = true;
};
hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;}; hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;};
# deprecated packages # deprecated packages
@@ -61,6 +69,22 @@ in {
# Packages for extra software recommended for usage with Hyprland, # Packages for extra software recommended for usage with Hyprland,
# including forked or patched packages for compatibility. # including forked or patched packages for compatibility.
hyprland-extras = lib.composeManyExtensions [ hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.xdg-desktop-portal-hyprland inputs.xdph.overlays.default
]; ];
# udis86 from nixpkgs is too old, and also does not provide a .pc file
# this version is the one used in the git submodule, and allows us to
# fetch the source without '?submodules=1'
udis86 = final: prev: {
udis86-hyprland = prev.udis86.overrideAttrs (_self: _super: {
src = final.fetchFromGitHub {
owner = "canihavesomecoffee";
repo = "udis86";
rev = "5336633af70f3917760a6d441ff02d93477b0c86";
hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g=";
};
patches = [];
});
};
} }

View File

@@ -1,12 +0,0 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cfbd431f..73e8e0c2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,6 +64,7 @@ endif()
include_directories(. "src/" "subprojects/udis86/" "protocols/")
set(CMAKE_CXX_STANDARD 26)
add_compile_options(
+ -std=c++26
-Wall
-Wextra
-Wno-unused-parameter

View File

@@ -7,7 +7,7 @@ wayland_protos = dependency(
hyprland_protos = dependency( hyprland_protos = dependency(
'hyprland-protocols', 'hyprland-protocols',
version: '>=0.2', version: '>=0.4',
fallback: 'hyprland-protocols', fallback: 'hyprland-protocols',
) )
@@ -36,6 +36,7 @@ protocols = [
hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml',
wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml', wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml',
wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
@@ -63,6 +64,8 @@ protocols = [
wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml',
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
wayland_protocol_dir / 'staging/security-context/security-context-v1.xml',
] ]
wl_protocols = [] wl_protocols = []

View File

@@ -1,4 +1,5 @@
#include "Compositor.hpp" #include "Compositor.hpp"
#include "debug/Log.hpp"
#include "helpers/Splashes.hpp" #include "helpers/Splashes.hpp"
#include "config/ConfigValue.hpp" #include "config/ConfigValue.hpp"
#include "managers/CursorManager.hpp" #include "managers/CursorManager.hpp"
@@ -8,7 +9,9 @@
#include "managers/eventLoop/EventLoopManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp"
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
#include <bit> #include <bit>
#include <ctime>
#include <random> #include <random>
#include <print>
#include <cstring> #include <cstring>
#include <filesystem> #include <filesystem>
#include <unordered_set> #include <unordered_set>
@@ -23,11 +26,15 @@
#include "protocols/PointerConstraints.hpp" #include "protocols/PointerConstraints.hpp"
#include "protocols/LayerShell.hpp" #include "protocols/LayerShell.hpp"
#include "protocols/XDGShell.hpp" #include "protocols/XDGShell.hpp"
#include "protocols/XDGOutput.hpp"
#include "protocols/SecurityContext.hpp"
#include "protocols/core/Compositor.hpp" #include "protocols/core/Compositor.hpp"
#include "protocols/core/Subcompositor.hpp" #include "protocols/core/Subcompositor.hpp"
#include "desktop/LayerSurface.hpp" #include "desktop/LayerSurface.hpp"
#include "render/Renderer.hpp" #include "render/Renderer.hpp"
#include "xwayland/XWayland.hpp" #include "xwayland/XWayland.hpp"
#include "helpers/ByteOperations.hpp"
#include "render/decorations/CHyprGroupBarDecoration.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>
@@ -134,37 +141,37 @@ CCompositor::CCompositor() {
m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr"; m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr";
if (m_szHyprTempDataRoot.starts_with("/hypr")) { if (m_szHyprTempDataRoot.starts_with("/hypr")) {
std::cout << "Bailing out, XDG_RUNTIME_DIR is invalid\n"; std::println("Bailing out, $XDG_RUNTIME_DIR is invalid");
throw std::runtime_error("CCompositor() failed"); throw std::runtime_error("CCompositor() failed");
} }
if (!m_szHyprTempDataRoot.starts_with("/run/user")) if (!m_szHyprTempDataRoot.starts_with("/run/user"))
std::cout << "[!!WARNING!!] XDG_RUNTIME_DIR looks non-standard. Proceeding anyways...\n"; std::println("[!!WARNING!!] XDG_RUNTIME_DIR looks non-standard. Proceeding anyways...");
std::random_device dev; std::random_device dev;
std::mt19937 engine(dev()); std::mt19937 engine(dev());
std::uniform_int_distribution<> distribution(0, INT32_MAX); std::uniform_int_distribution<> distribution(0, INT32_MAX);
m_szInstanceSignature = GIT_COMMIT_HASH + std::string("_") + std::to_string(time(NULL)) + "_" + std::to_string(distribution(engine)); m_szInstanceSignature = std::format("{}_{}_{}", GIT_COMMIT_HASH, std::time(NULL), distribution(engine));
setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true); setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true);
if (!std::filesystem::exists(m_szHyprTempDataRoot)) if (!std::filesystem::exists(m_szHyprTempDataRoot))
mkdir(m_szHyprTempDataRoot.c_str(), S_IRWXU); mkdir(m_szHyprTempDataRoot.c_str(), S_IRWXU);
else if (!std::filesystem::is_directory(m_szHyprTempDataRoot)) { else if (!std::filesystem::is_directory(m_szHyprTempDataRoot)) {
std::cout << "Bailing out, " << m_szHyprTempDataRoot << " is not a directory\n"; std::println("Bailing out, {} is not a directory", m_szHyprTempDataRoot);
throw std::runtime_error("CCompositor() failed"); throw std::runtime_error("CCompositor() failed");
} }
m_szInstancePath = m_szHyprTempDataRoot + "/" + m_szInstanceSignature; m_szInstancePath = m_szHyprTempDataRoot + "/" + m_szInstanceSignature;
if (std::filesystem::exists(m_szInstancePath)) { if (std::filesystem::exists(m_szInstancePath)) {
std::cout << "Bailing out, " << m_szInstancePath << " exists??\n"; std::println("Bailing out, {} exists??", m_szInstancePath);
throw std::runtime_error("CCompositor() failed"); throw std::runtime_error("CCompositor() failed");
} }
if (mkdir(m_szInstancePath.c_str(), S_IRWXU) < 0) { if (mkdir(m_szInstancePath.c_str(), S_IRWXU) < 0) {
std::cout << "Bailing out, couldn't create " << m_szInstancePath << "\n"; std::println("Bailing out, couldn't create {}", m_szInstancePath);
throw std::runtime_error("CCompositor() failed"); throw std::runtime_error("CCompositor() failed");
} }
@@ -208,11 +215,22 @@ void CCompositor::setRandomSplash() {
static std::vector<SP<Aquamarine::IOutput>> pendingOutputs; static std::vector<SP<Aquamarine::IOutput>> pendingOutputs;
//
static bool filterGlobals(const wl_client* client, const wl_global* global, void* data) {
if (!PROTO::securityContext->isClientSandboxed(client))
return true;
return !g_pProtocolManager || !g_pProtocolManager->isGlobalPrivileged(global);
}
// //
void CCompositor::initServer(std::string socketName, int socketFd) { void CCompositor::initServer(std::string socketName, int socketFd) {
m_sWLDisplay = wl_display_create(); m_sWLDisplay = wl_display_create();
wl_display_set_global_filter(m_sWLDisplay, ::filterGlobals, nullptr);
m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay); m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay);
// register crit signal handler // register crit signal handler
@@ -229,6 +247,9 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
if (envEnabled("HYPRLAND_TRACE")) if (envEnabled("HYPRLAND_TRACE"))
Debug::trace = true; Debug::trace = true;
// set the buffer size to 1MB to avoid disconnects due to an app hanging for a short while
wl_display_set_default_max_buffer_size(m_sWLDisplay, 1_MB);
Aquamarine::SBackendOptions options; Aquamarine::SBackendOptions options;
options.logFunction = aqLog; options.logFunction = aqLog;
@@ -392,8 +413,8 @@ void CCompositor::initAllSignals() {
m_bSessionActive = true; m_bSessionActive = true;
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
scheduleFrameForMonitor(m.get()); scheduleFrameForMonitor(m);
g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); g_pHyprRenderer->applyMonitorRule(m, &m->activeMonitorRule, true);
} }
g_pConfigManager->m_bWantsMonitorReload = true; g_pConfigManager->m_bWantsMonitorReload = true;
@@ -478,7 +499,7 @@ void CCompositor::cleanup() {
m_vWindows.clear(); m_vWindows.clear();
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
g_pHyprOpenGL->destroyMonitorResources(m.get()); g_pHyprOpenGL->destroyMonitorResources(m);
m->output->state->setEnabled(false); m->output->state->setEnabled(false);
m->state.commit(); m->state.commit();
@@ -697,39 +718,39 @@ void CCompositor::startCompositor() {
g_pEventLoopManager->enterLoop(); g_pEventLoopManager->enterLoop();
} }
CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) { PHLMONITOR CCompositor::getMonitorFromID(const MONITORID& id) {
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
if (m->ID == id) { if (m->ID == id) {
return m.get(); return m;
} }
} }
return nullptr; return nullptr;
} }
CMonitor* CCompositor::getMonitorFromName(const std::string& name) { PHLMONITOR CCompositor::getMonitorFromName(const std::string& name) {
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
if (m->szName == name) { if (m->szName == name) {
return m.get(); return m;
} }
} }
return nullptr; return nullptr;
} }
CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) { PHLMONITOR CCompositor::getMonitorFromDesc(const std::string& desc) {
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
if (m->szDescription.starts_with(desc)) if (m->szDescription.starts_with(desc))
return m.get(); return m;
} }
return nullptr; return nullptr;
} }
CMonitor* CCompositor::getMonitorFromCursor() { PHLMONITOR CCompositor::getMonitorFromCursor() {
return getMonitorFromVector(g_pPointerManager->position()); return getMonitorFromVector(g_pPointerManager->position());
} }
CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { PHLMONITOR CCompositor::getMonitorFromVector(const Vector2D& point) {
SP<CMonitor> mon; PHLMONITOR mon;
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) { if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) {
mon = m; mon = m;
@@ -739,7 +760,7 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
if (!mon) { if (!mon) {
float bestDistance = 0.f; float bestDistance = 0.f;
SP<CMonitor> pBestMon; PHLMONITOR pBestMon;
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize); float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize);
@@ -752,13 +773,13 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
if (!pBestMon) { // ????? if (!pBestMon) { // ?????
Debug::log(WARN, "getMonitorFromVector no close mon???"); Debug::log(WARN, "getMonitorFromVector no close mon???");
return m_vMonitors.front().get(); return m_vMonitors.front();
} }
return pBestMon.get(); return pBestMon;
} }
return mon.get(); return mon;
} }
void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) {
@@ -770,9 +791,9 @@ void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) {
} }
} }
bool CCompositor::monitorExists(CMonitor* pMonitor) { bool CCompositor::monitorExists(PHLMONITOR pMonitor) {
for (auto const& m : m_vRealMonitors) { for (auto const& m : m_vRealMonitors) {
if (m.get() == pMonitor) if (m == pMonitor)
return true; return true;
} }
@@ -790,10 +811,10 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
// pinned windows on top of floating regardless // pinned windows on top of floating regardless
if (properties & ALLOW_FLOATING) { if (properties & ALLOW_FLOATING) {
for (auto const& w : m_vWindows | std::views::reverse) { for (auto const& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowBoxUnified(properties);
CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0);
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() &&
w != pIgnoreWindow) { w != pIgnoreWindow) {
const auto BB = w->getWindowBoxUnified(properties);
CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0);
if (box.containsPoint(g_pPointerManager->position())) if (box.containsPoint(g_pPointerManager->position()))
return w; return w;
@@ -812,22 +833,25 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (special && !w->onSpecialWorkspace()) // because special floating may creep up into regular if (special && !w->onSpecialWorkspace()) // because special floating may creep up into regular
continue; continue;
const auto BB = w->getWindowBoxUnified(properties); const auto PWINDOWMONITOR = w->m_pMonitor.lock();
const auto PWINDOWMONITOR = getMonitorFromID(w->m_iMonitorID);
// to avoid focusing windows behind special workspaces from other monitors // to avoid focusing windows behind special workspaces from other monitors
if (!*PSPECIALFALLTHRU && PWINDOWMONITOR && PWINDOWMONITOR->activeSpecialWorkspace && w->m_pWorkspace != PWINDOWMONITOR->activeSpecialWorkspace && if (!*PSPECIALFALLTHRU && PWINDOWMONITOR && PWINDOWMONITOR->activeSpecialWorkspace && w->m_pWorkspace != PWINDOWMONITOR->activeSpecialWorkspace) {
BB.x >= PWINDOWMONITOR->vecPosition.x && BB.y >= PWINDOWMONITOR->vecPosition.y && const auto BB = w->getWindowBoxUnified(properties);
BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) if (BB.x >= PWINDOWMONITOR->vecPosition.x && BB.y >= PWINDOWMONITOR->vecPosition.y &&
BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x &&
BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y)
continue; continue;
}
CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0);
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() &&
w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
// OR windows should add focus to parent // OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && !w->isX11OverrideRedirect()) if (w->m_bX11ShouldntFocus && !w->isX11OverrideRedirect())
continue; continue;
const auto BB = w->getWindowBoxUnified(properties);
CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0);
if (box.containsPoint(g_pPointerManager->position())) { if (box.containsPoint(g_pPointerManager->position())) {
if (w->m_bIsX11 && w->isX11OverrideRedirect() && !w->m_pXWaylandSurface->wantsFocus()) { if (w->m_bIsX11 && w->isX11OverrideRedirect() && !w->m_pXWaylandSurface->wantsFocus()) {
@@ -885,11 +909,13 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (special != w->onSpecialWorkspace()) if (special != w->onSpecialWorkspace())
continue; continue;
if (!w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() &&
w != pIgnoreWindow) {
CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize};
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && if (box.containsPoint(pos))
!w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow)
return w; return w;
} }
}
return nullptr; return nullptr;
}; };
@@ -962,20 +988,20 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo
return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y};
} }
CMonitor* CCompositor::getMonitorFromOutput(SP<Aquamarine::IOutput> out) { PHLMONITOR CCompositor::getMonitorFromOutput(SP<Aquamarine::IOutput> out) {
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
if (m->output == out) { if (m->output == out) {
return m.get(); return m;
} }
} }
return nullptr; return nullptr;
} }
CMonitor* CCompositor::getRealMonitorFromOutput(SP<Aquamarine::IOutput> out) { PHLMONITOR CCompositor::getRealMonitorFromOutput(SP<Aquamarine::IOutput> out) {
for (auto const& m : m_vRealMonitors) { for (auto const& m : m_vRealMonitors) {
if (m->output == out) { if (m->output == out) {
return m.get(); return m;
} }
} }
@@ -1036,13 +1062,13 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface
return; return;
} }
if (m_pLastWindow.lock() == pWindow && g_pSeatManager->state.keyboardFocus == pSurface) if (m_pLastWindow.lock() == pWindow && g_pSeatManager->state.keyboardFocus == pSurface && g_pSeatManager->state.keyboardFocus)
return; return;
if (pWindow->m_bPinned) if (pWindow->m_bPinned)
pWindow->m_pWorkspace = m_pLastMonitor->activeWorkspace; pWindow->m_pWorkspace = m_pLastMonitor->activeWorkspace;
const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = pWindow->m_pMonitor.lock();
if (!isWorkspaceVisible(pWindow->m_pWorkspace)) { if (!isWorkspaceVisible(pWindow->m_pWorkspace)) {
const auto PWORKSPACE = pWindow->m_pWorkspace; const auto PWORKSPACE = pWindow->m_pWorkspace;
@@ -1051,7 +1077,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface
PWORKSPACE->rememberPrevWorkspace(m_pLastMonitor->activeWorkspace); PWORKSPACE->rememberPrevWorkspace(m_pLastMonitor->activeWorkspace);
if (PWORKSPACE->m_bIsSpecialWorkspace) if (PWORKSPACE->m_bIsSpecialWorkspace)
m_pLastMonitor->changeWorkspace(PWORKSPACE, false, true); // if special ws, open on current monitor m_pLastMonitor->changeWorkspace(PWORKSPACE, false, true); // if special ws, open on current monitor
else else if (PMONITOR)
PMONITOR->changeWorkspace(PWORKSPACE, false, true); PMONITOR->changeWorkspace(PWORKSPACE, false, true);
// changeworkspace already calls focusWindow // changeworkspace already calls focusWindow
return; return;
@@ -1062,7 +1088,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface
/* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which /* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which
window focuses are "via keybinds" and which ones aren't. */ window focuses are "via keybinds" and which ones aren't. */
if (PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace != pWindow->m_pWorkspace && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH) if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace != pWindow->m_pWorkspace && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window // we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
@@ -1163,7 +1189,7 @@ void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindo
SURF->constraint()->activate(); SURF->constraint()->activate();
} }
SP<CWLSurfaceResource> CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { SP<CWLSurfaceResource> CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, PHLMONITOR monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) {
for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) {
for (auto const& ls : lsl | std::views::reverse) { for (auto const& ls : lsl | std::views::reverse) {
if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f)
@@ -1238,7 +1264,7 @@ bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) {
if (!valid(w)) if (!valid(w))
return false; return false;
const auto PMONITOR = getMonitorFromID(w->m_iMonitorID); const auto PMONITOR = w->m_pMonitor.lock();
if (PMONITOR->activeSpecialWorkspace) if (PMONITOR->activeSpecialWorkspace)
return PMONITOR->activeSpecialWorkspace->m_iID == w->m_iID; return PMONITOR->activeSpecialWorkspace->m_iID == w->m_iID;
@@ -1333,7 +1359,7 @@ PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) {
if (!PWORKSPACE) if (!PWORKSPACE)
return nullptr; return nullptr;
const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID); const auto PMONITOR = PWORKSPACE->m_pMonitor.lock();
for (auto const& w : m_vWindows) { for (auto const& w : m_vWindows) {
if (w->workspaceID() != id || !w->m_bIsMapped || w->isHidden()) if (w->workspaceID() != id || !w->m_bIsMapped || w->isHidden())
@@ -1363,6 +1389,12 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
if (!validMapped(pWindow)) if (!validMapped(pWindow))
return; return;
if (top)
pWindow->m_bCreatedOverFullscreen = true;
if (pWindow == (top ? m_vWindows.back() : m_vWindows.front()))
return;
auto moveToZ = [&](PHLWINDOW pw, bool top) -> void { auto moveToZ = [&](PHLWINDOW pw, bool top) -> void {
if (top) { if (top) {
for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) { for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) {
@@ -1381,12 +1413,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
} }
if (pw->m_bIsMapped) if (pw->m_bIsMapped)
g_pHyprRenderer->damageMonitor(getMonitorFromID(pw->m_iMonitorID)); g_pHyprRenderer->damageMonitor(pw->m_pMonitor.lock());
}; };
if (top)
pWindow->m_bCreatedOverFullscreen = true;
if (!pWindow->m_bIsX11) if (!pWindow->m_bIsX11)
moveToZ(pWindow, top); moveToZ(pWindow, top);
else { else {
@@ -1420,7 +1449,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) {
auto w = ww.lock(); auto w = ww.lock();
if (w->m_iMonitorID != monid) if (w->monitorID() != monid && w->m_pMonitor)
continue; continue;
if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) { if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) {
@@ -1450,7 +1479,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) {
continue; continue;
} }
if (ls->monitorID != monid) if (ls->monitorID() != monid && ls->monitor)
continue; continue;
// mark blur for recalc // mark blur for recalc
@@ -1513,7 +1542,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
static auto PMETHOD = CConfigValue<Hyprlang::INT>("binds:focus_preferred_method"); static auto PMETHOD = CConfigValue<Hyprlang::INT>("binds:focus_preferred_method");
static auto PMONITORFALLBACK = CConfigValue<Hyprlang::INT>("binds:window_direction_monitor_fallback"); static auto PMONITORFALLBACK = CConfigValue<Hyprlang::INT>("binds:window_direction_monitor_fallback");
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = pWindow->m_pMonitor.lock();
if (!PMONITOR) if (!PMONITOR)
return nullptr; // ?? return nullptr; // ??
@@ -1534,13 +1563,13 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace))
continue; continue;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace) if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace)
continue; continue;
if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen)
continue; continue;
if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) if (!*PMONITORFALLBACK && pWindow->m_pMonitor != w->m_pMonitor)
continue; continue;
const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
@@ -1626,13 +1655,13 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace))
continue; continue;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace) if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace)
continue; continue;
if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen)
continue; continue;
if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) if (!*PMONITORFALLBACK && pWindow->m_pMonitor != w->m_pMonitor)
continue; continue;
const auto DIST = w->middle().distance(pWindow->middle()); const auto DIST = w->middle().distance(pWindow->middle());
@@ -1756,7 +1785,7 @@ bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) {
return false; return false;
} }
bool CCompositor::isPointOnReservedArea(const Vector2D& point, const CMonitor* pMonitor) { bool CCompositor::isPointOnReservedArea(const Vector2D& point, const PHLMONITOR pMonitor) {
const auto PMONITOR = pMonitor ? pMonitor : getMonitorFromVector(point); const auto PMONITOR = pMonitor ? pMonitor : getMonitorFromVector(point);
const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
@@ -1765,11 +1794,11 @@ bool CCompositor::isPointOnReservedArea(const Vector2D& point, const CMonitor* p
return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y); return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y);
} }
CMonitor* CCompositor::getMonitorInDirection(const char& dir) { PHLMONITOR CCompositor::getMonitorInDirection(const char& dir) {
return this->getMonitorInDirection(m_pLastMonitor.get(), dir); return getMonitorInDirection(m_pLastMonitor.lock(), dir);
} }
CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const char& dir) { PHLMONITOR CCompositor::getMonitorInDirection(PHLMONITOR pSourceMonitor, const char& dir) {
if (!pSourceMonitor) if (!pSourceMonitor)
return nullptr; return nullptr;
@@ -1777,7 +1806,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha
const auto SIZEA = pSourceMonitor->vecSize; const auto SIZEA = pSourceMonitor->vecSize;
auto longestIntersect = -1; auto longestIntersect = -1;
CMonitor* longestIntersectMonitor = nullptr; PHLMONITOR longestIntersectMonitor = nullptr;
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
if (m == m_pLastMonitor) if (m == m_pLastMonitor)
@@ -1791,7 +1820,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
if (INTERSECTLEN > longestIntersect) { if (INTERSECTLEN > longestIntersect) {
longestIntersect = INTERSECTLEN; longestIntersect = INTERSECTLEN;
longestIntersectMonitor = m.get(); longestIntersectMonitor = m;
} }
} }
break; break;
@@ -1800,7 +1829,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
if (INTERSECTLEN > longestIntersect) { if (INTERSECTLEN > longestIntersect) {
longestIntersect = INTERSECTLEN; longestIntersect = INTERSECTLEN;
longestIntersectMonitor = m.get(); longestIntersectMonitor = m;
} }
} }
break; break;
@@ -1810,7 +1839,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
if (INTERSECTLEN > longestIntersect) { if (INTERSECTLEN > longestIntersect) {
longestIntersect = INTERSECTLEN; longestIntersect = INTERSECTLEN;
longestIntersectMonitor = m.get(); longestIntersectMonitor = m;
} }
} }
break; break;
@@ -1820,7 +1849,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
if (INTERSECTLEN > longestIntersect) { if (INTERSECTLEN > longestIntersect) {
longestIntersect = INTERSECTLEN; longestIntersect = INTERSECTLEN;
longestIntersectMonitor = m.get(); longestIntersectMonitor = m;
} }
} }
break; break;
@@ -1864,8 +1893,8 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity"); static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity");
static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity"); static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity");
static auto PFULLSCREENALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:fullscreen_opacity"); static auto PFULLSCREENALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:fullscreen_opacity");
static auto PSHADOWCOL = CConfigValue<Hyprlang::INT>("decoration:col.shadow"); static auto PSHADOWCOL = CConfigValue<Hyprlang::INT>("decoration:shadow:color");
static auto PSHADOWCOLINACTIVE = CConfigValue<Hyprlang::INT>("decoration:col.shadow_inactive"); static auto PSHADOWCOLINACTIVE = CConfigValue<Hyprlang::INT>("decoration:shadow:color_inactive");
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength"); static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
static auto PDIMENABLED = CConfigValue<Hyprlang::INT>("decoration:dim_inactive"); static auto PDIMENABLED = CConfigValue<Hyprlang::INT>("decoration:dim_inactive");
@@ -1936,11 +1965,10 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
// shadow // shadow
if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) { if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) {
if (pWindow == m_pLastWindow) { if (pWindow == m_pLastWindow)
pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL); pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL);
} else { else
pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
}
} else { } else {
pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow
} }
@@ -1967,12 +1995,12 @@ MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) {
return nextID; return nextID;
} }
void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) { void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitorB) {
const auto PWORKSPACEA = pMonitorA->activeWorkspace; const auto PWORKSPACEA = pMonitorA->activeWorkspace;
const auto PWORKSPACEB = pMonitorB->activeWorkspace; const auto PWORKSPACEB = pMonitorB->activeWorkspace;
PWORKSPACEA->m_iMonitorID = pMonitorB->ID; PWORKSPACEA->m_pMonitor = pMonitorB;
PWORKSPACEA->moveToMonitor(pMonitorB->ID); PWORKSPACEA->moveToMonitor(pMonitorB->ID);
for (auto const& w : m_vWindows) { for (auto const& w : m_vWindows) {
@@ -1982,7 +2010,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
continue; continue;
} }
w->m_iMonitorID = pMonitorB->ID; w->m_pMonitor = pMonitorB;
// additionally, move floating and fs windows manually // additionally, move floating and fs windows manually
if (w->m_bIsFloating) if (w->m_bIsFloating)
@@ -1997,7 +2025,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
} }
} }
PWORKSPACEB->m_iMonitorID = pMonitorA->ID; PWORKSPACEB->m_pMonitor = pMonitorA;
PWORKSPACEB->moveToMonitor(pMonitorA->ID); PWORKSPACEB->moveToMonitor(pMonitorA->ID);
for (auto const& w : m_vWindows) { for (auto const& w : m_vWindows) {
@@ -2007,7 +2035,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
continue; continue;
} }
w->m_iMonitorID = pMonitorA->ID; w->m_pMonitor = pMonitorA;
// additionally, move floating and fs windows manually // additionally, move floating and fs windows manually
if (w->m_bIsFloating) if (w->m_bIsFloating)
@@ -2054,16 +2082,16 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{PWORKSPACEB, pMonitorA})); EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{PWORKSPACEB, pMonitorA}));
} }
CMonitor* CCompositor::getMonitorFromString(const std::string& name) { PHLMONITOR CCompositor::getMonitorFromString(const std::string& name) {
if (name == "current") if (name == "current")
return g_pCompositor->m_pLastMonitor.get(); return g_pCompositor->m_pLastMonitor.lock();
else if (isDirection(name)) else if (isDirection(name))
return getMonitorInDirection(name[0]); return getMonitorInDirection(name[0]);
else if (name[0] == '+' || name[0] == '-') { else if (name[0] == '+' || name[0] == '-') {
// relative // relative
if (m_vMonitors.size() == 1) if (m_vMonitors.size() == 1)
return m_vMonitors.begin()->get(); return *m_vMonitors.begin();
const auto OFFSET = name[0] == '-' ? name : name.substr(1); const auto OFFSET = name[0] == '-' ? name : name.substr(1);
@@ -2096,7 +2124,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
currentPlace = std::clamp(currentPlace, 0, (int)m_vMonitors.size() - 1); currentPlace = std::clamp(currentPlace, 0, (int)m_vMonitors.size() - 1);
} }
return m_vMonitors[currentPlace].get(); return m_vMonitors[currentPlace];
} else if (isNumber(name)) { } else if (isNumber(name)) {
// change by ID // change by ID
MONITORID monID = MONITOR_INVALID; MONITORID monID = MONITOR_INVALID;
@@ -2120,7 +2148,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
continue; continue;
if (m->matchesStaticSelector(name)) { if (m->matchesStaticSelector(name)) {
return m.get(); return m;
} }
} }
} }
@@ -2128,16 +2156,16 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
return nullptr; return nullptr;
} }
void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMonitor, bool noWarpCursor) { void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMonitor, bool noWarpCursor) {
// We trust the monitor to be correct. // We trust the monitor to be correct.
if (pWorkspace->m_iMonitorID == pMonitor->ID) if (pWorkspace->m_pMonitor == pMonitor)
return; return;
Debug::log(LOG, "moveWorkspaceToMonitor: Moving {} to monitor {}", pWorkspace->m_iID, pMonitor->ID); Debug::log(LOG, "moveWorkspaceToMonitor: Moving {} to monitor {}", pWorkspace->m_iID, pMonitor->ID);
const auto POLDMON = getMonitorFromID(pWorkspace->m_iMonitorID); const auto POLDMON = pWorkspace->m_pMonitor.lock();
const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace : false; const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace : false;
@@ -2147,7 +2175,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
nextWorkspaceOnMonitorID = pWorkspace->m_iID; nextWorkspaceOnMonitorID = pWorkspace->m_iID;
else { else {
for (auto const& w : m_vWorkspaces) { for (auto const& w : m_vWorkspaces) {
if (w->m_iMonitorID == POLDMON->ID && w->m_iID != pWorkspace->m_iID && !w->m_bIsSpecialWorkspace) { if (w->m_pMonitor == POLDMON && w->m_iID != pWorkspace->m_iID && !w->m_bIsSpecialWorkspace) {
nextWorkspaceOnMonitorID = w->m_iID; nextWorkspaceOnMonitorID = w->m_iID;
break; break;
} }
@@ -2172,7 +2200,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
} }
// move the workspace // move the workspace
pWorkspace->m_iMonitorID = pMonitor->ID; pWorkspace->m_pMonitor = pMonitor;
pWorkspace->moveToMonitor(pMonitor->ID); pWorkspace->moveToMonitor(pMonitor->ID);
for (auto const& w : m_vWindows) { for (auto const& w : m_vWindows) {
@@ -2182,7 +2210,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
continue; continue;
} }
w->m_iMonitorID = pMonitor->ID; w->m_pMonitor = pMonitor;
// additionally, move floating and fs windows manually // additionally, move floating and fs windows manually
if (w->m_bIsMapped && !w->isHidden()) { if (w->m_bIsMapped && !w->isHidden()) {
@@ -2203,7 +2231,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
} }
} }
if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor.get()) { // if it was active, preserve its' status. If it wasn't, don't. if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor) { // if it was active, preserve its' status. If it wasn't, don't.
Debug::log(LOG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {}", pMonitor->activeWorkspaceID(), pWorkspace->m_iID); Debug::log(LOG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {}", pMonitor->activeWorkspaceID(), pWorkspace->m_iID);
if (valid(pMonitor->activeWorkspace)) { if (valid(pMonitor->activeWorkspace)) {
@@ -2275,7 +2303,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) {
} }
} }
const auto PMONITOR = getMonitorFromID(pWorkspace->m_iMonitorID); const auto PMONITOR = pWorkspace->m_pMonitor.lock();
if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) { if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) {
for (auto const& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { for (auto const& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
@@ -2318,7 +2346,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS
state.internal = std::clamp(state.internal, (eFullscreenMode)0, FSMODE_MAX); state.internal = std::clamp(state.internal, (eFullscreenMode)0, FSMODE_MAX);
state.client = std::clamp(state.client, (eFullscreenMode)0, FSMODE_MAX); state.client = std::clamp(state.client, (eFullscreenMode)0, FSMODE_MAX);
const auto PMONITOR = getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = PWINDOW->m_pMonitor.lock();
const auto PWORKSPACE = PWINDOW->m_pWorkspace; const auto PWORKSPACE = PWINDOW->m_pWorkspace;
const eFullscreenMode CURRENT_EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)PWINDOW->m_sFullscreenState.internal); const eFullscreenMode CURRENT_EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)PWINDOW->m_sFullscreenState.internal);
@@ -2336,7 +2364,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS
if (!CHANGEINTERNAL) { if (!CHANGEINTERNAL) {
PWINDOW->updateDynamicRules(); PWINDOW->updateDynamicRules();
updateWindowAnimatedDecorationValues(PWINDOW); updateWindowAnimatedDecorationValues(PWINDOW);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID());
return; return;
} }
@@ -2351,7 +2379,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS
PWINDOW->updateDynamicRules(); PWINDOW->updateDynamicRules();
updateWindowAnimatedDecorationValues(PWINDOW); updateWindowAnimatedDecorationValues(PWINDOW);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID());
// make all windows on the same workspace under the fullscreen window // make all windows on the same workspace under the fullscreen window
for (auto const& w : m_vWindows) { for (auto const& w : m_vWindows) {
@@ -2415,7 +2443,7 @@ void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) {
} }
} }
void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleFrameReason reason) { void CCompositor::scheduleFrameForMonitor(PHLMONITOR pMonitor, IOutput::scheduleFrameReason reason) {
if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive) if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive)
return; return;
@@ -2428,13 +2456,31 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleF
pMonitor->output->scheduleFrame(reason); pMonitor->output->scheduleFrame(reason);
} }
PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp_) {
auto regexp = trim(regexp_);
if (regexp.starts_with("active")) if (regexp.starts_with("active"))
return m_pLastWindow.lock(); return m_pLastWindow.lock();
else if (regexp.starts_with("floating") || regexp.starts_with("tiled")) {
// first floating on the current ws
if (!valid(m_pLastWindow))
return nullptr;
const bool FLOAT = regexp.starts_with("floating");
for (auto const& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden())
continue;
return w;
}
return nullptr;
}
eFocusWindowMode mode = MODE_CLASS_REGEX; eFocusWindowMode mode = MODE_CLASS_REGEX;
std::regex regexCheck(regexp); std::regex regexCheck(regexp_);
std::string matchCheck; std::string matchCheck;
if (regexp.starts_with("class:")) { if (regexp.starts_with("class:")) {
regexCheck = std::regex(regexp.substr(6)); regexCheck = std::regex(regexp.substr(6));
@@ -2453,21 +2499,6 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) {
} else if (regexp.starts_with("pid:")) { } else if (regexp.starts_with("pid:")) {
mode = MODE_PID; mode = MODE_PID;
matchCheck = regexp.substr(4); matchCheck = regexp.substr(4);
} else if (regexp.starts_with("floating") || regexp.starts_with("tiled")) {
// first floating on the current ws
if (!valid(m_pLastWindow))
return nullptr;
const bool FLOAT = regexp.starts_with("floating");
for (auto const& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden())
continue;
return w;
}
return nullptr;
} }
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
@@ -2529,7 +2560,7 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) {
if (*PNOWARPS && !force) { if (*PNOWARPS && !force) {
const auto PMONITORNEW = getMonitorFromVector(pos); const auto PMONITORNEW = getMonitorFromVector(pos);
if (PMONITORNEW != m_pLastMonitor.get()) if (PMONITORNEW != m_pLastMonitor)
setActiveMonitor(PMONITORNEW); setActiveMonitor(PMONITORNEW);
return; return;
} }
@@ -2537,7 +2568,7 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) {
g_pPointerManager->warpTo(pos); g_pPointerManager->warpTo(pos);
const auto PMONITORNEW = getMonitorFromVector(pos); const auto PMONITORNEW = getMonitorFromVector(pos);
if (PMONITORNEW != m_pLastMonitor.get()) if (PMONITORNEW != m_pLastMonitor)
setActiveMonitor(PMONITORNEW); setActiveMonitor(PMONITORNEW);
} }
@@ -2636,13 +2667,12 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO
auto monID = monid; auto monID = monid;
// check if bound // check if bound
if (const auto PMONITOR = g_pConfigManager->getBoundMonitorForWS(NAME); PMONITOR) { if (const auto PMONITOR = g_pConfigManager->getBoundMonitorForWS(NAME); PMONITOR)
monID = PMONITOR->ID; monID = PMONITOR->ID;
}
const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2; const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2;
const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, monID, NAME, SPECIAL, isEmpty)); const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, getMonitorFromID(monID), NAME, SPECIAL, isEmpty));
PWORKSPACE->m_fAlpha.setValueAndWarp(0); PWORKSPACE->m_fAlpha.setValueAndWarp(0);
@@ -2664,8 +2694,8 @@ void CCompositor::renameWorkspace(const WORKSPACEID& id, const std::string& name
g_pEventManager->postEvent({"renameworkspace", std::to_string(PWORKSPACE->m_iID) + "," + PWORKSPACE->m_szName}); g_pEventManager->postEvent({"renameworkspace", std::to_string(PWORKSPACE->m_iID) + "," + PWORKSPACE->m_szName});
} }
void CCompositor::setActiveMonitor(CMonitor* pMonitor) { void CCompositor::setActiveMonitor(PHLMONITOR pMonitor) {
if (m_pLastMonitor.get() == pMonitor) if (m_pLastMonitor == pMonitor)
return; return;
if (!pMonitor) { if (!pMonitor) {
@@ -2707,6 +2737,12 @@ void CCompositor::performUserChecks() {
CColor{}, 15000, ICON_WARNING); CColor{}, 15000, ICON_WARNING);
} }
} }
if (g_pHyprOpenGL->failedAssetsNo > 0) {
g_pHyprNotificationOverlay->addNotification(std::format("Hyprland failed to load {} essential asset{}, blame your distro's packager for doing a bad job at packaging!",
g_pHyprOpenGL->failedAssetsNo, g_pHyprOpenGL->failedAssetsNo > 1 ? "s" : ""),
CColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR);
}
} }
void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) { void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) {
@@ -2722,31 +2758,57 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor
if (FULLSCREEN) if (FULLSCREEN)
setWindowFullscreenInternal(pWindow, FSMODE_NONE); setWindowFullscreenInternal(pWindow, FSMODE_NONE);
if (!pWindow->m_bIsFloating) { const PHLWINDOW pFirstWindowOnWorkspace = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); const int visibleWindowsOnWorkspace = g_pCompositor->getWindowsOnWorkspace(pWorkspace->m_iID, std::nullopt, true);
pWindow->moveToWorkspace(pWorkspace); const auto PWINDOWMONITOR = pWindow->m_pMonitor.lock();
pWindow->m_iMonitorID = pWorkspace->m_iMonitorID;
g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(pWindow);
} else {
const auto PWINDOWMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition; const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition;
const auto PWORKSPACEMONITOR = pWorkspace->m_pMonitor.lock();
const auto PWORKSPACEMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); if (!pWindow->m_bIsFloating)
g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow);
pWindow->moveToWorkspace(pWorkspace); pWindow->moveToWorkspace(pWorkspace);
pWindow->m_iMonitorID = pWorkspace->m_iMonitorID; pWindow->m_pMonitor = pWorkspace->m_pMonitor;
static auto PGROUPONMOVETOWORKSPACE = CConfigValue<Hyprlang::INT>("group:group_on_movetoworkspace");
if (*PGROUPONMOVETOWORKSPACE && visibleWindowsOnWorkspace == 1 && pFirstWindowOnWorkspace && pFirstWindowOnWorkspace != pWindow &&
pFirstWindowOnWorkspace->m_sGroupData.pNextWindow.lock() && pWindow->canBeGroupedInto(pFirstWindowOnWorkspace)) {
pWindow->m_bIsFloating = pFirstWindowOnWorkspace->m_bIsFloating; // match the floating state. Needed to group tiled into floated and vice versa.
if (!pWindow->m_sGroupData.pNextWindow.expired()) {
PHLWINDOW next = pWindow->m_sGroupData.pNextWindow.lock();
while (next != pWindow) {
next->m_bIsFloating = pFirstWindowOnWorkspace->m_bIsFloating; // match the floating state of group members
next = next->m_sGroupData.pNextWindow.lock();
}
}
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? pFirstWindowOnWorkspace : pFirstWindowOnWorkspace->getGroupTail())->insertWindowToGroup(pWindow);
pFirstWindowOnWorkspace->setGroupCurrent(pWindow);
pWindow->updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
} else {
if (!pWindow->m_bIsFloating)
g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(pWindow);
if (pWindow->m_bIsFloating)
pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition; pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition;
} }
pWindow->updateToplevel(); pWindow->updateToplevel();
pWindow->updateDynamicRules(); pWindow->updateDynamicRules();
pWindow->uncacheWindowDecos(); pWindow->uncacheWindowDecos();
pWindow->updateGroupOutputs();
if (!pWindow->m_sGroupData.pNextWindow.expired()) { if (!pWindow->m_sGroupData.pNextWindow.expired()) {
PHLWINDOW next = pWindow->m_sGroupData.pNextWindow.lock(); PHLWINDOW next = pWindow->m_sGroupData.pNextWindow.lock();
while (next != pWindow) { while (next != pWindow) {
next->moveToWorkspace(pWorkspace);
next->updateToplevel(); next->updateToplevel();
next = next->m_sGroupData.pNextWindow.lock(); next = next->m_sGroupData.pNextWindow.lock();
} }
@@ -2777,11 +2839,11 @@ PHLWINDOW CCompositor::getForceFocus() {
void CCompositor::arrangeMonitors() { void CCompositor::arrangeMonitors() {
static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling"); static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling");
std::vector<CMonitor*> toArrange; std::vector<PHLMONITOR> toArrange;
std::vector<CMonitor*> arranged; std::vector<PHLMONITOR> arranged;
for (auto const& m : m_vMonitors) for (auto const& m : m_vMonitors)
toArrange.push_back(m.get()); toArrange.push_back(m);
Debug::log(LOG, "arrangeMonitors: {} to arrange", toArrange.size()); Debug::log(LOG, "arrangeMonitors: {} to arrange", toArrange.size());
@@ -2865,6 +2927,8 @@ void CCompositor::arrangeMonitors() {
else else
m->xwaylandScale = 1.f; m->xwaylandScale = 1.f;
} }
PROTO::xdgOutput->updateAllOutputs();
} }
void CCompositor::enterUnsafeState() { void CCompositor::enterUnsafeState() {
@@ -2878,7 +2942,7 @@ void CCompositor::enterUnsafeState() {
m_bUnsafeState = true; m_bUnsafeState = true;
setActiveMonitor(m_pUnsafeOutput); setActiveMonitor(m_pUnsafeOutput.lock());
} }
void CCompositor::leaveUnsafeState() { void CCompositor::leaveUnsafeState() {
@@ -2889,10 +2953,10 @@ void CCompositor::leaveUnsafeState() {
m_bUnsafeState = false; m_bUnsafeState = false;
CMonitor* pNewMonitor = nullptr; PHLMONITOR pNewMonitor = nullptr;
for (auto const& pMonitor : m_vMonitors) { for (auto const& pMonitor : m_vMonitors) {
if (pMonitor->output != m_pUnsafeOutput->output) { if (pMonitor->output != m_pUnsafeOutput->output) {
pNewMonitor = pMonitor.get(); pNewMonitor = pMonitor;
break; break;
} }
} }
@@ -2903,7 +2967,7 @@ void CCompositor::leaveUnsafeState() {
m_pUnsafeOutput->onDisconnect(); m_pUnsafeOutput->onDisconnect();
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
scheduleFrameForMonitor(m.get()); scheduleFrameForMonitor(m);
} }
} }
@@ -2953,7 +3017,7 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) {
return {}; return {};
} }
static void checkDefaultCursorWarp(SP<CMonitor> monitor) { static void checkDefaultCursorWarp(PHLMONITOR monitor) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor"); static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static bool cursorDefaultDone = false; static bool cursorDefaultDone = false;
static bool firstLaunch = true; static bool firstLaunch = true;
@@ -2979,7 +3043,7 @@ static void checkDefaultCursorWarp(SP<CMonitor> monitor) {
} }
// modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed. // modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed.
if (g_pCompositor->getMonitorFromCursor() == monitor.get()) { if (g_pCompositor->getMonitorFromCursor() == monitor) {
g_pCompositor->warpCursorTo(POS, true); g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus(); g_pInputManager->refocus();
} }
@@ -2989,7 +3053,7 @@ void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) {
// add it to real // add it to real
auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>(output)); auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>(output));
if (std::string("HEADLESS-1") == output->name) { if (std::string("HEADLESS-1") == output->name) {
g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); g_pCompositor->m_pUnsafeOutput = PNEWMONITOR;
output->name = "FALLBACK"; // we are allowed to do this :) output->name = "FALLBACK"; // we are allowed to do this :)
} }
@@ -3012,22 +3076,22 @@ void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) {
// ready to process if we have a real monitor // ready to process if we have a real monitor
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled) if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get(); g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
g_pCompositor->m_bReadyToProcess = true; g_pCompositor->m_bReadyToProcess = true;
g_pConfigManager->m_bWantsMonitorReload = true; g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR, IOutput::AQ_SCHEDULE_NEW_MONITOR);
checkDefaultCursorWarp(PNEWMONITOR); checkDefaultCursorWarp(PNEWMONITOR);
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) { if (w->m_pMonitor == PNEWMONITOR) {
w->m_iLastSurfaceMonitorID = MONITOR_INVALID; w->m_iLastSurfaceMonitorID = MONITOR_INVALID;
w->updateSurfaceScaleTransformDetails(); w->updateSurfaceScaleTransformDetails();
} }
} }
g_pHyprRenderer->damageMonitor(PNEWMONITOR.get()); g_pHyprRenderer->damageMonitor(PNEWMONITOR);
Events::listener_monitorFrame(PNEWMONITOR.get(), nullptr); PNEWMONITOR->onMonitorFrame();
} }

View File

@@ -59,8 +59,8 @@ class CCompositor {
std::string m_szInstancePath = ""; std::string m_szInstancePath = "";
std::string m_szCurrentSplash = "error"; std::string m_szCurrentSplash = "error";
std::vector<SP<CMonitor>> m_vMonitors; std::vector<PHLMONITOR> m_vMonitors;
std::vector<SP<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off std::vector<PHLMONITOR> m_vRealMonitors; // for all monitors, even those turned off
std::vector<PHLWINDOW> m_vWindows; std::vector<PHLWINDOW> m_vWindows;
std::vector<PHLLS> m_vLayers; std::vector<PHLLS> m_vLayers;
std::vector<PHLWORKSPACE> m_vWorkspaces; std::vector<PHLWORKSPACE> m_vWorkspaces;
@@ -80,7 +80,7 @@ class CCompositor {
WP<CWLSurfaceResource> m_pLastFocus; WP<CWLSurfaceResource> m_pLastFocus;
PHLWINDOWREF m_pLastWindow; PHLWINDOWREF m_pLastWindow;
WP<CMonitor> m_pLastMonitor; PHLMONITORREF m_pLastMonitor;
std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused. std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused.
@@ -89,7 +89,7 @@ class CCompositor {
bool m_bDPMSStateON = true; bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; bool m_bNextIsUnsafe = false;
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state PHLMONITORREF m_pUnsafeOutput; // fallback output for the unsafe state
bool m_bIsShuttingDown = false; bool m_bIsShuttingDown = false;
bool m_bFinalRequests = false; bool m_bFinalRequests = false;
bool m_bDesktopEnvSet = false; bool m_bDesktopEnvSet = false;
@@ -97,22 +97,22 @@ class CCompositor {
// ------------------------------------------------- // // ------------------------------------------------- //
CMonitor* getMonitorFromID(const MONITORID&); PHLMONITOR getMonitorFromID(const MONITORID&);
CMonitor* getMonitorFromName(const std::string&); PHLMONITOR getMonitorFromName(const std::string&);
CMonitor* getMonitorFromDesc(const std::string&); PHLMONITOR getMonitorFromDesc(const std::string&);
CMonitor* getMonitorFromCursor(); PHLMONITOR getMonitorFromCursor();
CMonitor* getMonitorFromVector(const Vector2D&); PHLMONITOR getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(PHLWINDOW); void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr); void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr);
void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr); void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr);
bool monitorExists(CMonitor*); bool monitorExists(PHLMONITOR);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, PHLMONITOR monitor, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
CMonitor* getMonitorFromOutput(SP<Aquamarine::IOutput>); PHLMONITOR getMonitorFromOutput(SP<Aquamarine::IOutput>);
CMonitor* getRealMonitorFromOutput(SP<Aquamarine::IOutput>); PHLMONITOR getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>); PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
PHLWINDOW getWindowFromHandle(uint32_t); PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE); bool isWorkspaceVisible(PHLWORKSPACE);
@@ -138,16 +138,16 @@ class CCompositor {
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
WORKSPACEID getNextAvailableNamedWorkspace(); WORKSPACEID getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr);
CMonitor* getMonitorInDirection(const char&); PHLMONITOR getMonitorInDirection(const char&);
CMonitor* getMonitorInDirection(CMonitor*, const char&); PHLMONITOR getMonitorInDirection(PHLMONITOR, const char&);
void updateAllWindowsAnimatedDecorationValues(); void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const WORKSPACEID& id); void updateWorkspaceWindows(const WORKSPACEID& id);
void updateWindowAnimatedDecorationValues(PHLWINDOW); void updateWindowAnimatedDecorationValues(PHLWINDOW);
MONITORID getNextAvailableMonitorID(std::string const& name); MONITORID getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false); void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false);
void swapActiveWorkspaces(CMonitor*, CMonitor*); void swapActiveWorkspaces(PHLMONITOR, PHLMONITOR);
CMonitor* getMonitorFromString(const std::string&); PHLMONITOR getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const WORKSPACEID&); bool workspaceIDOutOfBounds(const WORKSPACEID&);
void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
@@ -156,7 +156,7 @@ class CCompositor {
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON); void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW); PHLWINDOW getX11Parent(PHLWINDOW);
void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN); void scheduleFrameForMonitor(PHLMONITOR, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
void addToFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLLS);
void removeFromFadingOutSafe(PHLLS); void removeFromFadingOutSafe(PHLLS);
void addToFadingOutSafe(PHLWINDOW); void addToFadingOutSafe(PHLWINDOW);
@@ -169,7 +169,7 @@ class CCompositor {
PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "",
bool isEmpty = true); // will be deleted next frame if left empty and unfocused! bool isEmpty = true); // will be deleted next frame if left empty and unfocused!
void renameWorkspace(const WORKSPACEID&, const std::string& name = ""); void renameWorkspace(const WORKSPACEID&, const std::string& name = "");
void setActiveMonitor(CMonitor*); void setActiveMonitor(PHLMONITOR);
bool isWorkspaceSpecial(const WORKSPACEID&); bool isWorkspaceSpecial(const WORKSPACEID&);
WORKSPACEID getNewSpecialID(); WORKSPACEID getNewSpecialID();
void performUserChecks(); void performUserChecks();

View File

@@ -104,6 +104,30 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{0, 0, 4}, .data = SConfigOptionDescription::SRangeData{0, 0, 4},
}, },
SConfigOptionDescription{
.value = "general:snap:enabled",
.description = "enable snapping for floating windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "general:snap:window_gap",
.description = "minimum gap in pixels between windows before snapping",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{10, 0, 100},
},
SConfigOptionDescription{
.value = "general:snap:monitor_gap",
.description = "minimum gap in pixels between window and monitor edges before snapping",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{10, 0, 100},
},
SConfigOptionDescription{
.value = "general:snap:border_overlap",
.description = "if true, windows snap such that only one border's worth of space is between them",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* decoration: * decoration:
@@ -134,49 +158,55 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SFloatData{1, 0, 1}, .data = SConfigOptionDescription::SFloatData{1, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:drop_shadow", .value = "decoration:shadow:enabled",
.description = "enable drop shadows on windows", .description = "enable drop shadows on windows",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow_range", .value = "decoration:shadow:range",
.description = "Shadow range (size) in layout px", .description = "Shadow range (size) in layout px",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{4, 0, 100}, .data = SConfigOptionDescription::SRangeData{4, 0, 100},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow_render_power", .value = "decoration:shadow:render_power",
.description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]", .description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{3, 1, 4}, .data = SConfigOptionDescription::SRangeData{3, 1, 4},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow_ignore_window", .value = "decoration:shadow:sharp",
.description = "whether the shadow should be sharp or not. Akin to an infinitely high render power.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "decoration:shadow:ignore_window",
.description = "if true, the shadow will not be rendered behind the window itself, only around it.", .description = "if true, the shadow will not be rendered behind the window itself, only around it.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:col.shadow", .value = "decoration:shadow:color",
.description = "shadow's color. Alpha dictates shadow's opacity.", .description = "shadow's color. Alpha dictates shadow's opacity.",
.type = CONFIG_OPTION_COLOR, .type = CONFIG_OPTION_COLOR,
.data = SConfigOptionDescription::SColorData{0xee1a1a1a}, .data = SConfigOptionDescription::SColorData{0xee1a1a1a},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:col.shadow_inactive", .value = "decoration:shadow:color_inactive",
.description = "inactive shadow color. (if not set, will fall back to col.shadow)", .description = "inactive shadow color. (if not set, will fall back to col.shadow)",
.type = CONFIG_OPTION_COLOR, .type = CONFIG_OPTION_COLOR,
.data = SConfigOptionDescription::SColorData{}, //##TODO UNSET? .data = SConfigOptionDescription::SColorData{}, //TODO: UNSET?
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow_offset", .value = "decoration:shadow:offset",
.description = "shadow's rendering offset.", .description = "shadow's rendering offset.",
.type = CONFIG_OPTION_VECTOR, .type = CONFIG_OPTION_VECTOR,
.data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}}, .data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow_scale", .value = "decoration:shadow:scale",
.description = "shadow's scale. [0.0 - 1.0]", .description = "shadow's scale. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1}, .data = SConfigOptionDescription::SFloatData{1, 0, 1},
@@ -748,6 +778,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "group:merge_groups_on_groupbar",
.description = "whether one group will be merged with another when dragged into its groupbar",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "general:col.border_active", .value = "general:col.border_active",
.description = "border color for inactive windows", .description = "border color for inactive windows",
@@ -772,6 +808,30 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66775500"}, .data = SConfigOptionDescription::SGradientData{"0x66775500"},
}, },
SConfigOptionDescription{
.value = "group:auto_group",
.description = "automatically group new windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:drag_into_group",
.description = "whether dragging a window into a unlocked group will merge them. Options: 0 (disabled), 1 (enabled), 2 (only when dragging into the groupbar)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "disabled,enabled,only when dragging into the groupbar"},
},
SConfigOptionDescription{
.value = "group:merge_floated_into_tiled_on_groupbar",
.description = "whether dragging a floating window into a tiled window groupbar will merge them",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "group:group_on_movetoworkspace",
.description = "whether using movetoworkspace[silent] will merge the window into the workspace's solitary unlocked group",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* group:groupbar: * group:groupbar:
@@ -1202,8 +1262,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_hardware_cursors", .value = "cursor:no_hardware_cursors",
.description = "disables hardware cursors", .description = "disables hardware cursors",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_break_fs_vrr", .value = "cursor:no_break_fs_vrr",
@@ -1372,4 +1432,152 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
/*
* dwindle:
*/
SConfigOptionDescription{
.value = "dwindle:pseudotile",
.description = "enable pseudotiling. Pseudotiled windows retain their floating size when tiled.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:force_split",
.description = "0 -> split follows mouse, 1 -> always split to the left (new = left or top) 2 -> always split to the right (new = right or bottom)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "follow mouse,left or top,right or bottom"},
},
SConfigOptionDescription{
.value = "dwindle:preserve_split",
.description = "if enabled, the split (side/top) will not change regardless of what happens to the container.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:smart_split",
.description = "if enabled, allows a more precise control over the window split direction based on the cursor's position. The window is conceptually divided into four "
"triangles, and cursor's triangle determines the split direction. This feature also turns on preserve_split.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:smart_resizing",
.description =
"if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "dwindle:permanent_direction_override",
.description = "if enabled, makes the preselect direction persist until either this mode is turned off, another direction is specified, or a non-direction is specified "
"(anything other than l,r,u/t,d/b)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:special_scale_factor",
.description = "specifies the scale factor of windows on the special workspace [0 - 1]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
},
SConfigOptionDescription{
.value = "dwindle:split_width_multiplier",
.description = "specifies the auto-split width multiplier",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0.1, 3},
},
SConfigOptionDescription{
.value = "dwindle:use_active_for_splits",
.description = "whether to prefer the active window or the mouse position for splits",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "dwindle:default_split_ratio",
.description = "the default split ratio on window open. 1 means even 50/50 split. [0.1 - 1.9]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0.1, 1.9},
},
SConfigOptionDescription{
.value = "dwindle:split_bias",
.description = "specifies which window will receive the larger half of a split. positional - 0, current window - 1, opening window - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "positional,current,opening"},
},
/*
* master:
*/
SConfigOptionDescription{
.value = "master:allow_small_split",
.description = "enable adding additional master windows in a horizontal split style",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:special_scale_factor",
.description = "the scale of the special workspace windows. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
},
SConfigOptionDescription{
.value = "master:mfact",
.description =
"the size as a percentage of the master window, for example `mfact = 0.70` would mean 70% of the screen will be the master window, and 30% the slave [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.55, 0, 1},
},
SConfigOptionDescription{
.value = "master:new_status",
.description = "`master`: new window becomes master; `slave`: new windows are added to slave stack; `inherit`: inherit from focused window",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"slave"},
},
SConfigOptionDescription{
.value = "master:new_on_top",
.description = "whether a newly open window should be on the top of the stack",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:new_on_active",
.description = "`before`, `after`: place new window relative to the focused window; `none`: place new window according to the value of `new_on_top`. ",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"none"},
},
SConfigOptionDescription{
.value = "master:orientation",
.description = "default placement of the master area, can be left, right, top, bottom or center",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"left"},
},
SConfigOptionDescription{
.value = "master:inherit_fullscreen",
.description = "inherit fullscreen status when cycling/swapping to another window (e.g. monocle layout)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:always_center_master",
.description = "when using orientation=center, keep the master window centered, even when it is the only window in the workspace.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:smart_resizing",
.description =
"if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:drop_at_cursor",
.description = "when enabled, dragging and dropping windows will put them at the cursor position. Otherwise, when dropped at the stack side, they will go to the "
"top/bottom of the stack depending on new_on_top.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
}; };

View File

@@ -7,6 +7,7 @@
#include "helpers/varlist/VarList.hpp" #include "helpers/varlist/VarList.hpp"
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../xwayland/XWayland.hpp" #include "../xwayland/XWayland.hpp"
#include "../protocols/OutputManagement.hpp"
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
@@ -340,6 +341,10 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("general:layout", {"dwindle"}); m_pConfig->addConfigValue("general:layout", {"dwindle"});
m_pConfig->addConfigValue("general:allow_tearing", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:allow_tearing", Hyprlang::INT{0});
m_pConfig->addConfigValue("general:resize_corner", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:resize_corner", Hyprlang::INT{0});
m_pConfig->addConfigValue("general:snap:enabled", Hyprlang::INT{0});
m_pConfig->addConfigValue("general:snap:window_gap", Hyprlang::INT{10});
m_pConfig->addConfigValue("general:snap:monitor_gap", Hyprlang::INT{10});
m_pConfig->addConfigValue("general:snap:border_overlap", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:disable_hyprland_logo", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_hyprland_logo", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:disable_splash_rendering", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_splash_rendering", Hyprlang::INT{0});
@@ -376,6 +381,11 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:merge_groups_on_groupbar", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:merge_floated_into_tiled_on_groupbar", Hyprlang::INT{0});
m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:drag_into_group", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:group_on_movetoworkspace", Hyprlang::INT{0});
m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY});
m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8});
@@ -422,14 +432,15 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("decoration:inactive_opacity", {1.F}); m_pConfig->addConfigValue("decoration:inactive_opacity", {1.F});
m_pConfig->addConfigValue("decoration:fullscreen_opacity", {1.F}); m_pConfig->addConfigValue("decoration:fullscreen_opacity", {1.F});
m_pConfig->addConfigValue("decoration:no_blur_on_oversized", Hyprlang::INT{0}); m_pConfig->addConfigValue("decoration:no_blur_on_oversized", Hyprlang::INT{0});
m_pConfig->addConfigValue("decoration:drop_shadow", Hyprlang::INT{1}); m_pConfig->addConfigValue("decoration:shadow:enabled", Hyprlang::INT{1});
m_pConfig->addConfigValue("decoration:shadow_range", Hyprlang::INT{4}); m_pConfig->addConfigValue("decoration:shadow:range", Hyprlang::INT{4});
m_pConfig->addConfigValue("decoration:shadow_render_power", Hyprlang::INT{3}); m_pConfig->addConfigValue("decoration:shadow:render_power", Hyprlang::INT{3});
m_pConfig->addConfigValue("decoration:shadow_ignore_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("decoration:shadow:ignore_window", Hyprlang::INT{1});
m_pConfig->addConfigValue("decoration:shadow_offset", Hyprlang::VEC2{0, 0}); m_pConfig->addConfigValue("decoration:shadow:offset", Hyprlang::VEC2{0, 0});
m_pConfig->addConfigValue("decoration:shadow_scale", {1.f}); m_pConfig->addConfigValue("decoration:shadow:scale", {1.f});
m_pConfig->addConfigValue("decoration:col.shadow", Hyprlang::INT{0xee1a1a1a}); m_pConfig->addConfigValue("decoration:shadow:sharp", Hyprlang::INT{0});
m_pConfig->addConfigValue("decoration:col.shadow_inactive", {(Hyprlang::INT)INT_MAX}); m_pConfig->addConfigValue("decoration:shadow:color", Hyprlang::INT{0xee1a1a1a});
m_pConfig->addConfigValue("decoration:shadow:color_inactive", {(Hyprlang::INT)INT64_MAX});
m_pConfig->addConfigValue("decoration:dim_inactive", Hyprlang::INT{0}); m_pConfig->addConfigValue("decoration:dim_inactive", Hyprlang::INT{0});
m_pConfig->addConfigValue("decoration:dim_strength", {0.5f}); m_pConfig->addConfigValue("decoration:dim_strength", {0.5f});
m_pConfig->addConfigValue("decoration:dim_special", {0.2f}); m_pConfig->addConfigValue("decoration:dim_special", {0.2f});
@@ -442,9 +453,9 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("dwindle:preserve_split", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:preserve_split", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:special_scale_factor", {1.f}); m_pConfig->addConfigValue("dwindle:special_scale_factor", {1.f});
m_pConfig->addConfigValue("dwindle:split_width_multiplier", {1.0f}); m_pConfig->addConfigValue("dwindle:split_width_multiplier", {1.0f});
m_pConfig->addConfigValue("dwindle:no_gaps_when_only", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:use_active_for_splits", Hyprlang::INT{1}); m_pConfig->addConfigValue("dwindle:use_active_for_splits", Hyprlang::INT{1});
m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f}); m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f});
m_pConfig->addConfigValue("dwindle:split_bias", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:smart_split", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:smart_split", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:smart_resizing", Hyprlang::INT{1}); m_pConfig->addConfigValue("dwindle:smart_resizing", Hyprlang::INT{1});
@@ -454,7 +465,6 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0});
m_pConfig->addConfigValue("master:new_on_active", {"none"}); m_pConfig->addConfigValue("master:new_on_active", {"none"});
m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0});
m_pConfig->addConfigValue("master:no_gaps_when_only", Hyprlang::INT{0});
m_pConfig->addConfigValue("master:orientation", {"left"}); m_pConfig->addConfigValue("master:orientation", {"left"});
m_pConfig->addConfigValue("master:inherit_fullscreen", Hyprlang::INT{1}); m_pConfig->addConfigValue("master:inherit_fullscreen", Hyprlang::INT{1});
m_pConfig->addConfigValue("master:allow_small_split", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:allow_small_split", Hyprlang::INT{0});
@@ -545,7 +555,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1});
m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2}); m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2});
m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{2});
m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24});
m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0});
@@ -582,6 +592,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("render:explicit_sync", Hyprlang::INT{2}); m_pConfig->addConfigValue("render:explicit_sync", Hyprlang::INT{2});
m_pConfig->addConfigValue("render:explicit_sync_kms", Hyprlang::INT{2}); m_pConfig->addConfigValue("render:explicit_sync_kms", Hyprlang::INT{2});
m_pConfig->addConfigValue("render:direct_scanout", Hyprlang::INT{0}); m_pConfig->addConfigValue("render:direct_scanout", Hyprlang::INT{0});
m_pConfig->addConfigValue("render:expand_undersized_textures", Hyprlang::INT{1});
// devices // devices
m_pConfig->addSpecialCategory("device", {"name"}); m_pConfig->addSpecialCategory("device", {"name"});
@@ -683,12 +694,15 @@ std::string CConfigManager::getMainConfigPath() {
if (!g_pCompositor->explicitConfigPath.empty()) if (!g_pCompositor->explicitConfigPath.empty())
return g_pCompositor->explicitConfigPath; return g_pCompositor->explicitConfigPath;
static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland"); if (const auto CFG_ENV = getenv("HYPRLAND_CONFIG"); CFG_ENV)
if (paths.first.has_value()) { return CFG_ENV;
return paths.first.value();
} else if (paths.second.has_value()) { const auto PATHS = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland");
auto configPath = Hyprutils::Path::fullConfigPath(paths.second.value(), ISDEBUG ? "hyprlandd" : "hyprland"); if (PATHS.first.has_value()) {
return generateConfig(configPath).value(); return PATHS.first.value();
} else if (PATHS.second.has_value()) {
const auto CONFIGPATH = Hyprutils::Path::fullConfigPath(PATHS.second.value(), ISDEBUG ? "hyprlandd" : "hyprland");
return generateConfig(CONFIGPATH).value();
} else } else
throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME are set in the environment. Could not find config in XDG_CONFIG_DIRS or /etc/xdg."); throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME are set in the environment. Could not find config in XDG_CONFIG_DIRS or /etc/xdg.");
} }
@@ -860,7 +874,9 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
if (result.error && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:suppress_errors"))) if (result.error && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:suppress_errors")))
g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1) else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1)
g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland", g_pHyprError->queueCreate(
"Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() +
" )\nSUPER+Q -> kitty (if it doesn't launch, make sure it's installed or choose a different terminal in the config)\nSUPER+M -> exit Hyprland",
CColor(1.0, 1.0, 70.0 / 255.0, 1.0)); CColor(1.0, 1.0, 70.0 / 255.0, 1.0));
else if (*PENABLEEXPLICIT != prevEnabledExplicit) else if (*PENABLEEXPLICIT != prevEnabledExplicit)
g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
@@ -935,9 +951,9 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
// mark blur dirty // mark blur dirty
g_pHyprOpenGL->markBlurDirtyForMonitor(m.get()); g_pHyprOpenGL->markBlurDirtyForMonitor(m);
g_pCompositor->scheduleFrameForMonitor(m.get()); g_pCompositor->scheduleFrameForMonitor(m);
// Force the compositor to fully re-render all monitors // Force the compositor to fully re-render all monitors
m->forceFullFrames = 2; m->forceFullFrames = 2;
@@ -1075,28 +1091,69 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s
return VAL; return VAL;
} }
SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { SMonitorRule CConfigManager::getMonitorRuleFor(const PHLMONITOR PMONITOR) {
auto applyWlrOutputConfig = [PMONITOR](SMonitorRule rule) -> SMonitorRule {
const auto CONFIG = PROTO::outputManagement->getOutputStateFor(PMONITOR);
if (!CONFIG)
return rule;
Debug::log(LOG, "CConfigManager::getMonitorRuleFor: found a wlr_output_manager override for {}", PMONITOR->szName);
Debug::log(LOG, " > overriding enabled: {} -> {}", !rule.disabled, !CONFIG->enabled);
rule.disabled = !CONFIG->enabled;
if ((CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_MODE) || (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE)) {
Debug::log(LOG, " > overriding mode: {:.0f}x{:.0f}@{:.2f}Hz -> {:.0f}x{:.0f}@{:.2f}Hz", rule.resolution.x, rule.resolution.y, rule.refreshRate, CONFIG->resolution.x,
CONFIG->resolution.y, CONFIG->refresh / 1000.F);
rule.resolution = CONFIG->resolution;
rule.refreshRate = CONFIG->refresh / 1000.F;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) {
Debug::log(LOG, " > overriding offset: {:.0f}, {:.0f} -> {:.0f}, {:.0f}", rule.offset.x, rule.offset.y, CONFIG->position.x, CONFIG->position.y);
rule.offset = CONFIG->position;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) {
Debug::log(LOG, " > overriding transform: {} -> {}", (uint8_t)rule.transform, (uint8_t)CONFIG->transform);
rule.transform = CONFIG->transform;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) {
Debug::log(LOG, " > overriding scale: {} -> {}", (uint8_t)rule.scale, (uint8_t)CONFIG->scale);
rule.scale = CONFIG->scale;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
Debug::log(LOG, " > overriding vrr: {} -> {}", rule.vrr.value_or(0), CONFIG->adaptiveSync);
rule.vrr = (int)CONFIG->adaptiveSync;
}
return rule;
};
for (auto const& r : m_dMonitorRules | std::views::reverse) { for (auto const& r : m_dMonitorRules | std::views::reverse) {
if (PMONITOR.matchesStaticSelector(r.name)) { if (PMONITOR->matchesStaticSelector(r.name)) {
return r; return applyWlrOutputConfig(r);
} }
} }
Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName); Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR->szName);
for (auto const& r : m_dMonitorRules) { for (auto const& r : m_dMonitorRules) {
if (r.name.empty()) { if (r.name.empty()) {
return r; return applyWlrOutputConfig(r);
} }
} }
Debug::log(WARN, "No rules configured. Using the default hardcoded one."); Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
return SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT, return applyWlrOutputConfig(SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT,
.name = "", .name = "",
.resolution = Vector2D(0, 0), .resolution = Vector2D(0, 0),
.offset = Vector2D(-INT32_MAX, -INT32_MAX), .offset = Vector2D(-INT32_MAX, -INT32_MAX),
.scale = -1}; // 0, 0 is preferred and -1, -1 is auto .scale = -1}); // 0, 0 is preferred and -1, -1 is auto
} }
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) { SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) {
@@ -1455,9 +1512,9 @@ void CConfigManager::performMonitorReload() {
if (!m->output || m->isUnsafeFallback) if (!m->output || m->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(*m); auto rule = getMonitorRuleFor(m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { if (!g_pHyprRenderer->applyMonitorRule(m, &rule)) {
overAgain = true; overAgain = true;
break; break;
} }
@@ -1512,17 +1569,17 @@ void CConfigManager::ensureMonitorStatus() {
if (!rm->output || rm->isUnsafeFallback) if (!rm->output || rm->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(*rm); auto rule = getMonitorRuleFor(rm);
if (rule.disabled == rm->m_bEnabled) if (rule.disabled == rm->m_bEnabled)
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule); g_pHyprRenderer->applyMonitorRule(rm, &rule);
} }
} }
void CConfigManager::ensureVRR(CMonitor* pMonitor) { void CConfigManager::ensureVRR(PHLMONITOR pMonitor) {
static auto PVRR = reinterpret_cast<Hyprlang::INT* const*>(getConfigValuePtr("misc:vrr")); static auto PVRR = reinterpret_cast<Hyprlang::INT* const*>(getConfigValuePtr("misc:vrr"));
static auto ensureVRRForDisplay = [&](CMonitor* m) -> void { static auto ensureVRRForDisplay = [&](PHLMONITOR m) -> void {
if (!m->output || m->createdByUser) if (!m->output || m->createdByUser)
return; return;
@@ -1554,9 +1611,6 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
m->vrrActive = true; m->vrrActive = true;
return; return;
} else if (USEVRR == 2) { } else if (USEVRR == 2) {
/* fullscreen */
m->vrrActive = true;
const auto PWORKSPACE = m->activeWorkspace; const auto PWORKSPACE = m->activeWorkspace;
if (!PWORKSPACE) if (!PWORKSPACE)
@@ -1565,6 +1619,9 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN); const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN);
if (WORKSPACEFULL) { if (WORKSPACEFULL) {
/* fullscreen */
m->vrrActive = true;
m->output->state->resetExplicitFences(); m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(true); m->output->state->setAdaptiveSync(true);
@@ -1577,6 +1634,8 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} else if (!WORKSPACEFULL) { } else if (!WORKSPACEFULL) {
m->vrrActive = false;
m->output->state->resetExplicitFences(); m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(false); m->output->state->setAdaptiveSync(false);
@@ -1592,7 +1651,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
} }
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
ensureVRRForDisplay(m.get()); ensureVRRForDisplay(m);
} }
} }
@@ -1604,7 +1663,7 @@ void CConfigManager::addParseError(const std::string& err) {
g_pHyprError->queueCreate(err + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); g_pHyprError->queueCreate(err + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
} }
CMonitor* CConfigManager::getBoundMonitorForWS(const std::string& wsname) { PHLMONITOR CConfigManager::getBoundMonitorForWS(const std::string& wsname) {
auto monitor = getBoundMonitorStringForWS(wsname); auto monitor = getBoundMonitorStringForWS(wsname);
if (monitor.substr(0, 5) == "desc:") if (monitor.substr(0, 5) == "desc:")
return g_pCompositor->getMonitorFromDesc(monitor.substr(5)); return g_pCompositor->getMonitorFromDesc(monitor.substr(5));
@@ -2725,6 +2784,18 @@ const std::vector<SConfigOptionDescription>& CConfigManager::getAllDescriptions(
return CONFIG_OPTIONS; return CONFIG_OPTIONS;
} }
bool CConfigManager::shouldUseSoftwareCursors() {
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
switch (*PNOHW) {
case 0: return false;
case 1: return true;
default: return g_pHyprRenderer->isNvidia();
}
return true;
}
std::string SConfigOptionDescription::jsonify() const { std::string SConfigOptionDescription::jsonify() const {
auto parseData = [this]() -> std::string { auto parseData = [this]() -> std::string {
return std::visit( return std::visit(

View File

@@ -169,11 +169,11 @@ class CConfigManager {
static std::string getMainConfigPath(); static std::string getMainConfigPath();
const std::string getConfigString(); const std::string getConfigString();
SMonitorRule getMonitorRuleFor(const CMonitor&); SMonitorRule getMonitorRuleFor(const PHLMONITOR);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
std::string getDefaultWorkspaceFor(const std::string&); std::string getDefaultWorkspaceFor(const std::string&);
CMonitor* getBoundMonitorForWS(const std::string&); PHLMONITOR getBoundMonitorForWS(const std::string&);
std::string getBoundMonitorStringForWS(const std::string&); std::string getBoundMonitorStringForWS(const std::string&);
const std::deque<SWorkspaceRule>& getAllWorkspaceRules(); const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
@@ -198,7 +198,9 @@ class CConfigManager {
void appendMonitorRule(const SMonitorRule&); void appendMonitorRule(const SMonitorRule&);
bool replaceMonitorRule(const SMonitorRule&); bool replaceMonitorRule(const SMonitorRule&);
void ensureMonitorStatus(); void ensureMonitorStatus();
void ensureVRR(CMonitor* pMonitor = nullptr); void ensureVRR(PHLMONITOR pMonitor = nullptr);
bool shouldUseSoftwareCursors();
std::string parseKeyword(const std::string&, const std::string&); std::string parseKeyword(const std::string&, const std::string&);

View File

@@ -13,7 +13,7 @@ autogenerated = 1 # remove this line to remove the warning
# This is an example Hyprland config file. # This is an example Hyprland config file.
# Refer to the wiki for more information. # Refer to the wiki for more information.
# https://wiki.hyprland.org/Configuring/Configuring-Hyprland/ # https://wiki.hyprland.org/Configuring/
# Please note not all available settings / options are set here. # Please note not all available settings / options are set here.
# For a full list, see the wiki # For a full list, see the wiki
@@ -99,10 +99,12 @@ decoration {
active_opacity = 1.0 active_opacity = 1.0
inactive_opacity = 1.0 inactive_opacity = 1.0
drop_shadow = true shadow {
shadow_range = 4 enabled = true
shadow_render_power = 3 range = 4
col.shadow = rgba(1a1a1aee) render_power = 3
color = rgba(1a1a1aee)
}
# https://wiki.hyprland.org/Configuring/Variables/#blur # https://wiki.hyprland.org/Configuring/Variables/#blur
blur { blur {
@@ -116,20 +118,44 @@ decoration {
# https://wiki.hyprland.org/Configuring/Variables/#animations # https://wiki.hyprland.org/Configuring/Variables/#animations
animations { animations {
enabled = true enabled = yes, please :)
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = myBezier, 0.05, 0.9, 0.1, 1.05 bezier = easeOutQuint,0.23,1,0.32,1
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = windows, 1, 7, myBezier animation = global, 1, 10, default
animation = windowsOut, 1, 7, default, popin 80% animation = border, 1, 5.39, easeOutQuint
animation = border, 1, 10, default animation = windows, 1, 4.79, easeOutQuint
animation = borderangle, 1, 8, default animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
animation = fade, 1, 7, default animation = windowsOut, 1, 1.49, linear, popin 87%
animation = workspaces, 1, 6, default animation = fadeIn, 1, 1.73, almostLinear
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, fade
animation = workspacesIn, 1, 1.21, almostLinear, fade
animation = workspacesOut, 1, 1.94, almostLinear, fade
} }
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
@@ -268,5 +294,9 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# Example windowrule v2 # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
)#"; )#";

View File

@@ -159,7 +159,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "GPU:\n\t"; finalCrashReport += "GPU:\n\t";
#if defined(__DragonFly__) || defined(__FreeBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__)
finalCrashReport.writeCmdOutput("pciconf -lv | fgrep -A4 vga"); finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga");
#else #else
finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA"); finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA");
#endif #endif

View File

@@ -54,7 +54,7 @@ static std::string formatToString(uint32_t drmFormat) {
return "Invalid"; return "Invalid";
} }
static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) { static std::string availableModesForOutput(PHLMONITOR pMonitor, eHyprCtlOutputFormat format) {
std::string result; std::string result;
for (auto const& m : pMonitor->output->modes) { for (auto const& m : pMonitor->output->modes) {
@@ -103,9 +103,11 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"focused": {}, "focused": {},
"dpmsStatus": {}, "dpmsStatus": {},
"vrr": {}, "vrr": {},
"solitary": "{:x}",
"activelyTearing": {}, "activelyTearing": {},
"disabled": {}, "disabled": {},
"currentFormat": "{}", "currentFormat": "{}",
"mirrorOf": "{}",
"availableModes": [{}] "availableModes": [{}]
}},)#", }},)#",
@@ -114,19 +116,21 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(),
escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(),
(m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat),
m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format));
} else { } else {
result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", "dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tmirrorOf: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(),
!m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat),
m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format));
} }
return result; return result;
@@ -158,16 +162,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
if (!m->output || m->ID == -1) if (!m->output || m->ID == -1)
continue; continue;
result += std::format( result += CHyprCtl::getMonitorData(m, format);
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: A {} H {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"),
(int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), m->tearingState.activelyTearing, !m->m_bEnabled,
formatToString(m->output->state->state().drmFormat), formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
} }
} }
@@ -249,7 +244,7 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
(uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"),
(int64_t)w->m_iMonitorID, escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), (int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass),
escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
(uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
@@ -261,7 +256,7 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", "{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName),
(int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(),
(int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
} }
@@ -295,7 +290,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) { std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) {
const auto PLASTW = w->getLastFocusedWindow(); const auto PLASTW = w->getLastFocusedWindow();
const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID); const auto PMONITOR = w->m_pMonitor.lock();
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
return std::format(R"#({{ return std::format(R"#({{
"id": {}, "id": {},
@@ -334,11 +329,13 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : ""; const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : "";
const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : ""; const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : "";
const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : ""; const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : "";
const std::string defaultName = r.defaultName.has_value() ? std::format(",\n \"defaultName\": \"{}\"", escapeJSONStrings(r.defaultName.value())) : "";
std::string result = std::format(R"#({{ std::string result =
"workspaceString": "{}"{}{}{}{}{}{}{}{} std::format(R"#({{
"workspaceString": "{}"{}{}{}{}{}{}{}{}{}{}{}
}})#", }})#",
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow); escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow, defaultName);
return result; return result;
} else { } else {
@@ -356,9 +353,10 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>"); const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>");
const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>"); const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>");
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : "<unset>"); const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : "<unset>");
const std::string defaultName = std::format("\tdefaultName: {}\n", r.defaultName.value_or("<unset>"));
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow); borderSize, border, rounding, decorate, shadow, defaultName);
return result; return result;
} }
@@ -553,6 +551,15 @@ std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request
std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
auto getModState = [](SP<IKeyboard> keyboard, const char* xkbModName) -> bool {
auto IDX = xkb_keymap_mod_get_index(keyboard->xkbKeymap, xkbModName);
if (IDX == XKB_MOD_INVALID)
return false;
return (keyboard->modifiersState.locked & (1 << IDX)) > 0;
};
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n"; result += "{\n";
result += "\"mice\": [\n"; result += "\"mice\": [\n";
@@ -584,11 +591,13 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
"variant": "{}", "variant": "{}",
"options": "{}", "options": "{}",
"active_keymap": "{}", "active_keymap": "{}",
"capsLock": {},
"numLock": {},
"main": {} "main": {}
}},)#", }},)#",
(uintptr_t)k.get(), escapeJSONStrings(k->hlName), escapeJSONStrings(k->currentRules.rules), escapeJSONStrings(k->currentRules.model), (uintptr_t)k.get(), escapeJSONStrings(k->hlName), escapeJSONStrings(k->currentRules.rules), escapeJSONStrings(k->currentRules.model),
escapeJSONStrings(k->currentRules.layout), escapeJSONStrings(k->currentRules.variant), escapeJSONStrings(k->currentRules.options), escapeJSONStrings(KM), escapeJSONStrings(k->currentRules.layout), escapeJSONStrings(k->currentRules.variant), escapeJSONStrings(k->currentRules.options), escapeJSONStrings(KM),
(k->active ? "true" : "false")); (getModState(k, XKB_MOD_NAME_CAPS) ? "true" : "false"), (getModState(k, XKB_MOD_NAME_NUM) ? "true" : "false"), (k->active ? "true" : "false"));
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -672,9 +681,11 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
for (auto const& k : g_pInputManager->m_vKeyboards) { for (auto const& k : g_pInputManager->m_vKeyboards) {
const auto KM = k->getActiveLayout(); const auto KM = k->getActiveLayout();
result += std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tmain: {}\n", result +=
(uintptr_t)k.get(), k->hlName, k->currentRules.rules, k->currentRules.model, k->currentRules.layout, k->currentRules.variant, std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tcapsLock: "
k->currentRules.options, KM, (k->active ? "yes" : "no")); "{}\n\t\t\tnumLock: {}\n\t\t\tmain: {}\n",
(uintptr_t)k.get(), k->hlName, k->currentRules.rules, k->currentRules.model, k->currentRules.layout, k->currentRules.variant, k->currentRules.options,
KM, (getModState(k, XKB_MOD_NAME_CAPS) ? "yes" : "no"), (getModState(k, XKB_MOD_NAME_NUM) ? "yes" : "no"), (k->active ? "yes" : "no"));
} }
result += "\n\nTablets:\n"; result += "\n\nTablets:\n";
@@ -857,26 +868,33 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' ');
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n"
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + "Date: {}\n"
"\n\nflags: (if any)\n"; "Tag: {}, commits: {}\n"
"built against aquamarine {}\n\n\n",
HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION);
#if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND))
result += "no flags were set\n";
#else
result += "flags set:\n";
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "legacyrenderer\n"; result += "legacyrenderer\n";
#endif #endif
#ifndef ISDEBUG #ifdef ISDEBUG
result += "debug\n"; result += "debug\n";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
result += "no xwayland\n"; result += "no xwayland\n";
#endif #endif
#endif
return result; return result;
} else { } else {
std::string result = std::format( std::string result = std::format(
R"#({{ R"#({{
"branch": "{}", "branch": "{}",
"commit": "{}", "commit": "{}",
"version": "{}",
"dirty": {}, "dirty": {},
"commit_message": "{}", "commit_message": "{}",
"commit_date": "{}", "commit_date": "{}",
@@ -884,13 +902,13 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
"commits": "{}", "commits": "{}",
"buildAquamarine": "{}", "buildAquamarine": "{}",
"flags": [)#", "flags": [)#",
GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG,
AQUAMARINE_VERSION); GIT_COMMITS, AQUAMARINE_VERSION);
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "\"legacyrenderer\","; result += "\"legacyrenderer\",";
#endif #endif
#ifndef ISDEBUG #ifdef ISDEBUG
result += "\"debug\","; result += "\"debug\",";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
@@ -924,7 +942,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
result += "\n\n"; result += "\n\n";
#if defined(__DragonFly__) || defined(__FreeBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga"); const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga");
#elif defined(__arm__) || defined(__aarch64__) #elif defined(__arm__) || defined(__aarch64__)
const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible"); const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible");
#else #else
@@ -938,11 +956,14 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n"; result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
result += "plugins:\n"; result += "plugins:\n";
if (g_pPluginSystem) {
for (auto const& pl : g_pPluginSystem->getAllPlugins()) { for (auto const& pl : g_pPluginSystem->getAllPlugins()) {
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
} }
} else
result += "\tunknown: not runtime\n";
if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { if (g_pHyprCtl && g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) {
result += "\n======Config-Start======\n"; result += "\n======Config-Start======\n";
result += g_pConfigManager->getConfigString(); result += g_pConfigManager->getConfigString();
result += "\n======Config-End========\n"; result += "\n======Config-End========\n";
@@ -1022,9 +1043,10 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
} }
// decorations will probably need a repaint // decorations will probably need a repaint
if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source") { if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source" ||
COMMAND.starts_with("windowrule")) {
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
g_pHyprRenderer->damageMonitor(m.get()); g_pHyprRenderer->damageMonitor(m);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
} }
} }
@@ -1243,101 +1265,8 @@ std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
} }
std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) { std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); auto result = g_pKeybindManager->m_mDispatchers["setprop"](request.substr(request.find_first_of(' ') + 1, -1));
return "DEPRECATED: use hyprctl dispatch setprop instead" + (result.success ? "" : "\n" + result.error);
if (vars.size() < 4)
return "not enough args";
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
if (!PWINDOW)
return "window not found";
const auto PROP = vars[2];
const auto VAL = vars[3];
bool noFocus = PWINDOW->m_sWindowData.noFocus.valueOrDefault();
try {
if (PROP == "animationstyle") {
PWINDOW->m_sWindowData.animationStyle = CWindowOverridableVar(VAL, PRIORITY_SET_PROP);
} else if (PROP == "maxsize") {
PWINDOW->m_sWindowData.maxSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sWindowData.maxSize.value().x, PWINDOW->m_vRealSize.goal().x),
std::min((double)PWINDOW->m_sWindowData.maxSize.value().y, PWINDOW->m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
PWINDOW->setHidden(false);
} else if (PROP == "minsize") {
PWINDOW->m_sWindowData.minSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sWindowData.minSize.value().x, PWINDOW->m_vRealSize.goal().x),
std::max((double)PWINDOW->m_sWindowData.minSize.value().y, PWINDOW->m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
PWINDOW->setHidden(false);
} else if (PROP == "alpha") {
PWINDOW->m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alpha.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactive") {
PWINDOW->m_sWindowData.alphaInactive =
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphafullscreen") {
PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphaoverride") {
PWINDOW->m_sWindowData.alpha =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactiveoverride") {
PWINDOW->m_sWindowData.alphaInactive =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphafullscreenoverride") {
PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") {
CGradientValueData colorData = {};
if (vars.size() > 4) {
for (int i = 3; i < static_cast<int>(vars.size()); ++i) {
const auto TOKEN = vars[i];
if (TOKEN.ends_with("deg"))
colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0);
else
colorData.m_vColors.push_back(configStringToInt(TOKEN));
}
} else if (VAL != "-1")
colorData.m_vColors.push_back(configStringToInt(VAL));
if (PROP == "activebordercolor")
PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
else
PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
} else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) {
auto pWindowDataElement = search->second(PWINDOW);
if (VAL == "toggle")
*pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP);
else if (VAL == "unset")
pWindowDataElement->unset(PRIORITY_SET_PROP);
else
*pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP);
} else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) {
if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else
*(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP);
} else {
return "prop not found";
}
} catch (std::exception& e) { return "error in parsing prop value: " + std::string(e.what()); }
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!(PWINDOW->m_sWindowData.noFocus.valueOrDefault() == noFocus)) {
g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->focusWindow(PLASTWINDOW);
}
for (auto const& m : g_pCompositor->m_vMonitors)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
return "ok";
} }
std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) { std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
@@ -1624,6 +1553,14 @@ std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
return json; return json;
} }
std::string submapRequest(eHyprCtlOutputFormat format, std::string request) {
std::string submap = g_pKeybindManager->getCurrentSubmap();
if (submap.empty())
submap = "default";
return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n");
}
CHyprCtl::CHyprCtl() { CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
@@ -1645,6 +1582,7 @@ CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest}); registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest});
registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions}); registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
registerCommand(SHyprCtlCommand{"submap", true, submapRequest});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
@@ -1763,8 +1701,16 @@ std::string CHyprCtl::getReply(std::string request) {
rd.blurFBDirty = true; rd.blurFBDirty = true;
} }
for (auto const& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || !g_pCompositor->isWorkspaceVisible(w->m_pWorkspace))
continue;
w->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(w);
}
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
g_pHyprRenderer->damageMonitor(m.get()); g_pHyprRenderer->damageMonitor(m);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
} }
} }

View File

@@ -5,6 +5,10 @@
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#include <functional> #include <functional>
// exposed for main.cpp
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request);
std::string versionRequest(eHyprCtlOutputFormat format, std::string request);
class CHyprCtl { class CHyprCtl {
public: public:
CHyprCtl(); CHyprCtl();

View File

@@ -7,7 +7,7 @@ CHyprDebugOverlay::CHyprDebugOverlay() {
m_pTexture = makeShared<CTexture>(); m_pTexture = makeShared<CTexture>();
} }
void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
m_dLastRenderTimes.push_back(durationUs / 1000.f); m_dLastRenderTimes.push_back(durationUs / 1000.f);
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
@@ -17,7 +17,7 @@ void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs)
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f); m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f);
if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
@@ -27,7 +27,7 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float dur
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) { void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
m_dLastFrametimes.push_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f); m_dLastFrametimes.push_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate)
@@ -39,7 +39,7 @@ void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) {
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
// anim data too // anim data too
const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor.get(); const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor.lock() : g_pCompositor->m_pLastMonitor.lock();
if (PMONITORFORTICKS) { if (PMONITORFORTICKS) {
if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate) if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate)
m_dLastAnimationTicks.pop_front(); m_dLastAnimationTicks.pop_front();
@@ -188,21 +188,21 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
return posY - offset; return posY - offset;
} }
void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) { void CHyprDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs); m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs);
} }
void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) { void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs); m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
} }
void CHyprDebugOverlay::frameData(CMonitor* pMonitor) { void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) {
m_mMonitorOverlays[pMonitor].frameData(pMonitor); m_mMonitorOverlays[pMonitor].frameData(pMonitor);
} }
void CHyprDebugOverlay::draw() { void CHyprDebugOverlay::draw() {
const auto PMONITOR = g_pCompositor->m_vMonitors.front().get(); const auto PMONITOR = g_pCompositor->m_vMonitors.front();
if (!m_pCairoSurface || !m_pCairo) { if (!m_pCairoSurface || !m_pCairo) {
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
@@ -218,7 +218,7 @@ void CHyprDebugOverlay::draw() {
// draw the things // draw the things
int offsetY = 0; int offsetY = 0;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
offsetY += m_mMonitorOverlays[m.get()].draw(offsetY); offsetY += m_mMonitorOverlays[m].draw(offsetY);
offsetY += 5; // for padding between mons offsetY += 5; // for padding between mons
} }

View File

@@ -5,7 +5,7 @@
#include "../render/Texture.hpp" #include "../render/Texture.hpp"
#include <deque> #include <deque>
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <unordered_map> #include <map>
class CHyprRenderer; class CHyprRenderer;
@@ -13,9 +13,9 @@ class CHyprMonitorDebugOverlay {
public: public:
int draw(int offset); int draw(int offset);
void renderData(CMonitor* pMonitor, float durationUs); void renderData(PHLMONITOR pMonitor, float durationUs);
void renderDataNoOverlay(CMonitor* pMonitor, float durationUs); void renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs);
void frameData(CMonitor* pMonitor); void frameData(PHLMONITOR pMonitor);
private: private:
std::deque<float> m_dLastFrametimes; std::deque<float> m_dLastFrametimes;
@@ -23,7 +23,7 @@ class CHyprMonitorDebugOverlay {
std::deque<float> m_dLastRenderTimesNoOverlay; std::deque<float> m_dLastRenderTimesNoOverlay;
std::deque<float> m_dLastAnimationTicks; std::deque<float> m_dLastAnimationTicks;
std::chrono::high_resolution_clock::time_point m_tpLastFrame; std::chrono::high_resolution_clock::time_point m_tpLastFrame;
CMonitor* m_pMonitor = nullptr; PHLMONITORREF m_pMonitor;
CBox m_wbLastDrawnBox; CBox m_wbLastDrawnBox;
friend class CHyprRenderer; friend class CHyprRenderer;
@@ -33,12 +33,12 @@ class CHyprDebugOverlay {
public: public:
CHyprDebugOverlay(); CHyprDebugOverlay();
void draw(); void draw();
void renderData(CMonitor*, float durationUs); void renderData(PHLMONITOR, float durationUs);
void renderDataNoOverlay(CMonitor*, float durationUs); void renderDataNoOverlay(PHLMONITOR, float durationUs);
void frameData(CMonitor*); void frameData(PHLMONITOR);
private: private:
std::unordered_map<CMonitor*, CHyprMonitorDebugOverlay> m_mMonitorOverlays; std::map<PHLMONITORREF, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
cairo_surface_t* m_pCairoSurface = nullptr; cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr; cairo_t* m_pCairo = nullptr;

View File

@@ -37,7 +37,7 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() {
void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) { void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) {
const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get(); const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
PNOTIF->text = text; PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text;
PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color; PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color;
PNOTIF->started.reset(); PNOTIF->started.reset();
PNOTIF->timeMs = timeMs; PNOTIF->timeMs = timeMs;
@@ -45,7 +45,7 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC
PNOTIF->fontSize = fontSize; PNOTIF->fontSize = fontSize;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m.get()); g_pCompositor->scheduleFrameForMonitor(m);
} }
} }
@@ -61,7 +61,7 @@ void CHyprNotificationOverlay::dismissNotifications(const int amount) {
} }
} }
CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
static constexpr auto ANIM_DURATION_MS = 600.0; static constexpr auto ANIM_DURATION_MS = 600.0;
static constexpr auto ANIM_LAG_MS = 100.0; static constexpr auto ANIM_LAG_MS = 100.0;
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0; static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
@@ -187,7 +187,7 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10}; return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
} }
void CHyprNotificationOverlay::draw(CMonitor* pMonitor) { void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
const auto MONSIZE = pMonitor->vecTransformedSize; const auto MONSIZE = pMonitor->vecTransformedSize;

View File

@@ -41,13 +41,13 @@ class CHyprNotificationOverlay {
CHyprNotificationOverlay(); CHyprNotificationOverlay();
~CHyprNotificationOverlay(); ~CHyprNotificationOverlay();
void draw(CMonitor* pMonitor); void draw(PHLMONITOR pMonitor);
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f); void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
void dismissNotifications(const int amount); void dismissNotifications(const int amount);
bool hasAny(); bool hasAny();
private: private:
CBox drawNotifications(CMonitor* pMonitor); CBox drawNotifications(PHLMONITOR pMonitor);
CBox m_bLastDamage; CBox m_bLastDamage;
std::deque<std::unique_ptr<SNotification>> m_dNotifications; std::deque<std::unique_ptr<SNotification>> m_dNotifications;
@@ -55,7 +55,7 @@ class CHyprNotificationOverlay {
cairo_surface_t* m_pCairoSurface = nullptr; cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr; cairo_t* m_pCairo = nullptr;
CMonitor* m_pLastMonitor = nullptr; PHLMONITORREF m_pLastMonitor;
Vector2D m_vecLastSize = Vector2D(-1, -1); Vector2D m_vecLastSize = Vector2D(-1, -1);
SP<CTexture> m_pTexture; SP<CTexture> m_pTexture;

View File

@@ -4,7 +4,7 @@
#include "RollingLogFollow.hpp" #include "RollingLogFollow.hpp"
#include <fstream> #include <fstream>
#include <iostream> #include <print>
#include <fcntl.h> #include <fcntl.h>
void Debug::init(const std::string& IS) { void Debug::init(const std::string& IS) {
@@ -69,5 +69,5 @@ void Debug::log(LogLevel level, std::string str) {
// log it to the stdout too. // log it to the stdout too.
if (!disableStdout) if (!disableStdout)
std::cout << ((coloredLogs && !**coloredLogs) ? str : coloredStr) << "\n"; std::println("{}", ((coloredLogs && !**coloredLogs) ? str : coloredStr));
} }

View File

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

View File

@@ -3,6 +3,7 @@
class CWorkspace; class CWorkspace;
class CWindow; class CWindow;
class CLayerSurface; class CLayerSurface;
class CMonitor;
/* Shared pointer to a workspace */ /* Shared pointer to a workspace */
typedef SP<CWorkspace> PHLWORKSPACE; typedef SP<CWorkspace> PHLWORKSPACE;
@@ -18,3 +19,8 @@ typedef WP<CWindow> PHLWINDOWREF;
typedef SP<CLayerSurface> PHLLS; typedef SP<CLayerSurface> PHLLS;
/* Weak pointer to a layer surface */ /* Weak pointer to a layer surface */
typedef WP<CLayerSurface> PHLLSREF; typedef WP<CLayerSurface> PHLLSREF;
/* Shared pointer to a monitor */
typedef SP<CMonitor> PHLMONITOR;
/* Weak pointer to a monitor */
typedef WP<CMonitor> PHLMONITORREF;

View File

@@ -8,7 +8,7 @@
PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) { PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource)); PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource));
CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor); auto pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor);
pLS->surface->assign(resource->surface.lock(), pLS); pLS->surface->assign(resource->surface.lock(), pLS);
@@ -18,7 +18,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
} }
if (pMonitor->pMirrorOf) if (pMonitor->pMirrorOf)
pMonitor = g_pCompositor->m_vMonitors.front().get(); pMonitor = g_pCompositor->m_vMonitors.front();
pLS->self = pLS; pLS->self = pLS;
@@ -26,7 +26,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
pLS->layer = resource->current.layer; pLS->layer = resource->current.layer;
pLS->popupHead = std::make_unique<CPopup>(pLS); pLS->popupHead = std::make_unique<CPopup>(pLS);
pLS->monitorID = pMonitor->ID; pLS->monitor = pMonitor;
pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS);
pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace);
@@ -50,7 +50,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
void CLayerSurface::registerCallbacks() { void CLayerSurface::registerCallbacks() {
alpha.setUpdateCallback([this](void*) { alpha.setUpdateCallback([this](void*) {
if (dimAround) if (dimAround)
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(monitorID)); g_pHyprRenderer->damageMonitor(monitor.lock());
}); });
} }
@@ -82,9 +82,9 @@ CLayerSurface::~CLayerSurface() {
void CLayerSurface::onDestroy() { void CLayerSurface::onDestroy() {
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get()); Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get());
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const auto PMONITOR = monitor.lock();
if (!g_pCompositor->getMonitorFromID(monitorID)) if (!PMONITOR)
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)"); Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
if (!fadingOut) { if (!fadingOut) {
@@ -137,7 +137,7 @@ void CLayerSurface::onMap() {
g_pCompositor->removeFromFadingOutSafe(self.lock()); g_pCompositor->removeFromFadingOutSafe(self.lock());
// fix if it changed its mon // fix if it changed its mon
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const auto PMONITOR = monitor.lock();
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -175,8 +175,7 @@ void CLayerSurface::onMap() {
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
const auto WORKSPACE = PMONITOR->activeWorkspace; const bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN;
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
readyToDelete = false; readyToDelete = false;
@@ -197,7 +196,7 @@ void CLayerSurface::onUnmap() {
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) { if (!monitor || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
@@ -221,9 +220,9 @@ void CLayerSurface::onUnmap() {
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const auto PMONITOR = monitor.lock();
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == surface->resource() || g_pSeatManager->state.pointerFocus == surface->resource();
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -232,7 +231,7 @@ void CLayerSurface::onUnmap() {
// vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable())) if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
g_pInputManager->refocusLastWindow(PMONITOR); g_pInputManager->refocusLastWindow(PMONITOR);
else if (g_pCompositor->m_pLastFocus) else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource())
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock()); g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
@@ -256,13 +255,13 @@ void CLayerSurface::onCommit() {
if (layerSurface->surface && !layerSurface->surface->current.texture) { if (layerSurface->surface && !layerSurface->surface->current.texture) {
fadingOut = false; fadingOut = false;
geometry = {}; geometry = {};
g_pHyprRenderer->arrangeLayersForMonitor(monitorID); g_pHyprRenderer->arrangeLayersForMonitor(monitorID());
} }
return; return;
} }
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const auto PMONITOR = monitor.lock();
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -321,8 +320,18 @@ void CLayerSurface::onCommit() {
realSize.setValueAndWarp(geometry.size()); realSize.setValueAndWarp(geometry.size());
} }
if (mapped) { if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) {
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); bool WASLASTFOCUS = false;
layerSurface->surface->breadthfirst(
[&WASLASTFOCUS](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->state.keyboardFocus == surf; },
nullptr);
if (!WASLASTFOCUS && popupHead) {
popupHead->breadthfirst(
[&WASLASTFOCUS](CPopup* popup, void* data) {
WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource());
},
nullptr);
}
const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
@@ -332,11 +341,13 @@ void CLayerSurface::onCommit() {
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
// if the surface was focused and interactive but now isn't, refocus // if the surface was focused and interactive but now isn't, refocus
if (WASLASTFOCUS && !layerSurface->current.interactivity) { if (WASLASTFOCUS && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) {
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either, // moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
// so unfocus the surface here. // so unfocus the surface here.
g_pCompositor->focusSurface(nullptr); g_pCompositor->focusSurface(nullptr);
g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID)); g_pInputManager->refocusLastWindow(monitor.lock());
} else if (WASLASTFOCUS && WASEXCLUSIVE && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) {
g_pInputManager->simulateMouseMovement();
} else if (!WASEXCLUSIVE && ISEXCLUSIVE) { } else if (!WASEXCLUSIVE && ISEXCLUSIVE) {
// if now exclusive and not previously // if now exclusive and not previously
g_pSeatManager->setGrab(nullptr); g_pSeatManager->setGrab(nullptr);
@@ -545,3 +556,7 @@ int CLayerSurface::popupsCount() {
popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no);
return no; return no;
} }
MONITORID CLayerSurface::monitorID() {
return monitor ? monitor->ID : MONITOR_INVALID;
}

View File

@@ -42,7 +42,7 @@ class CLayerSurface {
bool mapped = false; bool mapped = false;
uint32_t layer = 0; uint32_t layer = 0;
MONITORID monitorID = -1; PHLMONITORREF monitor;
bool fadingOut = false; bool fadingOut = false;
bool readyToDelete = false; bool readyToDelete = false;
@@ -70,6 +70,7 @@ class CLayerSurface {
void onMap(); void onMap();
void onUnmap(); void onUnmap();
void onCommit(); void onCommit();
MONITORID monitorID();
private: private:
struct { struct {
@@ -83,6 +84,6 @@ class CLayerSurface {
// For the list lookup // For the list lookup
bool operator==(const CLayerSurface& rhs) const { bool operator==(const CLayerSurface& rhs) const {
return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID; return layerSurface == rhs.layerSurface && monitor == rhs.monitor;
} }
}; };

View File

@@ -4,6 +4,8 @@
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include <ranges> #include <ranges>
CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) {
@@ -106,6 +108,8 @@ void CPopup::onUnmap() {
return; return;
} }
m_bMapped = false;
m_vLastSize = m_pResource->surface->surface->current.size; m_vLastSize = m_pResource->surface->surface->current.size;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
@@ -116,8 +120,6 @@ void CPopup::onUnmap() {
m_pSubsurfaceHead.reset(); m_pSubsurfaceHead.reset();
g_pInputManager->simulateMouseMovement();
if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
@@ -131,6 +133,11 @@ void CPopup::onUnmap() {
g_pHyprRenderer->damageBox(&box); g_pHyprRenderer->damageBox(&box);
}, },
nullptr); nullptr);
const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource();
if (WASLASTFOCUS)
g_pInputManager->simulateMouseMovement();
} }
void CPopup::onCommit(bool ignoreSiblings) { void CPopup::onCommit(bool ignoreSiblings) {
@@ -288,12 +295,13 @@ bool CPopup::visible() {
return false; return false;
} }
void CPopup::bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data) { void CPopup::bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPopup*, void*)> fn, void* data) {
for (auto const& n : nodes) { for (auto const& n : nodes) {
fn(n, data); fn(n, data);
} }
std::vector<CPopup*> nodes2; std::vector<CPopup*> nodes2;
nodes2.reserve(nodes.size() * 2);
for (auto const& n : nodes) { for (auto const& n : nodes) {
for (auto const& c : n->m_vChildren) { for (auto const& c : n->m_vChildren) {
@@ -316,7 +324,7 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
breadthfirst([](CPopup* popup, void* data) { ((std::vector<CPopup*>*)data)->push_back(popup); }, &popups); breadthfirst([](CPopup* popup, void* data) { ((std::vector<CPopup*>*)data)->push_back(popup); }, &popups);
for (auto const& p : popups | std::views::reverse) { for (auto const& p : popups | std::views::reverse) {
if (!p->m_pResource) if (!p->m_pResource || !p->m_bMapped)
continue; continue;
if (!allowsInput) { if (!allowsInput) {

View File

@@ -41,6 +41,7 @@ class CPopup {
// //
SP<CWLSurface> m_pWLSurface; SP<CWLSurface> m_pWLSurface;
bool m_bMapped = false;
private: private:
// T1 owners, each popup has to have one of these // T1 owners, each popup has to have one of these
@@ -58,7 +59,6 @@ class CPopup {
bool m_bRequestedReposition = false; bool m_bRequestedReposition = false;
bool m_bInert = false; bool m_bInert = false;
bool m_bMapped = false;
// //
std::vector<SP<CPopup>> m_vChildren; std::vector<SP<CPopup>> m_vChildren;
@@ -81,5 +81,5 @@ class CPopup {
Vector2D localToGlobal(const Vector2D& rel); Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords(); Vector2D t1ParentCoords();
static void bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data); static void bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPopup*, void*)> fn, void* data);
}; };

View File

@@ -30,13 +30,7 @@ CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner)
} }
CSubsurface::~CSubsurface() { CSubsurface::~CSubsurface() {
hyprListener_newSubsurface.removeCallback(); ;
if (!m_pSubsurface)
return;
hyprListener_commitSubsurface.removeCallback();
hyprListener_destroySubsurface.removeCallback();
} }
void CSubsurface::initSignals() { void CSubsurface::initSignals() {

View File

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

View File

@@ -62,7 +62,7 @@ bool CWLSurface::small() const {
const auto O = m_pWindowOwner.lock(); const auto O = m_pWindowOwner.lock();
return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1; return O->m_vReportedSize.x > m_pResource->current.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1;
} }
Vector2D CWLSurface::correctSmallVec() const { Vector2D CWLSurface::correctSmallVec() const {

View File

@@ -113,7 +113,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
const int BORDERSIZE = getRealBorderSize(); const int BORDERSIZE = getRealBorderSize();
if (m_sWindowData.dimAround.valueOrDefault()) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
} }
@@ -173,7 +173,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
CBox CWindow::getFullWindowBoundingBox() { CBox CWindow::getFullWindowBoundingBox() {
if (m_sWindowData.dimAround.valueOrDefault()) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
} }
@@ -186,7 +186,7 @@ CBox CWindow::getFullWindowBoundingBox() {
} }
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = m_pMonitor.lock();
if (!PMONITOR) if (!PMONITOR)
return {m_vPosition, m_vSize}; return {m_vPosition, m_vSize};
@@ -221,7 +221,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
CBox CWindow::getWindowBoxUnified(uint64_t properties) { CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_sWindowData.dimAround.valueOrDefault()) { if (m_sWindowData.dimAround.valueOrDefault()) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR) if (PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
} }
@@ -240,10 +240,6 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) {
return box; return box;
} }
CBox CWindow::getWindowMainSurfaceBox() {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
SBoxExtents CWindow::getFullWindowReservedArea() { SBoxExtents CWindow::getFullWindowReservedArea() {
return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock()); return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock());
} }
@@ -356,9 +352,9 @@ void CWindow::updateSurfaceScaleTransformDetails(bool force) {
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID); const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
m_iLastSurfaceMonitorID = m_iMonitorID; m_iLastSurfaceMonitorID = monitorID();
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PNEWMONITOR = m_pMonitor.lock();
if (!PNEWMONITOR) if (!PNEWMONITOR)
return; return;
@@ -370,10 +366,10 @@ void CWindow::updateSurfaceScaleTransformDetails(bool force) {
m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr); m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr);
} }
m_pWLSurface->resource()->breadthfirst( const auto PMONITOR = m_pMonitor.lock();
[this](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
m_pWLSurface->resource()->breadthfirst(
[PMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) {
const auto PSURFACE = CWLSurface::fromResource(s); const auto PSURFACE = CWLSurface::fromResource(s);
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale) if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
return; return;
@@ -408,7 +404,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
const auto OLDWORKSPACE = m_pWorkspace; const auto OLDWORKSPACE = m_pWorkspace;
m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->m_iMonitorID : -1; m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1;
m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F); m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F);
m_fMovingToWorkspaceAlpha = 0.F; m_fMovingToWorkspaceAlpha = 0.F;
m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; }); m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; });
@@ -419,11 +415,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID); g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID);
g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID); g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->monitorID());
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -435,14 +431,14 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
if (const auto SWALLOWED = m_pSwallowed.lock()) { if (const auto SWALLOWED = m_pSwallowed.lock()) {
SWALLOWED->moveToWorkspace(pWorkspace); SWALLOWED->moveToWorkspace(pWorkspace);
SWALLOWED->m_iMonitorID = m_iMonitorID; SWALLOWED->m_pMonitor = m_pMonitor;
} }
// update xwayland coords // update xwayland coords
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value()); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value());
if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE->m_iID) == 0 && *PCLOSEONLASTSPECIAL) { if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE->m_iID) == 0 && *PCLOSEONLASTSPECIAL) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(OLDWORKSPACE->m_iMonitorID); PMONITOR) if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
} }
@@ -452,14 +448,20 @@ PHLWINDOW CWindow::X11TransientFor() {
return nullptr; return nullptr;
auto s = m_pXWaylandSurface->parent; auto s = m_pXWaylandSurface->parent;
auto oldParent = s; std::vector<SP<CXWaylandSurface>> visited;
while (s) { while (s) {
// break cyclic loop of m_pXWaylandSurface being parent of itself, #TODO reject this from even being created? // break loops. Some X apps make them, and it seems like it's valid behavior?!?!?!
if (!s->parent || s->parent == oldParent) // TODO: we should reject loops being created in the first place.
if (std::find(visited.begin(), visited.end(), s) != visited.end())
break; break;
visited.emplace_back(s.lock());
s = s->parent; s = s->parent;
} }
if (s == m_pXWaylandSurface)
return nullptr; // dead-ass circle
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pXWaylandSurface != s) if (w->m_pXWaylandSurface != s)
continue; continue;
@@ -515,19 +517,19 @@ void CWindow::onUnmap() {
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; }); std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; });
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) { if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace) if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this) if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this)
PMONITOR->solitaryClient.reset(); PMONITOR->solitaryClient.reset();
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
m_pWorkspace.reset(); m_pWorkspace.reset();
@@ -736,9 +738,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} }
m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority); m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
m_vRealSize = clampWindowSize(std::nullopt, m_sWindowData.maxSize.value());
Vector2D(std::min((double)m_sWindowData.maxSize.value().x, m_vRealSize.goal().x), std::min((double)m_sWindowData.maxSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("minsize")) { } else if (r.szRule.starts_with("minsize")) {
try { try {
@@ -751,9 +752,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} }
m_sWindowData.minSize = CWindowOverridableVar(VEC, priority); m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
m_vRealSize = clampWindowSize(m_sWindowData.minSize.value(), std::nullopt);
Vector2D(std::max((double)m_sWindowData.minSize.value().x, m_vRealSize.goal().x), std::max((double)m_sWindowData.minSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
if (m_sGroupData.pNextWindow.expired()) if (m_sGroupData.pNextWindow.expired())
setHidden(false); setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
@@ -790,7 +790,7 @@ void CWindow::updateDynamicRules() {
EMIT_HOOK_EVENT("windowUpdateRules", m_pSelf.lock()); EMIT_HOOK_EVENT("windowUpdateRules", m_pSelf.lock());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
} }
// check if the point is "hidden" under a rounded corner of the window // check if the point is "hidden" under a rounded corner of the window
@@ -857,7 +857,7 @@ void CWindow::createGroup() {
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("1,{:x}", (uintptr_t)this)}); g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("1,{:x}", (uintptr_t)this)});
@@ -875,7 +875,7 @@ void CWindow::destroyGroup() {
updateWindowDecos(); updateWindowDecos();
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("0,{:x}", (uintptr_t)this)}); g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("0,{:x}", (uintptr_t)this)});
@@ -911,7 +911,7 @@ void CWindow::destroyGroup() {
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!addresses.empty()) if (!addresses.empty())
@@ -1087,7 +1087,7 @@ void CWindow::updateGroupOutputs() {
const auto WS = m_pWorkspace; const auto WS = m_pWorkspace;
while (curr.get() != this) { while (curr.get() != this) {
curr->m_iMonitorID = m_iMonitorID; curr->m_pMonitor = m_pMonitor;
curr->moveToWorkspace(WS); curr->moveToWorkspace(WS);
curr->m_vRealPosition = m_vRealPosition.goal(); curr->m_vRealPosition = m_vRealPosition.goal();
@@ -1184,7 +1184,7 @@ void CWindow::setSuspended(bool suspend) {
m_bSuspended = suspend; m_bSuspended = suspend;
} }
bool CWindow::visibleOnMonitor(CMonitor* pMonitor) { bool CWindow::visibleOnMonitor(PHLMONITOR pMonitor) {
CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()}; CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()};
return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty(); return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty();
@@ -1209,7 +1209,7 @@ void CWindow::onWorkspaceAnimUpdate() {
if (!PWORKSPACE) if (!PWORKSPACE)
return; return;
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); const auto PWSMON = m_pMonitor.lock();
if (!PWSMON) if (!PWSMON)
return; return;
@@ -1253,6 +1253,16 @@ int CWindow::surfacesCount() {
return no; return no;
} }
void CWindow::clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize) {
const Vector2D REALSIZE = m_vRealSize.goal();
const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), maxSize.value_or(Vector2D{INFINITY, INFINITY}));
const Vector2D DELTA = REALSIZE - NEWSIZE;
m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0;
m_vRealSize = NEWSIZE;
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE);
}
bool CWindow::isFullscreen() { bool CWindow::isFullscreen() {
return m_sFullscreenState.internal != FSMODE_NONE; return m_sFullscreenState.internal != FSMODE_NONE;
} }
@@ -1265,6 +1275,10 @@ WORKSPACEID CWindow::workspaceID() {
return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace; return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace;
} }
MONITORID CWindow::monitorID() {
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID;
}
bool CWindow::onSpecialWorkspace() { bool CWindow::onSpecialWorkspace() {
return m_pWorkspace ? m_pWorkspace->m_bIsSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_iLastWorkspace); return m_pWorkspace ? m_pWorkspace->m_bIsSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_iLastWorkspace);
} }
@@ -1451,7 +1465,7 @@ void CWindow::onX11Configure(CBox box) {
m_pXWaylandSurface->configure(box); m_pXWaylandSurface->configure(box);
m_vPendingReportedSize = box.size(); m_vPendingReportedSize = box.size();
m_vReportedSize = box.size(); m_vReportedSize = box.size();
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
m_fX11SurfaceScaledBy = PMONITOR->scale; m_fX11SurfaceScaledBy = PMONITOR->scale;
return; return;
} }
@@ -1477,7 +1491,7 @@ void CWindow::onX11Configure(CBox box) {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling"); static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (*PXWLFORCESCALEZERO) { if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) { if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) {
m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale); m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale);
m_fX11SurfaceScaledBy = PMONITOR->scale; m_fX11SurfaceScaledBy = PMONITOR->scale;
} }
@@ -1521,7 +1535,7 @@ PHLWINDOW CWindow::getSwallower() {
static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex"); static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex");
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow"); static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
if (!*PSWALLOW || (*PSWALLOWREGEX).empty()) if (!*PSWALLOW || std::string{*PSWALLOWREGEX} == STRVAL_EMPTY || (*PSWALLOWREGEX).empty())
return nullptr; return nullptr;
// check parent // check parent
@@ -1587,3 +1601,29 @@ bool CWindow::isX11OverrideRedirect() {
bool CWindow::isModal() { bool CWindow::isModal() {
return (m_pXWaylandSurface && m_pXWaylandSurface->modal); return (m_pXWaylandSurface && m_pXWaylandSurface->modal);
} }
Vector2D CWindow::requestedMinSize() {
if ((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel))
return Vector2D(1, 1);
Vector2D minSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->min_width, m_pXWaylandSurface->sizeHints->min_height) : m_pXDGSurface->toplevel->layoutMinSize();
minSize = minSize.clamp({1, 1});
return minSize;
}
Vector2D CWindow::requestedMaxSize() {
constexpr int NO_MAX_SIZE_LIMIT = 99999;
if (((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel) || m_sWindowData.noMaxSize.valueOrDefault()))
return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT);
Vector2D maxSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->max_width, m_pXWaylandSurface->sizeHints->max_height) : m_pXDGSurface->toplevel->layoutMaxSize();
if (maxSize.x < 5)
maxSize.x = NO_MAX_SIZE_LIMIT;
if (maxSize.y < 5)
maxSize.y = NO_MAX_SIZE_LIMIT;
return maxSize;
}

View File

@@ -144,6 +144,13 @@ class CWindowOverridableVar {
unset(priority); unset(priority);
} }
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private: private:
std::map<eOverridePriority, T> values; std::map<eOverridePriority, T> values;
T defaultValue; // used for toggling, so required for bool T defaultValue; // used for toggling, so required for bool
@@ -272,12 +279,12 @@ class CWindow {
bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bWasMaximized = false; bool m_bWasMaximized = false;
sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE}; sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
MONITORID m_iMonitorID = -1;
std::string m_szTitle = ""; std::string m_szTitle = "";
std::string m_szClass = ""; std::string m_szClass = "";
std::string m_szInitialTitle = ""; std::string m_szInitialTitle = "";
std::string m_szInitialClass = ""; std::string m_szInitialClass = "";
PHLWORKSPACE m_pWorkspace; PHLWORKSPACE m_pWorkspace;
PHLMONITORREF m_pMonitor;
bool m_bIsMapped = false; bool m_bIsMapped = false;
@@ -357,6 +364,7 @@ class CWindow {
// swallowing // swallowing
PHLWINDOWREF m_pSwallowed; PHLWINDOWREF m_pSwallowed;
bool m_bGroupSwallowed = false;
// focus stuff // focus stuff
bool m_bStayFocused = false; bool m_bStayFocused = false;
@@ -398,7 +406,6 @@ class CWindow {
CBox getFullWindowBoundingBox(); CBox getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents(); SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props); CBox getWindowBoxUnified(uint64_t props);
CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved(); CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco); void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos(); void updateWindowDecos();
@@ -424,24 +431,22 @@ class CWindow {
float rounding(); float rounding();
bool canBeTorn(); bool canBeTorn();
void setSuspended(bool suspend); void setSuspended(bool suspend);
bool visibleOnMonitor(CMonitor* pMonitor); bool visibleOnMonitor(PHLMONITOR pMonitor);
WORKSPACEID workspaceID(); WORKSPACEID workspaceID();
MONITORID monitorID();
bool onSpecialWorkspace(); bool onSpecialWorkspace();
void activate(bool force = false); void activate(bool force = false);
int surfacesCount(); int surfacesCount();
void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
bool isFullscreen(); bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode); bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize(); int getRealBorderSize();
void updateWindowData(); void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&); void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(void* ptr); void onBorderAngleAnimEnd(void* ptr);
bool isInCurvedCorner(double x, double y); bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos); bool hasPopupAt(const Vector2D& pos);
int popupsCount(); int popupsCount();
void applyGroupRules(); void applyGroupRules();
void createGroup(); void createGroup();
void destroyGroup(); void destroyGroup();
@@ -469,6 +474,12 @@ class CWindow {
void unsetWindowData(eOverridePriority priority); void unsetWindowData(eOverridePriority priority);
bool isX11OverrideRedirect(); bool isX11OverrideRedirect();
bool isModal(); bool isModal();
Vector2D requestedMinSize();
Vector2D requestedMaxSize();
inline CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
// listeners // listeners
void onAck(uint32_t serial); void onAck(uint32_t serial);
@@ -555,7 +566,7 @@ struct std::formatter<PHLWINDOW, CharT> : std::formatter<CharT> {
if (formatWorkspace) if (formatWorkspace)
std::format_to(out, ", workspace: {}", w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID); std::format_to(out, ", workspace: {}", w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID);
if (formatMonitor) if (formatMonitor)
std::format_to(out, ", monitor: {}", w->m_iMonitorID); std::format_to(out, ", monitor: {}", w->monitorID());
if (formatClass) if (formatClass)
std::format_to(out, ", class: {}", w->m_szClass); std::format_to(out, ", class: {}", w->m_szClass);
return std::format_to(out, "]"); return std::format_to(out, "]");

View File

@@ -5,14 +5,14 @@
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) { PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) {
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmpty); PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitor, name, special, isEmpty);
workspace->init(workspace); workspace->init(workspace);
return workspace; return workspace;
} }
CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) { CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) {
m_iMonitorID = monitorID; m_pMonitor = monitor;
m_iID = id; m_iID = id;
m_szName = name; m_szName = name;
m_bIsSpecialWorkspace = special; m_bIsSpecialWorkspace = special;
@@ -103,7 +103,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
}); });
if (ANIMSTYLE.starts_with("slidefade")) { if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = m_pMonitor.lock();
float movePerc = 100.f; float movePerc = 100.f;
if (ANIMSTYLE.find("%") != std::string::npos) { if (ANIMSTYLE.find("%") != std::string::npos) {
@@ -151,7 +151,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} }
} else if (ANIMSTYLE == "slidevert") { } else if (ANIMSTYLE == "slidevert") {
// fallback is slide // fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = m_pMonitor.lock();
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. m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
@@ -164,7 +164,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} }
} else { } else {
// fallback is slide // fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = m_pMonitor.lock();
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. m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
@@ -224,7 +224,7 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
m_sPrevWorkspace.id = prev->m_iID; m_sPrevWorkspace.id = prev->m_iID;
m_sPrevWorkspace.name = prev->m_szName; m_sPrevWorkspace.name = prev->m_szName;
if (prev->m_iMonitorID == m_iMonitorID) { if (prev->m_pMonitor == m_pMonitor) {
m_sPrevWorkspacePerMonitor.id = prev->m_iID; m_sPrevWorkspacePerMonitor.id = prev->m_iID;
m_sPrevWorkspacePerMonitor.name = prev->m_szName; m_sPrevWorkspacePerMonitor.name = prev->m_szName;
} }
@@ -347,7 +347,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto PMONITOR = g_pCompositor->getMonitorFromString(prop); const auto PMONITOR = g_pCompositor->getMonitorFromString(prop);
if (!(PMONITOR ? PMONITOR->ID == m_iMonitorID : false)) if (!(PMONITOR ? PMONITOR == m_pMonitor : false))
return false; return false;
continue; continue;
} }
@@ -514,10 +514,14 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
void CWorkspace::markInert() { void CWorkspace::markInert() {
m_bInert = true; m_bInert = true;
m_iID = WORKSPACE_INVALID; m_iID = WORKSPACE_INVALID;
m_iMonitorID = MONITOR_INVALID;
m_bVisible = false; m_bVisible = false;
m_pMonitor.reset();
} }
bool CWorkspace::inert() { bool CWorkspace::inert() {
return m_bInert; return m_bInert;
} }
MONITORID CWorkspace::monitorID() {
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID;
}

View File

@@ -17,16 +17,16 @@ class CWindow;
class CWorkspace { class CWorkspace {
public: public:
static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); static PHLWORKSPACE create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true);
// use create() don't use this // use create() don't use this
CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true);
~CWorkspace(); ~CWorkspace();
// Workspaces ID-based have IDs > 0 // Workspaces ID-based have IDs > 0
// and workspaces name-based have IDs starting with -1337 // and workspaces name-based have IDs starting with -1337
WORKSPACEID m_iID = WORKSPACE_INVALID; WORKSPACEID m_iID = WORKSPACE_INVALID;
std::string m_szName = ""; std::string m_szName = "";
MONITORID m_iMonitorID = MONITOR_INVALID; PHLMONITORREF m_pMonitor;
// Previous workspace ID and name is stored during a workspace change, allowing travel // Previous workspace ID and name is stored during a workspace change, allowing travel
// to the previous workspace. // to the previous workspace.
SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor; SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor;
@@ -68,6 +68,7 @@ class CWorkspace {
void setActive(bool on); void setActive(bool on);
void moveToMonitor(const MONITORID&); void moveToMonitor(const MONITORID&);
MONITORID monitorID();
PHLWINDOW getLastFocusedWindow(); PHLWINDOW getLastFocusedWindow();
void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);

View File

@@ -36,5 +36,5 @@ class IHID {
CSignal destroy; CSignal destroy;
} events; } events;
std::string deviceName; std::string deviceName, hlName;
}; };

View File

@@ -178,13 +178,18 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (xkbState) if (xkbState)
xkb_state_unref(xkbState); xkb_state_unref(xkbState);
if (xkbSymState)
xkb_state_unref(xkbSymState);
xkbState = nullptr; xkbState = nullptr;
xkbStaticState = nullptr; xkbStaticState = nullptr;
xkbSymState = nullptr;
if (keymap) { if (keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
xkbStaticState = xkb_state_new(keymap); xkbStaticState = xkb_state_new(keymap);
xkbState = xkb_state_new(keymap); xkbState = xkb_state_new(keymap);
xkbSymState = xkb_state_new(keymap);
return; return;
} }
@@ -230,6 +235,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkbState = xkb_state_new(KEYMAP); xkbState = xkb_state_new(KEYMAP);
xkbStaticState = xkb_state_new(KEYMAP); xkbStaticState = xkb_state_new(KEYMAP);
xkbSymState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP); xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
@@ -252,6 +258,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkbState = xkb_state_new(NEWKEYMAP); xkbState = xkb_state_new(NEWKEYMAP);
xkbStaticState = xkb_state_new(NEWKEYMAP); xkbStaticState = xkb_state_new(NEWKEYMAP);
xkbSymState = xkb_state_new(NEWKEYMAP);
xkb_keymap_unref(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
@@ -332,6 +339,9 @@ void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t l
xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group); xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group);
if (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, group);
if (!updateModifiersState()) if (!updateModifiersState())
return; return;
@@ -382,6 +392,9 @@ void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
if (updateModifiersState()) { if (updateModifiersState()) {
if (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, modifiersState.group);
keyboardEvents.modifiers.emit(SModifiersEvent{ keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed, .depressed = modifiersState.depressed,
.latched = modifiersState.latched, .latched = modifiersState.latched,

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
@@ -83,7 +82,8 @@ class IKeyboard : public IHID {
bool keymapOverridden = false; bool keymapOverridden = false;
xkb_layout_index_t activeLayout = 0; xkb_layout_index_t activeLayout = 0;
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr; xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr,
*xkbSymState = nullptr /* Same as static but gets layouts */;
xkb_keymap* xkbKeymap = nullptr; xkb_keymap* xkbKeymap = nullptr;
struct { struct {
@@ -94,7 +94,6 @@ class IKeyboard : public IHID {
std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID}; std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID};
uint32_t leds = 0; uint32_t leds = 0;
std::string hlName = "";
std::string xkbFilePath = ""; std::string xkbFilePath = "";
std::string xkbKeymapString = ""; std::string xkbKeymapString = "";
int xkbKeymapFD = -1; int xkbKeymapFD = -1;

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
@@ -105,7 +104,6 @@ class IPointer : public IHID {
CSignal holdEnd; CSignal holdEnd;
} pointerEvents; } pointerEvents;
std::string hlName;
bool connected = false; // means connected to the cursor bool connected = false; // means connected to the cursor
std::string boundOutput = ""; std::string boundOutput = "";

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
@@ -45,7 +44,6 @@ class ITouch : public IHID {
CSignal frame; CSignal frame;
} touchEvents; } touchEvents;
std::string hlName = "";
std::string boundOutput = ""; std::string boundOutput = "";
WP<ITouch> self; WP<ITouch> self;

View File

@@ -197,7 +197,7 @@ CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
}); });
}); });
listeners.attach = pad->events.attach.registerListener([this](std::any d) { listeners.attach = pad->events.attach.registerListener([](std::any d) {
; // TODO: this doesn't do anything in aq atm ; // TODO: this doesn't do anything in aq atm
}); });

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
@@ -93,7 +92,6 @@ class CTablet : public IHID {
WP<CTablet> self; WP<CTablet> self;
bool relativeInput = false; bool relativeInput = false;
std::string hlName = "";
std::string boundOutput = ""; std::string boundOutput = "";
CBox activeArea; CBox activeArea;
CBox boundBox; // output-local CBox boundBox; // output-local
@@ -155,8 +153,6 @@ class CTabletPad : public IHID {
WP<CTabletPad> self; WP<CTabletPad> self;
WP<CTabletTool> parent; WP<CTabletTool> parent;
std::string hlName;
private: private:
CTabletPad(SP<Aquamarine::ITabletPad> pad); CTabletPad(SP<Aquamarine::ITabletPad> pad);
@@ -211,8 +207,6 @@ class CTabletTool : public IHID {
std::vector<uint32_t> buttonsDown; std::vector<uint32_t> buttonsDown;
Vector2D absolutePos; // last known absolute position. Vector2D absolutePos; // last known absolute position.
std::string hlName;
private: private:
CTabletTool(SP<Aquamarine::ITabletTool> tool); CTabletTool(SP<Aquamarine::ITabletTool> tool);

View File

@@ -24,12 +24,4 @@ namespace Events {
DYNLISTENFUNC(requestMaximize); DYNLISTENFUNC(requestMaximize);
DYNLISTENFUNC(setOverrideRedirect); DYNLISTENFUNC(setOverrideRedirect);
DYNLISTENFUNC(ackConfigure); DYNLISTENFUNC(ackConfigure);
// Monitor part 2 the sequel
DYNLISTENFUNC(monitorFrame);
DYNLISTENFUNC(monitorStateRequest);
DYNLISTENFUNC(monitorDamage);
DYNLISTENFUNC(monitorNeedsFrame);
DYNLISTENFUNC(monitorCommit);
DYNLISTENFUNC(monitorBind);
}; };

View File

@@ -1,105 +0,0 @@
#include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "Events.hpp"
#include "../debug/HyprCtl.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/Screencopy.hpp"
#include "../protocols/ToplevelExport.hpp"
#include <aquamarine/output/Output.hpp>
// --------------------------------------------------------- //
// __ __ ____ _ _ _____ _______ ____ _____ _____ //
// | \/ |/ __ \| \ | |_ _|__ __/ __ \| __ \ / ____| //
// | \ / | | | | \| | | | | | | | | | |__) | (___ //
// | |\/| | | | | . ` | | | | | | | | | _ / \___ \ //
// | | | | |__| | |\ |_| |_ | | | |__| | | \ \ ____) | //
// |_| |_|\____/|_| \_|_____| |_| \____/|_| \_\_____/ //
// //
// --------------------------------------------------------- //
void Events::listener_monitorFrame(void* owner, void* data) {
CMonitor* const PMONITOR = (CMonitor*)owner;
if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!");
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
return m->output != g_pCompositor->m_pUnsafeOutput->output;
})) {
// restore from unsafe state
g_pCompositor->leaveUnsafeState();
}
return; // cannot draw on session inactive (different tty)
}
if (!PMONITOR->m_bEnabled)
return;
g_pHyprRenderer->recheckSolitaryForMonitor(PMONITOR);
PMONITOR->tearingState.busy = false;
if (PMONITOR->tearingState.activelyTearing && PMONITOR->solitaryClient.lock() /* can be invalidated by a recheck */) {
if (!PMONITOR->tearingState.frameScheduledWhileBusy)
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
PMONITOR->tearingState.nextRenderTorn = true;
PMONITOR->tearingState.frameScheduledWhileBusy = false;
}
static auto PENABLERAT = CConfigValue<Hyprlang::INT>("misc:render_ahead_of_time");
static auto PRATSAFE = CConfigValue<Hyprlang::INT>("misc:render_ahead_safezone");
PMONITOR->lastPresentationTimer.reset();
if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
if (!PMONITOR->RATScheduled) {
// render
g_pHyprRenderer->renderMonitor(PMONITOR);
}
PMONITOR->RATScheduled = false;
const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR);
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 TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1)
g_pHyprRenderer->renderMonitor(PMONITOR);
else
wl_event_source_timer_update(PMONITOR->renderTimer, TIMETOSLEEP);
} else {
g_pHyprRenderer->renderMonitor(PMONITOR);
}
}
void Events::listener_monitorNeedsFrame(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME);
}
void Events::listener_monitorCommit(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
PROTO::screencopy->onOutputCommit(PMONITOR);
PROTO::toplevelExport->onOutputCommit(PMONITOR);
}
}
void Events::listener_monitorBind(void* owner, void* data) {
;
}

View File

@@ -12,6 +12,7 @@
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/ToplevelExport.hpp" #include "../protocols/ToplevelExport.hpp"
#include "../xwayland/XSurface.hpp" #include "../xwayland/XSurface.hpp"
#include "managers/PointerManager.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
@@ -43,18 +44,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity"); static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity");
static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity"); static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity");
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength"); static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
static auto PSWALLOWREGEX = CConfigValue<std::string>("misc:swallow_regex");
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen"); static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen");
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking"); static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); auto PMONITOR = g_pCompositor->m_pLastMonitor.lock();
if (!g_pCompositor->m_pLastMonitor) { if (!g_pCompositor->m_pLastMonitor) {
g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({})); g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({}));
PMONITOR = g_pCompositor->m_pLastMonitor.get(); PMONITOR = g_pCompositor->m_pLastMonitor.lock();
} }
auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_pMonitor = PMONITOR;
PWINDOW->m_pWorkspace = PWORKSPACE; PWINDOW->m_pWorkspace = PWORKSPACE;
PWINDOW->m_bIsMapped = true; PWINDOW->m_bIsMapped = true;
PWINDOW->m_bReadyToDelete = false; PWINDOW->m_bReadyToDelete = false;
@@ -145,18 +144,18 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' '))); const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' ')));
if (MONITORSTR == "unset") { if (MONITORSTR == "unset") {
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_pMonitor = PMONITOR;
} else { } else {
if (isNumber(MONITORSTR)) { if (isNumber(MONITORSTR)) {
const MONITORID MONITOR = std::stoi(MONITORSTR); const MONITORID MONITOR = std::stoi(MONITORSTR);
if (!g_pCompositor->getMonitorFromID(MONITOR)) if (const auto PM = g_pCompositor->getMonitorFromID(MONITOR); PM)
PWINDOW->m_iMonitorID = 0; PWINDOW->m_pMonitor = PM;
else else
PWINDOW->m_iMonitorID = MONITOR; PWINDOW->m_pMonitor = g_pCompositor->m_vMonitors.at(0);
} else { } else {
const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR); const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR);
if (PMONITOR) if (PMONITOR)
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_pMonitor = PMONITOR;
else { else {
Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR); Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
continue; continue;
@@ -164,10 +163,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
} }
const auto PMONITORFROMID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock();
if (PWINDOW->m_iMonitorID != PMONITOR->ID) { if (PWINDOW->m_pMonitor != PMONITOR) {
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID)); g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID()));
PMONITOR = PMONITORFROMID; PMONITOR = PMONITORFROMID;
} }
PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
@@ -297,23 +296,23 @@ void Events::listener_mapWindow(void* owner, void* data) {
auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID); auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID);
if (!pWorkspace) if (!pWorkspace)
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName); pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->monitorID(), requestedWorkspaceName, false);
PWORKSPACE = pWorkspace; PWORKSPACE = pWorkspace;
PWINDOW->m_pWorkspace = pWorkspace; PWINDOW->m_pWorkspace = pWorkspace;
PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID; PWINDOW->m_pMonitor = pWorkspace->m_pMonitor;
if (g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeSpecialWorkspace && !pWorkspace->m_bIsSpecialWorkspace) if (PWINDOW->m_pMonitor.lock()->activeSpecialWorkspace && !pWorkspace->m_bIsSpecialWorkspace)
workspaceSilent = true; workspaceSilent = true;
if (!workspaceSilent) { if (!workspaceSilent) {
if (pWorkspace->m_bIsSpecialWorkspace) if (pWorkspace->m_bIsSpecialWorkspace)
g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID)->setSpecialWorkspace(pWorkspace); pWorkspace->m_pMonitor->setSpecialWorkspace(pWorkspace);
else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID) else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID)
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName); g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
PMONITOR = g_pCompositor->m_pLastMonitor.get(); PMONITOR = g_pCompositor->m_pLastMonitor.lock();
} }
} else } else
workspaceSilent = false; workspaceSilent = false;
@@ -321,32 +320,43 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->updateWindowData(); PWINDOW->updateWindowData();
// Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped.
const auto SWALLOWER = PWINDOW->getSwallower();
PWINDOW->m_pSwallowed = SWALLOWER;
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
PWINDOW->m_bCreatedOverFullscreen = true; PWINDOW->m_bCreatedOverFullscreen = true;
// size and move rules // size and move rules
for (auto const& r : PWINDOW->m_vMatchedRules) { for (auto const& r : PWINDOW->m_vMatchedRules) {
if (r.szRule.starts_with("size")) { if (r.szRule.starts_with("size")) {
try { try {
auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) {
if (VALUE.starts_with('<'))
return std::min(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
else if (VALUE.starts_with('>'))
return std::max(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
return stringToPercentage(VALUE, REL);
};
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); const auto MAXSIZE = PWINDOW->requestedMaxSize();
const auto SIZEX = SIZEXSTR == "max" ? const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) :
std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) : stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x);
(!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
const auto SIZEY = SIZEYSTR == "max" ? const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) :
std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) : stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y);
(!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
Debug::log(LOG, "Rule size, applying to {}", PWINDOW); Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY); PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY});
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal();
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
PWINDOW->setHidden(false); PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); } } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
@@ -459,14 +469,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); const auto MAXSIZE = PWINDOW->requestedMaxSize();
const auto SIZEX = SIZEXSTR == "max" ? const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x);
std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) :
(!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x); const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : stringToPercentage(SIZEYSTR, PMONITOR->vecSize.y);
const auto SIZEY = SIZEYSTR == "max" ?
std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) :
(!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW); Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW);
@@ -552,20 +559,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(nullptr);
} }
// verify swallowing
if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) {
const auto SWALLOWER = PWINDOW->getSwallower();
if (SWALLOWER) {
// swallow // swallow
PWINDOW->m_pSwallowed = SWALLOWER; if (SWALLOWER) {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER);
g_pHyprRenderer->damageWindow(SWALLOWER);
SWALLOWER->setHidden(true); SWALLOWER->setHidden(true);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
}
} }
PWINDOW->m_bFirstMap = false; PWINDOW->m_bFirstMap = false;
@@ -626,7 +625,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
return; return;
} }
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = PWINDOW->m_pMonitor.lock();
if (PMONITOR) { if (PMONITOR) {
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition; PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value(); PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value();
@@ -647,7 +646,13 @@ void Events::listener_unmapWindow(void* owner, void* data) {
// swallowing // swallowing
if (valid(PWINDOW->m_pSwallowed)) { if (valid(PWINDOW->m_pSwallowed)) {
PWINDOW->m_pSwallowed->setHidden(false); PWINDOW->m_pSwallowed->setHidden(false);
if (PWINDOW->m_sGroupData.pNextWindow.lock())
PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false.
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock()); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock());
PWINDOW->m_pSwallowed->m_bGroupSwallowed = false;
PWINDOW->m_pSwallowed.reset(); PWINDOW->m_pSwallowed.reset();
} }
@@ -672,6 +677,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
g_pHyprRenderer->damageWindow(PWINDOW);
// do this after onWindowRemoved because otherwise it'll think the window is invalid // do this after onWindowRemoved because otherwise it'll think the window is invalid
PWINDOW->m_bIsMapped = false; PWINDOW->m_bIsMapped = false;
@@ -711,8 +718,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pCompositor->addToFadingOutSafe(PWINDOW); g_pCompositor->addToFadingOutSafe(PWINDOW);
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
@@ -748,44 +753,40 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
if (!PWINDOW->m_bIsX11 && !PWINDOW->isFullscreen() && PWINDOW->m_bIsFloating) { if (!PWINDOW->m_bIsX11 && !PWINDOW->isFullscreen() && PWINDOW->m_bIsFloating) {
const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->layoutMinSize();
const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize; const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->layoutMaxSize();
if (MAXSIZE > Vector2D{1, 1}) { PWINDOW->clampWindowSize(MINSIZE, MAXSIZE > Vector2D{1, 1} ? std::optional<Vector2D>{MAXSIZE} : std::nullopt);
const auto REALSIZE = PWINDOW->m_vRealSize.goal();
Vector2D newSize = REALSIZE;
if (MAXSIZE.x < newSize.x)
newSize.x = MAXSIZE.x;
if (MAXSIZE.y < newSize.y)
newSize.y = MAXSIZE.y;
if (MINSIZE.x > newSize.x)
newSize.x = MINSIZE.x;
if (MINSIZE.y > newSize.y)
newSize.y = MINSIZE.y;
const Vector2D DELTA = REALSIZE - newSize;
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0;
PWINDOW->m_vRealSize = newSize;
g_pXWaylandManager->setWindowSize(PWINDOW, newSize);
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
} }
}
if (!PWINDOW->m_pWorkspace->m_bVisible) if (!PWINDOW->m_pWorkspace->m_bVisible)
return; return;
const auto PMONITOR = PWINDOW->m_pMonitor.lock();
if (PMONITOR)
PMONITOR->debugLastPresentation(g_pSeatManager->isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow");
if (g_pSeatManager->isPointerFrameCommit) {
g_pSeatManager->isPointerFrameSkipped = false;
g_pSeatManager->isPointerFrameCommit = false;
} else
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
if (g_pSeatManager->isPointerFrameSkipped) {
g_pPointerManager->sendStoredMovement();
g_pSeatManager->sendPointerFrame();
g_pSeatManager->isPointerFrameCommit = true;
}
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces(); PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
PWINDOW->m_pPopupHead->recheckTree(); PWINDOW->m_pPopupHead->recheckTree();
} }
// tearing: if solitary, redraw it. This still might be a single surface window // tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) { if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()}; CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
@@ -900,7 +901,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size()); PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size());
if (*PXWLFORCESCALEZERO) { if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) { if (const auto PMONITOR = PWINDOW->m_pMonitor.lock(); PMONITOR) {
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale); PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
} }
} }

View File

@@ -0,0 +1,54 @@
#pragma once
#include <type_traits>
#define ULL unsigned long long
#define LD long double
constexpr ULL operator""_kB(const ULL BYTES) {
return BYTES * 1024;
}
constexpr ULL operator""_MB(const ULL BYTES) {
return BYTES * 1024 * 1024;
}
constexpr ULL operator""_GB(const ULL BYTES) {
return BYTES * 1024 * 1024 * 1024;
}
constexpr ULL operator""_TB(const ULL BYTES) {
return BYTES * 1024 * 1024 * 1024 * 1024;
}
constexpr LD operator""_kB(const LD BYTES) {
return BYTES * 1024;
}
constexpr LD operator""_MB(const LD BYTES) {
return BYTES * 1024 * 1024;
}
constexpr LD operator""_GB(const LD BYTES) {
return BYTES * 1024 * 1024 * 1024;
}
constexpr LD operator""_TB(const LD BYTES) {
return BYTES * 1024 * 1024 * 1024 * 1024;
}
template <typename T>
using __acceptable_byte_operation_type = typename std::enable_if<std::is_trivially_constructible<T, ULL>::value || std::is_trivially_constructible<T, LD>::value>::type;
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X kBtoBytes(const X kB) {
return kB * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X MBtoBytes(const X MB) {
return MB * 1024 * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X GBtoBytes(const X GB) {
return GB * 1024 * 1024 * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X TBtoBytes(const X TB) {
return TB * 1024 * 1024 * 1024 * 1024;
}
#undef ULL
#undef LD

View File

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

View File

@@ -302,7 +302,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
// Collect all the workspaces we can't jump to. // Collect all the workspaces we can't jump to.
for (auto const& ws : g_pCompositor->m_vWorkspaces) { for (auto const& ws : g_pCompositor->m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)) { if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor)) {
// Can't jump to this workspace // Can't jump to this workspace
invalidWSes.insert(ws->m_iID); invalidWSes.insert(ws->m_iID);
} }
@@ -320,7 +320,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
// Prepare all named workspaces in case when we need them // Prepare all named workspaces in case when we need them
std::vector<WORKSPACEID> namedWSes; std::vector<WORKSPACEID> namedWSes;
for (auto const& ws : g_pCompositor->m_vWorkspaces) { for (auto const& ws : g_pCompositor->m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0) if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor) || ws->m_iID >= 0)
continue; continue;
namedWSes.push_back(ws->m_iID); namedWSes.push_back(ws->m_iID);
@@ -464,7 +464,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
std::vector<WORKSPACEID> validWSes; std::vector<WORKSPACEID> validWSes;
for (auto const& ws : g_pCompositor->m_vWorkspaces) { for (auto const& ws : g_pCompositor->m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors)) if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor && !onAllMonitors))
continue; continue;
validWSes.push_back(ws->m_iID); validWSes.push_back(ws->m_iID);
@@ -610,7 +610,7 @@ void logSystemInfo() {
Debug::log(NONE, "\n"); Debug::log(NONE, "\n");
#if defined(__DragonFly__) || defined(__FreeBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga"); const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga");
#elif defined(__arm__) || defined(__aarch64__) #elif defined(__arm__) || defined(__aarch64__)
const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible"); const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible");
#else #else
@@ -628,27 +628,6 @@ void logSystemInfo() {
Debug::log(NONE, "{}", execAndGet("cat /etc/os-release")); Debug::log(NONE, "{}", execAndGet("cat /etc/os-release"));
} }
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
memset(mat, 0, sizeof(*mat) * 9);
const float* t = transforms[tr];
float x = 2.0f / w;
float y = 2.0f / h;
// Rotation + reflection
mat[0] = x * t[0];
mat[1] = x * t[1];
mat[3] = y * t[3];
mat[4] = y * t[4];
// Translation
mat[2] = -copysign(1.0f, mat[0] + mat[1]);
mat[5] = -copysign(1.0f, mat[3] + mat[4]);
// Identity
mat[8] = 1.0f;
}
int64_t getPPIDof(int64_t pid) { int64_t getPPIDof(int64_t pid) {
#if defined(KERN_PROC_PID) #if defined(KERN_PROC_PID)
int mib[] = { int mib[] = {
@@ -884,3 +863,10 @@ bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) {
*ro_fd_ptr = ro_fd; *ro_fd_ptr = ro_fd;
return true; return true;
} }
float stringToPercentage(const std::string& VALUE, const float REL) {
if (VALUE.ends_with('%'))
return (std::stof(VALUE.substr(0, VALUE.length() - 1)) * REL) / 100.f;
else
return std::stof(VALUE);
};

View File

@@ -34,13 +34,13 @@ int64_t getPPIDof(int64_t pid);
int64_t configStringToInt(const std::string&); int64_t configStringToInt(const std::string&);
Vector2D configStringToVector2D(const std::string&); Vector2D configStringToVector2D(const std::string&);
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative); std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
double normalizeAngleRad(double ang); double normalizeAngleRad(double ang);
std::vector<SCallstackFrameInfo> getBacktrace(); std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err); void throwError(const std::string& err);
bool envEnabled(const std::string& env); bool envEnabled(const std::string& env);
int allocateSHMFile(size_t len); int allocateSHMFile(size_t len);
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr);
float stringToPercentage(const std::string& VALUE, const float REL);
template <typename... Args> template <typename... Args>
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) { [[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {

View File

@@ -11,17 +11,21 @@
#include "../protocols/DRMLease.hpp" #include "../protocols/DRMLease.hpp"
#include "../protocols/DRMSyncobj.hpp" #include "../protocols/DRMSyncobj.hpp"
#include "../protocols/core/Output.hpp" #include "../protocols/core/Output.hpp"
#include "../protocols/Screencopy.hpp"
#include "../protocols/ToplevelExport.hpp"
#include "../managers/PointerManager.hpp" #include "../managers/PointerManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "sync/SyncTimeline.hpp" #include "sync/SyncTimeline.hpp"
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
#include "debug/Log.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <hyprutils/utils/ScopeGuard.hpp> #include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::Utils; using namespace Hyprutils::Utils;
int ratHandler(void* data) { int ratHandler(void* data) {
g_pHyprRenderer->renderMonitor((CMonitor*)data); g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock());
return 1; return 1;
} }
@@ -35,16 +39,22 @@ CMonitor::~CMonitor() {
} }
void CMonitor::onConnect(bool noRule) { void CMonitor::onConnect(bool noRule) {
CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }};
if (output->supportsExplicit) { if (output->supportsExplicit) {
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
outTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); outTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
} }
listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); }); listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); });
listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); }); listeners.commit = output->events.commit.registerListener([this](std::any d) {
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
PROTO::screencopy->onOutputCommit(self.lock());
PROTO::toplevelExport->onOutputCommit(self.lock());
}
});
listeners.needsFrame = listeners.needsFrame =
output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); }); output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); });
listeners.presented = output->events.present.registerListener([this](std::any d) { listeners.presented = output->events.present.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IOutput::SPresentEvent>(d); auto E = std::any_cast<Aquamarine::IOutput::SPresentEvent>(d);
@@ -61,7 +71,7 @@ void CMonitor::onConnect(bool noRule) {
Debug::log(LOG, "Removing monitor {} from realMonitors", szName); Debug::log(LOG, "Removing monitor {} from realMonitors", szName);
std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP<CMonitor>& el) { return el.get() == this; }); std::erase_if(g_pCompositor->m_vRealMonitors, [&](PHLMONITOR& el) { return el.get() == this; });
}); });
listeners.state = output->events.state.registerListener([this](std::any d) { listeners.state = output->events.state.registerListener([this](std::any d) {
@@ -74,7 +84,7 @@ void CMonitor::onConnect(bool noRule) {
return; return;
Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName); Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName);
g_pHyprRenderer->applyMonitorRule(this, &activeMonitorRule, true); g_pHyprRenderer->applyMonitorRule(self.lock(), &activeMonitorRule, true);
return; return;
} }
@@ -88,7 +98,7 @@ void CMonitor::onConnect(bool noRule) {
SMonitorRule rule = activeMonitorRule; SMonitorRule rule = activeMonitorRule;
rule.resolution = SIZE; rule.resolution = SIZE;
g_pHyprRenderer->applyMonitorRule(this, &rule); g_pHyprRenderer->applyMonitorRule(self.lock(), &rule);
}); });
tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
@@ -114,7 +124,7 @@ void CMonitor::onConnect(bool noRule) {
createdByUser = true; // should be true. WL and Headless backends should be addable / removable createdByUser = true; // should be true. WL and Headless backends should be addable / removable
// get monitor rule that matches // get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this); SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(self.lock());
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { if (monitorRule.disabled) {
@@ -139,7 +149,7 @@ void CMonitor::onConnect(bool noRule) {
return; return;
} }
SP<CMonitor>* thisWrapper = nullptr; PHLMONITOR* thisWrapper = nullptr;
// find the wrap // find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
@@ -161,7 +171,7 @@ void CMonitor::onConnect(bool noRule) {
// set mode, also applies // set mode, also applies
if (!noRule) if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); g_pHyprRenderer->applyMonitorRule(self.lock(), &monitorRule, true);
if (!state.commit()) if (!state.commit())
Debug::log(WARN, "state.commit() failed in CMonitor::onCommit"); Debug::log(WARN, "state.commit() failed in CMonitor::onCommit");
@@ -177,7 +187,7 @@ void CMonitor::onConnect(bool noRule) {
continue; continue;
if (ws->m_szLastMonitor == szName || g_pCompositor->m_vMonitors.size() == 1 /* avoid lost workspaces on recover */) { if (ws->m_szLastMonitor == szName || g_pCompositor->m_vMonitors.size() == 1 /* avoid lost workspaces on recover */) {
g_pCompositor->moveWorkspaceToMonitor(ws, this); g_pCompositor->moveWorkspaceToMonitor(ws, self.lock());
ws->startAnim(true, true, true); ws->startAnim(true, true, true);
ws->m_szLastMonitor = ""; ws->m_szLastMonitor = "";
} }
@@ -194,13 +204,13 @@ void CMonitor::onConnect(bool noRule) {
setMirror(activeMonitorRule.mirrorOf); setMirror(activeMonitorRule.mirrorOf);
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->setActiveMonitor(this); g_pCompositor->setActiveMonitor(self.lock());
g_pHyprRenderer->arrangeLayersForMonitor(ID); g_pHyprRenderer->arrangeLayersForMonitor(ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
// ensure VRR (will enable if necessary) // ensure VRR (will enable if necessary)
g_pConfigManager->ensureVRR(this); g_pConfigManager->ensureVRR(self.lock());
// verify last mon valid // verify last mon valid
bool found = false; bool found = false;
@@ -212,22 +222,29 @@ void CMonitor::onConnect(bool noRule) {
} }
if (!found) if (!found)
g_pCompositor->setActiveMonitor(this); g_pCompositor->setActiveMonitor(self.lock());
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this); renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR); g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR);
PROTO::gamma->applyGammaToState(this); PROTO::gamma->applyGammaToState(self.lock());
events.connect.emit(); events.connect.emit();
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)}); g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)});
EMIT_HOOK_EVENT("monitorAdded", this); EMIT_HOOK_EVENT("monitorAdded", self.lock());
} }
void CMonitor::onDisconnect(bool destroy) { void CMonitor::onDisconnect(bool destroy) {
CScopeGuard x = {[this]() {
if (g_pCompositor->m_bIsShuttingDown)
return;
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", self.lock());
g_pCompositor->arrangeMonitors();
}};
if (renderTimer) { if (renderTimer) {
wl_event_source_remove(renderTimer); wl_event_source_remove(renderTimer);
@@ -242,21 +259,21 @@ void CMonitor::onDisconnect(bool destroy) {
events.disconnect.emit(); events.disconnect.emit();
// Cleanup everything. Move windows back, snap cursor, shit. // Cleanup everything. Move windows back, snap cursor, shit.
CMonitor* BACKUPMON = nullptr; PHLMONITOR BACKUPMON = nullptr;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
if (m.get() != this) { if (m.get() != this) {
BACKUPMON = m.get(); BACKUPMON = m;
break; break;
} }
} }
// remove mirror // remove mirror
if (pMirrorOf) { if (pMirrorOf) {
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; })); pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == self; }));
// unlock software for mirrored monitor // unlock software for mirrored monitor
g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf); g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf.lock());
pMirrorOf = nullptr; pMirrorOf.reset();
} }
if (!mirrors.empty()) { if (!mirrors.empty()) {
@@ -297,10 +314,9 @@ void CMonitor::onDisconnect(bool destroy) {
// move workspaces // move workspaces
std::deque<PHLWORKSPACE> wspToMove; std::deque<PHLWORKSPACE> wspToMove;
for (auto const& w : g_pCompositor->m_vWorkspaces) { for (auto const& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) { if (w->m_pMonitor == self || !w->m_pMonitor)
wspToMove.push_back(w); wspToMove.push_back(w);
} }
}
for (auto const& w : wspToMove) { for (auto const& w : wspToMove) {
w->m_szLastMonitor = szName; w->m_szLastMonitor = szName;
@@ -318,40 +334,38 @@ void CMonitor::onDisconnect(bool destroy) {
activeWorkspace.reset(); activeWorkspace.reset();
output->state->resetExplicitFences(); output->state->resetExplicitFences();
output->state->setAdaptiveSync(false);
output->state->setEnabled(false); output->state->setEnabled(false);
if (!state.commit()) if (!state.commit())
Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect"); Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor.get() == this) if (g_pCompositor->m_pLastMonitor == self)
g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput); g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput.lock());
if (g_pHyprRenderer->m_pMostHzMonitor == this) { if (g_pHyprRenderer->m_pMostHzMonitor == self) {
int mostHz = 0; int mostHz = 0;
CMonitor* pMonitorMostHz = nullptr; PHLMONITOR pMonitorMostHz = nullptr;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
if (m->refreshRate > mostHz && m.get() != this) { if (m->refreshRate > mostHz && m != self) {
pMonitorMostHz = m.get(); pMonitorMostHz = m;
mostHz = m->refreshRate; mostHz = m->refreshRate;
} }
} }
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
} }
std::erase_if(g_pCompositor->m_vMonitors, [&](SP<CMonitor>& el) { return el.get() == this; }); std::erase_if(g_pCompositor->m_vMonitors, [&](PHLMONITOR& el) { return el.get() == this; });
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", this);
} }
void CMonitor::addDamage(const pixman_region32_t* rg) { void CMonitor::addDamage(const pixman_region32_t* rg) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor"); static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) {
damage.damageEntire(); damage.damageEntire();
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} else if (damage.damage(rg)) } else if (damage.damage(rg))
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} }
void CMonitor::addDamage(const CRegion* rg) { void CMonitor::addDamage(const CRegion* rg) {
@@ -360,13 +374,13 @@ void CMonitor::addDamage(const CRegion* rg) {
void CMonitor::addDamage(const CBox* box) { void CMonitor::addDamage(const CBox* box) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor"); static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) {
damage.damageEntire(); damage.damageEntire();
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} }
if (damage.damage(*box)) if (damage.damage(*box))
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} }
bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
@@ -378,7 +392,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
// keep requested minimum refresh rate // keep requested minimum refresh rate
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) {
// damage whole screen because some previous cursor box damages were skipped // damage whole screen because some previous cursor box damages were skipped
damage.damageEntire(); damage.damageEntire();
return false; return false;
@@ -442,7 +456,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
if (PNEWWORKSPACE) { if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor // workspace exists, move it to the newly connected monitor
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this); g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, self.lock());
activeWorkspace = PNEWWORKSPACE; activeWorkspace = PNEWWORKSPACE;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
PNEWWORKSPACE->startAnim(true, true, true); PNEWWORKSPACE->startAnim(true, true, true);
@@ -450,7 +464,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
if (newDefaultWorkspaceName == "") if (newDefaultWorkspaceName == "")
newDefaultWorkspaceName = std::to_string(wsID); newDefaultWorkspaceName = std::to_string(wsID);
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(CWorkspace::create(wsID, ID, newDefaultWorkspaceName)); PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(CWorkspace::create(wsID, self.lock(), newDefaultWorkspaceName));
} }
activeWorkspace = PNEWWORKSPACE; activeWorkspace = PNEWWORKSPACE;
@@ -471,7 +485,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
return; return;
} }
if (PMIRRORMON == this) { if (PMIRRORMON == self) {
Debug::log(ERR, "Cannot mirror self!"); Debug::log(ERR, "Cannot mirror self!");
return; return;
} }
@@ -480,22 +494,22 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
// disable mirroring // disable mirroring
if (pMirrorOf) { if (pMirrorOf) {
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; })); pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == self; }));
// unlock software for mirrored monitor // unlock software for mirrored monitor
g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf); g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf.lock());
} }
pMirrorOf = nullptr; pMirrorOf.reset();
// set rule // set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(*this); const auto RULE = g_pConfigManager->getMonitorRuleFor(self.lock());
vecPosition = RULE.offset; vecPosition = RULE.offset;
// push to mvmonitors // push to mvmonitors
SP<CMonitor>* thisWrapper = nullptr; PHLMONITOR* thisWrapper = nullptr;
// find the wrap // find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
@@ -514,12 +528,12 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
setupDefaultWS(RULE); setupDefaultWS(RULE);
g_pHyprRenderer->applyMonitorRule(this, (SMonitorRule*)&RULE, true); // will apply the offset and stuff g_pHyprRenderer->applyMonitorRule(self.lock(), (SMonitorRule*)&RULE, true); // will apply the offset and stuff
} else { } else {
CMonitor* BACKUPMON = nullptr; PHLMONITOR BACKUPMON = nullptr;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
if (m.get() != this) { if (m.get() != this) {
BACKUPMON = m.get(); BACKUPMON = m;
break; break;
} }
} }
@@ -527,10 +541,9 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
// move all the WS // move all the WS
std::deque<PHLWORKSPACE> wspToMove; std::deque<PHLWORKSPACE> wspToMove;
for (auto const& w : g_pCompositor->m_vWorkspaces) { for (auto const& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID) { if (w->m_pMonitor == self || !w->m_pMonitor)
wspToMove.push_back(w); wspToMove.push_back(w);
} }
}
for (auto const& w : wspToMove) { for (auto const& w : wspToMove) {
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON); g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
@@ -543,14 +556,14 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = PMIRRORMON; pMirrorOf = PMIRRORMON;
pMirrorOf->mirrors.push_back(this); pMirrorOf->mirrors.push_back(self);
// remove from mvmonitors // remove from mvmonitors
std::erase_if(g_pCompositor->m_vMonitors, [&](const auto& other) { return other.get() == this; }); std::erase_if(g_pCompositor->m_vMonitors, [&](const auto& other) { return other == self; });
g_pCompositor->arrangeMonitors(); g_pCompositor->arrangeMonitors();
g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front().get()); g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front());
g_pCompositor->sanityCheckWorkspaces(); g_pCompositor->sanityCheckWorkspaces();
@@ -612,7 +625,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
} }
if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace && if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace &&
!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) { !(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse"); static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
auto pWindow = pWorkspace->getLastFocusedWindow(); auto pWindow = pWorkspace->getLastFocusedWindow();
@@ -640,11 +653,11 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
EMIT_HOOK_EVENT("workspace", pWorkspace); EMIT_HOOK_EVENT("workspace", pWorkspace);
} }
g_pHyprRenderer->damageMonitor(this); g_pHyprRenderer->damageMonitor(self.lock());
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace); g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
g_pConfigManager->ensureVRR(this); g_pConfigManager->ensureVRR(self.lock());
g_pCompositor->updateSuspendedStates(); g_pCompositor->updateSuspendedStates();
@@ -660,7 +673,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
if (activeSpecialWorkspace == pWorkspace) if (activeSpecialWorkspace == pWorkspace)
return; return;
g_pHyprRenderer->damageMonitor(this); g_pHyprRenderer->damageMonitor(self.lock());
if (!pWorkspace) { if (!pWorkspace) {
// remove special if exists // remove special if exists
@@ -673,7 +686,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) { if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) {
if (const auto PLAST = activeWorkspace->getLastFocusedWindow(); PLAST) if (const auto PLAST = activeWorkspace->getLastFocusedWindow(); PLAST)
g_pCompositor->focusWindow(PLAST); g_pCompositor->focusWindow(PLAST);
else else
@@ -682,7 +695,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pCompositor->updateFullscreenFadeOnWorkspace(activeWorkspace); g_pCompositor->updateFullscreenFadeOnWorkspace(activeWorkspace);
g_pConfigManager->ensureVRR(this); g_pConfigManager->ensureVRR(self.lock());
g_pCompositor->updateSuspendedStates(); g_pCompositor->updateSuspendedStates();
@@ -696,7 +709,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
bool animate = true; bool animate = true;
//close if open elsewhere //close if open elsewhere
const auto PMONITORWORKSPACEOWNER = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); const auto PMONITORWORKSPACEOWNER = pWorkspace->m_pMonitor.lock();
if (PMONITORWORKSPACEOWNER->activeSpecialWorkspace == pWorkspace) { if (PMONITORWORKSPACEOWNER->activeSpecialWorkspace == pWorkspace) {
PMONITORWORKSPACEOWNER->activeSpecialWorkspace.reset(); PMONITORWORKSPACEOWNER->activeSpecialWorkspace.reset();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
@@ -709,7 +722,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
} }
// open special // open special
pWorkspace->m_iMonitorID = ID; pWorkspace->m_pMonitor = self;
activeSpecialWorkspace = pWorkspace; activeSpecialWorkspace = pWorkspace;
activeSpecialWorkspace->m_bVisible = true; activeSpecialWorkspace->m_bVisible = true;
if (animate) if (animate)
@@ -717,7 +730,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == pWorkspace) { if (w->m_pWorkspace == pWorkspace) {
w->m_iMonitorID = ID; w->m_pMonitor = self;
w->updateSurfaceScaleTransformDetails(); w->updateSurfaceScaleTransformDetails();
w->setAnimationsToMove(); w->setAnimationsToMove();
@@ -741,7 +754,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) { if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) {
if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST) if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST)
g_pCompositor->focusWindow(PLAST); g_pCompositor->focusWindow(PLAST);
else else
@@ -750,11 +763,11 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
g_pHyprRenderer->damageMonitor(this); g_pHyprRenderer->damageMonitor(self.lock());
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace); g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
g_pConfigManager->ensureVRR(this); g_pConfigManager->ensureVRR(self.lock());
g_pCompositor->updateSuspendedStates(); g_pCompositor->updateSuspendedStates();
} }
@@ -772,12 +785,9 @@ Vector2D CMonitor::middle() {
} }
void CMonitor::updateMatrix() { void CMonitor::updateMatrix() {
matrixIdentity(projMatrix.data()); projMatrix = Mat3x3::identity();
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { if (transform != WL_OUTPUT_TRANSFORM_NORMAL)
matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0); projMatrix.translate(vecPixelSize / 2.0).transform(wlTransformToHyprutils(transform)).translate(-vecTransformedSize / 2.0);
matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform));
matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
}
} }
WORKSPACEID CMonitor::activeWorkspaceID() { WORKSPACEID CMonitor::activeWorkspaceID() {
@@ -792,20 +802,28 @@ CBox CMonitor::logicalBox() {
return {vecPosition, vecSize}; return {vecPosition, vecSize};
} }
static void onDoneSource(void* data) { void CMonitor::scheduleDone() {
auto pMonitor = (CMonitor*)data; if (doneScheduled)
if (!PROTO::outputs.contains(pMonitor->szName))
return; return;
PROTO::outputs.at(pMonitor->szName)->sendDone(); doneScheduled = true;
g_pEventLoopManager->doLater([M = self] {
if (!M) // if M is gone, we got destroyed, doesn't matter.
return;
if (!PROTO::outputs.contains(M->szName))
return;
PROTO::outputs.at(M->szName)->sendDone();
M->doneScheduled = false;
});
} }
void CMonitor::scheduleDone() { void CMonitor::setCTM(const Mat3x3& ctm_) {
if (doneSource) ctm = ctm_;
return; ctmUpdated = true;
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::scheduleFrameReason::AQ_SCHEDULE_NEEDS_FRAME);
doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this);
} }
bool CMonitor::attemptDirectScanout() { bool CMonitor::attemptDirectScanout() {
@@ -826,7 +844,7 @@ bool CMonitor::attemptDirectScanout() {
return false; return false;
// we can't scanout shm buffers. // we can't scanout shm buffers.
if (!PSURFACE->current.buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */) if (!PSURFACE->current.buffer || !PSURFACE->current.buffer->buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
return false; return false;
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get()); Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get());
@@ -922,6 +940,74 @@ bool CMonitor::attemptDirectScanout() {
return true; return true;
} }
void CMonitor::debugLastPresentation(const std::string& message) {
Debug::log(TRACE, "{} (last presentation {} - {} fps)", message, lastPresentationTimer.getMillis(),
lastPresentationTimer.getMillis() > 0 ? 1000.0f / lastPresentationTimer.getMillis() : 0.0f);
}
void CMonitor::onMonitorFrame() {
if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!");
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
return m->output != g_pCompositor->m_pUnsafeOutput->output;
})) {
// restore from unsafe state
g_pCompositor->leaveUnsafeState();
}
return; // cannot draw on session inactive (different tty)
}
if (!m_bEnabled)
return;
g_pHyprRenderer->recheckSolitaryForMonitor(self.lock());
tearingState.busy = false;
if (tearingState.activelyTearing && solitaryClient.lock() /* can be invalidated by a recheck */) {
if (!tearingState.frameScheduledWhileBusy)
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
tearingState.nextRenderTorn = true;
tearingState.frameScheduledWhileBusy = false;
}
static auto PENABLERAT = CConfigValue<Hyprlang::INT>("misc:render_ahead_of_time");
static auto PRATSAFE = CConfigValue<Hyprlang::INT>("misc:render_ahead_safezone");
lastPresentationTimer.reset();
if (*PENABLERAT && !tearingState.nextRenderTorn) {
if (!RATScheduled) {
// render
g_pHyprRenderer->renderMonitor(self.lock());
}
RATScheduled = false;
const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(self.lock());
if (max + *PRATSAFE > 1000.0 / refreshRate)
return;
const auto MSLEFT = 1000.0 / refreshRate - lastPresentationTimer.getMillis();
RATScheduled = true;
const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE);
const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1)
g_pHyprRenderer->renderMonitor(self.lock());
else
wl_event_source_timer_update(renderTimer, TIMETOSLEEP);
} else
g_pHyprRenderer->renderMonitor(self.lock());
}
CMonitorState::CMonitorState(CMonitor* owner) { CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner; m_pOwner = owner;
} }
@@ -953,7 +1039,7 @@ bool CMonitorState::commit() {
if (!updateSwapchain()) if (!updateSwapchain())
return false; return false;
EMIT_HOOK_EVENT("preMonitorCommit", m_pOwner); EMIT_HOOK_EVENT("preMonitorCommit", m_pOwner->self.lock());
ensureBufferPresent(); ensureBufferPresent();

View File

@@ -54,7 +54,7 @@ class CMonitorState {
private: private:
void ensureBufferPresent(); void ensureBufferPresent();
CMonitor* m_pOwner; CMonitor* m_pOwner = nullptr;
}; };
class CMonitor { class CMonitor {
@@ -96,7 +96,7 @@ class CMonitor {
bool scheduledRecalc = false; bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float xwaylandScale = 1.f; float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0}; Mat3x3 projMatrix;
std::optional<Vector2D> forceSize; std::optional<Vector2D> forceSize;
SP<Aquamarine::SOutputMode> currentMode; SP<Aquamarine::SOutputMode> currentMode;
SP<Aquamarine::CSwapchain> cursorSwapchain; SP<Aquamarine::CSwapchain> cursorSwapchain;
@@ -125,11 +125,15 @@ class CMonitor {
SP<CSyncTimeline> outTimeline; SP<CSyncTimeline> outTimeline;
uint64_t commitSeq = 0; uint64_t commitSeq = 0;
WP<CMonitor> self; PHLMONITORREF self;
// mirroring // mirroring
CMonitor* pMirrorOf = nullptr; PHLMONITORREF pMirrorOf;
std::vector<CMonitor*> mirrors; std::vector<PHLMONITORREF> mirrors;
// ctm
Mat3x3 ctm = Mat3x3::identity();
bool ctmUpdated = false;
// for tearing // for tearing
PHLWINDOWREF solitaryClient; PHLWINDOWREF solitaryClient;
@@ -179,6 +183,10 @@ class CMonitor {
CBox logicalBox(); CBox logicalBox();
void scheduleDone(); void scheduleDone();
bool attemptDirectScanout(); bool attemptDirectScanout();
void setCTM(const Mat3x3& ctm);
void debugLastPresentation(const std::string& message);
void onMonitorFrame();
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false; bool m_bRenderingInitPassed = false;
@@ -193,7 +201,7 @@ class CMonitor {
void setupDefaultWS(const SMonitorRule&); void setupDefaultWS(const SMonitorRule&);
WORKSPACEID findAvailableDefaultWS(); WORKSPACEID findAvailableDefaultWS();
wl_event_source* doneSource = nullptr; bool doneScheduled = false;
struct { struct {
CHyprSignalListener frame; CHyprSignalListener frame;

View File

@@ -8,6 +8,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <cstring> #include <cstring>
namespace Systemd { namespace Systemd {

View File

@@ -1,4 +1,5 @@
#include "Timer.hpp" #include "Timer.hpp"
#include <chrono>
void CTimer::reset() { void CTimer::reset() {
m_tpLastReset = std::chrono::steady_clock::now(); m_tpLastReset = std::chrono::steady_clock::now();
@@ -8,8 +9,8 @@ std::chrono::steady_clock::duration CTimer::getDuration() {
return std::chrono::steady_clock::now() - m_tpLastReset; return std::chrono::steady_clock::now() - m_tpLastReset;
} }
long CTimer::getMillis() { float CTimer::getMillis() {
return std::chrono::duration_cast<std::chrono::milliseconds>(getDuration()).count(); return std::chrono::duration_cast<std::chrono::microseconds>(getDuration()).count() / 1000.f;
} }
float CTimer::getSeconds() { float CTimer::getSeconds() {

View File

@@ -6,7 +6,7 @@ class CTimer {
public: public:
void reset(); void reset();
float getSeconds(); float getSeconds();
long getMillis(); float getMillis();
const std::chrono::steady_clock::time_point& chrono() const; const std::chrono::steady_clock::time_point& chrono() const;
private: private:

View File

@@ -18,7 +18,7 @@ class CWLSurfaceResource;
AQUAMARINE_FORWARD(ISwitch); AQUAMARINE_FORWARD(ISwitch);
struct SRenderData { struct SRenderData {
CMonitor* pMonitor; PHLMONITORREF pMonitor;
timespec* when; timespec* when;
double x, y; double x, y;
@@ -68,7 +68,7 @@ struct SSwipeGesture {
int speedPoints = 0; int speedPoints = 0;
int touch_id = 0; int touch_id = 0;
CMonitor* pMonitor = nullptr; PHLMONITORREF pMonitor;
}; };
struct SSwitchDevice { struct SSwitchDevice {

View File

@@ -1,62 +0,0 @@
#include "WLListener.hpp"
#include "MiscFunctions.hpp"
#include <string>
#include "../debug/Log.hpp"
#include "Watchdog.hpp"
void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
if (g_pWatchdog)
g_pWatchdog->startWatching();
try {
pWrap->m_pSelf->emit(data);
} catch (std::exception& e) { Debug::log(ERR, "Listener {} threw or timed out and was killed by Watchdog!!! This is bad. what(): {}", (uintptr_t)listener, e.what()); }
if (g_pWatchdog)
g_pWatchdog->endWatching();
}
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> const& callback, void* pOwner) {
initCallback(pSignal, callback, pOwner);
}
CHyprWLListener::CHyprWLListener() {
m_swWrapper.m_pSelf = this;
m_swWrapper.m_sListener.notify = &handleWrapped;
wl_list_init(&m_swWrapper.m_sListener.link);
}
CHyprWLListener::~CHyprWLListener() {
removeCallback();
}
void CHyprWLListener::removeCallback() {
if (isConnected()) {
Debug::log(LOG, "Callback {:x} -> {:x}, {} removed.", (uintptr_t)&m_pCallback, (uintptr_t)&m_pOwner, m_szAuthor);
wl_list_remove(&m_swWrapper.m_sListener.link);
wl_list_init(&m_swWrapper.m_sListener.link);
}
}
bool CHyprWLListener::isConnected() {
return !wl_list_empty(&m_swWrapper.m_sListener.link);
}
void CHyprWLListener::initCallback(wl_signal* pSignal, std::function<void(void*, void*)> const& callback, void* pOwner, std::string author) {
if (isConnected()) {
Debug::log(ERR, "Tried to connect a listener twice?!");
return;
}
m_pOwner = pOwner;
m_pCallback = callback;
m_szAuthor = author;
addWLSignal(pSignal, &m_swWrapper.m_sListener, pOwner, m_szAuthor);
}
void CHyprWLListener::emit(void* data) {
m_pCallback(m_pOwner, data);
}

View File

@@ -1,39 +0,0 @@
#pragma once
#include <string>
#include <functional>
#include <wayland-server.h>
class CHyprWLListener {
public:
CHyprWLListener(wl_signal*, std::function<void(void*, void*)> const&, void* owner);
CHyprWLListener();
~CHyprWLListener();
CHyprWLListener(const CHyprWLListener&) = delete;
CHyprWLListener(CHyprWLListener&&) = delete;
CHyprWLListener& operator=(const CHyprWLListener&) = delete;
CHyprWLListener& operator=(CHyprWLListener&&) = delete;
void initCallback(wl_signal*, std::function<void(void*, void*)> const&, void* owner, std::string author = "");
void removeCallback();
bool isConnected();
struct SWrapper {
wl_listener m_sListener;
CHyprWLListener* m_pSelf;
};
void emit(void*);
private:
SWrapper m_swWrapper;
void* m_pOwner = nullptr;
std::function<void(void*, void*)> m_pCallback = nullptr;
std::string m_szAuthor = "";
};

View File

@@ -1,6 +1,4 @@
#include "Math.hpp" #include "Math.hpp"
#include <unordered_map>
#include <cstring>
Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) {
switch (t) { switch (t) {
@@ -17,124 +15,6 @@ Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) {
return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL;
} }
void matrixIdentity(float mat[9]) {
static const float identity[9] = {
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
};
memcpy(mat, identity, sizeof(identity));
}
void matrixMultiply(float mat[9], const float a[9], const float b[9]) {
float product[9];
product[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6];
product[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7];
product[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8];
product[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6];
product[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7];
product[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8];
product[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6];
product[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7];
product[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8];
memcpy(mat, product, sizeof(product));
}
void matrixTranspose(float mat[9], const float a[9]) {
float transposition[9] = {
a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8],
};
memcpy(mat, transposition, sizeof(transposition));
}
void matrixTranslate(float mat[9], float x, float y) {
float translate[9] = {
1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f,
};
matrixMultiply(mat, mat, translate);
}
void matrixScale(float mat[9], float x, float y) {
float scale[9] = {
x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f,
};
matrixMultiply(mat, mat, scale);
}
void matrixRotate(float mat[9], float rad) {
float rotate[9] = {
cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f,
};
matrixMultiply(mat, mat, rotate);
}
const std::unordered_map<eTransform, std::array<float, 9>>& getTransforms() {
static std::unordered_map<eTransform, std::array<float, 9>> transforms = {
{HYPRUTILS_TRANSFORM_NORMAL, {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_90, {0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_180, {-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_270, {0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED, {-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED_90, {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED_180, {1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED_270, {0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
};
return transforms;
}
void matrixTransform(float mat[9], eTransform transform) {
matrixMultiply(mat, mat, getTransforms().at(transform).data());
}
void matrixProjection(float mat[9], int width, int height, eTransform transform) {
memset(mat, 0, sizeof(*mat) * 9);
const float* t = getTransforms().at(transform).data();
float x = 2.0f / width;
float y = 2.0f / height;
// Rotation + reflection
mat[0] = x * t[0];
mat[1] = x * t[1];
mat[3] = y * -t[3];
mat[4] = y * -t[4];
// Translation
mat[2] = -copysign(1.0f, mat[0] + mat[1]);
mat[5] = -copysign(1.0f, mat[3] + mat[4]);
// Identity
mat[8] = 1.0f;
}
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]) {
double x = box.x;
double y = box.y;
double width = box.width;
double height = box.height;
matrixIdentity(mat);
matrixTranslate(mat, x, y);
if (rotation != 0) {
matrixTranslate(mat, width / 2, height / 2);
matrixRotate(mat, rotation);
matrixTranslate(mat, -width / 2, -height / 2);
}
matrixScale(mat, width, height);
if (transform != HYPRUTILS_TRANSFORM_NORMAL) {
matrixTranslate(mat, 0.5, 0.5);
matrixTransform(mat, transform);
matrixTranslate(mat, -0.5, -0.5);
}
matrixMultiply(mat, projection, mat);
}
wl_output_transform invertTransform(wl_output_transform tr) { wl_output_transform invertTransform(wl_output_transform tr) {
if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED)) if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED))
tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180); tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180);

View File

@@ -4,17 +4,9 @@
// includes box and vector as well // includes box and vector as well
#include <hyprutils/math/Region.hpp> #include <hyprutils/math/Region.hpp>
#include <hyprutils/math/Mat3x3.hpp>
using namespace Hyprutils::Math; using namespace Hyprutils::Math;
eTransform wlTransformToHyprutils(wl_output_transform t); eTransform wlTransformToHyprutils(wl_output_transform t);
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]);
void matrixProjection(float mat[9], int width, int height, eTransform transform);
void matrixTransform(float mat[9], eTransform transform);
void matrixRotate(float mat[9], float rad);
void matrixScale(float mat[9], float x, float y);
void matrixTranslate(float mat[9], float x, float y);
void matrixTranspose(float mat[9], const float a[9]);
void matrixMultiply(float mat[9], const float a[9], const float b[9]);
void matrixIdentity(float mat[9]);
wl_output_transform invertTransform(wl_output_transform tr); wl_output_transform invertTransform(wl_output_transform tr);

View File

@@ -3,6 +3,9 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::Utils;
CHyprError::CHyprError() { CHyprError::CHyprError() {
m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE); m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE);
m_fFadeOpacity.registerVar(); m_fFadeOpacity.registerVar();
@@ -11,7 +14,7 @@ CHyprError::CHyprError() {
if (!m_bIsCreated) if (!m_bIsCreated)
return; return;
g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor.get()); g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor.lock());
m_bMonitorChanged = true; m_bMonitorChanged = true;
}); });
@@ -44,7 +47,7 @@ void CHyprError::createQueued() {
m_fFadeOpacity.setValueAndWarp(0.f); m_fFadeOpacity.setValueAndWarp(0.f);
m_fFadeOpacity = 1.f; m_fFadeOpacity = 1.f;
const auto PMONITOR = g_pCompositor->m_vMonitors.front().get(); const auto PMONITOR = g_pCompositor->m_vMonitors.front();
const auto SCALE = PMONITOR->scale; const auto SCALE = PMONITOR->scale;
@@ -130,6 +133,8 @@ void CHyprError::createQueued() {
} }
m_szQueued = ""; m_szQueued = "";
m_fLastHeight = yoffset + PAD + 1 - (TOPBAR ? 0 : Y - PAD);
pango_font_description_free(pangoFD); pango_font_description_free(pangoFD);
g_object_unref(layoutText); g_object_unref(layoutText);
@@ -158,6 +163,8 @@ void CHyprError::createQueued() {
m_cQueued = CColor(); m_cQueued = CColor();
g_pHyprRenderer->damageMonitor(PMONITOR); g_pHyprRenderer->damageMonitor(PMONITOR);
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
} }
void CHyprError::draw() { void CHyprError::draw() {
@@ -174,6 +181,11 @@ void CHyprError::draw() {
m_pTexture->destroyTexture(); m_pTexture->destroyTexture();
m_bIsCreated = false; m_bIsCreated = false;
m_szQueued = ""; m_szQueued = "";
for (auto& m : g_pCompositor->m_vMonitors) {
g_pHyprRenderer->arrangeLayersForMonitor(m->ID);
}
return; return;
} else { } else {
m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut"));
@@ -203,3 +215,11 @@ void CHyprError::destroy() {
else else
m_szQueued = ""; m_szQueued = "";
} }
bool CHyprError::active() {
return m_bIsCreated;
}
float CHyprError::height() {
return m_fLastHeight;
}

View File

@@ -15,6 +15,9 @@ class CHyprError {
void draw(); void draw();
void destroy(); void destroy();
bool active();
float height(); // logical
private: private:
void createQueued(); void createQueued();
std::string m_szQueued = ""; std::string m_szQueued = "";
@@ -24,6 +27,7 @@ class CHyprError {
SP<CTexture> m_pTexture; SP<CTexture> m_pTexture;
CAnimatedVariable<float> m_fFadeOpacity; CAnimatedVariable<float> m_fFadeOpacity;
CBox m_bDamageBox = {0, 0, 0, 0}; CBox m_bDamageBox = {0, 0, 0, 0};
float m_fLastHeight = 0.F;
bool m_bMonitorChanged = false; bool m_bMonitorChanged = false;
}; };

View File

@@ -1,7 +1,7 @@
#include "DwindleLayout.hpp" #include "DwindleLayout.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) { void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) {
if (children[0]) { if (children[0]) {
@@ -101,18 +101,17 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
if (pNode->isNode) if (pNode->isNode)
return; return;
CMonitor* PMONITOR = nullptr; PHLMONITOR PMONITOR = nullptr;
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
if (m->activeSpecialWorkspaceID() == pNode->workspaceID) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) {
PMONITOR = m.get(); PMONITOR = m;
break; break;
} }
} }
} else { } else
PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID); PMONITOR = g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_pMonitor.lock();
}
if (!PMONITOR) { if (!PMONITOR) {
Debug::log(ERR, "Orphaned Node {}!!", pNode); Debug::log(ERR, "Orphaned Node {}!!", pNode);
@@ -142,7 +141,6 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->unsetWindowData(PRIORITY_LAYOUT);
PWINDOW->updateWindowData(); PWINDOW->updateWindowData();
static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("dwindle:no_gaps_when_only");
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in"); static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out"); static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
auto* const PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); auto* const PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData();
@@ -156,27 +154,6 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
PWINDOW->m_vSize = nodeBox.size(); PWINDOW->m_vSize = nodeBox.size();
PWINDOW->m_vPosition = nodeBox.pos(); PWINDOW->m_vPosition = nodeBox.pos();
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->workspaceID());
if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (NODESONWORKSPACE == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) {
PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT);
PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->updateWindowDecos();
const auto RESERVED = PWINDOW->getFullWindowReservedArea();
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft;
PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
return;
}
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
auto calcPos = PWINDOW->m_vPosition; auto calcPos = PWINDOW->m_vPosition;
@@ -257,7 +234,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
m_lDwindleNodesData.push_back(SDwindleNodeData()); m_lDwindleNodesData.push_back(SDwindleNodeData());
const auto PNODE = &m_lDwindleNodesData.back(); const auto PNODE = &m_lDwindleNodesData.back();
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = pWindow->m_pMonitor.lock();
static auto PUSEACTIVE = CConfigValue<Hyprlang::INT>("dwindle:use_active_for_splits"); static auto PUSEACTIVE = CConfigValue<Hyprlang::INT>("dwindle:use_active_for_splits");
static auto PDEFAULTSPLIT = CConfigValue<Hyprlang::FLOAT>("dwindle:default_split_ratio"); static auto PDEFAULTSPLIT = CConfigValue<Hyprlang::FLOAT>("dwindle:default_split_ratio");
@@ -306,7 +283,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
// first, check if OPENINGON isn't too big. // first, check if OPENINGON isn't too big.
const auto PREDSIZEMAX = OPENINGON ? Vector2D(OPENINGON->box.w, OPENINGON->box.h) : PMONITOR->vecSize; const auto PREDSIZEMAX = OPENINGON ? Vector2D(OPENINGON->box.w, OPENINGON->box.h) : PMONITOR->vecSize;
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) { if (const auto MAXSIZE = pWindow->requestedMaxSize(); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) {
// we can't continue. make it floating. // we can't continue. make it floating.
pWindow->m_bIsFloating = true; pWindow->m_bIsFloating = true;
m_lDwindleNodesData.remove(*PNODE); m_lDwindleNodesData.remove(*PNODE);
@@ -330,36 +307,10 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
applyNodeDataToWindow(PNODE); applyNodeDataToWindow(PNODE);
pWindow->applyGroupRules();
return; return;
} }
if (!m_vOverrideFocalPoint && g_pInputManager->m_bWasDraggingWindow) { // get the node under our cursor
if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow))
return;
}
// if it's a group, add the window
if (OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow.lock()) && !m_vOverrideFocalPoint) { // we are not moving window
m_lDwindleNodesData.remove(*PNODE);
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return;
}
// If it's not, get the node under our cursor
m_lDwindleNodesData.push_back(SDwindleNodeData()); m_lDwindleNodesData.push_back(SDwindleNodeData());
const auto NEWPARENT = &m_lDwindleNodesData.back(); const auto NEWPARENT = &m_lDwindleNodesData.back();
@@ -459,6 +410,12 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
} }
} }
// split in favor of a specific window
const auto first = NEWPARENT->children[0];
static auto PSPLITBIAS = CConfigValue<Hyprlang::INT>("dwindle:split_bias");
if ((*PSPLITBIAS == 1 && first == PNODE) || (*PSPLITBIAS == 2 && first == OPENINGON))
NEWPARENT->splitRatio = 2.f - NEWPARENT->splitRatio;
// and update the previous parent if it exists // and update the previous parent if it exists
if (OPENINGON->pParent) { if (OPENINGON->pParent) {
if (OPENINGON->pParent->children[0] == OPENINGON) { if (OPENINGON->pParent->children[0] == OPENINGON) {
@@ -484,9 +441,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride); NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride);
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->monitorID());
pWindow->applyGroupRules();
} }
void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
@@ -552,7 +507,7 @@ void CHyprDwindleLayout::recalculateMonitor(const MONITORID& monid) {
} }
void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) { void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); const auto PMONITOR = pWorkspace->m_pMonitor.lock();
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -608,7 +563,9 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
const auto PNODE = getNodeFromWindow(PWINDOW); const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) { if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goal() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goal() + pixResize).y, 20.0)); PWINDOW->m_vRealSize =
(PWINDOW->m_vRealSize.goal() + pixResize)
.clamp(PWINDOW->m_sWindowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), PWINDOW->m_sWindowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY}));
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
return; return;
} }
@@ -617,7 +574,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("dwindle:smart_resizing"); static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("dwindle:smart_resizing");
// get some data about our window // get some data about our window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = PWINDOW->m_pMonitor.lock();
const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x); const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool DISPLAYRIGHT = STICKS(PWINDOW->m_vPosition.x + PWINDOW->m_vSize.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x); const bool DISPLAYRIGHT = STICKS(PWINDOW->m_vPosition.x + PWINDOW->m_vSize.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(PWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y); const bool DISPLAYTOP = STICKS(PWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
@@ -790,7 +747,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
} }
void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) { void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = pWindow->m_pMonitor.lock();
const auto PWORKSPACE = pWindow->m_pWorkspace; const auto PWORKSPACE = pWindow->m_pWorkspace;
// save position and size if floating // save position and size if floating
@@ -900,9 +857,9 @@ void CHyprDwindleLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir,
const auto PMONITORFOCAL = g_pCompositor->getMonitorFromVector(focalPoint); const auto PMONITORFOCAL = g_pCompositor->getMonitorFromVector(focalPoint);
if (PMONITORFOCAL->ID != pWindow->m_iMonitorID) { if (PMONITORFOCAL != pWindow->m_pMonitor) {
pWindow->moveToWorkspace(PMONITORFOCAL->activeWorkspace); pWindow->moveToWorkspace(PMONITORFOCAL->activeWorkspace);
pWindow->m_iMonitorID = PMONITORFOCAL->ID; pWindow->m_pMonitor = PMONITORFOCAL;
} }
onWindowCreatedTiling(pWindow); onWindowCreatedTiling(pWindow);
@@ -940,7 +897,7 @@ void CHyprDwindleLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) {
PNODE->pWindow = pWindow2; PNODE->pWindow = pWindow2;
if (PNODE->workspaceID != PNODE2->workspaceID) { if (PNODE->workspaceID != PNODE2->workspaceID) {
std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID); std::swap(pWindow2->m_pMonitor, pWindow->m_pMonitor);
std::swap(pWindow2->m_pWorkspace, pWindow->m_pWorkspace); std::swap(pWindow2->m_pWorkspace, pWindow->m_pWorkspace);
} }
@@ -992,6 +949,10 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str
toggleSplit(header.pWindow); toggleSplit(header.pWindow);
} else if (ARGS[0] == "swapsplit") { } else if (ARGS[0] == "swapsplit") {
swapSplit(header.pWindow); swapSplit(header.pWindow);
} else if (ARGS[0] == "movetoroot") {
const auto WINDOW = ARGS[1].empty() ? header.pWindow : g_pCompositor->getWindowByRegex(ARGS[1]);
const auto STABLE = ARGS[2].empty() || ARGS[2] != "unstable";
moveToRoot(WINDOW, STABLE);
} else if (ARGS[0] == "preselect") { } else if (ARGS[0] == "preselect") {
std::string direction = ARGS[1]; std::string direction = ARGS[1];
@@ -1059,6 +1020,44 @@ void CHyprDwindleLayout::swapSplit(PHLWINDOW pWindow) {
PNODE->pParent->recalcSizePosRecursive(); PNODE->pParent->recalcSizePosRecursive();
} }
// goal: maximize the chosen window within current dwindle layout
// impl: swap the selected window with the other sub-tree below root
void CHyprDwindleLayout::moveToRoot(PHLWINDOW pWindow, bool stable) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE || !PNODE->pParent)
return;
if (pWindow->isFullscreen())
return;
// already at root
if (!PNODE->pParent->pParent)
return;
auto& pNode = PNODE->pParent->children[0] == PNODE ? PNODE->pParent->children[0] : PNODE->pParent->children[1];
// instead of [getMasterNodeOnWorkspace], we walk back to root since we need
// to know which children of root is our ancestor
auto pAncestor = PNODE, pRoot = PNODE->pParent;
while (pRoot->pParent) {
pAncestor = pRoot;
pRoot = pRoot->pParent;
}
auto& pSwap = pRoot->children[0] == pAncestor ? pRoot->children[1] : pRoot->children[0];
std::swap(pNode, pSwap);
std::swap(pNode->pParent, pSwap->pParent);
// [stable] in that the focused window occupies same side of screen
if (stable)
std::swap(pRoot->children[0], pRoot->children[1]);
// if the workspace is visible, recalculate layout
if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace))
pRoot->recalcSizePosRecursive();
}
void CHyprDwindleLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) { void CHyprDwindleLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) {
const auto PNODE = getNodeFromWindow(from); const auto PNODE = getNodeFromWindow(from);

View File

@@ -87,6 +87,7 @@ class CHyprDwindleLayout : public IHyprLayout {
void toggleSplit(PHLWINDOW); void toggleSplit(PHLWINDOW);
void swapSplit(PHLWINDOW); void swapSplit(PHLWINDOW);
void moveToRoot(PHLWINDOW, bool stable = true);
eDirection overrideDirection = DIRECTION_DEFAULT; eDirection overrideDirection = DIRECTION_DEFAULT;

View File

@@ -9,24 +9,29 @@
#include "../xwayland/XSurface.hpp" #include "../xwayland/XSurface.hpp"
void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) {
onWindowCreatedFloating(pWindow);
} else {
CBox desiredGeometry = {}; CBox desiredGeometry = {};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = pWindow->m_pMonitor.lock();
pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f; pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f;
} else { } else
pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height); pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
}
pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize; pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize;
if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows
pWindow->applyGroupRules();
bool autoGrouped = IHyprLayout::onWindowCreatedAutoGroup(pWindow);
if (autoGrouped)
return;
if (pWindow->m_bIsFloating)
onWindowCreatedFloating(pWindow);
else
onWindowCreatedTiling(pWindow, direction); onWindowCreatedTiling(pWindow, direction);
} }
}
void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) { void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) {
if (pWindow->isFullscreen()) if (pWindow->isFullscreen())
@@ -83,7 +88,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
CBox desiredGeometry = {0}; CBox desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = pWindow->m_pMonitor.lock();
if (pWindow->m_bIsX11) { if (pWindow->m_bIsX11) {
Vector2D xy = {desiredGeometry.x, desiredGeometry.y}; Vector2D xy = {desiredGeometry.x, desiredGeometry.y};
@@ -178,6 +183,40 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
} }
} }
bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) {
static auto PAUTOGROUP = CConfigValue<Hyprlang::INT>("group:auto_group");
const PHLWINDOW OPENINGON = g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ?
g_pCompositor->m_pLastWindow.lock() :
g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID());
const bool FLOATEDINTOTILED = pWindow->m_bIsFloating && !OPENINGON->m_bIsFloating;
const bool SWALLOWING = pWindow->m_pSwallowed || pWindow->m_bGroupSwallowed;
if ((*PAUTOGROUP || SWALLOWING) // continue if auto_group is enabled or if dealing with window swallowing.
&& OPENINGON // this shouldn't be 0, but honestly, better safe than sorry.
&& OPENINGON != pWindow // prevent freeze when the "group set" window rule makes the new window to be already a group.
&& OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group.
&& pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON.
&& !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !FLOATEDINTOTILED.
&& !FLOATEDINTOTILED) { // don't group a new floated window into a tiled group (for convenience).
pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state. Needed to autogroup a new tiled window into a floated group.
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->setGroupCurrent(pWindow);
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return true;
}
return false;
}
void IHyprLayout::onBeginDragWindow() { void IHyprLayout::onBeginDragWindow() {
const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock(); const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock();
@@ -291,21 +330,37 @@ void IHyprLayout::onEndDragWindow() {
g_pInputManager->currentlyDraggedWindow.reset(); g_pInputManager->currentlyDraggedWindow.reset();
g_pInputManager->m_bWasDraggingWindow = true; g_pInputManager->m_bWasDraggingWindow = true;
if (DRAGGINGWINDOW->m_bDraggingTiled) { if (g_pInputManager->dragMode == MBIND_MOVE) {
DRAGGINGWINDOW->m_bIsFloating = false;
g_pInputManager->refocus();
changeWindowFloatingMode(DRAGGINGWINDOW);
DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize;
} else if (g_pInputManager->dragMode == MBIND_MOVE) {
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
PHLWINDOW pWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING | FLOATING_ONLY, DRAGGINGWINDOW); PHLWINDOW pWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING, DRAGGINGWINDOW);
if (pWindow) { if (pWindow) {
if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW)) if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW))
return; return;
if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) { const bool FLOATEDINTOTILED = !pWindow->m_bIsFloating && !DRAGGINGWINDOW->m_bDraggingTiled;
static auto PDRAGINTOGROUP = CConfigValue<Hyprlang::INT>("group:drag_into_group");
if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow) && *PDRAGINTOGROUP == 1 && !FLOATEDINTOTILED) {
if (DRAGGINGWINDOW->m_sGroupData.pNextWindow) {
PHLWINDOW next = DRAGGINGWINDOW->m_sGroupData.pNextWindow.lock();
while (next != DRAGGINGWINDOW) {
next->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of group members
next->m_vRealSize = pWindow->m_vRealSize.goal(); // match the size of group members
next->m_vRealPosition = pWindow->m_vRealPosition.goal(); // match the position of group members
next = next->m_sGroupData.pNextWindow.lock();
}
}
DRAGGINGWINDOW->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of the window
DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize;
DRAGGINGWINDOW->m_bDraggingTiled = false;
if (pWindow->m_bIsFloating)
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, pWindow->m_vRealSize.goal()); // match the size of the window
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current"); static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
pWindow->setGroupCurrent(DRAGGINGWINDOW); pWindow->setGroupCurrent(DRAGGINGWINDOW);
@@ -317,12 +372,159 @@ void IHyprLayout::onEndDragWindow() {
} }
} }
if (DRAGGINGWINDOW->m_bDraggingTiled) {
DRAGGINGWINDOW->m_bIsFloating = false;
g_pInputManager->refocus();
changeWindowFloatingMode(DRAGGINGWINDOW);
DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize;
}
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
g_pCompositor->focusWindow(DRAGGINGWINDOW); g_pCompositor->focusWindow(DRAGGINGWINDOW);
g_pInputManager->m_bWasDraggingWindow = false; g_pInputManager->m_bWasDraggingWindow = false;
} }
static inline bool canSnap(const double SIDEA, const double SIDEB, const double GAP) {
return std::abs(SIDEA - SIDEB) < GAP;
}
static void snapMove(double& start, double& end, const double P) {
end = P + (end - start);
start = P;
}
static void snapResize(double& start, double& end, const double P) {
start = P;
}
typedef std::function<void(double&, double&, const double)> SnapFn;
static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRAGGINGWINDOW, const eMouseBindMode MODE, const int CORNER, const Vector2D& BEGINSIZE) {
static auto SNAPWINDOWGAP = CConfigValue<Hyprlang::INT>("general:snap:window_gap");
static auto SNAPMONITORGAP = CConfigValue<Hyprlang::INT>("general:snap:monitor_gap");
static auto SNAPBORDEROVERLAP = CConfigValue<Hyprlang::INT>("general:snap:border_overlap");
const SnapFn SNAP = (MODE == MBIND_MOVE) ? snapMove : snapResize;
int snaps = 0;
const bool OVERLAP = *SNAPBORDEROVERLAP;
const int DRAGGINGBORDERSIZE = DRAGGINGWINDOW->getRealBorderSize();
struct SRange {
double start = 0;
double end = 0;
};
SRange sourceX = {sourcePos.x, sourcePos.x + sourceSize.x};
SRange sourceY = {sourcePos.y, sourcePos.y + sourceSize.y};
if (*SNAPWINDOWGAP) {
const double GAPSIZE = *SNAPWINDOWGAP;
const auto WSID = DRAGGINGWINDOW->workspaceID();
for (auto& other : g_pCompositor->m_vWindows) {
if (other == DRAGGINGWINDOW || other->workspaceID() != WSID || !other->m_bIsMapped || other->m_bFadingOut || other->isX11OverrideRedirect())
continue;
const int OTHERBORDERSIZE = other->getRealBorderSize();
const double BORDERSIZE = OVERLAP ? std::max(DRAGGINGBORDERSIZE, OTHERBORDERSIZE) : (DRAGGINGBORDERSIZE + OTHERBORDERSIZE);
const CBox SURF = other->getWindowMainSurfaceBox();
const SRange SURFBX = {SURF.x - BORDERSIZE, SURF.x + SURF.w + BORDERSIZE};
const SRange SURFBY = {SURF.y - BORDERSIZE, SURF.y + SURF.h + BORDERSIZE};
// only snap windows if their ranges overlap in the opposite axis
if (sourceY.start <= SURFBY.end && SURFBY.start <= sourceY.end) {
if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceX.start, SURFBX.end, GAPSIZE)) {
SNAP(sourceX.start, sourceX.end, SURFBX.end);
snaps |= SNAP_LEFT;
} else if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(sourceX.end, SURFBX.start, GAPSIZE)) {
SNAP(sourceX.end, sourceX.start, SURFBX.start);
snaps |= SNAP_RIGHT;
}
}
if (sourceX.start <= SURFBX.end && SURFBX.start <= sourceX.end) {
if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceY.start, SURFBY.end, GAPSIZE)) {
SNAP(sourceY.start, sourceY.end, SURFBY.end);
snaps |= SNAP_UP;
} else if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(sourceY.end, SURFBY.start, GAPSIZE)) {
SNAP(sourceY.end, sourceY.start, SURFBY.start);
snaps |= SNAP_DOWN;
}
}
// corner snapping
const double BORDERDIFF = OTHERBORDERSIZE - DRAGGINGBORDERSIZE;
if (sourceX.start == SURFBX.end || SURFBX.start == sourceX.end) {
const SRange SURFY = {SURF.y - BORDERDIFF, SURF.y + SURF.h + BORDERDIFF};
if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceY.start, SURFY.start, GAPSIZE)) {
SNAP(sourceY.start, sourceY.end, SURFY.start);
snaps |= SNAP_UP;
} else if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(sourceY.end, SURFY.end, GAPSIZE)) {
SNAP(sourceY.end, sourceY.start, SURFY.end);
snaps |= SNAP_DOWN;
}
}
if (sourceY.start == SURFBY.end || SURFBY.start == sourceY.end) {
const SRange SURFX = {SURF.x - BORDERDIFF, SURF.x + SURF.w + BORDERDIFF};
if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceX.start, SURFX.start, GAPSIZE)) {
SNAP(sourceX.start, sourceX.end, SURFX.start);
snaps |= SNAP_LEFT;
} else if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(sourceX.end, SURFX.end, GAPSIZE)) {
SNAP(sourceX.end, sourceX.start, SURFX.end);
snaps |= SNAP_RIGHT;
}
}
}
}
if (*SNAPMONITORGAP) {
const double GAPSIZE = *SNAPMONITORGAP;
const double BORDERSIZE = OVERLAP ? 0 : DRAGGINGBORDERSIZE;
const double BORDERDIFF = DRAGGINGBORDERSIZE - BORDERSIZE;
const auto MON = DRAGGINGWINDOW->m_pMonitor.lock();
SRange monX = {MON->vecPosition.x + BORDERSIZE, MON->vecSize.x - BORDERSIZE};
SRange monY = {MON->vecPosition.y + BORDERSIZE, MON->vecSize.y - BORDERSIZE};
if (canSnap(sourceX.start, monX.start, GAPSIZE) || canSnap(sourceX.start, (monX.start += MON->vecReservedTopLeft.x + BORDERDIFF), GAPSIZE)) {
SNAP(sourceX.start, sourceX.end, monX.start);
snaps |= SNAP_LEFT;
}
if (canSnap(sourceX.end, monX.end, GAPSIZE) || canSnap(sourceX.end, (monX.end -= MON->vecReservedBottomRight.x + BORDERDIFF), GAPSIZE)) {
SNAP(sourceX.end, sourceX.start, monX.end);
snaps |= SNAP_RIGHT;
}
if (canSnap(sourceY.start, monY.start, GAPSIZE) || canSnap(sourceY.start, (monY.start += MON->vecReservedTopLeft.y + BORDERDIFF), GAPSIZE)) {
SNAP(sourceY.start, sourceY.end, monY.start);
snaps |= SNAP_UP;
}
if (canSnap(sourceY.end, monY.end, GAPSIZE) || canSnap(sourceY.end, (monY.end -= MON->vecReservedBottomRight.y + BORDERDIFF), GAPSIZE)) {
SNAP(sourceY.end, sourceY.start, monY.end);
snaps |= SNAP_DOWN;
}
}
if (MODE == MBIND_RESIZE_FORCE_RATIO) {
if ((CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && snaps & SNAP_LEFT) || (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && snaps & SNAP_RIGHT)) {
const double SIZEY = (sourceX.end - sourceX.start) * (BEGINSIZE.y / BEGINSIZE.x);
if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT))
sourceY.start = sourceY.end - SIZEY;
else
sourceY.end = sourceY.start + SIZEY;
} else if ((CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && snaps & SNAP_UP) || (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && snaps & SNAP_DOWN)) {
const double SIZEX = (sourceY.end - sourceY.start) * (BEGINSIZE.x / BEGINSIZE.y);
if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT))
sourceX.start = sourceX.end - SIZEX;
else
sourceX.end = sourceX.start + SIZEX;
}
}
sourcePos = {sourceX.start, sourceY.start};
sourceSize = {sourceX.end - sourceX.start, sourceY.end - sourceY.start};
}
void IHyprLayout::onMouseMove(const Vector2D& mousePos) { void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (g_pInputManager->currentlyDraggedWindow.expired()) if (g_pInputManager->currentlyDraggedWindow.expired())
return; return;
@@ -345,6 +547,8 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
static auto PANIMATEMOUSE = CConfigValue<Hyprlang::INT>("misc:animate_mouse_windowdragging"); static auto PANIMATEMOUSE = CConfigValue<Hyprlang::INT>("misc:animate_mouse_windowdragging");
static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes"); static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
static auto SNAPENABLED = CConfigValue<Hyprlang::INT>("general:snap:enabled");
const auto TIMERDELTA = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count(); const auto TIMERDELTA = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count();
const auto MSDELTA = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - MSTIMER).count(); const auto MSDELTA = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - MSTIMER).count();
const auto MSMONITOR = 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate; const auto MSMONITOR = 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate;
@@ -375,7 +579,13 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (g_pInputManager->dragMode == MBIND_MOVE) { if (g_pInputManager->dragMode == MBIND_MOVE) {
CBox wb = {m_vBeginDragPositionXY + DELTA, DRAGGINGWINDOW->m_vRealSize.goal()}; Vector2D newPos = m_vBeginDragPositionXY + DELTA;
Vector2D newSize = DRAGGINGWINDOW->m_vRealSize.goal();
if (*SNAPENABLED && !DRAGGINGWINDOW->m_bDraggingTiled)
performSnap(newPos, newSize, DRAGGINGWINDOW, MBIND_MOVE, -1, m_vBeginDragSizeXY);
CBox wb = {newPos, newSize};
wb.round(); wb.round();
if (*PANIMATEMOUSE) if (*PANIMATEMOUSE)
@@ -387,12 +597,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
} else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) {
if (DRAGGINGWINDOW->m_bIsFloating) { if (DRAGGINGWINDOW->m_bIsFloating) {
Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sWindowData.minSize.valueOr(Vector2D(20, 20))); Vector2D MINSIZE = DRAGGINGWINDOW->requestedMinSize().clamp(DRAGGINGWINDOW->m_sWindowData.minSize.valueOr(Vector2D(20, 20)));
Vector2D MAXSIZE; Vector2D MAXSIZE;
if (DRAGGINGWINDOW->m_sWindowData.maxSize.hasValue()) if (DRAGGINGWINDOW->m_sWindowData.maxSize.hasValue())
MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, DRAGGINGWINDOW->m_sWindowData.maxSize.value()); MAXSIZE = DRAGGINGWINDOW->requestedMaxSize().clamp({}, DRAGGINGWINDOW->m_sWindowData.maxSize.value());
else else
MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max())); MAXSIZE = DRAGGINGWINDOW->requestedMaxSize().clamp({}, Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max()));
Vector2D newSize = m_vBeginDragSizeXY; Vector2D newSize = m_vBeginDragSizeXY;
Vector2D newPos = m_vBeginDragPositionXY; Vector2D newPos = m_vBeginDragPositionXY;
@@ -406,9 +616,11 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT)
newSize = newSize + Vector2D(-DELTA.x, DELTA.y); newSize = newSize + Vector2D(-DELTA.x, DELTA.y);
if ((m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1) && eMouseBindMode mode = g_pInputManager->dragMode;
(g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || if (DRAGGINGWINDOW->m_sWindowData.keepAspectRatio.valueOrDefault() && mode != MBIND_RESIZE_BLOCK_RATIO)
(!(g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) && DRAGGINGWINDOW->m_sWindowData.keepAspectRatio.valueOrDefault()))) { mode = MBIND_RESIZE_FORCE_RATIO;
if (m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1 && mode == MBIND_RESIZE_FORCE_RATIO) {
const float RATIO = m_vBeginDragSizeXY.y / m_vBeginDragSizeXY.x; const float RATIO = m_vBeginDragSizeXY.y / m_vBeginDragSizeXY.x;
@@ -437,6 +649,11 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT)
newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0.0); newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0.0);
if (*SNAPENABLED) {
performSnap(newPos, newSize, DRAGGINGWINDOW, mode, m_eGrabbedCorner, m_vBeginDragSizeXY);
newSize = newSize.clamp(MINSIZE, MAXSIZE);
}
CBox wb = {newPos, newSize}; CBox wb = {newPos, newSize};
wb.round(); wb.round();
@@ -461,7 +678,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle); const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle);
if (PMONITOR && !SPECIAL) { if (PMONITOR && !SPECIAL) {
DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID; DRAGGINGWINDOW->m_pMonitor = PMONITOR;
DRAGGINGWINDOW->moveToWorkspace(PMONITOR->activeWorkspace); DRAGGINGWINDOW->moveToWorkspace(PMONITOR->activeWorkspace);
DRAGGINGWINDOW->updateGroupOutputs(); DRAGGINGWINDOW->updateGroupOutputs();
@@ -490,7 +707,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
if (!TILED) { if (!TILED) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f); const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID; pWindow->m_pMonitor = PNEWMON;
pWindow->moveToWorkspace(PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace); pWindow->moveToWorkspace(PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace);
pWindow->updateGroupOutputs(); pWindow->updateGroupOutputs();
@@ -518,7 +735,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
pWindow->m_vRealSize.setValue(PSAVEDSIZE); pWindow->m_vRealSize.setValue(PSAVEDSIZE);
// fix pseudo leaving artifacts // fix pseudo leaving artifacts
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); g_pHyprRenderer->damageMonitor(pWindow->m_pMonitor.lock());
if (pWindow == g_pCompositor->m_pLastWindow) if (pWindow == g_pCompositor->m_pLastWindow)
m_pLastTiledWindow = pWindow; m_pLastTiledWindow = pWindow;
@@ -541,7 +758,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
pWindow->m_vSize = wb.pos(); pWindow->m_vSize = wb.pos();
pWindow->m_vPosition = wb.size(); pWindow->m_vPosition = wb.size();
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); g_pHyprRenderer->damageMonitor(pWindow->m_pMonitor.lock());
pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->unsetWindowData(PRIORITY_LAYOUT);
pWindow->updateWindowData(); pWindow->updateWindowData();
@@ -631,7 +848,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) {
pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID());
if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus || if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus ||
pWindowCandidate->isX11OverrideRedirect() || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) pWindowCandidate->isX11OverrideRedirect() || pWindowCandidate->m_pMonitor != g_pCompositor->m_pLastMonitor)
return nullptr; return nullptr;
return pWindowCandidate; return pWindowCandidate;
@@ -667,14 +884,13 @@ Vector2D IHyprLayout::predictSizeForNewWindowFloating(PHLWINDOW pWindow) { // ge
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); const auto MAXSIZE = pWindow->requestedMaxSize();
const auto SIZEX = SIZEXSTR == "max" ? const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.x) :
std::clamp(MAXSIZE.x, 20.0, g_pCompositor->m_pLastMonitor->vecSize.x) : stringToPercentage(SIZEXSTR, g_pCompositor->m_pLastMonitor->vecSize.x);
(!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * g_pCompositor->m_pLastMonitor->vecSize.x);
const auto SIZEY = SIZEYSTR == "max" ? const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.y) :
std::clamp(MAXSIZE.y, 20.0, g_pCompositor->m_pLastMonitor->vecSize.y) : stringToPercentage(SIZEYSTR, g_pCompositor->m_pLastMonitor->vecSize.y);
(!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * g_pCompositor->m_pLastMonitor->vecSize.y);
sizeOverride = {SIZEX, SIZEY}; sizeOverride = {SIZEX, SIZEY};

View File

@@ -19,10 +19,18 @@ enum eFullscreenMode : int8_t;
enum eRectCorner { enum eRectCorner {
CORNER_NONE = 0, CORNER_NONE = 0,
CORNER_TOPLEFT, CORNER_TOPLEFT = (1 << 0),
CORNER_TOPRIGHT, CORNER_TOPRIGHT = (1 << 1),
CORNER_BOTTOMRIGHT, CORNER_BOTTOMRIGHT = (1 << 2),
CORNER_BOTTOMLEFT CORNER_BOTTOMLEFT = (1 << 3),
};
enum eSnapEdge {
SNAP_INVALID = 0,
SNAP_UP = (1 << 0),
SNAP_DOWN = (1 << 1),
SNAP_LEFT = (1 << 2),
SNAP_RIGHT = (1 << 3),
}; };
enum eDirection { enum eDirection {
@@ -47,6 +55,7 @@ class IHyprLayout {
virtual void onWindowCreated(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowCreated(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT) = 0; virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT) = 0;
virtual void onWindowCreatedFloating(PHLWINDOW); virtual void onWindowCreatedFloating(PHLWINDOW);
virtual bool onWindowCreatedAutoGroup(PHLWINDOW);
/* /*
Return tiled status Return tiled status

View File

@@ -80,7 +80,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
static auto PNEWONTOP = CConfigValue<Hyprlang::INT>("master:new_on_top"); static auto PNEWONTOP = CConfigValue<Hyprlang::INT>("master:new_on_top");
static auto PNEWSTATUS = CConfigValue<std::string>("master:new_status"); static auto PNEWSTATUS = CConfigValue<std::string>("master:new_status");
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = pWindow->m_pMonitor.lock();
const bool BNEWBEFOREACTIVE = *PNEWONACTIVE == "before"; const bool BNEWBEFOREACTIVE = *PNEWONACTIVE == "before";
const bool BNEWISMASTER = *PNEWSTATUS == "master"; const bool BNEWISMASTER = *PNEWSTATUS == "master";
@@ -110,34 +110,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
getMasterNodeOnWorkspace(pWindow->workspaceID()); getMasterNodeOnWorkspace(pWindow->workspaceID());
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
if (g_pInputManager->m_bWasDraggingWindow && OPENINGON) {
if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow))
return;
}
// if it's a group, add the window
if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow.lock())) {
m_lMasterNodesData.remove(*PNODE);
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return;
}
pWindow->applyGroupRules();
static auto PDROPATCURSOR = CConfigValue<Hyprlang::INT>("master:drop_at_cursor"); static auto PDROPATCURSOR = CConfigValue<Hyprlang::INT>("master:drop_at_cursor");
eOrientation orientation = getDynamicOrientation(pWindow->m_pWorkspace); eOrientation orientation = getDynamicOrientation(pWindow->m_pWorkspace);
const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE); const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE);
@@ -228,7 +200,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
PNODE->percMaster = lastSplitPercent; PNODE->percMaster = lastSplitPercent;
// first, check if it isn't too big. // first, check if it isn't too big.
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PMONITOR->vecSize.x * lastSplitPercent || MAXSIZE.y < PMONITOR->vecSize.y) { if (const auto MAXSIZE = pWindow->requestedMaxSize(); MAXSIZE.x < PMONITOR->vecSize.x * lastSplitPercent || MAXSIZE.y < PMONITOR->vecSize.y) {
// we can't continue. make it floating. // we can't continue. make it floating.
pWindow->m_bIsFloating = true; pWindow->m_bIsFloating = true;
m_lMasterNodesData.remove(*PNODE); m_lMasterNodesData.remove(*PNODE);
@@ -240,7 +212,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
PNODE->percMaster = lastSplitPercent; PNODE->percMaster = lastSplitPercent;
// first, check if it isn't too big. // first, check if it isn't too big.
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); if (const auto MAXSIZE = pWindow->requestedMaxSize();
MAXSIZE.x < PMONITOR->vecSize.x * (1 - lastSplitPercent) || MAXSIZE.y < PMONITOR->vecSize.y * (1.f / (WINDOWSONWORKSPACE - 1))) { MAXSIZE.x < PMONITOR->vecSize.x * (1 - lastSplitPercent) || MAXSIZE.y < PMONITOR->vecSize.y * (1.f / (WINDOWSONWORKSPACE - 1))) {
// we can't continue. make it floating. // we can't continue. make it floating.
pWindow->m_bIsFloating = true; pWindow->m_bIsFloating = true;
@@ -251,7 +223,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
} }
// recalc // recalc
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->monitorID());
} }
void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
@@ -301,7 +273,7 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
} }
} }
} }
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->monitorID());
} }
void CHyprMasterLayout::recalculateMonitor(const MONITORID& monid) { void CHyprMasterLayout::recalculateMonitor(const MONITORID& monid) {
@@ -319,7 +291,7 @@ void CHyprMasterLayout::recalculateMonitor(const MONITORID& monid) {
} }
void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); const auto PMONITOR = pWorkspace->m_pMonitor.lock();
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -616,18 +588,17 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
} }
void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
CMonitor* PMONITOR = nullptr; PHLMONITOR PMONITOR = nullptr;
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
if (m->activeSpecialWorkspaceID() == pNode->workspaceID) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) {
PMONITOR = m.get(); PMONITOR = m;
break; break;
} }
} }
} else { } else
PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID); PMONITOR = g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_pMonitor.lock();
}
if (!PMONITOR) { if (!PMONITOR) {
Debug::log(ERR, "Orphaned Node {}!!", pNode); Debug::log(ERR, "Orphaned Node {}!!", pNode);
@@ -651,7 +622,6 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->unsetWindowData(PRIORITY_LAYOUT);
PWINDOW->updateWindowData(); PWINDOW->updateWindowData();
static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("master:no_gaps_when_only");
static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes"); static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in"); static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out"); static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
@@ -669,25 +639,6 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->m_vSize = pNode->size; PWINDOW->m_vSize = pNode->size;
PWINDOW->m_vPosition = pNode->position; PWINDOW->m_vPosition = pNode->position;
if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) {
PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT);
PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->updateWindowDecos();
const auto RESERVED = PWINDOW->getFullWindowReservedArea();
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft;
PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
return;
}
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
auto calcPos = PWINDOW->m_vPosition; auto calcPos = PWINDOW->m_vPosition;
@@ -749,12 +700,14 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
const auto PNODE = getNodeFromWindow(PWINDOW); const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) { if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goal() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goal() + pixResize).y, 20.0)); PWINDOW->m_vRealSize =
(PWINDOW->m_vRealSize.goal() + pixResize)
.clamp(PWINDOW->m_sWindowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), PWINDOW->m_sWindowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY}));
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
return; return;
} }
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = PWINDOW->m_pMonitor.lock();
static auto ALWAYSCENTER = CConfigValue<Hyprlang::INT>("master:always_center_master"); static auto ALWAYSCENTER = CConfigValue<Hyprlang::INT>("master:always_center_master");
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing"); static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing");
@@ -883,7 +836,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
} }
void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) { void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = pWindow->m_pMonitor.lock();
const auto PWORKSPACE = pWindow->m_pWorkspace; const auto PWORKSPACE = pWindow->m_pWorkspace;
// save position and size if floating // save position and size if floating
@@ -939,7 +892,7 @@ void CHyprMasterLayout::recalculateWindow(PHLWINDOW pWindow) {
if (!PNODE) if (!PNODE)
return; return;
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->monitorID());
} }
SWindowRenderLayoutHints CHyprMasterLayout::requestRenderHints(PHLWINDOW pWindow) { SWindowRenderLayoutHints CHyprMasterLayout::requestRenderHints(PHLWINDOW pWindow) {
@@ -965,9 +918,9 @@ void CHyprMasterLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir,
// if different monitors, send to monitor // if different monitors, send to monitor
onWindowRemovedTiling(pWindow); onWindowRemovedTiling(pWindow);
pWindow->moveToWorkspace(PWINDOW2->m_pWorkspace); pWindow->moveToWorkspace(PWINDOW2->m_pWorkspace);
pWindow->m_iMonitorID = PWINDOW2->m_iMonitorID; pWindow->m_pMonitor = PWINDOW2->m_pMonitor;
if (!silent) { if (!silent) {
const auto pMonitor = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto pMonitor = pWindow->m_pMonitor.lock();
g_pCompositor->setActiveMonitor(pMonitor); g_pCompositor->setActiveMonitor(pMonitor);
} }
onWindowCreatedTiling(pWindow); onWindowCreatedTiling(pWindow);
@@ -989,7 +942,7 @@ void CHyprMasterLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) {
return; return;
if (PNODE->workspaceID != PNODE2->workspaceID) { if (PNODE->workspaceID != PNODE2->workspaceID) {
std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID); std::swap(pWindow2->m_pMonitor, pWindow->m_pMonitor);
std::swap(pWindow2->m_pWorkspace, pWindow->m_pWorkspace); std::swap(pWindow2->m_pWorkspace, pWindow->m_pWorkspace);
} }
@@ -1000,9 +953,9 @@ void CHyprMasterLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) {
pWindow->setAnimationsToMove(); pWindow->setAnimationsToMove();
pWindow2->setAnimationsToMove(); pWindow2->setAnimationsToMove();
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->monitorID());
if (PNODE2->workspaceID != PNODE->workspaceID) if (PNODE2->workspaceID != PNODE->workspaceID)
recalculateMonitor(pWindow2->m_iMonitorID); recalculateMonitor(pWindow2->monitorID());
g_pHyprRenderer->damageWindow(pWindow); g_pHyprRenderer->damageWindow(pWindow);
g_pHyprRenderer->damageWindow(pWindow2); g_pHyprRenderer->damageWindow(pWindow2);
@@ -1021,7 +974,7 @@ void CHyprMasterLayout::alterSplitRatio(PHLWINDOW pWindow, float ratio, bool exa
float newRatio = exact ? ratio : PMASTER->percMaster + ratio; float newRatio = exact ? ratio : PMASTER->percMaster + ratio;
PMASTER->percMaster = std::clamp(newRatio, 0.05f, 0.95f); PMASTER->percMaster = std::clamp(newRatio, 0.05f, 0.95f);
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->monitorID());
} }
PHLWINDOW CHyprMasterLayout::getNextWindow(PHLWINDOW pWindow, bool next) { PHLWINDOW CHyprMasterLayout::getNextWindow(PHLWINDOW pWindow, bool next) {
@@ -1228,7 +1181,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
PNODE->isMaster = true; PNODE->isMaster = true;
} }
recalculateMonitor(header.pWindow->m_iMonitorID); recalculateMonitor(header.pWindow->monitorID());
} else if (command == "removemaster") { } else if (command == "removemaster") {
@@ -1260,7 +1213,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
PNODE->isMaster = false; PNODE->isMaster = false;
} }
recalculateMonitor(header.pWindow->m_iMonitorID); recalculateMonitor(header.pWindow->monitorID());
} else if (command == "orientationleft" || command == "orientationright" || command == "orientationtop" || command == "orientationbottom" || command == "orientationcenter") { } else if (command == "orientationleft" || command == "orientationright" || command == "orientationtop" || command == "orientationbottom" || command == "orientationcenter") {
const auto PWINDOW = header.pWindow; const auto PWINDOW = header.pWindow;
@@ -1282,7 +1235,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
else if (command == "orientationcenter") else if (command == "orientationcenter")
PWORKSPACEDATA->orientation = ORIENTATION_CENTER; PWORKSPACEDATA->orientation = ORIENTATION_CENTER;
recalculateMonitor(header.pWindow->m_iMonitorID); recalculateMonitor(header.pWindow->monitorID());
} else if (command == "orientationnext") { } else if (command == "orientationnext") {
runOrientationCycle(header, nullptr, 1); runOrientationCycle(header, nullptr, 1);
@@ -1317,7 +1270,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
} }
} }
recalculateMonitor(PWINDOW->m_iMonitorID); recalculateMonitor(PWINDOW->monitorID());
} else if (command == "rollprev") { } else if (command == "rollprev") {
const auto PWINDOW = header.pWindow; const auto PWINDOW = header.pWindow;
const auto PNODE = getNodeFromWindow(PWINDOW); const auto PNODE = getNodeFromWindow(PWINDOW);
@@ -1343,7 +1296,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
} }
} }
recalculateMonitor(PWINDOW->m_iMonitorID); recalculateMonitor(PWINDOW->monitorID());
} }
return 0; return 0;
@@ -1381,7 +1334,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi
nextOrPrev = cycle.size() + (nextOrPrev % (int)cycle.size()); nextOrPrev = cycle.size() + (nextOrPrev % (int)cycle.size());
PWORKSPACEDATA->orientation = cycle.at(nextOrPrev); PWORKSPACEDATA->orientation = cycle.at(nextOrPrev);
recalculateMonitor(header.pWindow->m_iMonitorID); recalculateMonitor(header.pWindow->monitorID());
} }
void CHyprMasterLayout::buildOrientationCycleVectorFromEOperation(std::vector<eOrientation>& cycle) { void CHyprMasterLayout::buildOrientationCycleVectorFromEOperation(std::vector<eOrientation>& cycle) {

View File

@@ -29,6 +29,8 @@
#define MONITOR_INVALID -1L #define MONITOR_INVALID -1L
#define MIN_WINDOW_SIZE 20.0
#define LISTENER(name) \ #define LISTENER(name) \
void listener_##name(wl_listener*, void*); \ void listener_##name(wl_listener*, void*); \
inline wl_listener listen_##name = {.notify = listener_##name} inline wl_listener listen_##name = {.notify = listener_##name}

View File

@@ -3,8 +3,11 @@
#include "Compositor.hpp" #include "Compositor.hpp"
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "init/initHelpers.hpp" #include "init/initHelpers.hpp"
#include "debug/HyprCtl.hpp"
#include <cstdio>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <print>
using namespace Hyprutils::String; using namespace Hyprutils::String;
#include <fcntl.h> #include <fcntl.h>
@@ -16,14 +19,15 @@ using namespace Hyprutils::String;
#include <filesystem> #include <filesystem>
void help() { void help() {
std::cout << "usage: Hyprland [arg [...]].\n"; std::println("usage: Hyprland [arg [...]].\n");
std::cout << "\nArguments:\n"; std::println(R"(Arguments:
std::cout << " --help -h - Show this message again\n"; --help -h - Show this message again
std::cout << " --config FILE -c FILE - Specify config file to use\n"; --config FILE -c FILE - Specify config file to use
std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; --socket NAME - Sets the Wayland socket name (for Wayland socket handover)
std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)
std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; --systeminfo - Prints system infos
std::cout << " --version -v - Print this binary's version\n"; --i-am-really-stupid - Omits root user privileges check (why would you do that?)
--version -v - Print this binary's version)");
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
@@ -32,9 +36,9 @@ int main(int argc, char** argv) {
throwError("XDG_RUNTIME_DIR is not set!"); throwError("XDG_RUNTIME_DIR is not set!");
// export HYPRLAND_CMD // export HYPRLAND_CMD
std::string cmd = ""; std::string cmd = argv[0];
for (auto i = 0; i < argc; ++i) for (int i = 1; i < argc; ++i)
cmd += std::string(i == 0 ? "" : " ") + argv[i]; cmd += std::string(" ") + argv[i];
setenv("HYPRLAND_CMD", cmd.c_str(), 1); setenv("HYPRLAND_CMD", cmd.c_str(), 1);
setenv("XDG_BACKEND", "wayland", 1); setenv("XDG_BACKEND", "wayland", 1);
@@ -51,7 +55,7 @@ int main(int argc, char** argv) {
for (auto it = args.begin(); it != args.end(); it++) { for (auto it = args.begin(); it != args.end(); it++) {
if (it->compare("--i-am-really-stupid") == 0 && !ignoreSudo) { if (it->compare("--i-am-really-stupid") == 0 && !ignoreSudo) {
std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n"; std::println("[ WARNING ] Running Hyprland with superuser privileges might damage your system");
ignoreSudo = true; ignoreSudo = true;
} else if (it->compare("--socket") == 0) { } else if (it->compare("--socket") == 0) {
@@ -77,7 +81,7 @@ int main(int argc, char** argv) {
if (fcntl(socketFd, F_GETFD) == -1) if (fcntl(socketFd, F_GETFD) == -1)
throw std::exception(); throw std::exception();
} catch (...) { } catch (...) {
std::cerr << "[ ERROR ] Invalid Wayland FD!\n"; std::println(stderr, "[ ERROR ] Invalid Wayland FD!");
help(); help();
return 1; return 1;
@@ -99,7 +103,7 @@ int main(int argc, char** argv) {
throw std::exception(); throw std::exception();
} }
} catch (...) { } catch (...) {
std::cerr << "[ ERROR ] Config file '" << configPath << "' doesn't exist!\n"; std::println(stderr, "[ ERROR ] Config file '{}' doesn't exist!", configPath);
help(); help();
return 1; return 1;
@@ -115,26 +119,13 @@ int main(int argc, char** argv) {
return 0; return 0;
} else if (it->compare("-v") == 0 || it->compare("--version") == 0) { } else if (it->compare("-v") == 0 || it->compare("--version") == 0) {
auto commitMsg = trim(GIT_COMMIT_MESSAGE); std::println("{}", versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""));
std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); return 0;
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + } else if (it->compare("--systeminfo") == 0) {
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + std::println("{}", systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""));
"\n\nflags: (if any)\n";
#ifdef LEGACY_RENDERER
result += "legacyrenderer\n";
#endif
#ifndef ISDEBUG
result += "debug\n";
#endif
#ifdef NO_XWAYLAND
result += "no xwayland\n";
#endif
std::cout << result;
return 0; return 0;
} else { } else {
std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n"; std::println(stderr, "[ ERROR ] Unknown option '{}' !", it->c_str());
help(); help();
return 1; return 1;
@@ -142,30 +133,32 @@ int main(int argc, char** argv) {
} }
if (!ignoreSudo && Init::isSudo()) { if (!ignoreSudo && Init::isSudo()) {
std::cerr << "[ ERROR ] Hyprland was launched with superuser privileges, but the privileges check is not omitted.\n"; std::println(stderr,
std::cerr << " Hint: Use the --i-am-really-stupid flag to omit that check.\n"; "[ ERROR ] Hyprland was launched with superuser privileges, but the privileges check is not omitted.\n"
" Hint: Use the --i-am-really-stupid flag to omit that check.");
return 1; return 1;
} else if (ignoreSudo && Init::isSudo()) { } else if (ignoreSudo && Init::isSudo()) {
std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n"; std::println("Superuser privileges check is omitted. I hope you know what you're doing.");
} }
if (socketName.empty() ^ (socketFd == -1)) { if (socketName.empty() ^ (socketFd == -1)) {
std::cerr << "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n"; std::println(stderr,
std::cerr << " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover.\n"; "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n"
" Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover.");
return 1; return 1;
} }
std::cout << "Welcome to Hyprland!\n"; std::println("Welcome to Hyprland!");
// let's init the compositor. // let's init the compositor.
// it initializes basic Wayland stuff in the constructor. // it initializes basic Wayland stuff in the constructor.
try { try {
g_pCompositor = std::make_unique<CCompositor>(); g_pCompositor = std::make_unique<CCompositor>();
g_pCompositor->explicitConfigPath = configPath; g_pCompositor->explicitConfigPath = configPath;
} catch (std::exception& e) { } catch (const std::exception& e) {
std::cout << "Hyprland threw in ctor: " << e.what() << "\nCannot continue.\n"; std::println(stderr, "Hyprland threw in ctor: {}\nCannot continue.", e.what());
return 1; return 1;
} }

View File

@@ -64,7 +64,7 @@ void CAnimationManager::tick() {
if (!*PANIMENABLED) if (!*PANIMENABLED)
animGlobalDisabled = true; animGlobalDisabled = true;
static auto* const PSHADOWSENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:drop_shadow"); static auto* const PSHADOWSENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:shadow:enabled");
const auto DEFAULTBEZIER = m_mBezierCurves.find("default"); const auto DEFAULTBEZIER = m_mBezierCurves.find("default");
@@ -85,7 +85,7 @@ void CAnimationManager::tick() {
PHLWINDOW PWINDOW = av->m_pWindow.lock(); PHLWINDOW PWINDOW = av->m_pWindow.lock();
PHLWORKSPACE PWORKSPACE = av->m_pWorkspace.lock(); PHLWORKSPACE PWORKSPACE = av->m_pWorkspace.lock();
PHLLS PLAYER = av->m_pLayer.lock(); PHLLS PLAYER = av->m_pLayer.lock();
CMonitor* PMONITOR = nullptr; PHLMONITOR PMONITOR = nullptr;
bool animationsDisabled = animGlobalDisabled; bool animationsDisabled = animGlobalDisabled;
if (PWINDOW) { if (PWINDOW) {
@@ -99,12 +99,12 @@ void CAnimationManager::tick() {
PDECO->damageEntire(); PDECO->damageEntire();
} }
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR = PWINDOW->m_pMonitor.lock();
if (!PMONITOR) if (!PMONITOR)
continue; continue;
animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled); animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled);
} else if (PWORKSPACE) { } else if (PWORKSPACE) {
PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); PMONITOR = PWORKSPACE->m_pMonitor.lock();
if (!PMONITOR) if (!PMONITOR)
continue; continue;
@@ -259,7 +259,7 @@ void CAnimationManager::tick() {
// manually schedule a frame // manually schedule a frame
if (PMONITOR) if (PMONITOR)
g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION);
} }
// do it here, because if this alters the animation vars deque we would be in trouble above. // do it here, because if this alters the animation vars deque we would be in trouble above.
@@ -325,7 +325,7 @@ void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, boo
const auto GOALPOS = pWindow->m_vRealPosition.goal(); const auto GOALPOS = pWindow->m_vRealPosition.goal();
const auto GOALSIZE = pWindow->m_vRealSize.goal(); const auto GOALSIZE = pWindow->m_vRealSize.goal();
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = pWindow->m_pMonitor.lock();
if (!PMONITOR) if (!PMONITOR)
return; // unsafe state most likely return; // unsafe state most likely

View File

@@ -309,7 +309,7 @@ void CCursorManager::updateTheme() {
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
m->forceFullFrames = 5; m->forceFullFrames = 5;
g_pCompositor->scheduleFrameForMonitor(m.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); g_pCompositor->scheduleFrameForMonitor(m, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
} }
} }

View File

@@ -126,6 +126,7 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup; m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup;
m_mDispatchers["event"] = event; m_mDispatchers["event"] = event;
m_mDispatchers["global"] = global; m_mDispatchers["global"] = global;
m_mDispatchers["setprop"] = setProp;
m_tScrollTimer.reset(); m_tScrollTimer.reset();
@@ -271,11 +272,11 @@ void updateRelativeCursorCoords() {
g_pCompositor->m_pLastWindow->m_vRelativeCursorCoordsOnLastWarp = g_pInputManager->getMouseCoordsInternal() - g_pCompositor->m_pLastWindow->m_vPosition; g_pCompositor->m_pLastWindow->m_vRelativeCursorCoordsOnLastWarp = g_pInputManager->getMouseCoordsInternal() - g_pCompositor->m_pLastWindow->m_vPosition;
} }
bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { bool CKeybindManager::tryMoveFocusToMonitor(PHLMONITOR monitor) {
if (!monitor) if (!monitor)
return false; return false;
const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get(); const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.lock();
if (!LASTMONITOR) if (!LASTMONITOR)
return false; return false;
if (LASTMONITOR == monitor) { if (LASTMONITOR == monitor) {
@@ -349,9 +350,9 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
g_pInputManager->m_pForcedFocus.reset(); g_pInputManager->m_pForcedFocus.reset();
} }
if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) { if (PLASTWINDOW && PLASTWINDOW->m_pMonitor != PWINDOWTOCHANGETO->m_pMonitor) {
// event // event
const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID); const auto PNEWMON = PWINDOWTOCHANGETO->m_pMonitor.lock();
g_pCompositor->setActiveMonitor(PNEWMON); g_pCompositor->setActiveMonitor(PNEWMON);
} }
@@ -376,7 +377,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput 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(pKeyboard->resolveBindsBySym ? pKeyboard->xkbState : m_pXKBTranslationState, KEYCODE); const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbSymState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE);
if (handleInternalKeybinds(internalKeysym)) if (handleInternalKeybinds(internalKeysym))
@@ -594,6 +595,10 @@ eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) {
return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys); return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys);
} }
std::string CKeybindManager::getCurrentSubmap() {
return m_szCurrentSelectedSubmap;
}
SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) {
static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing"); static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
bool found = false; bool found = false;
@@ -1007,7 +1012,7 @@ static SDispatchResult toggleActiveFloatingCore(std::string args, std::optional<
} }
g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID()); g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID());
g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID()); g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
return {}; return {};
@@ -1031,7 +1036,7 @@ SDispatchResult CKeybindManager::centerWindow(std::string args) {
if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->isFullscreen())
return {.success = false, .error = "No floating window found"}; return {.success = false, .error = "No floating window found"};
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = PWINDOW->m_pMonitor.lock();
auto RESERVEDOFFSET = Vector2D(); auto RESERVEDOFFSET = Vector2D();
if (args == "1") if (args == "1")
@@ -1077,7 +1082,7 @@ SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCU
const auto ID = PCURRENTWORKSPACE->m_iID; const auto ID = PCURRENTWORKSPACE->m_iID;
if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO) { if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO) {
if (PER_MON && PCURRENTWORKSPACE->m_iMonitorID != PWORKSPACETOCHANGETO->m_iMonitorID) if (PER_MON && PCURRENTWORKSPACE->m_pMonitor != PWORKSPACETOCHANGETO->m_pMonitor)
return {WORKSPACE_NOT_CHANGED, ""}; return {WORKSPACE_NOT_CHANGED, ""};
return {ID, PWORKSPACETOCHANGETO->m_szName}; return {ID, PWORKSPACETOCHANGETO->m_szName};
} }
@@ -1092,7 +1097,7 @@ SDispatchResult CKeybindManager::changeworkspace(std::string args) {
static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles"); static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
static auto PWORKSPACECENTERON = CConfigValue<Hyprlang::INT>("binds:workspace_center_on"); static auto PWORKSPACECENTERON = CConfigValue<Hyprlang::INT>("binds:workspace_center_on");
const auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); const auto PMONITOR = g_pCompositor->m_pLastMonitor.lock();
if (!PMONITOR) if (!PMONITOR)
return {.success = false, .error = "Last monitor not found"}; return {.success = false, .error = "Last monitor not found"};
@@ -1131,7 +1136,7 @@ SDispatchResult CKeybindManager::changeworkspace(std::string args) {
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
const auto PMONITORWORKSPACEOWNER = PMONITOR->ID == pWorkspaceToChangeTo->m_iMonitorID ? PMONITOR : g_pCompositor->getMonitorFromID(pWorkspaceToChangeTo->m_iMonitorID); const auto PMONITORWORKSPACEOWNER = PMONITOR == pWorkspaceToChangeTo->m_pMonitor ? PMONITOR : pWorkspaceToChangeTo->m_pMonitor.lock();
if (!PMONITORWORKSPACEOWNER) if (!PMONITORWORKSPACEOWNER)
return {.success = false, .error = "Workspace to switch to has no monitor"}; return {.success = false, .error = "Workspace to switch to has no monitor"};
@@ -1256,7 +1261,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) {
} }
auto pWorkspace = g_pCompositor->getWorkspaceByID(WORKSPACEID); auto pWorkspace = g_pCompositor->getWorkspaceByID(WORKSPACEID);
CMonitor* pMonitor = nullptr; PHLMONITOR pMonitor = nullptr;
const auto POLDWS = PWINDOW->m_pWorkspace; const auto POLDWS = PWINDOW->m_pWorkspace;
static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles"); static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
@@ -1266,11 +1271,11 @@ SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) {
if (pWorkspace) { if (pWorkspace) {
g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace);
pMonitor = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); pMonitor = pWorkspace->m_pMonitor.lock();
g_pCompositor->setActiveMonitor(pMonitor); g_pCompositor->setActiveMonitor(pMonitor);
} else { } else {
pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->m_iMonitorID, workspaceName, false); pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->monitorID(), workspaceName, false);
pMonitor = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); pMonitor = pWorkspace->m_pMonitor.lock();
g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace);
} }
@@ -1279,7 +1284,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) {
if (pWorkspace->m_bIsSpecialWorkspace) if (pWorkspace->m_bIsSpecialWorkspace)
pMonitor->setSpecialWorkspace(pWorkspace); pMonitor->setSpecialWorkspace(pWorkspace);
else if (POLDWS->m_bIsSpecialWorkspace) else if (POLDWS->m_bIsSpecialWorkspace)
g_pCompositor->getMonitorFromID(POLDWS->m_iMonitorID)->setSpecialWorkspace(nullptr); POLDWS->m_pMonitor.lock()->setSpecialWorkspace(nullptr);
if (*PALLOWWORKSPACECYCLES) if (*PALLOWWORKSPACECYCLES)
pWorkspace->rememberPrevWorkspace(POLDWS); pWorkspace->rememberPrevWorkspace(POLDWS);
@@ -1324,7 +1329,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
if (pWorkspace) { if (pWorkspace) {
g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace);
} else { } else {
pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->m_iMonitorID, workspaceName, false); pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->monitorID(), workspaceName, false);
g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace);
} }
@@ -1471,7 +1476,7 @@ SDispatchResult CKeybindManager::moveActiveTo(std::string args) {
if (PLASTWINDOW->m_bIsFloating) { if (PLASTWINDOW->m_bIsFloating) {
std::optional<float> vPosx, vPosy; std::optional<float> vPosx, vPosy;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PLASTWINDOW->m_iMonitorID); const auto PMONITOR = PLASTWINDOW->m_pMonitor.lock();
const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize(); const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize();
switch (arg) { switch (arg) {
@@ -1791,7 +1796,7 @@ SDispatchResult CKeybindManager::exitHyprland(std::string argz) {
} }
SDispatchResult CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { SDispatchResult CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
CMonitor* PMONITOR = g_pCompositor->getMonitorFromString(args); PHLMONITOR PMONITOR = g_pCompositor->getMonitorFromString(args);
if (!PMONITOR) { if (!PMONITOR) {
Debug::log(ERR, "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist"); Debug::log(ERR, "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist");
@@ -1844,13 +1849,13 @@ SDispatchResult CKeybindManager::moveWorkspaceToMonitor(std::string args) {
} }
SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
auto workspaceID = getWorkspaceIDNameFromString(args).id; auto [workspaceID, workspaceName] = getWorkspaceIDNameFromString(args);
if (workspaceID == WORKSPACE_INVALID) { if (workspaceID == WORKSPACE_INVALID) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!"); Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!");
return {.success = false, .error = "focusWorkspaceOnCurrentMonitor invalid workspace!"}; return {.success = false, .error = "focusWorkspaceOnCurrentMonitor invalid workspace!"};
} }
const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor.get(); const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor.lock();
if (!PCURRMONITOR) { if (!PCURRMONITOR) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!"); Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!");
@@ -1860,7 +1865,7 @@ SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args
auto pWorkspace = g_pCompositor->getWorkspaceByID(workspaceID); auto pWorkspace = g_pCompositor->getWorkspaceByID(workspaceID);
if (!pWorkspace) { if (!pWorkspace) {
pWorkspace = g_pCompositor->createNewWorkspace(workspaceID, PCURRMONITOR->ID); pWorkspace = g_pCompositor->createNewWorkspace(workspaceID, PCURRMONITOR->ID, workspaceName);
// we can skip the moving, since it's already on the current monitor // we can skip the moving, since it's already on the current monitor
changeworkspace(pWorkspace->getConfigName()); changeworkspace(pWorkspace->getConfigName());
return {}; return {};
@@ -1878,8 +1883,8 @@ SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args
workspaceID = pWorkspace->m_iID; workspaceID = pWorkspace->m_iID;
} }
if (pWorkspace->m_iMonitorID != PCURRMONITOR->ID) { if (pWorkspace->m_pMonitor != PCURRMONITOR) {
const auto POLDMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); const auto POLDMONITOR = pWorkspace->m_pMonitor.lock();
if (!POLDMONITOR) { // wat if (!POLDMONITOR) { // wat
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"); Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!");
return {.success = false, .error = "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"}; return {.success = false, .error = "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"};
@@ -1939,8 +1944,8 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) {
if (!m->output) if (!m->output)
continue; continue;
auto rule = g_pConfigManager->getMonitorRuleFor(*m); auto rule = g_pConfigManager->getMonitorRuleFor(m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) { if (!g_pHyprRenderer->applyMonitorRule(m, &rule, true)) {
overAgain = true; overAgain = true;
break; break;
} }
@@ -2399,9 +2404,7 @@ SDispatchResult CKeybindManager::dpms(std::string arg) {
bool enable = arg.starts_with("on"); bool enable = arg.starts_with("on");
std::string port = ""; std::string port = "";
if (arg.starts_with("toggle")) bool isToggle = arg.starts_with("toggle");
enable = !std::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return !other->dpmsStatus; }); // enable if any is off
if (arg.find_first_of(' ') != std::string::npos) if (arg.find_first_of(' ') != std::string::npos)
port = arg.substr(arg.find_first_of(' ') + 1); port = arg.substr(arg.find_first_of(' ') + 1);
@@ -2410,6 +2413,9 @@ SDispatchResult CKeybindManager::dpms(std::string arg) {
if (!port.empty() && m->szName != port) if (!port.empty() && m->szName != port)
continue; continue;
if (isToggle)
enable = !m->dpmsStatus;
m->output->state->resetExplicitFences(); m->output->state->resetExplicitFences();
m->output->state->setEnabled(enable); m->output->state->setEnabled(enable);
@@ -2422,7 +2428,7 @@ SDispatchResult CKeybindManager::dpms(std::string arg) {
} }
if (enable) if (enable)
g_pHyprRenderer->damageMonitor(m.get()); g_pHyprRenderer->damageMonitor(m);
m->events.dpmsChanged.emit(); m->events.dpmsChanged.emit();
} }
@@ -2504,7 +2510,7 @@ SDispatchResult CKeybindManager::pinActive(std::string args) {
PWINDOW->m_bPinned = !PWINDOW->m_bPinned; PWINDOW->m_bPinned = !PWINDOW->m_bPinned;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = PWINDOW->m_pMonitor.lock();
if (!PMONITOR) { if (!PMONITOR) {
Debug::log(ERR, "pin: monitor not found"); Debug::log(ERR, "pin: monitor not found");
@@ -2653,15 +2659,14 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property! g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property!
if (pWindow->m_iMonitorID != pWindowInDirection->m_iMonitorID) { if (pWindow->m_pMonitor != pWindowInDirection->m_pMonitor) {
pWindow->moveToWorkspace(pWindowInDirection->m_pWorkspace); pWindow->moveToWorkspace(pWindowInDirection->m_pWorkspace);
pWindow->m_iMonitorID = pWindowInDirection->m_iMonitorID; pWindow->m_pMonitor = pWindowInDirection->m_pMonitor;
} }
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current"); static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail(); (*USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail())->insertWindowToGroup(pWindow);
pWindowInDirection->insertWindowToGroup(pWindow);
pWindowInDirection->setGroupCurrent(pWindow); pWindowInDirection->setGroupCurrent(pWindow);
pWindow->updateWindowDecos(); pWindow->updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow);
@@ -2886,3 +2891,97 @@ SDispatchResult CKeybindManager::event(std::string args) {
g_pEventManager->postEvent(SHyprIPCEvent{"custom", args}); g_pEventManager->postEvent(SHyprIPCEvent{"custom", args});
return {}; return {};
} }
SDispatchResult CKeybindManager::setProp(std::string args) {
CVarList vars(args, 3, ' ');
if (vars.size() < 3)
return {.success = false, .error = "Not enough args"};
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[0]);
if (!PWINDOW)
return {.success = false, .error = "Window not found"};
const auto PROP = vars[1];
const auto VAL = vars[2];
bool noFocus = PWINDOW->m_sWindowData.noFocus.valueOrDefault();
try {
if (PROP == "animationstyle") {
PWINDOW->m_sWindowData.animationStyle = CWindowOverridableVar(VAL, PRIORITY_SET_PROP);
} else if (PROP == "maxsize") {
PWINDOW->m_sWindowData.maxSize = CWindowOverridableVar(configStringToVector2D(VAL), PRIORITY_SET_PROP);
PWINDOW->clampWindowSize(std::nullopt, PWINDOW->m_sWindowData.maxSize.value());
PWINDOW->setHidden(false);
} else if (PROP == "minsize") {
PWINDOW->m_sWindowData.minSize = CWindowOverridableVar(configStringToVector2D(VAL), PRIORITY_SET_PROP);
PWINDOW->clampWindowSize(PWINDOW->m_sWindowData.minSize.value(), std::nullopt);
PWINDOW->setHidden(false);
} else if (PROP == "alpha") {
PWINDOW->m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alpha.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactive") {
PWINDOW->m_sWindowData.alphaInactive =
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphafullscreen") {
PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphaoverride") {
PWINDOW->m_sWindowData.alpha =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactiveoverride") {
PWINDOW->m_sWindowData.alphaInactive =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphafullscreenoverride") {
PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") {
CGradientValueData colorData = {};
if (vars.size() > 4) {
for (int i = 3; i < static_cast<int>(vars.size()); ++i) {
const auto TOKEN = vars[i];
if (TOKEN.ends_with("deg"))
colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0);
else
colorData.m_vColors.push_back(configStringToInt(TOKEN));
}
} else if (VAL != "-1")
colorData.m_vColors.push_back(configStringToInt(VAL));
if (PROP == "activebordercolor")
PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
else
PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
} else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) {
auto pWindowDataElement = search->second(PWINDOW);
if (VAL == "toggle")
*pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP);
else if (VAL == "unset")
pWindowDataElement->unset(PRIORITY_SET_PROP);
else
*pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP);
} else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) {
if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else
*(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP);
} else {
return {.success = false, .error = "Prop not found"};
}
} catch (std::exception& e) { return {.success = false, .error = std::format("Error parsing prop value: {}", std::string(e.what()))}; }
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!(PWINDOW->m_sWindowData.noFocus.valueOrDefault() == noFocus)) {
g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->focusWindow(PLASTWINDOW);
}
for (auto const& m : g_pCompositor->m_vMonitors)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
return {};
}

View File

@@ -96,6 +96,7 @@ class CKeybindManager {
uint32_t keycodeToModifier(xkb_keycode_t); uint32_t keycodeToModifier(xkb_keycode_t);
void clearKeybinds(); void clearKeybinds();
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0); void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0);
std::string getCurrentSubmap();
std::unordered_map<std::string, std::function<SDispatchResult(std::string)>> m_mDispatchers; std::unordered_map<std::string, std::function<SDispatchResult(std::string)>> m_mDispatchers;
@@ -145,7 +146,7 @@ class CKeybindManager {
void updateXKBTranslationState(); void updateXKBTranslationState();
bool ensureMouseBindState(); bool ensureMouseBindState();
static bool tryMoveFocusToMonitor(CMonitor* monitor); static bool tryMoveFocusToMonitor(PHLMONITOR monitor);
static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = ""); static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = "");
static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection); static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection);
static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO); static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO);
@@ -216,6 +217,7 @@ class CKeybindManager {
static SDispatchResult denyWindowFromGroup(std::string); static SDispatchResult denyWindowFromGroup(std::string);
static SDispatchResult global(std::string); static SDispatchResult global(std::string);
static SDispatchResult event(std::string); static SDispatchResult event(std::string);
static SDispatchResult setProp(std::string);
friend class CCompositor; friend class CCompositor;
friend class CInputManager; friend class CInputManager;

View File

@@ -2,6 +2,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../protocols/PointerGestures.hpp" #include "../protocols/PointerGestures.hpp"
#include "../protocols/RelativePointer.hpp"
#include "../protocols/FractionalScale.hpp" #include "../protocols/FractionalScale.hpp"
#include "../protocols/IdleNotify.hpp" #include "../protocols/IdleNotify.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
@@ -13,14 +14,12 @@
CPointerManager::CPointerManager() { CPointerManager::CPointerManager() {
hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) {
auto PMONITOR = std::any_cast<CMonitor*>(data)->self.lock(); auto PMONITOR = std::any_cast<PHLMONITOR>(data);
onMonitorLayoutChange(); onMonitorLayoutChange();
PMONITOR->events.modeChanged.registerStaticListener( PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr);
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.disconnect.registerStaticListener(
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.destroy.registerStaticListener( PMONITOR->events.destroy.registerStaticListener(
[this](void* owner, std::any data) { [this](void* owner, std::any data) {
if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown)
@@ -30,7 +29,7 @@ CPointerManager::CPointerManager() {
}); });
hooks.monitorPreRender = g_pHookSystem->hookDynamic("preMonitorCommit", [this](void* self, SCallbackInfo& info, std::any data) { hooks.monitorPreRender = g_pHookSystem->hookDynamic("preMonitorCommit", [this](void* self, SCallbackInfo& info, std::any data) {
auto state = stateFor(std::any_cast<CMonitor*>(data)->self.lock()); auto state = stateFor(std::any_cast<PHLMONITOR>(data));
if (!state) if (!state)
return; return;
@@ -52,34 +51,16 @@ void CPointerManager::unlockSoftwareAll() {
updateCursorBackend(); updateCursorBackend();
} }
void CPointerManager::lockSoftwareForMonitor(CMonitor* Monitor) { void CPointerManager::lockSoftwareForMonitor(PHLMONITOR mon) {
for (auto const& m : g_pCompositor->m_vMonitors) { auto const state = stateFor(mon);
if (m->ID == Monitor->ID) {
lockSoftwareForMonitor(m);
return;
}
}
}
void CPointerManager::lockSoftwareForMonitor(SP<CMonitor> mon) {
auto state = stateFor(mon);
state->softwareLocks++; state->softwareLocks++;
if (state->softwareLocks == 1) if (state->softwareLocks == 1)
updateCursorBackend(); updateCursorBackend();
} }
void CPointerManager::unlockSoftwareForMonitor(CMonitor* Monitor) { void CPointerManager::unlockSoftwareForMonitor(PHLMONITOR mon) {
for (auto const& m : g_pCompositor->m_vMonitors) { auto const state = stateFor(mon);
if (m->ID == Monitor->ID) {
unlockSoftwareForMonitor(m);
return;
}
}
}
void CPointerManager::unlockSoftwareForMonitor(SP<CMonitor> mon) {
auto state = stateFor(mon);
state->softwareLocks--; state->softwareLocks--;
if (state->softwareLocks < 0) if (state->softwareLocks < 0)
state->softwareLocks = 0; state->softwareLocks = 0;
@@ -88,8 +69,8 @@ void CPointerManager::unlockSoftwareForMonitor(SP<CMonitor> mon) {
updateCursorBackend(); updateCursorBackend();
} }
bool CPointerManager::softwareLockedFor(SP<CMonitor> mon) { bool CPointerManager::softwareLockedFor(PHLMONITOR mon) {
auto state = stateFor(mon); auto const state = stateFor(mon);
return state->softwareLocks > 0 || state->hardwareFailed; return state->softwareLocks > 0 || state->hardwareFailed;
} }
@@ -101,7 +82,7 @@ bool CPointerManager::hasCursor() {
return currentCursorImage.pBuffer || currentCursorImage.surface; return currentCursorImage.pBuffer || currentCursorImage.surface;
} }
SP<CPointerManager::SMonitorPointerState> CPointerManager::stateFor(SP<CMonitor> mon) { SP<CPointerManager::SMonitorPointerState> CPointerManager::stateFor(PHLMONITOR mon) {
auto it = std::find_if(monitorStates.begin(), monitorStates.end(), [mon](const auto& other) { return other->monitor == mon; }); auto it = std::find_if(monitorStates.begin(), monitorStates.end(), [mon](const auto& other) { return other->monitor == mon; });
if (it == monitorStates.end()) if (it == monitorStates.end())
return monitorStates.emplace_back(makeShared<CPointerManager::SMonitorPointerState>(mon)); return monitorStates.emplace_back(makeShared<CPointerManager::SMonitorPointerState>(mon));
@@ -266,19 +247,16 @@ void CPointerManager::resetCursorImage(bool apply) {
} }
void CPointerManager::updateCursorBackend() { void CPointerManager::updateCursorBackend() {
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
const auto CURSORBOX = getCursorBoxGlobal(); const auto CURSORBOX = getCursorBoxGlobal();
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
auto state = stateFor(m);
if (!m->m_bEnabled || !m->dpmsStatus) { if (!m->m_bEnabled || !m->dpmsStatus) {
Debug::log(TRACE, "Not updating hw cursors: disabled / dpms off display"); Debug::log(TRACE, "Not updating hw cursors: disabled / dpms off display");
continue; continue;
} }
auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty(); auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty();
auto state = stateFor(m);
if (!CROSSES) { if (!CROSSES) {
if (state->cursorFrontBuffer) if (state->cursorFrontBuffer)
@@ -287,7 +265,7 @@ void CPointerManager::updateCursorBackend() {
continue; continue;
} }
if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) { if (state->softwareLocks > 0 || g_pConfigManager->shouldUseSoftwareCursors() || !attemptHardwareCursor(state)) {
Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName);
state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock());
state->hardwareFailed = true; state->hardwareFailed = true;
@@ -330,7 +308,7 @@ void CPointerManager::onCursorMoved() {
continue; continue;
const auto CURSORPOS = getCursorPosForMonitor(m); const auto CURSORPOS = getCursorPosForMonitor(m);
m->output->moveCursor(CURSORPOS); m->output->moveCursor(CURSORPOS, m->shouldSkipScheduleFrameOnMouseEvent());
} }
if (recalc) if (recalc)
@@ -344,7 +322,7 @@ bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerS
return false; return false;
const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock()); const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock());
state->monitor->output->moveCursor(CURSORPOS); state->monitor->output->moveCursor(CURSORPOS, state->monitor->shouldSkipScheduleFrameOnMouseEvent());
auto texture = getCurrentCursorTexture(); auto texture = getCurrentCursorTexture();
@@ -387,16 +365,15 @@ bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquam
state->cursorFrontBuffer = buf; state->cursorFrontBuffer = buf;
g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent())
g_pCompositor->scheduleFrameForMonitor(state->monitor.lock(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
return true; return true;
} }
SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) { SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
auto output = state->monitor->output; auto maxSize = state->monitor->output->cursorPlaneSize();
auto const& cursorSize = currentCursorImage.size;
auto maxSize = output->cursorPlaneSize();
auto cursorSize = currentCursorImage.size;
if (maxSize == Vector2D{}) if (maxSize == Vector2D{})
return nullptr; return nullptr;
@@ -443,10 +420,8 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
return nullptr; return nullptr;
} }
CRegion damage = {0, 0, INT16_MAX, INT16_MAX};
g_pHyprRenderer->makeEGLCurrent(); g_pHyprRenderer->makeEGLCurrent();
g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor;
auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format);
if (!RBO) { if (!RBO) {
@@ -503,7 +478,7 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
RBO->bind(); RBO->bind();
g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO); g_pHyprOpenGL->beginSimple(state->monitor.lock(), {0, 0, INT16_MAX, INT16_MAX}, RBO);
g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F}); g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F});
CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()}; CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()};
@@ -514,14 +489,14 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
g_pHyprOpenGL->end(); g_pHyprOpenGL->end();
glFlush(); glFlush();
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; g_pHyprOpenGL->m_RenderData.pMonitor.reset();
g_pHyprRenderer->onRenderbufferDestroy(RBO.get()); g_pHyprRenderer->onRenderbufferDestroy(RBO.get());
return buf; return buf;
} }
void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) { void CPointerManager::renderSoftwareCursorsFor(PHLMONITOR pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) {
if (!hasCursor()) if (!hasCursor())
return; return;
@@ -556,7 +531,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec*
currentCursorImage.surface->resource()->frame(now); currentCursorImage.surface->resource()->frame(now);
} }
Vector2D CPointerManager::getCursorPosForMonitor(SP<CMonitor> pMonitor) { Vector2D CPointerManager::getCursorPosForMonitor(PHLMONITOR pMonitor) {
return CBox{pointerPos - pMonitor->vecPosition, {0, 0}} return CBox{pointerPos - pMonitor->vecPosition, {0, 0}}
.transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x / pMonitor->scale, .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x / pMonitor->scale,
pMonitor->vecTransformedSize.y / pMonitor->scale) pMonitor->vecTransformedSize.y / pMonitor->scale)
@@ -564,7 +539,7 @@ Vector2D CPointerManager::getCursorPosForMonitor(SP<CMonitor> pMonitor) {
pMonitor->scale; pMonitor->scale;
} }
Vector2D CPointerManager::transformedHotspot(SP<CMonitor> pMonitor) { Vector2D CPointerManager::transformedHotspot(PHLMONITOR pMonitor) {
if (!pMonitor->cursorSwapchain) if (!pMonitor->cursorSwapchain)
return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors
@@ -574,7 +549,7 @@ Vector2D CPointerManager::transformedHotspot(SP<CMonitor> pMonitor) {
.pos(); .pos();
} }
CBox CPointerManager::getCursorBoxLogicalForMonitor(SP<CMonitor> pMonitor) { CBox CPointerManager::getCursorBoxLogicalForMonitor(PHLMONITOR pMonitor) {
return getCursorBoxGlobal().translate(-pMonitor->vecPosition); return getCursorBoxGlobal().translate(-pMonitor->vecPosition);
} }
@@ -659,15 +634,13 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) {
} }
void CPointerManager::damageIfSoftware() { void CPointerManager::damageIfSoftware() {
auto b = getCursorBoxGlobal(); auto b = getCursorBoxGlobal().expand(4);
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
for (auto const& mw : monitorStates) { for (auto const& mw : monitorStates) {
if (mw->monitor.expired() || !mw->monitor->output) if (mw->monitor.expired() || !mw->monitor->output)
continue; continue;
if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { if ((mw->softwareLocks > 0 || mw->hardwareFailed || g_pConfigManager->shouldUseSoftwareCursors()) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) {
g_pHyprRenderer->damageBox(&b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent()); g_pHyprRenderer->damageBox(&b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent());
break; break;
} }
@@ -678,8 +651,11 @@ void CPointerManager::warpTo(const Vector2D& logical) {
damageIfSoftware(); damageIfSoftware();
pointerPos = closestValid(logical); pointerPos = closestValid(logical);
if (!g_pInputManager->isLocked()) {
recheckEnteredOutputs(); recheckEnteredOutputs();
onCursorMoved(); onCursorMoved();
}
damageIfSoftware(); damageIfSoftware();
} }
@@ -693,7 +669,7 @@ void CPointerManager::move(const Vector2D& deltaLogical) {
void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) { void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) {
SP<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor.lock(); PHLMONITOR currentMonitor = g_pCompositor->m_pLastMonitor.lock();
if (!currentMonitor || !dev) if (!currentMonitor || !dev)
return; return;
@@ -861,6 +837,13 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
}); });
listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) { listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) {
bool shouldSkip = false;
if (!g_pSeatManager->mouse.expired() && g_pInputManager->isLocked()) {
auto PMONITOR = g_pCompositor->m_pLastMonitor.get();
shouldSkip = PMONITOR && PMONITOR->shouldSkipScheduleFrameOnMouseEvent();
}
g_pSeatManager->isPointerFrameSkipped = shouldSkip;
if (!g_pSeatManager->isPointerFrameSkipped)
g_pSeatManager->sendPointerFrame(); g_pSeatManager->sendPointerFrame();
}); });
@@ -1063,7 +1046,7 @@ void CPointerManager::detachTablet(SP<CTablet> tablet) {
std::erase_if(tabletListeners, [tablet](const auto& e) { return e->tablet.expired() || e->tablet == tablet; }); std::erase_if(tabletListeners, [tablet](const auto& e) { return e->tablet.expired() || e->tablet == tablet; });
} }
void CPointerManager::damageCursor(SP<CMonitor> pMonitor) { void CPointerManager::damageCursor(PHLMONITOR pMonitor) {
for (auto const& mw : monitorStates) { for (auto const& mw : monitorStates) {
if (mw->monitor != pMonitor) if (mw->monitor != pMonitor)
continue; continue;
@@ -1082,3 +1065,22 @@ void CPointerManager::damageCursor(SP<CMonitor> pMonitor) {
Vector2D CPointerManager::cursorSizeLogical() { Vector2D CPointerManager::cursorSizeLogical() {
return currentCursorImage.size / currentCursorImage.scale; return currentCursorImage.size / currentCursorImage.scale;
} }
void CPointerManager::storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) {
storedTime = time;
storedDelta += delta;
storedUnaccel += deltaUnaccel;
}
void CPointerManager::setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) {
storedTime = time;
storedDelta = delta;
storedUnaccel = deltaUnaccel;
}
void CPointerManager::sendStoredMovement() {
PROTO::relativePointer->sendRelativeMotion((uint64_t)storedTime * 1000, storedDelta, storedUnaccel);
storedTime = 0;
storedDelta = Vector2D{};
storedUnaccel = Vector2D{};
}

View File

@@ -43,24 +43,25 @@ class CPointerManager {
void setCursorSurface(SP<CWLSurface> buf, const Vector2D& hotspot); void setCursorSurface(SP<CWLSurface> buf, const Vector2D& hotspot);
void resetCursorImage(bool apply = true); void resetCursorImage(bool apply = true);
void lockSoftwareForMonitor(SP<CMonitor> pMonitor); void lockSoftwareForMonitor(PHLMONITOR pMonitor);
void unlockSoftwareForMonitor(SP<CMonitor> pMonitor); void unlockSoftwareForMonitor(PHLMONITOR pMonitor);
void lockSoftwareForMonitor(CMonitor* pMonitor);
void unlockSoftwareForMonitor(CMonitor* pMonitor);
void lockSoftwareAll(); void lockSoftwareAll();
void unlockSoftwareAll(); void unlockSoftwareAll();
bool softwareLockedFor(SP<CMonitor> pMonitor); bool softwareLockedFor(PHLMONITOR pMonitor);
void renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */); void renderSoftwareCursorsFor(PHLMONITOR pMonitor, timespec* now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */);
// this is needed e.g. during screensharing where // this is needed e.g. during screensharing where
// the software cursors aren't locked during the cursor move, but they // the software cursors aren't locked during the cursor move, but they
// are rendered later. // are rendered later.
void damageCursor(SP<CMonitor> pMonitor); void damageCursor(PHLMONITOR pMonitor);
// //
Vector2D position(); Vector2D position();
Vector2D cursorSizeLogical(); Vector2D cursorSizeLogical();
void storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel);
void setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel);
void sendStoredMovement();
void recheckEnteredOutputs(); void recheckEnteredOutputs();
@@ -77,13 +78,13 @@ class CPointerManager {
Vector2D closestValid(const Vector2D& pos); Vector2D closestValid(const Vector2D& pos);
// returns the thing in device coordinates. Is NOT offset by the hotspot, relies on set_cursor with hotspot. // returns the thing in device coordinates. Is NOT offset by the hotspot, relies on set_cursor with hotspot.
Vector2D getCursorPosForMonitor(SP<CMonitor> pMonitor); Vector2D getCursorPosForMonitor(PHLMONITOR pMonitor);
// returns the thing in logical coordinates of the monitor // returns the thing in logical coordinates of the monitor
CBox getCursorBoxLogicalForMonitor(SP<CMonitor> pMonitor); CBox getCursorBoxLogicalForMonitor(PHLMONITOR pMonitor);
// returns the thing in global coords // returns the thing in global coords
CBox getCursorBoxGlobal(); CBox getCursorBoxGlobal();
Vector2D transformedHotspot(SP<CMonitor> pMonitor); Vector2D transformedHotspot(PHLMONITOR pMonitor);
SP<CTexture> getCurrentCursorTexture(); SP<CTexture> getCurrentCursorTexture();
@@ -154,11 +155,15 @@ class CPointerManager {
Vector2D pointerPos = {0, 0}; Vector2D pointerPos = {0, 0};
uint64_t storedTime = 0;
Vector2D storedDelta = {0, 0};
Vector2D storedUnaccel = {0, 0};
struct SMonitorPointerState { struct SMonitorPointerState {
SMonitorPointerState(SP<CMonitor> m) : monitor(m) {} SMonitorPointerState(PHLMONITOR m) : monitor(m) {}
~SMonitorPointerState() {} ~SMonitorPointerState() {}
WP<CMonitor> monitor; PHLMONITORREF monitor;
int softwareLocks = 0; int softwareLocks = 0;
bool hardwareFailed = false; bool hardwareFailed = false;
@@ -171,7 +176,7 @@ class CPointerManager {
}; };
std::vector<SP<SMonitorPointerState>> monitorStates; std::vector<SP<SMonitorPointerState>> monitorStates;
SP<SMonitorPointerState> stateFor(SP<CMonitor> mon); SP<SMonitorPointerState> stateFor(PHLMONITOR mon);
bool attemptHardwareCursor(SP<SMonitorPointerState> state); bool attemptHardwareCursor(SP<SMonitorPointerState> state);
SP<Aquamarine::IBuffer> renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture); SP<Aquamarine::IBuffer> renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture);
bool setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf); bool setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf);

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