Compare commits
340 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c5e28ebcfe | ||
|
c942ce6dce | ||
|
5e5d7e2abc | ||
|
19c90048d6 | ||
|
3f5f5f5491 | ||
|
2a2da6082e | ||
|
c4f52d1979 | ||
|
38576d651a | ||
|
72d78eff95 | ||
|
a958884b52 | ||
|
bb933dcf04 | ||
|
bc15a8f600 | ||
|
6c24cee88f | ||
|
d00c658405 | ||
|
dc44bd7113 | ||
|
045c3fbd85 | ||
|
b7b13623ba | ||
|
164e92f8e3 | ||
|
3e67ee0f5f | ||
|
893c55217b | ||
|
c58fcfbce2 | ||
|
7ea555da7f | ||
|
6c53d4d82f | ||
|
5da9591775 | ||
|
f1ec0ba467 | ||
|
a065b481f3 | ||
|
0fc9d45e4b | ||
|
66330281ff | ||
|
220144276b | ||
|
0a1632a79f | ||
|
981296f101 | ||
|
0c28d4e334 | ||
|
335506d555 | ||
|
b0f98a3d3e | ||
|
2ed032a7fd | ||
|
739c5bc98c | ||
|
26cd1bf949 | ||
|
18a35b1406 | ||
|
7e41e5146d | ||
|
c3882bb832 | ||
|
e7a5db4852 | ||
|
a01949dd28 | ||
|
fa886d8b11 | ||
|
3f58e77e75 | ||
|
300d77edd9 | ||
|
c9ea600baa | ||
|
3e930a568a | ||
|
024d4ddc74 | ||
|
717d5b3cc2 | ||
|
0a4ade01d3 | ||
|
5920c6a6b8 | ||
|
4c34e4aac2 | ||
|
d1c80c31c8 | ||
|
1290507ac4 | ||
|
e52d3fa852 | ||
|
ceecdd0fd5 | ||
|
6c4e2489a0 | ||
|
bf71026b8d | ||
|
77161fdbef | ||
|
ce072638e9 | ||
|
95769a3c54 | ||
|
067df84388 | ||
|
8e2a62e53b | ||
|
669ea8a373 | ||
|
082bf00254 | ||
|
d6f1b151b2 | ||
|
fb87e332c5 | ||
|
b1e2ca04a0 | ||
|
05dd204c5f | ||
|
31e1287da2 | ||
|
a4c1f4a03d | ||
|
0ee69058c4 | ||
|
f8a081b56d | ||
|
bdfa8ab856 | ||
|
08152477dc | ||
|
12985fa0d8 | ||
|
9c48c322d4 | ||
|
7a76ab01d1 | ||
|
f3c92e75c8 | ||
|
07c7235b72 | ||
|
12da0fc84f | ||
|
9d89b7109d | ||
|
063708df26 | ||
|
8ccbd272cc | ||
|
28272d2d74 | ||
|
c701767038 | ||
|
cc94123fa7 | ||
|
2a08f2ba84 | ||
|
689fced8b9 | ||
|
acf0b536a6 | ||
|
1762e9c6ec | ||
|
964f1a438d | ||
|
508262b7db | ||
|
d72ea5f2a7 | ||
|
328ab43165 | ||
|
d2289d8327 | ||
|
be89d6faa9 | ||
|
8811f4b69a | ||
|
52db216608 | ||
|
1e311c947e | ||
|
7ce781e87c | ||
|
b2c3440477 | ||
|
f115ba94d2 | ||
|
6e3a494d1d | ||
|
555afea73c | ||
|
4937352761 | ||
|
f590505daf | ||
|
f801d15947 | ||
|
e63b4b18aa | ||
|
1698d336f2 | ||
|
fbba8757cb | ||
|
6916d0a6a3 | ||
|
bcec082a1c | ||
|
2e111c8cf9 | ||
|
b39dcfa497 | ||
|
4bff762d97 | ||
|
b1c0f1cc01 | ||
|
1e7eb3a5a5 | ||
|
097f561e41 | ||
|
a31433c215 | ||
|
51b1b17fcb | ||
|
29cdd7de1f | ||
|
4bc669f933 | ||
|
f4f3aa2e50 | ||
|
c198d744b7 | ||
|
1c460e98f8 | ||
|
489ac40abd | ||
|
e3373669e5 | ||
|
f26d7aa58d | ||
|
e2c286548d | ||
|
60f81b8a23 | ||
|
98034fea3c | ||
|
21f7f32dc9 | ||
|
ffd7217243 | ||
|
bc3f5b94eb | ||
|
f7a3453487 | ||
|
1742605eb8 | ||
|
81fe2ae7f1 | ||
|
dfcfb92ec6 | ||
|
9815402074 | ||
|
a14f6b570f | ||
|
7f35bff720 | ||
|
54a8329936 | ||
|
f9cfec8abb | ||
|
f534ac3fc4 | ||
|
9103af317e | ||
|
5824b0f305 | ||
|
e9528fc214 | ||
|
6f83856025 | ||
|
d92da7959a | ||
|
f27054c13e | ||
|
bdbd8d965d | ||
|
bfb1e876a8 | ||
|
ca59bd5739 | ||
|
f389f77015 | ||
|
8c3613632a | ||
|
c1ef361e02 | ||
|
35e80a64a6 | ||
|
e83bf4f7b7 | ||
|
c353b7c4f7 | ||
|
d9757b61bf | ||
|
28410922da | ||
|
cfc652e17d | ||
|
dbccbabac5 | ||
|
9a6956fe67 | ||
|
af0c8e299b | ||
|
7fbe016c15 | ||
|
0ebee80bca | ||
|
c4283abb9f | ||
|
94aeb06d6b | ||
|
ea3fd13e24 | ||
|
dad8ffd576 | ||
|
fc5ca391ad | ||
|
e5eb1bdf01 | ||
|
ddf022d61c | ||
|
13d9854897 | ||
|
cd73dda16e | ||
|
02c9a2d769 | ||
|
7ea37c9dc9 | ||
|
86be75dd97 | ||
|
030ed27cc8 | ||
|
e793f10b8b | ||
|
d62e7a5125 | ||
|
fe9c8d8745 | ||
|
df82625206 | ||
|
1763566308 | ||
|
e4790e3f8e | ||
|
69a4f08dbe | ||
|
c6b1d82c70 | ||
|
301b48b740 | ||
|
fae47ef462 | ||
|
5fc0b772c7 | ||
|
13f6f0b923 | ||
|
7e8bcd675d | ||
|
683a4b07c5 | ||
|
5261a8df81 | ||
|
289d952a6e | ||
|
294e51a857 | ||
|
cdcc5aba06 | ||
|
e3e7e1fdda | ||
|
fbf5ba87ce | ||
|
a8dae8f5e1 | ||
|
a42b984f51 | ||
|
e5ac970d6e | ||
|
770956b092 | ||
|
3cca36e773 | ||
|
ef490965a2 | ||
|
b7ab15dc80 | ||
|
9c3f3b0018 | ||
|
8d68d6bfa5 | ||
|
60834a4687 | ||
|
7f52db806c | ||
|
305b1419c8 | ||
|
d5950f7719 | ||
|
0608791480 | ||
|
2a002f31e4 | ||
|
2a3429d4cf | ||
|
95abf1220f | ||
|
b500e5699b | ||
|
61378380ee | ||
|
890307532c | ||
|
f33d73b9cf | ||
|
927da86e3e | ||
|
cca3c64301 | ||
|
6e5c78bf63 | ||
|
e4bb5fa4af | ||
|
cb258c82f4 | ||
|
658f718fa3 | ||
|
334a0f03ee | ||
|
289d4241be | ||
|
a6ccd36147 | ||
|
3d9ca6381d | ||
|
f085ed4454 | ||
|
ded174d6e5 | ||
|
181f651de2 | ||
|
8a6e428d32 | ||
|
1fd82e37a7 | ||
|
f9202f791e | ||
|
84ab8d11e8 | ||
|
60bda7ee3d | ||
|
939696f97e | ||
|
cbadf3e3f3 | ||
|
1ed4f1cb25 | ||
|
5d4ff60f53 | ||
|
504ebe1b37 | ||
|
cf1886ca44 | ||
|
341e04a36c | ||
|
d7514412d8 | ||
|
7447be8220 | ||
|
4644de2269 | ||
|
3656045ad8 | ||
|
15316aaa31 | ||
|
cfd68af5b6 | ||
|
4f804d5f96 | ||
|
e6f7724ab0 | ||
|
e65f52bf2d | ||
|
c51b3fb06f | ||
|
3ff59e7e1d | ||
|
3d0d3b6343 | ||
|
2e3f0d5991 | ||
|
91e8c42843 | ||
|
4b4bd90b14 | ||
|
7009dc9184 | ||
|
b7840c6461 | ||
|
5a90911b70 | ||
|
0e5f14d8d2 | ||
|
df990c80e2 | ||
|
352574d862 | ||
|
bfcc2adbda | ||
|
9002657bcc | ||
|
3e93fdf779 | ||
|
bc7e488a4c | ||
|
8b1069b330 | ||
|
61fd75b55e | ||
|
7b3d039388 | ||
|
12d79d6342 | ||
|
08e3519747 | ||
|
5cd7e4587e | ||
|
72987dee88 | ||
|
754eaf5b8b | ||
|
df17991b1c | ||
|
791e1b96b3 | ||
|
02b4a9bded | ||
|
4d403dac32 | ||
|
f40e382fc6 | ||
|
b86ed02d8a | ||
|
17339e0ae9 | ||
|
5eeec8860e | ||
|
9f20a15955 | ||
|
c4365f20ed | ||
|
307dd8f511 | ||
|
8342bac697 | ||
|
3c964a9fdc | ||
|
f14c5ea5c5 | ||
|
dcd7a92b01 | ||
|
b6516bad02 | ||
|
13d9a637d6 | ||
|
4cee94b91c | ||
|
c4da4b026d | ||
|
babb9c07b0 | ||
|
6b92144f15 | ||
|
8d31c84483 | ||
|
d484506600 | ||
|
b240704bee | ||
|
71166ef40b | ||
|
252aaaecfa | ||
|
f92a86af53 | ||
|
2ba2c8aeee | ||
|
955009655d | ||
|
d7d333d162 | ||
|
f5b2fd2bc3 | ||
|
44ee9915e3 | ||
|
9f2bde925b | ||
|
7904188de9 | ||
|
666ee61c13 | ||
|
7e033e48ac | ||
|
d8dbdc4a01 | ||
|
d3acf8da3b | ||
|
aeeeace102 | ||
|
880996b053 | ||
|
4d6d662c67 | ||
|
1512b81126 | ||
|
4f26c4e1eb | ||
|
3c33d4b9dd | ||
|
bd3ea8dcb5 | ||
|
813af393f1 | ||
|
583b05a8c6 | ||
|
1607e96704 | ||
|
1a4f23eb2f | ||
|
42ab06e7c8 | ||
|
46753b1f22 | ||
|
d4e68ab602 | ||
|
37b76cd1ca | ||
|
0be36cd02d | ||
|
4e0e8d933e | ||
|
c7ba460687 | ||
|
3a189c265d | ||
|
069880e374 | ||
|
fa5e812304 | ||
|
33444e1e5e |
17
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -9,12 +9,23 @@ body:
|
||||
|
||||
---
|
||||
|
||||
- type: input
|
||||
- type: textarea
|
||||
id: ver
|
||||
attributes:
|
||||
label: Hyprland Version
|
||||
description: "Paste here the output of `hyprctl version`."
|
||||
placeholder: Hyprland, built from branch main at commit...
|
||||
description: "Paste here the output of `hyprctl version`. For hyprland after 0.34.0, paste `hyprctl systeminfo` instead."
|
||||
value: "<details>
|
||||
<summary>System/Version info</summary>
|
||||
|
||||
|
||||
```sh
|
||||
|
||||
<Paste the output of the command here>
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
15
.github/actions/setup_base/action.yml
vendored
@@ -12,6 +12,7 @@ runs:
|
||||
- name: Get required pacman pkgs
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i -e "1i [extra-testing]\nInclude = /etc/pacman.d/mirrorlist" "/etc/pacman.conf"
|
||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||
pacman --noconfirm --noprogressbar -Syyu
|
||||
pacman --noconfirm --noprogressbar -Sy \
|
||||
@@ -23,6 +24,7 @@ runs:
|
||||
glm \
|
||||
glslang \
|
||||
go \
|
||||
hyprlang \
|
||||
jq \
|
||||
libc++ \
|
||||
libdisplay-info \
|
||||
@@ -50,7 +52,18 @@ runs:
|
||||
wayland-protocols \
|
||||
xcb-util-errors \
|
||||
xcb-util-renderutil \
|
||||
xcb-util-wm
|
||||
xcb-util-wm \
|
||||
libzip \
|
||||
librsvg
|
||||
|
||||
- name: Get hyprcursor-git
|
||||
shell: bash
|
||||
run: |
|
||||
git clone https://github.com/hyprwm/hyprcursor --recursive
|
||||
cd hyprcursor
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
cmake --install build
|
||||
|
||||
- name: Get Xorg pacman pkgs
|
||||
shell: bash
|
||||
|
1
.github/workflows/ci.yaml
vendored
@@ -31,6 +31,7 @@ jobs:
|
||||
cp ./LICENSE hyprland/
|
||||
cp build/Hyprland hyprland/
|
||||
cp build/hyprctl/hyprctl hyprland/
|
||||
cp build/hyprpm/hyprpm hyprland/
|
||||
cp subprojects/wlroots/build/libwlroots.so.13032 hyprland/
|
||||
cp build/Hyprland hyprland/
|
||||
cp -r example/ hyprland/
|
||||
|
2
.github/workflows/nix-build.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
- uses: cachix/install-nix-action@v25
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
|
41
.github/workflows/security-checks.yml
vendored
@@ -24,44 +24,3 @@ jobs:
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
||||
|
||||
codeql:
|
||||
name: CodeQL
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: archlinux
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository actions
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Setup base
|
||||
uses: ./.github/actions/setup_base
|
||||
with:
|
||||
INSTALL_XORG_PKGS: true
|
||||
|
||||
- name: Build Hyprland
|
||||
run: |
|
||||
make all
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
28
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
|
||||
#
|
||||
# You can adjust the behavior by modifying this file.
|
||||
# For more information, see:
|
||||
# https://github.com/actions/stale
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '7 */4 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.STALEBOT_PAT }}
|
||||
stale-issue-label: 'stale'
|
||||
stale-pr-label: 'stale'
|
||||
operations-per-run: 40
|
||||
days-before-close: -1
|
2
.gitignore
vendored
@@ -31,3 +31,5 @@ gmon.out
|
||||
PKGBUILD
|
||||
|
||||
src/version.h
|
||||
|
||||
.direnv
|
||||
|
@@ -57,8 +57,8 @@ ExternalProject_Add(
|
||||
wlroots
|
||||
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||
PATCH_COMMAND sed -E -i -e "s/(soversion = 13)([^032]|$$)/soversion = 13032/g" meson.build
|
||||
CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> --reconfigure
|
||||
PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build
|
||||
CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$<IF:$<BOOL:${NO_XWAYLAND}>,disabled,enabled> -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none>
|
||||
BUILD_COMMAND ninja -C build
|
||||
BUILD_ALWAYS true
|
||||
BUILD_IN_SOURCE true
|
||||
@@ -101,7 +101,7 @@ message(STATUS "Checking deps...")
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1) # we do not check for wlroots, as we provide it ourselves
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2 hyprcursor) # we do not check for wlroots, as we provide it ourselves
|
||||
|
||||
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||
|
||||
|
34
Makefile
@@ -1,22 +1,22 @@
|
||||
PREFIX = /usr/local
|
||||
|
||||
legacyrenderer:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
chmod -R 777 ./build
|
||||
|
||||
legacyrendererdebug:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
chmod -R 777 ./build
|
||||
|
||||
release:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
chmod -R 777 ./build
|
||||
|
||||
debug:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -S . -B ./build -G Ninja
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
chmod -R 777 ./build
|
||||
|
||||
@@ -42,10 +42,10 @@ install:
|
||||
chmod 755 ${PREFIX}/bin/Hyprland
|
||||
chmod 755 ${PREFIX}/bin/hyprctl
|
||||
chmod 755 ${PREFIX}/bin/hyprpm
|
||||
ln -s -r ${PREFIX}/bin/Hyprland ${PREFIX}/bin/hyprland
|
||||
cd ${PREFIX}/bin && ln -sf Hyprland hyprland
|
||||
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
|
||||
mkdir -p ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_* ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall* ${PREFIX}/share/hyprland
|
||||
mkdir -p ${PREFIX}/share/xdg-desktop-portal
|
||||
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
|
||||
|
||||
@@ -60,6 +60,7 @@ install:
|
||||
uninstall:
|
||||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||
rm -f ${PREFIX}/bin/Hyprland
|
||||
rm -f ${PREFIX}/bin/hyprland
|
||||
rm -f ${PREFIX}/bin/hyprctl
|
||||
rm -f ${PREFIX}/bin/hyprpm
|
||||
rm -f ${PREFIX}/lib/libwlroots.so.13032
|
||||
@@ -105,3 +106,24 @@ man:
|
||||
--variable=section:1 \
|
||||
--from rst \
|
||||
--to man > ./docs/hyprctl.1
|
||||
|
||||
asan:
|
||||
@echo -en "!!WARNING!!\nOnly run this in the TTY.\n"
|
||||
@pidof Hyprland > /dev/null && echo -ne "Refusing to run with Hyprland running.\n" || echo ""
|
||||
@pidof Hyprland > /dev/null && exit 1 || echo ""
|
||||
|
||||
rm -rf ./wayland
|
||||
git reset --hard
|
||||
|
||||
git clone --recursive https://gitlab.freedesktop.org/wayland/wayland
|
||||
cd wayland && patch -p1 < ../scripts/waylandStatic.diff && meson setup build --buildtype=debug -Db_sanitize=address -Ddocumentation=false && ninja -C build && cd ..
|
||||
cp ./wayland/build/src/libwayland-server.a .
|
||||
@echo "Wayland done"
|
||||
|
||||
patch -p1 < ./scripts/hyprlandStaticAsan.diff
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DWITH_ASAN:STRING=True -DUSE_TRACY:STRING=False -DUSE_TRACY_GPU:STRING=False -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
@echo "Hyprland done"
|
||||
|
||||
ASAN_OPTIONS="detect_odr_violation=0,log_path=asan.log" HYPRLAND_NO_CRASHREPORTER=1 ./build/Hyprland -c ~/.config/hypr/hyprland.conf
|
||||
|
||||
|
@@ -124,7 +124,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
|
||||
[Wayfire]: https://github.com/WayfireWM/wayfire
|
||||
[TinyWl]: https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/tinywl/tinywl.c
|
||||
[Sway]: https://github.com/swaywm/sway
|
||||
[DWL]: https://github.com/djpohly/dwl
|
||||
[DWL]: https://codeberg.org/dwl/dwl
|
||||
|
||||
<!----------------------------------{ Images }--------------------------------->
|
||||
|
||||
|
@@ -1,9 +1,7 @@
|
||||
wallpaper_types = ['', 'anime_', 'anime2_']
|
||||
wallpapers = ['0', '1', '2']
|
||||
|
||||
foreach type : wallpaper_types
|
||||
foreach size : [2, 4, 8]
|
||||
install_data(f'wall_@type@@size@K.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
|
||||
endforeach
|
||||
foreach type : wallpapers
|
||||
install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
|
||||
endforeach
|
||||
|
||||
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')
|
||||
|
BIN
assets/wall0.png
Normal file
After Width: | Height: | Size: 14 MiB |
BIN
assets/wall1.png
Normal file
After Width: | Height: | Size: 5.9 MiB |
BIN
assets/wall2.png
Normal file
After Width: | Height: | Size: 27 MiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 511 KiB |
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 502 KiB |
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 1.6 MiB |
@@ -47,7 +47,7 @@ basically, directories in /tmp/hypr are your sessions.
|
||||
|
||||
## Obtaining the Hyprland Crash Report (v0.22.0beta and up)
|
||||
|
||||
If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `~/.hyprland`
|
||||
If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `$HOME/.cache/hyprland`.
|
||||
|
||||
Go to the crash report directory and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.
|
||||
|
||||
|
@@ -1,8 +0,0 @@
|
||||
# compile with HYPRLAND_HEADERS=<path_to_hl> make all
|
||||
# make sure that the path above is to the root hl repo directory, NOT src/
|
||||
# and that you have ran `make protocols` in the hl dir.
|
||||
|
||||
all:
|
||||
$(CXX) -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g `pkg-config --cflags pixman-1 libdrm hyprland` -std=c++2b
|
||||
clean:
|
||||
rm ./examplePlugin.so
|
@@ -1,74 +0,0 @@
|
||||
#include "customDecoration.hpp"
|
||||
#include <hyprland/src/Window.hpp>
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include "globals.hpp"
|
||||
|
||||
CCustomDecoration::CCustomDecoration(CWindow* pWindow) {
|
||||
m_pWindow = pWindow;
|
||||
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
||||
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
||||
}
|
||||
|
||||
CCustomDecoration::~CCustomDecoration() {
|
||||
damageEntire();
|
||||
}
|
||||
|
||||
SWindowDecorationExtents CCustomDecoration::getWindowDecorationExtents() {
|
||||
return m_seExtents;
|
||||
}
|
||||
|
||||
void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
|
||||
if (!g_pCompositor->windowValidMapped(m_pWindow))
|
||||
return;
|
||||
|
||||
if (!m_pWindow->m_sSpecialRenderData.decorate)
|
||||
return;
|
||||
|
||||
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color")->intValue;
|
||||
static auto* const PROUNDING = &HyprlandAPI::getConfigValue(PHANDLE, "decoration:rounding")->intValue;
|
||||
static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
|
||||
|
||||
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ?
|
||||
0 :
|
||||
(m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
|
||||
|
||||
// draw the border
|
||||
CBox fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE),
|
||||
(int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
|
||||
|
||||
fullBox.x -= pMonitor->vecPosition.x;
|
||||
fullBox.y -= pMonitor->vecPosition.y;
|
||||
|
||||
m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2},
|
||||
{fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2,
|
||||
fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}};
|
||||
|
||||
fullBox.x += offset.x;
|
||||
fullBox.y += offset.y;
|
||||
|
||||
if (fullBox.width < 1 || fullBox.height < 1)
|
||||
return; // don't draw invisible shadows
|
||||
|
||||
g_pHyprOpenGL->scissor((CBox*)nullptr);
|
||||
|
||||
fullBox.scale(pMonitor->scale);
|
||||
g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
|
||||
}
|
||||
|
||||
eDecorationType CCustomDecoration::getDecorationType() {
|
||||
return DECORATION_CUSTOM;
|
||||
}
|
||||
|
||||
void CCustomDecoration::updateWindow(CWindow* pWindow) {
|
||||
|
||||
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
||||
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
||||
|
||||
damageEntire();
|
||||
}
|
||||
|
||||
void CCustomDecoration::damageEntire() {
|
||||
CBox dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y),
|
||||
(int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
|
||||
g_pHyprRenderer->damageBox(&dm);
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define WLR_USE_UNSTABLE
|
||||
|
||||
#include <hyprland/src/render/decorations/IHyprWindowDecoration.hpp>
|
||||
|
||||
class CCustomDecoration : public IHyprWindowDecoration {
|
||||
public:
|
||||
CCustomDecoration(CWindow*);
|
||||
virtual ~CCustomDecoration();
|
||||
|
||||
virtual SWindowDecorationExtents getWindowDecorationExtents();
|
||||
|
||||
virtual void draw(CMonitor*, float a, const Vector2D& offset);
|
||||
|
||||
virtual eDecorationType getDecorationType();
|
||||
|
||||
virtual void updateWindow(CWindow*);
|
||||
|
||||
virtual void damageEntire();
|
||||
|
||||
private:
|
||||
SWindowDecorationExtents m_seExtents;
|
||||
|
||||
CWindow* m_pWindow = nullptr;
|
||||
|
||||
Vector2D m_vLastWindowPos;
|
||||
Vector2D m_vLastWindowSize;
|
||||
};
|
@@ -1,80 +0,0 @@
|
||||
#include "customLayout.hpp"
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include "globals.hpp"
|
||||
|
||||
void CHyprCustomLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
const auto SIZE = PMONITOR->vecSize;
|
||||
|
||||
// these are used for focus and move calculations, and are *required* to touch for moving focus to work properly.
|
||||
pWindow->m_vPosition = Vector2D{(SIZE.x / 2.0) * (m_vWindowData.size() % 2), (SIZE.y / 2.0) * (int)(m_vWindowData.size() > 1)};
|
||||
pWindow->m_vSize = SIZE / 2.0;
|
||||
|
||||
// this is the actual pos and size of the window (where it's rendered)
|
||||
pWindow->m_vRealPosition = pWindow->m_vPosition + Vector2D{10, 10};
|
||||
pWindow->m_vRealSize = pWindow->m_vSize - Vector2D{20, 20};
|
||||
|
||||
const auto PDATA = &m_vWindowData.emplace_back();
|
||||
PDATA->pWindow = pWindow;
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
std::erase_if(m_vWindowData, [&](const auto& other) { return other.pWindow == pWindow; });
|
||||
}
|
||||
|
||||
bool CHyprCustomLayout::isWindowTiled(CWindow* pWindow) {
|
||||
return std::find_if(m_vWindowData.begin(), m_vWindowData.end(), [&](const auto& other) { return other.pWindow == pWindow; }) != m_vWindowData.end();
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::recalculateMonitor(const int& eIdleInhibitMode) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::recalculateWindow(CWindow* pWindow) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::resizeActiveWindow(const Vector2D& delta, CWindow* pWindow) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mode, bool on) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
std::any CHyprCustomLayout::layoutMessage(SLayoutMessageHeader header, std::string content) {
|
||||
return "";
|
||||
}
|
||||
|
||||
SWindowRenderLayoutHints CHyprCustomLayout::requestRenderHints(CWindow* pWindow) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
std::string CHyprCustomLayout::getLayoutName() {
|
||||
return "custom";
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::onEnable() {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || w->m_bIsFloating)
|
||||
continue;
|
||||
|
||||
onWindowCreatedTiling(w.get());
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::onDisable() {
|
||||
m_vWindowData.clear();
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define WLR_USE_UNSTABLE
|
||||
|
||||
#include <hyprland/src/layout/IHyprLayout.hpp>
|
||||
|
||||
struct SWindowData {
|
||||
CWindow* pWindow = nullptr;
|
||||
};
|
||||
|
||||
class CHyprCustomLayout : public IHyprLayout {
|
||||
public:
|
||||
virtual void onWindowCreatedTiling(CWindow*);
|
||||
virtual void onWindowRemovedTiling(CWindow*);
|
||||
virtual bool isWindowTiled(CWindow*);
|
||||
virtual void recalculateMonitor(const int&);
|
||||
virtual void recalculateWindow(CWindow*);
|
||||
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
|
||||
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
|
||||
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
|
||||
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
|
||||
virtual void switchWindows(CWindow*, CWindow*);
|
||||
virtual void alterSplitRatio(CWindow*, float, bool);
|
||||
virtual std::string getLayoutName();
|
||||
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
|
||||
|
||||
virtual void onEnable();
|
||||
virtual void onDisable();
|
||||
|
||||
private:
|
||||
std::vector<SWindowData> m_vWindowData;
|
||||
};
|
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||
|
||||
inline HANDLE PHANDLE = nullptr;
|
@@ -1,99 +0,0 @@
|
||||
#define WLR_USE_UNSTABLE
|
||||
|
||||
#include "globals.hpp"
|
||||
|
||||
#include <hyprland/src/Window.hpp>
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include "customLayout.hpp"
|
||||
#include "customDecoration.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
|
||||
// Methods
|
||||
inline std::unique_ptr<CHyprCustomLayout> g_pCustomLayout;
|
||||
inline CFunctionHook* g_pFocusHook = nullptr;
|
||||
inline CFunctionHook* g_pMotionHook = nullptr;
|
||||
inline CFunctionHook* g_pMouseDownHook = nullptr;
|
||||
typedef void (*origFocusWindow)(void*, CWindow*, wlr_surface*);
|
||||
typedef void (*origMotion)(wlr_seat*, uint32_t, double, double);
|
||||
typedef void (*origMouseDownNormal)(void*, wlr_pointer_button_event*);
|
||||
|
||||
// Do NOT change this function.
|
||||
APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
||||
return HYPRLAND_API_VERSION;
|
||||
}
|
||||
|
||||
static void onActiveWindowChange(void* self, std::any data) {
|
||||
try {
|
||||
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
||||
|
||||
HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: " + (PWINDOW ? PWINDOW->m_szTitle : "None"), CColor{0.f, 0.5f, 1.f, 1.f}, 5000);
|
||||
} catch (std::bad_any_cast& e) { HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: None", CColor{0.f, 0.5f, 1.f, 1.f}, 5000); }
|
||||
}
|
||||
|
||||
static void onNewWindow(void* self, std::any data) {
|
||||
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
||||
|
||||
HyprlandAPI::addWindowDecoration(PHANDLE, PWINDOW, new CCustomDecoration(PWINDOW));
|
||||
}
|
||||
|
||||
void hkFocusWindow(void* thisptr, CWindow* pWindow, wlr_surface* pSurface) {
|
||||
// HyprlandAPI::addNotification(PHANDLE, getFormat("FocusWindow with %lx %lx", pWindow, pSurface), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||
(*(origFocusWindow)g_pFocusHook->m_pOriginal)(thisptr, pWindow, pSurface);
|
||||
}
|
||||
|
||||
void hkNotifyMotion(wlr_seat* wlr_seat, uint32_t time_msec, double sx, double sy) {
|
||||
// HyprlandAPI::addNotification(PHANDLE, getFormat("NotifyMotion with %lf %lf", sx, sy), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||
(*(origMotion)g_pMotionHook->m_pOriginal)(wlr_seat, time_msec, sx, sy);
|
||||
}
|
||||
|
||||
void hkProcessMouseDownNormal(void* thisptr, wlr_pointer_button_event* e) {
|
||||
// HyprlandAPI::addNotification(PHANDLE, "Mouse down normal!", CColor{0.8f, 0.2f, 0.5f, 1.0f}, 5000);
|
||||
(*(origMouseDownNormal)g_pMouseDownHook->m_pOriginal)(thisptr, e);
|
||||
}
|
||||
|
||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||
PHANDLE = handle;
|
||||
|
||||
HyprlandAPI::addNotification(PHANDLE, "Hello World from an example plugin!", CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||
|
||||
HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, SCallbackInfo& info, std::any data) { onActiveWindowChange(self, data); });
|
||||
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, SCallbackInfo& info, std::any data) { onNewWindow(self, data); });
|
||||
|
||||
g_pCustomLayout = std::make_unique<CHyprCustomLayout>();
|
||||
|
||||
HyprlandAPI::addLayout(PHANDLE, "custom", g_pCustomLayout.get());
|
||||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:example:border_color", SConfigValue{.intValue = configStringToInt("rgb(44ee44)")});
|
||||
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "example", [](std::string arg) { HyprlandAPI::addNotification(PHANDLE, "Arg passed: " + arg, CColor{0.5f, 0.5f, 0.7f, 1.0f}, 5000); });
|
||||
|
||||
// Hook a public member
|
||||
g_pFocusHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CCompositor::focusWindow, (void*)&hkFocusWindow);
|
||||
// Hook a public non-member
|
||||
g_pMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion);
|
||||
// Hook a private member
|
||||
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "processMouseDownNormal");
|
||||
g_pMouseDownHook = HyprlandAPI::createFunctionHook(PHANDLE, METHODS[0].address, (void*)&hkProcessMouseDownNormal);
|
||||
|
||||
static auto* const PBORDERCOLOR = HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color");
|
||||
|
||||
// fancy notifications
|
||||
HyprlandAPI::addNotificationV2(
|
||||
PHANDLE,
|
||||
{{"text", "Example hint, color " + std::to_string(PBORDERCOLOR->intValue)}, {"time", (uint64_t)10000}, {"color", CColor{PBORDERCOLOR->intValue}}, {"icon", ICON_HINT}});
|
||||
|
||||
// Enable our hooks
|
||||
g_pFocusHook->hook();
|
||||
g_pMotionHook->hook();
|
||||
g_pMouseDownHook->hook();
|
||||
|
||||
HyprlandAPI::reloadConfig();
|
||||
|
||||
return {"ExamplePlugin", "An example plugin", "Vaxry", "1.0"};
|
||||
}
|
||||
|
||||
APICALL EXPORT void PLUGIN_EXIT() {
|
||||
HyprlandAPI::invokeHyprctlCommand("seterror", "disable");
|
||||
}
|
@@ -112,12 +112,13 @@ gestures {
|
||||
|
||||
misc {
|
||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
|
||||
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
||||
}
|
||||
|
||||
# Example per-device config
|
||||
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
|
||||
device:epic-mouse-v1 {
|
||||
device {
|
||||
name = epic-mouse-v1
|
||||
sensitivity = -0.5
|
||||
}
|
||||
|
||||
@@ -126,7 +127,7 @@ device:epic-mouse-v1 {
|
||||
# Example windowrule v2
|
||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
||||
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
|
||||
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
|
||||
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||
|
111
flake.lock
generated
@@ -1,5 +1,29 @@
|
||||
{
|
||||
"nodes": {
|
||||
"hyprcursor": {
|
||||
"inputs": {
|
||||
"hyprlang": "hyprlang",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710257359,
|
||||
"narHash": "sha256-43re5pzE/cswFAgw92/ugsB3+d5ufDaCcLtl9ztKfBo=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprcursor",
|
||||
"rev": "1761f6cefd77f4fcd2039d930c88d6716ddc4974",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprcursor",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-protocols": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -23,13 +47,58 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprlang": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"hyprcursor",
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709914708,
|
||||
"narHash": "sha256-bR4o3mynoTa1Wi4ZTjbnsZ6iqVcPGriXp56bZh5UFTk=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "a685493fdbeec01ca8ccdf1f3655c044a8ce2fe2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprlang_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709914708,
|
||||
"narHash": "sha256-bR4o3mynoTa1Wi4ZTjbnsZ6iqVcPGriXp56bZh5UFTk=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "a685493fdbeec01ca8ccdf1f3655c044a8ce2fe2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1703438236,
|
||||
"narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
|
||||
"lastModified": 1710272261,
|
||||
"narHash": "sha256-g0bDwXFmTE7uGDOs9HcJsfLFhH7fOsASbAuOzDC+fhQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
|
||||
"rev": "0ad13a6833440b8e238947e47bea7f11071dc2b2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -41,9 +110,11 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"hyprcursor": "hyprcursor",
|
||||
"hyprland-protocols": "hyprland-protocols",
|
||||
"hyprlang": "hyprlang_2",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems",
|
||||
"systems": "systems_2",
|
||||
"wlroots": "wlroots",
|
||||
"xdph": "xdph"
|
||||
}
|
||||
@@ -63,22 +134,37 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1689347949,
|
||||
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default-linux",
|
||||
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default-linux",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"wlroots": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"lastModified": 1701368958,
|
||||
"narHash": "sha256-7kvyoA91etzVEl9mkA/EJfB6z/PltxX7Xc4gcr7/xlo=",
|
||||
"lastModified": 1709983277,
|
||||
"narHash": "sha256-wXWIJLd4F2JZeMaihWVDW/yYXCLEC8OpeNJZg9a9ly8=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||
"rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||
"rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
@@ -87,6 +173,9 @@
|
||||
"hyprland-protocols": [
|
||||
"hyprland-protocols"
|
||||
],
|
||||
"hyprlang": [
|
||||
"hyprlang"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
@@ -95,11 +184,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1703514399,
|
||||
"narHash": "sha256-VRr5Xc4S/VPr/gU3fiOD3vSIL2+GJ+LUrmFTWTwnTz4=",
|
||||
"lastModified": 1709299639,
|
||||
"narHash": "sha256-jYqJM5khksLIbqSxCLUUcqEgI+O2LdlSlcMEBs39CAU=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "0a318a7a217a6402b0b705837cd5b50b0e94b31b",
|
||||
"rev": "2d2fb547178ec025da643db57d40a971507b82fe",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
20
flake.nix
@@ -12,21 +12,34 @@
|
||||
host = "gitlab.freedesktop.org";
|
||||
owner = "wlroots";
|
||||
repo = "wlroots";
|
||||
rev = "5d639394f3e83b01596dcd166a44a9a1a2583350";
|
||||
rev = "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
hyprcursor = {
|
||||
url = "github:hyprwm/hyprcursor";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
|
||||
hyprland-protocols = {
|
||||
url = "github:hyprwm/hyprland-protocols";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
|
||||
hyprlang = {
|
||||
url = "github:hyprwm/hyprlang";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
|
||||
xdph = {
|
||||
url = "github:hyprwm/xdg-desktop-portal-hyprland";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
inputs.hyprland-protocols.follows = "hyprland-protocols";
|
||||
inputs.hyprlang.follows = "hyprlang";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -64,9 +77,9 @@
|
||||
# hyprland-packages
|
||||
|
||||
hyprland
|
||||
hyprland-unwrapped
|
||||
hyprland-debug
|
||||
hyprland-legacy-renderer
|
||||
hyprland-unwrapped
|
||||
# hyprland-extras
|
||||
|
||||
xdg-desktop-portal-hyprland
|
||||
@@ -84,8 +97,9 @@
|
||||
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
||||
} {
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
|
||||
nativeBuildInputs = with pkgsFor.${system}; [cmake python3 expat libxml2];
|
||||
buildInputs = [self.packages.${system}.wlroots-hyprland];
|
||||
hardeningDisable = ["fortify"];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
self.packages.${system}.hyprland
|
||||
|
@@ -33,6 +33,7 @@ commands:
|
||||
cursorpos
|
||||
decorations
|
||||
devices
|
||||
dismissnotify
|
||||
dispatch
|
||||
getoption
|
||||
globalshortcuts
|
||||
@@ -51,12 +52,14 @@ commands:
|
||||
setprop
|
||||
splash
|
||||
switchxkblayout
|
||||
systeminfo
|
||||
version
|
||||
workspacerules
|
||||
workspaces
|
||||
|
||||
flags:
|
||||
-j -> output in JSON
|
||||
-r -> refresh state after issuing command (e.g. for updating variables)
|
||||
--batch -> execute a batch of commands, separated by ';'
|
||||
--instance (-i) -> use a specific instance. Can be either signature or index in hyprctl instances (0, 1, etc)
|
||||
)#";
|
||||
@@ -77,7 +80,7 @@ std::vector<SInstanceData> instances() {
|
||||
std::vector<SInstanceData> result;
|
||||
|
||||
for (const auto& el : std::filesystem::directory_iterator("/tmp/hypr")) {
|
||||
if (el.is_directory())
|
||||
if (el.is_directory() || !el.path().string().ends_with(".lock"))
|
||||
continue;
|
||||
|
||||
// read lock
|
||||
@@ -85,7 +88,9 @@ std::vector<SInstanceData> instances() {
|
||||
data->id = el.path().string();
|
||||
data->id = data->id.substr(data->id.find_last_of('/') + 1, data->id.find(".lock") - data->id.find_last_of('/') - 1);
|
||||
|
||||
try {
|
||||
data->time = std::stoull(data->id.substr(data->id.find_first_of('_') + 1));
|
||||
} catch (std::exception& e) { continue; }
|
||||
|
||||
// read file
|
||||
std::ifstream ifs(el.path().string());
|
||||
@@ -93,7 +98,9 @@ std::vector<SInstanceData> instances() {
|
||||
int i = 0;
|
||||
for (std::string line; std::getline(ifs, line); ++i) {
|
||||
if (i == 0) {
|
||||
try {
|
||||
data->pid = std::stoull(line);
|
||||
} catch (std::exception& e) { continue; }
|
||||
} else if (i == 1) {
|
||||
data->wlSocket = line;
|
||||
} else
|
||||
@@ -300,6 +307,10 @@ int main(int argc, char** argv) {
|
||||
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
|
||||
fullArgs += "j";
|
||||
json = true;
|
||||
} else if (ARGS[i] == "-r" && !fullArgs.contains("r")) {
|
||||
fullArgs += "r";
|
||||
} else if (ARGS[i] == "-a" && !fullArgs.contains("a")) {
|
||||
fullArgs += "a";
|
||||
} else if (ARGS[i] == "--batch") {
|
||||
fullRequest = "--batch ";
|
||||
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
|
||||
@@ -359,7 +370,7 @@ int main(int argc, char** argv) {
|
||||
const auto ISIG = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
|
||||
if (!ISIG) {
|
||||
std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)";
|
||||
std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -370,42 +381,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
if (fullRequest.contains("/--batch"))
|
||||
batchRequest(fullRequest);
|
||||
else if (fullRequest.contains("/monitors"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/clients"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/workspaces"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/activeworkspace"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/workspacerules"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/activewindow"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/layers"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/version"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/kill"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/splash"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/devices"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/reload"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/getoption"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/binds"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/cursorpos"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/animations"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/globalshortcuts"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/rollinglog"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/hyprpaper"))
|
||||
requestHyprpaper(fullRequest);
|
||||
else if (fullRequest.contains("/switchxkblayout"))
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/seterror"))
|
||||
@@ -414,6 +391,8 @@ int main(int argc, char** argv) {
|
||||
request(fullRequest, 3);
|
||||
else if (fullRequest.contains("/plugin"))
|
||||
request(fullRequest, 1);
|
||||
else if (fullRequest.contains("/dismissnotify"))
|
||||
request(fullRequest, 0);
|
||||
else if (fullRequest.contains("/notify"))
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/output"))
|
||||
@@ -426,15 +405,10 @@ int main(int argc, char** argv) {
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/decorations"))
|
||||
request(fullRequest, 1);
|
||||
else if (fullRequest.contains("/hyprpaper"))
|
||||
requestHyprpaper(fullRequest);
|
||||
else if (fullRequest.contains("/layouts"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/--help"))
|
||||
printf("%s", USAGE.c_str());
|
||||
else {
|
||||
printf("%s\n", USAGE.c_str());
|
||||
return 1;
|
||||
request(fullRequest);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
@@ -20,11 +20,18 @@ std::string DataState::getDataStatePath() {
|
||||
return std::string{HOME} + "/.local/share/hyprpm";
|
||||
}
|
||||
|
||||
std::string DataState::getHeadersPath() {
|
||||
return getDataStatePath() + "/headersRoot";
|
||||
}
|
||||
|
||||
void DataState::ensureStateStoreExists() {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
if (!std::filesystem::exists(PATH))
|
||||
std::filesystem::create_directories(PATH);
|
||||
|
||||
if (!std::filesystem::exists(getHeadersPath()))
|
||||
std::filesystem::create_directories(getHeadersPath());
|
||||
}
|
||||
|
||||
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
||||
@@ -38,16 +45,19 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
||||
{"repository", toml::table{
|
||||
{"name", repo.name},
|
||||
{"hash", repo.hash},
|
||||
{"url", repo.url}
|
||||
{"url", repo.url},
|
||||
{"rev", repo.rev}
|
||||
}}
|
||||
};
|
||||
for (auto& p : repo.plugins) {
|
||||
// copy .so to the good place
|
||||
if (std::filesystem::exists(p.filename))
|
||||
std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so");
|
||||
|
||||
DATA.emplace(p.name, toml::table{
|
||||
{"filename", p.name + ".so"},
|
||||
{"enabled", p.enabled}
|
||||
{"enabled", p.enabled},
|
||||
{"failed", p.failed}
|
||||
});
|
||||
}
|
||||
// clang-format on
|
||||
@@ -63,7 +73,10 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
@@ -84,7 +97,10 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
@@ -153,28 +169,34 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
|
||||
std::vector<SPluginRepository> repos;
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
const auto REV = STATE["repository"]["rev"].value_or("");
|
||||
const auto HASH = STATE["repository"]["hash"].value_or("");
|
||||
|
||||
SPluginRepository repo;
|
||||
repo.hash = HASH;
|
||||
repo.name = NAME;
|
||||
repo.url = URL;
|
||||
repo.rev = REV;
|
||||
|
||||
for (const auto& [key, val] : STATE) {
|
||||
if (key == "repository")
|
||||
continue;
|
||||
|
||||
const auto ENABLED = STATE[key]["enabled"].value_or(false);
|
||||
const auto FAILED = STATE[key]["failed"].value_or(false);
|
||||
const auto FILENAME = STATE[key]["filename"].value_or("");
|
||||
|
||||
repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED});
|
||||
repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED, FAILED});
|
||||
}
|
||||
|
||||
repos.push_back(repo);
|
||||
@@ -189,7 +211,10 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
@@ -201,6 +226,11 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
if (key.str() != name)
|
||||
continue;
|
||||
|
||||
const auto FAILED = STATE[key]["failed"].value_or(false);
|
||||
|
||||
if (FAILED)
|
||||
return false;
|
||||
|
||||
(*STATE[key].as_table()).insert_or_assign("enabled", enabled);
|
||||
|
||||
std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
|
||||
|
@@ -10,6 +10,7 @@ struct SGlobalState {
|
||||
|
||||
namespace DataState {
|
||||
std::string getDataStatePath();
|
||||
std::string getHeadersPath();
|
||||
void ensureStateStoreExists();
|
||||
void addNewPluginRepo(const SPluginRepository& repo);
|
||||
void removePluginRepo(const std::string& urlOrName);
|
||||
|
@@ -19,6 +19,7 @@ class CManifest {
|
||||
std::vector<std::string> authors;
|
||||
std::vector<std::string> buildSteps;
|
||||
std::string output;
|
||||
bool failed = false;
|
||||
};
|
||||
|
||||
struct {
|
||||
|
@@ -6,11 +6,13 @@
|
||||
struct SPlugin {
|
||||
std::string name;
|
||||
std::string filename;
|
||||
bool enabled;
|
||||
bool enabled = false;
|
||||
bool failed = false;
|
||||
};
|
||||
|
||||
struct SPluginRepository {
|
||||
std::string url;
|
||||
std::string rev;
|
||||
std::string name;
|
||||
std::vector<SPlugin> plugins;
|
||||
std::string hash;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
|
||||
#include <toml++/toml.hpp>
|
||||
|
||||
@@ -76,7 +77,8 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
|
||||
return ver;
|
||||
}
|
||||
|
||||
bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& rev) {
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
if (DataState::pluginRepoExists(url)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
|
||||
@@ -131,6 +133,14 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rev.empty()) {
|
||||
std::string ret = execAndGet("git -C /tmp/hyprpm/new reset --hard --recurse-submodules " + rev);
|
||||
if (ret.compare(0, 6, "fatal:") == 0) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
progress.m_iSteps = 1;
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned");
|
||||
progress.m_szCurrentMessage = "Reading the manifest";
|
||||
@@ -170,6 +180,22 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
message += " version " + pl.version;
|
||||
progress.printMessageAbove(message);
|
||||
}
|
||||
|
||||
if (!pManifest->m_sRepository.commitPins.empty()) {
|
||||
// check commit pins
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
|
||||
|
||||
for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) {
|
||||
if (hl != HLVER.hash)
|
||||
continue;
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
|
||||
|
||||
execAndGet("cd /tmp/hyprpm/new/ && git reset --hard --recurse-submodules " + plugin);
|
||||
}
|
||||
}
|
||||
|
||||
progress.m_szCurrentMessage = "Verifying headers";
|
||||
progress.print();
|
||||
|
||||
@@ -191,16 +217,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto& bs : p.buildSteps) {
|
||||
out += execAndGet("cd /tmp/hyprpm/new && " + bs) + "\n";
|
||||
std::string cmd = std::format("cd /tmp/hyprpm/new && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", DataState::getHeadersPath(), bs);
|
||||
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Plugin " << p.name << " failed to build.\n";
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Plugin " + p.name + " failed to build.\n");
|
||||
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
|
||||
|
||||
return false;
|
||||
p.failed = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output);
|
||||
@@ -218,9 +247,10 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
repohash.pop_back();
|
||||
repo.name = pManifest->m_sRepository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_sRepository.name;
|
||||
repo.url = url;
|
||||
repo.rev = rev;
|
||||
repo.hash = repohash;
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false});
|
||||
repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false, p.failed});
|
||||
}
|
||||
DataState::addNewPluginRepo(repo);
|
||||
|
||||
@@ -263,8 +293,12 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
|
||||
eHeadersErrors CPluginManager::headersValid() {
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc"))
|
||||
return HEADERS_MISSING;
|
||||
|
||||
// find headers commit
|
||||
auto headers = execAndGet("pkg-config --cflags --keep-system-cflags hyprland");
|
||||
std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkg-config --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
|
||||
auto headers = execAndGet(cmd.c_str());
|
||||
|
||||
if (!headers.contains("-I/"))
|
||||
return HEADERS_MISSING;
|
||||
@@ -296,10 +330,6 @@ eHeadersErrors CPluginManager::headersValid() {
|
||||
if (!ifs.good())
|
||||
return HEADERS_CORRUPTED;
|
||||
|
||||
if ((std::filesystem::exists("/usr/include/hyprland/src/version.h") && verHeader != "/usr/include/hyprland/src/version.h") ||
|
||||
(std::filesystem::exists("/usr/local/include/hyprland/src/version.h") && verHeader != "/usr/local/include/hyprland/src/version.h"))
|
||||
return HEADERS_DUPLICATED;
|
||||
|
||||
std::string verHeaderContent((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
|
||||
ifs.close();
|
||||
|
||||
@@ -314,7 +344,9 @@ eHeadersErrors CPluginManager::headersValid() {
|
||||
return HEADERS_OK;
|
||||
}
|
||||
|
||||
bool CPluginManager::updateHeaders() {
|
||||
bool CPluginManager::updateHeaders(bool force) {
|
||||
|
||||
DataState::ensureStateStoreExists();
|
||||
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
@@ -323,11 +355,8 @@ bool CPluginManager::updateHeaders() {
|
||||
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
if (headersValid() == HEADERS_OK) {
|
||||
std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Your headers are already up-to-date.\n";
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
GLOBALSTATE.headersHashCompiled = HLVER.hash;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
if (!force && headersValid() == HEADERS_OK) {
|
||||
std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Headers up to date.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -369,23 +398,38 @@ bool CPluginManager::updateHeaders() {
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland");
|
||||
|
||||
ret = execAndGet("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja");
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath());
|
||||
|
||||
ret = execAndGet(
|
||||
std::format("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja",
|
||||
DataState::getHeadersPath()));
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
|
||||
|
||||
// le hack. Wlroots has to generate its build/include
|
||||
ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots && meson setup -Drenderers=gles2 -Dexamples=false build");
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret);
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " configured Hyprland");
|
||||
progress.m_iSteps = 4;
|
||||
progress.m_szCurrentMessage = "Installing sources";
|
||||
progress.print();
|
||||
|
||||
progress.printMessageAbove(
|
||||
std::string{Colors::YELLOW} + "!" + Colors::RESET +
|
||||
" in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
|
||||
// progress.printMessageAbove(
|
||||
// std::string{Colors::YELLOW} + "!" + Colors::RESET +
|
||||
// " in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
|
||||
|
||||
ret = execAndGet("pkexec sh \"-c\" \"cd /tmp/hyprpm/hyprland && make installheaders\"");
|
||||
std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" /tmp/hyprpm/hyprland/Makefile && cd /tmp/hyprpm/hyprland && make installheaders",
|
||||
DataState::getHeadersPath());
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd);
|
||||
|
||||
ret = execAndGet(cmd);
|
||||
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "pkexec returned: " << ret << "\n";
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n";
|
||||
|
||||
// remove build files
|
||||
std::filesystem::remove_all("/tmp/hyprpm/hyprland");
|
||||
@@ -397,10 +441,6 @@ bool CPluginManager::updateHeaders() {
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
GLOBALSTATE.headersHashCompiled = HLVER.hash;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
|
||||
std::cout << "\n";
|
||||
} else {
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID));
|
||||
@@ -434,7 +474,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
CProgressBar progress;
|
||||
progress.m_iMaxSteps = REPOS.size() * 2 + 1;
|
||||
progress.m_iMaxSteps = REPOS.size() * 2 + 2;
|
||||
progress.m_iSteps = 0;
|
||||
progress.m_szCurrentMessage = "Updating repositories";
|
||||
progress.print();
|
||||
@@ -462,6 +502,16 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!repo.rev.empty()) {
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Plugin has revision set, resetting: " + repo.rev);
|
||||
|
||||
std::string ret = execAndGet("git -C /tmp/hyprpm reset --hard --recurse-submodules " + repo.rev);
|
||||
if (ret.compare(0, 6, "fatal:") == 0) {
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!update) {
|
||||
// check if git has updates
|
||||
std::string hash = execAndGet("cd /tmp/hyprpm/update && git rev-parse HEAD");
|
||||
@@ -506,8 +556,8 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pManifest->m_sRepository.commitPins.empty()) {
|
||||
// check commit pins
|
||||
if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) {
|
||||
// check commit pins unless a revision is specified
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
|
||||
|
||||
@@ -528,7 +578,8 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto& bs : p.buildSteps) {
|
||||
out += execAndGet("cd /tmp/hyprpm/update && " + bs) + "\n";
|
||||
std::string cmd = std::format("cd /tmp/hyprpm/update && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", DataState::getHeadersPath(), bs);
|
||||
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) {
|
||||
@@ -566,6 +617,14 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " updated " + repo.name);
|
||||
}
|
||||
|
||||
progress.m_iSteps++;
|
||||
progress.m_szCurrentMessage = "Updating global state...";
|
||||
progress.print();
|
||||
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
GLOBALSTATE.headersHashCompiled = HLVER.hash;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
|
||||
progress.m_iSteps++;
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
@@ -696,8 +755,13 @@ void CPluginManager::listAllPlugins() {
|
||||
std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n";
|
||||
|
||||
for (auto& p : r.plugins) {
|
||||
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name + "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false")
|
||||
<< Colors::RESET << "\n";
|
||||
|
||||
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
|
||||
|
||||
if (!p.failed)
|
||||
std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n";
|
||||
else
|
||||
std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -36,11 +36,11 @@ struct SHyprlandVersion {
|
||||
|
||||
class CPluginManager {
|
||||
public:
|
||||
bool addNewPluginRepo(const std::string& url);
|
||||
bool addNewPluginRepo(const std::string& url, const std::string& rev);
|
||||
bool removePluginRepo(const std::string& urlOrName);
|
||||
|
||||
eHeadersErrors headersValid();
|
||||
bool updateHeaders();
|
||||
bool updateHeaders(bool force = false);
|
||||
bool updatePlugins(bool forceUpdateAll);
|
||||
|
||||
void listAllPlugins();
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "progress/CProgressBar.hpp"
|
||||
#include "helpers/Colors.hpp"
|
||||
#include "core/PluginManager.hpp"
|
||||
#include "core/DataState.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
@@ -10,7 +11,8 @@
|
||||
|
||||
const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
┃
|
||||
┣ add [url] → Install a new plugin repository from git
|
||||
┣ add [url] [git rev] → Install a new plugin repository from git. Git revision
|
||||
┃ is optional, when set, commit locks are ignored.
|
||||
┣ remove [url/name] → Remove an installed plugin repository
|
||||
┣ enable [name] → Enable a plugin
|
||||
┣ disable [name] → Disable a plugin
|
||||
@@ -23,6 +25,7 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
┣ --notify | -n → Send a hyprland notification for important events (e.g. load fail)
|
||||
┣ --help | -h → Show this menu
|
||||
┣ --verbose | -v → Enable too much logging
|
||||
┣ --force | -f → Force an operation ignoring checks (e.g. update -f)
|
||||
┗
|
||||
)#";
|
||||
|
||||
@@ -38,7 +41,7 @@ int main(int argc, char** argv, char** envp) {
|
||||
}
|
||||
|
||||
std::vector<std::string> command;
|
||||
bool notify = false, verbose = false;
|
||||
bool notify = false, verbose = false, force = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (ARGS[i].starts_with("-")) {
|
||||
@@ -49,6 +52,9 @@ int main(int argc, char** argv, char** envp) {
|
||||
notify = true;
|
||||
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
|
||||
verbose = true;
|
||||
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
|
||||
force = true;
|
||||
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
|
||||
} else {
|
||||
std::cerr << "Unrecognized option " << ARGS[i];
|
||||
return 1;
|
||||
@@ -72,7 +78,12 @@ int main(int argc, char** argv, char** envp) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return g_pPluginManager->addNewPluginRepo(command[1]) ? 0 : 1;
|
||||
std::string rev = "";
|
||||
if (command.size() >= 3) {
|
||||
rev = command[2];
|
||||
}
|
||||
|
||||
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
|
||||
} else if (command[0] == "remove") {
|
||||
if (ARGS.size() < 2) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for remove.\n";
|
||||
@@ -82,9 +93,13 @@ int main(int argc, char** argv, char** envp) {
|
||||
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
|
||||
} else if (command[0] == "update") {
|
||||
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
|
||||
bool headers = g_pPluginManager->updateHeaders();
|
||||
bool headers = g_pPluginManager->updateHeaders(force);
|
||||
if (headers) {
|
||||
bool ret1 = g_pPluginManager->updatePlugins(!headersValid);
|
||||
const auto HLVER = g_pPluginManager->getHyprlandVersion();
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
|
||||
|
||||
bool ret1 = g_pPluginManager->updatePlugins(!headersValid || force || COMPILEDOUTDATED);
|
||||
|
||||
if (!ret1)
|
||||
return 1;
|
||||
|
@@ -8,7 +8,9 @@
|
||||
binutils,
|
||||
cairo,
|
||||
git,
|
||||
hyprcursor,
|
||||
hyprland-protocols,
|
||||
hyprlang,
|
||||
jq,
|
||||
libGL,
|
||||
libdrm,
|
||||
@@ -74,7 +76,9 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||
[
|
||||
cairo
|
||||
git
|
||||
hyprcursor.dev
|
||||
hyprland-protocols
|
||||
hyprlang
|
||||
libdrm
|
||||
libGL
|
||||
libinput
|
||||
@@ -130,6 +134,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||
|
||||
postInstall = ''
|
||||
ln -s ${wlroots}/include/wlr $dev/include/hyprland/wlroots
|
||||
|
||||
${lib.optionalString wrapRuntimeDeps ''
|
||||
wrapProgram $out/bin/Hyprland \
|
||||
--suffix PATH : ${lib.makeBinPath [
|
||||
|
@@ -10,21 +10,20 @@
|
||||
(builtins.substring 4 2 longDate)
|
||||
(builtins.substring 6 2 longDate)
|
||||
]);
|
||||
|
||||
mkJoinedOverlays = overlays: final: prev:
|
||||
lib.foldl' (attrs: overlay: attrs // (overlay final prev)) {} overlays;
|
||||
in {
|
||||
# Contains what a user is most likely to care about:
|
||||
# Hyprland itself, XDPH and the Share Picker.
|
||||
default = mkJoinedOverlays (with self.overlays; [
|
||||
default = lib.composeManyExtensions (with self.overlays; [
|
||||
hyprland-packages
|
||||
hyprland-extras
|
||||
]);
|
||||
|
||||
# Packages for variations of Hyprland, dependencies included.
|
||||
hyprland-packages = mkJoinedOverlays [
|
||||
hyprland-packages = lib.composeManyExtensions [
|
||||
# Dependencies
|
||||
inputs.hyprcursor.overlays.default
|
||||
inputs.hyprland-protocols.overlays.default
|
||||
inputs.hyprlang.overlays.default
|
||||
self.overlays.wlroots-hyprland
|
||||
self.overlays.udis86
|
||||
# Hyprland packages themselves
|
||||
@@ -34,9 +33,9 @@ in {
|
||||
hyprland = final.callPackage ./default.nix {
|
||||
stdenv = final.gcc13Stdenv;
|
||||
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
|
||||
wlroots = final.wlroots-hyprland;
|
||||
commit = self.rev or "";
|
||||
inherit (final) udis86 hyprland-protocols;
|
||||
wlroots = final.wlroots-hyprland; # explicit override until decided on breaking change of the name
|
||||
udis86 = final.udis86-hyprland; # explicit override until decided on breaking change of the name
|
||||
inherit date;
|
||||
};
|
||||
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
|
||||
@@ -59,12 +58,12 @@ in {
|
||||
|
||||
# Packages for extra software recommended for usage with Hyprland,
|
||||
# including forked or patched packages for compatibility.
|
||||
hyprland-extras = mkJoinedOverlays [
|
||||
hyprland-extras = lib.composeManyExtensions [
|
||||
inputs.xdph.overlays.xdg-desktop-portal-hyprland
|
||||
];
|
||||
|
||||
udis86 = final: prev: {
|
||||
udis86 = final.callPackage ./udis86.nix {};
|
||||
udis86-hyprland = final.callPackage ./udis86.nix {};
|
||||
};
|
||||
|
||||
# Patched version of wlroots for Hyprland.
|
||||
|
@@ -34,17 +34,19 @@ index 1d2c7f9f..c5ef4e67 100644
|
||||
headers = globber.stdout().strip().split('\n')
|
||||
foreach file : headers
|
||||
diff --git a/src/meson.build b/src/meson.build
|
||||
index 0af864b9..38723b8c 100644
|
||||
index 45701f5f..3505cefe 100644
|
||||
--- a/src/meson.build
|
||||
+++ b/src/meson.build
|
||||
@@ -9,16 +9,16 @@ executable('Hyprland', src,
|
||||
@@ -9,7 +9,7 @@ executable('Hyprland', src,
|
||||
server_protos,
|
||||
dependency('wayland-server'),
|
||||
dependency('wayland-client'),
|
||||
- wlroots.get_variable('wlroots'),
|
||||
+ dependency('wlroots'),
|
||||
dependency('cairo'),
|
||||
dependency('libdrm'),
|
||||
dependency('hyprcursor'),
|
||||
dependency('hyprlang', version: '>= 0.3.2'),
|
||||
@@ -16,12 +16,12 @@ executable('Hyprland', src,
|
||||
dependency('egl'),
|
||||
dependency('xkbcommon'),
|
||||
dependency('libinput'),
|
||||
|
@@ -8,7 +8,7 @@ CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }')
|
||||
if [ "$SUB_REV" != "$CRT_REV" ]; then
|
||||
echo "Updating wlroots..."
|
||||
# update wlroots to submodule revision
|
||||
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix subprojects/wlroots.wrap
|
||||
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix
|
||||
nix flake lock
|
||||
|
||||
echo "wlroots: $CRT_REV -> $SUB_REV"
|
||||
|
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "0.34.0"
|
||||
"version": "0.37.1"
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
wayland_protos = dependency('wayland-protocols',
|
||||
version: '>=1.25',
|
||||
version: '>=1.32',
|
||||
fallback: 'wayland-protocols',
|
||||
default_options: ['tests=false'],
|
||||
)
|
||||
|
21
scripts/hyprlandStaticAsan.diff
Normal file
@@ -0,0 +1,21 @@
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 857e21de..122d6a78 100755
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -101,7 +101,7 @@ message(STATUS "Checking deps...")
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
-pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2) # we do not check for wlroots, as we provide it ourselves
|
||||
+pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2 libffi) # we do not check for wlroots, as we provide it ourselves
|
||||
|
||||
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||
|
||||
@@ -121,6 +121,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
message(STATUS "Enabling ASan")
|
||||
|
||||
target_link_libraries(Hyprland asan)
|
||||
+ target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/libwayland-server.a)
|
||||
target_compile_options(Hyprland PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
|
23
scripts/waylandStatic.diff
Normal file
@@ -0,0 +1,23 @@
|
||||
diff --git a/src/meson.build b/src/meson.build
|
||||
index 5d04334..6645eec 100644
|
||||
--- a/src/meson.build
|
||||
+++ b/src/meson.build
|
||||
@@ -170,7 +170,7 @@ if get_option('libraries')
|
||||
error('We probably need to bump the SONAME of libwayland-server and -client')
|
||||
endif
|
||||
|
||||
- wayland_server = library(
|
||||
+ wayland_server = static_library(
|
||||
'wayland-server',
|
||||
sources: [
|
||||
wayland_server_protocol_core_h,
|
||||
@@ -180,9 +180,6 @@ if get_option('libraries')
|
||||
'wayland-shm.c',
|
||||
'event-loop.c'
|
||||
],
|
||||
- # To avoid an unnecessary SONAME bump, wayland 1.x.y produces
|
||||
- # libwayland-server.so.0.x.y.
|
||||
- version: '.'.join(['0', wayland_version[1], wayland_version[2]]),
|
||||
dependencies: [
|
||||
epoll_dep,
|
||||
ffi_dep,
|
@@ -21,7 +21,7 @@
|
||||
#include "debug/HyprDebugOverlay.hpp"
|
||||
#include "debug/HyprNotificationOverlay.hpp"
|
||||
#include "helpers/Monitor.hpp"
|
||||
#include "helpers/Workspace.hpp"
|
||||
#include "desktop/Workspace.hpp"
|
||||
#include "Window.hpp"
|
||||
#include "render/Renderer.hpp"
|
||||
#include "render/OpenGL.hpp"
|
||||
@@ -57,7 +57,6 @@ class CCompositor {
|
||||
wlr_layer_shell_v1* m_sWLRLayerShell;
|
||||
wlr_xdg_shell* m_sWLRXDGShell;
|
||||
wlr_cursor* m_sWLRCursor;
|
||||
wlr_xcursor_manager* m_sWLRXCursorMgr;
|
||||
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
|
||||
wlr_output_manager_v1* m_sWLROutputMgr;
|
||||
wlr_presentation* m_sWLRPresentation;
|
||||
@@ -93,9 +92,7 @@ class CCompositor {
|
||||
std::vector<std::shared_ptr<CMonitor>> m_vMonitors;
|
||||
std::vector<std::shared_ptr<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
|
||||
std::vector<std::unique_ptr<CWindow>> m_vWindows;
|
||||
std::vector<std::unique_ptr<SXDGPopup>> m_vXDGPopups;
|
||||
std::vector<std::unique_ptr<CWorkspace>> m_vWorkspaces;
|
||||
std::vector<std::unique_ptr<SSubsurface>> m_vSubsurfaces;
|
||||
std::vector<CWindow*> m_vWindowsFadingOut;
|
||||
std::vector<SLayerSurface*> m_vSurfacesFadingOut;
|
||||
|
||||
@@ -135,16 +132,14 @@ class CCompositor {
|
||||
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
|
||||
bool windowExists(CWindow*);
|
||||
bool windowValidMapped(CWindow*);
|
||||
CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow"
|
||||
CWindow* vectorToWindowTiled(const Vector2D&);
|
||||
bool monitorExists(CMonitor*);
|
||||
CWindow* vectorToWindowUnified(const Vector2D&, uint8_t properties, CWindow* pIgnoreWindow = nullptr);
|
||||
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
|
||||
SIMEPopup* vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopup>& popups);
|
||||
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
|
||||
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
|
||||
CWindow* windowFromCursor();
|
||||
CWindow* windowFloatingFromCursor();
|
||||
CMonitor* getMonitorFromOutput(wlr_output*);
|
||||
CWindow* getWindowForPopup(wlr_xdg_popup*);
|
||||
CMonitor* getRealMonitorFromOutput(wlr_output*);
|
||||
CWindow* getWindowFromSurface(wlr_surface*);
|
||||
CWindow* getWindowFromHandle(uint32_t);
|
||||
CWindow* getWindowFromZWLRHandle(wl_resource*);
|
||||
@@ -170,17 +165,17 @@ class CCompositor {
|
||||
int getNextAvailableNamedWorkspace();
|
||||
bool isPointOnAnyMonitor(const Vector2D&);
|
||||
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
|
||||
CWindow* getConstraintWindow(SMouse*);
|
||||
CMonitor* getMonitorInDirection(const char&);
|
||||
CMonitor* getMonitorInDirection(CMonitor*, const char&);
|
||||
void updateAllWindowsAnimatedDecorationValues();
|
||||
void updateWorkspaceWindows(const int64_t& id);
|
||||
void updateWindowAnimatedDecorationValues(CWindow*);
|
||||
int getNextAvailableMonitorID(std::string const& name);
|
||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
|
||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*, bool noWarpCursor = false);
|
||||
void swapActiveWorkspaces(CMonitor*, CMonitor*);
|
||||
CMonitor* getMonitorFromString(const std::string&);
|
||||
bool workspaceIDOutOfBounds(const int64_t&);
|
||||
void setWindowFullscreen(CWindow*, bool, eFullscreenMode);
|
||||
void setWindowFullscreen(CWindow*, bool, eFullscreenMode mode = FULLSCREEN_INVALID);
|
||||
void updateFullscreenFadeOnWorkspace(CWorkspace*);
|
||||
CWindow* getX11Parent(CWindow*);
|
||||
void scheduleFrameForMonitor(CMonitor*);
|
||||
@@ -214,6 +209,7 @@ class CCompositor {
|
||||
|
||||
private:
|
||||
void initAllSignals();
|
||||
void removeAllSignals();
|
||||
void setRandomSplash();
|
||||
void initManagers(eManagersInitStage stage);
|
||||
void prepareFallbackOutput();
|
||||
@@ -236,4 +232,7 @@ inline std::map<std::string, xcb_atom_t> HYPRATOMS = {HYPRATOM("_NET_WM_WINDOW_T
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION"),
|
||||
HYPRATOM("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE")};
|
||||
HYPRATOM("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"),
|
||||
HYPRATOM("_NET_SUPPORTING_WM_CHECK"),
|
||||
HYPRATOM("_NET_WM_NAME"),
|
||||
HYPRATOM("UTF8_STRING")};
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/Vector2D.hpp"
|
||||
#include <functional>
|
||||
|
||||
enum eIcons {
|
||||
ICON_WARNING = 0,
|
||||
@@ -52,4 +53,20 @@ struct SWindowDecorationExtents {
|
||||
bool operator==(const SWindowDecorationExtents& other) const {
|
||||
return topLeft == other.topLeft && bottomRight == other.bottomRight;
|
||||
}
|
||||
|
||||
void addExtents(const SWindowDecorationExtents& other) {
|
||||
topLeft = topLeft.getComponentMax(other.topLeft);
|
||||
bottomRight = bottomRight.getComponentMax(other.bottomRight);
|
||||
}
|
||||
};
|
||||
|
||||
enum eHyprCtlOutputFormat {
|
||||
FORMAT_NORMAL = 0,
|
||||
FORMAT_JSON
|
||||
};
|
||||
|
||||
struct SHyprCtlCommand {
|
||||
std::string name = "";
|
||||
bool exact = true;
|
||||
std::function<std::string(eHyprCtlOutputFormat, std::string)> fn;
|
||||
};
|
247
src/Window.cpp
@@ -3,16 +3,17 @@
|
||||
#include "render/decorations/CHyprDropShadowDecoration.hpp"
|
||||
#include "render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
#include "render/decorations/CHyprBorderDecoration.hpp"
|
||||
#include "config/ConfigValue.hpp"
|
||||
|
||||
CWindow::CWindow() {
|
||||
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_vRealSize.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_fBorderFadeAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
|
||||
m_fBorderAngleAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("borderangle"), (void*)this, AVARDAMAGE_BORDER);
|
||||
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
|
||||
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
|
||||
m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), (void*)this, AVARDAMAGE_BORDER);
|
||||
m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
|
||||
m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
|
||||
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
|
||||
addWindowDeco(std::make_unique<CHyprBorderDecoration>(this));
|
||||
@@ -39,8 +40,8 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
|
||||
|
||||
if (m_sAdditionalConfigData.dimAround) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
return {{m_vRealPosition.vec().x - PMONITOR->vecPosition.x, m_vRealPosition.vec().y - PMONITOR->vecPosition.y},
|
||||
{PMONITOR->vecSize.x - (m_vRealPosition.vec().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.vec().y - PMONITOR->vecPosition.y)}};
|
||||
return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
|
||||
{PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
|
||||
}
|
||||
|
||||
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||
@@ -101,8 +102,8 @@ CBox CWindow::getFullWindowBoundingBox() {
|
||||
|
||||
auto maxExtents = getFullWindowExtents();
|
||||
|
||||
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
||||
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||
CBox finalBox = {m_vRealPosition.value().x - maxExtents.topLeft.x, m_vRealPosition.value().y - maxExtents.topLeft.y,
|
||||
m_vRealSize.value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||
|
||||
return finalBox;
|
||||
}
|
||||
@@ -139,39 +140,29 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
||||
}
|
||||
|
||||
CBox CWindow::getWindowInputBox() {
|
||||
const int BORDERSIZE = getRealBorderSize();
|
||||
CBox CWindow::getWindowBoxUnified(uint64_t properties) {
|
||||
|
||||
if (m_sAdditionalConfigData.dimAround) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||
}
|
||||
|
||||
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||
SWindowDecorationExtents EXTENTS = {{0, 0}, {0, 0}};
|
||||
if (properties & RESERVED_EXTENTS)
|
||||
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(this));
|
||||
if (properties & INPUT_EXTENTS)
|
||||
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, true));
|
||||
if (properties & FULL_EXTENTS)
|
||||
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, false));
|
||||
|
||||
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
|
||||
CBox box = {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
|
||||
box.addExtents(EXTENTS);
|
||||
|
||||
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
||||
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
||||
|
||||
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
|
||||
maxExtents.topLeft.y = EXTENTS.topLeft.y;
|
||||
|
||||
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
|
||||
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
|
||||
|
||||
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
||||
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
||||
|
||||
// Add extents to the real base BB and return
|
||||
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
||||
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||
|
||||
return finalBox;
|
||||
return box;
|
||||
}
|
||||
|
||||
CBox CWindow::getWindowMainSurfaceBox() {
|
||||
return {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
|
||||
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
|
||||
}
|
||||
|
||||
SWindowDecorationExtents CWindow::getFullWindowReservedArea() {
|
||||
@@ -203,7 +194,14 @@ void CWindow::updateWindowDecos() {
|
||||
|
||||
m_vDecosToRemove.clear();
|
||||
|
||||
// make a copy because updateWindow can remove decos.
|
||||
std::vector<IHyprWindowDecoration*> decos;
|
||||
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
decos.push_back(wd.get());
|
||||
}
|
||||
|
||||
for (auto& wd : decos) {
|
||||
wd->updateWindow(this);
|
||||
}
|
||||
}
|
||||
@@ -249,13 +247,12 @@ bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoor
|
||||
pid_t CWindow::getPID() {
|
||||
pid_t PID = -1;
|
||||
if (!m_bIsX11) {
|
||||
|
||||
if (!m_bIsMapped)
|
||||
if (!m_uSurface.xdg)
|
||||
return -1;
|
||||
|
||||
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
|
||||
} else {
|
||||
if (!m_bIsMapped)
|
||||
if (!m_uSurface.xwayland)
|
||||
return -1;
|
||||
|
||||
PID = m_uSurface.xwayland->pid;
|
||||
@@ -318,7 +315,7 @@ void CWindow::destroyToplevelHandle() {
|
||||
}
|
||||
|
||||
void CWindow::updateToplevel() {
|
||||
updateSurfaceOutputs();
|
||||
updateSurfaceScaleTransformDetails();
|
||||
|
||||
if (!m_phForeignToplevel)
|
||||
return;
|
||||
@@ -345,8 +342,8 @@ void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
|
||||
wlr_surface_send_leave(pSurface, OUTPUT);
|
||||
}
|
||||
|
||||
void CWindow::updateSurfaceOutputs() {
|
||||
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden)
|
||||
void CWindow::updateSurfaceScaleTransformDetails() {
|
||||
if (!m_bIsMapped || m_bHidden || g_pCompositor->m_bUnsafeState)
|
||||
return;
|
||||
|
||||
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
|
||||
@@ -355,16 +352,26 @@ void CWindow::updateSurfaceOutputs() {
|
||||
|
||||
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
|
||||
if (!PNEWMONITOR)
|
||||
return;
|
||||
|
||||
if (PNEWMONITOR != PLASTMONITOR) {
|
||||
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
|
||||
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
|
||||
|
||||
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
|
||||
}
|
||||
|
||||
wlr_surface_for_each_surface(
|
||||
m_pWLSurface.wlr(),
|
||||
[](wlr_surface* surf, int x, int y, void* data) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
|
||||
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
|
||||
|
||||
const auto PSURFACE = CWLSurface::surfaceFromWlr(surf);
|
||||
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
|
||||
return;
|
||||
|
||||
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
|
||||
},
|
||||
this);
|
||||
@@ -374,7 +381,7 @@ void CWindow::moveToWorkspace(int workspaceID) {
|
||||
if (m_iWorkspaceID == workspaceID)
|
||||
return;
|
||||
|
||||
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
|
||||
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
|
||||
|
||||
const int OLDWORKSPACE = m_iWorkspaceID;
|
||||
|
||||
@@ -386,6 +393,7 @@ void CWindow::moveToWorkspace(int workspaceID) {
|
||||
|
||||
if (PWORKSPACE) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", std::format("{:x},{}", (uintptr_t)this, PWORKSPACE->m_szName)});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"movewindowv2", std::format("{:x},{},{}", (uintptr_t)this, PWORKSPACE->m_iID, PWORKSPACE->m_szName)});
|
||||
EMIT_HOOK_EVENT("moveWindow", (std::vector<void*>{this, PWORKSPACE}));
|
||||
}
|
||||
|
||||
@@ -395,7 +403,7 @@ void CWindow::moveToWorkspace(int workspaceID) {
|
||||
}
|
||||
|
||||
// update xwayland coords
|
||||
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec());
|
||||
g_pXWaylandManager->setWindowSize(this, m_vRealSize.value());
|
||||
|
||||
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) {
|
||||
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE);
|
||||
@@ -436,11 +444,11 @@ void CWindow::removeDecorationByType(eDecorationType type) {
|
||||
}
|
||||
|
||||
void unregisterVar(void* ptr) {
|
||||
((CAnimatedVariable*)ptr)->unregister();
|
||||
((CBaseAnimatedVariable*)ptr)->unregister();
|
||||
}
|
||||
|
||||
void CWindow::onUnmap() {
|
||||
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
|
||||
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
|
||||
|
||||
if (g_pCompositor->m_pLastWindow == this)
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
@@ -474,12 +482,17 @@ void CWindow::onUnmap() {
|
||||
PMONITOR->solitaryClient = nullptr;
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID);
|
||||
|
||||
if (m_bIsX11)
|
||||
return;
|
||||
|
||||
m_pSubsurfaceHead.reset();
|
||||
m_pPopupHead.reset();
|
||||
}
|
||||
|
||||
void CWindow::onMap() {
|
||||
|
||||
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this));
|
||||
m_pWLSurface.m_pOwner = this;
|
||||
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this), this);
|
||||
|
||||
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
|
||||
m_vRealPosition.resetAllCallbacks();
|
||||
@@ -511,10 +524,24 @@ void CWindow::onMap() {
|
||||
"CWindow");
|
||||
|
||||
m_vReportedSize = m_vPendingReportedSize;
|
||||
|
||||
for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) {
|
||||
if (ctrl->pWlrHint->surface != m_pWLSurface.wlr())
|
||||
continue;
|
||||
|
||||
m_bTearingHint = ctrl->pWlrHint->current;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_bIsX11)
|
||||
return;
|
||||
|
||||
m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
|
||||
m_pPopupHead = std::make_unique<CPopup>(this);
|
||||
}
|
||||
|
||||
void CWindow::onBorderAngleAnimEnd(void* ptr) {
|
||||
const auto PANIMVAR = (CAnimatedVariable*)ptr;
|
||||
const auto PANIMVAR = (CAnimatedVariable<float>*)ptr;
|
||||
|
||||
const std::string STYLE = PANIMVAR->getConfig()->pValues->internalStyle;
|
||||
|
||||
@@ -607,14 +634,42 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
m_sAdditionalConfigData.animationStyle = STYLE;
|
||||
} else if (r.szRule.starts_with("bordercolor")) {
|
||||
try {
|
||||
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||
// Each vector will only get used if it has at least one color
|
||||
CGradientValueData activeBorderGradient = {};
|
||||
CGradientValueData inactiveBorderGradient = {};
|
||||
bool active = true;
|
||||
CVarList colorsAndAngles = CVarList(removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
|
||||
|
||||
if (colorPart.contains(' ')) {
|
||||
// we have a space, 2 values
|
||||
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart.substr(0, colorPart.find_first_of(' ')));
|
||||
m_sSpecialRenderData.inactiveBorderColor = configStringToInt(colorPart.substr(colorPart.find_first_of(' ') + 1));
|
||||
} else {
|
||||
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
|
||||
// Basic form has only two colors, everything else can be parsed as a gradient
|
||||
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
|
||||
m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0])));
|
||||
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1])));
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& token : colorsAndAngles) {
|
||||
// The first angle, or an explicit "0deg", splits the two gradients
|
||||
if (active && token.contains("deg")) {
|
||||
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||
active = false;
|
||||
} else if (token.contains("deg"))
|
||||
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||
else if (active)
|
||||
activeBorderGradient.m_vColors.push_back(configStringToInt(token));
|
||||
else
|
||||
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
|
||||
}
|
||||
|
||||
// Includes sanity checks for the number of colors in each gradient
|
||||
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
|
||||
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
|
||||
else if (activeBorderGradient.m_vColors.empty())
|
||||
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
|
||||
else if (inactiveBorderGradient.m_vColors.empty())
|
||||
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
|
||||
else {
|
||||
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
|
||||
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient;
|
||||
}
|
||||
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||
} else if (r.szRule == "dimaround") {
|
||||
@@ -640,12 +695,44 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
|
||||
else
|
||||
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
|
||||
} else if (r.szRule.starts_with("maxsize")) {
|
||||
try {
|
||||
if (!m_bIsFloating)
|
||||
return;
|
||||
const auto VEC = configStringToVector2D(r.szRule.substr(8));
|
||||
if (VEC.x < 1 || VEC.y < 1) {
|
||||
Debug::log(ERR, "Invalid size for maxsize");
|
||||
return;
|
||||
}
|
||||
|
||||
m_sAdditionalConfigData.maxSize = VEC;
|
||||
m_vRealSize = Vector2D(std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().x, m_vRealSize.goal().x),
|
||||
std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().y, m_vRealSize.goal().y));
|
||||
g_pXWaylandManager->setWindowSize(this, m_vRealSize.goal());
|
||||
setHidden(false);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||
} else if (r.szRule.starts_with("minsize")) {
|
||||
try {
|
||||
if (!m_bIsFloating)
|
||||
return;
|
||||
const auto VEC = configStringToVector2D(r.szRule.substr(8));
|
||||
if (VEC.x < 1 || VEC.y < 1) {
|
||||
Debug::log(ERR, "Invalid size for minsize");
|
||||
return;
|
||||
}
|
||||
|
||||
m_sAdditionalConfigData.minSize = VEC;
|
||||
m_vRealSize = Vector2D(std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().x, m_vRealSize.goal().x),
|
||||
std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().y, m_vRealSize.goal().y));
|
||||
g_pXWaylandManager->setWindowSize(this, m_vRealSize.goal());
|
||||
setHidden(false);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||
}
|
||||
}
|
||||
|
||||
void CWindow::updateDynamicRules() {
|
||||
m_sSpecialRenderData.activeBorderColor = -1;
|
||||
m_sSpecialRenderData.inactiveBorderColor = -1;
|
||||
m_sSpecialRenderData.activeBorderColor = CGradientValueData();
|
||||
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData();
|
||||
m_sSpecialRenderData.alpha = 1.f;
|
||||
m_sSpecialRenderData.alphaInactive = -1.f;
|
||||
m_sAdditionalConfigData.forceNoBlur = false;
|
||||
@@ -654,6 +741,8 @@ void CWindow::updateDynamicRules() {
|
||||
m_sAdditionalConfigData.forceNoDim = false;
|
||||
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
|
||||
m_sAdditionalConfigData.forceOpaque = false;
|
||||
m_sAdditionalConfigData.maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
|
||||
m_sAdditionalConfigData.minSize = Vector2D(20, 20);
|
||||
m_sAdditionalConfigData.forceNoAnims = false;
|
||||
m_sAdditionalConfigData.animationStyle = std::string("");
|
||||
m_sAdditionalConfigData.rounding = -1;
|
||||
@@ -683,10 +772,10 @@ bool CWindow::isInCurvedCorner(double x, double y) {
|
||||
return false;
|
||||
|
||||
// (x0, y0), (x0, y1), ... are the center point of rounding at each corner
|
||||
double x0 = m_vRealPosition.vec().x + ROUNDING;
|
||||
double y0 = m_vRealPosition.vec().y + ROUNDING;
|
||||
double x1 = m_vRealPosition.vec().x + m_vRealSize.vec().x - ROUNDING;
|
||||
double y1 = m_vRealPosition.vec().y + m_vRealSize.vec().y - ROUNDING;
|
||||
double x0 = m_vRealPosition.value().x + ROUNDING;
|
||||
double y0 = m_vRealPosition.value().y + ROUNDING;
|
||||
double x1 = m_vRealPosition.value().x + m_vRealSize.value().x - ROUNDING;
|
||||
double y1 = m_vRealPosition.value().y + m_vRealSize.value().y - ROUNDING;
|
||||
|
||||
if (x < x0 && y < y0) {
|
||||
return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||
@@ -719,7 +808,7 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
|
||||
return false;
|
||||
|
||||
wlr_surface* resultSurf = nullptr;
|
||||
Vector2D origin = m_vRealPosition.vec();
|
||||
Vector2D origin = m_vRealPosition.value();
|
||||
SExtensionFindingData data = {origin, pos, &resultSurf};
|
||||
wlr_xdg_surface_for_each_popup_surface(m_uSurface.xdg, findExtensionForVector2D, &data);
|
||||
|
||||
@@ -858,8 +947,8 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
|
||||
const bool FULLSCREEN = PCURRENT->m_bIsFullscreen;
|
||||
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PCURRENT->m_iWorkspaceID);
|
||||
|
||||
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goalv();
|
||||
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goalv();
|
||||
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
|
||||
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
|
||||
|
||||
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow;
|
||||
|
||||
@@ -953,19 +1042,19 @@ void CWindow::updateGroupOutputs() {
|
||||
curr->m_iMonitorID = m_iMonitorID;
|
||||
curr->moveToWorkspace(m_iWorkspaceID);
|
||||
|
||||
curr->m_vRealPosition = m_vRealPosition.goalv();
|
||||
curr->m_vRealSize = m_vRealSize.goalv();
|
||||
curr->m_vRealPosition = m_vRealPosition.goal();
|
||||
curr->m_vRealSize = m_vRealSize.goal();
|
||||
|
||||
curr = curr->m_sGroupData.pNextWindow;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2D CWindow::middle() {
|
||||
return m_vRealPosition.goalv() + m_vRealSize.goalv() / 2.f;
|
||||
return m_vRealPosition.goal() + m_vRealSize.goal() / 2.f;
|
||||
}
|
||||
|
||||
bool CWindow::opaque() {
|
||||
if (m_fAlpha.fl() != 1.f || m_fActiveInactiveAlpha.fl() != 1.f)
|
||||
if (m_fAlpha.value() != 1.f || m_fActiveInactiveAlpha.value() != 1.f)
|
||||
return false;
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
|
||||
@@ -973,7 +1062,7 @@ bool CWindow::opaque() {
|
||||
if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall)
|
||||
return false;
|
||||
|
||||
if (PWORKSPACE->m_fAlpha.fl() != 1.f)
|
||||
if (PWORKSPACE->m_fAlpha.value() != 1.f)
|
||||
return false;
|
||||
|
||||
if (m_bIsX11)
|
||||
@@ -990,7 +1079,7 @@ bool CWindow::opaque() {
|
||||
}
|
||||
|
||||
float CWindow::rounding() {
|
||||
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
|
||||
static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding");
|
||||
|
||||
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
|
||||
|
||||
@@ -1002,7 +1091,9 @@ void CWindow::updateSpecialRenderData() {
|
||||
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
|
||||
bool border = true;
|
||||
|
||||
if (m_bIsFloating && g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue == 1)
|
||||
static auto PNOBORDERONFLOATING = CConfigValue<Hyprlang::INT>("general:no_border_on_floating");
|
||||
|
||||
if (m_bIsFloating && *PNOBORDERONFLOATING == 1)
|
||||
border = false;
|
||||
|
||||
m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(border);
|
||||
@@ -1022,16 +1113,18 @@ int CWindow::getRealBorderSize() {
|
||||
if (m_sSpecialRenderData.borderSize.toUnderlying() != -1)
|
||||
return m_sSpecialRenderData.borderSize.toUnderlying();
|
||||
|
||||
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
|
||||
|
||||
return *PBORDERSIZE;
|
||||
}
|
||||
|
||||
bool CWindow::canBeTorn() {
|
||||
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
|
||||
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint);
|
||||
}
|
||||
|
||||
bool CWindow::shouldSendFullscreenState() {
|
||||
const auto MODE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID)->m_efFullscreenMode;
|
||||
return m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL));
|
||||
return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL)));
|
||||
}
|
||||
|
||||
void CWindow::setSuspended(bool suspend) {
|
||||
@@ -1044,3 +1137,9 @@ void CWindow::setSuspended(bool suspend) {
|
||||
wlr_xdg_toplevel_set_suspended(m_uSurface.xdg->toplevel, suspend);
|
||||
m_bSuspended = suspend;
|
||||
}
|
||||
|
||||
bool CWindow::visibleOnMonitor(CMonitor* pMonitor) {
|
||||
CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()};
|
||||
|
||||
return wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, wbox.pWlr());
|
||||
}
|
||||
|
@@ -1,13 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "helpers/SubsurfaceTree.hpp"
|
||||
#include "desktop/Subsurface.hpp"
|
||||
#include "helpers/AnimatedVariable.hpp"
|
||||
#include "render/decorations/IHyprWindowDecoration.hpp"
|
||||
#include <deque>
|
||||
#include "config/ConfigDataValues.hpp"
|
||||
#include "helpers/Vector2D.hpp"
|
||||
#include "helpers/WLSurface.hpp"
|
||||
#include "desktop/WLSurface.hpp"
|
||||
#include "desktop/Popup.hpp"
|
||||
#include "macros.hpp"
|
||||
#include "managers/XWaylandManager.hpp"
|
||||
|
||||
@@ -30,6 +31,24 @@ enum eGroupRules {
|
||||
GROUP_OVERRIDE = 1 << 6, // Override other rules
|
||||
};
|
||||
|
||||
enum eGetWindowProperties {
|
||||
WINDOW_ONLY = 0,
|
||||
RESERVED_EXTENTS = 1 << 0,
|
||||
INPUT_EXTENTS = 1 << 1,
|
||||
FULL_EXTENTS = 1 << 2,
|
||||
FLOATING_ONLY = 1 << 3,
|
||||
ALLOW_FLOATING = 1 << 4,
|
||||
USE_PROP_TILED = 1 << 5,
|
||||
};
|
||||
|
||||
enum eSuppressEvents {
|
||||
SUPPRESS_NONE = 0,
|
||||
SUPPRESS_FULLSCREEN = 1 << 0,
|
||||
SUPPRESS_MAXIMIZE = 1 << 1,
|
||||
SUPPRESS_ACTIVATE = 1 << 2,
|
||||
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
|
||||
};
|
||||
|
||||
class IWindowTransformer;
|
||||
|
||||
template <typename T>
|
||||
@@ -111,8 +130,8 @@ struct SWindowSpecialRenderData {
|
||||
CWindowOverridableVar<bool> alphaInactiveOverride = false;
|
||||
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
|
||||
|
||||
CWindowOverridableVar<int64_t> activeBorderColor = -1; // -1 means unset
|
||||
CWindowOverridableVar<int64_t> inactiveBorderColor = -1; // -1 means unset
|
||||
CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset
|
||||
CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset
|
||||
|
||||
// set by the layout
|
||||
CWindowOverridableVar<int> borderSize = -1; // -1 means unset
|
||||
@@ -133,8 +152,11 @@ struct SWindowAdditionalConfigData {
|
||||
CWindowOverridableVar<bool> forceNoBorder = false;
|
||||
CWindowOverridableVar<bool> forceNoShadow = false;
|
||||
CWindowOverridableVar<bool> forceNoDim = false;
|
||||
CWindowOverridableVar<bool> noFocus = false;
|
||||
CWindowOverridableVar<bool> windowDanceCompat = false;
|
||||
CWindowOverridableVar<bool> noMaxSize = false;
|
||||
CWindowOverridableVar<Vector2D> maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
|
||||
CWindowOverridableVar<Vector2D> minSize = Vector2D(20, 20);
|
||||
CWindowOverridableVar<bool> dimAround = false;
|
||||
CWindowOverridableVar<bool> forceRGBX = false;
|
||||
CWindowOverridableVar<bool> keepAspectRatio = false;
|
||||
@@ -174,7 +196,6 @@ class CWindow {
|
||||
DYNLISTENER(setTitleWindow);
|
||||
DYNLISTENER(setGeometryX11U);
|
||||
DYNLISTENER(fullscreenWindow);
|
||||
DYNLISTENER(newPopupXDG);
|
||||
DYNLISTENER(requestMove);
|
||||
DYNLISTENER(requestMinimize);
|
||||
DYNLISTENER(requestMaximize);
|
||||
@@ -191,7 +212,6 @@ class CWindow {
|
||||
// DYNLISTENER(newSubsurfaceWindow);
|
||||
|
||||
CWLSurface m_pWLSurface;
|
||||
std::list<CWLSurface> m_lPopupSurfaces;
|
||||
|
||||
union {
|
||||
wlr_xdg_surface* xdg;
|
||||
@@ -203,8 +223,8 @@ class CWindow {
|
||||
Vector2D m_vSize = Vector2D(0, 0);
|
||||
|
||||
// this is the real position and size used to draw the thing
|
||||
CAnimatedVariable m_vRealPosition;
|
||||
CAnimatedVariable m_vRealSize;
|
||||
CAnimatedVariable<Vector2D> m_vRealPosition;
|
||||
CAnimatedVariable<Vector2D> m_vRealSize;
|
||||
|
||||
// for not spamming the protocols
|
||||
Vector2D m_vReportedPosition;
|
||||
@@ -225,6 +245,7 @@ class CWindow {
|
||||
bool m_bIsFloating = false;
|
||||
bool m_bDraggingTiled = false; // for dragging around tiled windows
|
||||
bool m_bIsFullscreen = false;
|
||||
bool m_bDontSendFullscreen = false;
|
||||
bool m_bWasMaximized = false;
|
||||
uint64_t m_iMonitorID = -1;
|
||||
std::string m_szTitle = "";
|
||||
@@ -250,24 +271,26 @@ class CWindow {
|
||||
//
|
||||
|
||||
// For nofocus
|
||||
bool m_bNoFocus = false;
|
||||
bool m_bNoInitialFocus = false;
|
||||
|
||||
// Fullscreen and Maximize
|
||||
bool m_bWantsInitialFullscreen = false;
|
||||
bool m_bNoFullscreenRequest = false;
|
||||
bool m_bNoMaximizeRequest = false;
|
||||
|
||||
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
|
||||
// bitfield eSuppressEvents
|
||||
uint64_t m_eSuppressedEvents = SUPPRESS_NONE;
|
||||
|
||||
// desktop components
|
||||
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
|
||||
std::unique_ptr<CPopup> m_pPopupHead;
|
||||
|
||||
// Animated border
|
||||
CGradientValueData m_cRealBorderColor = {0};
|
||||
CGradientValueData m_cRealBorderColorPrevious = {0};
|
||||
CAnimatedVariable m_fBorderFadeAnimationProgress;
|
||||
CAnimatedVariable m_fBorderAngleAnimationProgress;
|
||||
CAnimatedVariable<float> m_fBorderFadeAnimationProgress;
|
||||
CAnimatedVariable<float> m_fBorderAngleAnimationProgress;
|
||||
|
||||
// Fade in-out
|
||||
CAnimatedVariable m_fAlpha;
|
||||
CAnimatedVariable<float> m_fAlpha;
|
||||
bool m_bFadingOut = false;
|
||||
bool m_bReadyToDelete = false;
|
||||
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
|
||||
@@ -301,13 +324,13 @@ class CWindow {
|
||||
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
|
||||
|
||||
// for alpha
|
||||
CAnimatedVariable m_fActiveInactiveAlpha;
|
||||
CAnimatedVariable<float> m_fActiveInactiveAlpha;
|
||||
|
||||
// animated shadow color
|
||||
CAnimatedVariable m_cRealShadowColor;
|
||||
CAnimatedVariable<CColor> m_cRealShadowColor;
|
||||
|
||||
// animated tint
|
||||
CAnimatedVariable m_fDimPercent;
|
||||
CAnimatedVariable<float> m_fDimPercent;
|
||||
|
||||
// swallowing
|
||||
CWindow* m_pSwallowed = nullptr;
|
||||
@@ -342,7 +365,7 @@ class CWindow {
|
||||
// methods
|
||||
CBox getFullWindowBoundingBox();
|
||||
SWindowDecorationExtents getFullWindowExtents();
|
||||
CBox getWindowInputBox();
|
||||
CBox getWindowBoxUnified(uint64_t props);
|
||||
CBox getWindowMainSurfaceBox();
|
||||
CBox getWindowIdealBoundingBoxIgnoreReserved();
|
||||
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
|
||||
@@ -356,7 +379,7 @@ class CWindow {
|
||||
void createToplevelHandle();
|
||||
void destroyToplevelHandle();
|
||||
void updateToplevel();
|
||||
void updateSurfaceOutputs();
|
||||
void updateSurfaceScaleTransformDetails();
|
||||
void moveToWorkspace(int);
|
||||
CWindow* X11TransientFor();
|
||||
void onUnmap();
|
||||
@@ -372,6 +395,7 @@ class CWindow {
|
||||
bool canBeTorn();
|
||||
bool shouldSendFullscreenState();
|
||||
void setSuspended(bool suspend);
|
||||
bool visibleOnMonitor(CMonitor* pMonitor);
|
||||
|
||||
int getRealBorderSize();
|
||||
void updateSpecialRenderData();
|
||||
|
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/VarList.hpp"
|
||||
#include <vector>
|
||||
|
||||
enum eConfigValueDataTypes {
|
||||
CVD_TYPE_INVALID = -1,
|
||||
CVD_TYPE_GRADIENT = 0
|
||||
CVD_TYPE_GRADIENT = 0,
|
||||
CVD_TYPE_CSS_VALUE = 1
|
||||
};
|
||||
|
||||
class ICustomConfigValueData {
|
||||
@@ -12,10 +14,13 @@ class ICustomConfigValueData {
|
||||
virtual ~ICustomConfigValueData() = 0;
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() = 0;
|
||||
|
||||
virtual std::string toString() = 0;
|
||||
};
|
||||
|
||||
class CGradientValueData : public ICustomConfigValueData {
|
||||
public:
|
||||
CGradientValueData(){};
|
||||
CGradientValueData(CColor col) {
|
||||
m_vColors.push_back(col);
|
||||
};
|
||||
@@ -48,4 +53,69 @@ class CGradientValueData : public ICustomConfigValueData {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual std::string toString() {
|
||||
std::string result;
|
||||
for (auto& c : m_vColors) {
|
||||
result += std::format("{:x} ", c.getAsHex());
|
||||
}
|
||||
|
||||
result += std::format("{}deg", (int)(m_fAngle * 180.0 / M_PI));
|
||||
}
|
||||
};
|
||||
|
||||
class CCssGapData : public ICustomConfigValueData {
|
||||
public:
|
||||
CCssGapData() : top(0), right(0), bottom(0), left(0){};
|
||||
CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global){};
|
||||
CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal){};
|
||||
CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : top(top), right(horizontal), bottom(bottom), left(horizontal){};
|
||||
CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : top(top), right(right), bottom(bottom), left(left){};
|
||||
|
||||
/* Css like directions */
|
||||
int64_t top;
|
||||
int64_t right;
|
||||
int64_t bottom;
|
||||
int64_t left;
|
||||
|
||||
void parseGapData(CVarList varlist) {
|
||||
switch (varlist.size()) {
|
||||
case 1: {
|
||||
*this = CCssGapData(std::stoi(varlist[0]));
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]));
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]), std::stoi(varlist[2]));
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]), std::stoi(varlist[2]), std::stoi(varlist[3]));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Debug::log(WARN, "Too many arguments provided for gaps.");
|
||||
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]), std::stoi(varlist[2]), std::stoi(varlist[3]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reset(int64_t global) {
|
||||
top = global;
|
||||
right = global;
|
||||
bottom = global;
|
||||
left = global;
|
||||
}
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() {
|
||||
return CVD_TYPE_CSS_VALUE;
|
||||
}
|
||||
|
||||
virtual std::string toString() {
|
||||
return std::format("{} {} {} {}", top, right, bottom, left);
|
||||
}
|
||||
};
|
||||
|
@@ -21,21 +21,13 @@
|
||||
#include "defaultConfig.hpp"
|
||||
#include "ConfigDataValues.hpp"
|
||||
|
||||
#include <hyprlang.hpp>
|
||||
|
||||
#define INITANIMCFG(name) animationConfig[name] = {}
|
||||
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
|
||||
|
||||
#define HANDLE void*
|
||||
|
||||
struct SConfigValue {
|
||||
int64_t intValue = -INT64_MAX;
|
||||
float floatValue = -__FLT_MAX__;
|
||||
std::string strValue = "";
|
||||
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
|
||||
std::shared_ptr<ICustomConfigValueData> data;
|
||||
|
||||
bool set = false; // used for device configs
|
||||
};
|
||||
|
||||
struct SWorkspaceRule {
|
||||
std::string monitor = "";
|
||||
std::string workspaceString = "";
|
||||
@@ -43,14 +35,15 @@ struct SWorkspaceRule {
|
||||
int workspaceId = -1;
|
||||
bool isDefault = false;
|
||||
bool isPersistent = false;
|
||||
std::optional<int64_t> gapsIn;
|
||||
std::optional<int64_t> gapsOut;
|
||||
std::optional<CCssGapData> gapsIn;
|
||||
std::optional<CCssGapData> gapsOut;
|
||||
std::optional<int64_t> borderSize;
|
||||
std::optional<int> border;
|
||||
std::optional<int> rounding;
|
||||
std::optional<int> decorate;
|
||||
std::optional<int> shadow;
|
||||
std::optional<std::string> onCreatedEmptyRunCmd;
|
||||
std::optional<std::string> defaultName;
|
||||
std::map<std::string, std::string> layoutopts;
|
||||
};
|
||||
|
||||
@@ -76,7 +69,12 @@ struct SAnimationPropertyConfig {
|
||||
struct SPluginKeyword {
|
||||
HANDLE handle = 0;
|
||||
std::string name = "";
|
||||
std::function<void(const std::string&, const std::string&)> fn;
|
||||
Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
|
||||
};
|
||||
|
||||
struct SPluginVariable {
|
||||
HANDLE handle = 0;
|
||||
std::string name = "";
|
||||
};
|
||||
|
||||
struct SExecRequestedRule {
|
||||
@@ -91,28 +89,21 @@ class CConfigManager {
|
||||
void tick();
|
||||
void init();
|
||||
|
||||
int getInt(const std::string&);
|
||||
float getFloat(const std::string&);
|
||||
Vector2D getVec(const std::string&);
|
||||
std::string getString(const std::string&);
|
||||
void setFloat(const std::string&, float);
|
||||
void setInt(const std::string&, int);
|
||||
void setVec(const std::string&, Vector2D);
|
||||
void setString(const std::string&, const std::string&);
|
||||
|
||||
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
bool deviceConfigExists(const std::string&);
|
||||
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
|
||||
bool shouldBlurLS(const std::string&);
|
||||
|
||||
SConfigValue* getConfigValuePtr(const std::string&);
|
||||
SConfigValue* getConfigValuePtrSafe(const std::string&);
|
||||
void* const* getConfigValuePtr(const std::string&);
|
||||
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
|
||||
void onPluginLoadUnload(const std::string& name, bool load);
|
||||
static std::string getConfigDir();
|
||||
static std::string getMainConfigPath();
|
||||
|
||||
SMonitorRule getMonitorRuleFor(const std::string&, const std::string& displayName = "");
|
||||
SMonitorRule getMonitorRuleFor(const CMonitor&);
|
||||
SWorkspaceRule getWorkspaceRuleFor(CWorkspace*);
|
||||
std::string getDefaultWorkspaceFor(const std::string&);
|
||||
|
||||
@@ -120,15 +111,15 @@ class CConfigManager {
|
||||
std::string getBoundMonitorStringForWS(const std::string&);
|
||||
const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
|
||||
|
||||
std::vector<SWindowRule> getMatchingRules(CWindow*);
|
||||
std::vector<SWindowRule> getMatchingRules(CWindow*, bool dynamic = true, bool shadowExec = false);
|
||||
std::vector<SLayerRule> getMatchingRules(SLayerSurface*);
|
||||
|
||||
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
|
||||
|
||||
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
|
||||
|
||||
void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
|
||||
void addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& cmd, const std::string& val)> fun);
|
||||
void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value);
|
||||
void addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fun, Hyprlang::SHandlerOptions opts = {});
|
||||
void removePluginConfig(HANDLE handle);
|
||||
|
||||
// no-op when done.
|
||||
@@ -141,7 +132,7 @@ class CConfigManager {
|
||||
void ensureMonitorStatus();
|
||||
void ensureVRR(CMonitor* pMonitor = nullptr);
|
||||
|
||||
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
|
||||
std::string parseKeyword(const std::string&, const std::string&);
|
||||
|
||||
void addParseError(const std::string&);
|
||||
|
||||
@@ -151,28 +142,42 @@ class CConfigManager {
|
||||
|
||||
void handlePluginLoads();
|
||||
|
||||
// keywords
|
||||
std::optional<std::string> handleRawExec(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleMonitor(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleBind(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleBezier(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleAnimation(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleSource(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleSubmap(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleBindWS(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleEnv(const std::string&, const std::string&);
|
||||
std::optional<std::string> handlePlugin(const std::string&, const std::string&);
|
||||
|
||||
std::string configCurrentPath;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
|
||||
|
||||
std::deque<std::string> configPaths; // stores all the config paths
|
||||
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
|
||||
std::vector<std::pair<std::string, std::string>> configDynamicVars; // stores dynamic vars declared by the user
|
||||
std::unordered_map<std::string, SConfigValue> configValues;
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, SConfigValue>> deviceConfigs; // stores device configs
|
||||
|
||||
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
|
||||
|
||||
std::string currentCategory = ""; // For storing the category of the current item
|
||||
|
||||
std::string parseError = ""; // For storing a parse error to display later
|
||||
|
||||
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
|
||||
|
||||
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
|
||||
|
||||
std::vector<std::string> m_vDeclaredPlugins;
|
||||
std::unordered_map<HANDLE, std::unique_ptr<std::unordered_map<std::string, SConfigValue>>> pluginConfigs; // stores plugin configs
|
||||
std::vector<SPluginKeyword> pluginKeywords;
|
||||
std::vector<SPluginVariable> pluginVariables;
|
||||
|
||||
bool isFirstLaunch = true; // For exec-once
|
||||
|
||||
@@ -186,42 +191,16 @@ class CConfigManager {
|
||||
bool m_bManualCrashInitiated = false;
|
||||
std::deque<std::string> firstExecRequests;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> environmentVariables;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
|
||||
|
||||
// internal methods
|
||||
void setDefaultVars();
|
||||
void setDefaultAnimationVars();
|
||||
void setDeviceDefaultVars(const std::string&);
|
||||
void populateEnvironment();
|
||||
|
||||
void setAnimForChildren(SAnimationPropertyConfig* const);
|
||||
void updateBlurredLS(const std::string&, const bool);
|
||||
|
||||
void applyUserDefinedVars(std::string&, const size_t);
|
||||
void loadConfigLoadVars();
|
||||
SConfigValue getConfigValueSafe(const std::string&);
|
||||
SConfigValue getConfigValueSafeDevice(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
void parseLine(std::string&);
|
||||
void configSetValueSafe(const std::string&, const std::string&);
|
||||
void handleDeviceConfig(const std::string&, const std::string&);
|
||||
void handleRawExec(const std::string&, const std::string&);
|
||||
void handleMonitor(const std::string&, const std::string&);
|
||||
void handleBind(const std::string&, const std::string&);
|
||||
void handleUnbind(const std::string&, const std::string&);
|
||||
void handleWindowRule(const std::string&, const std::string&);
|
||||
void handleLayerRule(const std::string&, const std::string&);
|
||||
void handleWindowRuleV2(const std::string&, const std::string&);
|
||||
void handleWorkspaceRules(const std::string&, const std::string&);
|
||||
void handleBezier(const std::string&, const std::string&);
|
||||
void handleAnimation(const std::string&, const std::string&);
|
||||
void handleSource(const std::string&, const std::string&);
|
||||
void handleSubmap(const std::string&, const std::string&);
|
||||
void handleBlurLS(const std::string&, const std::string&);
|
||||
void handleBindWS(const std::string&, const std::string&);
|
||||
void handleEnv(const std::string&, const std::string&);
|
||||
void handlePlugin(const std::string&, const std::string&);
|
||||
void setDefaultAnimationVars();
|
||||
std::optional<std::string> resetHLConfig();
|
||||
std::optional<std::string> verifyConfigExists();
|
||||
void postConfigReload(const Hyprlang::CParseResult& result);
|
||||
void reload();
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CConfigManager> g_pConfigManager;
|
||||
|
72
src/config/ConfigValue.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <hyprlang.hpp>
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
|
||||
template <typename T>
|
||||
class CConfigValue {
|
||||
public:
|
||||
CConfigValue(const std::string& val) {
|
||||
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val.c_str());
|
||||
|
||||
p_ = PVHYPRLANG->getDataStaticPtr();
|
||||
|
||||
#ifdef HYPRLAND_DEBUG
|
||||
// verify type
|
||||
const auto ANY = PVHYPRLANG->getValue();
|
||||
const auto TYPE = std::type_index(ANY.type());
|
||||
|
||||
// exceptions
|
||||
const bool STRINGEX = (typeid(T) == typeid(std::string) && TYPE == typeid(Hyprlang::STRING));
|
||||
const bool CUSTOMEX = (typeid(T) == typeid(Hyprlang::CUSTOMTYPE) && (TYPE == typeid(Hyprlang::CUSTOMTYPE*) || TYPE == typeid(void*) /* dunno why it does this? */));
|
||||
|
||||
RASSERT(typeid(T) == TYPE || STRINGEX || CUSTOMEX, "Mismatched type in CConfigValue<T>, got {} but has {}", typeid(T).name(), TYPE.name());
|
||||
#endif
|
||||
}
|
||||
|
||||
T* ptr() const {
|
||||
return *(T* const*)p_;
|
||||
}
|
||||
|
||||
T operator*() const {
|
||||
return *ptr();
|
||||
}
|
||||
|
||||
private:
|
||||
void* const* p_ = nullptr;
|
||||
};
|
||||
|
||||
template <>
|
||||
inline std::string* CConfigValue<std::string>::ptr() const {
|
||||
RASSERT(false, "Impossible to implement ptr() of CConfigValue<std::string>");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string CConfigValue<std::string>::operator*() const {
|
||||
return std::string{*(Hyprlang::STRING*)p_};
|
||||
}
|
||||
|
||||
template <>
|
||||
inline Hyprlang::STRING* CConfigValue<Hyprlang::STRING>::ptr() const {
|
||||
return (Hyprlang::STRING*)p_;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline Hyprlang::STRING CConfigValue<Hyprlang::STRING>::operator*() const {
|
||||
return *(Hyprlang::STRING*)p_;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline Hyprlang::CUSTOMTYPE* CConfigValue<Hyprlang::CUSTOMTYPE>::ptr() const {
|
||||
return *(Hyprlang::CUSTOMTYPE* const*)p_;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline Hyprlang::CUSTOMTYPE CConfigValue<Hyprlang::CUSTOMTYPE>::operator*() const {
|
||||
RASSERT(false, "Impossible to implement operator* of CConfigValue<Hyprlang::CUSTOMTYPE>, use ptr()");
|
||||
return *ptr();
|
||||
}
|
@@ -4,9 +4,9 @@
|
||||
|
||||
inline const std::string AUTOCONFIG = R"#(
|
||||
# #######################################################################################
|
||||
AUTOGENERATED HYPR CONFIG.
|
||||
PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
|
||||
OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
|
||||
# AUTOGENERATED HYPR CONFIG.
|
||||
# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
|
||||
# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
|
||||
# #######################################################################################
|
||||
|
||||
#
|
||||
@@ -51,7 +51,7 @@ input {
|
||||
natural_scroll = no
|
||||
}
|
||||
|
||||
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
|
||||
sensitivity = 0 # -1.0 to 1.0, 0 means no modification.
|
||||
}
|
||||
|
||||
general {
|
||||
@@ -119,12 +119,13 @@ gestures {
|
||||
|
||||
misc {
|
||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
|
||||
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
||||
}
|
||||
|
||||
# Example per-device config
|
||||
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
|
||||
device:epic-mouse-v1 {
|
||||
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
|
||||
device {
|
||||
name = epic-mouse-v1
|
||||
sensitivity = -0.5
|
||||
}
|
||||
|
||||
@@ -133,7 +134,7 @@ device:epic-mouse-v1 {
|
||||
# Example windowrule v2
|
||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
||||
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
|
||||
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
|
||||
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <fstream>
|
||||
#include <signal.h>
|
||||
#include <link.h>
|
||||
|
||||
#include "../plugins/PluginSystem.hpp"
|
||||
|
||||
@@ -105,21 +106,43 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
const auto FPATH = std::filesystem::canonical("/proc/self/exe");
|
||||
#endif
|
||||
|
||||
std::string addrs = "";
|
||||
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
|
||||
finalCrashReport += std::format("\t#{} | {}\n", i, CALLSTACK[i].desc);
|
||||
|
||||
#ifdef __clang__
|
||||
const auto CMD = std::format("llvm-addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
|
||||
#ifdef __GLIBC__
|
||||
// convert in memory address to VMA address
|
||||
Dl_info info;
|
||||
struct link_map* linkMap;
|
||||
dladdr1((void*)CALLSTACK[i].adr, &info, (void**)&linkMap, RTLD_DL_LINKMAP);
|
||||
size_t vmaAddr = (size_t)CALLSTACK[i].adr - linkMap->l_addr;
|
||||
#else
|
||||
const auto CMD = std::format("addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
|
||||
// musl doesn't define dladdr1
|
||||
size_t vmaAddr = (size_t)CALLSTACK[i].adr;
|
||||
#endif
|
||||
const auto ADDR2LINE = replaceInString(execAndGet(CMD.c_str()), "\n", "\n\t\t");
|
||||
finalCrashReport += "\t\t" + ADDR2LINE.substr(0, ADDR2LINE.length() - 2);
|
||||
|
||||
addrs += std::format("0x{:x} ", vmaAddr);
|
||||
}
|
||||
#ifdef __clang__
|
||||
const auto CMD = std::format("llvm-addr2line -e {} -Cf {}", FPATH.c_str(), addrs);
|
||||
#else
|
||||
const auto CMD = std::format("addr2line -e {} -Cf {}", FPATH.c_str(), addrs);
|
||||
#endif
|
||||
|
||||
const auto ADDR2LINE = execAndGet(CMD.c_str());
|
||||
|
||||
std::stringstream ssin(ADDR2LINE);
|
||||
|
||||
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
|
||||
finalCrashReport += std::format("\t#{} | {}", i, CALLSTACK[i].desc);
|
||||
std::string functionInfo;
|
||||
std::string fileLineInfo;
|
||||
std::getline(ssin, functionInfo);
|
||||
std::getline(ssin, fileLineInfo);
|
||||
finalCrashReport += std::format("\n\t\t{}\n\t\t{}\n", functionInfo, fileLineInfo);
|
||||
}
|
||||
|
||||
finalCrashReport += "\n\nLog tail:\n";
|
||||
|
||||
finalCrashReport += Debug::rollingLog;
|
||||
finalCrashReport += Debug::rollingLog.substr(Debug::rollingLog.find("\n") + 1);
|
||||
|
||||
const auto HOME = getenv("HOME");
|
||||
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
|
||||
@@ -128,22 +151,19 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
return;
|
||||
|
||||
std::ofstream ofs;
|
||||
std::string path;
|
||||
if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
|
||||
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland"))
|
||||
std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
|
||||
std::string reportDir;
|
||||
|
||||
if (!CACHE_HOME || std::string(CACHE_HOME).empty())
|
||||
reportDir = std::string(HOME) + "/.cache/hyprland";
|
||||
else
|
||||
reportDir = std::string(CACHE_HOME) + "/hyprland";
|
||||
|
||||
if (!std::filesystem::exists(reportDir))
|
||||
std::filesystem::create_directory(reportDir);
|
||||
const auto path = reportDir + "/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||
|
||||
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||
ofs.open(path, std::ios::trunc);
|
||||
|
||||
} else {
|
||||
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland"))
|
||||
std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
|
||||
|
||||
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||
ofs.open(path, std::ios::trunc);
|
||||
}
|
||||
|
||||
ofs << finalCrashReport;
|
||||
|
||||
ofs.close();
|
||||
|
@@ -3,24 +3,27 @@
|
||||
#include "../Compositor.hpp"
|
||||
#include <fstream>
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
#include <functional>
|
||||
|
||||
class CHyprCtl {
|
||||
public:
|
||||
CHyprCtl();
|
||||
|
||||
namespace HyprCtl {
|
||||
void startHyprCtlSocket();
|
||||
std::string makeDynamicCall(const std::string& input);
|
||||
std::shared_ptr<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd);
|
||||
void unregisterCommand(const std::shared_ptr<SHyprCtlCommand>& cmd);
|
||||
std::string getReply(std::string);
|
||||
|
||||
// very simple thread-safe request method
|
||||
inline bool requestMade = false;
|
||||
inline bool requestReady = false;
|
||||
inline std::string request = "";
|
||||
int m_iSocketFD = -1;
|
||||
|
||||
inline std::ifstream requestStream;
|
||||
struct {
|
||||
bool all = false;
|
||||
} m_sCurrentRequestParams;
|
||||
|
||||
inline wl_event_source* hyprCtlTickSource = nullptr;
|
||||
private:
|
||||
void startHyprCtlSocket();
|
||||
|
||||
inline int iSocketFD = -1;
|
||||
|
||||
enum eHyprCtlOutputFormat {
|
||||
FORMAT_NORMAL = 0,
|
||||
FORMAT_JSON
|
||||
};
|
||||
std::vector<std::shared_ptr<SHyprCtlCommand>> m_vCommands;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprCtl> g_pHyprCtl;
|
@@ -36,7 +36,7 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
||||
m_szIconFontName = fonts.substr(COLON + 2, LASTCHAR - (COLON + 2));
|
||||
}
|
||||
|
||||
void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon) {
|
||||
void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) {
|
||||
const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
|
||||
|
||||
PNOTIF->text = text;
|
||||
@@ -44,12 +44,25 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC
|
||||
PNOTIF->started.reset();
|
||||
PNOTIF->timeMs = timeMs;
|
||||
PNOTIF->icon = icon;
|
||||
PNOTIF->fontSize = fontSize;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprNotificationOverlay::dismissNotifications(const int amount) {
|
||||
if (amount == -1)
|
||||
m_dNotifications.clear();
|
||||
else {
|
||||
const int AMT = std::min(amount, static_cast<int>(m_dNotifications.size()));
|
||||
|
||||
for (int i = 0; i < AMT; ++i) {
|
||||
m_dNotifications.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
||||
static constexpr auto ANIM_DURATION_MS = 600.0;
|
||||
static constexpr auto ANIM_LAG_MS = 100.0;
|
||||
@@ -62,27 +75,24 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
||||
float maxWidth = 0;
|
||||
|
||||
const auto SCALE = pMonitor->scale;
|
||||
const auto FONTSIZE = std::clamp((int)(13.f * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
|
||||
|
||||
const auto MONSIZE = pMonitor->vecPixelSize;
|
||||
|
||||
cairo_text_extents_t cairoExtents;
|
||||
int iconW = 0, iconH = 0;
|
||||
|
||||
PangoLayout* pangoLayout;
|
||||
PangoFontDescription* pangoFD;
|
||||
|
||||
pangoLayout = pango_cairo_create_layout(m_pCairo);
|
||||
pangoFD = pango_font_description_from_string(("Sans " + std::to_string(FONTSIZE * ICON_SCALE)).c_str());
|
||||
pango_layout_set_font_description(pangoLayout, pangoFD);
|
||||
|
||||
cairo_select_font_face(m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
cairo_set_font_size(m_pCairo, FONTSIZE);
|
||||
|
||||
const auto PBEZIER = g_pAnimationManager->getBezier("default");
|
||||
|
||||
for (auto& notif : m_dNotifications) {
|
||||
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
|
||||
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
|
||||
|
||||
PangoLayout* pangoLayout = pango_cairo_create_layout(m_pCairo);
|
||||
PangoFontDescription* pangoFD = pango_font_description_from_string(("Sans " + std::to_string(FONTSIZE * ICON_SCALE)).c_str());
|
||||
pango_layout_set_font_description(pangoLayout, pangoFD);
|
||||
cairo_set_font_size(m_pCairo, FONTSIZE);
|
||||
|
||||
// first rect (bg, col)
|
||||
const float FIRSTRECTANIMP =
|
||||
@@ -162,10 +172,10 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
||||
|
||||
if (maxWidth < NOTIFSIZE.x)
|
||||
maxWidth = NOTIFSIZE.x;
|
||||
}
|
||||
|
||||
pango_font_description_free(pangoFD);
|
||||
g_object_unref(pangoLayout);
|
||||
}
|
||||
|
||||
// cleanup notifs
|
||||
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
|
||||
@@ -227,3 +237,7 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
|
||||
CBox pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
|
||||
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
|
||||
}
|
||||
|
||||
bool CHyprNotificationOverlay::hasAny() {
|
||||
return !m_dNotifications.empty();
|
||||
}
|
@@ -33,6 +33,7 @@ struct SNotification {
|
||||
CTimer started;
|
||||
float timeMs = 0;
|
||||
eIcons icon = ICON_NONE;
|
||||
float fontSize = 13.f;
|
||||
};
|
||||
|
||||
class CHyprNotificationOverlay {
|
||||
@@ -40,7 +41,9 @@ class CHyprNotificationOverlay {
|
||||
CHyprNotificationOverlay();
|
||||
|
||||
void draw(CMonitor* pMonitor);
|
||||
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
|
||||
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
|
||||
void dismissNotifications(const int amount);
|
||||
bool hasAny();
|
||||
|
||||
private:
|
||||
CBox drawNotifications(CMonitor* pMonitor);
|
||||
|
@@ -22,7 +22,7 @@ void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
|
||||
|
||||
rollingLog += output + "\n";
|
||||
|
||||
if (!disableLogs || !*disableLogs) {
|
||||
if (!disableLogs || !**disableLogs) {
|
||||
std::ofstream ofs;
|
||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||
ofs << "[wlr] " << output << "\n";
|
||||
|
@@ -22,8 +22,8 @@ enum LogLevel {
|
||||
|
||||
namespace Debug {
|
||||
inline std::string logFile;
|
||||
inline int64_t* disableLogs = nullptr;
|
||||
inline int64_t* disableTime = nullptr;
|
||||
inline int64_t* const* disableLogs = nullptr;
|
||||
inline int64_t* const* disableTime = nullptr;
|
||||
inline bool disableStdout = false;
|
||||
inline bool trace = false;
|
||||
inline bool shuttingDown = false;
|
||||
@@ -52,7 +52,7 @@ namespace Debug {
|
||||
}
|
||||
|
||||
// print date and time to the ofs
|
||||
if (disableTime && !*disableTime) {
|
||||
if (disableTime && !**disableTime) {
|
||||
#ifndef _LIBCPP_VERSION
|
||||
logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())});
|
||||
#else
|
||||
@@ -73,7 +73,7 @@ namespace Debug {
|
||||
if (rollingLog.size() > ROLLING_LOG_SIZE)
|
||||
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
|
||||
|
||||
if (!disableLogs || !*disableLogs) {
|
||||
if (!disableLogs || !**disableLogs) {
|
||||
// log to a file
|
||||
std::ofstream ofs;
|
||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||
|
123
src/desktop/Constraint.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "Constraint.hpp"
|
||||
#include "WLSurface.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
CConstraint::CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner) : m_pOwner(owner), m_pConstraint(constraint) {
|
||||
initSignals();
|
||||
|
||||
m_vCursorPosOnActivate = g_pInputManager->getMouseCoordsInternal();
|
||||
|
||||
g_pInputManager->m_vConstraints.push_back(this);
|
||||
|
||||
if (g_pCompositor->m_pLastFocus == m_pOwner->wlr())
|
||||
activate();
|
||||
}
|
||||
|
||||
CConstraint::~CConstraint() {
|
||||
std::erase(g_pInputManager->m_vConstraints, this);
|
||||
}
|
||||
|
||||
static void onConstraintDestroy(void* owner, void* data) {
|
||||
const auto CONSTRAINT = (CConstraint*)owner;
|
||||
CONSTRAINT->onDestroy();
|
||||
}
|
||||
|
||||
static void onConstraintSetRegion(void* owner, void* data) {
|
||||
const auto CONSTRAINT = (CConstraint*)owner;
|
||||
CONSTRAINT->onSetRegion();
|
||||
}
|
||||
|
||||
void CConstraint::initSignals() {
|
||||
hyprListener_setConstraintRegion.initCallback(&m_pConstraint->events.set_region, ::onConstraintSetRegion, this, "CConstraint");
|
||||
hyprListener_destroyConstraint.initCallback(&m_pConstraint->events.destroy, ::onConstraintDestroy, this, "CConstraint");
|
||||
}
|
||||
|
||||
void CConstraint::onDestroy() {
|
||||
if (active())
|
||||
deactivate();
|
||||
|
||||
// this is us
|
||||
m_pOwner->m_pConstraint.reset();
|
||||
}
|
||||
|
||||
void CConstraint::onSetRegion() {
|
||||
if (!m_bActive)
|
||||
return;
|
||||
|
||||
m_rRegion.set(&m_pConstraint->region);
|
||||
m_vPositionHint = m_rRegion.closestPoint(m_vPositionHint);
|
||||
g_pInputManager->simulateMouseMovement(); // to warp the cursor if anything's amiss
|
||||
}
|
||||
|
||||
void CConstraint::onCommit() {
|
||||
if (!m_bActive)
|
||||
return;
|
||||
|
||||
const auto COMMITTED = m_pConstraint->current.committed;
|
||||
|
||||
if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) {
|
||||
m_bHintSet = true;
|
||||
m_vPositionHint = {m_pConstraint->current.cursor_hint.x, m_pConstraint->current.cursor_hint.y};
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
|
||||
if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_REGION)
|
||||
onSetRegion();
|
||||
}
|
||||
|
||||
CRegion CConstraint::logicConstraintRegion() {
|
||||
CRegion rg = m_rRegion;
|
||||
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
|
||||
const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{};
|
||||
rg.translate(CONSTRAINTPOS);
|
||||
return rg;
|
||||
}
|
||||
|
||||
CWLSurface* CConstraint::owner() {
|
||||
return m_pOwner;
|
||||
}
|
||||
|
||||
bool CConstraint::isLocked() {
|
||||
return m_pConstraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED;
|
||||
}
|
||||
|
||||
Vector2D CConstraint::logicPositionHint() {
|
||||
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
|
||||
const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{};
|
||||
|
||||
return m_bHintSet ? CONSTRAINTPOS + m_vPositionHint : m_vCursorPosOnActivate;
|
||||
}
|
||||
|
||||
void CConstraint::deactivate() {
|
||||
if (!m_bActive)
|
||||
return;
|
||||
|
||||
wlr_pointer_constraint_v1_send_deactivated(m_pConstraint);
|
||||
m_bActive = false;
|
||||
|
||||
if (isLocked())
|
||||
g_pCompositor->warpCursorTo(logicPositionHint(), true);
|
||||
|
||||
if (m_pConstraint->lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT)
|
||||
m_bDead = true;
|
||||
}
|
||||
|
||||
void CConstraint::activate() {
|
||||
if (m_bActive || m_bDead)
|
||||
return;
|
||||
|
||||
// TODO: hack, probably not a super duper great idea
|
||||
if (g_pCompositor->m_sSeat.seat->pointer_state.focused_surface != m_pOwner->wlr()) {
|
||||
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
|
||||
const auto LOCAL = SURFBOX.has_value() ? logicPositionHint() - SURFBOX->pos() : Vector2D{};
|
||||
wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, m_pOwner->wlr(), LOCAL.x, LOCAL.y);
|
||||
}
|
||||
|
||||
g_pCompositor->warpCursorTo(logicPositionHint(), true);
|
||||
wlr_pointer_constraint_v1_send_activated(m_pConstraint);
|
||||
m_bActive = true;
|
||||
}
|
||||
|
||||
bool CConstraint::active() {
|
||||
return m_bActive;
|
||||
}
|
44
src/desktop/Constraint.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "../includes.hpp"
|
||||
#include "../helpers/Region.hpp"
|
||||
#include "../helpers/WLListener.hpp"
|
||||
|
||||
class CWLSurface;
|
||||
|
||||
class CConstraint {
|
||||
public:
|
||||
CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner);
|
||||
~CConstraint();
|
||||
|
||||
void onCommit();
|
||||
void onDestroy();
|
||||
void onSetRegion();
|
||||
CRegion logicConstraintRegion();
|
||||
bool isLocked();
|
||||
Vector2D logicPositionHint();
|
||||
|
||||
void deactivate();
|
||||
void activate();
|
||||
bool active();
|
||||
|
||||
CWLSurface* owner();
|
||||
|
||||
private:
|
||||
bool m_bActive = false;
|
||||
CWLSurface* m_pOwner = nullptr;
|
||||
wlr_pointer_constraint_v1* m_pConstraint;
|
||||
|
||||
CRegion m_rRegion;
|
||||
bool m_bHintSet = false;
|
||||
Vector2D m_vPositionHint = {-1, -1};
|
||||
Vector2D m_vCursorPosOnActivate = {-1, -1};
|
||||
|
||||
// for oneshot constraints that have been activated once
|
||||
bool m_bDead = false;
|
||||
|
||||
DYNLISTENER(destroyConstraint);
|
||||
DYNLISTENER(setConstraintRegion);
|
||||
|
||||
void initSignals();
|
||||
};
|
247
src/desktop/Popup.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#include "Popup.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
CPopup::CPopup(CWindow* pOwner) : m_pWindowOwner(pOwner) {
|
||||
initAllSignals();
|
||||
}
|
||||
|
||||
CPopup::CPopup(SLayerSurface* pOwner) : m_pLayerOwner(pOwner) {
|
||||
initAllSignals();
|
||||
}
|
||||
|
||||
CPopup::CPopup(wlr_xdg_popup* popup, CPopup* pOwner) : m_pParent(pOwner), m_pWLR(popup) {
|
||||
m_pWLR->base->data = this;
|
||||
m_sWLSurface.assign(popup->base->surface, this);
|
||||
|
||||
m_pLayerOwner = pOwner->m_pLayerOwner;
|
||||
m_pWindowOwner = pOwner->m_pWindowOwner;
|
||||
|
||||
m_vLastSize = {m_pWLR->current.geometry.width, m_pWLR->current.geometry.height};
|
||||
unconstrain();
|
||||
|
||||
initAllSignals();
|
||||
}
|
||||
|
||||
CPopup::~CPopup() {
|
||||
m_sWLSurface.unassign();
|
||||
if (m_pWLR)
|
||||
m_pWLR->base->data = nullptr;
|
||||
|
||||
hyprListener_commitPopup.removeCallback();
|
||||
hyprListener_repositionPopup.removeCallback();
|
||||
hyprListener_mapPopup.removeCallback();
|
||||
hyprListener_unmapPopup.removeCallback();
|
||||
hyprListener_newPopup.removeCallback();
|
||||
hyprListener_destroyPopup.removeCallback();
|
||||
}
|
||||
|
||||
static void onNewPopup(void* owner, void* data) {
|
||||
const auto POPUP = (CPopup*)owner;
|
||||
POPUP->onNewPopup((wlr_xdg_popup*)data);
|
||||
}
|
||||
|
||||
static void onMapPopup(void* owner, void* data) {
|
||||
const auto POPUP = (CPopup*)owner;
|
||||
POPUP->onMap();
|
||||
}
|
||||
|
||||
static void onDestroyPopup(void* owner, void* data) {
|
||||
const auto POPUP = (CPopup*)owner;
|
||||
POPUP->onDestroy();
|
||||
}
|
||||
|
||||
static void onUnmapPopup(void* owner, void* data) {
|
||||
const auto POPUP = (CPopup*)owner;
|
||||
POPUP->onUnmap();
|
||||
}
|
||||
|
||||
static void onCommitPopup(void* owner, void* data) {
|
||||
const auto POPUP = (CPopup*)owner;
|
||||
POPUP->onCommit();
|
||||
}
|
||||
|
||||
static void onRepositionPopup(void* owner, void* data) {
|
||||
const auto POPUP = (CPopup*)owner;
|
||||
POPUP->onReposition();
|
||||
}
|
||||
|
||||
void CPopup::initAllSignals() {
|
||||
|
||||
if (!m_pWLR) {
|
||||
if (m_pWindowOwner)
|
||||
hyprListener_newPopup.initCallback(&m_pWindowOwner->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head");
|
||||
else if (m_pLayerOwner)
|
||||
hyprListener_newPopup.initCallback(&m_pLayerOwner->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head");
|
||||
else
|
||||
ASSERT(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
hyprListener_repositionPopup.initCallback(&m_pWLR->events.reposition, ::onRepositionPopup, this, "CPopup");
|
||||
hyprListener_destroyPopup.initCallback(&m_pWLR->events.destroy, ::onDestroyPopup, this, "CPopup");
|
||||
hyprListener_mapPopup.initCallback(&m_sWLSurface.wlr()->events.map, ::onMapPopup, this, "CPopup");
|
||||
hyprListener_unmapPopup.initCallback(&m_sWLSurface.wlr()->events.unmap, ::onUnmapPopup, this, "CPopup");
|
||||
hyprListener_commitPopup.initCallback(&m_sWLSurface.wlr()->events.commit, ::onCommitPopup, this, "CPopup");
|
||||
hyprListener_newPopup.initCallback(&m_pWLR->base->events.new_popup, ::onNewPopup, this, "CPopup");
|
||||
}
|
||||
|
||||
void CPopup::onNewPopup(wlr_xdg_popup* popup) {
|
||||
const auto POPUP = m_vChildren.emplace_back(std::make_unique<CPopup>(popup, this)).get();
|
||||
Debug::log(LOG, "New popup at wlr {:x} and hl {:x}", (uintptr_t)popup, (uintptr_t)POPUP);
|
||||
}
|
||||
|
||||
void CPopup::onDestroy() {
|
||||
m_bInert = true;
|
||||
|
||||
if (!m_pParent)
|
||||
return; // head node
|
||||
|
||||
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
|
||||
}
|
||||
|
||||
void CPopup::onMap() {
|
||||
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
|
||||
const auto COORDS = coordsGlobal();
|
||||
|
||||
CBox box;
|
||||
wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr());
|
||||
box.applyFromWlr().translate(COORDS).expand(4);
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
|
||||
m_vLastPos = coordsRelativeToParent();
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
|
||||
|
||||
unconstrain();
|
||||
sendScale();
|
||||
}
|
||||
|
||||
void CPopup::onUnmap() {
|
||||
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
|
||||
const auto COORDS = coordsGlobal();
|
||||
|
||||
CBox box;
|
||||
wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr());
|
||||
box.applyFromWlr().translate(COORDS).expand(4);
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
|
||||
m_pSubsurfaceHead.reset();
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
|
||||
void CPopup::onCommit(bool ignoreSiblings) {
|
||||
if (m_pWLR->base->initial_commit) {
|
||||
wlr_xdg_surface_schedule_configure(m_pWLR->base);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto COORDS = coordsGlobal();
|
||||
const auto COORDSLOCAL = coordsRelativeToParent();
|
||||
|
||||
if (m_vLastSize != Vector2D{m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height} || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) {
|
||||
CBox box = {localToGlobal(m_vLastPos), m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
|
||||
box = {COORDS, m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
|
||||
m_vLastPos = COORDSLOCAL;
|
||||
}
|
||||
|
||||
if (!ignoreSiblings)
|
||||
m_pSubsurfaceHead->recheckDamageForSubsurfaces();
|
||||
|
||||
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
|
||||
|
||||
m_bRequestedReposition = false;
|
||||
}
|
||||
|
||||
void CPopup::onReposition() {
|
||||
Debug::log(LOG, "Popup {:x} requests reposition", (uintptr_t)this);
|
||||
|
||||
m_bRequestedReposition = true;
|
||||
|
||||
m_vLastPos = coordsRelativeToParent();
|
||||
|
||||
unconstrain();
|
||||
}
|
||||
|
||||
void CPopup::unconstrain() {
|
||||
const auto COORDS = t1ParentCoords();
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
|
||||
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
|
||||
CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||
wlr_xdg_popup_unconstrain_from_box(m_pWLR, box.pWlr());
|
||||
}
|
||||
|
||||
Vector2D CPopup::coordsRelativeToParent() {
|
||||
Vector2D offset;
|
||||
|
||||
CPopup* current = this;
|
||||
|
||||
offset -= {m_pWLR->base->current.geometry.x, m_pWLR->base->current.geometry.y};
|
||||
|
||||
while (current->m_pParent) {
|
||||
|
||||
offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy};
|
||||
offset += {current->m_pWLR->current.geometry.x, current->m_pWLR->current.geometry.y};
|
||||
|
||||
current = current->m_pParent;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
Vector2D CPopup::coordsGlobal() {
|
||||
return localToGlobal(coordsRelativeToParent());
|
||||
}
|
||||
|
||||
Vector2D CPopup::localToGlobal(const Vector2D& rel) {
|
||||
return t1ParentCoords() + rel;
|
||||
}
|
||||
|
||||
Vector2D CPopup::t1ParentCoords() {
|
||||
if (m_pWindowOwner)
|
||||
return m_pWindowOwner->m_vRealPosition.value();
|
||||
if (m_pLayerOwner)
|
||||
return m_pLayerOwner->realPosition.value();
|
||||
|
||||
ASSERT(false);
|
||||
return {};
|
||||
}
|
||||
|
||||
void CPopup::recheckTree() {
|
||||
CPopup* curr = this;
|
||||
while (curr->m_pParent) {
|
||||
curr = curr->m_pParent;
|
||||
}
|
||||
|
||||
curr->recheckChildrenRecursive();
|
||||
}
|
||||
|
||||
void CPopup::recheckChildrenRecursive() {
|
||||
for (auto& c : m_vChildren) {
|
||||
c->onCommit(true);
|
||||
c->recheckChildrenRecursive();
|
||||
}
|
||||
}
|
||||
|
||||
Vector2D CPopup::size() {
|
||||
return m_vLastSize;
|
||||
}
|
||||
|
||||
void CPopup::sendScale() {
|
||||
if (m_pWindowOwner)
|
||||
g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pWindowOwner->m_pWLSurface.m_fLastScale);
|
||||
else if (m_pLayerOwner)
|
||||
g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pLayerOwner->surface.m_fLastScale);
|
||||
else
|
||||
UNREACHABLE();
|
||||
}
|
72
src/desktop/Popup.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "Subsurface.hpp"
|
||||
|
||||
struct SLayerSurface;
|
||||
|
||||
class CPopup {
|
||||
public:
|
||||
// dummy head nodes
|
||||
CPopup(CWindow* pOwner);
|
||||
CPopup(SLayerSurface* pOwner);
|
||||
|
||||
// real nodes
|
||||
CPopup(wlr_xdg_popup* popup, CPopup* pOwner);
|
||||
|
||||
~CPopup();
|
||||
|
||||
Vector2D coordsRelativeToParent();
|
||||
Vector2D coordsGlobal();
|
||||
|
||||
Vector2D size();
|
||||
|
||||
void onNewPopup(wlr_xdg_popup* popup);
|
||||
void onDestroy();
|
||||
void onMap();
|
||||
void onUnmap();
|
||||
void onCommit(bool ignoreSiblings = false);
|
||||
void onReposition();
|
||||
|
||||
void recheckTree();
|
||||
|
||||
CWLSurface m_sWLSurface;
|
||||
|
||||
private:
|
||||
// T1 owners, each popup has to have one of these
|
||||
CWindow* m_pWindowOwner = nullptr;
|
||||
SLayerSurface* m_pLayerOwner = nullptr;
|
||||
|
||||
// T2 owners
|
||||
CPopup* m_pParent = nullptr;
|
||||
|
||||
wlr_xdg_popup* m_pWLR = nullptr;
|
||||
|
||||
Vector2D m_vLastSize = {};
|
||||
Vector2D m_vLastPos = {};
|
||||
|
||||
bool m_bRequestedReposition = false;
|
||||
|
||||
bool m_bInert = false;
|
||||
|
||||
//
|
||||
std::vector<std::unique_ptr<CPopup>> m_vChildren;
|
||||
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
|
||||
|
||||
// signals
|
||||
DYNLISTENER(newPopup);
|
||||
DYNLISTENER(destroyPopup);
|
||||
DYNLISTENER(mapPopup);
|
||||
DYNLISTENER(unmapPopup);
|
||||
DYNLISTENER(commitPopup);
|
||||
DYNLISTENER(repositionPopup);
|
||||
|
||||
void initAllSignals();
|
||||
void unconstrain();
|
||||
void recheckChildrenRecursive();
|
||||
void sendScale();
|
||||
|
||||
Vector2D localToGlobal(const Vector2D& rel);
|
||||
Vector2D t1ParentCoords();
|
||||
};
|
243
src/desktop/Subsurface.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
#include "Subsurface.hpp"
|
||||
#include "../events/Events.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
static void onNewSubsurface(void* owner, void* data);
|
||||
|
||||
CSubsurface::CSubsurface(CWindow* pOwner) : m_pWindowParent(pOwner) {
|
||||
initSignals();
|
||||
|
||||
wlr_subsurface* wlrSubsurface;
|
||||
wl_list_for_each(wlrSubsurface, &pOwner->m_pWLSurface.wlr()->current.subsurfaces_below, current.link) {
|
||||
::onNewSubsurface(this, wlrSubsurface);
|
||||
}
|
||||
wl_list_for_each(wlrSubsurface, &pOwner->m_pWLSurface.wlr()->current.subsurfaces_above, current.link) {
|
||||
::onNewSubsurface(this, wlrSubsurface);
|
||||
}
|
||||
}
|
||||
|
||||
CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) {
|
||||
initSignals();
|
||||
|
||||
wlr_subsurface* wlrSubsurface;
|
||||
wl_list_for_each(wlrSubsurface, &pOwner->m_sWLSurface.wlr()->current.subsurfaces_below, current.link) {
|
||||
::onNewSubsurface(this, wlrSubsurface);
|
||||
}
|
||||
wl_list_for_each(wlrSubsurface, &pOwner->m_sWLSurface.wlr()->current.subsurfaces_above, current.link) {
|
||||
::onNewSubsurface(this, wlrSubsurface);
|
||||
}
|
||||
}
|
||||
|
||||
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) {
|
||||
m_sWLSurface.assign(pSubsurface->surface, this);
|
||||
initSignals();
|
||||
initExistingSubsurfaces();
|
||||
}
|
||||
|
||||
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
|
||||
m_sWLSurface.assign(pSubsurface->surface, this);
|
||||
initSignals();
|
||||
initExistingSubsurfaces();
|
||||
}
|
||||
|
||||
CSubsurface::~CSubsurface() {
|
||||
hyprListener_newSubsurface.removeCallback();
|
||||
|
||||
if (!m_pSubsurface)
|
||||
return;
|
||||
|
||||
hyprListener_commitSubsurface.removeCallback();
|
||||
hyprListener_destroySubsurface.removeCallback();
|
||||
}
|
||||
|
||||
static void onNewSubsurface(void* owner, void* data) {
|
||||
const auto PSUBSURFACE = (CSubsurface*)owner;
|
||||
PSUBSURFACE->onNewSubsurface((wlr_subsurface*)data);
|
||||
}
|
||||
|
||||
static void onDestroySubsurface(void* owner, void* data) {
|
||||
const auto PSUBSURFACE = (CSubsurface*)owner;
|
||||
PSUBSURFACE->onDestroy();
|
||||
}
|
||||
|
||||
static void onCommitSubsurface(void* owner, void* data) {
|
||||
const auto PSUBSURFACE = (CSubsurface*)owner;
|
||||
PSUBSURFACE->onCommit();
|
||||
}
|
||||
|
||||
static void onMapSubsurface(void* owner, void* data) {
|
||||
const auto PSUBSURFACE = (CSubsurface*)owner;
|
||||
PSUBSURFACE->onMap();
|
||||
}
|
||||
|
||||
static void onUnmapSubsurface(void* owner, void* data) {
|
||||
const auto PSUBSURFACE = (CSubsurface*)owner;
|
||||
PSUBSURFACE->onUnmap();
|
||||
}
|
||||
|
||||
void CSubsurface::initSignals() {
|
||||
if (m_pSubsurface) {
|
||||
hyprListener_commitSubsurface.initCallback(&m_pSubsurface->surface->events.commit, &onCommitSubsurface, this, "CSubsurface");
|
||||
hyprListener_destroySubsurface.initCallback(&m_pSubsurface->events.destroy, &onDestroySubsurface, this, "CSubsurface");
|
||||
hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface");
|
||||
hyprListener_mapSubsurface.initCallback(&m_pSubsurface->surface->events.map, &onMapSubsurface, this, "CSubsurface");
|
||||
hyprListener_unmapSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface");
|
||||
} else {
|
||||
if (m_pWindowParent)
|
||||
hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
|
||||
else if (m_pPopupParent)
|
||||
hyprListener_newSubsurface.initCallback(&m_pPopupParent->m_sWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
|
||||
else
|
||||
RASSERT(false, "CSubsurface::initSignals empty subsurface");
|
||||
}
|
||||
}
|
||||
|
||||
void CSubsurface::checkSiblingDamage() {
|
||||
if (!m_pParent)
|
||||
return; // ??????????
|
||||
|
||||
const double SCALE = m_pWindowParent && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0;
|
||||
|
||||
for (auto& n : m_pParent->m_vChildren) {
|
||||
if (n.get() == this)
|
||||
continue;
|
||||
|
||||
const auto COORDS = n->coordsGlobal();
|
||||
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE);
|
||||
}
|
||||
}
|
||||
|
||||
void CSubsurface::recheckDamageForSubsurfaces() {
|
||||
for (auto& n : m_vChildren) {
|
||||
const auto COORDS = n->coordsGlobal();
|
||||
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y);
|
||||
}
|
||||
}
|
||||
|
||||
void CSubsurface::onCommit() {
|
||||
// no damaging if it's not visible
|
||||
if (m_pWindowParent && !g_pHyprRenderer->shouldRenderWindow(m_pWindowParent)) {
|
||||
m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
|
||||
|
||||
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
|
||||
if (*PLOGDAMAGE)
|
||||
Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_pWindowParent);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto COORDS = coordsGlobal();
|
||||
|
||||
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
|
||||
|
||||
if (m_pPopupParent)
|
||||
m_pPopupParent->recheckTree();
|
||||
if (m_pWindowParent) // I hate you firefox why are you doing this
|
||||
m_pWindowParent->m_pPopupHead->recheckTree();
|
||||
|
||||
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
|
||||
checkSiblingDamage();
|
||||
|
||||
if (m_vLastSize != Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}) {
|
||||
CBox box{COORDS, m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
|
||||
box = {COORDS, m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
}
|
||||
}
|
||||
|
||||
void CSubsurface::onDestroy() {
|
||||
// destroy children
|
||||
m_vChildren.clear();
|
||||
|
||||
m_bInert = true;
|
||||
|
||||
if (!m_pSubsurface)
|
||||
return; // dummy node, nothing to do, it's the parent dying
|
||||
|
||||
// kill ourselves
|
||||
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
|
||||
}
|
||||
|
||||
void CSubsurface::onNewSubsurface(wlr_subsurface* pSubsurface) {
|
||||
CSubsurface* PSUBSURFACE = nullptr;
|
||||
|
||||
if (m_pWindowParent)
|
||||
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pWindowParent)).get();
|
||||
else if (m_pPopupParent)
|
||||
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pPopupParent)).get();
|
||||
PSUBSURFACE->m_pParent = this;
|
||||
|
||||
ASSERT(PSUBSURFACE);
|
||||
}
|
||||
|
||||
void CSubsurface::onMap() {
|
||||
m_vLastSize = {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
|
||||
|
||||
const auto COORDS = coordsGlobal();
|
||||
CBox box{COORDS, m_vLastSize};
|
||||
box.expand(4);
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
|
||||
if (m_pWindowParent)
|
||||
m_pWindowParent->updateSurfaceScaleTransformDetails();
|
||||
}
|
||||
|
||||
void CSubsurface::onUnmap() {
|
||||
const auto COORDS = coordsGlobal();
|
||||
CBox box{COORDS, m_vLastSize};
|
||||
box.expand(4);
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
|
||||
if (m_sWLSurface.wlr() == g_pCompositor->m_pLastFocus)
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
// TODO: should this remove children? Currently it won't, only on .destroy
|
||||
}
|
||||
|
||||
Vector2D CSubsurface::coordsRelativeToParent() {
|
||||
Vector2D offset;
|
||||
|
||||
CSubsurface* current = this;
|
||||
|
||||
while (current->m_pParent) {
|
||||
|
||||
offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy};
|
||||
offset += {current->m_pSubsurface->current.x, current->m_pSubsurface->current.y};
|
||||
|
||||
current = current->m_pParent;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
Vector2D CSubsurface::coordsGlobal() {
|
||||
Vector2D coords = coordsRelativeToParent();
|
||||
|
||||
if (m_pWindowParent)
|
||||
coords += m_pWindowParent->m_vRealPosition.value();
|
||||
else if (m_pPopupParent)
|
||||
coords += m_pPopupParent->coordsGlobal();
|
||||
|
||||
return coords;
|
||||
}
|
||||
|
||||
void CSubsurface::initExistingSubsurfaces() {
|
||||
if (m_pWindowParent)
|
||||
return;
|
||||
|
||||
wlr_subsurface* wlrSubsurface;
|
||||
wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_below, current.link) {
|
||||
::onNewSubsurface(this, wlrSubsurface);
|
||||
}
|
||||
wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_above, current.link) {
|
||||
::onNewSubsurface(this, wlrSubsurface);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2D CSubsurface::size() {
|
||||
return {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
|
||||
}
|
59
src/desktop/Subsurface.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include <vector>
|
||||
#include "WLSurface.hpp"
|
||||
|
||||
class CWindow;
|
||||
class CPopup;
|
||||
|
||||
class CSubsurface {
|
||||
public:
|
||||
// root dummy nodes
|
||||
CSubsurface(CWindow* pOwner);
|
||||
CSubsurface(CPopup* pOwner);
|
||||
|
||||
// real nodes
|
||||
CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner);
|
||||
CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner);
|
||||
|
||||
~CSubsurface();
|
||||
|
||||
Vector2D coordsRelativeToParent();
|
||||
Vector2D coordsGlobal();
|
||||
|
||||
Vector2D size();
|
||||
|
||||
void onCommit();
|
||||
void onDestroy();
|
||||
void onNewSubsurface(wlr_subsurface* pSubsurface);
|
||||
void onMap();
|
||||
void onUnmap();
|
||||
|
||||
void recheckDamageForSubsurfaces();
|
||||
|
||||
private:
|
||||
DYNLISTENER(destroySubsurface);
|
||||
DYNLISTENER(commitSubsurface);
|
||||
DYNLISTENER(newSubsurface);
|
||||
DYNLISTENER(mapSubsurface);
|
||||
DYNLISTENER(unmapSubsurface);
|
||||
|
||||
wlr_subsurface* m_pSubsurface = nullptr;
|
||||
CWLSurface m_sWLSurface;
|
||||
Vector2D m_vLastSize = {};
|
||||
|
||||
// if nullptr, means it's a dummy node
|
||||
CSubsurface* m_pParent = nullptr;
|
||||
|
||||
CWindow* m_pWindowParent = nullptr;
|
||||
CPopup* m_pPopupParent = nullptr;
|
||||
|
||||
std::vector<std::unique_ptr<CSubsurface>> m_vChildren;
|
||||
|
||||
bool m_bInert = false;
|
||||
|
||||
void initSignals();
|
||||
void initExistingSubsurfaces();
|
||||
void checkSiblingDamage();
|
||||
};
|
196
src/desktop/WLSurface.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
#include "WLSurface.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
void CWLSurface::assign(wlr_surface* pSurface) {
|
||||
m_pWLRSurface = pSurface;
|
||||
init();
|
||||
m_bInert = false;
|
||||
}
|
||||
|
||||
void CWLSurface::assign(wlr_surface* pSurface, CWindow* pOwner) {
|
||||
m_pWindowOwner = pOwner;
|
||||
m_pWLRSurface = pSurface;
|
||||
init();
|
||||
m_bInert = false;
|
||||
}
|
||||
|
||||
void CWLSurface::assign(wlr_surface* pSurface, SLayerSurface* pOwner) {
|
||||
m_pLayerOwner = pOwner;
|
||||
m_pWLRSurface = pSurface;
|
||||
init();
|
||||
m_bInert = false;
|
||||
}
|
||||
|
||||
void CWLSurface::assign(wlr_surface* pSurface, CSubsurface* pOwner) {
|
||||
m_pSubsurfaceOwner = pOwner;
|
||||
m_pWLRSurface = pSurface;
|
||||
init();
|
||||
m_bInert = false;
|
||||
}
|
||||
|
||||
void CWLSurface::assign(wlr_surface* pSurface, CPopup* pOwner) {
|
||||
m_pPopupOwner = pOwner;
|
||||
m_pWLRSurface = pSurface;
|
||||
init();
|
||||
m_bInert = false;
|
||||
}
|
||||
|
||||
void CWLSurface::unassign() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
CWLSurface::~CWLSurface() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
bool CWLSurface::exists() const {
|
||||
return m_pWLRSurface;
|
||||
}
|
||||
|
||||
wlr_surface* CWLSurface::wlr() const {
|
||||
return m_pWLRSurface;
|
||||
}
|
||||
|
||||
bool CWLSurface::small() const {
|
||||
if (!m_pWindowOwner || !exists())
|
||||
return false;
|
||||
|
||||
return m_pWindowOwner->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || m_pWindowOwner->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1;
|
||||
}
|
||||
|
||||
Vector2D CWLSurface::correctSmallVec() const {
|
||||
if (!m_pWindowOwner || !exists() || !small() || m_bFillIgnoreSmall)
|
||||
return {};
|
||||
|
||||
const auto SIZE = getViewporterCorrectedSize();
|
||||
|
||||
return Vector2D{(m_pWindowOwner->m_vReportedSize.x - SIZE.x) / 2, (m_pWindowOwner->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) *
|
||||
(m_pWindowOwner->m_vRealSize.value() / m_pWindowOwner->m_vReportedSize);
|
||||
}
|
||||
|
||||
Vector2D CWLSurface::getViewporterCorrectedSize() const {
|
||||
if (!exists())
|
||||
return {};
|
||||
|
||||
return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} :
|
||||
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
|
||||
}
|
||||
|
||||
CRegion CWLSurface::logicalDamage() const {
|
||||
CRegion damage{&m_pWLRSurface->buffer_damage};
|
||||
damage.transform(m_pWLRSurface->current.transform, m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height);
|
||||
damage.scale(1.0 / m_pWLRSurface->current.scale);
|
||||
|
||||
const auto VPSIZE = getViewporterCorrectedSize();
|
||||
const auto CORRECTVEC = correctSmallVec();
|
||||
|
||||
if (m_pWLRSurface->current.viewport.has_src) {
|
||||
damage.intersect(CBox{std::floor(m_pWLRSurface->current.viewport.src.x), std::floor(m_pWLRSurface->current.viewport.src.y),
|
||||
std::ceil(m_pWLRSurface->current.viewport.src.width), std::ceil(m_pWLRSurface->current.viewport.src.height)});
|
||||
}
|
||||
|
||||
const auto SCALEDSRCSIZE = m_pWLRSurface->current.viewport.has_src ?
|
||||
Vector2D{m_pWLRSurface->current.viewport.src.width, m_pWLRSurface->current.viewport.src.height} * m_pWLRSurface->current.scale :
|
||||
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
|
||||
|
||||
damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y});
|
||||
damage.translate(CORRECTVEC);
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
void CWLSurface::destroy() {
|
||||
if (!m_pWLRSurface)
|
||||
return;
|
||||
|
||||
m_pConstraint.reset();
|
||||
|
||||
hyprListener_destroy.removeCallback();
|
||||
hyprListener_commit.removeCallback();
|
||||
m_pWLRSurface->data = nullptr;
|
||||
m_pWindowOwner = nullptr;
|
||||
m_pLayerOwner = nullptr;
|
||||
m_pPopupOwner = nullptr;
|
||||
m_pSubsurfaceOwner = nullptr;
|
||||
m_bInert = true;
|
||||
|
||||
if (g_pCompositor && g_pCompositor->m_pLastFocus == m_pWLRSurface)
|
||||
g_pCompositor->m_pLastFocus = nullptr;
|
||||
if (g_pInputManager && g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
|
||||
g_pInputManager->m_pLastMouseSurface = nullptr;
|
||||
if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
|
||||
g_pHyprRenderer->m_sLastCursorData.surf.reset();
|
||||
|
||||
m_pWLRSurface = nullptr;
|
||||
|
||||
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
|
||||
}
|
||||
|
||||
static void onCommit(void* owner, void* data) {
|
||||
const auto SURF = (CWLSurface*)owner;
|
||||
SURF->onCommit();
|
||||
}
|
||||
|
||||
void CWLSurface::init() {
|
||||
if (!m_pWLRSurface)
|
||||
return;
|
||||
|
||||
RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!");
|
||||
|
||||
m_pWLRSurface->data = this;
|
||||
|
||||
hyprListener_destroy.initCallback(
|
||||
&m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
|
||||
hyprListener_commit.initCallback(&m_pWLRSurface->events.commit, ::onCommit, this, "CWLSurface");
|
||||
|
||||
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
|
||||
}
|
||||
|
||||
CWindow* CWLSurface::getWindow() {
|
||||
return m_pWindowOwner;
|
||||
}
|
||||
|
||||
SLayerSurface* CWLSurface::getLayer() {
|
||||
return m_pLayerOwner;
|
||||
}
|
||||
|
||||
CPopup* CWLSurface::getPopup() {
|
||||
return m_pPopupOwner;
|
||||
}
|
||||
|
||||
CSubsurface* CWLSurface::getSubsurface() {
|
||||
return m_pSubsurfaceOwner;
|
||||
}
|
||||
|
||||
bool CWLSurface::desktopComponent() {
|
||||
return m_pLayerOwner || m_pWindowOwner || m_pSubsurfaceOwner || m_pPopupOwner;
|
||||
}
|
||||
|
||||
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() {
|
||||
if (!desktopComponent())
|
||||
return {};
|
||||
|
||||
if (m_pWindowOwner)
|
||||
return m_pWindowOwner->getWindowMainSurfaceBox();
|
||||
if (m_pLayerOwner)
|
||||
return m_pLayerOwner->geometry;
|
||||
if (m_pPopupOwner)
|
||||
return CBox{m_pPopupOwner->coordsGlobal(), m_pPopupOwner->size()};
|
||||
if (m_pSubsurfaceOwner)
|
||||
return CBox{m_pSubsurfaceOwner->coordsGlobal(), m_pSubsurfaceOwner->size()};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void CWLSurface::appendConstraint(wlr_pointer_constraint_v1* constraint) {
|
||||
m_pConstraint = std::make_unique<CConstraint>(constraint, this);
|
||||
}
|
||||
|
||||
void CWLSurface::onCommit() {
|
||||
if (m_pConstraint)
|
||||
m_pConstraint->onCommit();
|
||||
}
|
||||
|
||||
CConstraint* CWLSurface::constraint() {
|
||||
return m_pConstraint.get();
|
||||
}
|
105
src/desktop/WLSurface.hpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/Region.hpp"
|
||||
#include "Constraint.hpp"
|
||||
|
||||
class CWindow;
|
||||
struct SLayerSurface;
|
||||
class CSubsurface;
|
||||
class CPopup;
|
||||
|
||||
class CWLSurface {
|
||||
public:
|
||||
CWLSurface() = default;
|
||||
~CWLSurface();
|
||||
|
||||
// anonymous surfaces are non-desktop components, e.g. a cursor surface or a DnD
|
||||
void assign(wlr_surface* pSurface);
|
||||
void assign(wlr_surface* pSurface, CWindow* pOwner);
|
||||
void assign(wlr_surface* pSurface, SLayerSurface* pOwner);
|
||||
void assign(wlr_surface* pSurface, CSubsurface* pOwner);
|
||||
void assign(wlr_surface* pSurface, CPopup* pOwner);
|
||||
void unassign();
|
||||
|
||||
CWLSurface(const CWLSurface&) = delete;
|
||||
CWLSurface(CWLSurface&&) = delete;
|
||||
CWLSurface& operator=(const CWLSurface&) = delete;
|
||||
CWLSurface& operator=(CWLSurface&&) = delete;
|
||||
|
||||
wlr_surface* wlr() const;
|
||||
bool exists() const;
|
||||
bool small() const; // means surface is smaller than the requested size
|
||||
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
|
||||
Vector2D getViewporterCorrectedSize() const;
|
||||
CRegion logicalDamage() const;
|
||||
void onCommit();
|
||||
|
||||
// getters for owners.
|
||||
CWindow* getWindow();
|
||||
SLayerSurface* getLayer();
|
||||
CPopup* getPopup();
|
||||
CSubsurface* getSubsurface();
|
||||
|
||||
// desktop components misc utils
|
||||
std::optional<CBox> getSurfaceBoxGlobal();
|
||||
void appendConstraint(wlr_pointer_constraint_v1* constraint);
|
||||
CConstraint* constraint();
|
||||
|
||||
// allow stretching. Useful for plugins.
|
||||
bool m_bFillIgnoreSmall = false;
|
||||
|
||||
// track surface data and avoid dupes
|
||||
float m_fLastScale = 0;
|
||||
int m_iLastScale = 0;
|
||||
wl_output_transform m_eLastTransform = (wl_output_transform)-1;
|
||||
|
||||
//
|
||||
CWLSurface& operator=(wlr_surface* pSurface) {
|
||||
destroy();
|
||||
m_pWLRSurface = pSurface;
|
||||
init();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const CWLSurface& other) const {
|
||||
return other.wlr() == wlr();
|
||||
}
|
||||
|
||||
bool operator==(const wlr_surface* other) const {
|
||||
return other == wlr();
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return exists();
|
||||
}
|
||||
|
||||
static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) {
|
||||
if (!pSurface)
|
||||
return nullptr;
|
||||
return (CWLSurface*)pSurface->data;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_bInert = true;
|
||||
|
||||
wlr_surface* m_pWLRSurface = nullptr;
|
||||
|
||||
CWindow* m_pWindowOwner = nullptr;
|
||||
SLayerSurface* m_pLayerOwner = nullptr;
|
||||
CPopup* m_pPopupOwner = nullptr;
|
||||
CSubsurface* m_pSubsurfaceOwner = nullptr;
|
||||
|
||||
//
|
||||
std::unique_ptr<CConstraint> m_pConstraint;
|
||||
|
||||
void destroy();
|
||||
void init();
|
||||
bool desktopComponent();
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(commit);
|
||||
|
||||
friend class CConstraint;
|
||||
};
|
@@ -1,7 +1,8 @@
|
||||
#include "Workspace.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
|
||||
CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
|
||||
|
||||
if (!PMONITOR) {
|
||||
@@ -10,12 +11,13 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
|
||||
}
|
||||
|
||||
m_iMonitorID = monitorID;
|
||||
m_iID = id;
|
||||
m_szName = name;
|
||||
m_bIsSpecialWorkspace = special;
|
||||
|
||||
m_vRenderOffset.m_pWorkspace = this;
|
||||
m_vRenderOffset.create(AVARTYPE_VECTOR, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"),
|
||||
nullptr, AVARDAMAGE_ENTIRE);
|
||||
m_vRenderOffset.create(special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr,
|
||||
AVARDAMAGE_ENTIRE);
|
||||
m_fAlpha.m_pWorkspace = this;
|
||||
m_fAlpha.create(AVARTYPE_FLOAT, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"),
|
||||
nullptr, AVARDAMAGE_ENTIRE);
|
||||
@@ -24,7 +26,12 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
|
||||
m_vRenderOffset.registerVar();
|
||||
m_fAlpha.registerVar();
|
||||
|
||||
const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(this);
|
||||
if (RULEFORTHIS.defaultName.has_value())
|
||||
m_szName = RULEFORTHIS.defaultName.value();
|
||||
|
||||
g_pEventManager->postEvent({"createworkspace", m_szName});
|
||||
g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)});
|
||||
EMIT_HOOK_EVENT("createWorkspace", this);
|
||||
}
|
||||
|
||||
@@ -34,12 +41,13 @@ CWorkspace::~CWorkspace() {
|
||||
Debug::log(LOG, "Destroying workspace ID {}", m_iID);
|
||||
|
||||
g_pEventManager->postEvent({"destroyworkspace", m_szName});
|
||||
g_pEventManager->postEvent({"destroyworkspacev2", std::format("{},{}", m_iID, m_szName)});
|
||||
EMIT_HOOK_EVENT("destroyWorkspace", this);
|
||||
}
|
||||
|
||||
void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
|
||||
const auto PWORKSPACEGAP = &g_pConfigManager->getConfigValuePtr("general:gaps_workspaces")->intValue;
|
||||
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
|
||||
|
||||
if (ANIMSTYLE.starts_with("slidefade")) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "AnimatedVariable.hpp"
|
||||
#include "../helpers/AnimatedVariable.hpp"
|
||||
#include <string>
|
||||
#include "../defines.hpp"
|
||||
|
||||
@@ -14,7 +14,7 @@ class CWindow;
|
||||
|
||||
class CWorkspace {
|
||||
public:
|
||||
CWorkspace(int monitorID, std::string name, bool special = false);
|
||||
CWorkspace(int id, int monitorID, std::string name, bool special = false);
|
||||
~CWorkspace();
|
||||
|
||||
// Workspaces ID-based have IDs > 0
|
||||
@@ -35,8 +35,8 @@ class CWorkspace {
|
||||
wl_array m_wlrCoordinateArr;
|
||||
|
||||
// for animations
|
||||
CAnimatedVariable m_vRenderOffset;
|
||||
CAnimatedVariable m_fAlpha;
|
||||
CAnimatedVariable<Vector2D> m_vRenderOffset;
|
||||
CAnimatedVariable<float> m_fAlpha;
|
||||
bool m_bForceRendering = false;
|
||||
|
||||
// "scratchpad"
|
@@ -74,7 +74,7 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "Attached a touch device with name {}", DEVICE->name);
|
||||
g_pInputManager->newTouchDevice(DEVICE);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
||||
case WLR_INPUT_DEVICE_TABLET:
|
||||
Debug::log(LOG, "Attached a tablet tool with name {}", DEVICE->name);
|
||||
g_pInputManager->newTabletTool(DEVICE);
|
||||
break;
|
||||
@@ -97,44 +97,14 @@ void Events::listener_newConstraint(wl_listener* listener, void* data) {
|
||||
|
||||
Debug::log(LOG, "New mouse constraint at {:x}", (uintptr_t)PCONSTRAINT);
|
||||
|
||||
g_pInputManager->m_lConstraints.emplace_back();
|
||||
const auto CONSTRAINT = &g_pInputManager->m_lConstraints.back();
|
||||
const auto SURFACE = CWLSurface::surfaceFromWlr(PCONSTRAINT->surface);
|
||||
|
||||
CONSTRAINT->pMouse = g_pCompositor->m_sSeat.mouse;
|
||||
CONSTRAINT->constraint = PCONSTRAINT;
|
||||
|
||||
CONSTRAINT->hyprListener_destroyConstraint.initCallback(&PCONSTRAINT->events.destroy, &Events::listener_destroyConstraint, CONSTRAINT, "Constraint");
|
||||
CONSTRAINT->hyprListener_setConstraintRegion.initCallback(&PCONSTRAINT->events.set_region, &Events::listener_setConstraintRegion, CONSTRAINT, "Constraint");
|
||||
|
||||
if (g_pCompositor->m_pLastFocus == PCONSTRAINT->surface) {
|
||||
g_pInputManager->constrainMouse(CONSTRAINT->pMouse, PCONSTRAINT);
|
||||
|
||||
if (!CONSTRAINT->hintSet)
|
||||
CONSTRAINT->positionHint = Vector2D{-1, -1};
|
||||
}
|
||||
if (!SURFACE) {
|
||||
Debug::log(ERR, "Refusing a constraint from an unassigned wl_surface {:x}", (uintptr_t)PCONSTRAINT->surface);
|
||||
return;
|
||||
}
|
||||
|
||||
void Events::listener_destroyConstraint(void* owner, void* data) {
|
||||
const auto PCONSTRAINT = (SConstraint*)owner;
|
||||
|
||||
if (PCONSTRAINT->pMouse->currentConstraint == PCONSTRAINT->constraint) {
|
||||
PCONSTRAINT->pMouse->hyprListener_commitConstraint.removeCallback();
|
||||
|
||||
const auto PWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
|
||||
|
||||
if (PWINDOW && PCONSTRAINT->active && PCONSTRAINT->constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
|
||||
g_pInputManager->warpMouseToConstraintMiddle(PCONSTRAINT);
|
||||
|
||||
PCONSTRAINT->pMouse->currentConstraint = nullptr;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Unconstrained mouse from {:x}", (uintptr_t)PCONSTRAINT->constraint);
|
||||
|
||||
g_pInputManager->m_lConstraints.remove(*PCONSTRAINT);
|
||||
}
|
||||
|
||||
void Events::listener_setConstraintRegion(void* owner, void* data) {
|
||||
// no
|
||||
SURFACE->appendConstraint(PCONSTRAINT);
|
||||
}
|
||||
|
||||
void Events::listener_newVirtPtr(wl_listener* listener, void* data) {
|
||||
|
@@ -22,25 +22,6 @@ namespace Events {
|
||||
DYNLISTENFUNC(unmapLayerSurface);
|
||||
DYNLISTENFUNC(commitLayerSurface);
|
||||
|
||||
// Subsurfaces
|
||||
DYNLISTENFUNC(newSubsurfaceNode);
|
||||
DYNLISTENFUNC(destroySubsurfaceNode);
|
||||
DYNLISTENFUNC(mapSubsurface);
|
||||
DYNLISTENFUNC(unmapSubsurface);
|
||||
DYNLISTENFUNC(destroySubsurface);
|
||||
DYNLISTENFUNC(commitSubsurface);
|
||||
|
||||
// Popups
|
||||
DYNLISTENFUNC(newPopup); // LayerSurface
|
||||
|
||||
DYNLISTENFUNC(newPopupXDG);
|
||||
DYNLISTENFUNC(mapPopupXDG);
|
||||
DYNLISTENFUNC(unmapPopupXDG);
|
||||
DYNLISTENFUNC(destroyPopupXDG);
|
||||
DYNLISTENFUNC(commitPopupXDG);
|
||||
DYNLISTENFUNC(newPopupFromPopupXDG);
|
||||
DYNLISTENFUNC(repositionPopupXDG);
|
||||
|
||||
// Surface XDG (window)
|
||||
LISTENER(newXDGToplevel);
|
||||
LISTENER(activateXDG);
|
||||
@@ -84,10 +65,7 @@ namespace Events {
|
||||
DYNLISTENFUNC(keyboardMod);
|
||||
DYNLISTENFUNC(keyboardDestroy);
|
||||
|
||||
DYNLISTENFUNC(commitConstraint);
|
||||
LISTENER(newConstraint);
|
||||
DYNLISTENFUNC(setConstraintRegion);
|
||||
DYNLISTENFUNC(destroyConstraint);
|
||||
|
||||
// Various
|
||||
LISTENER(requestMouse);
|
||||
@@ -174,4 +152,7 @@ namespace Events {
|
||||
|
||||
// Tearing hints
|
||||
LISTENER(newTearingHint);
|
||||
|
||||
// Shortcut inhibitor
|
||||
LISTENER(newShortcutInhibitor);
|
||||
};
|
||||
|
@@ -46,12 +46,12 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
|
||||
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface");
|
||||
layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");
|
||||
layerSurface->hyprListener_unmapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.unmap, &Events::listener_unmapLayerSurface, layerSurface, "layerSurface");
|
||||
layerSurface->hyprListener_newPopup.initCallback(&WLRLAYERSURFACE->events.new_popup, &Events::listener_newPopup, layerSurface, "layerSurface");
|
||||
|
||||
layerSurface->layerSurface = WLRLAYERSURFACE;
|
||||
layerSurface->layer = WLRLAYERSURFACE->current.layer;
|
||||
WLRLAYERSURFACE->data = layerSurface;
|
||||
layerSurface->monitorID = PMONITOR->ID;
|
||||
layerSurface->popupHead = std::make_unique<CPopup>(layerSurface);
|
||||
|
||||
layerSurface->forceBlur = g_pConfigManager->shouldBlurLS(layerSurface->szNamespace);
|
||||
|
||||
@@ -66,6 +66,8 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
||||
|
||||
layersurface->popupHead.reset();
|
||||
|
||||
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID))
|
||||
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
|
||||
|
||||
@@ -87,7 +89,6 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
|
||||
layersurface->hyprListener_destroyLayerSurface.removeCallback();
|
||||
layersurface->hyprListener_mapLayerSurface.removeCallback();
|
||||
layersurface->hyprListener_unmapLayerSurface.removeCallback();
|
||||
layersurface->hyprListener_newPopup.removeCallback();
|
||||
|
||||
// rearrange to fix the reserved areas
|
||||
if (PMONITOR) {
|
||||
@@ -113,9 +114,6 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive;
|
||||
layersurface->surface = layersurface->layerSurface->surface;
|
||||
|
||||
// anim
|
||||
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
|
||||
|
||||
// fix if it changed its mon
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
|
||||
|
||||
@@ -142,9 +140,12 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
|
||||
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
|
||||
|
||||
if (layersurface->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
|
||||
g_pInputManager->m_dExclusiveLSes.push_back(layersurface);
|
||||
|
||||
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
|
||||
// don't focus if constrained
|
||||
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
|
||||
(!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained());
|
||||
|
||||
if (GRABSFOCUS) {
|
||||
g_pCompositor->focusSurface(layersurface->layerSurface->surface);
|
||||
@@ -153,6 +154,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
|
||||
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y);
|
||||
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y);
|
||||
g_pInputManager->m_bEmptyFocusCursorSet = false;
|
||||
}
|
||||
|
||||
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
|
||||
@@ -163,8 +165,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
|
||||
|
||||
layersurface->alpha.setValue(0);
|
||||
layersurface->alpha = ((layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS) ? 0.f : 1.f);
|
||||
layersurface->startAnimation(!(layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
|
||||
layersurface->readyToDelete = false;
|
||||
layersurface->fadingOut = false;
|
||||
|
||||
@@ -183,6 +184,11 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
|
||||
EMIT_HOOK_EVENT("closeLayer", layersurface);
|
||||
|
||||
std::erase(g_pInputManager->m_dExclusiveLSes, layersurface);
|
||||
|
||||
if (!g_pInputManager->m_dExclusiveLSes.empty())
|
||||
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface);
|
||||
|
||||
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
|
||||
|
||||
@@ -190,23 +196,17 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||
|
||||
layersurface->mapped = false;
|
||||
|
||||
layersurface->fadingOut = true;
|
||||
|
||||
layersurface->alpha.setValueAndWarp(0.f);
|
||||
layersurface->startAnimation(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// anim
|
||||
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut"));
|
||||
|
||||
// make a snapshot and start fade
|
||||
g_pHyprOpenGL->makeLayerSnapshot(layersurface);
|
||||
layersurface->alpha = 0.f;
|
||||
|
||||
layersurface->startAnimation(false);
|
||||
|
||||
layersurface->mapped = false;
|
||||
|
||||
layersurface->fadingOut = true;
|
||||
|
||||
g_pCompositor->addToFadingOutSafe(layersurface);
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
|
||||
@@ -236,7 +236,7 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
&surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
if (!foundSurface) {
|
||||
if (!foundSurface && g_pCompositor->m_pLastWindow) {
|
||||
// if there isn't any, focus the last window
|
||||
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
|
||||
g_pCompositor->focusWindow(nullptr);
|
||||
@@ -327,8 +327,20 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||
}
|
||||
}
|
||||
|
||||
if (layersurface->layerSurface->current.keyboard_interactive &&
|
||||
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) // don't focus if constrained
|
||||
if (layersurface->realPosition.goal() != layersurface->geometry.pos()) {
|
||||
if (layersurface->realPosition.isBeingAnimated())
|
||||
layersurface->realPosition = layersurface->geometry.pos();
|
||||
else
|
||||
layersurface->realPosition.setValueAndWarp(layersurface->geometry.pos());
|
||||
}
|
||||
if (layersurface->realSize.goal() != layersurface->geometry.size()) {
|
||||
if (layersurface->realSize.isBeingAnimated())
|
||||
layersurface->realSize = layersurface->geometry.size();
|
||||
else
|
||||
layersurface->realSize.setValueAndWarp(layersurface->geometry.size());
|
||||
}
|
||||
|
||||
if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained()) // don't focus if constrained
|
||||
&& !layersurface->keyboardExclusive && layersurface->mapped) {
|
||||
g_pCompositor->focusSurface(layersurface->layerSurface->surface);
|
||||
|
||||
@@ -336,7 +348,8 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||
g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
|
||||
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y);
|
||||
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y);
|
||||
} else if (!layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) &&
|
||||
g_pInputManager->m_bEmptyFocusCursorSet = false;
|
||||
} else if (!layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained()) &&
|
||||
layersurface->keyboardExclusive) {
|
||||
g_pInputManager->refocus();
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "../helpers/WLClasses.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
#include "../managers/CursorManager.hpp"
|
||||
|
||||
// ------------------------------ //
|
||||
// __ __ _____ _____ _____ //
|
||||
@@ -63,15 +64,26 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
|
||||
}
|
||||
|
||||
ATOM.second = reply->atom;
|
||||
|
||||
free(reply);
|
||||
}
|
||||
|
||||
wlr_xwayland_set_seat(g_pXWaylandManager->m_sWLRXWayland, g_pCompositor->m_sSeat.seat);
|
||||
|
||||
const auto XCURSOR = wlr_xcursor_manager_get_xcursor(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", 1);
|
||||
if (XCURSOR) {
|
||||
wlr_xwayland_set_cursor(g_pXWaylandManager->m_sWLRXWayland, XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, XCURSOR->images[0]->width,
|
||||
XCURSOR->images[0]->height, XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y);
|
||||
}
|
||||
g_pCursorManager->setXWaylandCursor(g_pXWaylandManager->m_sWLRXWayland);
|
||||
|
||||
const auto ROOT = xcb_setup_roots_iterator(xcb_get_setup(XCBCONNECTION)).data->root;
|
||||
auto cookie = xcb_get_property(XCBCONNECTION, 0, ROOT, HYPRATOMS["_NET_SUPPORTING_WM_CHECK"], XCB_ATOM_ANY, 0, 2048);
|
||||
auto reply = xcb_get_property_reply(XCBCONNECTION, cookie, nullptr);
|
||||
|
||||
const auto XWMWINDOW = *(xcb_window_t*)xcb_get_property_value(reply);
|
||||
const char* name = "Hyprland";
|
||||
|
||||
xcb_change_property(wlr_xwayland_get_xwm_connection(g_pXWaylandManager->m_sWLRXWayland), XCB_PROP_MODE_REPLACE, XWMWINDOW, HYPRATOMS["_NET_WM_NAME"], HYPRATOMS["UTF8_STRING"],
|
||||
8, // format
|
||||
strlen(name), name);
|
||||
|
||||
free(reply);
|
||||
|
||||
xcb_disconnect(XCBCONNECTION);
|
||||
#endif
|
||||
@@ -128,6 +140,8 @@ void Events::listener_destroyDrag(void* owner, void* data) {
|
||||
g_pInputManager->m_sDrag.drag = nullptr;
|
||||
g_pInputManager->m_sDrag.dragIcon = nullptr;
|
||||
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
|
||||
|
||||
g_pCompositor->focusWindow(g_pCompositor->m_pLastWindow, g_pCompositor->m_pLastWindow ? g_pXWaylandManager->getWindowSurface(g_pCompositor->m_pLastWindow) : nullptr);
|
||||
}
|
||||
|
||||
void Events::listener_mapDragIcon(void* owner, void* data) {
|
||||
@@ -167,6 +181,7 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||
g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true);
|
||||
}
|
||||
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
@@ -176,10 +191,16 @@ void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "PowerMgr set mode!");
|
||||
|
||||
const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(EVENT->output);
|
||||
|
||||
wlr_output_enable(EVENT->output, EVENT->mode == 1);
|
||||
if (!PMONITOR) {
|
||||
Debug::log(ERR, "Invalid powerMgrSetMode output");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wlr_output_commit(EVENT->output))
|
||||
wlr_output_state_set_enabled(PMONITOR->state.wlr(), EVENT->mode == 1);
|
||||
|
||||
if (!PMONITOR->state.commit())
|
||||
Debug::log(ERR, "Couldn't set power mode");
|
||||
}
|
||||
|
||||
@@ -225,16 +246,7 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
|
||||
}
|
||||
|
||||
void Events::listener_newTearingHint(wl_listener* listener, void* data) {
|
||||
const auto TCTL = (wlr_tearing_control_v1*)data;
|
||||
|
||||
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface);
|
||||
|
||||
if (!PWINDOW) {
|
||||
Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)data);
|
||||
Debug::log(LOG, "New tearing hint at {:x}", (uintptr_t)data);
|
||||
|
||||
const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
|
||||
NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
|
||||
@@ -242,7 +254,7 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
|
||||
NEWCTRL->hyprListener_destroy.initCallback(
|
||||
&NEWCTRL->pWlrHint->events.destroy,
|
||||
[&](void* owner, void* data) {
|
||||
Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
|
||||
Debug::log(LOG, "Destroyed {:x} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
|
||||
|
||||
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
|
||||
},
|
||||
@@ -256,10 +268,27 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
|
||||
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
|
||||
|
||||
if (PWINDOW) {
|
||||
PWINDOW->m_bTearingHint = TEARINGHINT->pWlrHint->hint;
|
||||
PWINDOW->m_bTearingHint = (bool)TEARINGHINT->pWlrHint->current;
|
||||
|
||||
Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->hint);
|
||||
Debug::log(LOG, "Hint {:x} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->current);
|
||||
}
|
||||
},
|
||||
NEWCTRL, "TearingController");
|
||||
}
|
||||
|
||||
void Events::listener_newShortcutInhibitor(wl_listener* listener, void* data) {
|
||||
const auto INHIBITOR = (wlr_keyboard_shortcuts_inhibitor_v1*)data;
|
||||
|
||||
const auto PINH = &g_pKeybindManager->m_lShortcutInhibitors.emplace_back();
|
||||
PINH->hyprListener_destroy.initCallback(
|
||||
&INHIBITOR->events.destroy,
|
||||
[](void* owner, void* data) {
|
||||
const auto OWNER = (SShortcutInhibitor*)owner;
|
||||
g_pKeybindManager->m_lShortcutInhibitors.remove(*OWNER);
|
||||
},
|
||||
PINH, "ShortcutInhibitor");
|
||||
|
||||
PINH->pWlrInhibitor = INHIBITOR;
|
||||
|
||||
Debug::log(LOG, "New shortcut inhibitor for surface {:x}", (uintptr_t)INHIBITOR->surface);
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "../render/Renderer.hpp"
|
||||
#include "Events.hpp"
|
||||
#include "../debug/HyprCtl.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
// --------------------------------------------------------- //
|
||||
// __ __ ____ _ _ _____ _______ ____ _____ _____ //
|
||||
@@ -109,7 +110,7 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iMonitorID == PNEWMONITOR->ID) {
|
||||
w->m_iLastSurfaceMonitorID = -1;
|
||||
w->updateSurfaceOutputs();
|
||||
w->updateSurfaceScaleTransformDetails();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,8 +148,8 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
PMONITOR->tearingState.frameScheduledWhileBusy = false;
|
||||
}
|
||||
|
||||
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
|
||||
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
|
||||
static auto PENABLERAT = CConfigValue<Hyprlang::INT>("misc:render_ahead_of_time");
|
||||
static auto PRATSAFE = CConfigValue<Hyprlang::INT>("misc:render_ahead_safezone");
|
||||
|
||||
PMONITOR->lastPresentationTimer.reset();
|
||||
|
||||
@@ -212,7 +213,17 @@ void Events::listener_monitorStateRequest(void* owner, void* data) {
|
||||
const auto PMONITOR = (CMonitor*)owner;
|
||||
const auto E = (wlr_output_event_request_state*)data;
|
||||
|
||||
wlr_output_commit_state(PMONITOR->output, E->state);
|
||||
if (!PMONITOR->createdByUser)
|
||||
return;
|
||||
|
||||
const auto SIZE = E->state->mode ? Vector2D{E->state->mode->width, E->state->mode->height} : Vector2D{E->state->custom_mode.width, E->state->custom_mode.height};
|
||||
|
||||
PMONITOR->forceSize = SIZE;
|
||||
|
||||
SMonitorRule rule = PMONITOR->activeMonitorRule;
|
||||
rule.resolution = SIZE;
|
||||
|
||||
g_pHyprRenderer->applyMonitorRule(PMONITOR, &rule);
|
||||
}
|
||||
|
||||
void Events::listener_monitorDamage(void* owner, void* data) {
|
||||
|
@@ -1,264 +0,0 @@
|
||||
#include "Events.hpp"
|
||||
|
||||
#include "../Compositor.hpp"
|
||||
#include "../helpers/WLClasses.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
|
||||
// --------------------------------------------- //
|
||||
// _____ ____ _____ _ _ _____ _____ //
|
||||
// | __ \ / __ \| __ \| | | | __ \ / ____| //
|
||||
// | |__) | | | | |__) | | | | |__) | (___ //
|
||||
// | ___/| | | | ___/| | | | ___/ \___ \ //
|
||||
// | | | |__| | | | |__| | | ____) | //
|
||||
// |_| \____/|_| \____/|_| |_____/ //
|
||||
// //
|
||||
// --------------------------------------------- //
|
||||
|
||||
void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
|
||||
SXDGPopup* const PPOPUP = (SXDGPopup*)pPopup;
|
||||
|
||||
auto curPopup = PPOPUP;
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
while (true) {
|
||||
px += curPopup->popup->current.geometry.x;
|
||||
py += curPopup->popup->current.geometry.y;
|
||||
|
||||
if (curPopup == PPOPUP && PPOPUP->parentWindow) {
|
||||
px -= curPopup->popup->base->current.geometry.x;
|
||||
py -= curPopup->popup->base->current.geometry.y;
|
||||
}
|
||||
|
||||
if (curPopup->popup && !curPopup->parentPopup && !curPopup->parentWindow) {
|
||||
const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->popup->base->surface->input_region);
|
||||
px -= EXTENTSSURFACE->x1;
|
||||
py -= EXTENTSSURFACE->y1;
|
||||
}
|
||||
|
||||
if (curPopup->parentPopup) {
|
||||
curPopup = curPopup->parentPopup;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
px += PPOPUP->lx;
|
||||
py += PPOPUP->ly;
|
||||
|
||||
*x += px;
|
||||
*y += py;
|
||||
}
|
||||
|
||||
void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
|
||||
pHyprPopup->popup = popup;
|
||||
|
||||
pHyprPopup->hyprListener_destroyPopupXDG.initCallback(&popup->base->events.destroy, &Events::listener_destroyPopupXDG, pHyprPopup, "HyprPopup");
|
||||
pHyprPopup->hyprListener_mapPopupXDG.initCallback(&popup->base->surface->events.map, &Events::listener_mapPopupXDG, pHyprPopup, "HyprPopup");
|
||||
pHyprPopup->hyprListener_unmapPopupXDG.initCallback(&popup->base->surface->events.unmap, &Events::listener_unmapPopupXDG, pHyprPopup, "HyprPopup");
|
||||
pHyprPopup->hyprListener_newPopupFromPopupXDG.initCallback(&popup->base->events.new_popup, &Events::listener_newPopupFromPopupXDG, pHyprPopup, "HyprPopup");
|
||||
pHyprPopup->hyprListener_commitPopupXDG.initCallback(&popup->base->surface->events.commit, &Events::listener_commitPopupXDG, pHyprPopup, "HyprPopup");
|
||||
pHyprPopup->hyprListener_repositionPopupXDG.initCallback(&popup->events.reposition, &Events::listener_repositionPopupXDG, pHyprPopup, "HyprPopup");
|
||||
|
||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
|
||||
CBox box = {PMONITOR->vecPosition.x - pHyprPopup->lx, PMONITOR->vecPosition.y - pHyprPopup->ly, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||
|
||||
wlr_xdg_popup_unconstrain_from_box(popup, box.pWlr());
|
||||
|
||||
pHyprPopup->monitor = PMONITOR;
|
||||
|
||||
Debug::log(LOG, "Popup: Unconstrained from lx ly: {:j5}, pHyprPopup lx ly: {:.5f} {:.5f}", PMONITOR->vecPosition, (float)pHyprPopup->lx, (float)pHyprPopup->ly);
|
||||
}
|
||||
|
||||
void Events::listener_newPopup(void* owner, void* data) {
|
||||
SLayerSurface* layersurface = (SLayerSurface*)owner;
|
||||
|
||||
ASSERT(layersurface);
|
||||
|
||||
Debug::log(LOG, "New layer popup created from surface {:x}", (uintptr_t)layersurface);
|
||||
|
||||
const auto WLRPOPUP = (wlr_xdg_popup*)data;
|
||||
|
||||
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
||||
|
||||
PNEWPOPUP->popup = WLRPOPUP;
|
||||
PNEWPOPUP->lx = layersurface->position.x;
|
||||
PNEWPOPUP->ly = layersurface->position.y;
|
||||
PNEWPOPUP->monitor = PMONITOR;
|
||||
PNEWPOPUP->parentLS = layersurface;
|
||||
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
||||
}
|
||||
|
||||
void Events::listener_newPopupXDG(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
ASSERT(PWINDOW);
|
||||
|
||||
if (!PWINDOW->m_bIsMapped)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "New layer popup created from XDG window {}", PWINDOW);
|
||||
|
||||
const auto WLRPOPUP = (wlr_xdg_popup*)data;
|
||||
|
||||
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
|
||||
PNEWPOPUP->popup = WLRPOPUP;
|
||||
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x;
|
||||
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y;
|
||||
PNEWPOPUP->parentWindow = PWINDOW;
|
||||
PNEWPOPUP->monitor = PMONITOR;
|
||||
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
||||
}
|
||||
|
||||
void Events::listener_newPopupFromPopupXDG(void* owner, void* data) {
|
||||
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||
|
||||
ASSERT(PPOPUP);
|
||||
|
||||
if (PPOPUP->parentWindow)
|
||||
Debug::log(LOG, "New popup created from XDG Window popup {:x} -> {}", (uintptr_t)PPOPUP, PPOPUP->parentWindow);
|
||||
else
|
||||
Debug::log(LOG, "New popup created from Non-Window popup {:x}", (uintptr_t)PPOPUP);
|
||||
|
||||
const auto WLRPOPUP = (wlr_xdg_popup*)data;
|
||||
|
||||
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
|
||||
|
||||
PNEWPOPUP->popup = WLRPOPUP;
|
||||
PNEWPOPUP->parentPopup = PPOPUP;
|
||||
PNEWPOPUP->lx = PPOPUP->lx;
|
||||
PNEWPOPUP->ly = PPOPUP->ly;
|
||||
PNEWPOPUP->parentWindow = PPOPUP->parentWindow;
|
||||
PNEWPOPUP->monitor = PPOPUP->monitor;
|
||||
|
||||
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
||||
}
|
||||
|
||||
void Events::listener_mapPopupXDG(void* owner, void* data) {
|
||||
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||
|
||||
ASSERT(PPOPUP);
|
||||
|
||||
Debug::log(LOG, "New XDG Popup mapped at {} {}", (int)PPOPUP->lx, (int)PPOPUP->ly);
|
||||
|
||||
if (PPOPUP->parentWindow)
|
||||
PPOPUP->parentWindow->m_lPopupSurfaces.emplace_back(PPOPUP->popup->base->surface);
|
||||
else if (PPOPUP->parentLS)
|
||||
PPOPUP->parentLS->popupSurfaces.emplace_back(PPOPUP->popup->base->surface);
|
||||
|
||||
PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow);
|
||||
|
||||
int lx = 0, ly = 0;
|
||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||
|
||||
CBox extents;
|
||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||
extents.applyFromWlr();
|
||||
|
||||
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
||||
|
||||
if (PPOPUP->monitor) {
|
||||
g_pCompositor->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->transform);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree);
|
||||
}
|
||||
|
||||
void Events::listener_repositionPopupXDG(void* owner, void* data) {
|
||||
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||
|
||||
Debug::log(LOG, "XDG Popup {:x} asks for a reposition", (uintptr_t)PPOPUP);
|
||||
|
||||
int lx = 0, ly = 0;
|
||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||
|
||||
CBox extents;
|
||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||
extents.applyFromWlr();
|
||||
|
||||
PPOPUP->lastPos = {lx - extents.x, ly - extents.y};
|
||||
PPOPUP->repositionRequested = true;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
|
||||
CBox box = {PMONITOR->vecPosition.x - lx + PPOPUP->popup->current.geometry.x, PMONITOR->vecPosition.y - ly + PPOPUP->popup->current.geometry.y, PMONITOR->vecSize.x,
|
||||
PMONITOR->vecSize.y};
|
||||
wlr_xdg_popup_unconstrain_from_box(PPOPUP->popup, box.pWlr());
|
||||
}
|
||||
|
||||
void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
||||
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||
Debug::log(LOG, "XDG Popup unmapped");
|
||||
|
||||
ASSERT(PPOPUP);
|
||||
|
||||
if (PPOPUP->popup->base->surface == g_pCompositor->m_pLastFocus)
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
|
||||
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
||||
|
||||
int lx = 0, ly = 0;
|
||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||
|
||||
CBox extents;
|
||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||
extents.applyFromWlr();
|
||||
|
||||
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
||||
|
||||
if (PPOPUP->parentWindow)
|
||||
std::erase(PPOPUP->parentWindow->m_lPopupSurfaces, PPOPUP->popup->base->surface);
|
||||
else if (PPOPUP->parentLS)
|
||||
std::erase(PPOPUP->parentLS->popupSurfaces, PPOPUP->popup->base->surface);
|
||||
|
||||
PPOPUP->pSurfaceTree = nullptr;
|
||||
|
||||
g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface
|
||||
}
|
||||
|
||||
void Events::listener_commitPopupXDG(void* owner, void* data) {
|
||||
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||
|
||||
if (g_pCompositor->windowValidMapped(PPOPUP->parentWindow)) {
|
||||
PPOPUP->lx = PPOPUP->parentWindow->m_vRealPosition.vec().x;
|
||||
PPOPUP->ly = PPOPUP->parentWindow->m_vRealPosition.vec().y;
|
||||
}
|
||||
|
||||
int lx = 0, ly = 0;
|
||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||
|
||||
CBox extents;
|
||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||
extents.applyFromWlr();
|
||||
|
||||
if (PPOPUP->repositionRequested)
|
||||
g_pHyprRenderer->damageBox(PPOPUP->lastPos.x, PPOPUP->lastPos.y, extents.width + 2, extents.height + 2);
|
||||
|
||||
PPOPUP->repositionRequested = false;
|
||||
|
||||
g_pHyprRenderer->damageSurface(PPOPUP->popup->base->surface, lx, ly);
|
||||
}
|
||||
|
||||
void Events::listener_destroyPopupXDG(void* owner, void* data) {
|
||||
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||
|
||||
ASSERT(PPOPUP);
|
||||
|
||||
Debug::log(LOG, "Destroyed popup XDG {:x}", (uintptr_t)PPOPUP);
|
||||
|
||||
if (PPOPUP->pSurfaceTree) {
|
||||
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
||||
PPOPUP->pSurfaceTree = nullptr;
|
||||
}
|
||||
|
||||
std::erase_if(g_pCompositor->m_vXDGPopups, [&](std::unique_ptr<SXDGPopup>& el) { return el.get() == PPOPUP; });
|
||||
}
|
@@ -4,6 +4,7 @@
|
||||
#include "../helpers/WLClasses.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
// ------------------------------------------------------------ //
|
||||
// __ _______ _ _ _____ ______ _______ //
|
||||
@@ -17,8 +18,8 @@
|
||||
|
||||
void addViewCoords(void* pWindow, int* x, int* y) {
|
||||
const auto PWINDOW = (CWindow*)pWindow;
|
||||
*x += PWINDOW->m_vRealPosition.goalv().x;
|
||||
*y += PWINDOW->m_vRealPosition.goalv().y;
|
||||
*x += PWINDOW->m_vRealPosition.goal().x;
|
||||
*y += PWINDOW->m_vRealPosition.goal().y;
|
||||
|
||||
if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) {
|
||||
wlr_box geom;
|
||||
@@ -32,7 +33,7 @@ void addViewCoords(void* pWindow, int* x, int* y) {
|
||||
void setAnimToMove(void* data) {
|
||||
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
|
||||
|
||||
CAnimatedVariable* animvar = (CAnimatedVariable*)data;
|
||||
CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data;
|
||||
|
||||
animvar->setConfig(PANIMCFG);
|
||||
}
|
||||
@@ -40,17 +41,16 @@ void setAnimToMove(void* data) {
|
||||
void Events::listener_mapWindow(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
|
||||
static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
|
||||
static auto* const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
|
||||
static auto* const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
|
||||
static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
|
||||
static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex")->strValue;
|
||||
static auto* const PNEWTAKESOVERFS = &g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen")->intValue;
|
||||
static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity");
|
||||
static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity");
|
||||
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
|
||||
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
|
||||
static auto PSWALLOWREGEX = CConfigValue<std::string>("misc:swallow_regex");
|
||||
static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex");
|
||||
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen");
|
||||
|
||||
auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
const auto PWORKSPACE =
|
||||
PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
auto PWORKSPACE = PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
||||
PWINDOW->m_bIsMapped = true;
|
||||
@@ -101,7 +101,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
|
||||
// window rules
|
||||
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
|
||||
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW, false);
|
||||
std::string requestedWorkspace = "";
|
||||
bool workspaceSilent = false;
|
||||
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen ||
|
||||
@@ -173,13 +173,23 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
} else if (r.szRule.starts_with("pseudo")) {
|
||||
PWINDOW->m_bIsPseudotiled = true;
|
||||
} else if (r.szRule.starts_with("nofocus")) {
|
||||
PWINDOW->m_bNoFocus = true;
|
||||
PWINDOW->m_sAdditionalConfigData.noFocus = true;
|
||||
} else if (r.szRule.starts_with("noinitialfocus")) {
|
||||
PWINDOW->m_bNoInitialFocus = true;
|
||||
} else if (r.szRule.starts_with("nofullscreenrequest")) {
|
||||
PWINDOW->m_bNoFullscreenRequest = true;
|
||||
} else if (r.szRule.starts_with("nomaximizerequest")) {
|
||||
PWINDOW->m_bNoMaximizeRequest = true;
|
||||
} else if (r.szRule.starts_with("suppressevent")) {
|
||||
CVarList vars(r.szRule, 0, 's', true);
|
||||
for (size_t i = 1; i < vars.size(); ++i) {
|
||||
if (vars[i] == "fullscreen")
|
||||
PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN;
|
||||
else if (vars[i] == "maximize")
|
||||
PWINDOW->m_eSuppressedEvents |= SUPPRESS_MAXIMIZE;
|
||||
else if (vars[i] == "activate")
|
||||
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
|
||||
else if (vars[i] == "activatefocus")
|
||||
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
|
||||
else
|
||||
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
|
||||
}
|
||||
} else if (r.szRule == "fullscreen") {
|
||||
requestsFullscreen = true;
|
||||
overridingNoFullscreen = true;
|
||||
@@ -249,8 +259,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->applyDynamicRule(r);
|
||||
}
|
||||
|
||||
PWINDOW->updateSpecialRenderData();
|
||||
|
||||
// disallow tiled pinned
|
||||
if (PWINDOW->m_bPinned && !PWINDOW->m_bIsFloating)
|
||||
PWINDOW->m_bPinned = false;
|
||||
@@ -270,6 +278,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (!pWorkspace)
|
||||
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName);
|
||||
|
||||
PWORKSPACE = pWorkspace;
|
||||
|
||||
PWINDOW->m_iWorkspaceID = pWorkspace->m_iID;
|
||||
PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID;
|
||||
|
||||
@@ -279,7 +289,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (!workspaceSilent) {
|
||||
if (pWorkspace->m_bIsSpecialWorkspace)
|
||||
g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID)->setSpecialWorkspace(pWorkspace);
|
||||
else
|
||||
else if (PMONITOR->activeWorkspace != REQUESTEDWORKSPACEID)
|
||||
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
|
||||
|
||||
PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
@@ -288,6 +298,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
workspaceSilent = false;
|
||||
}
|
||||
|
||||
PWINDOW->updateSpecialRenderData();
|
||||
|
||||
if (PWINDOW->m_bIsFloating) {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
|
||||
PWINDOW->m_bCreatedOverFullscreen = true;
|
||||
@@ -312,38 +324,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
|
||||
|
||||
PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY);
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
|
||||
|
||||
PWINDOW->setHidden(false);
|
||||
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||
} else if (r.szRule.starts_with("minsize")) {
|
||||
try {
|
||||
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
||||
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
|
||||
|
||||
const auto SIZE =
|
||||
Vector2D(std::max((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::max((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goalv().y));
|
||||
|
||||
PWINDOW->m_vRealSize = SIZE;
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
PWINDOW->setHidden(false);
|
||||
} catch (...) { Debug::log(LOG, "Rule minsize failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||
} else if (r.szRule.starts_with("maxsize")) {
|
||||
try {
|
||||
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
||||
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
|
||||
|
||||
const auto SIZE =
|
||||
Vector2D(std::min((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::min((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goalv().y));
|
||||
|
||||
PWINDOW->m_vRealSize = SIZE;
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
PWINDOW->setHidden(false);
|
||||
} catch (...) { Debug::log(LOG, "Rule maxsize failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||
} else if (r.szRule.starts_with("move")) {
|
||||
try {
|
||||
auto value = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||
@@ -379,7 +363,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
|
||||
} else {
|
||||
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
|
||||
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().x);
|
||||
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,7 +382,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
|
||||
} else {
|
||||
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
|
||||
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().y);
|
||||
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,10 +390,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
int borderSize = PWINDOW->getRealBorderSize();
|
||||
|
||||
posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
|
||||
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goalv().x - borderSize));
|
||||
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize));
|
||||
|
||||
posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
|
||||
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goalv().y - borderSize));
|
||||
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize));
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
|
||||
@@ -424,26 +408,26 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (ARGS[1] == "1")
|
||||
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
|
||||
|
||||
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goalv() / 2.f + RESERVEDOFFSET;
|
||||
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
// set the pseudo size to the GOAL of our current size
|
||||
// because the windows are animated on RealSize
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv();
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal();
|
||||
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
} else {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
|
||||
|
||||
// Set the pseudo size here too so that it doesnt end up being 0x0
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10, 10);
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10);
|
||||
}
|
||||
|
||||
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow;
|
||||
|
||||
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) {
|
||||
PWINDOW->m_bNoFocus = false;
|
||||
PWINDOW->m_sAdditionalConfigData.noFocus = false;
|
||||
PWINDOW->m_bNoInitialFocus = false;
|
||||
PWINDOW->m_bX11ShouldntFocus = false;
|
||||
}
|
||||
@@ -464,9 +448,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
requestsFullscreen = true;
|
||||
}
|
||||
|
||||
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus &&
|
||||
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
|
||||
(!PFORCEFOCUS || PFORCEFOCUS == PWINDOW)) {
|
||||
if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus &&
|
||||
(PWINDOW->m_iX11Type != 2 ||
|
||||
(PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->window_type_len > 0 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) &&
|
||||
!workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) {
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH);
|
||||
@@ -475,11 +460,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(0);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree);
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW,
|
||||
"XDG Window Late");
|
||||
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW,
|
||||
@@ -504,8 +486,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
"XWayland Window Late");
|
||||
}
|
||||
|
||||
if ((requestsFullscreen && (!PWINDOW->m_bNoFullscreenRequest || overridingNoFullscreen)) || (requestsMaximize && (!PWINDOW->m_bNoMaximizeRequest || overridingNoMaximize)) ||
|
||||
requestsFakeFullscreen) {
|
||||
if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) ||
|
||||
(requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) {
|
||||
// fix fullscreen on requested (basically do a switcheroo)
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
@@ -527,8 +509,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
// recheck idle inhibitors
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
|
||||
PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(PWINDOW->m_pWLSurface.wlr(), addViewCoords, PWINDOW, PWINDOW);
|
||||
|
||||
PWINDOW->updateToplevel();
|
||||
|
||||
if (workspaceSilent) {
|
||||
@@ -540,7 +520,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
|
||||
// verify swallowing
|
||||
if (*PSWALLOW && *PSWALLOWREGEX != STRVAL_EMPTY) {
|
||||
if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) {
|
||||
// don't swallow ourselves
|
||||
std::regex rgx(*PSWALLOWREGEX);
|
||||
if (!std::regex_match(g_pXWaylandManager->getAppIDClass(PWINDOW), rgx)) {
|
||||
@@ -587,7 +567,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (finalFound) {
|
||||
bool valid = std::regex_match(g_pXWaylandManager->getAppIDClass(finalFound), rgx);
|
||||
|
||||
if (*PSWALLOWEXREGEX != STRVAL_EMPTY) {
|
||||
if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) {
|
||||
std::regex exc(*PSWALLOWEXREGEX);
|
||||
|
||||
valid = valid && !std::regex_match(g_pXWaylandManager->getTitle(finalFound), exc);
|
||||
@@ -611,7 +591,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
PWINDOW->m_bFirstMap = false;
|
||||
|
||||
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goalv(), PWINDOW->m_vRealSize.goalv());
|
||||
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goal(), PWINDOW->m_vRealSize.goal());
|
||||
|
||||
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, g_pXWaylandManager->getAppIDClass(PWINDOW), PWINDOW->m_szTitle)});
|
||||
@@ -639,12 +619,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
|
||||
|
||||
if (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained())
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
// fix some xwayland apps that don't behave nicely
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
if (PMONITOR && PWINDOW->m_iX11Type == 2)
|
||||
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
}
|
||||
|
||||
void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
@@ -660,8 +644,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
if (PMONITOR) {
|
||||
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
|
||||
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
|
||||
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition;
|
||||
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value();
|
||||
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
|
||||
}
|
||||
|
||||
@@ -673,7 +657,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
Debug::log(LOG, "Unregistered late callbacks XDG");
|
||||
PWINDOW->hyprListener_setTitleWindow.removeCallback();
|
||||
PWINDOW->hyprListener_newPopupXDG.removeCallback();
|
||||
PWINDOW->hyprListener_requestMaximize.removeCallback();
|
||||
PWINDOW->hyprListener_requestMinimize.removeCallback();
|
||||
PWINDOW->hyprListener_requestMove.removeCallback();
|
||||
@@ -733,6 +716,9 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
|
||||
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
|
||||
|
||||
if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->m_iWorkspaceID) == 0)
|
||||
g_pInputManager->refocus();
|
||||
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
// CWindow::onUnmap will remove this window's active status, but we can't really do it above.
|
||||
@@ -745,11 +731,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window {}", PWINDOW);
|
||||
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
|
||||
|
||||
PWINDOW->m_pSurfaceTree = nullptr;
|
||||
|
||||
PWINDOW->m_bFadingOut = true;
|
||||
|
||||
g_pCompositor->addToFadingOutSafe(PWINDOW);
|
||||
@@ -757,7 +738,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
|
||||
|
||||
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.vec() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
|
||||
|
||||
// anims
|
||||
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true);
|
||||
@@ -793,6 +774,30 @@ void Events::listener_ackConfigure(void* owner, void* data) {
|
||||
void Events::listener_commitWindow(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
if (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->initial_commit) {
|
||||
Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow();
|
||||
|
||||
if (g_pXWaylandManager->shouldBeFloated(PWINDOW, true))
|
||||
predSize = {};
|
||||
|
||||
Vector2D maxSize = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->pending.max_width, PWINDOW->m_uSurface.xdg->toplevel->pending.max_height};
|
||||
|
||||
if ((maxSize.x > 0 && maxSize.x < predSize.x) || (maxSize.y > 0 && maxSize.y < predSize.y))
|
||||
predSize = {};
|
||||
|
||||
for (auto& r : g_pConfigManager->getMatchingRules(PWINDOW, true, true)) {
|
||||
if (r.szRule.starts_with("float")) {
|
||||
predSize = {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Layout predicts size {} for {}", predSize, PWINDOW);
|
||||
|
||||
wlr_xdg_toplevel_set_size(PWINDOW->m_uSurface.xdg->toplevel, predSize.x, predSize.y);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
|
||||
return;
|
||||
|
||||
@@ -803,11 +808,30 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||
PWINDOW->m_pPendingSizeAck.reset();
|
||||
}
|
||||
|
||||
PWINDOW->updateSurfaceOutputs();
|
||||
|
||||
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
|
||||
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
|
||||
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
|
||||
PWINDOW->m_pPopupHead->recheckTree();
|
||||
}
|
||||
|
||||
// tearing: if solitary, redraw it. This still might be a single surface window
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
if (PMONITOR && PMONITOR->solitaryClient == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear &&
|
||||
PWINDOW->m_pWLSurface.wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
|
||||
CRegion damageBox{&PWINDOW->m_pWLSurface.wlr()->buffer_damage};
|
||||
|
||||
if (!damageBox.empty()) {
|
||||
if (PMONITOR->tearingState.busy) {
|
||||
PMONITOR->tearingState.frameScheduledWhileBusy = true;
|
||||
} else {
|
||||
PMONITOR->tearingState.nextRenderTorn = true;
|
||||
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
|
||||
return;
|
||||
|
||||
@@ -817,7 +841,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||
if (MAXSIZE < Vector2D{1, 1})
|
||||
return;
|
||||
|
||||
const auto REALSIZE = PWINDOW->m_vRealSize.goalv();
|
||||
const auto REALSIZE = PWINDOW->m_vRealSize.goal();
|
||||
Vector2D newSize = REALSIZE;
|
||||
|
||||
if (MAXSIZE.x < newSize.x)
|
||||
@@ -831,7 +855,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||
|
||||
const Vector2D DELTA = REALSIZE - newSize;
|
||||
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0;
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0;
|
||||
PWINDOW->m_vRealSize = newSize;
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true);
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
@@ -861,14 +885,10 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
|
||||
|
||||
if (PWINDOW->m_pSurfaceTree) {
|
||||
Debug::log(LOG, "Destroying Subsurface tree of {} in destroyWindow", PWINDOW);
|
||||
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
|
||||
PWINDOW->m_pSurfaceTree = nullptr;
|
||||
}
|
||||
|
||||
PWINDOW->m_bReadyToDelete = true;
|
||||
|
||||
PWINDOW->m_uSurface.xdg = nullptr;
|
||||
|
||||
if (!PWINDOW->m_bFadingOut) {
|
||||
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
|
||||
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
|
||||
@@ -881,7 +901,12 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
|
||||
if (!g_pCompositor->windowValidMapped(PWINDOW))
|
||||
return;
|
||||
|
||||
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
|
||||
const auto NEWTITLE = g_pXWaylandManager->getTitle(PWINDOW);
|
||||
|
||||
if (NEWTITLE == PWINDOW->m_szTitle)
|
||||
return;
|
||||
|
||||
PWINDOW->m_szTitle = NEWTITLE;
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)PWINDOW)});
|
||||
EMIT_HOOK_EVENT("windowTitle", PWINDOW);
|
||||
|
||||
@@ -906,7 +931,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PWINDOW->isHidden() || PWINDOW->m_bNoFullscreenRequest)
|
||||
if (PWINDOW->isHidden() || (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
|
||||
return;
|
||||
|
||||
bool requestedFullState = false;
|
||||
@@ -960,7 +985,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
|
||||
void Events::listener_activateXDG(wl_listener* listener, void* data) {
|
||||
const auto E = (wlr_xdg_activation_v1_request_activate_event*)data;
|
||||
|
||||
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
|
||||
static auto PFOCUSONACTIVATE = CConfigValue<Hyprlang::INT>("misc:focus_on_activate");
|
||||
|
||||
Debug::log(LOG, "Activate request for surface at {:x}", (uintptr_t)E->surface);
|
||||
|
||||
@@ -969,7 +994,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
|
||||
|
||||
const auto PWINDOW = g_pCompositor->getWindowFromSurface(E->surface);
|
||||
|
||||
if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow)
|
||||
if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE))
|
||||
return;
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
|
||||
@@ -977,7 +1002,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
|
||||
|
||||
PWINDOW->m_bIsUrgent = true;
|
||||
|
||||
if (!*PFOCUSONACTIVATE)
|
||||
if (!*PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY))
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_bIsFloating)
|
||||
@@ -990,7 +1015,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
|
||||
void Events::listener_activateX11(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
|
||||
static auto PFOCUSONACTIVATE = CConfigValue<Hyprlang::INT>("misc:focus_on_activate");
|
||||
|
||||
Debug::log(LOG, "X11 Activate request for window {}", PWINDOW);
|
||||
|
||||
@@ -1001,17 +1026,20 @@ void Events::listener_activateX11(void* owner, void* data) {
|
||||
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID())
|
||||
return;
|
||||
|
||||
if (!wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))
|
||||
return;
|
||||
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow)
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE))
|
||||
return;
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
|
||||
EMIT_HOOK_EVENT("urgent", PWINDOW);
|
||||
|
||||
if (!*PFOCUSONACTIVATE)
|
||||
if (!*PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY))
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_bIsFloating)
|
||||
@@ -1030,13 +1058,15 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
|
||||
PWINDOW->m_vPendingReportedSize = {E->width, E->height};
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
|
||||
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
return;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == PWINDOW) {
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
|
||||
g_pInputManager->refocus();
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
return;
|
||||
@@ -1052,17 +1082,16 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(LOGICALPOS);
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height));
|
||||
|
||||
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
|
||||
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
|
||||
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
|
||||
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
}
|
||||
}
|
||||
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
|
||||
PWINDOW->m_vSize = PWINDOW->m_vRealSize.vec();
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.value();
|
||||
PWINDOW->m_vSize = PWINDOW->m_vRealSize.value();
|
||||
|
||||
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
|
||||
|
||||
@@ -1074,7 +1103,7 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_iWorkspaceID))
|
||||
return; // further things are only for visible windows
|
||||
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
|
||||
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
|
||||
@@ -1092,8 +1121,8 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
if (!PWINDOW->m_bIsMapped)
|
||||
return;
|
||||
|
||||
const auto POS = PWINDOW->m_vRealPosition.goalv();
|
||||
const auto SIZ = PWINDOW->m_vRealSize.goalv();
|
||||
const auto POS = PWINDOW->m_vRealPosition.goal();
|
||||
const auto SIZ = PWINDOW->m_vRealSize.goal();
|
||||
|
||||
if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1)
|
||||
PWINDOW->setHidden(false);
|
||||
@@ -1101,12 +1130,12 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
PWINDOW->setHidden(true);
|
||||
|
||||
if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) {
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
return;
|
||||
}
|
||||
|
||||
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
|
||||
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
|
||||
|
||||
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y});
|
||||
|
||||
@@ -1123,24 +1152,23 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
|
||||
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
|
||||
const Vector2D DELTA = PWINDOW->m_vRealSize.goal() - PWINDOW->m_vRealSize.goal() / PMONITOR->scale;
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goal() + DELTA / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
|
||||
PWINDOW->m_vSize = PWINDOW->m_vRealSize.goalv();
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal();
|
||||
PWINDOW->m_vSize = PWINDOW->m_vRealSize.goal();
|
||||
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
|
||||
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
PWINDOW->updateWindowDecos();
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goalv();
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vRealSize.goalv();
|
||||
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vReportedSize;
|
||||
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goal();
|
||||
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1211,7 +1239,7 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
|
||||
void Events::listener_requestMaximize(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
if (PWINDOW->m_bNoMaximizeRequest)
|
||||
if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Maximize request for {}", PWINDOW);
|
||||
|
@@ -2,12 +2,11 @@
|
||||
#include "../managers/AnimationManager.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
|
||||
CAnimatedVariable::CAnimatedVariable() {
|
||||
CBaseAnimatedVariable::CBaseAnimatedVariable(ANIMATEDVARTYPE type) : m_Type(type) {
|
||||
; // dummy var
|
||||
}
|
||||
|
||||
void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
|
||||
m_eVarType = type;
|
||||
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
|
||||
m_eDamagePolicy = policy;
|
||||
m_pConfig = pAnimConfig;
|
||||
m_pWindow = pWindow;
|
||||
@@ -15,42 +14,11 @@ void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* p
|
||||
m_bDummy = false;
|
||||
}
|
||||
|
||||
void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
|
||||
create(type, pAnimConfig, pWindow, policy);
|
||||
|
||||
try {
|
||||
switch (type) {
|
||||
case AVARTYPE_FLOAT: {
|
||||
const auto V = std::any_cast<float>(val);
|
||||
m_fValue = V;
|
||||
m_fGoal = V;
|
||||
break;
|
||||
}
|
||||
case AVARTYPE_VECTOR: {
|
||||
const auto V = std::any_cast<Vector2D>(val);
|
||||
m_vValue = V;
|
||||
m_vGoal = V;
|
||||
break;
|
||||
}
|
||||
case AVARTYPE_COLOR: {
|
||||
const auto V = std::any_cast<CColor>(val);
|
||||
m_cValue = V;
|
||||
m_cGoal = V;
|
||||
break;
|
||||
}
|
||||
default: ASSERT(false); break;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "CAnimatedVariable create error: {}", e.what());
|
||||
RASSERT(false, "CAnimatedVariable create error: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
CAnimatedVariable::~CAnimatedVariable() {
|
||||
CBaseAnimatedVariable::~CBaseAnimatedVariable() {
|
||||
unregister();
|
||||
}
|
||||
|
||||
void CAnimatedVariable::unregister() {
|
||||
void CBaseAnimatedVariable::unregister() {
|
||||
if (!g_pAnimationManager)
|
||||
return;
|
||||
std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; });
|
||||
@@ -58,23 +26,26 @@ void CAnimatedVariable::unregister() {
|
||||
disconnectFromActive();
|
||||
}
|
||||
|
||||
void CAnimatedVariable::registerVar() {
|
||||
void CBaseAnimatedVariable::registerVar() {
|
||||
if (!m_bIsRegistered)
|
||||
g_pAnimationManager->m_vAnimatedVariables.push_back(this);
|
||||
m_bIsRegistered = true;
|
||||
}
|
||||
|
||||
int CAnimatedVariable::getDurationLeftMs() {
|
||||
int CBaseAnimatedVariable::getDurationLeftMs() {
|
||||
return std::max(
|
||||
(int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0);
|
||||
}
|
||||
|
||||
float CAnimatedVariable::getPercent() {
|
||||
float CBaseAnimatedVariable::getPercent() {
|
||||
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count();
|
||||
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
|
||||
}
|
||||
|
||||
float CAnimatedVariable::getCurveValue() {
|
||||
float CBaseAnimatedVariable::getCurveValue() {
|
||||
if (!m_bIsBeingAnimated)
|
||||
return 1.f;
|
||||
|
||||
const auto SPENT = getPercent();
|
||||
|
||||
if (SPENT >= 1.f)
|
||||
@@ -83,7 +54,7 @@ float CAnimatedVariable::getCurveValue() {
|
||||
return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT);
|
||||
}
|
||||
|
||||
void CAnimatedVariable::connectToActive() {
|
||||
void CBaseAnimatedVariable::connectToActive() {
|
||||
g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up
|
||||
|
||||
if (!m_bIsConnectedToActive)
|
||||
@@ -92,7 +63,7 @@ void CAnimatedVariable::connectToActive() {
|
||||
m_bIsConnectedToActive = true;
|
||||
}
|
||||
|
||||
void CAnimatedVariable::disconnectFromActive() {
|
||||
void CBaseAnimatedVariable::disconnectFromActive() {
|
||||
std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; });
|
||||
m_bIsConnectedToActive = false;
|
||||
}
|
@@ -3,6 +3,7 @@
|
||||
#include <functional>
|
||||
#include <any>
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
#include "Vector2D.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "../macros.hpp"
|
||||
@@ -15,6 +16,30 @@ enum ANIMATEDVARTYPE {
|
||||
AVARTYPE_COLOR
|
||||
};
|
||||
|
||||
// Utility to bind a type with its corresponding ANIMATEDVARTYPE
|
||||
template <class T>
|
||||
struct typeToANIMATEDVARTYPE_t {
|
||||
static constexpr ANIMATEDVARTYPE value = AVARTYPE_INVALID;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct typeToANIMATEDVARTYPE_t<float> {
|
||||
static constexpr ANIMATEDVARTYPE value = AVARTYPE_FLOAT;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct typeToANIMATEDVARTYPE_t<Vector2D> {
|
||||
static constexpr ANIMATEDVARTYPE value = AVARTYPE_VECTOR;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct typeToANIMATEDVARTYPE_t<CColor> {
|
||||
static constexpr ANIMATEDVARTYPE value = AVARTYPE_COLOR;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline constexpr ANIMATEDVARTYPE typeToANIMATEDVARTYPE = typeToANIMATEDVARTYPE_t<T>::value;
|
||||
|
||||
enum AVARDAMAGEPOLICY {
|
||||
AVARDAMAGE_NONE = -1,
|
||||
AVARDAMAGE_ENTIRE = 0,
|
||||
@@ -28,174 +53,34 @@ struct SLayerSurface;
|
||||
struct SAnimationPropertyConfig;
|
||||
class CHyprRenderer;
|
||||
|
||||
class CAnimatedVariable {
|
||||
// Utility to define a concept as a list of possible type
|
||||
template <class T, class... U>
|
||||
concept OneOf = (... or std::same_as<T, U>);
|
||||
|
||||
// Concept to describe which type can be placed into CAnimatedVariable
|
||||
// This is mainly to get better errors if we put a type that's not supported
|
||||
// Otherwise template errors are ugly
|
||||
template <class T>
|
||||
concept Animable = OneOf<T, Vector2D, float, CColor>;
|
||||
|
||||
class CBaseAnimatedVariable {
|
||||
public:
|
||||
CAnimatedVariable(); // dummy var
|
||||
CBaseAnimatedVariable(ANIMATEDVARTYPE type);
|
||||
void create(SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy);
|
||||
|
||||
void create(ANIMATEDVARTYPE, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
|
||||
void create(ANIMATEDVARTYPE, std::any val, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
|
||||
CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
|
||||
CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
|
||||
CBaseAnimatedVariable& operator=(const CBaseAnimatedVariable&) = delete;
|
||||
CBaseAnimatedVariable& operator=(CBaseAnimatedVariable&&) = delete;
|
||||
|
||||
CAnimatedVariable(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable(CAnimatedVariable&&) = delete;
|
||||
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
|
||||
|
||||
~CAnimatedVariable();
|
||||
virtual ~CBaseAnimatedVariable();
|
||||
|
||||
void unregister();
|
||||
void registerVar();
|
||||
|
||||
// gets the current vector value (real time)
|
||||
const Vector2D& vec() const {
|
||||
return m_vValue;
|
||||
}
|
||||
|
||||
// gets the current float value (real time)
|
||||
const float& fl() const {
|
||||
return m_fValue;
|
||||
}
|
||||
|
||||
// gets the current color value (real time)
|
||||
const CColor& col() const {
|
||||
return m_cValue;
|
||||
}
|
||||
|
||||
// gets the goal vector value
|
||||
const Vector2D& goalv() const {
|
||||
return m_vGoal;
|
||||
}
|
||||
|
||||
// gets the goal float value
|
||||
const float& goalf() const {
|
||||
return m_fGoal;
|
||||
}
|
||||
|
||||
// gets the goal color value
|
||||
const CColor& goalc() const {
|
||||
return m_cGoal;
|
||||
}
|
||||
|
||||
CAnimatedVariable& operator=(const Vector2D& v) {
|
||||
if (v == m_vGoal)
|
||||
return *this;
|
||||
|
||||
m_vGoal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
|
||||
onAnimationBegin();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAnimatedVariable& operator=(const float& v) {
|
||||
if (v == m_fGoal)
|
||||
return *this;
|
||||
|
||||
m_fGoal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_fBegun = m_fValue;
|
||||
|
||||
onAnimationBegin();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAnimatedVariable& operator=(const CColor& v) {
|
||||
if (v == m_cGoal)
|
||||
return *this;
|
||||
|
||||
m_cGoal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_cBegun = m_cValue;
|
||||
|
||||
onAnimationBegin();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
void setValue(const Vector2D& v) {
|
||||
if (v == m_vValue)
|
||||
return;
|
||||
|
||||
m_vValue = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
void setValue(const float& v) {
|
||||
if (v == m_fValue)
|
||||
return;
|
||||
|
||||
m_fValue = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
void setValue(const CColor& v) {
|
||||
if (v == m_cValue)
|
||||
return;
|
||||
|
||||
m_cValue = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
// Sets the actual value and goal
|
||||
void setValueAndWarp(const Vector2D& v) {
|
||||
m_vGoal = v;
|
||||
warp();
|
||||
}
|
||||
|
||||
// Sets the actual value and goal
|
||||
void setValueAndWarp(const float& v) {
|
||||
m_fGoal = v;
|
||||
warp();
|
||||
}
|
||||
|
||||
// Sets the actual value and goal
|
||||
void setValueAndWarp(const CColor& v) {
|
||||
m_cGoal = v;
|
||||
warp();
|
||||
}
|
||||
|
||||
// checks if an animation is in progress
|
||||
inline bool isBeingAnimated() {
|
||||
return m_bIsBeingAnimated;
|
||||
}
|
||||
|
||||
void warp(bool endCallback = true) {
|
||||
switch (m_eVarType) {
|
||||
case AVARTYPE_FLOAT: {
|
||||
m_fValue = m_fGoal;
|
||||
break;
|
||||
}
|
||||
case AVARTYPE_VECTOR: {
|
||||
m_vValue = m_vGoal;
|
||||
break;
|
||||
}
|
||||
case AVARTYPE_COLOR: {
|
||||
m_cValue = m_cGoal;
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
m_bIsBeingAnimated = false;
|
||||
|
||||
if (endCallback)
|
||||
onAnimationEnd();
|
||||
}
|
||||
virtual void warp(bool endCallback = true) = 0;
|
||||
|
||||
//
|
||||
void setConfig(SAnimationPropertyConfig* pConfig) {
|
||||
m_pConfig = pConfig;
|
||||
}
|
||||
@@ -212,6 +97,11 @@ class CAnimatedVariable {
|
||||
/* returns the current curve value */
|
||||
float getCurveValue();
|
||||
|
||||
// checks if an animation is in progress
|
||||
inline bool isBeingAnimated() {
|
||||
return m_bIsBeingAnimated;
|
||||
}
|
||||
|
||||
/* sets a function to be ran when the animation finishes.
|
||||
if an animation is not running, runs instantly.
|
||||
if "remove" is set to true, will remove the callback when ran. */
|
||||
@@ -245,20 +135,7 @@ class CAnimatedVariable {
|
||||
m_bRemoveEndAfterRan = false;
|
||||
}
|
||||
|
||||
private:
|
||||
Vector2D m_vValue = Vector2D(0, 0);
|
||||
float m_fValue = 0;
|
||||
CColor m_cValue;
|
||||
|
||||
Vector2D m_vGoal = Vector2D(0, 0);
|
||||
float m_fGoal = 0;
|
||||
CColor m_cGoal;
|
||||
|
||||
Vector2D m_vBegun = Vector2D(0, 0);
|
||||
float m_fBegun = 0;
|
||||
CColor m_cBegun;
|
||||
|
||||
// owners
|
||||
protected:
|
||||
void* m_pWindow = nullptr;
|
||||
void* m_pWorkspace = nullptr;
|
||||
void* m_pLayer = nullptr;
|
||||
@@ -271,8 +148,8 @@ class CAnimatedVariable {
|
||||
|
||||
std::chrono::system_clock::time_point animationBegin;
|
||||
|
||||
ANIMATEDVARTYPE m_eVarType = AVARTYPE_INVALID;
|
||||
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE;
|
||||
ANIMATEDVARTYPE m_Type;
|
||||
|
||||
bool m_bRemoveEndAfterRan = true;
|
||||
bool m_bRemoveBeginAfterRan = true;
|
||||
@@ -281,7 +158,9 @@ class CAnimatedVariable {
|
||||
std::function<void(void* thisptr)> m_fUpdateCallback;
|
||||
|
||||
bool m_bIsConnectedToActive = false;
|
||||
|
||||
void connectToActive();
|
||||
|
||||
void disconnectFromActive();
|
||||
|
||||
// methods
|
||||
@@ -314,3 +193,86 @@ class CAnimatedVariable {
|
||||
friend struct SLayerSurface;
|
||||
friend class CHyprRenderer;
|
||||
};
|
||||
|
||||
template <Animable VarType>
|
||||
class CAnimatedVariable : public CBaseAnimatedVariable {
|
||||
public:
|
||||
CAnimatedVariable() : CBaseAnimatedVariable(typeToANIMATEDVARTYPE<VarType>) {} // dummy var
|
||||
|
||||
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
|
||||
create(pAnimConfig, pWindow, policy);
|
||||
m_Value = value;
|
||||
m_Goal = value;
|
||||
}
|
||||
|
||||
using CBaseAnimatedVariable::create;
|
||||
|
||||
CAnimatedVariable(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable(CAnimatedVariable&&) = delete;
|
||||
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
|
||||
|
||||
~CAnimatedVariable() = default;
|
||||
|
||||
// gets the current vector value (real time)
|
||||
const VarType& value() const {
|
||||
return m_Value;
|
||||
}
|
||||
|
||||
// gets the goal vector value
|
||||
const VarType& goal() const {
|
||||
return m_Goal;
|
||||
}
|
||||
|
||||
CAnimatedVariable& operator=(const VarType& v) {
|
||||
if (v == m_Goal)
|
||||
return *this;
|
||||
|
||||
m_Goal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_Begun = m_Value;
|
||||
|
||||
onAnimationBegin();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
void setValue(const VarType& v) {
|
||||
if (v == m_Value)
|
||||
return;
|
||||
|
||||
m_Value = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_Begun = m_Value;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
// Sets the actual value and goal
|
||||
void setValueAndWarp(const VarType& v) {
|
||||
m_Goal = v;
|
||||
warp();
|
||||
}
|
||||
|
||||
void warp(bool endCallback = true) override {
|
||||
m_Value = m_Goal;
|
||||
|
||||
m_bIsBeingAnimated = false;
|
||||
|
||||
if (endCallback)
|
||||
onAnimationEnd();
|
||||
}
|
||||
|
||||
private:
|
||||
VarType m_Value{};
|
||||
VarType m_Goal{};
|
||||
VarType m_Begun{};
|
||||
|
||||
// owners
|
||||
|
||||
friend class CAnimationManager;
|
||||
friend class CWorkspace;
|
||||
friend struct SLayerSurface;
|
||||
friend class CHyprRenderer;
|
||||
};
|
||||
|
@@ -1,4 +1,8 @@
|
||||
#include "Box.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
wlr_box CBox::wlr() {
|
||||
CBox rounded = roundInternal();
|
||||
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
|
||||
@@ -105,6 +109,31 @@ CBox& CBox::expand(const double& value) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::noNegativeSize() {
|
||||
std::clamp(w, 0.0, std::numeric_limits<double>::infinity());
|
||||
std::clamp(h, 0.0, std::numeric_limits<double>::infinity());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::intersection(const CBox other) {
|
||||
const float newTop = std::max(y, other.y);
|
||||
const float newBottom = std::min(y + h, other.y + other.h);
|
||||
const float newLeft = std::max(x, other.x);
|
||||
const float newRight = std::min(x + w, other.x + other.w);
|
||||
y = newTop;
|
||||
x = newLeft;
|
||||
w = newRight - newLeft;
|
||||
h = newBottom - newTop;
|
||||
|
||||
if (w <= 0 || h <= 0) {
|
||||
w = 0;
|
||||
h = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox CBox::roundInternal() {
|
||||
float newW = x + w - std::floor(x);
|
||||
float newH = y + h - std::floor(y);
|
||||
|
@@ -51,6 +51,8 @@ class CBox {
|
||||
CBox& transform(const wl_output_transform t, double w, double h);
|
||||
CBox& addExtents(const SWindowDecorationExtents& e);
|
||||
CBox& expand(const double& value);
|
||||
CBox& noNegativeSize();
|
||||
CBox& intersection(const CBox other);
|
||||
|
||||
CBox copy() const;
|
||||
|
||||
@@ -73,6 +75,8 @@ class CBox {
|
||||
double height;
|
||||
};
|
||||
|
||||
double rot = 0; /* rad, ccw */
|
||||
|
||||
//
|
||||
bool operator==(const CBox& rhs) const {
|
||||
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
|
||||
|
@@ -159,6 +159,13 @@ void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, const
|
||||
Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString);
|
||||
}
|
||||
|
||||
void removeWLSignal(wl_listener* pListener) {
|
||||
wl_list_remove(&pListener->link);
|
||||
wl_list_init(&pListener->link);
|
||||
|
||||
Debug::log(LOG, "Removed listener {:x}", (uintptr_t)pListener);
|
||||
}
|
||||
|
||||
void handleNoop(struct wl_listener* listener, void* data) {
|
||||
// Do nothing
|
||||
}
|
||||
@@ -715,6 +722,32 @@ int64_t configStringToInt(const std::string& VALUE) {
|
||||
return std::stoll(VALUE);
|
||||
}
|
||||
|
||||
Vector2D configStringToVector2D(const std::string& VALUE) {
|
||||
std::istringstream iss(VALUE);
|
||||
std::string token;
|
||||
|
||||
if (!std::getline(iss, token, ' ') && !std::getline(iss, token, ','))
|
||||
throw std::invalid_argument("Invalid string format");
|
||||
|
||||
if (!isNumber(token))
|
||||
throw std::invalid_argument("Invalid x value");
|
||||
|
||||
long long x = std::stoll(token);
|
||||
|
||||
if (!std::getline(iss, token))
|
||||
throw std::invalid_argument("Invalid string format");
|
||||
|
||||
if (!isNumber(token))
|
||||
throw std::invalid_argument("Invalid y value");
|
||||
|
||||
long long y = std::stoll(token);
|
||||
|
||||
if (std::getline(iss, token))
|
||||
throw std::invalid_argument("Invalid string format");
|
||||
|
||||
return Vector2D(x, y);
|
||||
}
|
||||
|
||||
double normalizeAngleRad(double ang) {
|
||||
if (ang > M_PI * 2) {
|
||||
while (ang > M_PI * 2)
|
||||
|
@@ -15,6 +15,7 @@ struct SCallstackFrameInfo {
|
||||
|
||||
std::string absolutePath(const std::string&, const std::string&);
|
||||
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
|
||||
void removeWLSignal(wl_listener*);
|
||||
std::string escapeJSONStrings(const std::string& str);
|
||||
std::string removeBeginEndSpacesTabs(std::string);
|
||||
bool isNumber(const std::string&, bool allowfloat = false);
|
||||
@@ -27,6 +28,7 @@ void logSystemInfo();
|
||||
std::string execAndGet(const char*);
|
||||
int64_t getPPIDof(int64_t pid);
|
||||
int64_t configStringToInt(const std::string&);
|
||||
Vector2D configStringToVector2D(const std::string&);
|
||||
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
|
||||
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
|
||||
double normalizeAngleRad(double ang);
|
||||
|
@@ -1,14 +1,18 @@
|
||||
#include "Monitor.hpp"
|
||||
|
||||
#include "MiscFunctions.hpp"
|
||||
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
int ratHandler(void* data) {
|
||||
g_pHyprRenderer->renderMonitor((CMonitor*)data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
CMonitor::CMonitor() {
|
||||
CMonitor::CMonitor() : state(this) {
|
||||
wlr_damage_ring_init(&damage);
|
||||
}
|
||||
|
||||
@@ -43,8 +47,8 @@ void CMonitor::onConnect(bool noRule) {
|
||||
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
|
||||
|
||||
if (m_bEnabled) {
|
||||
wlr_output_enable(output, 1);
|
||||
wlr_output_commit(output);
|
||||
wlr_output_state_set_enabled(state.wlr(), true);
|
||||
state.commit();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,19 +56,24 @@ void CMonitor::onConnect(bool noRule) {
|
||||
|
||||
szDescription = output->description ? output->description : "";
|
||||
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
|
||||
szDescription.erase(std::remove(szDescription.begin(), szDescription.end(), ','), szDescription.end());
|
||||
std::erase(szDescription, ',');
|
||||
|
||||
// field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix
|
||||
szShortDescription =
|
||||
removeBeginEndSpacesTabs(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : ""));
|
||||
std::erase(szShortDescription, ',');
|
||||
|
||||
if (!wlr_backend_is_drm(output->backend))
|
||||
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
|
||||
|
||||
// get monitor rule that matches
|
||||
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");
|
||||
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
|
||||
|
||||
// if it's disabled, disable and ignore
|
||||
if (monitorRule.disabled) {
|
||||
|
||||
wlr_output_set_scale(output, 1);
|
||||
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
wlr_output_state_set_scale(state.wlr(), 1);
|
||||
wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
|
||||
auto PREFSTATE = wlr_output_preferred_mode(output);
|
||||
|
||||
@@ -72,9 +81,9 @@ void CMonitor::onConnect(bool noRule) {
|
||||
wlr_output_mode* mode;
|
||||
|
||||
wl_list_for_each(mode, &output->modes, link) {
|
||||
wlr_output_set_mode(output, PREFSTATE);
|
||||
wlr_output_state_set_mode(state.wlr(), mode);
|
||||
|
||||
if (!wlr_output_test(output))
|
||||
if (!wlr_output_test_state(output, state.wlr()))
|
||||
continue;
|
||||
|
||||
PREFSTATE = mode;
|
||||
@@ -83,13 +92,13 @@ void CMonitor::onConnect(bool noRule) {
|
||||
}
|
||||
|
||||
if (PREFSTATE)
|
||||
wlr_output_set_mode(output, PREFSTATE);
|
||||
wlr_output_state_set_mode(state.wlr(), PREFSTATE);
|
||||
else
|
||||
Debug::log(WARN, "No mode found for disabled output {}", output->name);
|
||||
|
||||
wlr_output_enable(output, 0);
|
||||
wlr_output_state_set_enabled(state.wlr(), 0);
|
||||
|
||||
if (!wlr_output_commit(output))
|
||||
if (!state.commit())
|
||||
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
|
||||
|
||||
m_bEnabled = false;
|
||||
@@ -130,18 +139,31 @@ void CMonitor::onConnect(bool noRule) {
|
||||
|
||||
m_bEnabled = true;
|
||||
|
||||
wlr_output_enable(output, 1);
|
||||
wlr_output_state_set_enabled(state.wlr(), 1);
|
||||
|
||||
// set mode, also applies
|
||||
if (!noRule)
|
||||
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
|
||||
|
||||
wlr_output_commit(output);
|
||||
for (const auto& PTOUCHDEV : g_pInputManager->m_lTouchDevices) {
|
||||
if (matchesStaticSelector(PTOUCHDEV.boundOutput)) {
|
||||
Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV.name, szName);
|
||||
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTOUCHDEV.pWlrDevice, output);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& PTABLET : g_pInputManager->m_lTablets) {
|
||||
if (matchesStaticSelector(PTABLET.boundOutput)) {
|
||||
Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName);
|
||||
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output);
|
||||
}
|
||||
}
|
||||
|
||||
if (!state.commit())
|
||||
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
|
||||
|
||||
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
|
||||
|
||||
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
|
||||
|
||||
Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output);
|
||||
|
||||
setupDefaultWS(monitorRule);
|
||||
@@ -162,13 +184,12 @@ void CMonitor::onConnect(bool noRule) {
|
||||
//
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)});
|
||||
EMIT_HOOK_EVENT("monitorAdded", this);
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
|
||||
g_pCompositor->setActiveMonitor(this);
|
||||
|
||||
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(ID);
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
|
||||
|
||||
@@ -283,9 +304,10 @@ void CMonitor::onDisconnect(bool destroy) {
|
||||
if (!destroy)
|
||||
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
|
||||
|
||||
wlr_output_enable(output, false);
|
||||
wlr_output_state_set_enabled(state.wlr(), false);
|
||||
|
||||
wlr_output_commit(output);
|
||||
if (!state.commit())
|
||||
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
|
||||
|
||||
if (g_pCompositor->m_pLastMonitor == this)
|
||||
g_pCompositor->setActiveMonitor(BACKUPMON);
|
||||
@@ -307,13 +329,11 @@ void CMonitor::onDisconnect(bool destroy) {
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(const pixman_region32_t* rg) {
|
||||
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
|
||||
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("misc:cursor_zoom_factor");
|
||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
|
||||
wlr_damage_ring_add_whole(&damage);
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
}
|
||||
|
||||
if (wlr_damage_ring_add(&damage, rg))
|
||||
} else if (wlr_damage_ring_add(&damage, rg))
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
}
|
||||
|
||||
@@ -322,7 +342,7 @@ void CMonitor::addDamage(const CRegion* rg) {
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(const CBox* box) {
|
||||
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
|
||||
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("misc:cursor_zoom_factor");
|
||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
|
||||
wlr_damage_ring_add_whole(&damage);
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
@@ -336,6 +356,18 @@ bool CMonitor::isMirror() {
|
||||
return pMirrorOf != nullptr;
|
||||
}
|
||||
|
||||
bool CMonitor::matchesStaticSelector(const std::string& selector) const {
|
||||
if (selector.starts_with("desc:")) {
|
||||
// match by description
|
||||
const auto DESCRIPTIONSELECTOR = selector.substr(5);
|
||||
|
||||
return DESCRIPTIONSELECTOR == szShortDescription || DESCRIPTIONSELECTOR == szDescription;
|
||||
} else {
|
||||
// match by selector
|
||||
return szName == selector;
|
||||
}
|
||||
}
|
||||
|
||||
int CMonitor::findAvailableDefaultWS() {
|
||||
for (size_t i = 1; i < INT32_MAX; ++i) {
|
||||
if (g_pCompositor->getWorkspaceByID(i))
|
||||
@@ -378,9 +410,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
|
||||
if (newDefaultWorkspaceName == "")
|
||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||
|
||||
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();
|
||||
|
||||
PNEWWORKSPACE->m_iID = WORKSPACEID;
|
||||
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(WORKSPACEID, ID, newDefaultWorkspaceName)).get();
|
||||
}
|
||||
|
||||
activeWorkspace = PNEWWORKSPACE->m_iID;
|
||||
@@ -415,7 +445,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||
pMirrorOf = nullptr;
|
||||
|
||||
// set rule
|
||||
const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName, this->output->description ? this->output->description : "");
|
||||
const auto RULE = g_pConfigManager->getMonitorRuleFor(*this);
|
||||
|
||||
vecPosition = RULE.offset;
|
||||
|
||||
@@ -502,7 +532,7 @@ float CMonitor::getDefaultScale() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove) {
|
||||
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove, bool noFocus) {
|
||||
if (!pWorkspace)
|
||||
return;
|
||||
|
||||
@@ -533,13 +563,13 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
if (!noFocus && !g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
|
||||
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
|
||||
CWindow* pWindow = pWorkspace->getLastFocusedWindow();
|
||||
|
||||
if (!pWindow) {
|
||||
if (*PFOLLOWMOUSE == 1)
|
||||
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
|
||||
pWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
if (!pWindow)
|
||||
pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
|
||||
@@ -557,6 +587,7 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", pWorkspace->m_szName});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"workspacev2", std::format("{},{}", pWorkspace->m_iID, pWorkspace->m_szName)});
|
||||
EMIT_HOOK_EVENT("workspace", pWorkspace);
|
||||
}
|
||||
|
||||
@@ -567,10 +598,16 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
||||
g_pConfigManager->ensureVRR(this);
|
||||
|
||||
g_pCompositor->updateSuspendedStates();
|
||||
|
||||
if (specialWorkspaceID) {
|
||||
const auto PSPECIALWS = g_pCompositor->getWorkspaceByID(specialWorkspaceID);
|
||||
if (PSPECIALWS->m_bHasFullscreenWindow)
|
||||
g_pCompositor->updateFullscreenFadeOnWorkspace(PSPECIALWS);
|
||||
}
|
||||
}
|
||||
|
||||
void CMonitor::changeWorkspace(const int& id, bool internal) {
|
||||
changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal);
|
||||
void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) {
|
||||
changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus);
|
||||
}
|
||||
|
||||
void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
@@ -592,6 +629,10 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
|
||||
g_pCompositor->updateFullscreenFadeOnWorkspace(PWORKSPACE);
|
||||
|
||||
g_pConfigManager->ensureVRR(this);
|
||||
|
||||
g_pCompositor->updateSuspendedStates();
|
||||
|
||||
return;
|
||||
@@ -609,6 +650,10 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
PMONITORWORKSPACEOWNER->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMONITORWORKSPACEOWNER->szName});
|
||||
|
||||
const auto PACTIVEWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITORWORKSPACEOWNER->activeWorkspace);
|
||||
g_pCompositor->updateFullscreenFadeOnWorkspace(PACTIVEWORKSPACE);
|
||||
|
||||
animate = false;
|
||||
}
|
||||
|
||||
@@ -621,17 +666,17 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
|
||||
w->m_iMonitorID = ID;
|
||||
w->updateSurfaceOutputs();
|
||||
w->updateSurfaceScaleTransformDetails();
|
||||
|
||||
const auto MIDDLE = w->middle();
|
||||
if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) {
|
||||
// if it's floating and the middle isnt on the current mon, move it to the center
|
||||
const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE);
|
||||
Vector2D pos = w->m_vRealPosition.goalv();
|
||||
Vector2D pos = w->m_vRealPosition.goal();
|
||||
if (!VECINRECT(MIDDLE, PMONFROMMIDDLE->vecPosition.x, PMONFROMMIDDLE->vecPosition.y, PMONFROMMIDDLE->vecPosition.x + PMONFROMMIDDLE->vecSize.x,
|
||||
PMONFROMMIDDLE->vecPosition.y + PMONFROMMIDDLE->vecSize.y)) {
|
||||
// not on any monitor, center
|
||||
pos = middle() / 2.f - w->m_vRealSize.goalv() / 2.f;
|
||||
pos = middle() / 2.f - w->m_vRealSize.goal() / 2.f;
|
||||
} else
|
||||
pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition;
|
||||
|
||||
@@ -652,6 +697,10 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
|
||||
g_pHyprRenderer->damageMonitor(this);
|
||||
|
||||
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
|
||||
|
||||
g_pConfigManager->ensureVRR(this);
|
||||
|
||||
g_pCompositor->updateSuspendedStates();
|
||||
}
|
||||
|
||||
@@ -678,3 +727,32 @@ void CMonitor::updateMatrix() {
|
||||
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
CMonitorState::CMonitorState(CMonitor* owner) {
|
||||
m_pOwner = owner;
|
||||
wlr_output_state_init(&m_state);
|
||||
}
|
||||
|
||||
CMonitorState::~CMonitorState() {
|
||||
wlr_output_state_finish(&m_state);
|
||||
}
|
||||
|
||||
wlr_output_state* CMonitorState::wlr() {
|
||||
return &m_state;
|
||||
}
|
||||
|
||||
void CMonitorState::clear() {
|
||||
wlr_output_state_finish(&m_state);
|
||||
m_state = {0};
|
||||
wlr_output_state_init(&m_state);
|
||||
}
|
||||
|
||||
bool CMonitorState::commit() {
|
||||
bool ret = wlr_output_commit_state(m_pOwner->output, &m_state);
|
||||
clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CMonitorState::test() {
|
||||
return wlr_output_test_state(m_pOwner->output, &m_state);
|
||||
}
|
||||
|
@@ -25,6 +25,25 @@ struct SMonitorRule {
|
||||
std::optional<int> vrr;
|
||||
};
|
||||
|
||||
class CMonitor;
|
||||
|
||||
// Class for wrapping the wlr state
|
||||
class CMonitorState {
|
||||
public:
|
||||
CMonitorState(CMonitor* owner);
|
||||
~CMonitorState();
|
||||
|
||||
wlr_output_state* wlr();
|
||||
void clear();
|
||||
// commit() will also clear()
|
||||
bool commit();
|
||||
bool test();
|
||||
|
||||
private:
|
||||
wlr_output_state m_state = {0};
|
||||
CMonitor* m_pOwner;
|
||||
};
|
||||
|
||||
class CMonitor {
|
||||
public:
|
||||
CMonitor();
|
||||
@@ -45,12 +64,15 @@ class CMonitor {
|
||||
|
||||
std::string szName = "";
|
||||
std::string szDescription = "";
|
||||
std::string szShortDescription = "";
|
||||
|
||||
Vector2D vecReservedTopLeft = Vector2D(0, 0);
|
||||
Vector2D vecReservedBottomRight = Vector2D(0, 0);
|
||||
|
||||
drmModeModeInfo customDrmMode = {};
|
||||
|
||||
CMonitorState state;
|
||||
|
||||
// WLR stuff
|
||||
wlr_damage_ring damage;
|
||||
wlr_output* output = nullptr;
|
||||
@@ -63,6 +85,7 @@ class CMonitor {
|
||||
bool gammaChanged = false;
|
||||
float xwaylandScale = 1.f;
|
||||
std::array<float, 9> projMatrix = {0};
|
||||
std::optional<Vector2D> forceSize;
|
||||
|
||||
bool dpmsStatus = true;
|
||||
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||
@@ -84,8 +107,6 @@ class CMonitor {
|
||||
CMonitor* pMirrorOf = nullptr;
|
||||
std::vector<CMonitor*> mirrors;
|
||||
|
||||
CRegion lastFrameDamage; // stores last frame damage
|
||||
|
||||
// for tearing
|
||||
CWindow* solitaryClient = nullptr;
|
||||
|
||||
@@ -119,9 +140,10 @@ class CMonitor {
|
||||
void addDamage(const CBox* box);
|
||||
void setMirror(const std::string&);
|
||||
bool isMirror();
|
||||
bool matchesStaticSelector(const std::string& selector) const;
|
||||
float getDefaultScale();
|
||||
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false);
|
||||
void changeWorkspace(const int& id, bool internal = false);
|
||||
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
|
||||
void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
|
||||
void setSpecialWorkspace(CWorkspace* const pWorkspace);
|
||||
void setSpecialWorkspace(const int& id);
|
||||
void moveTo(const Vector2D& pos);
|
||||
|
@@ -112,6 +112,11 @@ CRegion& CRegion::scale(float scale) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::scale(const Vector2D& scale) {
|
||||
wlr_region_scale_xy(&m_rRegion, &m_rRegion, scale.x, scale.y);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::vector<pixman_box32_t> CRegion::getRects() const {
|
||||
std::vector<pixman_box32_t> result;
|
||||
|
||||
|
@@ -49,6 +49,7 @@ class CRegion {
|
||||
CRegion& invert(pixman_box32_t* box);
|
||||
CRegion& invert(const CBox& box);
|
||||
CRegion& scale(float scale);
|
||||
CRegion& scale(const Vector2D& scale);
|
||||
CBox getExtents();
|
||||
bool containsPoint(const Vector2D& vec) const;
|
||||
bool empty() const;
|
||||
@@ -57,6 +58,7 @@ class CRegion {
|
||||
|
||||
std::vector<pixman_box32_t> getRects() const;
|
||||
|
||||
//
|
||||
pixman_region32_t* pixman() {
|
||||
return &m_rRegion;
|
||||
}
|
||||
|
@@ -19,6 +19,21 @@ inline const std::vector<std::string> SPLASHES = {
|
||||
"Compile, wait for 20 minutes, notice a new commit, compile again.",
|
||||
"To rice, or not to rice, that is the question.",
|
||||
"Now available on Fedora!",
|
||||
"\"Hyprland is so good it starts with a capital letter\" - Hazel",
|
||||
"\"please make this message a splash\" - eriedaberrie",
|
||||
"\"the only wayland compositor powered by fried chicken\" - raf",
|
||||
"\"This will never get into Hyprland\" - Flafy",
|
||||
"\"Hyprland only gives you up on -git\" - fazzi",
|
||||
"Segmentation fault (core dumped)",
|
||||
"\"disabling hyprland logo is a war crime\" - vaxry",
|
||||
"some basic startup code",
|
||||
"\"I think I am addicted to hyprland\" - mathisbuilder",
|
||||
"\"hyprland is the most important package in the arch repos\" - jacekpoz",
|
||||
"Thanks Brodie!",
|
||||
"Thanks fufexan!",
|
||||
"Thanks raf!",
|
||||
"You can't use --splash to change this message :)",
|
||||
"Hyprland will overtake Gnome in popularity by [insert year]",
|
||||
// music reference / quote section
|
||||
"J'remue le ciel, le jour, la nuit.",
|
||||
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
|
||||
@@ -60,6 +75,8 @@ inline const std::vector<std::string> SPLASHES = {
|
||||
"Join the discord server!",
|
||||
"Thanks ThatOneCalculator!",
|
||||
"The AUR packages always work, except for the times they don't.",
|
||||
"Funny animation compositor woo"
|
||||
"Funny animation compositor woo",
|
||||
//
|
||||
"2 years!"
|
||||
// clang-format on
|
||||
};
|
@@ -1,311 +0,0 @@
|
||||
#include "SubsurfaceTree.hpp"
|
||||
#include "../events/Events.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
|
||||
if (!node->pSurface || !node->pSurface->exists())
|
||||
return;
|
||||
|
||||
*lx += node->pSurface->wlr()->current.dx;
|
||||
*ly += node->pSurface->wlr()->current.dy;
|
||||
|
||||
if (node->offsetfn) {
|
||||
// This is the root node
|
||||
RASSERT(!node->pSubsurface, "Node had no subsurface!");
|
||||
node->offsetfn(node->globalOffsetData, lx, ly);
|
||||
} else {
|
||||
RASSERT(node->pSubsurface, "Node had no subsurface!");
|
||||
|
||||
*lx += node->pSubsurface->pSubsurface->current.x;
|
||||
*ly += node->pSubsurface->pSubsurface->current.y;
|
||||
|
||||
addSurfaceGlobalOffset(node->pParent, lx, ly);
|
||||
}
|
||||
}
|
||||
|
||||
SSurfaceTreeNode* createTree(wlr_surface* pSurface, CWindow* pWindow) {
|
||||
const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.emplace_back();
|
||||
|
||||
if (pSurface->data)
|
||||
PNODE->pSurface = (CWLSurface*)pSurface->data;
|
||||
else {
|
||||
PNODE->pInternalSurface = pSurface;
|
||||
PNODE->pSurface = &PNODE->pInternalSurface;
|
||||
}
|
||||
|
||||
PNODE->pWindowOwner = pWindow;
|
||||
|
||||
PNODE->hyprListener_newSubsurface.initCallback(&pSurface->events.new_subsurface, &Events::listener_newSubsurfaceNode, PNODE, "SurfaceTreeNode");
|
||||
PNODE->hyprListener_commit.initCallback(&pSurface->events.commit, &Events::listener_commitSubsurface, PNODE, "SurfaceTreeNode");
|
||||
PNODE->hyprListener_destroy.initCallback(&pSurface->events.destroy, &Events::listener_destroySubsurfaceNode, PNODE, "SurfaceTreeNode");
|
||||
|
||||
wlr_subsurface* wlrSubsurface;
|
||||
wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_below, current.link) {
|
||||
Events::listener_newSubsurfaceNode(PNODE, wlrSubsurface);
|
||||
}
|
||||
wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_above, current.link) {
|
||||
Events::listener_newSubsurfaceNode(PNODE, wlrSubsurface);
|
||||
}
|
||||
|
||||
return PNODE;
|
||||
}
|
||||
|
||||
SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* pSubsurface, wlr_surface* surface, CWindow* pWindow) {
|
||||
const auto PNODE = createTree(surface, pWindow);
|
||||
PNODE->pParent = pParent;
|
||||
PNODE->pSubsurface = pSubsurface;
|
||||
|
||||
Debug::log(LOG, "Creating a subsurface Node! {}", pWindow);
|
||||
|
||||
return PNODE;
|
||||
}
|
||||
|
||||
SSurfaceTreeNode* SubsurfaceTree::createTreeRoot(wlr_surface* pSurface, applyGlobalOffsetFn fn, void* data, CWindow* pWindow) {
|
||||
const auto PNODE = createTree(pSurface, pWindow);
|
||||
|
||||
Debug::log(LOG, "Creating a surfaceTree Root! {}", pWindow);
|
||||
|
||||
PNODE->offsetfn = fn;
|
||||
PNODE->globalOffsetData = data;
|
||||
|
||||
return PNODE;
|
||||
}
|
||||
|
||||
void destroySubsurface(SSubsurface* pSubsurface);
|
||||
|
||||
void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
|
||||
bool exists = false;
|
||||
for (auto& n : surfaceTreeNodes) {
|
||||
if (&n == pNode) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
Debug::log(ERR, "Tried to remove a SurfaceTreeNode that doesn't exist?? (Node {:x})", (uintptr_t)pNode);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& c : pNode->childSubsurfaces)
|
||||
destroySubsurface(&c);
|
||||
|
||||
pNode->childSubsurfaces.clear();
|
||||
|
||||
pNode->hyprListener_commit.removeCallback();
|
||||
pNode->hyprListener_destroy.removeCallback();
|
||||
pNode->hyprListener_newSubsurface.removeCallback();
|
||||
|
||||
// damage
|
||||
if (pNode->pSurface && pNode->pSurface->exists()) {
|
||||
CBox extents = {};
|
||||
wlr_surface_get_extends(pNode->pSurface->wlr(), extents.pWlr());
|
||||
extents.applyFromWlr();
|
||||
|
||||
int lx = 0, ly = 0;
|
||||
addSurfaceGlobalOffset(pNode, &lx, &ly);
|
||||
|
||||
extents.x += lx;
|
||||
extents.y += ly;
|
||||
|
||||
g_pHyprRenderer->damageBox(&extents);
|
||||
}
|
||||
|
||||
// remove references to this node
|
||||
for (auto& tn : surfaceTreeNodes) {
|
||||
for (auto& cs : tn.childSubsurfaces) {
|
||||
if (cs.pChild == pNode)
|
||||
cs.pChild = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
surfaceTreeNodes.remove(*pNode);
|
||||
|
||||
Debug::log(LOG, "SurfaceTree Node removed");
|
||||
}
|
||||
|
||||
void destroySubsurface(SSubsurface* pSubsurface) {
|
||||
if (pSubsurface->pChild) {
|
||||
SubsurfaceTree::destroySurfaceTree(pSubsurface->pChild);
|
||||
pSubsurface->pChild = nullptr;
|
||||
}
|
||||
|
||||
pSubsurface->hyprListener_destroy.removeCallback();
|
||||
pSubsurface->hyprListener_map.removeCallback();
|
||||
pSubsurface->hyprListener_unmap.removeCallback();
|
||||
}
|
||||
|
||||
//
|
||||
// Subsurface listeners
|
||||
//
|
||||
|
||||
void Events::listener_newSubsurfaceNode(void* owner, void* data) {
|
||||
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
|
||||
|
||||
const auto PSUBSURFACE = (wlr_subsurface*)data;
|
||||
|
||||
const auto PNEWSUBSURFACE = &pNode->childSubsurfaces.emplace_back();
|
||||
|
||||
Debug::log(LOG, "Added a new subsurface {:x}", (uintptr_t)PSUBSURFACE);
|
||||
|
||||
PNEWSUBSURFACE->pSubsurface = PSUBSURFACE;
|
||||
PNEWSUBSURFACE->pParent = pNode;
|
||||
|
||||
PNEWSUBSURFACE->hyprListener_map.initCallback(&PSUBSURFACE->surface->events.map, &Events::listener_mapSubsurface, PNEWSUBSURFACE, "Subsurface");
|
||||
PNEWSUBSURFACE->hyprListener_unmap.initCallback(&PSUBSURFACE->surface->events.unmap, &Events::listener_unmapSubsurface, PNEWSUBSURFACE, "Subsurface");
|
||||
PNEWSUBSURFACE->hyprListener_destroy.initCallback(&PSUBSURFACE->events.destroy, &Events::listener_destroySubsurface, PNEWSUBSURFACE, "Subsurface");
|
||||
|
||||
PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner;
|
||||
|
||||
if (PSUBSURFACE->surface->mapped)
|
||||
listener_mapSubsurface(PNEWSUBSURFACE, nullptr);
|
||||
|
||||
wlr_subsurface* existingWlrSubsurface;
|
||||
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) {
|
||||
listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
|
||||
}
|
||||
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_above, current.link) {
|
||||
listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_mapSubsurface(void* owner, void* data) {
|
||||
SSubsurface* subsurface = (SSubsurface*)owner;
|
||||
|
||||
if (subsurface->pChild)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface);
|
||||
|
||||
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
|
||||
}
|
||||
|
||||
void Events::listener_unmapSubsurface(void* owner, void* data) {
|
||||
SSubsurface* subsurface = (SSubsurface*)owner;
|
||||
|
||||
Debug::log(LOG, "Subsurface {:x} unmapped", (uintptr_t)subsurface);
|
||||
|
||||
if (subsurface->pSubsurface->surface == g_pCompositor->m_pLastFocus)
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
|
||||
if (subsurface->pChild) {
|
||||
const auto PNODE = subsurface->pChild;
|
||||
|
||||
const auto IT =
|
||||
std::find_if(SubsurfaceTree::surfaceTreeNodes.begin(), SubsurfaceTree::surfaceTreeNodes.end(), [&](const SSurfaceTreeNode& other) { return &other == PNODE; });
|
||||
|
||||
if (IT != SubsurfaceTree::surfaceTreeNodes.end()) {
|
||||
if (PNODE->pSurface && PNODE->pSurface->exists()) {
|
||||
int lx = 0, ly = 0;
|
||||
addSurfaceGlobalOffset(PNODE, &lx, &ly);
|
||||
|
||||
CBox extents = {lx, ly, 0, 0};
|
||||
|
||||
extents.width = PNODE->pSurface->wlr()->current.width;
|
||||
extents.height = PNODE->pSurface->wlr()->current.height;
|
||||
|
||||
g_pHyprRenderer->damageBox(&extents);
|
||||
}
|
||||
|
||||
// SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
|
||||
// subsurface->pChild = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface
|
||||
}
|
||||
|
||||
void Events::listener_commitSubsurface(void* owner, void* data) {
|
||||
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
|
||||
|
||||
// no damaging if it's not visible
|
||||
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
|
||||
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
|
||||
|
||||
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
|
||||
if (*PLOGDAMAGE)
|
||||
Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner);
|
||||
return;
|
||||
}
|
||||
|
||||
int lx = 0, ly = 0;
|
||||
|
||||
addSurfaceGlobalOffset(pNode, &lx, &ly);
|
||||
|
||||
const double SCALE = pNode->pWindowOwner && pNode->pWindowOwner->m_bIsX11 ? 1.0 / pNode->pWindowOwner->m_fX11SurfaceScaledBy : 1.0;
|
||||
|
||||
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
|
||||
// What this does is that basically, if the pNode is a child of some other node, on commit,
|
||||
// it will also damage (check & damage if needed) all its siblings.
|
||||
if (pNode->pParent)
|
||||
for (auto& cs : pNode->pParent->childSubsurfaces) {
|
||||
const auto NODECOORDS = pNode->pSubsurface ? Vector2D(pNode->pSubsurface->pSubsurface->current.x, pNode->pSubsurface->pSubsurface->current.y) : Vector2D();
|
||||
|
||||
if (&cs != pNode->pSubsurface && cs.pSubsurface) {
|
||||
g_pHyprRenderer->damageSurface(cs.pSubsurface->surface, lx - NODECOORDS.x + cs.pSubsurface->current.x, ly - NODECOORDS.y + cs.pSubsurface->current.y, SCALE);
|
||||
}
|
||||
}
|
||||
|
||||
if (pNode->pSurface && pNode->pSurface->exists()) {
|
||||
g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE);
|
||||
|
||||
if (pNode->lastSize != Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} && pNode->pWindowOwner)
|
||||
g_pHyprRenderer->damageWindow(pNode->pWindowOwner);
|
||||
}
|
||||
|
||||
if (pNode->pWindowOwner) {
|
||||
if (pNode->pWindowOwner->m_bIsX11)
|
||||
pNode->pWindowOwner->m_vReportedSize = pNode->pWindowOwner->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
|
||||
|
||||
// tearing: if solitary, redraw it. This still might be a single surface window
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID);
|
||||
if (PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
|
||||
pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
|
||||
CRegion damageBox;
|
||||
wlr_surface_get_effective_damage(pNode->pSurface->wlr(), damageBox.pixman());
|
||||
|
||||
if (!damageBox.empty()) {
|
||||
|
||||
if (PMONITOR->tearingState.busy) {
|
||||
PMONITOR->tearingState.frameScheduledWhileBusy = true;
|
||||
} else {
|
||||
PMONITOR->tearingState.nextRenderTorn = true;
|
||||
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
|
||||
}
|
||||
|
||||
void Events::listener_destroySubsurface(void* owner, void* data) {
|
||||
SSubsurface* subsurface = (SSubsurface*)owner;
|
||||
|
||||
if (subsurface->pChild) {
|
||||
SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Subsurface {:x} destroyed", (uintptr_t)subsurface);
|
||||
|
||||
subsurface->hyprListener_destroy.removeCallback();
|
||||
subsurface->hyprListener_map.removeCallback();
|
||||
subsurface->hyprListener_unmap.removeCallback();
|
||||
|
||||
subsurface->pParent->childSubsurfaces.remove(*subsurface);
|
||||
}
|
||||
|
||||
void Events::listener_destroySubsurfaceNode(void* owner, void* data) {
|
||||
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
|
||||
|
||||
Debug::log(LOG, "Subsurface Node {:x} destroyed", (uintptr_t)pNode);
|
||||
|
||||
for (auto& c : pNode->childSubsurfaces)
|
||||
destroySubsurface(&c);
|
||||
|
||||
pNode->hyprListener_commit.removeCallback();
|
||||
pNode->hyprListener_newSubsurface.removeCallback();
|
||||
pNode->hyprListener_destroy.removeCallback();
|
||||
|
||||
SubsurfaceTree::surfaceTreeNodes.remove(*pNode);
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include <list>
|
||||
#include "WLSurface.hpp"
|
||||
|
||||
struct SSubsurface;
|
||||
class CWindow;
|
||||
|
||||
typedef void (*applyGlobalOffsetFn)(void*, int*, int*);
|
||||
|
||||
struct SSurfaceTreeNode {
|
||||
CWLSurface* pSurface = nullptr; // actual surface
|
||||
CWLSurface pInternalSurface; // not present for head nodes to not dupe wlr_surface ownership
|
||||
|
||||
DYNLISTENER(newSubsurface);
|
||||
DYNLISTENER(commit);
|
||||
DYNLISTENER(destroy);
|
||||
|
||||
SSurfaceTreeNode* pParent = nullptr;
|
||||
SSubsurface* pSubsurface = nullptr;
|
||||
|
||||
std::list<SSubsurface> childSubsurfaces;
|
||||
|
||||
applyGlobalOffsetFn offsetfn;
|
||||
void* globalOffsetData;
|
||||
CWindow* pWindowOwner = nullptr;
|
||||
|
||||
Vector2D lastSize;
|
||||
|
||||
//
|
||||
bool operator==(const SSurfaceTreeNode& rhs) const {
|
||||
return pSurface == rhs.pSurface;
|
||||
}
|
||||
};
|
||||
|
||||
struct SSubsurface {
|
||||
wlr_subsurface* pSubsurface = nullptr;
|
||||
|
||||
SSurfaceTreeNode* pParent = nullptr;
|
||||
SSurfaceTreeNode* pChild = nullptr;
|
||||
|
||||
DYNLISTENER(map);
|
||||
DYNLISTENER(unmap);
|
||||
DYNLISTENER(destroy);
|
||||
|
||||
CWindow* pWindowOwner = nullptr;
|
||||
|
||||
//
|
||||
bool operator==(const SSubsurface& rhs) const {
|
||||
return pSubsurface == rhs.pSubsurface;
|
||||
}
|
||||
};
|
||||
|
||||
namespace SubsurfaceTree {
|
||||
SSurfaceTreeNode* createTreeRoot(wlr_surface*, applyGlobalOffsetFn, void*, CWindow* pWindow = nullptr);
|
||||
void destroySurfaceTree(SSurfaceTreeNode*);
|
||||
|
||||
inline std::list<SSurfaceTreeNode> surfaceTreeNodes;
|
||||
};
|
@@ -12,6 +12,11 @@ Vector2D::Vector2D() {
|
||||
y = 0;
|
||||
}
|
||||
|
||||
Vector2D::Vector2D(const Hyprlang::VEC2& ref) {
|
||||
x = ref.x;
|
||||
y = ref.y;
|
||||
}
|
||||
|
||||
Vector2D::~Vector2D() {}
|
||||
|
||||
double Vector2D::normalize() {
|
||||
@@ -42,14 +47,10 @@ double Vector2D::distance(const Vector2D& other) const {
|
||||
return std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
bool Vector2D::inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const {
|
||||
const auto a = ((p2.y - p3.y) * (x - p3.x) + (p3.x - p2.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
|
||||
const auto b = ((p3.y - p1.y) * (x - p3.x) + (p1.x - p3.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
|
||||
const auto c = 1 - a - b;
|
||||
|
||||
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
|
||||
}
|
||||
|
||||
double Vector2D::size() const {
|
||||
return std::sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
Vector2D Vector2D::getComponentMax(const Vector2D& other) const {
|
||||
return Vector2D(std::max(this->x, other.x), std::max(this->y, other.y));
|
||||
}
|
||||
|
@@ -3,12 +3,14 @@
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
#include "../macros.hpp"
|
||||
#include <hyprlang.hpp>
|
||||
|
||||
class Vector2D {
|
||||
public:
|
||||
Vector2D(double, double);
|
||||
Vector2D();
|
||||
~Vector2D();
|
||||
Vector2D(const Hyprlang::VEC2&);
|
||||
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
@@ -88,12 +90,12 @@ class Vector2D {
|
||||
|
||||
double distance(const Vector2D& other) const;
|
||||
double size() const;
|
||||
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const;
|
||||
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D{-1, -1}) const;
|
||||
|
||||
Vector2D floor() const;
|
||||
Vector2D round() const;
|
||||
|
||||
bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const;
|
||||
Vector2D getComponentMax(const Vector2D& other) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -3,9 +3,17 @@
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
SLayerSurface::SLayerSurface() {
|
||||
alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
alpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeLayers"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
realPosition.create(g_pConfigManager->getAnimationPropertyConfig("layers"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
realSize.create(g_pConfigManager->getAnimationPropertyConfig("layers"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
alpha.m_pLayer = this;
|
||||
realPosition.m_pLayer = this;
|
||||
realSize.m_pLayer = this;
|
||||
alpha.registerVar();
|
||||
realPosition.registerVar();
|
||||
realSize.registerVar();
|
||||
|
||||
alpha.setValueAndWarp(0.f);
|
||||
}
|
||||
|
||||
SLayerSurface::~SLayerSurface() {
|
||||
@@ -22,6 +30,7 @@ void SLayerSurface::applyRules() {
|
||||
ignoreAlpha = false;
|
||||
ignoreAlphaValue = 0.f;
|
||||
xray = -1;
|
||||
animationStyle.reset();
|
||||
|
||||
for (auto& rule : g_pConfigManager->getMatchingRules(this)) {
|
||||
if (rule.rule == "noanim")
|
||||
@@ -44,82 +53,193 @@ void SLayerSurface::applyRules() {
|
||||
try {
|
||||
xray = configStringToInt(vars[1]);
|
||||
} catch (...) {}
|
||||
} else if (rule.rule.starts_with("animation")) {
|
||||
CVarList vars{rule.rule, 2, 's'};
|
||||
animationStyle = vars[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CRegion SConstraint::getLogicCoordsRegion() {
|
||||
CRegion result;
|
||||
void SLayerSurface::startAnimation(bool in, bool instant) {
|
||||
const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle);
|
||||
|
||||
if (!constraint)
|
||||
return result;
|
||||
if (ANIMSTYLE == "slide") {
|
||||
// get closest edge
|
||||
const auto MIDDLE = geometry.middle();
|
||||
|
||||
const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface);
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE);
|
||||
|
||||
if (!PWINDOWOWNER)
|
||||
return result;
|
||||
const std::array<Vector2D, 4> edgePoints = {
|
||||
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0},
|
||||
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y},
|
||||
PMONITOR->vecPosition + Vector2D{0, PMONITOR->vecSize.y},
|
||||
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2},
|
||||
};
|
||||
|
||||
result.add(&constraint->region); // surface-local coords
|
||||
|
||||
if (!PWINDOWOWNER->m_bIsX11) {
|
||||
result.translate(PWINDOWOWNER->m_vRealPosition.goalv());
|
||||
return result;
|
||||
float closest = std::numeric_limits<float>::max();
|
||||
size_t leader = 0;
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
float dist = MIDDLE.distance(edgePoints[i]);
|
||||
if (dist < closest) {
|
||||
leader = i;
|
||||
closest = dist;
|
||||
}
|
||||
}
|
||||
|
||||
const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() :
|
||||
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y});
|
||||
realSize.setValueAndWarp(geometry.size());
|
||||
alpha.setValueAndWarp(1.f);
|
||||
|
||||
const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : g_pCompositor->getMonitorFromVector(COORDS);
|
||||
Vector2D prePos;
|
||||
|
||||
if (!PMONITOR)
|
||||
return CRegion{};
|
||||
|
||||
result.scale(PMONITOR->xwaylandScale);
|
||||
|
||||
result.translate(COORDS);
|
||||
|
||||
return result;
|
||||
switch (leader) {
|
||||
case 0:
|
||||
// TOP
|
||||
prePos = {geometry.x, PMONITOR->vecPosition.y - geometry.h};
|
||||
break;
|
||||
case 1:
|
||||
// BOTTOM
|
||||
prePos = {geometry.x, PMONITOR->vecPosition.y + PMONITOR->vecPosition.y};
|
||||
break;
|
||||
case 2:
|
||||
// LEFT
|
||||
prePos = {PMONITOR->vecPosition.x - geometry.w, geometry.y};
|
||||
break;
|
||||
case 3:
|
||||
// RIGHT
|
||||
prePos = {PMONITOR->vecPosition.x + PMONITOR->vecSize.x, geometry.y};
|
||||
break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
Vector2D SConstraint::getLogicConstraintPos() {
|
||||
if (!constraint)
|
||||
return {};
|
||||
|
||||
const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface);
|
||||
|
||||
if (!PWINDOWOWNER)
|
||||
return {};
|
||||
|
||||
if (!PWINDOWOWNER->m_bIsX11)
|
||||
return PWINDOWOWNER->m_vRealPosition.goalv();
|
||||
|
||||
const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() :
|
||||
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y});
|
||||
|
||||
return COORDS;
|
||||
if (in) {
|
||||
realPosition.setValueAndWarp(prePos);
|
||||
realPosition = geometry.pos();
|
||||
} else {
|
||||
realPosition.setValueAndWarp(geometry.pos());
|
||||
realPosition = prePos;
|
||||
}
|
||||
|
||||
Vector2D SConstraint::getLogicConstraintSize() {
|
||||
if (!constraint)
|
||||
return {};
|
||||
|
||||
const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface);
|
||||
|
||||
if (!PWINDOWOWNER)
|
||||
return {};
|
||||
|
||||
if (!PWINDOWOWNER->m_bIsX11)
|
||||
return PWINDOWOWNER->m_vRealSize.goalv();
|
||||
|
||||
const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ?
|
||||
g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) :
|
||||
g_pCompositor->getMonitorFromVector(g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y}));
|
||||
|
||||
if (!PMONITOR)
|
||||
return {};
|
||||
|
||||
const auto SIZE = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealSize.goalv() :
|
||||
Vector2D{PWINDOWOWNER->m_uSurface.xwayland->width, PWINDOWOWNER->m_uSurface.xwayland->height} * PMONITOR->xwaylandScale;
|
||||
|
||||
return SIZE;
|
||||
} else if (ANIMSTYLE.starts_with("popin")) {
|
||||
float minPerc = 0.f;
|
||||
if (ANIMSTYLE.find("%") != std::string::npos) {
|
||||
try {
|
||||
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' '));
|
||||
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
|
||||
} catch (std::exception& e) {
|
||||
; // oops
|
||||
}
|
||||
}
|
||||
|
||||
minPerc *= 0.01;
|
||||
|
||||
const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5});
|
||||
const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f;
|
||||
|
||||
alpha.setValueAndWarp(in ? 0.f : 1.f);
|
||||
alpha = in ? 1.f : 0.f;
|
||||
|
||||
if (in) {
|
||||
realSize.setValueAndWarp(GOALSIZE);
|
||||
realPosition.setValueAndWarp(GOALPOS);
|
||||
realSize = geometry.size();
|
||||
realPosition = geometry.pos();
|
||||
} else {
|
||||
realSize.setValueAndWarp(geometry.size());
|
||||
realPosition.setValueAndWarp(geometry.pos());
|
||||
realSize = GOALSIZE;
|
||||
realPosition = GOALPOS;
|
||||
}
|
||||
} else {
|
||||
// fade
|
||||
realPosition.setValueAndWarp(geometry.pos());
|
||||
realSize.setValueAndWarp(geometry.size());
|
||||
alpha = in ? 1.f : 0.f;
|
||||
}
|
||||
|
||||
if (!in)
|
||||
fadingOut = true;
|
||||
}
|
||||
|
||||
bool SLayerSurface::isFadedOut() {
|
||||
if (!fadingOut)
|
||||
return false;
|
||||
|
||||
return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated();
|
||||
}
|
||||
|
||||
void SKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
|
||||
xkb_state_unref(xkbTranslationState);
|
||||
|
||||
if (keymap) {
|
||||
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
|
||||
xkbTranslationState = xkb_state_new(keymap);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto WLRKB = wlr_keyboard_from_input_device(keyboard);
|
||||
const auto KEYMAP = WLRKB->keymap;
|
||||
const auto STATE = WLRKB->xkb_state;
|
||||
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
|
||||
|
||||
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
|
||||
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
|
||||
if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE)) {
|
||||
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an active index {}", (uintptr_t)this, i);
|
||||
|
||||
CVarList keyboardLayouts(currentRules.layout, 0, ',');
|
||||
CVarList keyboardModels(currentRules.model, 0, ',');
|
||||
CVarList keyboardVariants(currentRules.variant, 0, ',');
|
||||
|
||||
xkb_rule_names rules = {.rules = "", .model = "", .layout = "", .variant = "", .options = ""};
|
||||
|
||||
std::string layout, model, variant;
|
||||
layout = keyboardLayouts[i % keyboardLayouts.size()];
|
||||
model = keyboardModels[i % keyboardModels.size()];
|
||||
variant = keyboardVariants[i % keyboardVariants.size()];
|
||||
|
||||
rules.layout = layout.c_str();
|
||||
rules.model = model.c_str();
|
||||
rules.variant = variant.c_str();
|
||||
|
||||
auto KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
|
||||
if (!KEYMAP) {
|
||||
Debug::log(ERR, "updateXKBTranslationState: keymap failed 1, fallback without model/variant");
|
||||
rules.model = "";
|
||||
rules.variant = "";
|
||||
KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
}
|
||||
|
||||
if (!KEYMAP) {
|
||||
Debug::log(ERR, "updateXKBTranslationState: keymap failed 2, fallback to us");
|
||||
rules.layout = "us";
|
||||
KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
}
|
||||
|
||||
xkbTranslationState = xkb_state_new(KEYMAP);
|
||||
|
||||
xkb_keymap_unref(KEYMAP);
|
||||
xkb_context_unref(PCONTEXT);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an unknown index", (uintptr_t)this);
|
||||
|
||||
xkb_rule_names rules = {
|
||||
.rules = currentRules.rules.c_str(),
|
||||
.model = currentRules.model.c_str(),
|
||||
.layout = currentRules.layout.c_str(),
|
||||
.variant = currentRules.variant.c_str(),
|
||||
.options = currentRules.options.c_str(),
|
||||
};
|
||||
|
||||
const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
|
||||
xkbTranslationState = xkb_state_new(NEWKEYMAP);
|
||||
|
||||
xkb_keymap_unref(NEWKEYMAP);
|
||||
xkb_context_unref(PCONTEXT);
|
||||
}
|