mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-15 20:13:49 -07:00
Compare commits
254 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
03ebbe18ed | ||
|
7c1ac58a4b | ||
|
46997a7643 | ||
|
b5b025a1ed | ||
|
94d6b2d2c1 | ||
|
33fe3a2e7f | ||
|
2ad2e1d5f5 | ||
|
5f8e4068e5 | ||
|
78f9ba9fdd | ||
|
9242b03317 | ||
|
f9c13b614c | ||
|
ddf8e01c1e | ||
|
f771c10d1a | ||
|
8321d6be46 | ||
|
cedf5f1fca | ||
|
9fba887cc9 | ||
|
4f3ee4c645 | ||
|
5f65946c84 | ||
|
6a93cee74e | ||
|
07132741bc | ||
|
e5eb11ad04 | ||
|
e75dafd8b2 | ||
|
b7e8110a30 | ||
|
2702814a3f | ||
|
f86cdcf8d5 | ||
|
85d375e8ab | ||
|
6cd82d948f | ||
|
1ecd173c7a | ||
|
7474c81958 | ||
|
191fa587f4 | ||
|
9fb50252d3 | ||
|
bfb4d66c81 | ||
|
34b0ce66b3 | ||
|
2c2ff4b61b | ||
|
4f99e805b9 | ||
|
e2d04ae503 | ||
|
b25b06430b | ||
|
5aab4a96e3 | ||
|
ff75f991a5 | ||
|
f013acc6ee | ||
|
d5811283d2 | ||
|
5c7e23f86b | ||
|
b9c1414f25 | ||
|
cc0516a9ae | ||
|
6c8e0f9863 | ||
|
6b6f3396cf | ||
|
79ef29d6e0 | ||
|
c416880cf9 | ||
|
37d2840246 | ||
|
7cec618fe4 | ||
|
bd952dcef2 | ||
|
bc51a91043 | ||
|
698f3b6576 | ||
|
79f3888b4b | ||
|
4eb42fab7b | ||
|
48ecb13b14 | ||
|
a197fe3c11 | ||
|
53c78ab906 | ||
|
b4f4bd38e8 | ||
|
d1b8a63a8e | ||
|
3771c49a94 | ||
|
d9b74ff96b | ||
|
ef445093f9 | ||
|
11fd37418c | ||
|
0c74df4f9e | ||
|
460a326c90 | ||
|
403fd7d9f6 | ||
|
763d5fa05f | ||
|
9fd928e114 | ||
|
bf7374011b | ||
|
8c9f38e405 | ||
|
c0d9dcc586 | ||
|
2a777cb71b | ||
|
9ca0c7d814 | ||
|
b1b8d732e6 | ||
|
4e5d9b90c0 | ||
|
e1ed8e11ca | ||
|
79d8d14fe0 | ||
|
395ab3ba37 | ||
|
36fa33f7ca | ||
|
f7cde9c92c | ||
|
01e5c59d75 | ||
|
b2e5a80e2f | ||
|
55cb565e6d | ||
|
4190b96718 | ||
|
d9bc210285 | ||
|
4de986072c | ||
|
934112af5b | ||
|
ba2af6f86d | ||
|
1950c3fc9c | ||
|
8f38487884 | ||
|
accb3d8d0b | ||
|
ea7569d7e0 | ||
|
e53134ca90 | ||
|
8191e635a3 | ||
|
0fdf909b19 | ||
|
50648e6bae | ||
|
53ce7992be | ||
|
167f2ed3b2 | ||
|
d02ba422da | ||
|
359baa0214 | ||
|
efdf07e295 | ||
|
0c10b8ab2d | ||
|
9f5b9053c6 | ||
|
b3dc58e104 | ||
|
af6aae4e12 | ||
|
0ebbf371ff | ||
|
89d8f665b5 | ||
|
9132660768 | ||
|
dd0714c22a | ||
|
11d1c50420 | ||
|
288f1863f0 | ||
|
6fb1b89b98 | ||
|
004bf94a23 | ||
|
aa020a2a1a | ||
|
d9175a0181 | ||
|
a794eecd6a | ||
|
d360550546 | ||
|
62a8d0be5c | ||
|
4a42344e97 | ||
|
5489f9f07a | ||
|
d74607e414 | ||
|
c4bd91ec8a | ||
|
03c6f4506a | ||
|
13b4c6de86 | ||
|
8bd86cf37e | ||
|
cfd94c5b30 | ||
|
ab66fa430e | ||
|
37d7a8c64d | ||
|
da863459c4 | ||
|
83248b6936 | ||
|
3bb9c7c5cf | ||
|
2d04cb1cc6 | ||
|
c6804ccaab | ||
|
aa46aaed04 | ||
|
68783d904d | ||
|
5d100bdcbb | ||
|
45d3fbb8d8 | ||
|
9a9528d093 | ||
|
e496b0f250 | ||
|
dc2082b00a | ||
|
59cb0e20de | ||
|
80b9b21f9f | ||
|
758cf90ea1 | ||
|
6e8b9ef7d8 | ||
|
9c09f2a847 | ||
|
8440a30231 | ||
|
ab40f240c3 | ||
|
b394c1695c | ||
|
0a4c4da5f0 | ||
|
b2f3623131 | ||
|
5513eed64d | ||
|
29970228c5 | ||
|
12ec549a18 | ||
|
9f2027be4b | ||
|
b9937484f4 | ||
|
776f944619 | ||
|
1fc1e4e9cb | ||
|
e1258707ad | ||
|
d2c3b23ace | ||
|
b80c72c7dd | ||
|
3caaa483d4 | ||
|
e2f18f8c7f | ||
|
99ca26d4eb | ||
|
e416ab740d | ||
|
7a0a5666d5 | ||
|
1778fb77e2 | ||
|
adeb20ea11 | ||
|
68e57b7ee3 | ||
|
408d96668d | ||
|
75e5799310 | ||
|
9e2b939024 | ||
|
cd96ceecc5 | ||
|
ad3f688648 | ||
|
98c7ba4782 | ||
|
a5f64b48ca | ||
|
b281d8647a | ||
|
15b282ee0c | ||
|
6f733292bf | ||
|
3fe6162af1 | ||
|
2ce4b94a22 | ||
|
de95e956a0 | ||
|
929c44e361 | ||
|
512a59731b | ||
|
a6eba91935 | ||
|
745b998587 | ||
|
1a2a2da6aa | ||
|
822775aa8c | ||
|
d79cf0afe2 | ||
|
334d0ae31b | ||
|
be3d635265 | ||
|
f9ba5a0551 | ||
|
258c83f3bb | ||
|
aedcade68d | ||
|
802ab58f8a | ||
|
af5d06593f | ||
|
2ebfd0c745 | ||
|
e40e486f61 | ||
|
e55c5a916a | ||
|
45ebe0df8f | ||
|
812a3f6d78 | ||
|
44accacff9 | ||
|
d417370bb7 | ||
|
4729265284 | ||
|
572fd554b8 | ||
|
7d1c8d827a | ||
|
6d26199e1c | ||
|
646f4bc638 | ||
|
7e0c90b92c | ||
|
add23a9ba2 | ||
|
3d89654254 | ||
|
6ad5f26cfe | ||
|
89f6457a99 | ||
|
8b57a1973e | ||
|
483302a2cd | ||
|
a903dba858 | ||
|
395985f815 | ||
|
51282f964f | ||
|
db8f13291a | ||
|
30ad71ff36 | ||
|
84bc0a73f6 | ||
|
1d9bfa60a1 | ||
|
a34e192433 | ||
|
4868d4dfd3 | ||
|
859841f4d1 | ||
|
28ef18a921 | ||
|
91d6be1f09 | ||
|
9e3dccca76 | ||
|
81598b3dbd | ||
|
e195e51c1b | ||
|
e8469f8b1b | ||
|
49597688e9 | ||
|
5edb4e4a30 | ||
|
4d6fa6ed0c | ||
|
016a7a9c9b | ||
|
2e26542e3b | ||
|
68935ba9dc | ||
|
ba5bc5871f | ||
|
824ccd957b | ||
|
45e86d4fdf | ||
|
0ba2e68704 | ||
|
e974d1fe98 | ||
|
47d46aa56c | ||
|
65efde32c9 | ||
|
69e314207d | ||
|
1bfd4a2bff | ||
|
91cbe93cf8 | ||
|
9afdd61ade | ||
|
f39a6ca17c | ||
|
eab2799842 | ||
|
6eb2abcb20 | ||
|
ae46fbafe5 | ||
|
52cf122a0a | ||
|
844da8db56 |
1
.clang-format-ignore
Normal file
1
.clang-format-ignore
Normal file
@@ -0,0 +1 @@
|
||||
subprojects/**/*
|
75
.github/actions/setup_base/action.yml
vendored
Normal file
75
.github/actions/setup_base/action.yml
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
name: "Setup base"
|
||||
|
||||
inputs:
|
||||
INSTALL_XORG_PKGS:
|
||||
description: 'Install xorg dependencies'
|
||||
required: false
|
||||
default: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Get required pacman pkgs
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||
pacman --noconfirm --noprogressbar -Syyu
|
||||
pacman --noconfirm --noprogressbar -Sy \
|
||||
base-devel \
|
||||
cairo \
|
||||
clang \
|
||||
cmake \
|
||||
git \
|
||||
glm \
|
||||
glslang \
|
||||
go \
|
||||
jq \
|
||||
libc++ \
|
||||
libdisplay-info \
|
||||
libdrm \
|
||||
libepoxy \
|
||||
libfontenc \
|
||||
libglvnd \
|
||||
libinput \
|
||||
libliftoff \
|
||||
libxcvt \
|
||||
libxfont2 \
|
||||
libxkbcommon \
|
||||
libxkbfile \
|
||||
lld \
|
||||
meson \
|
||||
ninja \
|
||||
pango \
|
||||
pixman \
|
||||
pkgconf \
|
||||
scdoc \
|
||||
seatd \
|
||||
systemd \
|
||||
tomlplusplus \
|
||||
wayland \
|
||||
wayland-protocols \
|
||||
xcb-util-errors \
|
||||
xcb-util-renderutil \
|
||||
xcb-util-wm
|
||||
|
||||
- name: Get Xorg pacman pkgs
|
||||
shell: bash
|
||||
if: inputs.INSTALL_XORG_PKGS == 'true'
|
||||
run: |
|
||||
pacman --noconfirm --noprogressbar -Sy \
|
||||
xorg-fonts-encodings \
|
||||
xorg-server-common \
|
||||
xorg-setxkbmap \
|
||||
xorg-xkbcomp \
|
||||
xorg-xwayland
|
||||
|
||||
- name: Checkout Hyprland
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
# Fix an issue with actions/checkout where the checkout repo is not mark as safe
|
||||
- name: Mark directory as safe for git
|
||||
shell: bash
|
||||
run: |
|
||||
git config --global --add safe.directory /__w/Hyprland/Hyprland
|
106
.github/workflows/ci.yaml
vendored
106
.github/workflows/ci.yaml
vendored
@@ -8,29 +8,20 @@ jobs:
|
||||
container:
|
||||
image: archlinux
|
||||
steps:
|
||||
- name: Get required pacman pkgs
|
||||
run: |
|
||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||
pacman --noconfirm --noprogressbar -Syyu
|
||||
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd python libliftoff
|
||||
- name: Set up user
|
||||
run: |
|
||||
useradd -m githubuser
|
||||
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
|
||||
- name: Install libdisplay-info from the AUR
|
||||
run: |
|
||||
su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
|
||||
- name: Fix permissions for git
|
||||
run: |
|
||||
git config --global --add safe.directory /__w/Hyprland/Hyprland
|
||||
- name: Checkout Hyprland
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout repository actions
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
- name: Setup base
|
||||
uses: ./.github/actions/setup_base
|
||||
with:
|
||||
INSTALL_XORG_PKGS: true
|
||||
|
||||
- name: Build Hyprland
|
||||
run: |
|
||||
git submodule sync --recursive && git submodule update --init --force --recursive
|
||||
make all
|
||||
|
||||
- name: Compress and package artifacts
|
||||
run: |
|
||||
mkdir x86_64-pc-linux-gnu
|
||||
@@ -40,11 +31,12 @@ jobs:
|
||||
cp ./LICENSE hyprland/
|
||||
cp build/Hyprland hyprland/
|
||||
cp build/hyprctl/hyprctl hyprland/
|
||||
cp subprojects/wlroots/build/libwlroots.so.12032 hyprland/
|
||||
cp subprojects/wlroots/build/libwlroots.so.13032 hyprland/
|
||||
cp build/Hyprland hyprland/
|
||||
cp -r example/ hyprland/
|
||||
cp -r assets/ hyprland/
|
||||
tar -cvf Hyprland.tar.xz hyprland
|
||||
|
||||
- name: Release
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -57,28 +49,19 @@ jobs:
|
||||
container:
|
||||
image: archlinux
|
||||
steps:
|
||||
- name: Download dependencies
|
||||
run: |
|
||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||
pacman --noconfirm --noprogressbar -Syyu
|
||||
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd cmake jq python libliftoff
|
||||
- name: Set up user
|
||||
run: |
|
||||
useradd -m githubuser
|
||||
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
|
||||
- name: Install libdisplay-info from the AUR
|
||||
run: |
|
||||
su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
|
||||
- name: Checkout Hyprland
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout repository actions
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
- name: Setup base
|
||||
uses: ./.github/actions/setup_base
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
meson obj-x86_64-pc-linux-gnu \
|
||||
-Ddefault_library=static
|
||||
run: meson setup build -Ddefault_library=static
|
||||
|
||||
- name: Compile
|
||||
run: ninja -C obj-x86_64-pc-linux-gnu
|
||||
run: ninja -C build
|
||||
|
||||
noxwayland:
|
||||
name: "Build Hyprland in pure Wayland (Arch)"
|
||||
@@ -86,23 +69,36 @@ jobs:
|
||||
container:
|
||||
image: archlinux
|
||||
steps:
|
||||
- name: Download dependencies
|
||||
run: |
|
||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||
pacman --noconfirm --noprogressbar -Syyu
|
||||
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd libliftoff
|
||||
- name: Set up user
|
||||
run: |
|
||||
useradd -m githubuser
|
||||
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
|
||||
- name: Install libdisplay-info from the AUR
|
||||
run: |
|
||||
su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
|
||||
- name: Checkout Hyprland
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout repository actions
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
- name: Setup base
|
||||
uses: ./.github/actions/setup_base
|
||||
|
||||
- name: Configure
|
||||
run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja
|
||||
run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja
|
||||
|
||||
- name: Compile
|
||||
run: make release
|
||||
|
||||
clang-format:
|
||||
name: "Code Style (Arch)"
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: archlinux
|
||||
steps:
|
||||
- name: Checkout repository actions
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
- name: Setup base
|
||||
uses: ./.github/actions/setup_base
|
||||
|
||||
- name: Configure
|
||||
run: meson setup build -Ddefault_library=static
|
||||
|
||||
- name: clang-format check
|
||||
run: ninja -C build clang-format-check
|
||||
|
3
.github/workflows/nix-build.yml
vendored
3
.github/workflows/nix-build.yml
vendored
@@ -10,7 +10,6 @@ jobs:
|
||||
matrix:
|
||||
package:
|
||||
- hyprland
|
||||
- hyprland-nvidia
|
||||
- xdg-desktop-portal-hyprland
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
@@ -27,4 +26,4 @@ jobs:
|
||||
name: hyprland
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
|
||||
- run: nix build -L ${{ matrix.command }}
|
||||
- run: nix build .#${{ matrix.package }} -L
|
||||
|
29
.github/workflows/security-checks.yml
vendored
29
.github/workflows/security-checks.yml
vendored
@@ -24,13 +24,13 @@ 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
|
||||
@@ -42,34 +42,25 @@ jobs:
|
||||
language: [ 'cpp' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- 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: Init Hyprland build
|
||||
run: |
|
||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||
pacman --noconfirm --noprogressbar -Syyu
|
||||
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd python libliftoff
|
||||
useradd -m githubuser
|
||||
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
|
||||
su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
|
||||
git config --global --add safe.directory /__w/Hyprland/Hyprland
|
||||
|
||||
- name: Checkout Hyprland
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup base
|
||||
uses: ./.github/actions/setup_base
|
||||
with:
|
||||
submodules: recursive
|
||||
INSTALL_XORG_PKGS: true
|
||||
|
||||
- name: Build Hyprland
|
||||
run: |
|
||||
git submodule sync --recursive && git submodule update --init --force --recursive
|
||||
make all
|
||||
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
|
@@ -57,12 +57,12 @@ ExternalProject_Add(
|
||||
wlroots
|
||||
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||
PATCH_COMMAND sed -E -i -e "s/(soversion = 12)([^032]|$$)/soversion = 12032/g" meson.build
|
||||
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
|
||||
BUILD_COMMAND ninja -C build
|
||||
BUILD_ALWAYS true
|
||||
BUILD_IN_SOURCE true
|
||||
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032
|
||||
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032
|
||||
INSTALL_COMMAND echo "wlroots: install not needed"
|
||||
)
|
||||
|
||||
@@ -99,14 +99,19 @@ set(CMAKE_ENABLE_EXPORTS TRUE)
|
||||
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
|
||||
|
||||
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||
|
||||
add_executable(Hyprland ${SRCFILES})
|
||||
set(TRACY_CPP_FILES "")
|
||||
if(USE_TRACY)
|
||||
set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
|
||||
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
|
||||
endif()
|
||||
|
||||
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
|
||||
add_dependencies(Hyprland wlroots)
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
@@ -216,7 +221,7 @@ function(protocol protoPath protoName external)
|
||||
endfunction()
|
||||
|
||||
target_link_libraries(Hyprland
|
||||
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032 # wlroots is provided by us
|
||||
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032 # wlroots is provided by us
|
||||
OpenGL::EGL
|
||||
OpenGL::GL
|
||||
Threads::Threads
|
||||
@@ -240,5 +245,6 @@ protocol("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" f
|
||||
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
|
||||
protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
|
||||
|
||||
# hyprctl
|
||||
# tools
|
||||
add_subdirectory(hyprctl)
|
||||
add_subdirectory(hyprpm)
|
||||
|
10
Makefile
10
Makefile
@@ -38,8 +38,11 @@ install:
|
||||
mkdir -p ${PREFIX}/bin
|
||||
cp -f ./build/Hyprland ${PREFIX}/bin
|
||||
cp -f ./build/hyprctl/hyprctl ${PREFIX}/bin
|
||||
cp -f ./build/hyprpm/hyprpm ${PREFIX}/bin
|
||||
chmod 755 ${PREFIX}/bin/Hyprland
|
||||
chmod 755 ${PREFIX}/bin/hyprctl
|
||||
chmod 755 ${PREFIX}/bin/hyprpm
|
||||
ln -s -r ${PREFIX}/bin/Hyprland ${PREFIX}/bin/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
|
||||
@@ -50,7 +53,7 @@ install:
|
||||
install -m644 ./docs/*.1 ${PREFIX}/share/man/man1
|
||||
|
||||
mkdir -p ${PREFIX}/lib/
|
||||
cp ./subprojects/wlroots/build/libwlroots.so.12032 ${PREFIX}/lib/
|
||||
cp ./subprojects/wlroots/build/libwlroots.so.13032 ${PREFIX}/lib/
|
||||
|
||||
$(MAKE) installheaders
|
||||
|
||||
@@ -58,7 +61,8 @@ uninstall:
|
||||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||
rm -f ${PREFIX}/bin/Hyprland
|
||||
rm -f ${PREFIX}/bin/hyprctl
|
||||
rm -f ${PREFIX}/lib/libwlroots.so.12032
|
||||
rm -f ${PREFIX}/bin/hyprpm
|
||||
rm -f ${PREFIX}/lib/libwlroots.so.13032
|
||||
rm -rf ${PREFIX}/share/hyprland
|
||||
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
||||
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
||||
@@ -68,7 +72,7 @@ pluginenv:
|
||||
@exit 1
|
||||
|
||||
installheaders:
|
||||
@if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||
@if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||
|
||||
mkdir -p ${PREFIX}/include/hyprland
|
||||
mkdir -p ${PREFIX}/include/hyprland/protocols
|
||||
|
@@ -41,6 +41,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
|
||||
- Much more QoL stuff than other wlr-based compositors
|
||||
- Custom bezier curves for the best animations
|
||||
- Powerful plugin support
|
||||
- Built-in plugin manager
|
||||
- Tearing support for better gaming performance
|
||||
- Easily expandable and readable codebase
|
||||
- Fast and active development
|
||||
@@ -128,8 +129,8 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
|
||||
<!----------------------------------{ Images }--------------------------------->
|
||||
|
||||
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
||||
[Preview A]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png
|
||||
[Preview B]: https://i.ibb.co/SX7GbYR/winter-rice.png
|
||||
[Preview A]: https://i.ibb.co/C1yTb0r/falf.png
|
||||
[Preview B]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png
|
||||
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
|
||||
|
||||
|
||||
|
@@ -19,8 +19,14 @@ monitor=,preferred,auto,auto
|
||||
# Source a file (multi-file configs)
|
||||
# source = ~/.config/hypr/myColors.conf
|
||||
|
||||
# Set programs that you use
|
||||
$terminal = kitty
|
||||
$fileManager = dolphin
|
||||
$menu = wofi --show drun
|
||||
|
||||
# Some default env vars.
|
||||
env = XCURSOR_SIZE,24
|
||||
env = QT_QPA_PLATFORMTHEME,qt5ct # change to qt6ct if you have that
|
||||
|
||||
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
||||
input {
|
||||
@@ -120,18 +126,19 @@ 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.
|
||||
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||
$mainMod = SUPER
|
||||
|
||||
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
||||
bind = $mainMod, Q, exec, kitty
|
||||
bind = $mainMod, Q, exec, $terminal
|
||||
bind = $mainMod, C, killactive,
|
||||
bind = $mainMod, M, exit,
|
||||
bind = $mainMod, E, exec, dolphin
|
||||
bind = $mainMod, E, exec, $fileManager
|
||||
bind = $mainMod, V, togglefloating,
|
||||
bind = $mainMod, R, exec, wofi --show drun
|
||||
bind = $mainMod, R, exec, $menu
|
||||
bind = $mainMod, P, pseudo, # dwindle
|
||||
bind = $mainMod, J, togglesplit, # dwindle
|
||||
|
||||
|
20
flake.lock
generated
20
flake.lock
generated
@@ -25,11 +25,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1698134075,
|
||||
"narHash": "sha256-foCD+nuKzfh49bIoiCBur4+Fx1nozo+4C/6k8BYk4sg=",
|
||||
"lastModified": 1703438236,
|
||||
"narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "8efd5d1e283604f75a808a20e6cde0ef313d07d4",
|
||||
"rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -67,18 +67,18 @@
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"lastModified": 1699292815,
|
||||
"narHash": "sha256-HXu98PyBMKEWLqiTb8viuLDznud/SdkdJsx5A5CWx7I=",
|
||||
"lastModified": 1701368958,
|
||||
"narHash": "sha256-7kvyoA91etzVEl9mkA/EJfB6z/PltxX7Xc4gcr7/xlo=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1",
|
||||
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1",
|
||||
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
@@ -95,11 +95,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1697981233,
|
||||
"narHash": "sha256-y8q4XUwx+gVK7i2eLjfR32lVo7TYvEslyzrmzYEaPZU=",
|
||||
"lastModified": 1703514399,
|
||||
"narHash": "sha256-VRr5Xc4S/VPr/gU3fiOD3vSIL2+GJ+LUrmFTWTwnTz4=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "22e7a65ff9633e1dedfa5317fdffc49f68de2ff2",
|
||||
"rev": "0a318a7a217a6402b0b705837cd5b50b0e94b31b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
30
flake.nix
30
flake.nix
@@ -12,7 +12,7 @@
|
||||
host = "gitlab.freedesktop.org";
|
||||
owner = "wlroots";
|
||||
repo = "wlroots";
|
||||
rev = "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1";
|
||||
rev = "5d639394f3e83b01596dcd166a44a9a1a2583350";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
@@ -62,13 +62,16 @@
|
||||
inherit
|
||||
(pkgsFor.${system})
|
||||
# hyprland-packages
|
||||
|
||||
hyprland
|
||||
hyprland-unwrapped
|
||||
hyprland-debug
|
||||
hyprland-nvidia
|
||||
hyprland-legacy-renderer
|
||||
# hyprland-extras
|
||||
|
||||
xdg-desktop-portal-hyprland
|
||||
# dependencies
|
||||
|
||||
hyprland-protocols
|
||||
wlroots-hyprland
|
||||
udis86
|
||||
@@ -76,17 +79,18 @@
|
||||
});
|
||||
|
||||
devShells = eachSystem (system: {
|
||||
default = pkgsFor.${system}.mkShell.override {
|
||||
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
||||
} {
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
|
||||
buildInputs = [self.packages.${system}.wlroots-hyprland];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
self.packages.${system}.hyprland
|
||||
];
|
||||
};
|
||||
default =
|
||||
pkgsFor.${system}.mkShell.override {
|
||||
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
||||
} {
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
|
||||
buildInputs = [self.packages.${system}.wlroots-hyprland];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
self.packages.${system}.hyprland
|
||||
];
|
||||
};
|
||||
});
|
||||
|
||||
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
all:
|
||||
$(CXX) -std=c++2b ./main.cpp -o ./hyprctl
|
||||
$(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl
|
||||
clean:
|
||||
rm ./hyprctl
|
||||
|
@@ -26,32 +26,34 @@
|
||||
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
|
||||
|
||||
commands:
|
||||
monitors
|
||||
workspaces
|
||||
activeworkspace
|
||||
workspacerules
|
||||
clients
|
||||
activewindow
|
||||
layers
|
||||
devices
|
||||
activeworkspace
|
||||
binds
|
||||
clients
|
||||
cursorpos
|
||||
decorations
|
||||
devices
|
||||
dispatch
|
||||
keyword
|
||||
version
|
||||
kill
|
||||
splash
|
||||
getoption
|
||||
globalshortcuts
|
||||
hyprpaper
|
||||
instances
|
||||
keyword
|
||||
kill
|
||||
layers
|
||||
layouts
|
||||
monitors
|
||||
notify
|
||||
plugin
|
||||
reload
|
||||
setcursor
|
||||
getoption
|
||||
cursorpos
|
||||
switchxkblayout
|
||||
seterror
|
||||
setprop
|
||||
plugin
|
||||
notify
|
||||
globalshortcuts
|
||||
instances
|
||||
splash
|
||||
switchxkblayout
|
||||
version
|
||||
workspacerules
|
||||
workspaces
|
||||
|
||||
flags:
|
||||
-j -> output in JSON
|
||||
@@ -329,6 +331,12 @@ int main(int argc, char** argv) {
|
||||
|
||||
fullRequest = fullArgs + "/" + fullRequest;
|
||||
|
||||
// instances is HIS-independent
|
||||
if (fullRequest.contains("/instances")) {
|
||||
instancesRequest(json);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (overrideInstance.contains("_"))
|
||||
instanceSignature = overrideInstance;
|
||||
else if (!overrideInstance.empty()) {
|
||||
@@ -396,8 +404,8 @@ int main(int argc, char** argv) {
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/globalshortcuts"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/instances"))
|
||||
instancesRequest(json);
|
||||
else if (fullRequest.contains("/rollinglog"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/switchxkblayout"))
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/seterror"))
|
||||
@@ -416,8 +424,12 @@ int main(int argc, char** argv) {
|
||||
request(fullRequest, 1);
|
||||
else if (fullRequest.contains("/keyword"))
|
||||
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 {
|
||||
|
16
hyprpm/CMakeLists.txt
Normal file
16
hyprpm/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
project(
|
||||
hyprpm
|
||||
DESCRIPTION "A Hyprland Plugin Manager"
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus)
|
||||
|
||||
add_executable(hyprpm ${SRCFILES})
|
||||
|
||||
target_link_libraries(hyprpm PUBLIC PkgConfig::tomlplusplus)
|
215
hyprpm/src/core/DataState.cpp
Normal file
215
hyprpm/src/core/DataState.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
#include "DataState.hpp"
|
||||
#include <toml++/toml.hpp>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include "PluginManager.hpp"
|
||||
|
||||
std::string DataState::getDataStatePath() {
|
||||
const auto HOME = getenv("HOME");
|
||||
if (!HOME) {
|
||||
std::cerr << "DataState: no $HOME\n";
|
||||
throw std::runtime_error("no $HOME");
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME");
|
||||
|
||||
if (XDG_DATA_HOME)
|
||||
return std::string{XDG_DATA_HOME} + "/hyprpm";
|
||||
return std::string{HOME} + "/.local/share/hyprpm";
|
||||
}
|
||||
|
||||
void DataState::ensureStateStoreExists() {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
if (!std::filesystem::exists(PATH))
|
||||
std::filesystem::create_directories(PATH);
|
||||
}
|
||||
|
||||
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath() + "/" + repo.name;
|
||||
|
||||
std::filesystem::create_directories(PATH);
|
||||
// clang-format off
|
||||
auto DATA = toml::table{
|
||||
{"repository", toml::table{
|
||||
{"name", repo.name},
|
||||
{"hash", repo.hash},
|
||||
{"url", repo.url}
|
||||
}}
|
||||
};
|
||||
for (auto& p : repo.plugins) {
|
||||
// copy .so to the good place
|
||||
std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so");
|
||||
|
||||
DATA.emplace(p.name, toml::table{
|
||||
{"filename", p.name + ".so"},
|
||||
{"enabled", p.enabled}
|
||||
});
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
|
||||
ofs << DATA;
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
bool DataState::pluginRepoExists(const std::string& urlOrName) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
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("");
|
||||
|
||||
if (URL == urlOrName || NAME == urlOrName)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DataState::removePluginRepo(const std::string& urlOrName) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
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("");
|
||||
|
||||
if (URL == urlOrName || NAME == urlOrName) {
|
||||
|
||||
// unload the plugins!!
|
||||
for (const auto& file : std::filesystem::directory_iterator(entry.path())) {
|
||||
if (!file.path().string().ends_with(".so"))
|
||||
continue;
|
||||
|
||||
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
|
||||
}
|
||||
|
||||
std::filesystem::remove_all(entry.path());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DataState::updateGlobalState(const SGlobalState& state) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
std::filesystem::create_directories(PATH);
|
||||
// clang-format off
|
||||
auto DATA = toml::table{
|
||||
{"state", toml::table{
|
||||
{"hash", state.headersHashCompiled},
|
||||
{"dont_warn_install", state.dontWarnInstall}
|
||||
}}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
|
||||
ofs << DATA;
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
SGlobalState DataState::getGlobalState() {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
if (!std::filesystem::exists(PATH + "/state.toml"))
|
||||
return SGlobalState{};
|
||||
|
||||
auto DATA = toml::parse_file(PATH + "/state.toml");
|
||||
|
||||
SGlobalState state;
|
||||
state.headersHashCompiled = DATA["state"]["hash"].value_or("");
|
||||
state.dontWarnInstall = DATA["state"]["dont_warn_install"].value_or(false);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
std::vector<SPluginRepository> DataState::getAllRepositories() {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
std::vector<SPluginRepository> repos;
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
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 HASH = STATE["repository"]["hash"].value_or("");
|
||||
|
||||
SPluginRepository repo;
|
||||
repo.hash = HASH;
|
||||
repo.name = NAME;
|
||||
repo.url = URL;
|
||||
|
||||
for (const auto& [key, val] : STATE) {
|
||||
if (key == "repository")
|
||||
continue;
|
||||
|
||||
const auto ENABLED = STATE[key]["enabled"].value_or(false);
|
||||
const auto FILENAME = STATE[key]["filename"].value_or("");
|
||||
|
||||
repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED});
|
||||
}
|
||||
|
||||
repos.push_back(repo);
|
||||
}
|
||||
|
||||
return repos;
|
||||
}
|
||||
|
||||
bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
|
||||
for (const auto& [key, val] : STATE) {
|
||||
if (key == "repository")
|
||||
continue;
|
||||
|
||||
if (key.str() != name)
|
||||
continue;
|
||||
|
||||
(*STATE[key].as_table()).insert_or_assign("enabled", enabled);
|
||||
|
||||
std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
|
||||
state << STATE;
|
||||
state.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
21
hyprpm/src/core/DataState.hpp
Normal file
21
hyprpm/src/core/DataState.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Plugin.hpp"
|
||||
|
||||
struct SGlobalState {
|
||||
std::string headersHashCompiled = "";
|
||||
bool dontWarnInstall = false;
|
||||
};
|
||||
|
||||
namespace DataState {
|
||||
std::string getDataStatePath();
|
||||
void ensureStateStoreExists();
|
||||
void addNewPluginRepo(const SPluginRepository& repo);
|
||||
void removePluginRepo(const std::string& urlOrName);
|
||||
bool pluginRepoExists(const std::string& urlOrName);
|
||||
void updateGlobalState(const SGlobalState& state);
|
||||
SGlobalState getGlobalState();
|
||||
bool setPluginEnabled(const std::string& name, bool enabled);
|
||||
std::vector<SPluginRepository> getAllRepositories();
|
||||
};
|
104
hyprpm/src/core/Manifest.cpp
Normal file
104
hyprpm/src/core/Manifest.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "Manifest.hpp"
|
||||
#include <toml++/toml.hpp>
|
||||
#include <iostream>
|
||||
|
||||
CManifest::CManifest(const eManifestType type, const std::string& path) {
|
||||
auto manifest = toml::parse_file(path);
|
||||
|
||||
if (type == MANIFEST_HYPRLOAD) {
|
||||
for (auto& [key, val] : manifest) {
|
||||
if (key.str().ends_with(".build"))
|
||||
continue;
|
||||
|
||||
CManifest::SManifestPlugin plugin;
|
||||
plugin.name = key;
|
||||
m_vPlugins.push_back(plugin);
|
||||
}
|
||||
|
||||
for (auto& plugin : m_vPlugins) {
|
||||
plugin.description = manifest[plugin.name]["description"].value_or("?");
|
||||
plugin.version = manifest[plugin.name]["version"].value_or("?");
|
||||
plugin.output = manifest[plugin.name]["build"]["output"].value_or("?");
|
||||
auto authors = manifest[plugin.name]["authors"].as_array();
|
||||
if (authors) {
|
||||
for (auto&& a : *authors) {
|
||||
plugin.authors.push_back(a.as_string()->value_or("?"));
|
||||
}
|
||||
} else {
|
||||
auto author = manifest[plugin.name]["author"].value_or("");
|
||||
if (!std::string{author}.empty())
|
||||
plugin.authors.push_back(author);
|
||||
}
|
||||
auto buildSteps = manifest[plugin.name]["build"]["steps"].as_array();
|
||||
if (buildSteps) {
|
||||
for (auto&& s : *buildSteps) {
|
||||
plugin.buildSteps.push_back(s.as_string()->value_or("?"));
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin.output.empty() || plugin.buildSteps.empty()) {
|
||||
m_bGood = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (type == MANIFEST_HYPRPM) {
|
||||
m_sRepository.name = manifest["repository"]["name"].value_or("");
|
||||
auto authors = manifest["repository"]["authors"].as_array();
|
||||
if (authors) {
|
||||
for (auto&& a : *authors) {
|
||||
m_sRepository.authors.push_back(a.as_string()->value_or("?"));
|
||||
}
|
||||
} else {
|
||||
auto author = manifest["repository"]["author"].value_or("");
|
||||
if (!std::string{author}.empty())
|
||||
m_sRepository.authors.push_back(author);
|
||||
}
|
||||
|
||||
auto pins = manifest["repository"]["commit_pins"].as_array();
|
||||
if (pins) {
|
||||
for (auto&& pin : *pins) {
|
||||
auto pinArr = pin.as_array();
|
||||
if (pinArr && pinArr->get(1))
|
||||
m_sRepository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get()));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [key, val] : manifest) {
|
||||
if (key.str() == "repository")
|
||||
continue;
|
||||
|
||||
CManifest::SManifestPlugin plugin;
|
||||
plugin.name = key;
|
||||
m_vPlugins.push_back(plugin);
|
||||
}
|
||||
|
||||
for (auto& plugin : m_vPlugins) {
|
||||
plugin.description = manifest[plugin.name]["description"].value_or("?");
|
||||
plugin.output = manifest[plugin.name]["output"].value_or("?");
|
||||
auto authors = manifest[plugin.name]["authors"].as_array();
|
||||
if (authors) {
|
||||
for (auto&& a : *authors) {
|
||||
plugin.authors.push_back(a.as_string()->value_or("?"));
|
||||
}
|
||||
} else {
|
||||
auto author = manifest[plugin.name]["author"].value_or("");
|
||||
if (!std::string{author}.empty())
|
||||
plugin.authors.push_back(author);
|
||||
}
|
||||
auto buildSteps = manifest[plugin.name]["build"].as_array();
|
||||
if (buildSteps) {
|
||||
for (auto&& s : *buildSteps) {
|
||||
plugin.buildSteps.push_back(s.as_string()->value_or("?"));
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin.output.empty() || plugin.buildSteps.empty()) {
|
||||
m_bGood = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ???
|
||||
m_bGood = false;
|
||||
}
|
||||
}
|
32
hyprpm/src/core/Manifest.hpp
Normal file
32
hyprpm/src/core/Manifest.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
enum eManifestType {
|
||||
MANIFEST_HYPRLOAD,
|
||||
MANIFEST_HYPRPM
|
||||
};
|
||||
|
||||
class CManifest {
|
||||
public:
|
||||
CManifest(const eManifestType type, const std::string& path);
|
||||
|
||||
struct SManifestPlugin {
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string version;
|
||||
std::vector<std::string> authors;
|
||||
std::vector<std::string> buildSteps;
|
||||
std::string output;
|
||||
};
|
||||
|
||||
struct {
|
||||
std::string name;
|
||||
std::vector<std::string> authors;
|
||||
std::vector<std::pair<std::string, std::string>> commitPins;
|
||||
} m_sRepository;
|
||||
|
||||
std::vector<SManifestPlugin> m_vPlugins;
|
||||
bool m_bGood = true;
|
||||
};
|
17
hyprpm/src/core/Plugin.hpp
Normal file
17
hyprpm/src/core/Plugin.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct SPlugin {
|
||||
std::string name;
|
||||
std::string filename;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct SPluginRepository {
|
||||
std::string url;
|
||||
std::string name;
|
||||
std::vector<SPlugin> plugins;
|
||||
std::string hash;
|
||||
};
|
724
hyprpm/src/core/PluginManager.cpp
Normal file
724
hyprpm/src/core/PluginManager.cpp
Normal file
@@ -0,0 +1,724 @@
|
||||
#include "PluginManager.hpp"
|
||||
#include "../helpers/Colors.hpp"
|
||||
#include "../progress/CProgressBar.hpp"
|
||||
#include "Manifest.hpp"
|
||||
#include "DataState.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <toml++/toml.hpp>
|
||||
|
||||
static std::string removeBeginEndSpacesTabs(std::string str) {
|
||||
if (str.empty())
|
||||
return str;
|
||||
|
||||
int countBefore = 0;
|
||||
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
|
||||
countBefore++;
|
||||
}
|
||||
|
||||
int countAfter = 0;
|
||||
while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
|
||||
countAfter++;
|
||||
}
|
||||
|
||||
str = str.substr(countBefore, str.length() - countBefore - countAfter);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::string execAndGet(std::string cmd) {
|
||||
cmd += " 2>&1";
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||
if (!pipe)
|
||||
return "";
|
||||
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
result += buffer.data();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SHyprlandVersion CPluginManager::getHyprlandVersion() {
|
||||
static SHyprlandVersion ver;
|
||||
static bool once = false;
|
||||
|
||||
if (once)
|
||||
return ver;
|
||||
|
||||
once = true;
|
||||
const auto HLVERCALL = execAndGet("hyprctl version");
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "version returned: " << HLVERCALL << "\n";
|
||||
|
||||
if (!HLVERCALL.contains("Tag:")) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " You don't seem to be running Hyprland.";
|
||||
return SHyprlandVersion{};
|
||||
}
|
||||
|
||||
std::string hlcommit = HLVERCALL.substr(HLVERCALL.find("at commit") + 10);
|
||||
hlcommit = hlcommit.substr(0, hlcommit.find_first_of(' '));
|
||||
|
||||
std::string hlbranch = HLVERCALL.substr(HLVERCALL.find("from branch") + 12);
|
||||
hlbranch = hlbranch.substr(0, hlbranch.find(" at commit "));
|
||||
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << "\n";
|
||||
|
||||
ver = SHyprlandVersion{hlbranch, hlcommit};
|
||||
return ver;
|
||||
}
|
||||
|
||||
bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
|
||||
if (DataState::pluginRepoExists(url)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
if (!GLOBALSTATE.dontWarnInstall) {
|
||||
std::cout << Colors::YELLOW << "!" << Colors::RED << " Disclaimer:\n " << Colors::RESET
|
||||
<< "plugins, especially not official, have no guarantee of stability, availablity or security.\n Run them at your own risk.\n "
|
||||
<< "This message will not appear again.\n";
|
||||
GLOBALSTATE.dontWarnInstall = true;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
}
|
||||
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << Colors::RED << " adding a new plugin repository " << Colors::RESET << "from " << url << "\n " << Colors::RED
|
||||
<< "MAKE SURE" << Colors::RESET << " that you trust the authors. " << Colors::RED << "DO NOT" << Colors::RESET
|
||||
<< " install random plugins without verifying the code and author.\n "
|
||||
<< "Are you sure? [Y/n] ";
|
||||
std::fflush(stdout);
|
||||
std::string input;
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
|
||||
std::cout << "Aborting.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
CProgressBar progress;
|
||||
progress.m_iMaxSteps = 5;
|
||||
progress.m_iSteps = 0;
|
||||
progress.m_szCurrentMessage = "Cloning the plugin repository";
|
||||
|
||||
progress.print();
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm")) {
|
||||
std::filesystem::create_directory("/tmp/hyprpm");
|
||||
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/new")) {
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " old plugin repo build files found in temp directory, removing.");
|
||||
std::filesystem::remove_all("/tmp/hyprpm/new");
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + url);
|
||||
|
||||
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " new");
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/new")) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. 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";
|
||||
progress.print();
|
||||
|
||||
std::unique_ptr<CManifest> pManifest;
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/new/hyprpm.toml")) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, "/tmp/hyprpm/new/hyprpm.toml");
|
||||
} else if (std::filesystem::exists("/tmp/hyprpm/new/hyprload.toml")) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, "/tmp/hyprpm/new/hyprload.toml");
|
||||
}
|
||||
|
||||
if (!pManifest) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pManifest->m_bGood) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.m_iSteps = 2;
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:");
|
||||
for (auto& pl : pManifest->m_vPlugins) {
|
||||
std::string message = std::string{Colors::RESET} + " → " + pl.name + " by ";
|
||||
for (auto& a : pl.authors) {
|
||||
message += a + ", ";
|
||||
}
|
||||
if (pl.authors.size() > 0) {
|
||||
message.pop_back();
|
||||
message.pop_back();
|
||||
}
|
||||
message += " version " + pl.version;
|
||||
progress.printMessageAbove(message);
|
||||
}
|
||||
progress.m_szCurrentMessage = "Verifying headers";
|
||||
progress.print();
|
||||
|
||||
const auto HEADERSSTATUS = headersValid();
|
||||
|
||||
if (HEADERSSTATUS != HEADERS_OK) {
|
||||
std::cerr << "\n" << headerError(HEADERSSTATUS);
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.m_iSteps = 3;
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " Hyprland headers OK");
|
||||
progress.m_szCurrentMessage = "Building plugin(s)";
|
||||
progress.print();
|
||||
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
std::string out;
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto& bs : p.buildSteps) {
|
||||
out += execAndGet("cd /tmp/hyprpm/new && " + bs) + "\n";
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) {
|
||||
std::cerr << "\n" << 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;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output);
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " all plugins built");
|
||||
progress.m_iSteps = 4;
|
||||
progress.m_szCurrentMessage = "Installing repository";
|
||||
progress.print();
|
||||
|
||||
// add repo toml to DataState
|
||||
SPluginRepository repo;
|
||||
std::string repohash = execAndGet("cd /tmp/hyprpm/new/ && git rev-parse HEAD");
|
||||
if (repohash.length() > 0)
|
||||
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.hash = repohash;
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false});
|
||||
}
|
||||
DataState::addNewPluginRepo(repo);
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed repository");
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " you can now enable the plugin(s) with hyprpm enable");
|
||||
progress.m_iSteps = 5;
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
// remove build files
|
||||
std::filesystem::remove_all("/tmp/hyprpm/new");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
|
||||
if (!DataState::pluginRepoExists(urlOrName)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not remove the repository. Repository is not installed.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << Colors::YELLOW << "!" << Colors::RESET << Colors::RED << " removing a plugin repository: " << Colors::RESET << urlOrName << "\n "
|
||||
<< "Are you sure? [Y/n] ";
|
||||
std::fflush(stdout);
|
||||
std::string input;
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
|
||||
std::cout << "Aborting.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
DataState::removePluginRepo(urlOrName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
eHeadersErrors CPluginManager::headersValid() {
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
// find headers commit
|
||||
auto headers = execAndGet("pkg-config --cflags --keep-system-cflags hyprland");
|
||||
|
||||
if (!headers.contains("-I/"))
|
||||
return HEADERS_MISSING;
|
||||
|
||||
headers.pop_back(); // pop newline
|
||||
|
||||
std::string verHeader = "";
|
||||
|
||||
while (!headers.empty()) {
|
||||
const auto PATH = headers.substr(0, headers.find(" -I/", 3));
|
||||
|
||||
if (headers.find(" -I/", 3) != std::string::npos)
|
||||
headers = headers.substr(headers.find("-I/", 3));
|
||||
else
|
||||
headers = "";
|
||||
|
||||
if (PATH.ends_with("protocols") || PATH.ends_with("wlroots"))
|
||||
continue;
|
||||
|
||||
verHeader = removeBeginEndSpacesTabs(PATH.substr(2)) + "/hyprland/src/version.h";
|
||||
break;
|
||||
}
|
||||
|
||||
if (verHeader.empty())
|
||||
return HEADERS_CORRUPTED;
|
||||
|
||||
// read header
|
||||
std::ifstream ifs(verHeader);
|
||||
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();
|
||||
|
||||
std::string hash = verHeaderContent.substr(verHeaderContent.find("#define GIT_COMMIT_HASH") + 23);
|
||||
hash = hash.substr(0, hash.find_first_of('\n'));
|
||||
hash = hash.substr(hash.find_first_of('"') + 1);
|
||||
hash = hash.substr(0, hash.find_first_of('"'));
|
||||
|
||||
if (hash != HLVER.hash)
|
||||
return HEADERS_MISMATCHED;
|
||||
|
||||
return HEADERS_OK;
|
||||
}
|
||||
|
||||
bool CPluginManager::updateHeaders() {
|
||||
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm")) {
|
||||
std::filesystem::create_directory("/tmp/hyprpm");
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
CProgressBar progress;
|
||||
progress.m_iMaxSteps = 5;
|
||||
progress.m_iSteps = 0;
|
||||
progress.m_szCurrentMessage = "Cloning the hyprland repository";
|
||||
progress.print();
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/hyprland")) {
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " old hyprland source files found in temp directory, removing.");
|
||||
std::filesystem::remove_all("/tmp/hyprpm/hyprland");
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment.");
|
||||
|
||||
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland");
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/hyprland")) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned");
|
||||
progress.m_iSteps = 2;
|
||||
progress.m_szCurrentMessage = "Checking out sources";
|
||||
progress.print();
|
||||
|
||||
ret =
|
||||
execAndGet("cd /tmp/hyprpm/hyprland && git checkout " + HLVER.branch + " 2>&1 && git submodule update --init 2>&1 && git reset --hard --recurse-submodules " + HLVER.hash);
|
||||
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned: " + ret);
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " checked out to running ver");
|
||||
progress.m_iSteps = 3;
|
||||
progress.m_szCurrentMessage = "Building Hyprland";
|
||||
progress.print();
|
||||
|
||||
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");
|
||||
// le hack. Wlroots has to generate its build/include
|
||||
ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots && meson setup -Drenderers=gles2 -Dexamples=false build");
|
||||
|
||||
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.");
|
||||
|
||||
ret = execAndGet("pkexec sh \"-c\" \"cd /tmp/hyprpm/hyprland && make installheaders\"");
|
||||
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "pkexec returned: " << ret << "\n";
|
||||
|
||||
// remove build files
|
||||
std::filesystem::remove_all("/tmp/hyprpm/hyprland");
|
||||
|
||||
auto HEADERSVALID = headersValid();
|
||||
if (HEADERSVALID == HEADERS_OK) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed headers");
|
||||
progress.m_iSteps = 5;
|
||||
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));
|
||||
progress.m_iSteps = 5;
|
||||
progress.m_szCurrentMessage = "Failed";
|
||||
progress.print();
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
std::cerr << "\n" << headerError(HEADERSVALID);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
if (headersValid() != HEADERS_OK) {
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
if (REPOS.size() < 1) {
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " No repos to update.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
CProgressBar progress;
|
||||
progress.m_iMaxSteps = REPOS.size() * 2 + 1;
|
||||
progress.m_iSteps = 0;
|
||||
progress.m_szCurrentMessage = "Updating repositories";
|
||||
progress.print();
|
||||
|
||||
for (auto& repo : REPOS) {
|
||||
bool update = forceUpdateAll;
|
||||
|
||||
progress.m_iSteps++;
|
||||
progress.m_szCurrentMessage = "Updating " + repo.name;
|
||||
progress.print();
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → checking for updates for " + repo.name);
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/update")) {
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " old update build files found in temp directory, removing.");
|
||||
std::filesystem::remove_all("/tmp/hyprpm/update");
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + repo.url);
|
||||
|
||||
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " update");
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/update")) {
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " could not clone repo: 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");
|
||||
if (!hash.empty())
|
||||
hash.pop_back();
|
||||
|
||||
update = update || hash != repo.hash;
|
||||
}
|
||||
|
||||
if (!update) {
|
||||
std::filesystem::remove_all("/tmp/hyprpm/update");
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " is up-to-date.");
|
||||
progress.m_iSteps++;
|
||||
progress.print();
|
||||
continue;
|
||||
}
|
||||
|
||||
// we need to update
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " has updates.");
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + repo.name);
|
||||
progress.m_iSteps++;
|
||||
progress.print();
|
||||
|
||||
std::unique_ptr<CManifest> pManifest;
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/update/hyprpm.toml")) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, "/tmp/hyprpm/update/hyprpm.toml");
|
||||
} else if (std::filesystem::exists("/tmp/hyprpm/update/hyprload.toml")) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, "/tmp/hyprpm/update/hyprload.toml");
|
||||
}
|
||||
|
||||
if (!pManifest) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pManifest->m_bGood) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
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/update/ && git reset --hard --recurse-submodules " + plugin);
|
||||
}
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
std::string out;
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto& bs : p.buildSteps) {
|
||||
out += execAndGet("cd /tmp/hyprpm/update && " + bs) + "\n";
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Plugin " << p.name << " failed to build.\n";
|
||||
failed = true;
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output);
|
||||
}
|
||||
|
||||
if (failed)
|
||||
continue;
|
||||
|
||||
// add repo toml to DataState
|
||||
SPluginRepository newrepo = repo;
|
||||
newrepo.plugins.clear();
|
||||
execAndGet(
|
||||
"cd /tmp/hyprpm/update/ && git pull --recurse-submodules && git reset --hard --recurse-submodules"); // repo hash in the state.toml has to match head and not any pin
|
||||
std::string repohash = execAndGet("cd /tmp/hyprpm/update && git rev-parse HEAD");
|
||||
if (repohash.length() > 0)
|
||||
repohash.pop_back();
|
||||
newrepo.hash = repohash;
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; });
|
||||
newrepo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/update/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false});
|
||||
}
|
||||
DataState::removePluginRepo(newrepo.name);
|
||||
DataState::addNewPluginRepo(newrepo);
|
||||
|
||||
std::filesystem::remove_all("/tmp/hyprpm/update");
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " updated " + repo.name);
|
||||
}
|
||||
|
||||
progress.m_iSteps++;
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::enablePlugin(const std::string& name) {
|
||||
bool ret = DataState::setPluginEnabled(name, true);
|
||||
if (ret)
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Enabled " << name << "\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::disablePlugin(const std::string& name) {
|
||||
bool ret = DataState::setPluginEnabled(name, false);
|
||||
if (ret)
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Disabled " << name << "\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
|
||||
if (headersValid() != HEADERS_OK) {
|
||||
std::cerr << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
|
||||
return LOADSTATE_HEADERS_OUTDATED;
|
||||
}
|
||||
|
||||
const auto HOME = getenv("HOME");
|
||||
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
if (!HOME || !HIS) {
|
||||
std::cerr << "PluginManager: no $HOME or HIS\n";
|
||||
return LOADSTATE_FAIL;
|
||||
}
|
||||
const auto HYPRPMPATH = DataState::getDataStatePath() + "/";
|
||||
|
||||
auto pluginLines = execAndGet("hyprctl plugins list | grep Plugin");
|
||||
|
||||
std::vector<std::string> loadedPlugins;
|
||||
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Ensuring plugin load state\n";
|
||||
|
||||
// iterate line by line
|
||||
while (!pluginLines.empty()) {
|
||||
auto plLine = pluginLines.substr(0, pluginLines.find("\n"));
|
||||
|
||||
if (pluginLines.find("\n") != std::string::npos)
|
||||
pluginLines = pluginLines.substr(pluginLines.find("\n") + 1);
|
||||
else
|
||||
pluginLines = "";
|
||||
|
||||
if (plLine.back() != ':')
|
||||
continue;
|
||||
|
||||
plLine = plLine.substr(7);
|
||||
plLine = plLine.substr(0, plLine.find(" by "));
|
||||
|
||||
loadedPlugins.push_back(plLine);
|
||||
}
|
||||
|
||||
// get state
|
||||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
auto enabled = [REPOS](const std::string& plugin) -> bool {
|
||||
for (auto& r : REPOS) {
|
||||
for (auto& p : r.plugins) {
|
||||
if (p.name == plugin && p.enabled)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto repoForName = [REPOS](const std::string& name) -> std::string {
|
||||
for (auto& r : REPOS) {
|
||||
for (auto& p : r.plugins) {
|
||||
if (p.name == name)
|
||||
return r.name;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
// unload disabled plugins
|
||||
for (auto& p : loadedPlugins) {
|
||||
if (!enabled(p)) {
|
||||
// unload
|
||||
loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false);
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Unloaded " << p << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// load enabled plugins
|
||||
for (auto& r : REPOS) {
|
||||
for (auto& p : r.plugins) {
|
||||
if (!p.enabled)
|
||||
continue;
|
||||
|
||||
if (std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end())
|
||||
continue;
|
||||
|
||||
loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true);
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Loaded " << p.name << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Plugin load state ensured\n";
|
||||
|
||||
return LOADSTATE_OK;
|
||||
}
|
||||
|
||||
bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
|
||||
if (load)
|
||||
execAndGet("hyprctl plugin load " + path);
|
||||
else
|
||||
execAndGet("hyprctl plugin unload " + path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPluginManager::listAllPlugins() {
|
||||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
for (auto& r : REPOS) {
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message) {
|
||||
execAndGet("hyprctl notify " + std::to_string((int)icon) + " " + std::to_string(durationMs) + " " + std::to_string(color) + " " + message);
|
||||
}
|
||||
|
||||
std::string CPluginManager::headerError(const eHeadersErrors err) {
|
||||
switch (err) {
|
||||
case HEADERS_CORRUPTED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers corrupted. Please run hyprpm update to fix those.\n";
|
||||
case HEADERS_MISMATCHED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers version mismatch. Please run hyprpm update to fix those.\n";
|
||||
case HEADERS_NOT_HYPRLAND: return std::string{Colors::RED} + "✖" + Colors::RESET + " It doesn't seem you are running on hyprland.\n";
|
||||
case HEADERS_MISSING: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers missing. Please run hyprpm update to fix those.\n";
|
||||
case HEADERS_DUPLICATED: {
|
||||
return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers duplicated!!! This is a very bad sign.\n" +
|
||||
" This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" +
|
||||
" If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n";
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return std::string{Colors::RED} + "✖" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n";
|
||||
}
|
63
hyprpm/src/core/PluginManager.hpp
Normal file
63
hyprpm/src/core/PluginManager.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
enum eHeadersErrors {
|
||||
HEADERS_OK = 0,
|
||||
HEADERS_NOT_HYPRLAND,
|
||||
HEADERS_MISSING,
|
||||
HEADERS_CORRUPTED,
|
||||
HEADERS_MISMATCHED,
|
||||
HEADERS_DUPLICATED
|
||||
};
|
||||
|
||||
enum eNotifyIcons {
|
||||
ICON_WARNING = 0,
|
||||
ICON_INFO,
|
||||
ICON_HINT,
|
||||
ICON_ERROR,
|
||||
ICON_CONFUSED,
|
||||
ICON_OK,
|
||||
ICON_NONE
|
||||
};
|
||||
|
||||
enum ePluginLoadStateReturn {
|
||||
LOADSTATE_OK = 0,
|
||||
LOADSTATE_FAIL,
|
||||
LOADSTATE_PARTIAL_FAIL,
|
||||
LOADSTATE_HEADERS_OUTDATED
|
||||
};
|
||||
|
||||
struct SHyprlandVersion {
|
||||
std::string branch;
|
||||
std::string hash;
|
||||
};
|
||||
|
||||
class CPluginManager {
|
||||
public:
|
||||
bool addNewPluginRepo(const std::string& url);
|
||||
bool removePluginRepo(const std::string& urlOrName);
|
||||
|
||||
eHeadersErrors headersValid();
|
||||
bool updateHeaders();
|
||||
bool updatePlugins(bool forceUpdateAll);
|
||||
|
||||
void listAllPlugins();
|
||||
|
||||
bool enablePlugin(const std::string& name);
|
||||
bool disablePlugin(const std::string& name);
|
||||
ePluginLoadStateReturn ensurePluginsLoadState();
|
||||
|
||||
bool loadUnloadPlugin(const std::string& path, bool load);
|
||||
SHyprlandVersion getHyprlandVersion();
|
||||
|
||||
void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message);
|
||||
|
||||
bool m_bVerbose = false;
|
||||
|
||||
private:
|
||||
std::string headerError(const eHeadersErrors err);
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CPluginManager> g_pPluginManager;
|
11
hyprpm/src/helpers/Colors.hpp
Normal file
11
hyprpm/src/helpers/Colors.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace Colors {
|
||||
constexpr const char* RED = "\x1b[31m";
|
||||
constexpr const char* GREEN = "\x1b[32m";
|
||||
constexpr const char* YELLOW = "\x1b[33m";
|
||||
constexpr const char* BLUE = "\x1b[34m";
|
||||
constexpr const char* MAGENTA = "\x1b[35m";
|
||||
constexpr const char* CYAN = "\x1b[36m";
|
||||
constexpr const char* RESET = "\x1b[0m";
|
||||
};
|
149
hyprpm/src/main.cpp
Normal file
149
hyprpm/src/main.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "progress/CProgressBar.hpp"
|
||||
#include "helpers/Colors.hpp"
|
||||
#include "core/PluginManager.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
┃
|
||||
┣ add [url] → Install a new plugin repository from git
|
||||
┣ remove [url/name] → Remove an installed plugin repository
|
||||
┣ enable [name] → Enable a plugin
|
||||
┣ disable [name] → Disable a plugin
|
||||
┣ update → Check and update all plugins if needed
|
||||
┣ reload → Reload hyprpm state. Ensure all enabled plugins are loaded.
|
||||
┣ list → List all installed plugins
|
||||
┃
|
||||
┣ Flags:
|
||||
┃
|
||||
┣ --notify | -n → Send a hyprland notification for important events (e.g. load fail)
|
||||
┣ --help | -h → Show this menu
|
||||
┣ --verbose | -v → Enable too much logging
|
||||
┗
|
||||
)#";
|
||||
|
||||
int main(int argc, char** argv, char** envp) {
|
||||
std::vector<std::string> ARGS{argc};
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
ARGS[i] = std::string{argv[i]};
|
||||
}
|
||||
|
||||
if (ARGS.size() < 2) {
|
||||
std::cout << HELP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<std::string> command;
|
||||
bool notify = false, verbose = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (ARGS[i].starts_with("-")) {
|
||||
if (ARGS[i] == "--help" || ARGS[i] == "-h") {
|
||||
std::cout << HELP;
|
||||
return 0;
|
||||
} else if (ARGS[i] == "--notify" || ARGS[i] == "-n") {
|
||||
notify = true;
|
||||
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
|
||||
verbose = true;
|
||||
} else {
|
||||
std::cerr << "Unrecognized option " << ARGS[i];
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
command.push_back(ARGS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (command.empty()) {
|
||||
std::cout << HELP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_pPluginManager = std::make_unique<CPluginManager>();
|
||||
g_pPluginManager->m_bVerbose = verbose;
|
||||
|
||||
if (command[0] == "add") {
|
||||
if (command.size() < 2) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for add.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
return g_pPluginManager->addNewPluginRepo(command[1]) ? 0 : 1;
|
||||
} else if (command[0] == "remove") {
|
||||
if (ARGS.size() < 2) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for remove.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
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();
|
||||
if (headers) {
|
||||
bool ret1 = g_pPluginManager->updatePlugins(!headersValid);
|
||||
|
||||
if (!ret1)
|
||||
return 1;
|
||||
|
||||
auto ret2 = g_pPluginManager->ensurePluginsLoadState();
|
||||
|
||||
if (ret2 != LOADSTATE_OK)
|
||||
return 1;
|
||||
} else if (notify)
|
||||
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers");
|
||||
} else if (command[0] == "enable") {
|
||||
if (ARGS.size() < 2) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for enable.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!g_pPluginManager->enablePlugin(command[1])) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't enable plugin (missing?)\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||
if (ret != LOADSTATE_OK)
|
||||
return 1;
|
||||
} else if (command[0] == "disable") {
|
||||
if (command.size() < 2) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for disable.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!g_pPluginManager->disablePlugin(command[1])) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't disable plugin (missing?)\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||
if (ret != LOADSTATE_OK)
|
||||
return 1;
|
||||
} else if (command[0] == "reload") {
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||
|
||||
if (ret != LOADSTATE_OK && notify) {
|
||||
switch (ret) {
|
||||
case LOADSTATE_FAIL:
|
||||
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
|
||||
case LOADSTATE_HEADERS_OUTDATED:
|
||||
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually.");
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else if (notify) {
|
||||
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
|
||||
}
|
||||
} else if (command[0] == "list") {
|
||||
g_pPluginManager->listAllPlugins();
|
||||
} else {
|
||||
std::cout << HELP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
10
hyprpm/src/meson.build
Normal file
10
hyprpm/src/meson.build
Normal file
@@ -0,0 +1,10 @@
|
||||
globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
|
||||
src = globber.stdout().strip().split('\n')
|
||||
|
||||
executable('hyprpm', src,
|
||||
dependencies: [
|
||||
dependency('threads'),
|
||||
dependency('tomlplusplus')
|
||||
],
|
||||
install : true
|
||||
)
|
80
hyprpm/src/progress/CProgressBar.cpp
Normal file
80
hyprpm/src/progress/CProgressBar.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include "CProgressBar.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../helpers/Colors.hpp"
|
||||
|
||||
void CProgressBar::printMessageAbove(const std::string& msg) {
|
||||
struct winsize w;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
|
||||
std::string spaces;
|
||||
for (size_t i = 0; i < w.ws_col; ++i) {
|
||||
spaces += ' ';
|
||||
}
|
||||
|
||||
std::cout << "\r" << spaces << "\r" << msg << "\n";
|
||||
print();
|
||||
}
|
||||
|
||||
void CProgressBar::print() {
|
||||
struct winsize w;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
|
||||
if (m_bFirstPrint)
|
||||
std::cout << "\n";
|
||||
m_bFirstPrint = false;
|
||||
|
||||
std::string spaces;
|
||||
for (size_t i = 0; i < w.ws_col; ++i) {
|
||||
spaces += ' ';
|
||||
}
|
||||
|
||||
std::cout << "\r" << spaces << "\r";
|
||||
|
||||
std::string message = "";
|
||||
|
||||
float percentDone = 0;
|
||||
if (m_fPercentage >= 0)
|
||||
percentDone = m_fPercentage;
|
||||
else
|
||||
percentDone = (float)m_iSteps / (float)m_iMaxSteps;
|
||||
|
||||
const auto BARWIDTH = std::clamp(w.ws_col - static_cast<unsigned long>(m_szCurrentMessage.length()) - 2, 0UL, 50UL);
|
||||
|
||||
// draw bar
|
||||
message += std::string{" "} + Colors::GREEN;
|
||||
size_t i = 0;
|
||||
for (; i < std::floor(percentDone * BARWIDTH); ++i) {
|
||||
message += "━";
|
||||
}
|
||||
|
||||
if (i < BARWIDTH) {
|
||||
i++;
|
||||
|
||||
message += std::string{"╍"} + Colors::RESET;
|
||||
|
||||
for (; i < BARWIDTH; ++i) {
|
||||
message += "━";
|
||||
}
|
||||
} else
|
||||
message += Colors::RESET;
|
||||
|
||||
// draw progress
|
||||
if (m_fPercentage >= 0)
|
||||
message += " " + std::format("{}%", static_cast<int>(percentDone * 100.0)) + " ";
|
||||
else
|
||||
message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " ";
|
||||
|
||||
// draw message
|
||||
std::cout << message + " " + m_szCurrentMessage;
|
||||
|
||||
std::fflush(stdout);
|
||||
}
|
17
hyprpm/src/progress/CProgressBar.hpp
Normal file
17
hyprpm/src/progress/CProgressBar.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class CProgressBar {
|
||||
public:
|
||||
void print();
|
||||
void printMessageAbove(const std::string& msg);
|
||||
|
||||
std::string m_szCurrentMessage = "";
|
||||
size_t m_iSteps = 0;
|
||||
size_t m_iMaxSteps = 0;
|
||||
float m_fPercentage = -1; // if != -1, use percentage
|
||||
|
||||
private:
|
||||
bool m_bFirstPrint = true;
|
||||
};
|
@@ -80,6 +80,7 @@ endforeach
|
||||
subdir('protocols')
|
||||
subdir('src')
|
||||
subdir('hyprctl')
|
||||
subdir('hyprpm/src')
|
||||
subdir('assets')
|
||||
subdir('example')
|
||||
subdir('docs')
|
||||
|
@@ -10,6 +10,7 @@
|
||||
git,
|
||||
hyprland-protocols,
|
||||
jq,
|
||||
libGL,
|
||||
libdrm,
|
||||
libinput,
|
||||
libxcb,
|
||||
@@ -18,6 +19,7 @@
|
||||
pango,
|
||||
pciutils,
|
||||
systemd,
|
||||
tomlplusplus,
|
||||
udis86,
|
||||
wayland,
|
||||
wayland-protocols,
|
||||
@@ -26,21 +28,23 @@
|
||||
xcbutilwm,
|
||||
xwayland,
|
||||
debug ? false,
|
||||
enableNvidiaPatches ? false,
|
||||
enableXWayland ? true,
|
||||
legacyRenderer ? false,
|
||||
withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
|
||||
wrapRuntimeDeps ? true,
|
||||
version ? "git",
|
||||
commit,
|
||||
date,
|
||||
# deprecated flags
|
||||
enableNvidiaPatches ? false,
|
||||
nvidiaPatches ? false,
|
||||
hidpiXWayland ? false,
|
||||
}:
|
||||
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been renamed `enableNvidiaPatches`";
|
||||
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
|
||||
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
|
||||
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
|
||||
stdenv.mkDerivation {
|
||||
pname = "hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}${lib.optionalString debug "-debug"}";
|
||||
pname = "hyprland${lib.optionalString debug "-debug"}";
|
||||
inherit version;
|
||||
|
||||
src = lib.cleanSourceWith {
|
||||
@@ -68,19 +72,21 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||
|
||||
buildInputs =
|
||||
[
|
||||
git
|
||||
cairo
|
||||
git
|
||||
hyprland-protocols
|
||||
libdrm
|
||||
libGL
|
||||
libinput
|
||||
libxkbcommon
|
||||
mesa
|
||||
pango
|
||||
pciutils
|
||||
tomlplusplus
|
||||
udis86
|
||||
wayland
|
||||
wayland-protocols
|
||||
pciutils
|
||||
(wlroots.override {inherit enableNvidiaPatches;})
|
||||
wlroots
|
||||
]
|
||||
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
|
||||
++ lib.optionals withSystemd [systemd];
|
||||
@@ -113,6 +119,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||
--replace "@HASH@" '${commit}' \
|
||||
--replace "@BRANCH@" "" \
|
||||
--replace "@MESSAGE@" "" \
|
||||
--replace "@DATE@" "${date}" \
|
||||
--replace "@TAG@" "" \
|
||||
--replace "@DIRTY@" '${
|
||||
if commit == ""
|
||||
@@ -125,7 +132,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||
ln -s ${wlroots}/include/wlr $dev/include/hyprland/wlroots
|
||||
${lib.optionalString wrapRuntimeDeps ''
|
||||
wrapProgram $out/bin/Hyprland \
|
||||
--suffix PATH : ${lib.makeBinPath [binutils pciutils]}
|
||||
--suffix PATH : ${lib.makeBinPath [
|
||||
stdenv.cc
|
||||
binutils
|
||||
pciutils
|
||||
]}
|
||||
''}
|
||||
'';
|
||||
|
||||
|
@@ -4,174 +4,11 @@ self: {
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
cfg = config.wayland.windowManager.hyprland;
|
||||
defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = cfg.xwayland.enable;
|
||||
inherit (cfg) enableNvidiaPatches;
|
||||
};
|
||||
inherit (pkgs.stdenv.hostPlatform) system;
|
||||
|
||||
package = self.packages.${system}.default;
|
||||
in {
|
||||
disabledModules = ["services/window-managers/hyprland.nix"];
|
||||
|
||||
meta.maintainers = [lib.maintainers.fufexan];
|
||||
|
||||
options.wayland.windowManager.hyprland = {
|
||||
enable =
|
||||
lib.mkEnableOption null
|
||||
// {
|
||||
description = lib.mdDoc ''
|
||||
Whether to enable Hyprland, the dynamic tiling Wayland compositor
|
||||
that doesn't sacrifice on its looks.
|
||||
|
||||
You can manually launch Hyprland by executing {command}`Hyprland` on
|
||||
a TTY.
|
||||
|
||||
See <https://wiki.hyprland.org> for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
package = lib.mkOption {
|
||||
type = with lib.types; nullOr package;
|
||||
default = defaultHyprlandPackage;
|
||||
defaultText = lib.literalExpression ''
|
||||
hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = config.wayland.windowManager.hyprland.xwayland.enable;
|
||||
inherit (config.wayland.windowManager.hyprland) enableNvidiaPatches;
|
||||
}
|
||||
'';
|
||||
description = lib.mdDoc ''
|
||||
Hyprland package to use. Will override the 'xwayland' and
|
||||
'enableNvidiaPatches' options.
|
||||
|
||||
Defaults to the one provided by the flake. Set it to
|
||||
{package}`pkgs.hyprland` to use the one provided by nixpkgs or
|
||||
if you have an overlay.
|
||||
|
||||
Set to null to not add any Hyprland package to your path. This should
|
||||
be done if you want to use the NixOS module to install Hyprland.
|
||||
'';
|
||||
};
|
||||
|
||||
plugins = lib.mkOption {
|
||||
type = with lib.types; listOf (either package path);
|
||||
default = [];
|
||||
description = lib.mdDoc ''
|
||||
List of Hyprland plugins to use. Can either be packages or
|
||||
absolute plugin paths.
|
||||
'';
|
||||
};
|
||||
|
||||
systemdIntegration = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = pkgs.stdenv.isLinux;
|
||||
description = lib.mdDoc ''
|
||||
Whether to enable {file}`hyprland-session.target` on
|
||||
Hyprland startup. This links to {file}`graphical-session.target`.
|
||||
Some important environment variables will be imported to systemd
|
||||
and dbus user environment before reaching the target, including
|
||||
- {env}`DISPLAY`
|
||||
- {env}`HYPRLAND_INSTANCE_SIGNATURE`
|
||||
- {env}`WAYLAND_DISPLAY`
|
||||
- {env}`XDG_CURRENT_DESKTOP`
|
||||
'';
|
||||
};
|
||||
|
||||
disableAutoreload =
|
||||
lib.mkEnableOption null
|
||||
// {
|
||||
description = lib.mdDoc ''
|
||||
Whether to disable automatically reloading Hyprland's configuration when
|
||||
rebuilding the Home Manager profile.
|
||||
'';
|
||||
};
|
||||
|
||||
xwayland.enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;};
|
||||
|
||||
enableNvidiaPatches = lib.mkEnableOption (lib.mdDoc "patching wlroots for better Nvidia support.");
|
||||
|
||||
extraConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.lines;
|
||||
default = "";
|
||||
description = lib.mdDoc ''
|
||||
Extra configuration lines to add to {file}`~/.config/hypr/hyprland.conf`.
|
||||
'';
|
||||
};
|
||||
|
||||
recommendedEnvironment =
|
||||
lib.mkEnableOption null
|
||||
// {
|
||||
description = lib.mdDoc ''
|
||||
Whether to set the recommended environment variables.
|
||||
'';
|
||||
};
|
||||
config = {
|
||||
wayland.windowManager.hyprland.package = lib.mkDefault package;
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
warnings =
|
||||
if (cfg.systemdIntegration || cfg.plugins != []) && cfg.extraConfig == null
|
||||
then [
|
||||
''
|
||||
You have enabled hyprland.systemdIntegration or listed plugins in hyprland.plugins.
|
||||
Your Hyprland config will be linked by home manager.
|
||||
Set hyprland.extraConfig or unset hyprland.systemdIntegration and hyprland.plugins to remove this warning.
|
||||
''
|
||||
]
|
||||
else [];
|
||||
|
||||
home.packages =
|
||||
lib.optional (cfg.package != null) cfg.package
|
||||
++ lib.optional cfg.xwayland.enable pkgs.xwayland;
|
||||
|
||||
home.sessionVariables =
|
||||
lib.mkIf cfg.recommendedEnvironment {NIXOS_OZONE_WL = "1";};
|
||||
|
||||
xdg.configFile."hypr/hyprland.conf" = lib.mkIf (cfg.systemdIntegration || cfg.extraConfig != null || cfg.plugins != []) {
|
||||
text =
|
||||
(lib.optionalString cfg.systemdIntegration ''
|
||||
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && systemctl --user start hyprland-session.target
|
||||
'')
|
||||
+ lib.concatStrings (builtins.map (entry: let
|
||||
plugin =
|
||||
if lib.types.package.check entry
|
||||
then "${entry}/lib/lib${entry.pname}.so"
|
||||
else entry;
|
||||
in "plugin = ${plugin}\n")
|
||||
cfg.plugins)
|
||||
+ (
|
||||
if cfg.extraConfig != null
|
||||
then cfg.extraConfig
|
||||
else ""
|
||||
);
|
||||
|
||||
onChange = let
|
||||
hyprlandPackage =
|
||||
if cfg.package == null
|
||||
then defaultHyprlandPackage
|
||||
else cfg.package;
|
||||
in
|
||||
lib.mkIf (!cfg.disableAutoreload) ''
|
||||
( # execute in subshell so that `shopt` won't affect other scripts
|
||||
shopt -s nullglob # so that nothing is done if /tmp/hypr/ does not exist or is empty
|
||||
for instance in /tmp/hypr/*; do
|
||||
HYPRLAND_INSTANCE_SIGNATURE=''${instance##*/} ${hyprlandPackage}/bin/hyprctl reload config-only \
|
||||
|| true # ignore dead instance(s)
|
||||
done
|
||||
)
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.user.targets.hyprland-session = lib.mkIf cfg.systemdIntegration {
|
||||
Unit = {
|
||||
Description = "Hyprland compositor session";
|
||||
Documentation = ["man:systemd.special(7)"];
|
||||
BindsTo = ["graphical-session.target"];
|
||||
Wants = ["graphical-session-pre.target"];
|
||||
After = ["graphical-session-pre.target"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "hidpi"]
|
||||
"Support for this option has been removed. Refer to https://wiki.hyprland.org/Configuring/XWayland for more info")
|
||||
];
|
||||
}
|
||||
|
@@ -2,98 +2,20 @@ inputs: {
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
options,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.programs.hyprland;
|
||||
}: let
|
||||
inherit (pkgs.stdenv.hostPlatform) system;
|
||||
cfg = config.programs.hyprland;
|
||||
|
||||
finalPortalPackage = cfg.portalPackage.override {
|
||||
package = inputs.self.packages.${system}.hyprland;
|
||||
portalPackage = inputs.self.packages.${system}.xdg-desktop-portal-hyprland.override {
|
||||
hyprland = cfg.finalPackage;
|
||||
};
|
||||
in {
|
||||
# disables Nixpkgs Hyprland module to avoid conflicts
|
||||
disabledModules = ["programs/hyprland.nix"];
|
||||
|
||||
options.programs.hyprland = {
|
||||
enable =
|
||||
mkEnableOption null
|
||||
// {
|
||||
description = mdDoc ''
|
||||
Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
|
||||
|
||||
You can manually launch Hyprland by executing {command}`Hyprland` on a TTY.
|
||||
|
||||
A configuration file will be generated in {file}`~/.config/hypr/hyprland.conf`.
|
||||
See <https://wiki.hyprland.org> for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkPackageOptionMD inputs.self.packages.${system} "hyprland" { };
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
readOnly = true;
|
||||
default = cfg.package.override {
|
||||
enableXWayland = cfg.xwayland.enable;
|
||||
enableNvidiaPatches = cfg.enableNvidiaPatches;
|
||||
};
|
||||
defaultText =
|
||||
literalExpression
|
||||
"`programs.hyprland.package` with applied configuration";
|
||||
description = mdDoc ''
|
||||
The Hyprland package after applying configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
portalPackage = mkPackageOptionMD inputs.xdph.packages.${system} "xdg-desktop-portal-hyprland" {};
|
||||
|
||||
xwayland.enable = mkEnableOption (mdDoc "support for XWayland") // {default = true;};
|
||||
|
||||
enableNvidiaPatches =
|
||||
mkEnableOption null
|
||||
// {
|
||||
description = mdDoc "Whether to apply patches to wlroots for better Nvidia support.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [cfg.finalPackage];
|
||||
|
||||
# NixOS changed the name of this attribute between NixOS 23.05 and
|
||||
# 23.11
|
||||
fonts = if builtins.hasAttr "enableDefaultPackages" options.fonts
|
||||
then {enableDefaultPackages = mkDefault true;}
|
||||
else {enableDefaultFonts = mkDefault true;};
|
||||
|
||||
hardware.opengl.enable = mkDefault true;
|
||||
|
||||
programs = {
|
||||
dconf.enable = mkDefault true;
|
||||
xwayland.enable = mkDefault cfg.xwayland.enable;
|
||||
};
|
||||
|
||||
security.polkit.enable = true;
|
||||
|
||||
services.xserver.displayManager.sessionPackages = [cfg.finalPackage];
|
||||
|
||||
xdg.portal = {
|
||||
enable = mkDefault true;
|
||||
extraPortals = [finalPortalPackage];
|
||||
config = {
|
||||
programs.hyprland = {
|
||||
package = lib.mkDefault package;
|
||||
portalPackage = lib.mkDefault portalPackage;
|
||||
};
|
||||
};
|
||||
|
||||
imports = with lib; [
|
||||
(
|
||||
mkRemovedOptionModule
|
||||
["programs" "hyprland" "xwayland" "hidpi"]
|
||||
"XWayland patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland"
|
||||
)
|
||||
(
|
||||
mkRenamedOptionModule
|
||||
["programs" "hyprland" "nvidiaPatches"]
|
||||
["programs" "hyprland" "enableNvidiaPatches"]
|
||||
)
|
||||
];
|
||||
}
|
||||
|
@@ -28,17 +28,26 @@ in {
|
||||
self.overlays.wlroots-hyprland
|
||||
self.overlays.udis86
|
||||
# Hyprland packages themselves
|
||||
(final: prev: {
|
||||
(final: prev: let
|
||||
date = mkDate (self.lastModifiedDate or "19700101");
|
||||
in {
|
||||
hyprland = final.callPackage ./default.nix {
|
||||
stdenv = final.gcc13Stdenv;
|
||||
version = "${props.version}+date=${mkDate (self.lastModifiedDate or "19700101")}_${self.shortRev or "dirty"}";
|
||||
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
|
||||
wlroots = final.wlroots-hyprland;
|
||||
commit = self.rev or "";
|
||||
inherit (final) udis86 hyprland-protocols;
|
||||
inherit date;
|
||||
};
|
||||
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
|
||||
hyprland-debug = final.hyprland.override {debug = true;};
|
||||
hyprland-nvidia = final.hyprland.override {enableNvidiaPatches = true;};
|
||||
hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;};
|
||||
hyprland-nvidia =
|
||||
builtins.trace ''
|
||||
hyprland-nvidia was removed. Please use the hyprland package.
|
||||
Nvidia patches are no longer needed.
|
||||
''
|
||||
final.hyprland;
|
||||
hyprland-hidpi =
|
||||
builtins.trace ''
|
||||
hyprland-hidpi was removed. Please use the hyprland package.
|
||||
@@ -65,30 +74,6 @@ in {
|
||||
wlroots-hyprland = final.callPackage ./wlroots.nix {
|
||||
version = "${mkDate (inputs.wlroots.lastModifiedDate or "19700101")}_${inputs.wlroots.shortRev or "dirty"}";
|
||||
src = inputs.wlroots;
|
||||
|
||||
libdisplay-info = prev.libdisplay-info.overrideAttrs (old: {
|
||||
version = "0.1.1+date=2023-03-02";
|
||||
src = final.fetchFromGitLab {
|
||||
domain = "gitlab.freedesktop.org";
|
||||
owner = "emersion";
|
||||
repo = old.pname;
|
||||
rev = "147d6611a64a6ab04611b923e30efacaca6fc678";
|
||||
sha256 = "sha256-/q79o13Zvu7x02SBGu0W5yQznQ+p7ltZ9L6cMW5t/o4=";
|
||||
};
|
||||
});
|
||||
|
||||
libliftoff = prev.libliftoff.overrideAttrs (old: {
|
||||
version = "0.5.0-dev";
|
||||
src = final.fetchFromGitLab {
|
||||
domain = "gitlab.freedesktop.org";
|
||||
owner = "emersion";
|
||||
repo = old.pname;
|
||||
rev = "d98ae243280074b0ba44bff92215ae8d785658c0";
|
||||
sha256 = "sha256-DjwlS8rXE7srs7A8+tHqXyUsFGtucYSeq6X0T/pVOc8=";
|
||||
};
|
||||
|
||||
NIX_CFLAGS_COMPILE = toString ["-Wno-error=sign-conversion"];
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,41 +0,0 @@
|
||||
diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c
|
||||
index 9fe934f7..9662d4ee 100644
|
||||
--- a/render/gles2/renderer.c
|
||||
+++ b/render/gles2/renderer.c
|
||||
@@ -176,7 +176,7 @@ static bool gles2_bind_buffer(struct wlr_renderer *wlr_renderer,
|
||||
assert(wlr_egl_is_current(renderer->egl));
|
||||
|
||||
push_gles2_debug(renderer);
|
||||
- glFlush();
|
||||
+ glFinish();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
pop_gles2_debug(renderer);
|
||||
|
||||
diff --git a/types/output/render.c b/types/output/render.c
|
||||
index 2e38919a..97f78608 100644
|
||||
--- a/types/output/render.c
|
||||
+++ b/types/output/render.c
|
||||
@@ -240,22 +240,7 @@ bool output_pick_format(struct wlr_output *output,
|
||||
}
|
||||
|
||||
uint32_t wlr_output_preferred_read_format(struct wlr_output *output) {
|
||||
- struct wlr_renderer *renderer = output->renderer;
|
||||
- assert(renderer != NULL);
|
||||
-
|
||||
- if (!renderer->impl->preferred_read_format || !renderer->impl->read_pixels) {
|
||||
- return DRM_FORMAT_INVALID;
|
||||
- }
|
||||
-
|
||||
- if (!wlr_output_attach_render(output, NULL)) {
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- uint32_t fmt = renderer->impl->preferred_read_format(renderer);
|
||||
-
|
||||
- output_clear_back_buffer(output);
|
||||
-
|
||||
- return fmt;
|
||||
+ return DRM_FORMAT_XRGB8888;
|
||||
}
|
||||
|
||||
struct wlr_render_pass *wlr_output_begin_render_pass(struct wlr_output *output,
|
@@ -1,28 +1,13 @@
|
||||
{
|
||||
lib,
|
||||
version,
|
||||
src,
|
||||
wlroots,
|
||||
hwdata,
|
||||
libdisplay-info,
|
||||
libliftoff,
|
||||
enableXWayland ? true,
|
||||
enableNvidiaPatches ? false,
|
||||
}:
|
||||
wlroots.overrideAttrs (old: {
|
||||
inherit version src enableXWayland;
|
||||
|
||||
pname = "${old.pname}-hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}";
|
||||
pname = "${old.pname}-hyprland";
|
||||
|
||||
patches =
|
||||
(old.patches or [])
|
||||
++ (lib.optionals enableNvidiaPatches [
|
||||
./patches/wlroots-nvidia.patch
|
||||
]);
|
||||
|
||||
buildInputs = old.buildInputs ++ [hwdata libliftoff libdisplay-info];
|
||||
|
||||
NIX_CFLAGS_COMPILE = toString [
|
||||
"-Wno-error=maybe-uninitialized"
|
||||
];
|
||||
patches = [ ]; # don't inherit old.patches
|
||||
})
|
||||
|
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "0.32.1"
|
||||
"version": "0.34.0"
|
||||
}
|
@@ -4,11 +4,13 @@ cp -fr ./src/version.h.in ./src/version.h
|
||||
HASH=$(git rev-parse HEAD)
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
MESSAGE=$(git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g')
|
||||
DATE=$(git show ${GIT_COMMIT_HASH} --no-patch --format=%cd --date=local)
|
||||
DIRTY=$(git diff-index --quiet HEAD -- || echo dirty)
|
||||
TAG=$(git describe --tags)
|
||||
|
||||
sed -i -e "s#@HASH@#${HASH}#" ./src/version.h
|
||||
sed -i -e "s#@BRANCH@#${BRANCH}#" ./src/version.h
|
||||
sed -i -e "s#@MESSAGE@#${MESSAGE}#" ./src/version.h
|
||||
sed -i -e "s#@DATE@#${DATE}#" ./src/version.h
|
||||
sed -i -e "s#@DIRTY@#${DIRTY}#" ./src/version.h
|
||||
sed -i -e "s#@TAG@#${TAG}#" ./src/version.h
|
||||
sed -i -e "s#@TAG@#${TAG}#" ./src/version.h
|
||||
|
@@ -24,7 +24,7 @@ void handleUnrecoverableSignal(int sig) {
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
signal(SIGSEGV, SIG_DFL);
|
||||
|
||||
if (g_pHookSystem->m_bCurrentEventPlugin) {
|
||||
if (g_pHookSystem && g_pHookSystem->m_bCurrentEventPlugin) {
|
||||
longjmp(g_pHookSystem->m_jbHookFaultJumpBuf, 1);
|
||||
return;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ CCompositor::CCompositor() {
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hypr")) {
|
||||
std::filesystem::create_directory("/tmp/hypr");
|
||||
std::filesystem::permissions("/tmp/hypr", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
std::filesystem::permissions("/tmp/hypr", std::filesystem::perms::all | std::filesystem::perms::sticky_bit, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
const auto INSTANCEPATH = "/tmp/hypr/" + m_szInstanceSignature;
|
||||
@@ -125,13 +125,12 @@ void CCompositor::initServer() {
|
||||
|
||||
initManagers(STAGE_PRIORITY);
|
||||
|
||||
if (const auto ENV = getenv("HYPRLAND_TRACE"); ENV && std::string(ENV) == "1")
|
||||
if (envEnabled("HYPRLAND_TRACE"))
|
||||
Debug::trace = true;
|
||||
|
||||
wlr_log_init(WLR_INFO, NULL);
|
||||
|
||||
const auto LOGWLR = getenv("HYPRLAND_LOG_WLR");
|
||||
if (LOGWLR && std::string(LOGWLR) == "1")
|
||||
if (envEnabled("HYPRLAND_LOG_WLR"))
|
||||
wlr_log_init(WLR_DEBUG, Debug::wlrLog);
|
||||
else
|
||||
wlr_log_init(WLR_ERROR, Debug::wlrLog);
|
||||
@@ -190,11 +189,11 @@ void CCompositor::initServer() {
|
||||
|
||||
m_sWLRGammaCtrlMgr = wlr_gamma_control_manager_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWLROutputLayout = wlr_output_layout_create();
|
||||
m_sWLROutputLayout = wlr_output_layout_create(m_sWLDisplay);
|
||||
|
||||
m_sWLROutputPowerMgr = wlr_output_power_manager_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 5);
|
||||
m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 6);
|
||||
|
||||
m_sWLRCursor = wlr_cursor_create();
|
||||
wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout);
|
||||
@@ -225,7 +224,6 @@ void CCompositor::initServer() {
|
||||
|
||||
m_sWLROutputMgr = wlr_output_manager_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRInhibitMgr = wlr_input_inhibit_manager_create(m_sWLDisplay);
|
||||
m_sWLRKbShInhibitMgr = wlr_keyboard_shortcuts_inhibit_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRPointerConstraints = wlr_pointer_constraints_v1_create(m_sWLDisplay);
|
||||
@@ -283,7 +281,7 @@ void CCompositor::initServer() {
|
||||
|
||||
void CCompositor::initAllSignals() {
|
||||
addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend");
|
||||
addWLSignal(&m_sWLRXDGShell->events.new_surface, &Events::listen_newXDGSurface, m_sWLRXDGShell, "XDG Shell");
|
||||
addWLSignal(&m_sWLRXDGShell->events.new_toplevel, &Events::listen_newXDGToplevel, m_sWLRXDGShell, "XDG Shell");
|
||||
addWLSignal(&m_sWLRCursor->events.motion, &Events::listen_mouseMove, m_sWLRCursor, "WLRCursor");
|
||||
addWLSignal(&m_sWLRCursor->events.motion_absolute, &Events::listen_mouseMoveAbsolute, m_sWLRCursor, "WLRCursor");
|
||||
addWLSignal(&m_sWLRCursor->events.button, &Events::listen_mouseButton, m_sWLRCursor, "WLRCursor");
|
||||
@@ -312,8 +310,6 @@ void CCompositor::initAllSignals() {
|
||||
addWLSignal(&m_sWLROutputLayout->events.change, &Events::listen_change, m_sWLROutputLayout, "OutputLayout");
|
||||
addWLSignal(&m_sWLROutputMgr->events.apply, &Events::listen_outputMgrApply, m_sWLROutputMgr, "OutputMgr");
|
||||
addWLSignal(&m_sWLROutputMgr->events.test, &Events::listen_outputMgrTest, m_sWLROutputMgr, "OutputMgr");
|
||||
addWLSignal(&m_sWLRInhibitMgr->events.activate, &Events::listen_InhibitActivate, m_sWLRInhibitMgr, "InhibitMgr");
|
||||
addWLSignal(&m_sWLRInhibitMgr->events.deactivate, &Events::listen_InhibitDeactivate, m_sWLRInhibitMgr, "InhibitMgr");
|
||||
addWLSignal(&m_sWLRPointerConstraints->events.new_constraint, &Events::listen_newConstraint, m_sWLRPointerConstraints, "PointerConstraints");
|
||||
addWLSignal(&m_sWLRXDGDecoMgr->events.new_toplevel_decoration, &Events::listen_NewXDGDeco, m_sWLRXDGDecoMgr, "XDGDecoMgr");
|
||||
addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr");
|
||||
@@ -342,10 +338,11 @@ void CCompositor::cleanup() {
|
||||
|
||||
removeLockFile();
|
||||
|
||||
m_bIsShuttingDown = true;
|
||||
m_bIsShuttingDown = true;
|
||||
Debug::shuttingDown = true;
|
||||
|
||||
#ifdef USES_SYSTEMD
|
||||
if (sd_booted() > 0)
|
||||
if (sd_booted() > 0 && !envEnabled("HYPRLAND_NO_SD_NOTIFY"))
|
||||
sd_notify(0, "STOPPING=1");
|
||||
#endif
|
||||
|
||||
@@ -519,14 +516,15 @@ void CCompositor::startCompositor() {
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */ && fork() == 0)
|
||||
execl(
|
||||
"/bin/sh", "/bin/sh", "-c",
|
||||
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */) {
|
||||
const auto CMD =
|
||||
#ifdef USES_SYSTEMD
|
||||
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && hash dbus-update-activation-environment 2>/dev/null && "
|
||||
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME && hash "
|
||||
"dbus-update-activation-environment 2>/dev/null && "
|
||||
#endif
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE",
|
||||
nullptr);
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME";
|
||||
g_pKeybindManager->spawn(CMD);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket);
|
||||
|
||||
@@ -542,10 +540,11 @@ void CCompositor::startCompositor() {
|
||||
g_pHyprRenderer->setCursorFromName("left_ptr");
|
||||
|
||||
#ifdef USES_SYSTEMD
|
||||
if (sd_booted() > 0)
|
||||
if (sd_booted() > 0) {
|
||||
// tell systemd that we are ready so it can start other bond, following, related units
|
||||
sd_notify(0, "READY=1");
|
||||
else
|
||||
if (!envEnabled("HYPRLAND_NO_SD_NOTIFY"))
|
||||
sd_notify(0, "READY=1");
|
||||
} else
|
||||
Debug::log(LOG, "systemd integration is baked in but system itself is not booted à la systemd!");
|
||||
#endif
|
||||
|
||||
@@ -577,7 +576,7 @@ CMonitor* CCompositor::getMonitorFromName(const std::string& name) {
|
||||
|
||||
CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) {
|
||||
for (auto& m : m_vMonitors) {
|
||||
if (m->output->description && std::string(m->output->description).starts_with(desc))
|
||||
if (m->szDescription.starts_with(desc))
|
||||
return m.get();
|
||||
}
|
||||
return nullptr;
|
||||
@@ -630,46 +629,6 @@ bool CCompositor::windowExists(CWindow* pWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
auto box = w->getWindowMainSurfaceBox();
|
||||
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
auto box = w->getWindowMainSurfaceBox();
|
||||
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint(pos) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
|
||||
// pinned
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
auto box = w->getWindowMainSurfaceBox();
|
||||
if (box.containsPoint(pos) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
// first loop over floating cuz they're above, m_vWindows should be sorted bottom->top, for tiled it doesn't matter.
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
auto box = w->getWindowMainSurfaceBox();
|
||||
if (box.containsPoint(pos) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
auto box = w->getWindowMainSurfaceBox();
|
||||
if (box.containsPoint(pos) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->isHidden() && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
|
||||
@@ -690,36 +649,18 @@ CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
|
||||
CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreWindow) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
|
||||
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
|
||||
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
|
||||
|
||||
// special workspace
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
const auto BB = w->getWindowInputBox();
|
||||
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
|
||||
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bX11ShouldntFocus &&
|
||||
!w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (!w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bX11ShouldntFocus &&
|
||||
!w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
|
||||
// pinned windows on top of floating regardless
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
const auto BB = w->getWindowInputBox();
|
||||
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus) {
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
|
||||
return w.get();
|
||||
|
||||
@@ -730,48 +671,74 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
|
||||
}
|
||||
}
|
||||
|
||||
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
const auto BB = w->getWindowInputBox();
|
||||
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus) {
|
||||
// OR windows should add focus to parent
|
||||
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
|
||||
auto windowForWorkspace = [&](bool special) -> CWindow* {
|
||||
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
|
||||
if (special && !isWorkspaceSpecial(w->m_iWorkspaceID)) // because special floating may creep up into regular
|
||||
continue;
|
||||
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
|
||||
const auto BB = w->getWindowInputBox();
|
||||
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
|
||||
// OR windows should add focus to parent
|
||||
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
|
||||
continue;
|
||||
|
||||
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
|
||||
// Override Redirect
|
||||
return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
|
||||
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
|
||||
|
||||
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
|
||||
// Override Redirect
|
||||
return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
|
||||
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
|
||||
}
|
||||
|
||||
return w.get();
|
||||
}
|
||||
|
||||
return w.get();
|
||||
if (!w->m_bIsX11) {
|
||||
if (w->hasPopupAt(pos))
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!w->m_bIsX11) {
|
||||
const int64_t WORKSPACEID = special ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
||||
const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID);
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow)
|
||||
return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
|
||||
// for windows, we need to check their extensions too, first.
|
||||
for (auto& w : m_vWindows) {
|
||||
if (special != isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue;
|
||||
|
||||
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus &&
|
||||
w.get() != pIgnoreWindow) {
|
||||
if (w->hasPopupAt(pos))
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for windows, we need to check their extensions too, first.
|
||||
for (auto& w : m_vWindows) {
|
||||
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus) {
|
||||
if ((w)->hasPopupAt(pos))
|
||||
for (auto& w : m_vWindows) {
|
||||
if (special != isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue;
|
||||
|
||||
CBox box = {w->m_vPosition, w->m_vSize};
|
||||
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus &&
|
||||
w.get() != pIgnoreWindow)
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
for (auto& w : m_vWindows) {
|
||||
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus &&
|
||||
!w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
// special workspace
|
||||
if (PMONITOR->specialWorkspaceID)
|
||||
return windowForWorkspace(true);
|
||||
|
||||
return windowForWorkspace(false);
|
||||
}
|
||||
|
||||
CWindow* CCompositor::windowFromCursor() {
|
||||
@@ -977,6 +944,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
||||
|
||||
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
|
||||
if (windowValidMapped(PLASTWINDOW)) {
|
||||
PLASTWINDOW->updateDynamicRules();
|
||||
|
||||
updateWindowAnimatedDecorationValues(PLASTWINDOW);
|
||||
|
||||
if (!pWindow->m_bIsX11 || pWindow->m_iX11Type == 1)
|
||||
@@ -994,6 +963,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
||||
|
||||
g_pXWaylandManager->activateWindow(pWindow, true); // sets the m_pLastWindow
|
||||
|
||||
pWindow->updateDynamicRules();
|
||||
|
||||
updateWindowAnimatedDecorationValues(pWindow);
|
||||
|
||||
if (pWindow->m_bIsUrgent)
|
||||
@@ -1062,20 +1033,17 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto KEYBOARD = wlr_seat_get_keyboard(m_sSeat.seat);
|
||||
if (const auto KEYBOARD = wlr_seat_get_keyboard(m_sSeat.seat); KEYBOARD) {
|
||||
uint32_t keycodes[WLR_KEYBOARD_KEYS_CAP] = {0}; // TODO: maybe send valid, non-keybind codes?
|
||||
wlr_seat_keyboard_notify_enter(m_sSeat.seat, pSurface, keycodes, 0, &KEYBOARD->modifiers);
|
||||
|
||||
if (!KEYBOARD)
|
||||
return;
|
||||
|
||||
uint32_t keycodes[WLR_KEYBOARD_KEYS_CAP] = {0}; // TODO: maybe send valid, non-keybind codes?
|
||||
wlr_seat_keyboard_notify_enter(m_sSeat.seat, pSurface, keycodes, 0, &KEYBOARD->modifiers);
|
||||
|
||||
wlr_seat_keyboard_focus_change_event event = {
|
||||
.seat = m_sSeat.seat,
|
||||
.old_surface = m_pLastFocus,
|
||||
.new_surface = pSurface,
|
||||
};
|
||||
wl_signal_emit_mutable(&m_sSeat.seat->keyboard_state.events.focus_change, &event);
|
||||
wlr_seat_keyboard_focus_change_event event = {
|
||||
.seat = m_sSeat.seat,
|
||||
.old_surface = m_pLastFocus,
|
||||
.new_surface = pSurface,
|
||||
};
|
||||
wl_signal_emit_mutable(&m_sSeat.seat->keyboard_state.events.focus_change, &event);
|
||||
}
|
||||
|
||||
if (pWindowOwner)
|
||||
Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", (uintptr_t)pSurface, pWindowOwner);
|
||||
@@ -1095,9 +1063,6 @@ bool CCompositor::windowValidMapped(CWindow* pWindow) {
|
||||
if (!windowExists(pWindow))
|
||||
return false;
|
||||
|
||||
if (pWindow->m_bIsX11 && !pWindow->m_bMappedX11)
|
||||
return false;
|
||||
|
||||
if (!pWindow->m_bIsMapped)
|
||||
return false;
|
||||
|
||||
@@ -1144,9 +1109,24 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SIMEPopup* CCompositor::vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopup>& popups) {
|
||||
for (auto& popup : popups) {
|
||||
auto surface = popup.pSurface->surface;
|
||||
CBox box{
|
||||
popup.realX,
|
||||
popup.realY,
|
||||
surface->current.width,
|
||||
surface->current.height,
|
||||
};
|
||||
if (box.containsPoint(pos))
|
||||
return &popup;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->m_bFadingOut || !w->m_bMappedX11)
|
||||
if (!w->m_bIsMapped || w->m_bFadingOut)
|
||||
continue;
|
||||
|
||||
if (w->m_pWLSurface.wlr() == pSurface)
|
||||
@@ -1389,7 +1369,7 @@ void CCompositor::changeWindowZOrder(CWindow* pWindow, bool top) {
|
||||
toMove.emplace_front(pw);
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_bIsMapped && w->m_bMappedX11 && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw) {
|
||||
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw) {
|
||||
x11Stack(w.get(), top, x11Stack);
|
||||
}
|
||||
}
|
||||
@@ -1415,14 +1395,11 @@ void CCompositor::cleanupFadingOut(const int& monid) {
|
||||
if (valid && !w->m_bReadyToDelete)
|
||||
continue;
|
||||
|
||||
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return other.first == w; });
|
||||
w->m_bFadingOut = false;
|
||||
removeWindowFromVectorSafe(w);
|
||||
std::erase(m_vWindowsFadingOut, w);
|
||||
|
||||
Debug::log(LOG, "Cleanup: destroyed a window");
|
||||
|
||||
glFlush(); // to free mem NOW.
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1464,9 +1441,6 @@ void CCompositor::cleanupFadingOut(const int& monid) {
|
||||
g_pHyprOpenGL->markBlurDirtyForMonitor(getMonitorFromID(monid));
|
||||
|
||||
if (ls->fadingOut && ls->readyToDelete && !ls->alpha.isBeingAnimated()) {
|
||||
g_pHyprOpenGL->m_mLayerFramebuffers[ls].release();
|
||||
g_pHyprOpenGL->m_mLayerFramebuffers.erase(ls);
|
||||
|
||||
for (auto& m : m_vMonitors) {
|
||||
for (auto& lsl : m->m_aLayerSurfaceLayers) {
|
||||
if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](std::unique_ptr<SLayerSurface>& other) { return other.get() == ls; }) != lsl.end()) {
|
||||
@@ -1651,7 +1625,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableOnly) {
|
||||
CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableOnly, std::optional<bool> floating) {
|
||||
bool gotToWindow = false;
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w.get() != pWindow && !gotToWindow)
|
||||
@@ -1662,11 +1636,17 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
|
||||
continue;
|
||||
}
|
||||
|
||||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
continue;
|
||||
|
||||
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
@@ -1674,7 +1654,7 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableOnly) {
|
||||
CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableOnly, std::optional<bool> floating) {
|
||||
bool gotToWindow = false;
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
if (w.get() != pWindow && !gotToWindow)
|
||||
@@ -1685,11 +1665,17 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableO
|
||||
continue;
|
||||
}
|
||||
|
||||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
continue;
|
||||
|
||||
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
@@ -1738,6 +1724,15 @@ bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCompositor::isPointOnReservedArea(const Vector2D& point, const CMonitor* pMonitor) {
|
||||
const auto PMONITOR = pMonitor ? pMonitor : getMonitorFromVector(point);
|
||||
|
||||
const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
const auto XY2 = PMONITOR->vecPosition + PMONITOR->vecSize - PMONITOR->vecReservedBottomRight;
|
||||
|
||||
return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y);
|
||||
}
|
||||
|
||||
void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) {
|
||||
auto pair = (std::pair<wlr_surface*, bool>*)data;
|
||||
pair->second = pair->second || pSurface == pair->first;
|
||||
@@ -1750,7 +1745,7 @@ CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) {
|
||||
const auto PSURFACE = pMouse->currentConstraint->surface;
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->isHidden() || !w->m_bMappedX11 || !w->m_bIsMapped || !w->m_pWLSurface.exists())
|
||||
if (w->isHidden() || !w->m_bIsMapped || !w->m_pWLSurface.exists())
|
||||
continue;
|
||||
|
||||
if (w->m_bIsX11) {
|
||||
@@ -1838,6 +1833,15 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() {
|
||||
}
|
||||
}
|
||||
|
||||
void CCompositor::updateWorkspaceWindows(const int64_t& id) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->m_iWorkspaceID != id)
|
||||
continue;
|
||||
|
||||
w->updateDynamicRules();
|
||||
}
|
||||
}
|
||||
|
||||
void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
// optimization
|
||||
static auto* const ACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.active_border")->data.get();
|
||||
@@ -2010,7 +2014,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
|
||||
updateFullscreenFadeOnWorkspace(PWORKSPACEB);
|
||||
updateFullscreenFadeOnWorkspace(PWORKSPACEA);
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
// event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName});
|
||||
@@ -2082,7 +2086,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
|
||||
if (!m->output)
|
||||
continue;
|
||||
|
||||
if (m->output->description && std::string(m->output->description).starts_with(DESCRIPTION)) {
|
||||
if (m->szDescription.starts_with(DESCRIPTION)) {
|
||||
return m.get();
|
||||
}
|
||||
}
|
||||
@@ -2195,7 +2199,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
|
||||
|
||||
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
}
|
||||
|
||||
// finalize
|
||||
@@ -2278,7 +2282,7 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, MODE, on);
|
||||
|
||||
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && MODE == FULLSCREEN_FULL);
|
||||
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->shouldSendFullscreenState());
|
||||
|
||||
pWindow->updateDynamicRules();
|
||||
updateWindowAnimatedDecorationValues(pWindow);
|
||||
@@ -2534,17 +2538,6 @@ void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
|
||||
}
|
||||
}
|
||||
|
||||
bool CCompositor::cursorOnReservedArea() {
|
||||
const auto PMONITOR = getMonitorFromCursor();
|
||||
|
||||
const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
const auto XY2 = PMONITOR->vecPosition + PMONITOR->vecSize - PMONITOR->vecReservedBottomRight;
|
||||
|
||||
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
|
||||
|
||||
return !VECINRECT(CURSORPOS, XY1.x, XY1.y, XY2.x, XY2.y);
|
||||
}
|
||||
|
||||
CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name) {
|
||||
const auto NAME = name == "" ? std::to_string(id) : name;
|
||||
auto monID = monid;
|
||||
@@ -2561,6 +2554,8 @@ CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, con
|
||||
PWORKSPACE->m_iID = id;
|
||||
PWORKSPACE->m_iMonitorID = monID;
|
||||
|
||||
PWORKSPACE->m_fAlpha.setValueAndWarp(0);
|
||||
|
||||
return PWORKSPACE;
|
||||
}
|
||||
|
||||
@@ -2611,9 +2606,7 @@ int CCompositor::getNewSpecialID() {
|
||||
}
|
||||
|
||||
void CCompositor::performUserChecks() {
|
||||
const auto atomicEnv = getenv("WLR_DRM_NO_ATOMIC");
|
||||
const auto atomicEnvStr = std::string(atomicEnv ? atomicEnv : "");
|
||||
if (g_pConfigManager->getInt("general:allow_tearing") == 1 && atomicEnvStr != "1") {
|
||||
if (g_pConfigManager->getInt("general:allow_tearing") == 1 && !envEnabled("WLR_DRM_NO_ATOMIC")) {
|
||||
g_pHyprNotificationOverlay->addNotification("You have enabled tearing, but immediate presentations are not available on your configuration. Try adding "
|
||||
"env = WLR_DRM_NO_ATOMIC,1 to your config.",
|
||||
CColor(0), 15000, ICON_WARNING);
|
||||
@@ -2636,6 +2629,7 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
|
||||
pWindow->moveToWorkspace(pWorkspace->m_iID);
|
||||
pWindow->updateToplevel();
|
||||
pWindow->updateDynamicRules();
|
||||
pWindow->uncacheWindowDecos();
|
||||
|
||||
if (!pWindow->m_bIsFloating) {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow);
|
||||
@@ -2665,6 +2659,9 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
|
||||
|
||||
if (FULLSCREEN)
|
||||
setWindowFullscreen(pWindow, true, FULLSCREENMODE);
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID);
|
||||
g_pCompositor->updateWorkspaceWindows(pWindow->m_iWorkspaceID);
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getForceFocus() {
|
||||
@@ -2792,4 +2789,13 @@ void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scal
|
||||
|
||||
void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) {
|
||||
wlr_surface_set_preferred_buffer_transform(pSurface, transform);
|
||||
}
|
||||
}
|
||||
|
||||
void CCompositor::updateSuspendedStates() {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (!w->m_bIsMapped)
|
||||
continue;
|
||||
|
||||
w->setSuspended(w->isHidden() || !isWorkspaceVisible(w->m_iWorkspaceID));
|
||||
}
|
||||
}
|
||||
|
@@ -29,8 +29,7 @@
|
||||
#include "plugins/PluginSystem.hpp"
|
||||
#include "helpers/Watchdog.hpp"
|
||||
|
||||
enum eManagersInitStage
|
||||
{
|
||||
enum eManagersInitStage {
|
||||
STAGE_PRIORITY = 0,
|
||||
STAGE_LATE
|
||||
};
|
||||
@@ -62,7 +61,6 @@ class CCompositor {
|
||||
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
|
||||
wlr_output_manager_v1* m_sWLROutputMgr;
|
||||
wlr_presentation* m_sWLRPresentation;
|
||||
wlr_input_inhibit_manager* m_sWLRInhibitMgr;
|
||||
wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr;
|
||||
wlr_egl* m_sWLREGL;
|
||||
int m_iDRMFD;
|
||||
@@ -137,10 +135,10 @@ class CCompositor {
|
||||
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
|
||||
bool windowExists(CWindow*);
|
||||
bool windowValidMapped(CWindow*);
|
||||
CWindow* vectorToWindow(const Vector2D&);
|
||||
CWindow* vectorToWindowIdeal(const Vector2D&); // used only for finding a window to focus on, basically a "findFocusableWindow"
|
||||
CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow"
|
||||
CWindow* vectorToWindowTiled(const Vector2D&);
|
||||
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();
|
||||
@@ -167,13 +165,15 @@ class CCompositor {
|
||||
void changeWindowZOrder(CWindow*, bool);
|
||||
void cleanupFadingOut(const int& monid);
|
||||
CWindow* getWindowInDirection(CWindow*, char);
|
||||
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false, std::optional<bool> floating = {});
|
||||
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false, std::optional<bool> floating = {});
|
||||
int getNextAvailableNamedWorkspace();
|
||||
bool isPointOnAnyMonitor(const Vector2D&);
|
||||
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
|
||||
CWindow* getConstraintWindow(SMouse*);
|
||||
CMonitor* getMonitorInDirection(const char&);
|
||||
void updateAllWindowsAnimatedDecorationValues();
|
||||
void updateWorkspaceWindows(const int64_t& id);
|
||||
void updateWindowAnimatedDecorationValues(CWindow*);
|
||||
int getNextAvailableMonitorID(std::string const& name);
|
||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
|
||||
@@ -193,7 +193,6 @@ class CCompositor {
|
||||
void closeWindow(CWindow*);
|
||||
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
|
||||
void forceReportSizesToWindowsOnWorkspace(const int&);
|
||||
bool cursorOnReservedArea();
|
||||
CWorkspace* createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused!
|
||||
void renameWorkspace(const int&, const std::string& name = "");
|
||||
void setActiveMonitor(CMonitor*);
|
||||
@@ -209,6 +208,7 @@ class CCompositor {
|
||||
void leaveUnsafeState();
|
||||
void setPreferredScaleForSurface(wlr_surface* pSurface, double scale);
|
||||
void setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform);
|
||||
void updateSuspendedStates();
|
||||
|
||||
std::string explicitConfigPath;
|
||||
|
||||
|
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "helpers/Vector2D.hpp"
|
||||
|
||||
enum eIcons
|
||||
{
|
||||
enum eIcons {
|
||||
ICON_WARNING = 0,
|
||||
ICON_INFO,
|
||||
ICON_HINT,
|
||||
@@ -13,8 +12,7 @@ enum eIcons
|
||||
ICON_NONE
|
||||
};
|
||||
|
||||
enum eRenderStage
|
||||
{
|
||||
enum eRenderStage {
|
||||
RENDER_PRE = 0, /* Before binding the gl context */
|
||||
RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */
|
||||
RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */
|
||||
@@ -26,6 +24,14 @@ enum eRenderStage
|
||||
RENDER_POST_WINDOW, /* After rendering a window (any pass) */
|
||||
};
|
||||
|
||||
enum eInputType {
|
||||
INPUT_TYPE_AXIS = 0,
|
||||
INPUT_TYPE_BUTTON,
|
||||
INPUT_TYPE_DRAG_START,
|
||||
INPUT_TYPE_DRAG_END,
|
||||
INPUT_TYPE_MOTION
|
||||
};
|
||||
|
||||
struct SCallbackInfo {
|
||||
bool cancelled = false; /* on cancellable events, will cancel the event. */
|
||||
};
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include "Compositor.hpp"
|
||||
#include "render/decorations/CHyprDropShadowDecoration.hpp"
|
||||
#include "render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
#include "render/decorations/CHyprBorderDecoration.hpp"
|
||||
|
||||
CWindow::CWindow() {
|
||||
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
@@ -14,6 +15,7 @@ CWindow::CWindow() {
|
||||
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
|
||||
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
|
||||
addWindowDeco(std::make_unique<CHyprBorderDecoration>(this));
|
||||
}
|
||||
|
||||
CWindow::~CWindow() {
|
||||
@@ -21,6 +23,12 @@ CWindow::~CWindow() {
|
||||
g_pCompositor->m_pLastFocus = nullptr;
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
}
|
||||
|
||||
if (!g_pHyprOpenGL)
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return other.first == this; });
|
||||
}
|
||||
|
||||
SWindowDecorationExtents CWindow::getFullWindowExtents() {
|
||||
@@ -202,12 +210,40 @@ void CWindow::updateWindowDecos() {
|
||||
|
||||
void CWindow::addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco) {
|
||||
m_dWindowDecorations.emplace_back(std::move(deco));
|
||||
g_pDecorationPositioner->forceRecalcFor(this);
|
||||
updateWindowDecos();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||
}
|
||||
|
||||
void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
|
||||
m_vDecosToRemove.push_back(deco);
|
||||
g_pDecorationPositioner->forceRecalcFor(this);
|
||||
updateWindowDecos();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||
}
|
||||
|
||||
void CWindow::uncacheWindowDecos() {
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
g_pDecorationPositioner->uncacheDecoration(wd.get());
|
||||
}
|
||||
}
|
||||
|
||||
bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoords, std::any data) {
|
||||
if (type != INPUT_TYPE_DRAG_END && hasPopupAt(mouseCoords))
|
||||
return false;
|
||||
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (!g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords))
|
||||
continue;
|
||||
|
||||
if (wd->onInputOnDeco(type, mouseCoords, data))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pid_t CWindow::getPID() {
|
||||
@@ -219,7 +255,7 @@ pid_t CWindow::getPID() {
|
||||
|
||||
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
|
||||
} else {
|
||||
if (!m_bIsMapped || !m_bMappedX11)
|
||||
if (!m_bIsMapped)
|
||||
return -1;
|
||||
|
||||
PID = m_uSurface.xwayland->pid;
|
||||
@@ -310,7 +346,7 @@ void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
|
||||
}
|
||||
|
||||
void CWindow::updateSurfaceOutputs() {
|
||||
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden || !m_bMappedX11)
|
||||
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden)
|
||||
return;
|
||||
|
||||
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
|
||||
@@ -436,6 +472,8 @@ void CWindow::onUnmap() {
|
||||
|
||||
if (PMONITOR && PMONITOR->solitaryClient == this)
|
||||
PMONITOR->solitaryClient = nullptr;
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID);
|
||||
}
|
||||
|
||||
void CWindow::onMap() {
|
||||
@@ -497,6 +535,8 @@ void CWindow::setHidden(bool hidden) {
|
||||
if (hidden && g_pCompositor->m_pLastWindow == this) {
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
}
|
||||
|
||||
setSuspended(hidden);
|
||||
}
|
||||
|
||||
bool CWindow::isHidden() {
|
||||
@@ -587,6 +627,19 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
try {
|
||||
m_sAdditionalConfigData.xray = configStringToInt(vars[1]);
|
||||
} catch (...) {}
|
||||
} else if (r.szRule.starts_with("idleinhibit")) {
|
||||
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
|
||||
if (IDLERULE == "none")
|
||||
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||
else if (IDLERULE == "always")
|
||||
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
|
||||
else if (IDLERULE == "focus")
|
||||
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
|
||||
else if (IDLERULE == "fullscreen")
|
||||
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
|
||||
else
|
||||
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,6 +664,7 @@ void CWindow::updateDynamicRules() {
|
||||
m_sAdditionalConfigData.xray = -1;
|
||||
m_sAdditionalConfigData.forceTearing = false;
|
||||
m_sAdditionalConfigData.nearestNeighbor = false;
|
||||
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||
|
||||
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
|
||||
for (auto& r : WINDOWRULES) {
|
||||
@@ -940,7 +994,7 @@ float CWindow::rounding() {
|
||||
|
||||
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
|
||||
|
||||
return rounding;
|
||||
return m_sSpecialRenderData.rounding ? rounding : 0;
|
||||
}
|
||||
|
||||
void CWindow::updateSpecialRenderData() {
|
||||
@@ -974,3 +1028,19 @@ int CWindow::getRealBorderSize() {
|
||||
bool CWindow::canBeTorn() {
|
||||
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
|
||||
}
|
||||
|
||||
bool CWindow::shouldSendFullscreenState() {
|
||||
const auto MODE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID)->m_efFullscreenMode;
|
||||
return m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL));
|
||||
}
|
||||
|
||||
void CWindow::setSuspended(bool suspend) {
|
||||
if (suspend == m_bSuspended)
|
||||
return;
|
||||
|
||||
if (m_bIsX11)
|
||||
return;
|
||||
|
||||
wlr_xdg_toplevel_set_suspended(m_uSurface.xdg->toplevel, suspend);
|
||||
m_bSuspended = suspend;
|
||||
}
|
||||
|
@@ -11,16 +11,14 @@
|
||||
#include "macros.hpp"
|
||||
#include "managers/XWaylandManager.hpp"
|
||||
|
||||
enum eIdleInhibitMode
|
||||
{
|
||||
enum eIdleInhibitMode {
|
||||
IDLEINHIBIT_NONE = 0,
|
||||
IDLEINHIBIT_ALWAYS,
|
||||
IDLEINHIBIT_FULLSCREEN,
|
||||
IDLEINHIBIT_FOCUS
|
||||
};
|
||||
|
||||
enum eGroupRules
|
||||
{
|
||||
enum eGroupRules {
|
||||
// effective only during first map, except for _ALWAYS variant
|
||||
GROUP_NONE = 0,
|
||||
GROUP_SET = 1 << 0, // Open as new group or add to focused group
|
||||
@@ -153,11 +151,15 @@ struct SWindowRule {
|
||||
bool v2 = false;
|
||||
std::string szTitle;
|
||||
std::string szClass;
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
int bFullscreen = -1;
|
||||
int bPinned = -1;
|
||||
std::string szWorkspace = ""; // empty means any
|
||||
std::string szInitialTitle;
|
||||
std::string szInitialClass;
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
int bFullscreen = -1;
|
||||
int bPinned = -1;
|
||||
int bFocus = -1;
|
||||
int iOnWorkspace = -1;
|
||||
std::string szWorkspace = ""; // empty means any
|
||||
};
|
||||
|
||||
class CWindow {
|
||||
@@ -239,7 +241,6 @@ class CWindow {
|
||||
|
||||
// XWayland stuff
|
||||
bool m_bIsX11 = false;
|
||||
bool m_bMappedX11 = false;
|
||||
CWindow* m_pX11Parent = nullptr;
|
||||
uint64_t m_iX11Type = 0;
|
||||
bool m_bIsModal = false;
|
||||
@@ -347,6 +348,8 @@ class CWindow {
|
||||
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
|
||||
void updateWindowDecos();
|
||||
void removeWindowDeco(IHyprWindowDecoration* deco);
|
||||
void uncacheWindowDecos();
|
||||
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
|
||||
pid_t getPID();
|
||||
IHyprWindowDecoration* getDecorationByType(eDecorationType);
|
||||
void removeDecorationByType(eDecorationType);
|
||||
@@ -367,6 +370,8 @@ class CWindow {
|
||||
bool opaque();
|
||||
float rounding();
|
||||
bool canBeTorn();
|
||||
bool shouldSendFullscreenState();
|
||||
void setSuspended(bool suspend);
|
||||
|
||||
int getRealBorderSize();
|
||||
void updateSpecialRenderData();
|
||||
@@ -392,7 +397,8 @@ class CWindow {
|
||||
|
||||
private:
|
||||
// For hidden windows and stuff
|
||||
bool m_bHidden = false;
|
||||
bool m_bHidden = false;
|
||||
bool m_bSuspended = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#include "ConfigManager.hpp"
|
||||
#include "../managers/KeybindManager.hpp"
|
||||
|
||||
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
@@ -31,6 +33,8 @@ CConfigManager::CConfigManager() {
|
||||
configValues["group:groupbar:col.locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500);
|
||||
configValues["group:groupbar:col.locked_inactive"].data = std::make_shared<CGradientValueData>(0x66775500);
|
||||
|
||||
Debug::log(LOG, "NOTE: further logs to stdout / logfile are disabled by default. Use debug:disable_logs and debug:enable_stdout_logs to override this.");
|
||||
|
||||
setDefaultVars();
|
||||
setDefaultAnimationVars();
|
||||
|
||||
@@ -44,12 +48,11 @@ CConfigManager::CConfigManager() {
|
||||
|
||||
std::string CConfigManager::getConfigDir() {
|
||||
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
|
||||
std::string configPath;
|
||||
if (!xdgConfigHome)
|
||||
configPath = getenv("HOME") + std::string("/.config");
|
||||
else
|
||||
configPath = xdgConfigHome;
|
||||
return configPath;
|
||||
|
||||
if (xdgConfigHome && std::filesystem::path(xdgConfigHome).is_absolute())
|
||||
return xdgConfigHome;
|
||||
|
||||
return getenv("HOME") + std::string("/.config");
|
||||
}
|
||||
|
||||
std::string CConfigManager::getMainConfigPath() {
|
||||
@@ -77,8 +80,10 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["general:apply_sens_to_raw"].intValue = 0;
|
||||
configValues["general:border_size"].intValue = 1;
|
||||
configValues["general:no_border_on_floating"].intValue = 0;
|
||||
configValues["general:border_part_of_window"].intValue = 1;
|
||||
configValues["general:gaps_in"].intValue = 5;
|
||||
configValues["general:gaps_out"].intValue = 20;
|
||||
configValues["general:gaps_workspaces"].intValue = 0;
|
||||
((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff);
|
||||
((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
|
||||
((CGradientValueData*)configValues["general:col.nogroup_border"].data.get())->reset(0xff444444);
|
||||
@@ -129,9 +134,11 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["group:insert_after_current"].intValue = 1;
|
||||
configValues["group:focus_removed_window"].intValue = 1;
|
||||
|
||||
configValues["group:groupbar:enabled"].intValue = 1;
|
||||
configValues["group:groupbar:font_family"].strValue = "Sans";
|
||||
configValues["group:groupbar:font_size"].intValue = 8;
|
||||
configValues["group:groupbar:gradients"].intValue = 1;
|
||||
configValues["group:groupbar:priority"].intValue = 3;
|
||||
configValues["group:groupbar:render_titles"].intValue = 1;
|
||||
configValues["group:groupbar:scrolling"].intValue = 1;
|
||||
configValues["group:groupbar:text_color"].intValue = 0xffffffff;
|
||||
@@ -141,54 +148,57 @@ void CConfigManager::setDefaultVars() {
|
||||
((CGradientValueData*)configValues["group:groupbar:col.locked_active"].data.get())->reset(0x66ff5500);
|
||||
((CGradientValueData*)configValues["group:groupbar:col.locked_inactive"].data.get())->reset(0x66775500);
|
||||
|
||||
configValues["debug:int"].intValue = 0;
|
||||
configValues["debug:log_damage"].intValue = 0;
|
||||
configValues["debug:overlay"].intValue = 0;
|
||||
configValues["debug:damage_blink"].intValue = 0;
|
||||
configValues["debug:disable_logs"].intValue = 0;
|
||||
configValues["debug:disable_time"].intValue = 1;
|
||||
configValues["debug:enable_stdout_logs"].intValue = 0;
|
||||
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
|
||||
configValues["debug:manual_crash"].intValue = 0;
|
||||
configValues["debug:suppress_errors"].intValue = 0;
|
||||
configValues["debug:watchdog_timeout"].intValue = 5;
|
||||
configValues["debug:int"].intValue = 0;
|
||||
configValues["debug:log_damage"].intValue = 0;
|
||||
configValues["debug:overlay"].intValue = 0;
|
||||
configValues["debug:damage_blink"].intValue = 0;
|
||||
configValues["debug:disable_logs"].intValue = 1;
|
||||
configValues["debug:disable_time"].intValue = 1;
|
||||
configValues["debug:enable_stdout_logs"].intValue = 0;
|
||||
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
|
||||
configValues["debug:manual_crash"].intValue = 0;
|
||||
configValues["debug:suppress_errors"].intValue = 0;
|
||||
configValues["debug:watchdog_timeout"].intValue = 5;
|
||||
configValues["debug:disable_scale_checks"].intValue = 0;
|
||||
|
||||
configValues["decoration:rounding"].intValue = 0;
|
||||
configValues["decoration:blur:enabled"].intValue = 1;
|
||||
configValues["decoration:blur:size"].intValue = 8;
|
||||
configValues["decoration:blur:passes"].intValue = 1;
|
||||
configValues["decoration:blur:ignore_opacity"].intValue = 0;
|
||||
configValues["decoration:blur:new_optimizations"].intValue = 1;
|
||||
configValues["decoration:blur:xray"].intValue = 0;
|
||||
configValues["decoration:blur:contrast"].floatValue = 0.8916;
|
||||
configValues["decoration:blur:brightness"].floatValue = 1.0;
|
||||
configValues["decoration:blur:vibrancy"].floatValue = 0.1696;
|
||||
configValues["decoration:blur:vibrancy_darkness"].floatValue = 0.0;
|
||||
configValues["decoration:blur:noise"].floatValue = 0.0117;
|
||||
configValues["decoration:blur:special"].intValue = 0;
|
||||
configValues["decoration:active_opacity"].floatValue = 1;
|
||||
configValues["decoration:inactive_opacity"].floatValue = 1;
|
||||
configValues["decoration:fullscreen_opacity"].floatValue = 1;
|
||||
configValues["decoration:no_blur_on_oversized"].intValue = 0;
|
||||
configValues["decoration:drop_shadow"].intValue = 1;
|
||||
configValues["decoration:shadow_range"].intValue = 4;
|
||||
configValues["decoration:shadow_render_power"].intValue = 3;
|
||||
configValues["decoration:shadow_ignore_window"].intValue = 1;
|
||||
configValues["decoration:shadow_offset"].vecValue = Vector2D();
|
||||
configValues["decoration:shadow_scale"].floatValue = 1.f;
|
||||
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
|
||||
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
|
||||
configValues["decoration:dim_inactive"].intValue = 0;
|
||||
configValues["decoration:dim_strength"].floatValue = 0.5f;
|
||||
configValues["decoration:dim_special"].floatValue = 0.2f;
|
||||
configValues["decoration:dim_around"].floatValue = 0.4f;
|
||||
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
|
||||
configValues["decoration:rounding"].intValue = 0;
|
||||
configValues["decoration:blur:enabled"].intValue = 1;
|
||||
configValues["decoration:blur:size"].intValue = 8;
|
||||
configValues["decoration:blur:passes"].intValue = 1;
|
||||
configValues["decoration:blur:ignore_opacity"].intValue = 0;
|
||||
configValues["decoration:blur:new_optimizations"].intValue = 1;
|
||||
configValues["decoration:blur:xray"].intValue = 0;
|
||||
configValues["decoration:blur:contrast"].floatValue = 0.8916;
|
||||
configValues["decoration:blur:brightness"].floatValue = 1.0;
|
||||
configValues["decoration:blur:vibrancy"].floatValue = 0.1696;
|
||||
configValues["decoration:blur:vibrancy_darkness"].floatValue = 0.0;
|
||||
configValues["decoration:blur:noise"].floatValue = 0.0117;
|
||||
configValues["decoration:blur:special"].intValue = 0;
|
||||
configValues["decoration:blur:popups"].intValue = 0;
|
||||
configValues["decoration:blur:popups_ignorealpha"].floatValue = 0.2;
|
||||
configValues["decoration:active_opacity"].floatValue = 1;
|
||||
configValues["decoration:inactive_opacity"].floatValue = 1;
|
||||
configValues["decoration:fullscreen_opacity"].floatValue = 1;
|
||||
configValues["decoration:no_blur_on_oversized"].intValue = 0;
|
||||
configValues["decoration:drop_shadow"].intValue = 1;
|
||||
configValues["decoration:shadow_range"].intValue = 4;
|
||||
configValues["decoration:shadow_render_power"].intValue = 3;
|
||||
configValues["decoration:shadow_ignore_window"].intValue = 1;
|
||||
configValues["decoration:shadow_offset"].vecValue = Vector2D();
|
||||
configValues["decoration:shadow_scale"].floatValue = 1.f;
|
||||
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
|
||||
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
|
||||
configValues["decoration:dim_inactive"].intValue = 0;
|
||||
configValues["decoration:dim_strength"].floatValue = 0.5f;
|
||||
configValues["decoration:dim_special"].floatValue = 0.2f;
|
||||
configValues["decoration:dim_around"].floatValue = 0.4f;
|
||||
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
|
||||
|
||||
configValues["dwindle:pseudotile"].intValue = 0;
|
||||
configValues["dwindle:force_split"].intValue = 0;
|
||||
configValues["dwindle:permanent_direction_override"].intValue = 0;
|
||||
configValues["dwindle:preserve_split"].intValue = 0;
|
||||
configValues["dwindle:special_scale_factor"].floatValue = 0.8f;
|
||||
configValues["dwindle:special_scale_factor"].floatValue = 1.f;
|
||||
configValues["dwindle:split_width_multiplier"].floatValue = 1.0f;
|
||||
configValues["dwindle:no_gaps_when_only"].intValue = 0;
|
||||
configValues["dwindle:use_active_for_splits"].intValue = 1;
|
||||
@@ -196,7 +206,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["dwindle:smart_split"].intValue = 0;
|
||||
configValues["dwindle:smart_resizing"].intValue = 1;
|
||||
|
||||
configValues["master:special_scale_factor"].floatValue = 0.8f;
|
||||
configValues["master:special_scale_factor"].floatValue = 1.f;
|
||||
configValues["master:mfact"].floatValue = 0.55f;
|
||||
configValues["master:new_is_master"].intValue = 1;
|
||||
configValues["master:always_center_master"].intValue = 0;
|
||||
@@ -208,7 +218,8 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["master:smart_resizing"].intValue = 1;
|
||||
configValues["master:drop_at_cursor"].intValue = 1;
|
||||
|
||||
configValues["animations:enabled"].intValue = 1;
|
||||
configValues["animations:enabled"].intValue = 1;
|
||||
configValues["animations:first_launch_animation"].intValue = 1;
|
||||
|
||||
configValues["input:follow_mouse"].intValue = 1;
|
||||
configValues["input:mouse_refocus"].intValue = 1;
|
||||
@@ -230,6 +241,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:scroll_button"].intValue = 0;
|
||||
configValues["input:scroll_button_lock"].intValue = 0;
|
||||
configValues["input:scroll_points"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:touchpad:natural_scroll"].intValue = 0;
|
||||
configValues["input:touchpad:disable_while_typing"].intValue = 1;
|
||||
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
|
||||
@@ -245,6 +257,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["input:tablet:output"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:tablet:region_position"].vecValue = Vector2D();
|
||||
configValues["input:tablet:region_size"].vecValue = Vector2D();
|
||||
configValues["input:tablet:relative_input"].intValue = 0;
|
||||
|
||||
configValues["binds:pass_mouse_when_bound"].intValue = 0;
|
||||
configValues["binds:scroll_event_delay"].intValue = 300;
|
||||
@@ -271,6 +284,8 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["xwayland:use_nearest_neighbor"].intValue = 1;
|
||||
configValues["xwayland:force_zero_scaling"].intValue = 0;
|
||||
|
||||
configValues["opengl:nvidia_anti_flicker"].intValue = 1;
|
||||
|
||||
configValues["autogenerated"].intValue = 0;
|
||||
}
|
||||
|
||||
@@ -300,11 +315,13 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
|
||||
cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["scroll_button"].intValue = 0;
|
||||
cfgValues["scroll_button_lock"].intValue = 0;
|
||||
cfgValues["scroll_points"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["transform"].intValue = 0;
|
||||
cfgValues["output"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["enabled"].intValue = 1; // only for mice / touchpads
|
||||
cfgValues["region_position"].vecValue = Vector2D(); // only for tablets
|
||||
cfgValues["region_size"].vecValue = Vector2D(); // only for tablets
|
||||
cfgValues["relative_input"].intValue = 0; // only for tablets
|
||||
}
|
||||
|
||||
void CConfigManager::setDefaultAnimationVars() {
|
||||
@@ -1016,16 +1033,31 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
rule.szRule = RULE;
|
||||
rule.szValue = VALUE;
|
||||
|
||||
const auto TITLEPOS = VALUE.find("title:");
|
||||
const auto CLASSPOS = VALUE.find("class:");
|
||||
const auto X11POS = VALUE.find("xwayland:");
|
||||
const auto FLOATPOS = VALUE.find("floating:");
|
||||
const auto FULLSCREENPOS = VALUE.find("fullscreen:");
|
||||
const auto PINNEDPOS = VALUE.find("pinned:");
|
||||
const auto WORKSPACEPOS = VALUE.find("workspace:");
|
||||
const auto TITLEPOS = VALUE.find("title:");
|
||||
const auto CLASSPOS = VALUE.find("class:");
|
||||
const auto INITIALTITLEPOS = VALUE.find("initialTitle:");
|
||||
const auto INITIALCLASSPOS = VALUE.find("initialClass:");
|
||||
const auto X11POS = VALUE.find("xwayland:");
|
||||
const auto FLOATPOS = VALUE.find("floating:");
|
||||
const auto FULLSCREENPOS = VALUE.find("fullscreen:");
|
||||
const auto PINNEDPOS = VALUE.find("pinned:");
|
||||
const auto FOCUSPOS = VALUE.find("focus:");
|
||||
const auto ONWORKSPACEPOS = VALUE.find("onworkspace:");
|
||||
|
||||
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && X11POS == std::string::npos && FLOATPOS == std::string::npos && FULLSCREENPOS == std::string::npos &&
|
||||
PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos) {
|
||||
// find workspacepos that isn't onworkspacepos
|
||||
size_t WORKSPACEPOS = std::string::npos;
|
||||
size_t currentPos = VALUE.find("workspace:");
|
||||
while (currentPos != std::string::npos) {
|
||||
if (currentPos == 0 || VALUE[currentPos - 1] != 'n') {
|
||||
WORKSPACEPOS = currentPos;
|
||||
break;
|
||||
}
|
||||
currentPos = VALUE.find("workspace:", currentPos + 1);
|
||||
}
|
||||
|
||||
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && INITIALTITLEPOS == std::string::npos && INITIALCLASSPOS == std::string::npos &&
|
||||
X11POS == std::string::npos && FLOATPOS == std::string::npos && FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos &&
|
||||
FOCUSPOS == std::string::npos && ONWORKSPACEPOS == std::string::npos) {
|
||||
Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE);
|
||||
parseError = "Invalid rulev2 syntax: " + VALUE;
|
||||
return;
|
||||
@@ -1040,6 +1072,10 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
min = TITLEPOS;
|
||||
if (CLASSPOS > pos && CLASSPOS < min)
|
||||
min = CLASSPOS;
|
||||
if (INITIALTITLEPOS > pos && INITIALTITLEPOS < min)
|
||||
min = INITIALTITLEPOS;
|
||||
if (INITIALCLASSPOS > pos && INITIALCLASSPOS < min)
|
||||
min = INITIALCLASSPOS;
|
||||
if (X11POS > pos && X11POS < min)
|
||||
min = X11POS;
|
||||
if (FLOATPOS > pos && FLOATPOS < min)
|
||||
@@ -1048,8 +1084,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
min = FULLSCREENPOS;
|
||||
if (PINNEDPOS > pos && PINNEDPOS < min)
|
||||
min = PINNEDPOS;
|
||||
if (ONWORKSPACEPOS > pos && ONWORKSPACEPOS < min)
|
||||
min = ONWORKSPACEPOS;
|
||||
if (WORKSPACEPOS > pos && WORKSPACEPOS < min)
|
||||
min = PINNEDPOS;
|
||||
min = WORKSPACEPOS;
|
||||
if (FOCUSPOS > pos && FOCUSPOS < min)
|
||||
min = FOCUSPOS;
|
||||
|
||||
result = result.substr(0, min - pos);
|
||||
|
||||
@@ -1067,6 +1107,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
if (TITLEPOS != std::string::npos)
|
||||
rule.szTitle = extract(TITLEPOS + 6);
|
||||
|
||||
if (INITIALCLASSPOS != std::string::npos)
|
||||
rule.szInitialClass = extract(INITIALCLASSPOS + 13);
|
||||
|
||||
if (INITIALTITLEPOS != std::string::npos)
|
||||
rule.szInitialTitle = extract(INITIALTITLEPOS + 13);
|
||||
|
||||
if (X11POS != std::string::npos)
|
||||
rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
|
||||
|
||||
@@ -1082,6 +1128,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
if (WORKSPACEPOS != std::string::npos)
|
||||
rule.szWorkspace = extract(WORKSPACEPOS + 10);
|
||||
|
||||
if (FOCUSPOS != std::string::npos)
|
||||
rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0;
|
||||
|
||||
if (ONWORKSPACEPOS != std::string::npos)
|
||||
rule.iOnWorkspace = configStringToInt(extract(ONWORKSPACEPOS + 12));
|
||||
|
||||
if (RULE == "unset") {
|
||||
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
|
||||
if (!other.v2) {
|
||||
@@ -1093,6 +1145,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
if (!rule.szTitle.empty() && rule.szTitle != other.szTitle)
|
||||
return false;
|
||||
|
||||
if (!rule.szInitialClass.empty() && rule.szInitialClass != other.szInitialClass)
|
||||
return false;
|
||||
|
||||
if (!rule.szInitialTitle.empty() && rule.szInitialTitle != other.szInitialTitle)
|
||||
return false;
|
||||
|
||||
if (rule.bX11 != -1 && rule.bX11 != other.bX11)
|
||||
return false;
|
||||
|
||||
@@ -1108,6 +1166,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace)
|
||||
return false;
|
||||
|
||||
if (rule.bFocus != -1 && rule.bFocus != other.bFocus)
|
||||
return false;
|
||||
|
||||
if (rule.iOnWorkspace != -1 && rule.iOnWorkspace != other.iOnWorkspace)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@@ -1164,13 +1228,13 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
|
||||
auto rules = value.substr(FIRST_DELIM + 1);
|
||||
SWorkspaceRule wsRule;
|
||||
wsRule.workspaceString = first_ident;
|
||||
if (id == INT_MAX) {
|
||||
if (id == WORKSPACE_INVALID) {
|
||||
// it could be the monitor. If so, second value MUST be
|
||||
// the workspace.
|
||||
const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
|
||||
auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
|
||||
id = getWorkspaceIDFromString(wsIdent, name);
|
||||
if (id == INT_MAX) {
|
||||
if (id == WORKSPACE_INVALID) {
|
||||
Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
|
||||
parseError = "Invalid workspace identifier found: " + wsIdent;
|
||||
return;
|
||||
@@ -1208,6 +1272,20 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
|
||||
wsRule.isPersistent = configStringToInt(rule.substr(delim + 11));
|
||||
else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos)
|
||||
wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen));
|
||||
else if ((delim = rule.find("layoutopt:")) != std::string::npos) {
|
||||
std::string opt = rule.substr(delim + 10);
|
||||
if (!opt.contains(":")) {
|
||||
// invalid
|
||||
Debug::log(ERR, "Invalid workspace rule found: {}", rule);
|
||||
parseError = "Invalid workspace rule found: " + rule;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string val = opt.substr(opt.find(":") + 1);
|
||||
opt = opt.substr(0, opt.find(":"));
|
||||
|
||||
wsRule.layoutopts[opt] = val;
|
||||
}
|
||||
};
|
||||
|
||||
size_t pos = 0;
|
||||
@@ -1255,7 +1333,12 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
|
||||
for (size_t i = 0; i < glob_buf->gl_pathc; i++) {
|
||||
auto value = absolutePath(glob_buf->gl_pathv[i], configCurrentPath);
|
||||
|
||||
if (!std::filesystem::exists(value)) {
|
||||
if (!std::filesystem::is_regular_file(value)) {
|
||||
if (std::filesystem::exists(value)) {
|
||||
Debug::log(WARN, "source= skipping non-file {}", value);
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug::log(ERR, "source= file doesnt exist");
|
||||
parseError = "source file " + value + " doesn't exist!";
|
||||
return;
|
||||
@@ -1440,7 +1523,10 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||
void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equalsPlace) {
|
||||
auto dollarPlace = line.find_first_of('$', equalsPlace);
|
||||
|
||||
int times = 0;
|
||||
|
||||
while (dollarPlace != std::string::npos) {
|
||||
times++;
|
||||
|
||||
const auto STRAFTERDOLLAR = line.substr(dollarPlace + 1);
|
||||
bool found = false;
|
||||
@@ -1463,6 +1549,13 @@ void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equals
|
||||
}
|
||||
|
||||
dollarPlace = line.find_first_of('$', dollarPlace + 1);
|
||||
|
||||
if (times > 256 /* arbitrary limit */) {
|
||||
line = "";
|
||||
parseError = "Maximum variable recursion limit hit. Evaluating the line led to too many variable substitutions.";
|
||||
Debug::log(ERR, "Variable recursion limit hit in configmanager");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1509,7 +1602,7 @@ void CConfigManager::parseLine(std::string& line) {
|
||||
|
||||
const auto LASTSEP = currentCategory.find_last_of(':');
|
||||
|
||||
if (LASTSEP == std::string::npos || currentCategory.contains("device"))
|
||||
if (LASTSEP == std::string::npos || currentCategory.starts_with("device"))
|
||||
currentCategory = "";
|
||||
else
|
||||
currentCategory = currentCategory.substr(0, LASTSEP);
|
||||
@@ -1562,20 +1655,20 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
std::string mainConfigPath = getMainConfigPath();
|
||||
Debug::log(LOG, "Using config: {}", mainConfigPath);
|
||||
configPaths.push_back(mainConfigPath);
|
||||
std::string configPath = mainConfigPath.substr(0, mainConfigPath.find_last_of('/'));
|
||||
// find_last_of never returns npos since main_config at least has /hypr/
|
||||
|
||||
if (!std::filesystem::is_directory(configPath)) {
|
||||
Debug::log(WARN, "Creating config home directory");
|
||||
try {
|
||||
std::filesystem::create_directories(configPath);
|
||||
} catch (...) {
|
||||
parseError = "Broken config file! (Could not create config directory)";
|
||||
return;
|
||||
if (g_pCompositor->explicitConfigPath.empty() && !std::filesystem::exists(mainConfigPath)) {
|
||||
std::string configPath = std::filesystem::path(mainConfigPath).parent_path();
|
||||
|
||||
if (!std::filesystem::is_directory(configPath)) {
|
||||
Debug::log(WARN, "Creating config home directory");
|
||||
try {
|
||||
std::filesystem::create_directories(configPath);
|
||||
} catch (...) {
|
||||
parseError = "Broken config file! (Could not create config directory)";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(mainConfigPath)) {
|
||||
Debug::log(WARN, "No config file found; attempting to generate.");
|
||||
std::ofstream ofs;
|
||||
ofs.open(mainConfigPath, std::ios::trunc);
|
||||
@@ -1587,10 +1680,16 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
ifs.open(mainConfigPath);
|
||||
|
||||
if (!ifs.good()) {
|
||||
Debug::log(WARN, "Config reading error. Attempting to generate, backing up old one if exists");
|
||||
|
||||
ifs.close();
|
||||
|
||||
if (!g_pCompositor->explicitConfigPath.empty()) {
|
||||
Debug::log(WARN, "Config reading error!");
|
||||
parseError = "Broken config file! (Could not read)";
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(WARN, "Config reading error. Attempting to generate, backing up old one if exists");
|
||||
|
||||
if (std::filesystem::exists(mainConfigPath))
|
||||
std::filesystem::rename(mainConfigPath, mainConfigPath + ".backup");
|
||||
|
||||
@@ -1633,6 +1732,10 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
ifs.close();
|
||||
}
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
w->uncacheWindowDecos();
|
||||
}
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||
|
||||
@@ -1667,6 +1770,9 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
ensureVRR();
|
||||
}
|
||||
|
||||
if (!isFirstLaunch && !g_pCompositor->m_bUnsafeState)
|
||||
refreshGroupBarGradients();
|
||||
|
||||
// Updates dynamic window and workspace rules
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (!w->m_bIsMapped)
|
||||
@@ -1712,6 +1818,8 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
handlePluginLoads();
|
||||
|
||||
EMIT_HOOK_EVENT("configReloaded", nullptr);
|
||||
if (g_pEventManager)
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"configreloaded", ""});
|
||||
}
|
||||
|
||||
void CConfigManager::tick() {
|
||||
@@ -1930,6 +2038,20 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.szInitialTitle != "") {
|
||||
std::regex RULECHECK(rule.szInitialTitle);
|
||||
|
||||
if (!std::regex_search(pWindow->m_szInitialTitle, RULECHECK))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.szInitialClass != "") {
|
||||
std::regex RULECHECK(rule.szInitialClass);
|
||||
|
||||
if (!std::regex_search(pWindow->m_szInitialClass, RULECHECK))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.bX11 != -1) {
|
||||
if (pWindow->m_bIsX11 != rule.bX11)
|
||||
continue;
|
||||
@@ -1950,6 +2072,16 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.bFocus != -1) {
|
||||
if (rule.bFocus != (g_pCompositor->m_pLastWindow == pWindow))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.iOnWorkspace != -1) {
|
||||
if (rule.iOnWorkspace != g_pCompositor->getWindowsOnWorkspace(pWindow->m_iWorkspaceID))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rule.szWorkspace.empty()) {
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
||||
@@ -2040,12 +2172,12 @@ void CConfigManager::dispatchExecOnce() {
|
||||
|
||||
// update dbus env
|
||||
if (g_pCompositor->m_sWLRSession)
|
||||
handleRawExec(
|
||||
"",
|
||||
handleRawExec("",
|
||||
#ifdef USES_SYSTEMD
|
||||
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && hash dbus-update-activation-environment 2>/dev/null && "
|
||||
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME && hash "
|
||||
"dbus-update-activation-environment 2>/dev/null && "
|
||||
#endif
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE");
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME");
|
||||
|
||||
firstExecDispatched = true;
|
||||
|
||||
@@ -2073,7 +2205,7 @@ void CConfigManager::performMonitorReload() {
|
||||
if (!m->output || m->isUnsafeFallback)
|
||||
continue;
|
||||
|
||||
auto rule = getMonitorRuleFor(m->szName, m->output->description ? m->output->description : "");
|
||||
auto rule = getMonitorRuleFor(m->szName, m->szDescription);
|
||||
|
||||
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
|
||||
overAgain = true;
|
||||
@@ -2154,7 +2286,7 @@ void CConfigManager::ensureMonitorStatus() {
|
||||
if (!rm->output || rm->isUnsafeFallback)
|
||||
continue;
|
||||
|
||||
auto rule = getMonitorRuleFor(rm->szName, rm->output->description ? rm->output->description : "");
|
||||
auto rule = getMonitorRuleFor(rm->szName, rm->szDescription);
|
||||
|
||||
if (rule.disabled == rm->m_bEnabled)
|
||||
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
|
||||
|
@@ -37,20 +37,21 @@ struct SConfigValue {
|
||||
};
|
||||
|
||||
struct SWorkspaceRule {
|
||||
std::string monitor = "";
|
||||
std::string workspaceString = "";
|
||||
std::string workspaceName = "";
|
||||
int workspaceId = -1;
|
||||
bool isDefault = false;
|
||||
bool isPersistent = false;
|
||||
std::optional<int64_t> gapsIn;
|
||||
std::optional<int64_t> 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::string monitor = "";
|
||||
std::string workspaceString = "";
|
||||
std::string workspaceName = "";
|
||||
int workspaceId = -1;
|
||||
bool isDefault = false;
|
||||
bool isPersistent = false;
|
||||
std::optional<int64_t> gapsIn;
|
||||
std::optional<int64_t> 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::map<std::string, std::string> layoutopts;
|
||||
};
|
||||
|
||||
struct SMonitorAdditionalReservedArea {
|
||||
|
@@ -28,8 +28,14 @@ monitor=,preferred,auto,auto
|
||||
# Source a file (multi-file configs)
|
||||
# source = ~/.config/hypr/myColors.conf
|
||||
|
||||
# Set programs that you use
|
||||
$terminal = kitty
|
||||
$fileManager = dolphin
|
||||
$menu = wofi --show drun
|
||||
|
||||
# Some default env vars.
|
||||
env = XCURSOR_SIZE,24
|
||||
env = QT_QPA_PLATFORMTHEME,qt5ct # change to qt6ct if you have that
|
||||
|
||||
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
||||
input {
|
||||
@@ -127,18 +133,19 @@ 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.
|
||||
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||
$mainMod = SUPER
|
||||
|
||||
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
||||
bind = $mainMod, Q, exec, kitty
|
||||
bind = $mainMod, Q, exec, $terminal
|
||||
bind = $mainMod, C, killactive,
|
||||
bind = $mainMod, M, exit,
|
||||
bind = $mainMod, E, exec, dolphin
|
||||
bind = $mainMod, E, exec, $fileManager
|
||||
bind = $mainMod, V, togglefloating,
|
||||
bind = $mainMod, R, exec, wofi --show drun
|
||||
bind = $mainMod, R, exec, $menu
|
||||
bind = $mainMod, P, pseudo, # dwindle
|
||||
bind = $mainMod, J, togglesplit, # dwindle
|
||||
|
||||
|
@@ -13,19 +13,19 @@
|
||||
std::string getRandomMessage() {
|
||||
|
||||
const std::vector<std::string> MESSAGES = {"Sorry, didn't mean to...",
|
||||
"This was an accident, I swear!",
|
||||
"Calm down, it was a misinput! MISINPUT!",
|
||||
"Oops",
|
||||
"Vaxry is going to be upset.",
|
||||
"Who tried dividing by zero?!",
|
||||
"Maybe you should try dusting your PC in the meantime?",
|
||||
"I tried so hard, and got so far...",
|
||||
"I don't feel so good...",
|
||||
"*thud*",
|
||||
"Well this is awkward.",
|
||||
"\"stable\"",
|
||||
"I hope you didn't have any unsaved progress.",
|
||||
"All these computers..."};
|
||||
"This was an accident, I swear!",
|
||||
"Calm down, it was a misinput! MISINPUT!",
|
||||
"Oops",
|
||||
"Vaxry is going to be upset.",
|
||||
"Who tried dividing by zero?!",
|
||||
"Maybe you should try dusting your PC in the meantime?",
|
||||
"I tried so hard, and got so far...",
|
||||
"I don't feel so good...",
|
||||
"*thud*",
|
||||
"Well this is awkward.",
|
||||
"\"stable\"",
|
||||
"I hope you didn't have any unsaved progress.",
|
||||
"All these computers..."};
|
||||
|
||||
std::random_device dev;
|
||||
std::mt19937 engine(dev());
|
||||
@@ -63,8 +63,8 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
struct utsname unameInfo;
|
||||
uname(&unameInfo);
|
||||
|
||||
finalCrashReport +=
|
||||
std::format("\tSystem name: {}\n\tNode name: {}\n\tRelease: {}\n\tVersion: {}\n\n", unameInfo.sysname, unameInfo.nodename, unameInfo.release, unameInfo.version);
|
||||
finalCrashReport += std::format("\tSystem name: {}\n\tNode name: {}\n\tRelease: {}\n\tVersion: {}\n\n", std::string{unameInfo.sysname}, std::string{unameInfo.nodename},
|
||||
std::string{unameInfo.release}, std::string{unameInfo.version});
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
|
||||
@@ -119,7 +119,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
|
||||
finalCrashReport += "\n\nLog tail:\n";
|
||||
|
||||
finalCrashReport += execAndGet(("cat \"" + Debug::logFile + "\" | tail -n 50").c_str());
|
||||
finalCrashReport += Debug::rollingLog;
|
||||
|
||||
const auto HOME = getenv("HOME");
|
||||
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
|
||||
@@ -130,19 +130,15 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
std::ofstream ofs;
|
||||
std::string path;
|
||||
if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
|
||||
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
|
||||
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland"))
|
||||
std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
|
||||
std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
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")) {
|
||||
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland"))
|
||||
std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
|
||||
std::filesystem::permissions(std::string(CACHE_HOME) + "/hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||
ofs.open(path, std::ios::trunc);
|
||||
|
@@ -28,13 +28,22 @@ static std::string getWorkspaceNameFromSpecialID(const int workspaceID) {
|
||||
return workspace->m_szName;
|
||||
}
|
||||
|
||||
std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
auto allMonitors = false;
|
||||
|
||||
if (vars.size() > 2)
|
||||
return "too many args";
|
||||
|
||||
if (vars.size() == 2 && vars[1] == "all")
|
||||
allMonitors = true;
|
||||
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
result += "[";
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (!m->output)
|
||||
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
|
||||
if (!m->output || m->ID == -1ull)
|
||||
continue;
|
||||
|
||||
result += std::format(
|
||||
@@ -66,10 +75,10 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
"vrr": {},
|
||||
"activelyTearing": {}
|
||||
}},)#",
|
||||
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->output->description ? m->output->description : ""), (m->output->make ? m->output->make : ""),
|
||||
(m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate,
|
||||
(int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName),
|
||||
m->specialWorkspaceID, escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
|
||||
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szDescription), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
|
||||
(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
|
||||
m->activeWorkspace, (m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID,
|
||||
escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
|
||||
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"),
|
||||
(m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"),
|
||||
m->tearingState.activelyTearing ? "true" : "false");
|
||||
@@ -79,8 +88,8 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
|
||||
result += "]";
|
||||
} else {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (!m->output)
|
||||
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
|
||||
if (!m->output || m->ID == -1ull)
|
||||
continue;
|
||||
|
||||
result +=
|
||||
@@ -88,9 +97,9 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
"workspace: {} ({})\n\treserved: {} "
|
||||
"{} {} {}\n\tscale: {:.2f}\n\ttransform: "
|
||||
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\n",
|
||||
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
|
||||
(m->output->description ? m->output->description : ""), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
|
||||
(m->output->serial ? m->output->serial : ""), m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName, m->specialWorkspaceID,
|
||||
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szDescription,
|
||||
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspace,
|
||||
(m->activeWorkspace == -1 ? "" : g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName), m->specialWorkspaceID,
|
||||
getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x,
|
||||
(int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus,
|
||||
(int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing);
|
||||
@@ -250,7 +259,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
|
||||
std::string result = std::format(R"#({{
|
||||
"workspaceString": "{}"{}{}{}{}{}{}{}{}
|
||||
}})#",
|
||||
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow);
|
||||
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow);
|
||||
|
||||
return result;
|
||||
} else {
|
||||
@@ -266,7 +275,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
|
||||
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.shadow) ? boolToString(r.shadow.value()) : "<unset>");
|
||||
|
||||
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
|
||||
borderSize, border, rounding, decorate, shadow);
|
||||
borderSize, border, rounding, decorate, shadow);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -413,6 +422,28 @@ std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
result += "[";
|
||||
|
||||
for (auto& m : g_pLayoutManager->getAllLayoutNames()) {
|
||||
result += std::format(
|
||||
R"#(
|
||||
"{}",)#",
|
||||
m);
|
||||
}
|
||||
trimTrailingComma(result);
|
||||
|
||||
result += "\n]\n";
|
||||
} else {
|
||||
for (auto& m : g_pLayoutManager->getAllLayoutNames()) {
|
||||
result += std::format("{}\n", m);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string result = "";
|
||||
|
||||
@@ -625,6 +656,20 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string result = "";
|
||||
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
result += "[\n\"log\":\"";
|
||||
result += escapeJSONStrings(Debug::rollingLog);
|
||||
result += "\"]";
|
||||
} else {
|
||||
result = Debug::rollingLog;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string ret = "";
|
||||
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts();
|
||||
@@ -703,15 +748,12 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
|
||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg +
|
||||
").\nTag: " + GIT_TAG + "\n\nflags: (if any)\n";
|
||||
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + "\n\nflags: (if any)\n";
|
||||
|
||||
#ifdef LEGACY_RENDERER
|
||||
result += "legacyrenderer\n";
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
result += "debug\n";
|
||||
#endif
|
||||
#ifdef HYPRLAND_DEBUG
|
||||
#ifndef ISDEBUG
|
||||
result += "debug\n";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
@@ -726,17 +768,15 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
"commit": "{}",
|
||||
"dirty": {},
|
||||
"commit_message": "{}",
|
||||
"commit_date": "{}",
|
||||
"tag": "{}",
|
||||
"flags": [)#",
|
||||
GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_TAG);
|
||||
GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG);
|
||||
|
||||
#ifdef LEGACY_RENDERER
|
||||
result += "\"legacyrenderer\",";
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
result += "\"debug\",";
|
||||
#endif
|
||||
#ifdef HYPRLAND_DEBUG
|
||||
#ifndef ISDEBUG
|
||||
result += "\"debug\",";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
@@ -1134,6 +1174,32 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
|
||||
}
|
||||
}
|
||||
|
||||
std::string decorationRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
|
||||
|
||||
if (!PWINDOW)
|
||||
return "none";
|
||||
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
result += "[";
|
||||
for (auto& wd : PWINDOW->m_dWindowDecorations) {
|
||||
result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},";
|
||||
}
|
||||
|
||||
trimTrailingComma(result);
|
||||
result += "]";
|
||||
} else {
|
||||
result = +"Decoration\tPriority\n";
|
||||
for (auto& wd : PWINDOW->m_dWindowDecorations) {
|
||||
result += wd->getDisplayName() + "\t" + std::to_string(wd->getPositioningInfo().priority) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void createOutputIter(wlr_backend* backend, void* data) {
|
||||
const auto DATA = (std::pair<std::string, bool>*)data;
|
||||
|
||||
@@ -1230,7 +1296,7 @@ std::string dispatchPlugin(std::string request) {
|
||||
const auto PLUGIN = g_pPluginSystem->loadPlugin(PATH);
|
||||
|
||||
if (!PLUGIN)
|
||||
return "error in loading plugin";
|
||||
return "error in loading plugin, last error: " + g_pPluginSystem->m_szLastError;
|
||||
} else if (OPERATION == "unload") {
|
||||
if (vars.size() < 3)
|
||||
return "not enough args";
|
||||
@@ -1319,8 +1385,8 @@ std::string getReply(std::string request) {
|
||||
request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string
|
||||
}
|
||||
|
||||
if (request == "monitors")
|
||||
return monitorsRequest(format);
|
||||
if (request.starts_with("monitors"))
|
||||
return monitorsRequest(request, format);
|
||||
else if (request == "workspaces")
|
||||
return workspacesRequest(format);
|
||||
else if (request == "workspacerules")
|
||||
@@ -1351,6 +1417,10 @@ std::string getReply(std::string request) {
|
||||
return globalShortcutsRequest(format);
|
||||
else if (request == "animations")
|
||||
return animationsRequest(format);
|
||||
else if (request == "rollinglog")
|
||||
return rollinglogRequest(format);
|
||||
else if (request == "layouts")
|
||||
return layoutsRequest(format);
|
||||
else if (request.starts_with("plugin"))
|
||||
return dispatchPlugin(request);
|
||||
else if (request.starts_with("notify"))
|
||||
@@ -1371,6 +1441,8 @@ std::string getReply(std::string request) {
|
||||
return dispatchSetCursor(request);
|
||||
else if (request.starts_with("getoption"))
|
||||
return dispatchGetOption(request, format);
|
||||
else if (request.starts_with("decorations"))
|
||||
return decorationRequest(request, format);
|
||||
else if (request.starts_with("[[BATCH]]"))
|
||||
return dispatchBatch(request);
|
||||
|
||||
@@ -1385,14 +1457,14 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
|
||||
return 0;
|
||||
|
||||
sockaddr_in clientAddress;
|
||||
socklen_t clientSize = sizeof(clientAddress);
|
||||
sockaddr_in clientAddress;
|
||||
socklen_t clientSize = sizeof(clientAddress);
|
||||
|
||||
const auto ACCEPTEDCONNECTION = accept4(HyprCtl::iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
|
||||
const auto ACCEPTEDCONNECTION = accept4(HyprCtl::iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
|
||||
|
||||
char readBuffer[1024];
|
||||
std::array<char, 1024> readBuffer;
|
||||
|
||||
fd_set fdset;
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(ACCEPTEDCONNECTION, &fdset);
|
||||
timeval timeout = {.tv_sec = 0, .tv_usec = 5000};
|
||||
@@ -1403,10 +1475,17 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024);
|
||||
readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0';
|
||||
|
||||
std::string request(readBuffer);
|
||||
std::string request;
|
||||
while (true) {
|
||||
readBuffer.fill(0);
|
||||
auto messageSize = read(ACCEPTEDCONNECTION, readBuffer.data(), 1023);
|
||||
if (messageSize < 1)
|
||||
break;
|
||||
std::string recvd = readBuffer.data();
|
||||
request += recvd;
|
||||
if (messageSize < 1023)
|
||||
break;
|
||||
}
|
||||
|
||||
std::string reply = "";
|
||||
|
||||
|
@@ -10,16 +10,15 @@
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
enum eIconBackend
|
||||
{
|
||||
enum eIconBackend {
|
||||
ICONS_BACKEND_NONE = 0,
|
||||
ICONS_BACKEND_NF,
|
||||
ICONS_BACKEND_FA
|
||||
};
|
||||
|
||||
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
|
||||
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "", ""},
|
||||
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
|
||||
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""},
|
||||
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
|
||||
static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
|
||||
CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
|
||||
CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
|
||||
|
@@ -10,25 +10,24 @@ void Debug::init(const std::string& IS) {
|
||||
}
|
||||
|
||||
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
|
||||
if (disableLogs && *disableLogs)
|
||||
return;
|
||||
|
||||
if (level > wlr_log_get_verbosity())
|
||||
return;
|
||||
|
||||
char* outputStr = nullptr;
|
||||
|
||||
std::ofstream ofs;
|
||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||
char* outputStr = nullptr;
|
||||
|
||||
vasprintf(&outputStr, fmt, args);
|
||||
|
||||
std::string output = std::string(outputStr);
|
||||
free(outputStr);
|
||||
|
||||
ofs << "[wlr] " << output << "\n";
|
||||
rollingLog += output + "\n";
|
||||
|
||||
ofs.close();
|
||||
if (!disableLogs || !*disableLogs) {
|
||||
std::ofstream ofs;
|
||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||
ofs << "[wlr] " << output << "\n";
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
if (!disableStdout)
|
||||
std::cout << output << "\n";
|
||||
|
@@ -7,7 +7,8 @@
|
||||
#include "../includes.hpp"
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
|
||||
#define LOGMESSAGESIZE 1024
|
||||
#define LOGMESSAGESIZE 1024
|
||||
#define ROLLING_LOG_SIZE 4096
|
||||
|
||||
enum LogLevel {
|
||||
NONE = -1,
|
||||
@@ -25,14 +26,17 @@ namespace Debug {
|
||||
inline int64_t* disableTime = nullptr;
|
||||
inline bool disableStdout = false;
|
||||
inline bool trace = false;
|
||||
inline bool shuttingDown = false;
|
||||
|
||||
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
|
||||
|
||||
void init(const std::string& IS);
|
||||
template <typename... Args>
|
||||
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
|
||||
if (disableLogs && *disableLogs)
|
||||
if (level == TRACE && !trace)
|
||||
return;
|
||||
|
||||
if (level == TRACE && !trace)
|
||||
if (shuttingDown)
|
||||
return;
|
||||
|
||||
std::string logMsg = "";
|
||||
@@ -47,10 +51,6 @@ namespace Debug {
|
||||
default: break;
|
||||
}
|
||||
|
||||
// log to a file
|
||||
std::ofstream ofs;
|
||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||
|
||||
// print date and time to the ofs
|
||||
if (disableTime && !*disableTime) {
|
||||
#ifndef _LIBCPP_VERSION
|
||||
@@ -69,9 +69,18 @@ namespace Debug {
|
||||
// 3. this is actually what std::format in stdlib does
|
||||
logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
|
||||
ofs << logMsg << "\n";
|
||||
rollingLog += logMsg + "\n";
|
||||
if (rollingLog.size() > ROLLING_LOG_SIZE)
|
||||
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
|
||||
|
||||
ofs.close();
|
||||
if (!disableLogs || !*disableLogs) {
|
||||
// log to a file
|
||||
std::ofstream ofs;
|
||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||
ofs << logMsg << "\n";
|
||||
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
// log it to the stdout too.
|
||||
if (!disableStdout)
|
||||
|
@@ -13,15 +13,6 @@ inline PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v;
|
||||
|
||||
#include "../../subprojects/tracy/public/tracy/TracyOpenGL.hpp"
|
||||
|
||||
inline void loadGLProc(void* pProc, const char* name) {
|
||||
void* proc = (void*)eglGetProcAddress(name);
|
||||
if (proc == NULL) {
|
||||
Debug::log(CRIT, "[Tracy GPU Profiling] eglGetProcAddress({}) failed", name);
|
||||
abort();
|
||||
}
|
||||
*(void**)pProc = proc;
|
||||
}
|
||||
|
||||
#define TRACY_GPU_CONTEXT TracyGpuContext
|
||||
#define TRACY_GPU_ZONE(e) TracyGpuZone(e)
|
||||
#define TRACY_GPU_COLLECT TracyGpuCollect
|
||||
|
@@ -42,7 +42,7 @@ namespace Events {
|
||||
DYNLISTENFUNC(repositionPopupXDG);
|
||||
|
||||
// Surface XDG (window)
|
||||
LISTENER(newXDGSurface);
|
||||
LISTENER(newXDGToplevel);
|
||||
LISTENER(activateXDG);
|
||||
|
||||
// Window events
|
||||
@@ -121,10 +121,6 @@ namespace Events {
|
||||
DYNLISTENFUNC(destroyDragIcon);
|
||||
DYNLISTENFUNC(commitDragIcon);
|
||||
|
||||
// Inhibit
|
||||
LISTENER(InhibitActivate);
|
||||
LISTENER(InhibitDeactivate);
|
||||
|
||||
// Deco XDG
|
||||
LISTENER(NewXDGDeco);
|
||||
|
||||
|
@@ -254,6 +254,8 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||
geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y,
|
||||
(int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
|
||||
g_pHyprRenderer->damageBox(&geomFixed);
|
||||
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
}
|
||||
|
||||
void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||
|
@@ -156,20 +156,6 @@ void Events::listener_commitDragIcon(void* owner, void* data) {
|
||||
Debug::log(LOG, "Drag icon committed.");
|
||||
}
|
||||
|
||||
void Events::listener_InhibitActivate(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "Activated exclusive for {:x}.", (uintptr_t)g_pCompositor->m_sSeat.exclusiveClient);
|
||||
|
||||
g_pInputManager->refocus();
|
||||
g_pCompositor->m_sSeat.exclusiveClient = g_pCompositor->m_sWLRInhibitMgr->active_client;
|
||||
}
|
||||
|
||||
void Events::listener_InhibitDeactivate(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "Deactivated exclusive.");
|
||||
|
||||
g_pCompositor->m_sSeat.exclusiveClient = nullptr;
|
||||
g_pInputManager->refocus();
|
||||
}
|
||||
|
||||
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "!!Renderer destroyed!!");
|
||||
}
|
||||
|
@@ -22,10 +22,13 @@ void Events::listener_change(wl_listener* listener, void* data) {
|
||||
if (!CONFIG)
|
||||
return;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
if (!m->output)
|
||||
continue;
|
||||
|
||||
if (g_pCompositor->m_pUnsafeOutput == m.get())
|
||||
continue;
|
||||
|
||||
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output);
|
||||
|
||||
CBox BOX;
|
||||
@@ -195,7 +198,7 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
|
||||
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
|
||||
|
||||
pMonitor->onDisconnect();
|
||||
pMonitor->onDisconnect(true);
|
||||
|
||||
pMonitor->output = nullptr;
|
||||
pMonitor->m_bRenderingInitPassed = false;
|
||||
|
@@ -191,7 +191,7 @@ void Events::listener_repositionPopupXDG(void* owner, void* data) {
|
||||
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};
|
||||
PMONITOR->vecSize.y};
|
||||
wlr_xdg_popup_unconstrain_from_box(PPOPUP->popup, box.pWlr());
|
||||
}
|
||||
|
||||
|
@@ -52,7 +52,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
const auto PWORKSPACE =
|
||||
PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||
PWINDOW->m_bMappedX11 = true;
|
||||
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
||||
PWINDOW->m_bIsMapped = true;
|
||||
PWINDOW->m_bReadyToDelete = false;
|
||||
@@ -246,20 +245,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
vPrev = v;
|
||||
}
|
||||
} else if (r.szRule.starts_with("idleinhibit")) {
|
||||
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
|
||||
if (IDLERULE == "none") {
|
||||
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||
} else if (IDLERULE == "always") {
|
||||
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
|
||||
} else if (IDLERULE == "focus") {
|
||||
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
|
||||
} else if (IDLERULE == "fullscreen") {
|
||||
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
|
||||
} else {
|
||||
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
|
||||
}
|
||||
}
|
||||
PWINDOW->applyDynamicRule(r);
|
||||
}
|
||||
@@ -279,7 +264,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
std::string requestedWorkspaceName;
|
||||
const int REQUESTEDWORKSPACEID = getWorkspaceIDFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0), requestedWorkspaceName);
|
||||
|
||||
if (REQUESTEDWORKSPACEID != INT_MAX) {
|
||||
if (REQUESTEDWORKSPACEID != WORKSPACE_INVALID) {
|
||||
auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID);
|
||||
|
||||
if (!pWorkspace)
|
||||
@@ -493,7 +478,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree);
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xdg->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XDG Window Late");
|
||||
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,
|
||||
@@ -520,14 +504,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
"XWayland Window Late");
|
||||
}
|
||||
|
||||
// do the animation thing
|
||||
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
|
||||
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
|
||||
PWINDOW->m_fAlpha = 1.f;
|
||||
|
||||
PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove);
|
||||
PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove);
|
||||
|
||||
if ((requestsFullscreen && (!PWINDOW->m_bNoFullscreenRequest || overridingNoFullscreen)) || (requestsMaximize && (!PWINDOW->m_bNoMaximizeRequest || overridingNoMaximize)) ||
|
||||
requestsFakeFullscreen) {
|
||||
// fix fullscreen on requested (basically do a switcheroo)
|
||||
@@ -641,6 +617,19 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, g_pXWaylandManager->getAppIDClass(PWINDOW), PWINDOW->m_szTitle)});
|
||||
EMIT_HOOK_EVENT("openWindow", PWINDOW);
|
||||
|
||||
// apply data from default decos. Borders, shadows.
|
||||
g_pDecorationPositioner->forceRecalcFor(PWINDOW);
|
||||
PWINDOW->updateWindowDecos();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW);
|
||||
|
||||
// do animations
|
||||
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
|
||||
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
|
||||
PWINDOW->m_fAlpha = 1.f;
|
||||
|
||||
PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove);
|
||||
PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove);
|
||||
|
||||
// recalc the values for this window
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
||||
// avoid this window being visible
|
||||
@@ -650,11 +639,12 @@ 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->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == g_pCompositor->m_pLastWindow)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
// fix some xwayland apps that don't behave nicely
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
|
||||
}
|
||||
|
||||
void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
@@ -682,7 +672,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
Debug::log(LOG, "Unregistered late callbacks XDG");
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
PWINDOW->hyprListener_setTitleWindow.removeCallback();
|
||||
PWINDOW->hyprListener_newPopupXDG.removeCallback();
|
||||
PWINDOW->hyprListener_requestMaximize.removeCallback();
|
||||
@@ -724,8 +713,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
}
|
||||
|
||||
PWINDOW->m_bMappedX11 = false;
|
||||
|
||||
// remove the fullscreen window status from workspace if we closed it
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
@@ -746,8 +733,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
|
||||
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
|
||||
|
||||
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == PWINDOWCANDIDATE)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
// CWindow::onUnmap will remove this window's active status, but we can't really do it above.
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow || !g_pCompositor->m_pLastWindow) {
|
||||
@@ -807,7 +793,7 @@ void Events::listener_ackConfigure(void* owner, void* data) {
|
||||
void Events::listener_commitWindow(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11))
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_bIsX11)
|
||||
@@ -825,22 +811,29 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
|
||||
return;
|
||||
|
||||
const auto ISRIGID = PWINDOW->m_uSurface.xdg->toplevel->current.max_height == PWINDOW->m_uSurface.xdg->toplevel->current.min_height &&
|
||||
PWINDOW->m_uSurface.xdg->toplevel->current.max_width == PWINDOW->m_uSurface.xdg->toplevel->current.min_width;
|
||||
const auto MINSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.min_width, PWINDOW->m_uSurface.xdg->toplevel->current.min_height};
|
||||
const auto MAXSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.max_width, PWINDOW->m_uSurface.xdg->toplevel->current.max_height};
|
||||
|
||||
if (!ISRIGID)
|
||||
if (MAXSIZE < Vector2D{1, 1})
|
||||
return;
|
||||
|
||||
const Vector2D REQUESTEDSIZE = {PWINDOW->m_uSurface.xdg->toplevel->current.max_width, PWINDOW->m_uSurface.xdg->toplevel->current.max_height};
|
||||
const auto REALSIZE = PWINDOW->m_vRealSize.goalv();
|
||||
Vector2D newSize = REALSIZE;
|
||||
|
||||
if (REQUESTEDSIZE == PWINDOW->m_vReportedSize || REQUESTEDSIZE.x < 5 || REQUESTEDSIZE.y < 5)
|
||||
return;
|
||||
if (MAXSIZE.x < newSize.x)
|
||||
newSize.x = MAXSIZE.x;
|
||||
if (MAXSIZE.y < newSize.y)
|
||||
newSize.y = MAXSIZE.y;
|
||||
if (MINSIZE.x > newSize.x)
|
||||
newSize.x = MINSIZE.x;
|
||||
if (MINSIZE.y > newSize.y)
|
||||
newSize.y = MINSIZE.y;
|
||||
|
||||
const Vector2D DELTA = PWINDOW->m_vReportedSize - REQUESTEDSIZE;
|
||||
const Vector2D DELTA = REALSIZE - newSize;
|
||||
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0;
|
||||
PWINDOW->m_vRealSize = REQUESTEDSIZE;
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, REQUESTEDSIZE, true);
|
||||
PWINDOW->m_vRealSize = newSize;
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true);
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
}
|
||||
|
||||
@@ -857,6 +850,7 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||
g_pCompositor->m_pLastFocus = nullptr;
|
||||
}
|
||||
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
PWINDOW->hyprListener_mapWindow.removeCallback();
|
||||
PWINDOW->hyprListener_unmapWindow.removeCallback();
|
||||
PWINDOW->hyprListener_destroyWindow.removeCallback();
|
||||
@@ -1032,9 +1026,10 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
|
||||
const auto E = (wlr_xwayland_surface_configure_event*)data;
|
||||
|
||||
if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bMappedX11) {
|
||||
if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bIsMapped) {
|
||||
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
PWINDOW->m_vPendingReportedSize = {E->width, E->height};
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1071,6 +1066,14 @@ 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};
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
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;
|
||||
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
@@ -1081,16 +1084,12 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
g_pInputManager->refocus();
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
}
|
||||
|
||||
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
if (!PWINDOW->m_bMappedX11)
|
||||
if (!PWINDOW->m_bIsMapped)
|
||||
return;
|
||||
|
||||
const auto POS = PWINDOW->m_vRealPosition.goalv();
|
||||
@@ -1138,6 +1137,10 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1153,12 +1156,14 @@ void Events::listener_associateX11(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW, "XWayland Window");
|
||||
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XWayland Window");
|
||||
}
|
||||
|
||||
void Events::listener_dissociateX11(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
PWINDOW->hyprListener_mapWindow.removeCallback();
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
}
|
||||
|
||||
void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
|
||||
@@ -1183,20 +1188,19 @@ void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
|
||||
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW, "XWayland Window");
|
||||
}
|
||||
|
||||
void Events::listener_newXDGSurface(wl_listener* listener, void* data) {
|
||||
void Events::listener_newXDGToplevel(wl_listener* listener, void* data) {
|
||||
// A window got opened
|
||||
const auto XDGSURFACE = (wlr_xdg_surface*)data;
|
||||
const auto XDGTOPLEVEL = (wlr_xdg_toplevel*)data;
|
||||
const auto XDGSURFACE = XDGTOPLEVEL->base;
|
||||
|
||||
if (XDGSURFACE->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "New XDG Surface created. (class: {})", XDGSURFACE->toplevel->app_id ? XDGSURFACE->toplevel->app_id : "null");
|
||||
Debug::log(LOG, "New XDG Toplevel created. (class: {})", XDGSURFACE->toplevel->app_id ? XDGSURFACE->toplevel->app_id : "null");
|
||||
|
||||
const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(std::make_unique<CWindow>()).get();
|
||||
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
|
||||
|
||||
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->surface->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window");
|
||||
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XDGSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XDG Window");
|
||||
PNEWWINDOW->hyprListener_commitWindow.initCallback(&XDGSURFACE->surface->events.commit, &Events::listener_commitWindow, PNEWWINDOW, "XDG Window");
|
||||
}
|
||||
|
||||
void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
|
||||
@@ -1219,7 +1223,7 @@ void Events::listener_requestMaximize(void* owner, void* data) {
|
||||
|
||||
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
|
||||
} else {
|
||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
|
||||
return;
|
||||
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED);
|
||||
@@ -1232,7 +1236,7 @@ void Events::listener_requestMinimize(void* owner, void* data) {
|
||||
Debug::log(LOG, "Minimize request for {}", PWINDOW);
|
||||
|
||||
if (PWINDOW->m_bIsX11) {
|
||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
|
||||
return;
|
||||
|
||||
const auto E = (wlr_xwayland_minimize_event*)data;
|
||||
|
@@ -8,16 +8,14 @@
|
||||
#include "../macros.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
|
||||
enum ANIMATEDVARTYPE
|
||||
{
|
||||
enum ANIMATEDVARTYPE {
|
||||
AVARTYPE_INVALID = -1,
|
||||
AVARTYPE_FLOAT,
|
||||
AVARTYPE_VECTOR,
|
||||
AVARTYPE_COLOR
|
||||
};
|
||||
|
||||
enum AVARDAMAGEPOLICY
|
||||
{
|
||||
enum AVARDAMAGEPOLICY {
|
||||
AVARDAMAGE_NONE = -1,
|
||||
AVARDAMAGE_ENTIRE = 0,
|
||||
AVARDAMAGE_BORDER,
|
||||
@@ -37,10 +35,10 @@ class CAnimatedVariable {
|
||||
void create(ANIMATEDVARTYPE, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
|
||||
void create(ANIMATEDVARTYPE, std::any val, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
|
||||
|
||||
CAnimatedVariable(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable(CAnimatedVariable&&) = delete;
|
||||
CAnimatedVariable(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable(CAnimatedVariable&&) = delete;
|
||||
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
|
||||
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
|
||||
|
||||
~CAnimatedVariable();
|
||||
|
||||
|
@@ -112,6 +112,10 @@ CBox CBox::roundInternal() {
|
||||
return CBox{std::floor(x), std::floor(y), std::floor(newW), std::floor(newH)};
|
||||
}
|
||||
|
||||
CBox CBox::copy() const {
|
||||
return CBox{*this};
|
||||
}
|
||||
|
||||
Vector2D CBox::pos() const {
|
||||
return {x, y};
|
||||
}
|
||||
|
@@ -52,6 +52,8 @@ class CBox {
|
||||
CBox& addExtents(const SWindowDecorationExtents& e);
|
||||
CBox& expand(const double& value);
|
||||
|
||||
CBox copy() const;
|
||||
|
||||
SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box
|
||||
|
||||
Vector2D middle() const;
|
||||
|
@@ -204,12 +204,12 @@ std::string removeBeginEndSpacesTabs(std::string str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
float getPlusMinusKeywordResult(std::string source, float relative) {
|
||||
std::optional<float> getPlusMinusKeywordResult(std::string source, float relative) {
|
||||
try {
|
||||
return relative + stof(source);
|
||||
} catch (...) {
|
||||
Debug::log(ERR, "Invalid arg \"{}\" in getPlusMinusKeywordResult!", source);
|
||||
return INT_MAX;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ bool isDirection(const char& arg) {
|
||||
}
|
||||
|
||||
int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
int result = INT_MAX;
|
||||
int result = WORKSPACE_INVALID;
|
||||
if (in.starts_with("special")) {
|
||||
outName = "special";
|
||||
|
||||
@@ -280,17 +280,17 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
}
|
||||
} else if (in.starts_with("prev")) {
|
||||
if (!g_pCompositor->m_pLastMonitor)
|
||||
return INT_MAX;
|
||||
return WORKSPACE_INVALID;
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
|
||||
|
||||
if (!PWORKSPACE)
|
||||
return INT_MAX;
|
||||
return WORKSPACE_INVALID;
|
||||
|
||||
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.iID);
|
||||
|
||||
if (!PLASTWORKSPACE)
|
||||
return INT_MAX;
|
||||
return WORKSPACE_INVALID;
|
||||
|
||||
outName = PLASTWORKSPACE->m_szName;
|
||||
return PLASTWORKSPACE->m_iID;
|
||||
@@ -298,10 +298,15 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
if (in[0] == 'r' && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||
if (!g_pCompositor->m_pLastMonitor) {
|
||||
Debug::log(ERR, "Relative monitor workspace on monitor null!");
|
||||
result = INT_MAX;
|
||||
return result;
|
||||
return WORKSPACE_INVALID;
|
||||
}
|
||||
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
|
||||
|
||||
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in.substr(1), 0);
|
||||
|
||||
if (!PLUSMINUSRESULT.has_value())
|
||||
return WORKSPACE_INVALID;
|
||||
|
||||
result = (int)PLUSMINUSRESULT.value();
|
||||
|
||||
int remains = (int)result;
|
||||
|
||||
@@ -433,12 +438,16 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor) {
|
||||
Debug::log(ERR, "Relative monitor workspace on monitor null!");
|
||||
result = INT_MAX;
|
||||
return result;
|
||||
return WORKSPACE_INVALID;
|
||||
}
|
||||
|
||||
// monitor relative
|
||||
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
|
||||
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in.substr(1), 0);
|
||||
|
||||
if (!PLUSMINUSRESULT.has_value())
|
||||
return WORKSPACE_INVALID;
|
||||
|
||||
result = (int)PLUSMINUSRESULT.value();
|
||||
|
||||
// result now has +/- what we should move on mon
|
||||
int remains = (int)result;
|
||||
@@ -479,11 +488,15 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName;
|
||||
} else {
|
||||
if (in[0] == '+' || in[0] == '-') {
|
||||
if (g_pCompositor->m_pLastMonitor)
|
||||
result = std::max((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1);
|
||||
else {
|
||||
if (g_pCompositor->m_pLastMonitor) {
|
||||
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace);
|
||||
if (!PLUSMINUSRESULT.has_value())
|
||||
return WORKSPACE_INVALID;
|
||||
|
||||
result = std::max((int)PLUSMINUSRESULT.value(), 1);
|
||||
} else {
|
||||
Debug::log(ERR, "Relative workspace on no mon!");
|
||||
result = INT_MAX;
|
||||
return WORKSPACE_INVALID;
|
||||
}
|
||||
} else if (isNumber(in))
|
||||
result = std::max(std::stoi(in), 1);
|
||||
@@ -564,10 +577,10 @@ void logSystemInfo() {
|
||||
|
||||
uname(&unameInfo);
|
||||
|
||||
Debug::log(LOG, "System name: {}", unameInfo.sysname);
|
||||
Debug::log(LOG, "Node name: {}", unameInfo.nodename);
|
||||
Debug::log(LOG, "Release: {}", unameInfo.release);
|
||||
Debug::log(LOG, "Version: {}", unameInfo.version);
|
||||
Debug::log(LOG, "System name: {}", std::string{unameInfo.sysname});
|
||||
Debug::log(LOG, "Node name: {}", std::string{unameInfo.nodename});
|
||||
Debug::log(LOG, "Release: {}", std::string{unameInfo.release});
|
||||
Debug::log(LOG, "Version: {}", std::string{unameInfo.version});
|
||||
|
||||
Debug::log(NONE, "\n");
|
||||
|
||||
@@ -695,6 +708,10 @@ int64_t configStringToInt(const std::string& VALUE) {
|
||||
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (VALUE.empty() || !isNumber(VALUE))
|
||||
return 0;
|
||||
|
||||
return std::stoll(VALUE);
|
||||
}
|
||||
|
||||
@@ -764,4 +781,21 @@ uint32_t drmFormatToGL(uint32_t drm) {
|
||||
}
|
||||
UNREACHABLE();
|
||||
return GL_RGBA;
|
||||
}
|
||||
|
||||
uint32_t glFormatToType(uint32_t gl) {
|
||||
return gl != GL_RGBA ?
|
||||
#ifdef GLES2
|
||||
GL_UNSIGNED_INT_2_10_10_10_REV_EXT :
|
||||
#else
|
||||
GL_UNSIGNED_INT_2_10_10_10_REV :
|
||||
#endif
|
||||
GL_UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
bool envEnabled(const std::string& env) {
|
||||
const auto ENV = getenv(env.c_str());
|
||||
if (!ENV)
|
||||
return false;
|
||||
return std::string(ENV) == "1";
|
||||
}
|
@@ -27,13 +27,15 @@ void logSystemInfo();
|
||||
std::string execAndGet(const char*);
|
||||
int64_t getPPIDof(int64_t pid);
|
||||
int64_t configStringToInt(const std::string&);
|
||||
float getPlusMinusKeywordResult(std::string in, float relative);
|
||||
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
|
||||
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
|
||||
double normalizeAngleRad(double ang);
|
||||
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
|
||||
std::vector<SCallstackFrameInfo> getBacktrace();
|
||||
void throwError(const std::string& err);
|
||||
uint32_t drmFormatToGL(uint32_t drm);
|
||||
uint32_t glFormatToType(uint32_t gl);
|
||||
bool envEnabled(const std::string& env);
|
||||
|
||||
template <typename... Args>
|
||||
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {
|
||||
|
@@ -50,6 +50,10 @@ void CMonitor::onConnect(bool noRule) {
|
||||
|
||||
szName = output->name;
|
||||
|
||||
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());
|
||||
|
||||
if (!wlr_backend_is_drm(output->backend))
|
||||
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
|
||||
|
||||
@@ -188,7 +192,7 @@ void CMonitor::onConnect(bool noRule) {
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
}
|
||||
|
||||
void CMonitor::onDisconnect() {
|
||||
void CMonitor::onDisconnect(bool destroy) {
|
||||
|
||||
if (renderTimer) {
|
||||
wl_event_source_remove(renderTimer);
|
||||
@@ -276,7 +280,8 @@ void CMonitor::onDisconnect() {
|
||||
|
||||
activeWorkspace = -1;
|
||||
|
||||
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
|
||||
if (!destroy)
|
||||
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
|
||||
|
||||
wlr_output_enable(output, false);
|
||||
|
||||
@@ -298,7 +303,6 @@ void CMonitor::onDisconnect() {
|
||||
|
||||
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
|
||||
}
|
||||
|
||||
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
|
||||
}
|
||||
|
||||
@@ -353,7 +357,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
|
||||
findAvailableDefaultWS() :
|
||||
getWorkspaceIDFromString(g_pConfigManager->getDefaultWorkspaceFor(szName), newDefaultWorkspaceName);
|
||||
|
||||
if (WORKSPACEID == INT_MAX || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) {
|
||||
if (WORKSPACEID == WORKSPACE_INVALID || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) {
|
||||
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
|
||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||
|
||||
@@ -529,24 +533,24 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
||||
}
|
||||
}
|
||||
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
if (!g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
CWindow* pWindow = pWorkspace->getLastFocusedWindow();
|
||||
|
||||
if (const auto PLASTWINDOW = pWorkspace->getLastFocusedWindow(); PLASTWINDOW)
|
||||
g_pCompositor->focusWindow(PLASTWINDOW);
|
||||
else {
|
||||
CWindow* pWindow = nullptr;
|
||||
if (!pWindow) {
|
||||
if (*PFOLLOWMOUSE == 1)
|
||||
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
|
||||
|
||||
if (*PFOLLOWMOUSE == 1)
|
||||
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
|
||||
if (!pWindow)
|
||||
pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
|
||||
|
||||
if (!pWindow)
|
||||
pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
|
||||
|
||||
if (!pWindow)
|
||||
pWindow = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
|
||||
if (!pWindow)
|
||||
pWindow = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
|
||||
}
|
||||
|
||||
g_pCompositor->focusWindow(pWindow);
|
||||
}
|
||||
|
||||
if (!noMouseMove)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
@@ -561,6 +565,8 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
||||
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
|
||||
|
||||
g_pConfigManager->ensureVRR(this);
|
||||
|
||||
g_pCompositor->updateSuspendedStates();
|
||||
}
|
||||
|
||||
void CMonitor::changeWorkspace(const int& id, bool internal) {
|
||||
@@ -586,6 +592,8 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
|
||||
g_pCompositor->updateSuspendedStates();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -614,6 +622,22 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
|
||||
w->m_iMonitorID = ID;
|
||||
w->updateSurfaceOutputs();
|
||||
|
||||
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();
|
||||
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;
|
||||
} else
|
||||
pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition;
|
||||
|
||||
w->m_vRealPosition = pos;
|
||||
w->m_vPosition = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,6 +651,8 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
|
||||
|
||||
g_pHyprRenderer->damageMonitor(this);
|
||||
|
||||
g_pCompositor->updateSuspendedStates();
|
||||
}
|
||||
|
||||
void CMonitor::setSpecialWorkspace(const int& id) {
|
||||
@@ -642,4 +668,13 @@ void CMonitor::moveTo(const Vector2D& pos) {
|
||||
|
||||
Vector2D CMonitor::middle() {
|
||||
return vecPosition + vecSize / 2.f;
|
||||
}
|
||||
}
|
||||
|
||||
void CMonitor::updateMatrix() {
|
||||
wlr_matrix_identity(projMatrix.data());
|
||||
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
|
||||
wlr_matrix_translate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
|
||||
wlr_matrix_transform(projMatrix.data(), transform);
|
||||
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
|
||||
}
|
||||
}
|
||||
|
@@ -40,9 +40,11 @@ class CMonitor {
|
||||
|
||||
uint64_t ID = -1;
|
||||
int activeWorkspace = -1;
|
||||
float scale = 1;
|
||||
float setScale = 1; // scale set by cfg
|
||||
float scale = 1; // real scale
|
||||
|
||||
std::string szName = "";
|
||||
std::string szName = "";
|
||||
std::string szDescription = "";
|
||||
|
||||
Vector2D vecReservedTopLeft = Vector2D(0, 0);
|
||||
Vector2D vecReservedBottomRight = Vector2D(0, 0);
|
||||
@@ -50,32 +52,33 @@ class CMonitor {
|
||||
drmModeModeInfo customDrmMode = {};
|
||||
|
||||
// WLR stuff
|
||||
wlr_damage_ring damage;
|
||||
wlr_output* output = nullptr;
|
||||
float refreshRate = 60;
|
||||
int framesToSkip = 0;
|
||||
int forceFullFrames = 0;
|
||||
bool noFrameSchedule = false;
|
||||
bool scheduledRecalc = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
bool gammaChanged = false;
|
||||
float xwaylandScale = 1.f;
|
||||
wlr_damage_ring damage;
|
||||
wlr_output* output = nullptr;
|
||||
float refreshRate = 60;
|
||||
int framesToSkip = 0;
|
||||
int forceFullFrames = 0;
|
||||
bool noFrameSchedule = false;
|
||||
bool scheduledRecalc = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
bool gammaChanged = false;
|
||||
float xwaylandScale = 1.f;
|
||||
std::array<float, 9> projMatrix = {0};
|
||||
|
||||
bool dpmsStatus = true;
|
||||
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
bool createdByUser = false;
|
||||
uint32_t drmFormat = DRM_FORMAT_INVALID;
|
||||
bool isUnsafeFallback = false;
|
||||
bool dpmsStatus = true;
|
||||
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
bool createdByUser = false;
|
||||
uint32_t drmFormat = DRM_FORMAT_INVALID;
|
||||
bool isUnsafeFallback = false;
|
||||
|
||||
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||
bool renderingActive = false;
|
||||
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||
bool renderingActive = false;
|
||||
|
||||
wl_event_source* renderTimer = nullptr; // for RAT
|
||||
bool RATScheduled = false;
|
||||
CTimer lastPresentationTimer;
|
||||
wl_event_source* renderTimer = nullptr; // for RAT
|
||||
bool RATScheduled = false;
|
||||
CTimer lastPresentationTimer;
|
||||
|
||||
SMonitorRule activeMonitorRule;
|
||||
SMonitorRule activeMonitorRule;
|
||||
|
||||
// mirroring
|
||||
CMonitor* pMirrorOf = nullptr;
|
||||
@@ -110,7 +113,7 @@ class CMonitor {
|
||||
|
||||
// methods
|
||||
void onConnect(bool noRule);
|
||||
void onDisconnect();
|
||||
void onDisconnect(bool destroy = false);
|
||||
void addDamage(const pixman_region32_t* rg);
|
||||
void addDamage(const CRegion* rg);
|
||||
void addDamage(const CBox* box);
|
||||
@@ -123,6 +126,7 @@ class CMonitor {
|
||||
void setSpecialWorkspace(const int& id);
|
||||
void moveTo(const Vector2D& pos);
|
||||
Vector2D middle();
|
||||
void updateMatrix();
|
||||
|
||||
bool m_bEnabled = false;
|
||||
bool m_bRenderingInitPassed = false;
|
||||
|
@@ -88,11 +88,25 @@ CRegion& CRegion::invert(pixman_box32_t* box) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::invert(const CBox& box) {
|
||||
pixman_box32 pixmanBox = {box.x, box.y, box.w + box.x, box.h + box.y};
|
||||
return this->invert(&pixmanBox);
|
||||
}
|
||||
|
||||
CRegion& CRegion::translate(const Vector2D& vec) {
|
||||
pixman_region32_translate(&m_rRegion, vec.x, vec.y);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::transform(const wl_output_transform t, double w, double h) {
|
||||
wlr_region_transform(&m_rRegion, &m_rRegion, t, w, h);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion CRegion::copy() const {
|
||||
return CRegion(*this);
|
||||
}
|
||||
|
||||
CRegion& CRegion::scale(float scale) {
|
||||
wlr_region_scale(&m_rRegion, &m_rRegion, scale);
|
||||
return *this;
|
||||
|
@@ -45,12 +45,15 @@ class CRegion {
|
||||
CRegion& intersect(const CRegion& other);
|
||||
CRegion& intersect(double x, double y, double w, double h);
|
||||
CRegion& translate(const Vector2D& vec);
|
||||
CRegion& transform(const wl_output_transform t, double w, double h);
|
||||
CRegion& invert(pixman_box32_t* box);
|
||||
CRegion& invert(const CBox& box);
|
||||
CRegion& scale(float scale);
|
||||
CBox getExtents();
|
||||
bool containsPoint(const Vector2D& vec) const;
|
||||
bool empty() const;
|
||||
Vector2D closestPoint(const Vector2D& vec) const;
|
||||
CRegion copy() const;
|
||||
|
||||
std::vector<pixman_box32_t> getRects() const;
|
||||
|
||||
|
@@ -220,6 +220,8 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
|
||||
|
||||
// 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);
|
||||
@@ -244,9 +246,13 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
|
||||
}
|
||||
}
|
||||
|
||||
if (pNode->pSurface && pNode->pSurface->exists())
|
||||
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.
|
||||
@@ -269,6 +275,8 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@@ -26,6 +26,8 @@ struct SSurfaceTreeNode {
|
||||
void* globalOffsetData;
|
||||
CWindow* pWindowOwner = nullptr;
|
||||
|
||||
Vector2D lastSize;
|
||||
|
||||
//
|
||||
bool operator==(const SSurfaceTreeNode& rhs) const {
|
||||
return pSurface == rhs.pSurface;
|
||||
|
@@ -50,6 +50,15 @@ class CVarList {
|
||||
return m_vArgs.end();
|
||||
}
|
||||
|
||||
bool contains(const std::string& el) {
|
||||
for (auto& a : m_vArgs) {
|
||||
if (a == el)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_vArgs;
|
||||
};
|
@@ -25,10 +25,10 @@ class Vector2D {
|
||||
Vector2D operator-() const {
|
||||
return Vector2D(-this->x, -this->y);
|
||||
}
|
||||
Vector2D operator*(const float& a) const {
|
||||
Vector2D operator*(const double& a) const {
|
||||
return Vector2D(this->x * a, this->y * a);
|
||||
}
|
||||
Vector2D operator/(const float& a) const {
|
||||
Vector2D operator/(const double& a) const {
|
||||
return Vector2D(this->x / a, this->y / a);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,36 @@ class Vector2D {
|
||||
bool operator<(const Vector2D& a) const {
|
||||
return this->x < a.x && this->y < a.y;
|
||||
}
|
||||
Vector2D& operator+=(const Vector2D& a) {
|
||||
this->x += a.x;
|
||||
this->y += a.y;
|
||||
return *this;
|
||||
}
|
||||
Vector2D& operator-=(const Vector2D& a) {
|
||||
this->x -= a.x;
|
||||
this->y -= a.y;
|
||||
return *this;
|
||||
}
|
||||
Vector2D& operator*=(const Vector2D& a) {
|
||||
this->x *= a.x;
|
||||
this->y *= a.y;
|
||||
return *this;
|
||||
}
|
||||
Vector2D& operator/=(const Vector2D& a) {
|
||||
this->x /= a.x;
|
||||
this->y /= a.y;
|
||||
return *this;
|
||||
}
|
||||
Vector2D& operator*=(const double& a) {
|
||||
this->x *= a;
|
||||
this->y *= a;
|
||||
return *this;
|
||||
}
|
||||
Vector2D& operator/=(const double& a) {
|
||||
this->x /= a;
|
||||
this->y /= a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double distance(const Vector2D& other) const;
|
||||
double size() const;
|
||||
|
@@ -8,6 +8,14 @@ SLayerSurface::SLayerSurface() {
|
||||
alpha.registerVar();
|
||||
}
|
||||
|
||||
SLayerSurface::~SLayerSurface() {
|
||||
if (!g_pHyprOpenGL)
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first == this; });
|
||||
}
|
||||
|
||||
void SLayerSurface::applyRules() {
|
||||
noAnimations = false;
|
||||
forceBlur = false;
|
||||
|
@@ -16,6 +16,7 @@ struct SLayerRule {
|
||||
|
||||
struct SLayerSurface {
|
||||
SLayerSurface();
|
||||
~SLayerSurface();
|
||||
|
||||
void applyRules();
|
||||
|
||||
@@ -96,6 +97,8 @@ struct SRenderData {
|
||||
|
||||
// for calculating UV
|
||||
CWindow* pWindow = nullptr;
|
||||
|
||||
bool popup = false;
|
||||
};
|
||||
|
||||
struct SExtensionFindingData {
|
||||
@@ -179,7 +182,8 @@ struct SConstraint {
|
||||
Vector2D getLogicConstraintPos();
|
||||
Vector2D getLogicConstraintSize();
|
||||
|
||||
bool operator==(const SConstraint& b) const {
|
||||
//
|
||||
bool operator==(const SConstraint& b) const {
|
||||
return constraint == b.constraint;
|
||||
}
|
||||
};
|
||||
@@ -251,6 +255,8 @@ struct STablet {
|
||||
wlr_tablet_v2_tablet* wlrTabletV2 = nullptr;
|
||||
wlr_input_device* wlrDevice = nullptr;
|
||||
|
||||
bool relativeInput = false;
|
||||
|
||||
std::string name = "";
|
||||
|
||||
//
|
||||
|
@@ -65,7 +65,7 @@ void CWLSurface::destroy() {
|
||||
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
|
||||
g_pInputManager->m_pLastMouseSurface = nullptr;
|
||||
if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
|
||||
g_pInputManager->setCursorImageOverride("left_ptr");
|
||||
g_pHyprRenderer->m_sLastCursorData.surf.reset();
|
||||
|
||||
m_pWLRSurface = nullptr;
|
||||
|
||||
|
@@ -13,10 +13,10 @@ class CWLSurface {
|
||||
void assign(wlr_surface* pSurface);
|
||||
void unassign();
|
||||
|
||||
CWLSurface(const CWLSurface&) = delete;
|
||||
CWLSurface(CWLSurface&&) = delete;
|
||||
CWLSurface(const CWLSurface&) = delete;
|
||||
CWLSurface(CWLSurface&&) = delete;
|
||||
CWLSurface& operator=(const CWLSurface&) = delete;
|
||||
CWLSurface& operator=(CWLSurface&&) = delete;
|
||||
CWLSurface& operator=(CWLSurface&&) = delete;
|
||||
|
||||
wlr_surface* wlr() const;
|
||||
bool exists() const;
|
||||
|
@@ -38,7 +38,8 @@ CWorkspace::~CWorkspace() {
|
||||
}
|
||||
|
||||
void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
|
||||
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
|
||||
const auto PWORKSPACEGAP = &g_pConfigManager->getConfigValuePtr("general:gaps_workspaces")->intValue;
|
||||
|
||||
if (ANIMSTYLE.starts_with("slidefade")) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
@@ -89,27 +90,29 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||
}
|
||||
} else if (ANIMSTYLE == "slidevert") {
|
||||
// fallback is slide
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
|
||||
|
||||
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
|
||||
|
||||
if (in) {
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y));
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? YDISTANCE : -YDISTANCE));
|
||||
m_vRenderOffset = Vector2D(0, 0);
|
||||
} else {
|
||||
m_vRenderOffset = Vector2D(0, left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y);
|
||||
m_vRenderOffset = Vector2D(0, left ? -YDISTANCE : YDISTANCE);
|
||||
}
|
||||
} else {
|
||||
// fallback is slide
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
|
||||
|
||||
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
|
||||
|
||||
if (in) {
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D(left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x, 0));
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0));
|
||||
m_vRenderOffset = Vector2D(0, 0);
|
||||
} else {
|
||||
m_vRenderOffset = Vector2D(left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x, 0);
|
||||
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -28,8 +28,7 @@ typedef struct {
|
||||
} xcb_size_hints_t;
|
||||
typedef unsigned int xcb_window_t;
|
||||
|
||||
typedef enum xcb_stack_mode_t
|
||||
{
|
||||
typedef enum xcb_stack_mode_t {
|
||||
XCB_STACK_MODE_ABOVE = 0,
|
||||
XCB_STACK_MODE_BELOW = 1,
|
||||
XCB_STACK_MODE_TOP_IF = 2,
|
||||
|
@@ -27,7 +27,7 @@
|
||||
// pthread first because it uses class in a C++ way and XWayland includes that...
|
||||
#include <pthread.h>
|
||||
|
||||
#define class _class
|
||||
#define class _class
|
||||
#define namespace _namespace
|
||||
#define static
|
||||
#define delete delete_
|
||||
@@ -70,7 +70,6 @@ extern "C" {
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/types/wlr_subcompositor.h>
|
||||
#include <wlr/types/wlr_damage_ring.h>
|
||||
#include <wlr/types/wlr_input_inhibitor.h>
|
||||
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
|
||||
#include <wlr/types/wlr_virtual_pointer_v1.h>
|
||||
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
|
||||
@@ -106,6 +105,9 @@ extern "C" {
|
||||
#include <wlr/types/wlr_cursor_shape_v1.h>
|
||||
#include <wlr/types/wlr_tearing_control_v1.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/transform.h>
|
||||
#include <wlr/render/swapchain.h>
|
||||
#include <wlr/render/egl.h>
|
||||
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
|
||||
|
@@ -5,8 +5,8 @@ bool Init::isSudo() {
|
||||
}
|
||||
|
||||
void Init::gainRealTime() {
|
||||
const int minPrio = sched_get_priority_min(SCHED_RR);
|
||||
int old_policy;
|
||||
const int minPrio = sched_get_priority_min(SCHED_RR);
|
||||
int old_policy;
|
||||
struct sched_param param;
|
||||
|
||||
if (pthread_getschedparam(pthread_self(), &old_policy, ¶m)) {
|
||||
|
@@ -149,24 +149,20 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
PWINDOW->m_sSpecialRenderData.rounding = false;
|
||||
PWINDOW->m_sSpecialRenderData.shadow = false;
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
const auto RESERVED = PWINDOW->getFullWindowReservedArea();
|
||||
|
||||
const int BORDERSIZE = PWINDOW->getRealBorderSize();
|
||||
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE) + RESERVED.topLeft;
|
||||
PWINDOW->m_vRealSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE) - (RESERVED.topLeft + RESERVED.bottomRight);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft;
|
||||
PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight);
|
||||
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const int BORDERSIZE = PWINDOW->getRealBorderSize();
|
||||
|
||||
auto calcPos = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE);
|
||||
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
|
||||
auto calcPos = PWINDOW->m_vPosition;
|
||||
auto calcSize = PWINDOW->m_vSize;
|
||||
|
||||
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut : gapsIn, DISPLAYTOP ? gapsOut : gapsIn);
|
||||
|
||||
@@ -258,10 +254,11 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
||||
|
||||
const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
|
||||
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);
|
||||
const auto TARGETCOORDS = PMONITOR->ID == MONFROMCURSOR->ID && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR) ? pWindow->middle() : MOUSECOORDS;
|
||||
|
||||
if (PMONITOR->ID == MONFROMCURSOR->ID &&
|
||||
(PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(MOUSECOORDS));
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS));
|
||||
|
||||
// happens on reserved area
|
||||
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
|
||||
@@ -272,7 +269,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
||||
g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
|
||||
} else {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(MOUSECOORDS));
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS));
|
||||
}
|
||||
|
||||
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
|
||||
@@ -319,16 +316,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
||||
}
|
||||
|
||||
if (!m_vOverrideFocalPoint && g_pInputManager->m_bWasDraggingWindow) {
|
||||
for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
|
||||
if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow))
|
||||
return;
|
||||
}
|
||||
|
||||
// if it's a group, add the window
|
||||
@@ -403,15 +392,15 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
||||
const auto br = NEWPARENT->box.pos() + NEWPARENT->box.size();
|
||||
const auto cc = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
|
||||
|
||||
if (MOUSECOORDS.inTriangle(tl, tr, cc)) {
|
||||
if (TARGETCOORDS.inTriangle(tl, tr, cc)) {
|
||||
NEWPARENT->splitTop = true;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
} else if (MOUSECOORDS.inTriangle(tr, cc, br)) {
|
||||
} else if (TARGETCOORDS.inTriangle(tr, cc, br)) {
|
||||
NEWPARENT->splitTop = false;
|
||||
NEWPARENT->children[0] = OPENINGON;
|
||||
NEWPARENT->children[1] = PNODE;
|
||||
} else if (MOUSECOORDS.inTriangle(br, bl, cc)) {
|
||||
} else if (TARGETCOORDS.inTriangle(br, bl, cc)) {
|
||||
NEWPARENT->splitTop = true;
|
||||
NEWPARENT->children[0] = OPENINGON;
|
||||
NEWPARENT->children[1] = PNODE;
|
||||
@@ -422,9 +411,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
||||
}
|
||||
} else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
|
||||
if ((SIDEBYSIDE &&
|
||||
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
|
||||
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
|
||||
(!SIDEBYSIDE &&
|
||||
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
|
||||
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
|
||||
// we are hovering over the first node, make PNODE first.
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
@@ -1048,7 +1037,7 @@ std::string CHyprDwindleLayout::getLayoutName() {
|
||||
|
||||
void CHyprDwindleLayout::onEnable() {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->isHidden())
|
||||
if (w->m_bIsFloating || !w->m_bIsMapped || w->isHidden())
|
||||
continue;
|
||||
|
||||
onWindowCreatedTiling(w.get());
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "IHyprLayout.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
|
||||
void IHyprLayout::onWindowCreated(CWindow* pWindow, eDirection direction) {
|
||||
if (pWindow->m_bIsFloating) {
|
||||
@@ -35,15 +36,15 @@ void IHyprLayout::onWindowRemoved(CWindow* pWindow) {
|
||||
const auto WINDOWISVISIBLE = pWindow->getGroupCurrent() == pWindow;
|
||||
|
||||
if (WINDOWISVISIBLE)
|
||||
PWINDOWPREV->setGroupCurrent(PWINDOWPREV);
|
||||
PWINDOWPREV->setGroupCurrent(pWindow->m_sGroupData.head ? pWindow->m_sGroupData.pNextWindow : PWINDOWPREV);
|
||||
|
||||
PWINDOWPREV->m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow;
|
||||
|
||||
pWindow->m_sGroupData.pNextWindow = nullptr;
|
||||
|
||||
if (pWindow->m_sGroupData.head) {
|
||||
std::swap(PWINDOWPREV->m_sGroupData.head, pWindow->m_sGroupData.head);
|
||||
std::swap(PWINDOWPREV->m_sGroupData.locked, pWindow->m_sGroupData.locked);
|
||||
std::swap(PWINDOWPREV->m_sGroupData.pNextWindow->m_sGroupData.head, pWindow->m_sGroupData.head);
|
||||
std::swap(PWINDOWPREV->m_sGroupData.pNextWindow->m_sGroupData.locked, pWindow->m_sGroupData.locked);
|
||||
}
|
||||
|
||||
if (pWindow == m_pLastTiledWindow)
|
||||
@@ -264,10 +265,28 @@ void IHyprLayout::onEndDragWindow() {
|
||||
g_pInputManager->refocus();
|
||||
changeWindowFloatingMode(DRAGGINGWINDOW);
|
||||
DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize;
|
||||
} else if (g_pInputManager->dragMode == MBIND_MOVE) {
|
||||
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
|
||||
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS, DRAGGINGWINDOW);
|
||||
|
||||
if (pWindow && pWindow->m_bIsFloating) {
|
||||
if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW))
|
||||
return;
|
||||
|
||||
if (pWindow->m_sGroupData.pNextWindow && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) {
|
||||
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
|
||||
(*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
|
||||
pWindow->setGroupCurrent(DRAGGINGWINDOW);
|
||||
DRAGGINGWINDOW->updateWindowDecos();
|
||||
|
||||
if (!DRAGGINGWINDOW->getDecorationByType(DECORATION_GROUPBAR))
|
||||
DRAGGINGWINDOW->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(DRAGGINGWINDOW));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
|
||||
|
||||
g_pCompositor->focusWindow(DRAGGINGWINDOW);
|
||||
|
||||
g_pInputManager->m_bWasDraggingWindow = false;
|
||||
@@ -427,7 +446,8 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
|
||||
const auto PSAVEDSIZE = pWindow->m_vRealSize.goalv();
|
||||
|
||||
// if the window is pseudo, update its size
|
||||
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv();
|
||||
if (!pWindow->m_bDraggingTiled)
|
||||
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv();
|
||||
|
||||
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
|
||||
|
||||
@@ -537,13 +557,19 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
|
||||
}
|
||||
|
||||
// if it was a tiled window, we first try to find the window that will replace it.
|
||||
const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(pWindow->middle());
|
||||
auto pWindowCandidate = g_pCompositor->vectorToWindowIdeal(pWindow->middle());
|
||||
|
||||
if (!PWINDOWCANDIDATE || pWindow == PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bIsMapped || PWINDOWCANDIDATE->isHidden() || PWINDOWCANDIDATE->m_bX11ShouldntFocus ||
|
||||
PWINDOWCANDIDATE->m_iX11Type == 2 || PWINDOWCANDIDATE->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
|
||||
if (!pWindowCandidate)
|
||||
pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (!pWindowCandidate)
|
||||
pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus ||
|
||||
pWindowCandidate->m_iX11Type == 2 || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
|
||||
return nullptr;
|
||||
|
||||
return PWINDOWCANDIDATE;
|
||||
return pWindowCandidate;
|
||||
}
|
||||
|
||||
bool IHyprLayout::isWindowReachable(CWindow* pWindow) {
|
||||
|
@@ -15,8 +15,7 @@ struct SLayoutMessageHeader {
|
||||
|
||||
enum eFullscreenMode : int8_t;
|
||||
|
||||
enum eRectCorner
|
||||
{
|
||||
enum eRectCorner {
|
||||
CORNER_NONE = 0,
|
||||
CORNER_TOPLEFT,
|
||||
CORNER_TOPRIGHT,
|
||||
@@ -24,8 +23,7 @@ enum eRectCorner
|
||||
CORNER_BOTTOMLEFT
|
||||
};
|
||||
|
||||
enum eDirection
|
||||
{
|
||||
enum eDirection {
|
||||
DIRECTION_DEFAULT = -1,
|
||||
DIRECTION_UP = 0,
|
||||
DIRECTION_RIGHT,
|
||||
|
@@ -42,17 +42,24 @@ SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) {
|
||||
const auto PWORKSPACEDATA = &m_lMasterWorkspacesData.emplace_back();
|
||||
PWORKSPACEDATA->workspaceID = ws;
|
||||
const auto orientation = &g_pConfigManager->getConfigValuePtr("master:orientation")->strValue;
|
||||
if (*orientation == "top") {
|
||||
const auto layoutoptsForWs = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(ws)).layoutopts;
|
||||
auto orientationForWs = *orientation;
|
||||
|
||||
if (layoutoptsForWs.contains("orientation"))
|
||||
orientationForWs = layoutoptsForWs.at("orientation");
|
||||
|
||||
if (orientationForWs == "top") {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_TOP;
|
||||
} else if (*orientation == "right") {
|
||||
} else if (orientationForWs == "right") {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
|
||||
} else if (*orientation == "bottom") {
|
||||
} else if (orientationForWs == "bottom") {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
|
||||
} else if (*orientation == "left") {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
|
||||
} else {
|
||||
} else if (orientationForWs == "center") {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_CENTER;
|
||||
} else {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
|
||||
}
|
||||
|
||||
return PWORKSPACEDATA;
|
||||
}
|
||||
|
||||
@@ -95,16 +102,8 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
|
||||
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||
|
||||
if (g_pInputManager->m_bWasDraggingWindow && OPENINGON) {
|
||||
for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
|
||||
if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow))
|
||||
return;
|
||||
}
|
||||
|
||||
// if it's a group, add the window
|
||||
@@ -659,24 +658,20 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
PWINDOW->m_sSpecialRenderData.rounding = false;
|
||||
PWINDOW->m_sSpecialRenderData.shadow = false;
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
const auto RESERVED = PWINDOW->getFullWindowReservedArea();
|
||||
|
||||
const int BORDERSIZE = PWINDOW->getRealBorderSize();
|
||||
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE) + RESERVED.topLeft;
|
||||
PWINDOW->m_vRealSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE) - (RESERVED.topLeft + RESERVED.bottomRight);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft;
|
||||
PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight);
|
||||
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const int BORDERSIZE = PWINDOW->getRealBorderSize();
|
||||
|
||||
auto calcPos = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE);
|
||||
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
|
||||
auto calcPos = PWINDOW->m_vPosition;
|
||||
auto calcSize = PWINDOW->m_vSize;
|
||||
|
||||
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut : gapsIn, DISPLAYTOP ? gapsOut : gapsIn);
|
||||
|
||||
@@ -1329,6 +1324,50 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
||||
nd.percMaster = std::clamp(newMfact, 0.05f, 0.95f);
|
||||
}
|
||||
}
|
||||
} else if (command == "rollnext") {
|
||||
const auto PWINDOW = header.pWindow;
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
|
||||
const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER);
|
||||
|
||||
for (auto& nd : m_lMasterNodesData) {
|
||||
if (nd.workspaceID == PNODE->workspaceID && !nd.isMaster) {
|
||||
nd.isMaster = true;
|
||||
const auto NEWMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), nd);
|
||||
m_lMasterNodesData.splice(OLDMASTERIT, m_lMasterNodesData, NEWMASTERIT);
|
||||
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
|
||||
switchToWindow(nd.pWindow);
|
||||
prepareNewFocus(nd.pWindow, inheritFullscreen);
|
||||
OLDMASTER->isMaster = false;
|
||||
m_lMasterNodesData.splice(m_lMasterNodesData.end(), m_lMasterNodesData, OLDMASTERIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
recalculateMonitor(PWINDOW->m_iMonitorID);
|
||||
} else if (command == "rollprev") {
|
||||
const auto PWINDOW = header.pWindow;
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
|
||||
const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER);
|
||||
|
||||
for (auto& nd : m_lMasterNodesData | std::views::reverse) {
|
||||
if (nd.workspaceID == PNODE->workspaceID && !nd.isMaster) {
|
||||
nd.isMaster = true;
|
||||
const auto NEWMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), nd);
|
||||
m_lMasterNodesData.splice(OLDMASTERIT, m_lMasterNodesData, NEWMASTERIT);
|
||||
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
|
||||
switchToWindow(nd.pWindow);
|
||||
prepareNewFocus(nd.pWindow, inheritFullscreen);
|
||||
OLDMASTER->isMaster = false;
|
||||
m_lMasterNodesData.splice(m_lMasterNodesData.begin(), m_lMasterNodesData, OLDMASTERIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
recalculateMonitor(PWINDOW->m_iMonitorID);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1404,7 +1443,7 @@ void CHyprMasterLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
|
||||
|
||||
void CHyprMasterLayout::onEnable() {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->isHidden())
|
||||
if (w->m_bIsFloating || !w->m_bIsMapped || w->isHidden())
|
||||
continue;
|
||||
|
||||
onWindowCreatedTiling(w.get());
|
||||
|
@@ -22,6 +22,8 @@
|
||||
|
||||
#define STRVAL_EMPTY "[[EMPTY]]"
|
||||
|
||||
#define WORKSPACE_INVALID -1L
|
||||
|
||||
#define LISTENER(name) \
|
||||
void listener_##name(wl_listener*, void*); \
|
||||
inline wl_listener listen_##name = {.notify = listener_##name}
|
||||
@@ -42,7 +44,7 @@
|
||||
if (!(expr)) { \
|
||||
Debug::log(CRIT, "\n==========================================================================================\nASSERTION FAILED! \n\n{}\n\nat: line {} in {}", \
|
||||
std::format(reason, ##__VA_ARGS__), __LINE__, \
|
||||
([]() constexpr->std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })()); \
|
||||
([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })()); \
|
||||
printf("Assertion failed! See the log in /tmp/hypr/hyprland.log for more info."); \
|
||||
raise(SIGABRT); \
|
||||
}
|
||||
@@ -61,9 +63,7 @@
|
||||
}
|
||||
|
||||
#define FORMAT_FLAG(spec__, flag__) \
|
||||
case spec__: \
|
||||
(flag__) = true; \
|
||||
break;
|
||||
case spec__: (flag__) = true; break;
|
||||
|
||||
#define FORMAT_NUMBER(buf__) \
|
||||
case '0': \
|
||||
@@ -75,9 +75,7 @@
|
||||
case '6': \
|
||||
case '7': \
|
||||
case '8': \
|
||||
case '9': \
|
||||
(buf__).push_back(*it); \
|
||||
break;
|
||||
case '9': (buf__).push_back(*it); break;
|
||||
|
||||
#if ISDEBUG
|
||||
#define UNREACHABLE() \
|
||||
|
16
src/main.cpp
16
src/main.cpp
@@ -52,16 +52,21 @@ int main(int argc, char** argv) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
std::string next_arg = std::next(it)->c_str();
|
||||
configPath = std::next(it)->c_str();
|
||||
|
||||
if (!std::filesystem::exists(next_arg)) {
|
||||
std::cerr << "[ ERROR ] Config path '" << next_arg << "' doesn't exist!\n";
|
||||
try {
|
||||
configPath = std::filesystem::canonical(configPath);
|
||||
|
||||
if (!std::filesystem::is_regular_file(configPath)) {
|
||||
throw std::exception();
|
||||
}
|
||||
} catch (...) {
|
||||
std::cerr << "[ ERROR ] Config file '" << configPath << "' doesn't exist!\n";
|
||||
help();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
configPath = next_arg;
|
||||
Debug::log(LOG, "User-specified config location: '{}'", configPath);
|
||||
|
||||
it++;
|
||||
@@ -97,7 +102,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
g_pCompositor->initServer();
|
||||
|
||||
Init::gainRealTime();
|
||||
if (!envEnabled("HYPRLAND_NO_RT"))
|
||||
Init::gainRealTime();
|
||||
|
||||
Debug::log(LOG, "Hyprland init finished.");
|
||||
|
||||
|
@@ -213,6 +213,12 @@ void CAnimationManager::tick() {
|
||||
continue;
|
||||
|
||||
w->updateWindowDecos();
|
||||
|
||||
if (w->m_bIsFloating) {
|
||||
auto bb = w->getFullWindowBoundingBox();
|
||||
bb.translate(PWORKSPACE->m_vRenderOffset.vec());
|
||||
g_pHyprRenderer->damageBox(&bb);
|
||||
}
|
||||
}
|
||||
} else if (PLAYER) {
|
||||
if (PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
|
||||
@@ -223,6 +229,8 @@ void CAnimationManager::tick() {
|
||||
case AVARDAMAGE_BORDER: {
|
||||
RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!");
|
||||
|
||||
// TODO: move this to the border class
|
||||
|
||||
// damage only the border.
|
||||
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
|
||||
const auto ROUNDINGSIZE = *PROUNDING + 1;
|
||||
|
@@ -20,6 +20,7 @@ class CEventManager {
|
||||
void startThread();
|
||||
|
||||
std::thread m_tThread;
|
||||
|
||||
private:
|
||||
void flushEvents();
|
||||
|
||||
|
@@ -641,11 +641,6 @@ void CKeybindManager::spawn(std::string args) {
|
||||
args = args.substr(args.find_first_of(']') + 1);
|
||||
}
|
||||
|
||||
if (g_pXWaylandManager->m_sWLRXWayland)
|
||||
args = "WAYLAND_DISPLAY=" + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + args;
|
||||
else
|
||||
args = "WAYLAND_DISPLAY=" + std::string(g_pCompositor->m_szWLDisplaySocket) + " " + args;
|
||||
|
||||
const uint64_t PROC = spawnRaw(args);
|
||||
|
||||
if (!RULES.empty()) {
|
||||
@@ -735,11 +730,10 @@ void CKeybindManager::clearKeybinds() {
|
||||
void CKeybindManager::toggleActiveFloating(std::string args) {
|
||||
CWindow* PWINDOW = nullptr;
|
||||
|
||||
if (args != "" && args != "active" && args.length() > 1) {
|
||||
if (args != "" && args != "active" && args.length() > 1)
|
||||
PWINDOW = g_pCompositor->getWindowByRegex(args);
|
||||
} else {
|
||||
else
|
||||
PWINDOW = g_pCompositor->m_pLastWindow;
|
||||
}
|
||||
|
||||
if (!PWINDOW)
|
||||
return;
|
||||
@@ -747,9 +741,6 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
|
||||
// remove drag status
|
||||
g_pInputManager->currentlyDraggedWindow = nullptr;
|
||||
|
||||
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID))
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->m_sGroupData.pNextWindow != PWINDOW) {
|
||||
|
||||
const auto PCURRENT = PWINDOW->getGroupCurrent();
|
||||
@@ -760,6 +751,7 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
|
||||
while (curr != PCURRENT) {
|
||||
curr->m_bIsFloating = PCURRENT->m_bIsFloating;
|
||||
curr->updateDynamicRules();
|
||||
curr->updateSpecialRenderData();
|
||||
curr = curr->m_sGroupData.pNextWindow;
|
||||
}
|
||||
} else {
|
||||
@@ -809,9 +801,13 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
static auto* const PALLOWWORKSPACECYCLES = &g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles")->intValue;
|
||||
static auto* const PWORKSPACECENTERON = &g_pConfigManager->getConfigValuePtr("binds:workspace_center_on")->intValue;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
const bool EXPLICITPREVIOUS = args.starts_with("previous");
|
||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
|
||||
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
const bool EXPLICITPREVIOUS = args.starts_with("previous");
|
||||
|
||||
if (args.starts_with("previous")) {
|
||||
// Do nothing if there's no previous workspace, otherwise switch to it.
|
||||
@@ -831,7 +827,7 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
workspaceToChangeTo = getWorkspaceIDFromString(args, workspaceName);
|
||||
}
|
||||
|
||||
if (workspaceToChangeTo == INT_MAX) {
|
||||
if (workspaceToChangeTo == WORKSPACE_INVALID) {
|
||||
Debug::log(ERR, "Error in changeworkspace, invalid value");
|
||||
return;
|
||||
}
|
||||
@@ -884,10 +880,12 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
} else
|
||||
pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE);
|
||||
|
||||
if (!g_pCompositor->m_pLastFocus)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
else
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
if (!g_pInputManager->m_bLastFocusOnLS) {
|
||||
if (g_pCompositor->m_pLastFocus)
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
else
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
}
|
||||
|
||||
void CKeybindManager::fullscreenActive(std::string args) {
|
||||
@@ -920,7 +918,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
std::string workspaceName;
|
||||
const auto WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
|
||||
|
||||
if (WORKSPACEID == INT_MAX) {
|
||||
if (WORKSPACEID == WORKSPACE_INVALID) {
|
||||
Debug::log(LOG, "Invalid workspace in moveActiveToWorkspace");
|
||||
return;
|
||||
}
|
||||
@@ -949,6 +947,11 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
|
||||
POLDWS->m_pLastFocusedWindow = g_pCompositor->getFirstWindowOnWorkspace(POLDWS->m_iID);
|
||||
|
||||
if (pWorkspace->m_bIsSpecialWorkspace)
|
||||
pMonitor->setSpecialWorkspace(pWorkspace);
|
||||
else if (POLDWS->m_bIsSpecialWorkspace)
|
||||
g_pCompositor->getMonitorFromID(POLDWS->m_iMonitorID)->setSpecialWorkspace(nullptr);
|
||||
|
||||
pMonitor->changeWorkspace(pWorkspace);
|
||||
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
@@ -977,7 +980,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
|
||||
|
||||
const int WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
|
||||
|
||||
if (WORKSPACEID == INT_MAX) {
|
||||
if (WORKSPACEID == WORKSPACE_INVALID) {
|
||||
Debug::log(ERR, "Error in moveActiveToWorkspaceSilent, invalid value");
|
||||
return;
|
||||
}
|
||||
@@ -1216,24 +1219,16 @@ void CKeybindManager::toggleSplit(std::string args) {
|
||||
}
|
||||
|
||||
void CKeybindManager::alterSplitRatio(std::string args) {
|
||||
float splitratio = 0;
|
||||
bool exact = false;
|
||||
std::optional<float> splitResult;
|
||||
bool exact = false;
|
||||
|
||||
if (args == "+" || args == "-") {
|
||||
Debug::log(LOG, "alterSplitRatio: using LEGACY +/-, consider switching to the Hyprland syntax.");
|
||||
splitratio = (args == "+" ? 0.05f : -0.05f);
|
||||
}
|
||||
if (args.starts_with("exact")) {
|
||||
exact = true;
|
||||
splitResult = getPlusMinusKeywordResult(args.substr(5), 0);
|
||||
} else
|
||||
splitResult = getPlusMinusKeywordResult(args, 0);
|
||||
|
||||
if (splitratio == 0) {
|
||||
if (args.starts_with("exact")) {
|
||||
exact = true;
|
||||
splitratio = getPlusMinusKeywordResult(args.substr(5), 0);
|
||||
} else {
|
||||
splitratio = getPlusMinusKeywordResult(args, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (splitratio == INT_MAX) {
|
||||
if (!splitResult.has_value()) {
|
||||
Debug::log(ERR, "Splitratio invalid in alterSplitRatio!");
|
||||
return;
|
||||
}
|
||||
@@ -1243,7 +1238,7 @@ void CKeybindManager::alterSplitRatio(std::string args) {
|
||||
if (!PLASTWINDOW)
|
||||
return;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->alterSplitRatio(PLASTWINDOW, splitratio, exact);
|
||||
g_pLayoutManager->getCurrentLayout()->alterSplitRatio(PLASTWINDOW, splitResult.value(), exact);
|
||||
}
|
||||
|
||||
void CKeybindManager::focusMonitor(std::string arg) {
|
||||
@@ -1425,7 +1420,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
|
||||
std::string workspaceName;
|
||||
const int WORKSPACEID = getWorkspaceIDFromString(workspace, workspaceName);
|
||||
|
||||
if (WORKSPACEID == INT_MAX) {
|
||||
if (WORKSPACEID == WORKSPACE_INVALID) {
|
||||
Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!");
|
||||
return;
|
||||
}
|
||||
@@ -1447,7 +1442,7 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) {
|
||||
std::string workspaceName = "";
|
||||
int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName);
|
||||
|
||||
if (workspaceID == INT_MAX || !g_pCompositor->isWorkspaceSpecial(workspaceID)) {
|
||||
if (workspaceID == WORKSPACE_INVALID || !g_pCompositor->isWorkspaceSpecial(workspaceID)) {
|
||||
Debug::log(ERR, "Invalid workspace passed to special");
|
||||
return;
|
||||
}
|
||||
@@ -1485,7 +1480,7 @@ void CKeybindManager::forceRendererReload(std::string args) {
|
||||
if (!m->output)
|
||||
continue;
|
||||
|
||||
auto rule = g_pConfigManager->getMonitorRuleFor(m->szName, m->output->description ? m->output->description : "");
|
||||
auto rule = g_pConfigManager->getMonitorRuleFor(m->szName, m->szDescription);
|
||||
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) {
|
||||
overAgain = true;
|
||||
break;
|
||||
@@ -1579,10 +1574,18 @@ void CKeybindManager::circleNext(std::string arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg == "last" || arg == "l" || arg == "prev" || arg == "p")
|
||||
switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow, true));
|
||||
CVarList args{arg, 0, 's', true};
|
||||
|
||||
std::optional<bool> floatStatus = {};
|
||||
if (args.contains("tile") || args.contains("tiled"))
|
||||
floatStatus = false;
|
||||
else if (args.contains("float") || args.contains("floating"))
|
||||
floatStatus = true;
|
||||
|
||||
if (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l"))
|
||||
switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow, true, floatStatus));
|
||||
else
|
||||
switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow, true));
|
||||
switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow, true, floatStatus));
|
||||
}
|
||||
|
||||
void CKeybindManager::focusWindow(std::string regexp) {
|
||||
@@ -1840,17 +1843,8 @@ void CKeybindManager::mouse(std::string args) {
|
||||
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
|
||||
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
|
||||
if (pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(mouseCoords)) {
|
||||
for (auto& wd : pWindow->m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) {
|
||||
wd->onBeginWindowDragOnDeco(mouseCoords);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pWindow && !pWindow->m_bIsFullscreen)
|
||||
pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_START, mouseCoords);
|
||||
|
||||
if (!g_pInputManager->currentlyDraggedWindow)
|
||||
g_pInputManager->currentlyDraggedWindow = pWindow;
|
||||
@@ -1915,7 +1909,7 @@ void CKeybindManager::alterZOrder(std::string args) {
|
||||
else if (POSITION == "bottom")
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, 0);
|
||||
else {
|
||||
Debug::log(ERR, "alterZOrder: bad position: %s", POSITION);
|
||||
Debug::log(ERR, "alterZOrder: bad position: {}", POSITION);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1926,8 +1920,7 @@ void CKeybindManager::fakeFullscreenActive(std::string args) {
|
||||
if (g_pCompositor->m_pLastWindow) {
|
||||
// will also set the flag
|
||||
g_pCompositor->m_pLastWindow->m_bFakeFullscreenState = !g_pCompositor->m_pLastWindow->m_bFakeFullscreenState;
|
||||
g_pXWaylandManager->setWindowFullscreen(g_pCompositor->m_pLastWindow,
|
||||
g_pCompositor->m_pLastWindow->m_bFakeFullscreenState || g_pCompositor->m_pLastWindow->m_bIsFullscreen);
|
||||
g_pXWaylandManager->setWindowFullscreen(g_pCompositor->m_pLastWindow, g_pCompositor->m_pLastWindow->shouldSendFullscreenState());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2067,7 +2060,7 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
|
||||
static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue;
|
||||
|
||||
if (!isDirection(args)) {
|
||||
Debug::log(ERR, "Cannot move into group in direction %c, unsupported direction. Supported: l,r,u/t,d/b", arg);
|
||||
Debug::log(ERR, "Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -29,8 +29,7 @@ struct SKeybind {
|
||||
bool shadowed = false;
|
||||
};
|
||||
|
||||
enum eFocusWindowMode
|
||||
{
|
||||
enum eFocusWindowMode {
|
||||
MODE_CLASS_REGEX = 0,
|
||||
MODE_TITLE_REGEX,
|
||||
MODE_ADDRESS,
|
||||
|
@@ -51,3 +51,10 @@ bool CLayoutManager::removeLayout(IHyprLayout* layout) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> CLayoutManager::getAllLayoutNames() {
|
||||
std::vector<std::string> results(m_vLayouts.size());
|
||||
for (size_t i = 0; i < m_vLayouts.size(); ++i)
|
||||
results[i] = m_vLayouts[i].first;
|
||||
return results;
|
||||
}
|
||||
|
@@ -7,16 +7,16 @@ class CLayoutManager {
|
||||
public:
|
||||
CLayoutManager();
|
||||
|
||||
IHyprLayout* getCurrentLayout();
|
||||
IHyprLayout* getCurrentLayout();
|
||||
|
||||
void switchToLayout(std::string);
|
||||
void switchToLayout(std::string);
|
||||
|
||||
bool addLayout(const std::string& name, IHyprLayout* layout);
|
||||
bool removeLayout(IHyprLayout* layout);
|
||||
bool addLayout(const std::string& name, IHyprLayout* layout);
|
||||
bool removeLayout(IHyprLayout* layout);
|
||||
std::vector<std::string> getAllLayoutNames();
|
||||
|
||||
private:
|
||||
enum HYPRLAYOUTS
|
||||
{
|
||||
enum HYPRLAYOUTS {
|
||||
LAYOUT_DWINDLE = 0,
|
||||
LAYOUT_MASTER
|
||||
};
|
||||
@@ -25,8 +25,7 @@ class CLayoutManager {
|
||||
|
||||
CHyprDwindleLayout m_cDwindleLayout;
|
||||
CHyprMasterLayout m_cMasterLayout;
|
||||
|
||||
std::vector<std::pair<std::string, IHyprLayout*>> m_vLayouts;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CLayoutManager> g_pLayoutManager;
|
||||
inline std::unique_ptr<CLayoutManager> g_pLayoutManager;
|
||||
|
@@ -45,10 +45,11 @@ void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate)
|
||||
wlr_xdg_toplevel_set_activated(PSURF->toplevel, activate);
|
||||
|
||||
} else if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) {
|
||||
wlr_xwayland_surface_activate(wlr_xwayland_surface_try_from_wlr_surface(pSurface), activate);
|
||||
const auto XSURF = wlr_xwayland_surface_try_from_wlr_surface(pSurface);
|
||||
wlr_xwayland_surface_activate(XSURF, activate);
|
||||
|
||||
if (activate)
|
||||
wlr_xwayland_surface_restack(wlr_xwayland_surface_try_from_wlr_surface(pSurface), nullptr, XCB_STACK_MODE_ABOVE);
|
||||
if (activate && !XSURF->override_redirect)
|
||||
wlr_xwayland_surface_restack(XSURF, nullptr, XCB_STACK_MODE_ABOVE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +59,8 @@ void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) {
|
||||
|
||||
if (activate) {
|
||||
wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false);
|
||||
wlr_xwayland_surface_restack(pWindow->m_uSurface.xwayland, nullptr, XCB_STACK_MODE_ABOVE);
|
||||
if (!pWindow->m_uSurface.xwayland->override_redirect)
|
||||
wlr_xwayland_surface_restack(pWindow->m_uSurface.xwayland, nullptr, XCB_STACK_MODE_ABOVE);
|
||||
}
|
||||
|
||||
wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate);
|
||||
@@ -117,7 +119,7 @@ std::string CHyprXWaylandManager::getTitle(CWindow* pWindow) {
|
||||
}
|
||||
|
||||
std::string CHyprXWaylandManager::getAppIDClass(CWindow* pWindow) {
|
||||
if (!pWindow->m_bMappedX11 || !pWindow->m_bIsMapped)
|
||||
if (!pWindow->m_bIsMapped)
|
||||
return "";
|
||||
|
||||
try {
|
||||
@@ -148,14 +150,12 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f
|
||||
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
|
||||
// calculate pos
|
||||
// TODO: this should be decoupled from setWindowSize IMO
|
||||
Vector2D windowPos = pWindow->m_vRealPosition.vec();
|
||||
|
||||
if (pWindow->m_bIsX11) {
|
||||
if (pWindow->m_bIsX11 && PMONITOR) {
|
||||
windowPos = windowPos - PMONITOR->vecPosition; // normalize to monitor
|
||||
if (*PXWLFORCESCALEZERO)
|
||||
windowPos = windowPos * PMONITOR->scale; // scale if applicable
|
||||
@@ -170,11 +170,9 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f
|
||||
|
||||
pWindow->m_fX11SurfaceScaledBy = 1.f;
|
||||
|
||||
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); PMONITOR) {
|
||||
size = size * PMONITOR->scale;
|
||||
pWindow->m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
}
|
||||
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11 && PMONITOR) {
|
||||
size = size * PMONITOR->scale;
|
||||
pWindow->m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
}
|
||||
|
||||
if (pWindow->m_bIsX11)
|
||||
@@ -184,8 +182,11 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f
|
||||
}
|
||||
|
||||
void CHyprXWaylandManager::setWindowStyleTiled(CWindow* pWindow, uint32_t edgez) {
|
||||
if (!pWindow->m_bIsX11)
|
||||
wlr_xdg_toplevel_set_tiled(pWindow->m_uSurface.xdg->toplevel, edgez);
|
||||
if (pWindow->m_bIsX11)
|
||||
return;
|
||||
|
||||
wlr_xdg_toplevel_set_tiled(pWindow->m_uSurface.xdg->toplevel, edgez);
|
||||
wlr_xdg_toplevel_set_maximized(pWindow->m_uSurface.xdg->toplevel, true);
|
||||
}
|
||||
|
||||
wlr_surface* CHyprXWaylandManager::surfaceAt(CWindow* pWindow, const Vector2D& client, Vector2D& surface) {
|
||||
|
@@ -3,6 +3,18 @@
|
||||
#include "wlr/types/wlr_switch.h"
|
||||
#include <ranges>
|
||||
|
||||
CInputManager::~CInputManager() {
|
||||
m_lConstraints.clear();
|
||||
m_lKeyboards.clear();
|
||||
m_lMice.clear();
|
||||
m_lTablets.clear();
|
||||
m_lTabletTools.clear();
|
||||
m_lTabletPads.clear();
|
||||
m_lIdleInhibitors.clear();
|
||||
m_lTouchDevices.clear();
|
||||
m_lSwitches.clear();
|
||||
}
|
||||
|
||||
void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) {
|
||||
static auto* const PSENS = &g_pConfigManager->getConfigValuePtr("general:sensitivity")->floatValue;
|
||||
static auto* const PNOACCEL = &g_pConfigManager->getConfigValuePtr("input:force_no_accel")->intValue;
|
||||
@@ -221,10 +233,20 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
surfacePos = PMONITOR->vecPosition;
|
||||
}
|
||||
|
||||
// overlay is above fullscreen
|
||||
// overlays are above fullscreen
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
// also IME popups
|
||||
if (!foundSurface) {
|
||||
auto popup = g_pCompositor->vectorToIMEPopup(mouseCoords, m_sIMERelay.m_lIMEPopups);
|
||||
if (popup) {
|
||||
foundSurface = popup->pSurface->surface;
|
||||
surfacePos = Vector2D(popup->realX, popup->realY);
|
||||
}
|
||||
}
|
||||
|
||||
// also top layers
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
@@ -297,15 +319,17 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
|
||||
if (!foundSurface) {
|
||||
if (!m_bEmptyFocusCursorSet) {
|
||||
m_eBorderIconDirection = BORDERICON_NONE;
|
||||
if (g_pHyprRenderer->m_bHasARenderedCursor) {
|
||||
// TODO: maybe wrap?
|
||||
if (m_ecbClickBehavior == CLICKMODE_KILL)
|
||||
setCursorImageOverride("crosshair");
|
||||
else
|
||||
setCursorImageOverride("left_ptr");
|
||||
if (*PRESIZEONBORDER && *PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) {
|
||||
m_eBorderIconDirection = BORDERICON_NONE;
|
||||
unsetCursorImage();
|
||||
}
|
||||
|
||||
// TODO: maybe wrap?
|
||||
if (m_ecbClickBehavior == CLICKMODE_KILL)
|
||||
setCursorImageOverride("crosshair");
|
||||
else
|
||||
setCursorImageOverride("left_ptr");
|
||||
|
||||
m_bEmptyFocusCursorSet = true;
|
||||
}
|
||||
|
||||
@@ -459,13 +483,7 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
|
||||
}
|
||||
|
||||
void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e) {
|
||||
|
||||
if (!e->surface)
|
||||
g_pHyprRenderer->m_bWindowRequestedCursorHide = true;
|
||||
else
|
||||
g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
|
||||
|
||||
if (!cursorImageUnlocked() || !g_pHyprRenderer->m_bHasARenderedCursor)
|
||||
if (!cursorImageUnlocked())
|
||||
return;
|
||||
|
||||
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
|
||||
@@ -488,7 +506,7 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
|
||||
}
|
||||
|
||||
void CInputManager::processMouseRequest(wlr_cursor_shape_manager_v1_request_set_shape_event* e) {
|
||||
if (!g_pHyprRenderer->m_bHasARenderedCursor || !cursorImageUnlocked())
|
||||
if (!cursorImageUnlocked())
|
||||
return;
|
||||
|
||||
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
|
||||
@@ -530,9 +548,6 @@ void CInputManager::setCursorImageOverride(const std::string& name) {
|
||||
}
|
||||
|
||||
bool CInputManager::cursorImageUnlocked() {
|
||||
if (!g_pHyprRenderer->m_bHasARenderedCursor)
|
||||
return false;
|
||||
|
||||
if (m_ecbClickBehavior == CLICKMODE_KILL)
|
||||
return false;
|
||||
|
||||
@@ -572,10 +587,13 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
|
||||
void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
|
||||
|
||||
// notify the keybind manager
|
||||
static auto* const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue;
|
||||
const auto PASS = g_pKeybindManager->onMouseEvent(e);
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
|
||||
static auto* const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue;
|
||||
const auto PASS = g_pKeybindManager->onMouseEvent(e);
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
|
||||
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
|
||||
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
|
||||
|
||||
if (!PASS && !*PPASSMOUSE)
|
||||
return;
|
||||
@@ -583,24 +601,17 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
|
||||
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
|
||||
const auto w = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
|
||||
if (w && !w->m_bIsFullscreen && !w->hasPopupAt(mouseCoords)) {
|
||||
for (auto& wd : w->m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) {
|
||||
wd->onMouseButtonOnDeco(mouseCoords, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (w && !m_bLastFocusOnLS && w->checkInputOnDecos(INPUT_TYPE_BUTTON, mouseCoords, e))
|
||||
return;
|
||||
|
||||
// clicking on border triggers resize
|
||||
// TODO detect click on LS properly
|
||||
if (*PRESIZEONBORDER && !m_bLastFocusOnLS) {
|
||||
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e->state == WLR_BUTTON_PRESSED) {
|
||||
if (w && !w->m_bIsFullscreen) {
|
||||
const CBox real = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
|
||||
if ((!real.containsPoint(mouseCoords) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) && !w->hasPopupAt(mouseCoords)) {
|
||||
const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA};
|
||||
|
||||
if ((grab.containsPoint(mouseCoords) && (!real.containsPoint(mouseCoords) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y))) && !w->hasPopupAt(mouseCoords)) {
|
||||
g_pKeybindManager->resizeWithBorder(e);
|
||||
return;
|
||||
}
|
||||
@@ -662,31 +673,29 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
|
||||
}
|
||||
|
||||
void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
|
||||
static auto* const PSCROLLFACTOR = &g_pConfigManager->getConfigValuePtr("input:touchpad:scroll_factor")->floatValue;
|
||||
static auto* const PGROUPBARSCROLLING = &g_pConfigManager->getConfigValuePtr("group:groupbar:scrolling")->intValue;
|
||||
static auto* const PSCROLLFACTOR = &g_pConfigManager->getConfigValuePtr("input:touchpad:scroll_factor")->floatValue;
|
||||
|
||||
auto factor = (*PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : *PSCROLLFACTOR);
|
||||
|
||||
bool passEvent = g_pKeybindManager->onAxisEvent(e);
|
||||
const auto EMAP = std::unordered_map<std::string, std::any>{{"event", e}};
|
||||
EMIT_HOOK_EVENT_CANCELLABLE("mouseAxis", EMAP);
|
||||
|
||||
bool passEvent = g_pKeybindManager->onAxisEvent(e);
|
||||
|
||||
g_pCompositor->notifyIdleActivity();
|
||||
|
||||
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||
const auto pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS);
|
||||
if (!passEvent)
|
||||
return;
|
||||
|
||||
if (*PGROUPBARSCROLLING && pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(MOUSECOORDS) && pWindow->m_sGroupData.pNextWindow) {
|
||||
const CBox box = g_pDecorationPositioner->getWindowDecorationBox(pWindow->getDecorationByType(DECORATION_GROUPBAR));
|
||||
if (box.containsPoint(MOUSECOORDS)) {
|
||||
if (e->delta > 0)
|
||||
pWindow->setGroupCurrent(pWindow->m_sGroupData.pNextWindow);
|
||||
else
|
||||
pWindow->setGroupCurrent(pWindow->getGroupPrevious());
|
||||
if (!m_bLastFocusOnLS) {
|
||||
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||
const auto PWINDOW = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS);
|
||||
|
||||
if (PWINDOW && PWINDOW->checkInputOnDecos(INPUT_TYPE_AXIS, MOUSECOORDS, e))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (passEvent)
|
||||
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source);
|
||||
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source);
|
||||
}
|
||||
|
||||
Vector2D CInputManager::getMouseCoordsInternal() {
|
||||
@@ -823,7 +832,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
|
||||
pKeyboard->repeatDelay = REPEATDELAY;
|
||||
pKeyboard->repeatRate = REPEATRATE;
|
||||
pKeyboard->numlockOn = NUMLOCKON;
|
||||
pKeyboard->xkbFilePath = FILEPATH.c_str();
|
||||
pKeyboard->xkbFilePath = FILEPATH;
|
||||
|
||||
xkb_rule_names rules = {.rules = RULES.c_str(), .model = MODEL.c_str(), .layout = LAYOUT.c_str(), .variant = VARIANT.c_str(), .options = OPTIONS.c_str()};
|
||||
|
||||
@@ -871,7 +880,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
|
||||
pKeyboard->currentRules.model = "";
|
||||
pKeyboard->currentRules.variant = "";
|
||||
pKeyboard->currentRules.options = "";
|
||||
pKeyboard->currentRules.layout = "";
|
||||
pKeyboard->currentRules.layout = "us";
|
||||
|
||||
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
}
|
||||
@@ -899,7 +908,8 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->name + "," + LAYOUTSTR});
|
||||
EMIT_HOOK_EVENT("activeLayout", (std::vector<void*>{pKeyboard, (void*)&LAYOUTSTR}));
|
||||
|
||||
Debug::log(LOG, "Set the keyboard layout to {} and variant to {} for keyboard \"{}\"", rules.layout, rules.variant, pKeyboard->keyboard->name);
|
||||
Debug::log(LOG, "Set the keyboard layout to {} and variant to {} for keyboard \"{}\"", pKeyboard->currentRules.layout, pKeyboard->currentRules.variant,
|
||||
pKeyboard->keyboard->name);
|
||||
}
|
||||
|
||||
void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
|
||||
@@ -1036,24 +1046,41 @@ void CInputManager::setPointerConfigs() {
|
||||
libinput_device_config_accel_set_speed(LIBINPUTDEV, LIBINPUTSENS);
|
||||
|
||||
const auto ACCELPROFILE = g_pConfigManager->getDeviceString(devname, "accel_profile", "input:accel_profile");
|
||||
const auto SCROLLPOINTS = g_pConfigManager->getDeviceString(devname, "scroll_points", "input:scroll_points");
|
||||
|
||||
if (ACCELPROFILE == "") {
|
||||
if (ACCELPROFILE.empty()) {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
|
||||
} else if (ACCELPROFILE == "adaptive") {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
|
||||
} else if (ACCELPROFILE == "flat") {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
|
||||
} else if (ACCELPROFILE.starts_with("custom")) {
|
||||
CVarList args = {ACCELPROFILE, 0, ' '};
|
||||
CVarList accelValues = {ACCELPROFILE, 0, ' '};
|
||||
|
||||
try {
|
||||
double step = std::stod(args[1]);
|
||||
std::vector<double> points;
|
||||
for (size_t i = 2; i < args.size(); ++i)
|
||||
points.push_back(std::stod(args[i]));
|
||||
double accelStep = std::stod(accelValues[1]);
|
||||
std::vector<double> accelPoints;
|
||||
for (size_t i = 2; i < accelValues.size(); ++i) {
|
||||
accelPoints.push_back(std::stod(accelValues[i]));
|
||||
}
|
||||
|
||||
const auto CONFIG = libinput_config_accel_create(LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM);
|
||||
libinput_config_accel_set_points(CONFIG, LIBINPUT_ACCEL_TYPE_MOTION, step, points.size(), points.data());
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM);
|
||||
|
||||
if (!SCROLLPOINTS.empty()) {
|
||||
CVarList scrollValues = {SCROLLPOINTS, 0, ' '};
|
||||
try {
|
||||
double scrollStep = std::stod(scrollValues[0]);
|
||||
std::vector<double> scrollPoints;
|
||||
for (size_t i = 1; i < scrollValues.size(); ++i) {
|
||||
scrollPoints.push_back(std::stod(scrollValues[i]));
|
||||
}
|
||||
|
||||
libinput_config_accel_set_points(CONFIG, LIBINPUT_ACCEL_TYPE_SCROLL, scrollStep, scrollPoints.size(), scrollPoints.data());
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Invalid values in scroll_points"); }
|
||||
}
|
||||
|
||||
libinput_config_accel_set_points(CONFIG, LIBINPUT_ACCEL_TYPE_MOTION, accelStep, accelPoints.size(), accelPoints.data());
|
||||
libinput_device_config_accel_apply(LIBINPUTDEV, CONFIG);
|
||||
libinput_config_accel_destroy(CONFIG);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Invalid values in custom accel profile"); }
|
||||
} else {
|
||||
@@ -1131,6 +1158,9 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
|
||||
if (!pKeyboard->enabled)
|
||||
return;
|
||||
|
||||
const auto EMAP = std::unordered_map<std::string, std::any>{{"keyboard", pKeyboard}, {"event", e}};
|
||||
EMIT_HOOK_EVENT_CANCELLABLE("keyPress", EMAP);
|
||||
|
||||
static auto* const PDPMS = &g_pConfigManager->getConfigValuePtr("misc:key_press_enables_dpms")->intValue;
|
||||
if (*PDPMS && !g_pCompositor->m_bDPMSStateON) {
|
||||
// enable dpms
|
||||
@@ -1461,7 +1491,10 @@ void CInputManager::setTabletConfigs() {
|
||||
if (wlr_input_device_is_libinput(t.wlrDevice)) {
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(t.wlrDevice);
|
||||
|
||||
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(t.name, "transform", "input:tablet:transform"), 0, 7);
|
||||
const auto RELINPUT = g_pConfigManager->getDeviceInt(t.name, "relative_input", "input:tablet:relative_input");
|
||||
t.relativeInput = RELINPUT;
|
||||
|
||||
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(t.name, "transform", "input:tablet:transform"), 0, 7);
|
||||
Debug::log(LOG, "Setting calibration matrix for device {}", t.name);
|
||||
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
|
||||
|
||||
@@ -1533,7 +1566,7 @@ void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
|
||||
}
|
||||
|
||||
void CInputManager::setCursorImageUntilUnset(std::string name) {
|
||||
g_pHyprRenderer->setCursorFromName(name.c_str());
|
||||
g_pHyprRenderer->setCursorFromName(name);
|
||||
m_bCursorImageOverridden = true;
|
||||
m_sCursorSurfaceInfo.inUse = false;
|
||||
}
|
||||
@@ -1624,7 +1657,7 @@ void CInputManager::setCursorIconOnBorder(CWindow* w) {
|
||||
CBox box = w->getWindowMainSurfaceBox();
|
||||
eBorderIconDirection direction = BORDERICON_NONE;
|
||||
CBox boxFullGrabInput = {box.x - *PEXTENDBORDERGRAB - BORDERSIZE, box.y - *PEXTENDBORDERGRAB - BORDERSIZE, box.width + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE),
|
||||
box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)};
|
||||
box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)};
|
||||
|
||||
if (w->hasPopupAt(mouseCoords))
|
||||
direction = BORDERICON_NONE;
|
||||
|
@@ -61,6 +61,8 @@ class CKeybindManager;
|
||||
|
||||
class CInputManager {
|
||||
public:
|
||||
~CInputManager();
|
||||
|
||||
void onMouseMoved(wlr_pointer_motion_event*);
|
||||
void onMouseWarp(wlr_pointer_motion_absolute_event*);
|
||||
void onMouseButton(wlr_pointer_button_event*);
|
||||
|
@@ -44,13 +44,14 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
if (!m_sActiveSwipe.pWorkspaceBegin)
|
||||
return; // no valid swipe
|
||||
|
||||
static auto* const PSWIPEPERC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_cancel_ratio")->floatValue;
|
||||
static auto* const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue;
|
||||
static auto* const PSWIPEFORC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_min_speed_to_force")->intValue;
|
||||
static auto* const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue;
|
||||
static auto* const PSWIPENUMBER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_numbered")->intValue;
|
||||
static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue;
|
||||
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
|
||||
static auto* const PSWIPEPERC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_cancel_ratio")->floatValue;
|
||||
static auto* const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue;
|
||||
static auto* const PSWIPEFORC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_min_speed_to_force")->intValue;
|
||||
static auto* const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue;
|
||||
static auto* const PSWIPENUMBER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_numbered")->intValue;
|
||||
static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue;
|
||||
static auto* const PWORKSPACEGAP = &g_pConfigManager->getConfigValuePtr("general:gaps_workspaces")->intValue;
|
||||
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
|
||||
|
||||
// commit
|
||||
@@ -79,6 +80,8 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); // not guaranteed if PSWIPENUMBER
|
||||
|
||||
const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.vec();
|
||||
const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP;
|
||||
const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP;
|
||||
|
||||
CWorkspace* pSwitchedTo = nullptr;
|
||||
|
||||
@@ -94,18 +97,19 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
} else {
|
||||
if (m_sActiveSwipe.delta < 0) {
|
||||
// to left
|
||||
|
||||
if (PWORKSPACEL) {
|
||||
if (VERTANIMS)
|
||||
PWORKSPACEL->m_vRenderOffset = Vector2D({0, -m_sActiveSwipe.pMonitor->vecSize.y});
|
||||
PWORKSPACEL->m_vRenderOffset = Vector2D({0, -YDISTANCE});
|
||||
else
|
||||
PWORKSPACEL->m_vRenderOffset = Vector2D({-m_sActiveSwipe.pMonitor->vecSize.x, 0});
|
||||
PWORKSPACEL->m_vRenderOffset = Vector2D({-XDISTANCE, 0});
|
||||
}
|
||||
} else if (PWORKSPACER) {
|
||||
// to right
|
||||
if (VERTANIMS)
|
||||
PWORKSPACER->m_vRenderOffset = Vector2D({0, m_sActiveSwipe.pMonitor->vecSize.y});
|
||||
PWORKSPACER->m_vRenderOffset = Vector2D({0, YDISTANCE});
|
||||
else
|
||||
PWORKSPACER->m_vRenderOffset = Vector2D({m_sActiveSwipe.pMonitor->vecSize.x, 0});
|
||||
PWORKSPACER->m_vRenderOffset = Vector2D({XDISTANCE, 0});
|
||||
}
|
||||
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D();
|
||||
@@ -128,9 +132,9 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE);
|
||||
if (VERTANIMS)
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, m_sActiveSwipe.pMonitor->vecSize.y);
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, YDISTANCE);
|
||||
else
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(m_sActiveSwipe.pMonitor->vecSize.x, 0);
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(XDISTANCE, 0);
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f);
|
||||
|
||||
g_pInputManager->unconstrainMouse();
|
||||
@@ -154,9 +158,9 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE);
|
||||
if (VERTANIMS)
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, -m_sActiveSwipe.pMonitor->vecSize.y);
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, -YDISTANCE);
|
||||
else
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-m_sActiveSwipe.pMonitor->vecSize.x, 0);
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-XDISTANCE, 0);
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f);
|
||||
|
||||
g_pInputManager->unconstrainMouse();
|
||||
@@ -198,7 +202,10 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
static auto* const PSWIPEFOREVER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_forever")->intValue;
|
||||
static auto* const PSWIPENUMBER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_numbered")->intValue;
|
||||
static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue;
|
||||
static auto* const PWORKSPACEGAP = &g_pConfigManager->getConfigValuePtr("general:gaps_workspaces")->intValue;
|
||||
|
||||
const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP;
|
||||
const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP;
|
||||
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
|
||||
|
||||
@@ -211,7 +218,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
auto workspaceIDLeft = getWorkspaceIDFromString(*PSWIPENUMBER ? "-1" : (*PSWIPEUSER ? "r-1" : "m-1"), wsname);
|
||||
auto workspaceIDRight = getWorkspaceIDFromString(*PSWIPENUMBER ? "+1" : (*PSWIPEUSER ? "r+1" : "m+1"), wsname);
|
||||
|
||||
if ((workspaceIDLeft == INT_MAX || workspaceIDRight == INT_MAX || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) && !*PSWIPENEW) {
|
||||
if ((workspaceIDLeft == WORKSPACE_INVALID || workspaceIDRight == WORKSPACE_INVALID || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) && !*PSWIPENEW) {
|
||||
m_sActiveSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe
|
||||
return;
|
||||
}
|
||||
@@ -244,9 +251,9 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
|
||||
|
||||
if (VERTANIMS)
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
else
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
|
||||
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
|
||||
return;
|
||||
@@ -268,13 +275,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
}
|
||||
|
||||
if (VERTANIMS) {
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y - m_sActiveSwipe.pMonitor->vecSize.y));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y));
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE - YDISTANCE));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
} else {
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x - m_sActiveSwipe.pMonitor->vecSize.x, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0));
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE - XDISTANCE, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
}
|
||||
|
||||
g_pCompositor->updateWorkspaceWindowDecos(workspaceIDLeft);
|
||||
@@ -286,9 +291,9 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
|
||||
|
||||
if (VERTANIMS)
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
else
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
|
||||
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
|
||||
return;
|
||||
@@ -310,13 +315,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
}
|
||||
|
||||
if (VERTANIMS) {
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y + m_sActiveSwipe.pMonitor->vecSize.y));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y));
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE + YDISTANCE));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
} else {
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x + m_sActiveSwipe.pMonitor->vecSize.x, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0));
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE + XDISTANCE, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
}
|
||||
|
||||
g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight);
|
||||
|
@@ -43,9 +43,16 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
||||
g_pInputManager->m_tmrLastCursorMovement.reset();
|
||||
break;
|
||||
default:
|
||||
double x = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->x : NAN;
|
||||
double y = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->y : NAN;
|
||||
wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y);
|
||||
double x = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->x : NAN;
|
||||
double dx = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->dx : NAN;
|
||||
double y = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->y : NAN;
|
||||
double dy = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->dy : NAN;
|
||||
|
||||
if (PTAB->relativeInput)
|
||||
wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy);
|
||||
else
|
||||
wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y);
|
||||
|
||||
g_pInputManager->refocus();
|
||||
g_pInputManager->m_tmrLastCursorMovement.reset();
|
||||
break;
|
||||
@@ -83,6 +90,8 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
||||
|
||||
if (EVENT->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y))
|
||||
wlr_tablet_v2_tablet_tool_notify_tilt(PTOOL->wlrTabletToolV2, PTOOL->tiltX, PTOOL->tiltY);
|
||||
|
||||
g_pCompositor->notifyIdleActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
@@ -102,6 +111,8 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
||||
} else {
|
||||
wlr_send_tablet_v2_tablet_tool_up(PTOOL->wlrTabletToolV2);
|
||||
}
|
||||
|
||||
g_pCompositor->notifyIdleActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
@@ -113,6 +124,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
||||
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
|
||||
|
||||
wlr_tablet_v2_tablet_tool_notify_button(PTOOL->wlrTabletToolV2, (zwp_tablet_pad_v2_button_state)EVENT->button, (zwp_tablet_pad_v2_button_state)EVENT->state);
|
||||
g_pCompositor->notifyIdleActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
@@ -137,6 +149,8 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
||||
g_pInputManager->refocus();
|
||||
g_pInputManager->focusTablet(PTAB, EVENT->tool);
|
||||
}
|
||||
|
||||
g_pCompositor->notifyIdleActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
|
@@ -2,6 +2,8 @@
|
||||
#include "../../Compositor.hpp"
|
||||
|
||||
void CInputManager::onTouchDown(wlr_touch_down_event* e) {
|
||||
EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e);
|
||||
|
||||
auto PMONITOR = g_pCompositor->getMonitorFromName(e->touch->output_name ? e->touch->output_name : "");
|
||||
|
||||
const auto PDEVIT = std::find_if(m_lTouchDevices.begin(), m_lTouchDevices.end(), [&](const STouchDevice& other) { return other.pWlrDevice == &e->touch->base; });
|
||||
@@ -52,12 +54,14 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
|
||||
}
|
||||
|
||||
void CInputManager::onTouchUp(wlr_touch_up_event* e) {
|
||||
EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e);
|
||||
if (m_sTouchData.touchFocusSurface) {
|
||||
wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id);
|
||||
}
|
||||
}
|
||||
|
||||
void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
|
||||
EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e);
|
||||
if (m_sTouchData.touchFocusWindow && g_pCompositor->windowValidMapped(m_sTouchData.touchFocusWindow)) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID);
|
||||
|
||||
@@ -68,7 +72,7 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
|
||||
local = local * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy;
|
||||
|
||||
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
|
||||
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y);
|
||||
// wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y);
|
||||
} else if (m_sTouchData.touchFocusLS) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID);
|
||||
|
||||
@@ -77,7 +81,7 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
|
||||
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
|
||||
|
||||
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
|
||||
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y);
|
||||
// wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,6 @@
|
||||
#include "HookSystem.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../helpers/VarList.hpp"
|
||||
|
||||
#define register
|
||||
#include <udis86.h>
|
||||
@@ -18,12 +20,12 @@ CFunctionHook::~CFunctionHook() {
|
||||
unhook();
|
||||
}
|
||||
|
||||
size_t CFunctionHook::getInstructionLenAt(void* start) {
|
||||
CFunctionHook::SInstructionProbe CFunctionHook::getInstructionLenAt(void* start) {
|
||||
ud_t udis;
|
||||
|
||||
ud_init(&udis);
|
||||
ud_set_mode(&udis, 64);
|
||||
ud_set_syntax(&udis, UD_SYN_INTEL);
|
||||
ud_set_syntax(&udis, UD_SYN_ATT);
|
||||
|
||||
size_t curOffset = 1;
|
||||
size_t insSize = 0;
|
||||
@@ -40,27 +42,101 @@ size_t CFunctionHook::getInstructionLenAt(void* start) {
|
||||
if (const auto CINS = ud_insn_asm(&udis); CINS)
|
||||
ins = std::string(CINS);
|
||||
|
||||
if (!ins.empty() && ins.find("rip") != std::string::npos) {
|
||||
// todo: support something besides call qword ptr [rip + 0xdeadbeef]
|
||||
// I don't have an assembler. I don't think udis provides one. Besides, variables might be tricky.
|
||||
if (((uint8_t*)start)[0] == 0xFF && ((uint8_t*)start)[1] == 0x15)
|
||||
m_vTrampolineRIPUses.emplace_back(std::make_pair<>((uint64_t)start - (uint64_t)m_pSource, ins));
|
||||
}
|
||||
|
||||
return insSize;
|
||||
return {insSize, ins};
|
||||
}
|
||||
|
||||
size_t CFunctionHook::probeMinimumJumpSize(void* start, size_t min) {
|
||||
CFunctionHook::SInstructionProbe CFunctionHook::probeMinimumJumpSize(void* start, size_t min) {
|
||||
|
||||
size_t size = 0;
|
||||
size_t size = 0;
|
||||
|
||||
std::string instrs = "";
|
||||
std::vector<size_t> sizes;
|
||||
|
||||
while (size <= min) {
|
||||
// find info about this instruction
|
||||
size_t insLen = getInstructionLenAt((uint8_t*)start + size);
|
||||
size += insLen;
|
||||
auto probe = getInstructionLenAt((uint8_t*)start + size);
|
||||
sizes.push_back(probe.len);
|
||||
size += probe.len;
|
||||
instrs += probe.assembly + "\n";
|
||||
}
|
||||
|
||||
return size;
|
||||
return {size, instrs, sizes};
|
||||
}
|
||||
|
||||
CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstructionProbe& probe) {
|
||||
// analyze the code and fix what we know how to.
|
||||
uint64_t currentAddress = (uint64_t)m_pSource;
|
||||
// actually newline + 1
|
||||
size_t lastAsmNewline = 0;
|
||||
std::string assemblyBuilder;
|
||||
for (auto& len : probe.insSizes) {
|
||||
|
||||
std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline);
|
||||
if (code.contains("%rip")) {
|
||||
CVarList tokens{code, 0, 's'};
|
||||
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
|
||||
std::string addr = tokens[1].substr(plusPresent, tokens[1].find("(%rip)") - plusPresent);
|
||||
const uint64_t OFFSET = configStringToInt(addr);
|
||||
if (OFFSET == 0)
|
||||
return {};
|
||||
const uint64_t DESTINATION = currentAddress + OFFSET + len;
|
||||
|
||||
if (code.starts_with("mov")) {
|
||||
// mov +0xdeadbeef(%rip), %rax
|
||||
assemblyBuilder += std::format("movabs $0x{:x}, {}\n", DESTINATION, tokens[2]);
|
||||
} else if (code.starts_with("call")) {
|
||||
// call +0xdeadbeef(%rip)
|
||||
assemblyBuilder += std::format("pushq %rax\nmovabs $0x{:x}, %rax\ncallq *%rax\npopq %rax\n", DESTINATION);
|
||||
} else if (code.starts_with("lea")) {
|
||||
// lea 0xdeadbeef(%rip), %rax
|
||||
assemblyBuilder += std::format("movabs $0x{:x}, {}\n", DESTINATION, tokens[2]);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
} else if (code.contains("invalid")) {
|
||||
std::vector<uint8_t> bytes;
|
||||
bytes.resize(len);
|
||||
memcpy(bytes.data(), (std::byte*)currentAddress, len);
|
||||
if (len == 4 && bytes[0] == 0xF3 && bytes[1] == 0x0F && bytes[2] == 0x1E && bytes[3] == 0xFA) {
|
||||
// F3 0F 1E FA = endbr64, udis doesn't understand that one
|
||||
assemblyBuilder += "endbr64\n";
|
||||
} else {
|
||||
// raise error, unknown op
|
||||
std::string strBytes;
|
||||
for (auto& b : bytes) {
|
||||
strBytes += std::format("{:x} ", b);
|
||||
}
|
||||
Debug::log(ERR, "[functionhook] unknown bytes: {}", strBytes);
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
assemblyBuilder += code + "\n";
|
||||
}
|
||||
|
||||
lastAsmNewline = probe.assembly.find("\n", lastAsmNewline) + 1;
|
||||
currentAddress += len;
|
||||
}
|
||||
|
||||
std::ofstream ofs("/tmp/hypr/.hookcode.asm", std::ios::trunc);
|
||||
ofs << assemblyBuilder;
|
||||
ofs.close();
|
||||
std::string ret = execAndGet(
|
||||
"cc -x assembler -c /tmp/hypr/.hookcode.asm -o /tmp/hypr/.hookbinary.o 2>&1 && objcopy -O binary -j .text /tmp/hypr/.hookbinary.o /tmp/hypr/.hookbinary2.o 2>&1");
|
||||
Debug::log(LOG, "[functionhook] assembler returned:\n{}", ret);
|
||||
if (!std::filesystem::exists("/tmp/hypr/.hookbinary2.o")) {
|
||||
std::filesystem::remove("/tmp/hypr/.hookcode.asm");
|
||||
std::filesystem::remove("/tmp/hypr/.hookbinary.asm");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ifstream ifs("/tmp/hypr/.hookbinary2.o", std::ios::binary);
|
||||
SAssembly returns = {std::vector<char>(std::istreambuf_iterator<char>(ifs), {})};
|
||||
ifs.close();
|
||||
std::filesystem::remove("/tmp/hypr/.hookcode.asm");
|
||||
std::filesystem::remove("/tmp/hypr/.hookbinary.o");
|
||||
std::filesystem::remove("/tmp/hypr/.hookbinary2.o");
|
||||
|
||||
return returns;
|
||||
}
|
||||
|
||||
bool CFunctionHook::hook() {
|
||||
@@ -80,65 +156,62 @@ bool CFunctionHook::hook() {
|
||||
static constexpr uint8_t POP_RAX[] = {0x58};
|
||||
// nop
|
||||
static constexpr uint8_t NOP = 0x90;
|
||||
/*
|
||||
movabs $0,%rax
|
||||
callq *%rax
|
||||
|
||||
offset for addr: 3
|
||||
*/
|
||||
static constexpr uint8_t CALL_WITH_RAX[] = {0x48, 0xB8, 0xEF, 0xBE, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x10};
|
||||
static constexpr size_t CALL_WITH_RAX_ADDRESS_OFFSET = 2;
|
||||
// probe instructions to be trampolin'd
|
||||
SInstructionProbe probe;
|
||||
try {
|
||||
probe = probeMinimumJumpSize(m_pSource, sizeof(ABSOLUTE_JMP_ADDRESS) + sizeof(PUSH_RAX) + sizeof(POP_RAX));
|
||||
} catch (std::exception& e) { return false; }
|
||||
|
||||
// get minimum size to overwrite
|
||||
const auto HOOKSIZE = probeMinimumJumpSize(m_pSource, sizeof(ABSOLUTE_JMP_ADDRESS) + sizeof(PUSH_RAX) + sizeof(POP_RAX));
|
||||
const auto PROBEFIXEDASM = fixInstructionProbeRIPCalls(probe);
|
||||
|
||||
if (PROBEFIXEDASM.bytes.size() == 0) {
|
||||
Debug::log(ERR, "[functionhook] failed, unsupported asm / failed assembling:\n{}", probe.assembly);
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t HOOKSIZE = PROBEFIXEDASM.bytes.size();
|
||||
const size_t ORIGSIZE = probe.len;
|
||||
|
||||
// alloc trampoline
|
||||
const auto TRAMPOLINE_SIZE = sizeof(ABSOLUTE_JMP_ADDRESS) + HOOKSIZE + sizeof(PUSH_RAX) + m_vTrampolineRIPUses.size() * (sizeof(CALL_WITH_RAX) - 6);
|
||||
const auto TRAMPOLINE_SIZE = sizeof(ABSOLUTE_JMP_ADDRESS) + HOOKSIZE + sizeof(PUSH_RAX);
|
||||
m_pTrampolineAddr = mmap(NULL, TRAMPOLINE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
m_pOriginalBytes = malloc(HOOKSIZE);
|
||||
memcpy(m_pOriginalBytes, m_pSource, HOOKSIZE);
|
||||
m_pOriginalBytes = malloc(ORIGSIZE);
|
||||
memcpy(m_pOriginalBytes, m_pSource, ORIGSIZE);
|
||||
|
||||
// populate trampoline
|
||||
memcpy(m_pTrampolineAddr, m_pSource, HOOKSIZE); // first, original func bytes
|
||||
memcpy(m_pTrampolineAddr, PROBEFIXEDASM.bytes.data(), HOOKSIZE); // first, original but fixed func bytes
|
||||
memcpy((uint8_t*)m_pTrampolineAddr + HOOKSIZE, PUSH_RAX, sizeof(PUSH_RAX)); // then, pushq %rax
|
||||
memcpy((uint8_t*)m_pTrampolineAddr + HOOKSIZE + sizeof(PUSH_RAX), ABSOLUTE_JMP_ADDRESS, sizeof(ABSOLUTE_JMP_ADDRESS)); // then, jump to source
|
||||
|
||||
// fix trampoline %rip calls
|
||||
for (size_t i = 0; i < m_vTrampolineRIPUses.size(); ++i) {
|
||||
size_t callOffset = i * (sizeof(CALL_WITH_RAX) - 6 /* callq [rip + x] */) + m_vTrampolineRIPUses[i].first;
|
||||
size_t realCallAddress = (uint64_t)m_pSource + callOffset + 6 + *((uint32_t*)((uint8_t*)m_pSource + callOffset + 2));
|
||||
|
||||
memmove((uint8_t*)m_pTrampolineAddr + callOffset + sizeof(CALL_WITH_RAX), (uint8_t*)m_pTrampolineAddr + callOffset + 6, TRAMPOLINE_SIZE - callOffset - 6);
|
||||
memcpy((uint8_t*)m_pTrampolineAddr + callOffset, CALL_WITH_RAX, sizeof(CALL_WITH_RAX));
|
||||
|
||||
*(uint64_t*)((uint8_t*)m_pTrampolineAddr + callOffset + CALL_WITH_RAX_ADDRESS_OFFSET) = (uint64_t)realCallAddress;
|
||||
}
|
||||
|
||||
// fixup trampoline addr
|
||||
*(uint64_t*)((uint8_t*)m_pTrampolineAddr + TRAMPOLINE_SIZE - sizeof(ABSOLUTE_JMP_ADDRESS) + ABSOLUTE_JMP_ADDRESS_OFFSET) =
|
||||
(uint64_t)((uint8_t*)m_pSource + sizeof(ABSOLUTE_JMP_ADDRESS));
|
||||
|
||||
// make jump to hk
|
||||
mprotect((uint8_t*)m_pSource - ((uint64_t)m_pSource) % sysconf(_SC_PAGE_SIZE), sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
memcpy(m_pSource, ABSOLUTE_JMP_ADDRESS, sizeof(ABSOLUTE_JMP_ADDRESS));
|
||||
const auto PAGESIZE = sysconf(_SC_PAGE_SIZE);
|
||||
const uint8_t* PROTSTART = (uint8_t*)m_pSource - ((uint64_t)m_pSource % PAGESIZE);
|
||||
const size_t PROTLEN = std::ceil((float)(ORIGSIZE + ((uint64_t)m_pSource - (uint64_t)PROTSTART)) / (float)PAGESIZE) * PAGESIZE;
|
||||
mprotect((uint8_t*)PROTSTART, PROTLEN, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
memcpy((uint8_t*)m_pSource, ABSOLUTE_JMP_ADDRESS, sizeof(ABSOLUTE_JMP_ADDRESS));
|
||||
|
||||
// make popq %rax and NOP all remaining
|
||||
memcpy((uint8_t*)m_pSource + sizeof(ABSOLUTE_JMP_ADDRESS), POP_RAX, sizeof(POP_RAX));
|
||||
size_t currentOp = sizeof(ABSOLUTE_JMP_ADDRESS) + sizeof(POP_RAX);
|
||||
memset((uint8_t*)m_pSource + currentOp, NOP, HOOKSIZE - currentOp);
|
||||
memset((uint8_t*)m_pSource + currentOp, NOP, ORIGSIZE - currentOp);
|
||||
|
||||
// fixup jump addr
|
||||
*(uint64_t*)((uint8_t*)m_pSource + ABSOLUTE_JMP_ADDRESS_OFFSET) = (uint64_t)(m_pDestination);
|
||||
|
||||
// revert mprot
|
||||
mprotect((uint8_t*)m_pSource - ((uint64_t)m_pSource) % sysconf(_SC_PAGE_SIZE), sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_EXEC);
|
||||
mprotect((uint8_t*)PROTSTART, PROTLEN, PROT_READ | PROT_EXEC);
|
||||
|
||||
// set original addr to trampo addr
|
||||
m_pOriginal = m_pTrampolineAddr;
|
||||
|
||||
m_bActive = true;
|
||||
m_iHookLen = HOOKSIZE;
|
||||
m_iHookLen = ORIGSIZE;
|
||||
m_iTrampoLen = TRAMPOLINE_SIZE;
|
||||
|
||||
return true;
|
||||
|
@@ -14,29 +14,39 @@ class CFunctionHook {
|
||||
bool hook();
|
||||
bool unhook();
|
||||
|
||||
CFunctionHook(const CFunctionHook&) = delete;
|
||||
CFunctionHook(CFunctionHook&&) = delete;
|
||||
CFunctionHook(const CFunctionHook&) = delete;
|
||||
CFunctionHook(CFunctionHook&&) = delete;
|
||||
CFunctionHook& operator=(const CFunctionHook&) = delete;
|
||||
CFunctionHook& operator=(CFunctionHook&&) = delete;
|
||||
CFunctionHook& operator=(CFunctionHook&&) = delete;
|
||||
|
||||
void* m_pOriginal = nullptr;
|
||||
|
||||
private:
|
||||
void* m_pSource = nullptr;
|
||||
void* m_pFunctionAddr = nullptr;
|
||||
void* m_pTrampolineAddr = nullptr;
|
||||
void* m_pDestination = nullptr;
|
||||
size_t m_iHookLen = 0;
|
||||
size_t m_iTrampoLen = 0;
|
||||
HANDLE m_pOwner = nullptr;
|
||||
bool m_bActive = false;
|
||||
void* m_pSource = nullptr;
|
||||
void* m_pFunctionAddr = nullptr;
|
||||
void* m_pTrampolineAddr = nullptr;
|
||||
void* m_pDestination = nullptr;
|
||||
size_t m_iHookLen = 0;
|
||||
size_t m_iTrampoLen = 0;
|
||||
HANDLE m_pOwner = nullptr;
|
||||
bool m_bActive = false;
|
||||
|
||||
std::vector<std::pair<size_t, std::string>> m_vTrampolineRIPUses;
|
||||
void* m_pOriginalBytes = nullptr;
|
||||
|
||||
void* m_pOriginalBytes = nullptr;
|
||||
struct SInstructionProbe {
|
||||
size_t len = 0;
|
||||
std::string assembly = "";
|
||||
std::vector<size_t> insSizes;
|
||||
};
|
||||
|
||||
size_t probeMinimumJumpSize(void* start, size_t min);
|
||||
size_t getInstructionLenAt(void* start);
|
||||
struct SAssembly {
|
||||
std::vector<char> bytes;
|
||||
};
|
||||
|
||||
SInstructionProbe probeMinimumJumpSize(void* start, size_t min);
|
||||
SInstructionProbe getInstructionLenAt(void* start);
|
||||
|
||||
SAssembly fixInstructionProbeRIPCalls(const SInstructionProbe& probe);
|
||||
|
||||
friend class CHookSystem;
|
||||
};
|
||||
|
@@ -10,7 +10,10 @@ CPluginSystem::CPluginSystem() {
|
||||
|
||||
CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
|
||||
|
||||
m_szLastError = "";
|
||||
|
||||
if (getPluginByPath(path)) {
|
||||
m_szLastError = "Cannot load a plugin twice!";
|
||||
Debug::log(ERR, " [PluginSystem] Cannot load a plugin twice!");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -22,7 +25,9 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
|
||||
HANDLE MODULE = dlopen(path.c_str(), RTLD_LAZY);
|
||||
|
||||
if (!MODULE) {
|
||||
Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded: {}", path, dlerror());
|
||||
std::string strerr = dlerror();
|
||||
m_szLastError = std::format("Plugin {} could not be loaded: {}", path, strerr);
|
||||
Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded: {}", path, strerr);
|
||||
m_vLoadedPlugins.pop_back();
|
||||
return nullptr;
|
||||
}
|
||||
@@ -33,6 +38,7 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
|
||||
PPLUGIN_INIT_FUNC initFunc = (PPLUGIN_INIT_FUNC)dlsym(MODULE, PLUGIN_INIT_FUNC_STR);
|
||||
|
||||
if (!apiVerFunc || !initFunc) {
|
||||
m_szLastError = std::format("Plugin {} could not be loaded: {}", path, "missing apiver/init func");
|
||||
Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded. (No apiver/init func)", path);
|
||||
dlclose(MODULE);
|
||||
m_vLoadedPlugins.pop_back();
|
||||
@@ -42,6 +48,7 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
|
||||
const std::string PLUGINAPIVER = apiVerFunc();
|
||||
|
||||
if (PLUGINAPIVER != HYPRLAND_API_VERSION) {
|
||||
m_szLastError = std::format("Plugin {} could not be loaded: {}", path, "API version mismatch");
|
||||
Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded. (API version mismatch)", path);
|
||||
dlclose(MODULE);
|
||||
m_vLoadedPlugins.pop_back();
|
||||
@@ -56,10 +63,11 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
|
||||
PLUGINDATA = initFunc(MODULE);
|
||||
} else {
|
||||
// this module crashed.
|
||||
throw std::exception();
|
||||
throw std::runtime_error("received a fatal signal");
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
m_bAllowConfigVars = false;
|
||||
m_szLastError = std::format("Plugin {} could not be loaded: plugin crashed/threw in main: {}", path, e.what());
|
||||
Debug::log(ERR, " [PluginSystem] Plugin {} (Handle {:x}) crashed in init. Unloading.", path, (uintptr_t)MODULE);
|
||||
unloadPlugin(PLUGIN, true); // Plugin could've already hooked/done something
|
||||
return nullptr;
|
||||
|
@@ -38,6 +38,7 @@ class CPluginSystem {
|
||||
std::vector<CPlugin*> getAllPlugins();
|
||||
|
||||
bool m_bAllowConfigVars = false;
|
||||
std::string m_szLastError = "";
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<CPlugin>> m_vLoadedPlugins;
|
||||
|
@@ -53,7 +53,9 @@ void CFractionalScaleProtocolManager::bindManager(wl_client* client, void* data,
|
||||
static void handleDestroyScaleAddon(wl_client* client, wl_resource* resource);
|
||||
//
|
||||
|
||||
static const struct wp_fractional_scale_v1_interface fractionalScaleAddonImpl { .destroy = handleDestroyScaleAddon };
|
||||
static const struct wp_fractional_scale_v1_interface fractionalScaleAddonImpl {
|
||||
.destroy = handleDestroyScaleAddon
|
||||
};
|
||||
|
||||
//
|
||||
SFractionalScaleAddon* addonFromResource(wl_resource* resource) {
|
||||
|
@@ -210,7 +210,8 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
|
||||
PFRAME->client = PCLIENT;
|
||||
PCLIENT->ref++;
|
||||
|
||||
PFRAME->shmFormat = wlr_output_preferred_read_format(PFRAME->pMonitor->output);
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
PFRAME->shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PFRAME->pMonitor);
|
||||
if (PFRAME->shmFormat == DRM_FORMAT_INVALID) {
|
||||
Debug::log(ERR, "No format supported by renderer in capture output");
|
||||
zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
|
||||
@@ -241,7 +242,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
|
||||
wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh);
|
||||
PFRAME->box.transform(PFRAME->pMonitor->transform, ow, oh).scale(PFRAME->pMonitor->scale).round();
|
||||
|
||||
PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width;
|
||||
PFRAME->shmStride = pixel_format_info_min_stride(PSHMINFO, PFRAME->box.w);
|
||||
|
||||
zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
|
||||
|
||||
@@ -424,23 +425,76 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) {
|
||||
}
|
||||
|
||||
bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
|
||||
wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer);
|
||||
if (!sourceTex)
|
||||
return false;
|
||||
|
||||
void* data;
|
||||
uint32_t format;
|
||||
size_t stride;
|
||||
if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride))
|
||||
if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) {
|
||||
wlr_texture_destroy(sourceTex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer)) {
|
||||
Debug::log(ERR, "[sc] shm: Client requested a copy to a buffer that failed to pass wlr_renderer_begin_with_buffer");
|
||||
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
CFramebuffer fb;
|
||||
fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->drmFormat);
|
||||
|
||||
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb)) {
|
||||
wlr_texture_destroy(sourceTex);
|
||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = wlr_renderer_read_pixels(g_pCompositor->m_sWLRRenderer, format, stride, frame->box.width, frame->box.height, frame->box.x, frame->box.y, 0, 0, data);
|
||||
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
|
||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||
CBox monbox = CBox{0, 0, frame->pMonitor->vecTransformedSize.x, frame->pMonitor->vecTransformedSize.y}.translate({-frame->box.x, -frame->box.y});
|
||||
g_pHyprOpenGL->setMonitorTransformEnabled(false);
|
||||
g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1);
|
||||
g_pHyprOpenGL->setMonitorTransformEnabled(true);
|
||||
|
||||
return success;
|
||||
#ifndef GLES2
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb.m_iFb);
|
||||
#else
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.m_iFb);
|
||||
#endif
|
||||
|
||||
const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format);
|
||||
if (!PFORMAT) {
|
||||
g_pHyprRenderer->endRender();
|
||||
wlr_texture_destroy(sourceTex);
|
||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->endRender();
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
g_pHyprOpenGL->m_RenderData.pMonitor = frame->pMonitor;
|
||||
fb.bind();
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
const wlr_pixel_format_info* drmFmtWlr = drm_get_pixel_format_info(format);
|
||||
uint32_t packStride = pixel_format_info_min_stride(drmFmtWlr, frame->box.w);
|
||||
|
||||
if (packStride == stride) {
|
||||
glReadPixels(0, 0, frame->box.w, frame->box.h, PFORMAT->glFormat, PFORMAT->glType, data);
|
||||
} else {
|
||||
for (size_t i = 0; i < frame->box.h; ++i) {
|
||||
uint32_t y = i;
|
||||
glReadPixels(0, y, frame->box.w, 1, PFORMAT->glFormat, PFORMAT->glType, ((unsigned char*)data) + i * stride);
|
||||
}
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
|
||||
|
||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||
wlr_texture_destroy(sourceTex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
|
||||
@@ -448,25 +502,19 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
|
||||
if (!sourceTex)
|
||||
return false;
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_identity(glMatrix);
|
||||
wlr_matrix_translate(glMatrix, -frame->box.x, -frame->box.y);
|
||||
wlr_matrix_scale(glMatrix, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y);
|
||||
CRegion fakeDamage = {0, 0, frame->box.width, frame->box.height};
|
||||
|
||||
if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, frame->buffer)) {
|
||||
Debug::log(ERR, "[sc] dmabuf: Client requested a copy to a buffer that failed to pass wlr_renderer_begin_with_buffer");
|
||||
wlr_texture_destroy(sourceTex);
|
||||
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer))
|
||||
return false;
|
||||
}
|
||||
|
||||
float color[] = {0, 0, 0, 0};
|
||||
wlr_renderer_clear(g_pCompositor->m_sWLRRenderer, color);
|
||||
// TODO: use hl render methods to use damage
|
||||
wlr_render_texture_with_matrix(g_pCompositor->m_sWLRRenderer, sourceTex, glMatrix, 1.0f);
|
||||
CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y}.translate({-frame->box.x, -frame->box.y});
|
||||
g_pHyprOpenGL->setMonitorTransformEnabled(false);
|
||||
g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1);
|
||||
g_pHyprOpenGL->setMonitorTransformEnabled(true);
|
||||
|
||||
g_pHyprRenderer->endRender();
|
||||
|
||||
wlr_texture_destroy(sourceTex);
|
||||
|
||||
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user