mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-24 09:05:58 +01:00
Merge branch 'main' into movegroupfocus
This commit is contained in:
commit
31f08aab4e
171 changed files with 9560 additions and 4241 deletions
1
.clang-format-ignore
Normal file
1
.clang-format-ignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
subprojects/**/*
|
17
.github/ISSUE_TEMPLATE/bug.yml
vendored
17
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
@ -9,12 +9,23 @@ body:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
- type: input
|
- type: textarea
|
||||||
id: ver
|
id: ver
|
||||||
attributes:
|
attributes:
|
||||||
label: Hyprland Version
|
label: Hyprland Version
|
||||||
description: "Paste here the output of `hyprctl version`."
|
description: "Paste here the output of `hyprctl version`. For hyprland after 0.34.0, paste `hyprctl systeminfo` instead."
|
||||||
placeholder: Hyprland, built from branch main at commit...
|
value: "<details>
|
||||||
|
<summary>System/Version info</summary>
|
||||||
|
|
||||||
|
|
||||||
|
```sh
|
||||||
|
|
||||||
|
<Paste the output of the command here>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
</details>"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
|
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
|
108
.github/workflows/ci.yaml
vendored
108
.github/workflows/ci.yaml
vendored
|
@ -8,29 +8,20 @@ jobs:
|
||||||
container:
|
container:
|
||||||
image: archlinux
|
image: archlinux
|
||||||
steps:
|
steps:
|
||||||
- name: Get required pacman pkgs
|
- name: Checkout repository actions
|
||||||
run: |
|
uses: actions/checkout@v4
|
||||||
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
|
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
sparse-checkout: .github/actions
|
||||||
|
|
||||||
|
- name: Setup base
|
||||||
|
uses: ./.github/actions/setup_base
|
||||||
|
with:
|
||||||
|
INSTALL_XORG_PKGS: true
|
||||||
|
|
||||||
- name: Build Hyprland
|
- name: Build Hyprland
|
||||||
run: |
|
run: |
|
||||||
git submodule sync --recursive && git submodule update --init --force --recursive
|
|
||||||
make all
|
make all
|
||||||
|
|
||||||
- name: Compress and package artifacts
|
- name: Compress and package artifacts
|
||||||
run: |
|
run: |
|
||||||
mkdir x86_64-pc-linux-gnu
|
mkdir x86_64-pc-linux-gnu
|
||||||
|
@ -39,12 +30,13 @@ jobs:
|
||||||
mkdir hyprland/assets
|
mkdir hyprland/assets
|
||||||
cp ./LICENSE hyprland/
|
cp ./LICENSE hyprland/
|
||||||
cp build/Hyprland hyprland/
|
cp build/Hyprland hyprland/
|
||||||
cp hyprctl/hyprctl 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 build/Hyprland hyprland/
|
||||||
cp -r example/ hyprland/
|
cp -r example/ hyprland/
|
||||||
cp -r assets/ hyprland/
|
cp -r assets/ hyprland/
|
||||||
tar -cvf Hyprland.tar.xz hyprland
|
tar -cvf Hyprland.tar.xz hyprland
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
@ -57,28 +49,19 @@ jobs:
|
||||||
container:
|
container:
|
||||||
image: archlinux
|
image: archlinux
|
||||||
steps:
|
steps:
|
||||||
- name: Download dependencies
|
- name: Checkout repository actions
|
||||||
run: |
|
uses: actions/checkout@v4
|
||||||
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
|
|
||||||
with:
|
with:
|
||||||
submodules: true
|
sparse-checkout: .github/actions
|
||||||
|
|
||||||
|
- name: Setup base
|
||||||
|
uses: ./.github/actions/setup_base
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: meson setup build -Ddefault_library=static
|
||||||
meson obj-x86_64-pc-linux-gnu \
|
|
||||||
-Ddefault_library=static
|
|
||||||
- name: Compile
|
- name: Compile
|
||||||
run: ninja -C obj-x86_64-pc-linux-gnu
|
run: ninja -C build
|
||||||
|
|
||||||
noxwayland:
|
noxwayland:
|
||||||
name: "Build Hyprland in pure Wayland (Arch)"
|
name: "Build Hyprland in pure Wayland (Arch)"
|
||||||
|
@ -86,23 +69,36 @@ jobs:
|
||||||
container:
|
container:
|
||||||
image: archlinux
|
image: archlinux
|
||||||
steps:
|
steps:
|
||||||
- name: Download dependencies
|
- name: Checkout repository actions
|
||||||
run: |
|
uses: actions/checkout@v4
|
||||||
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
|
|
||||||
with:
|
with:
|
||||||
submodules: true
|
sparse-checkout: .github/actions
|
||||||
|
|
||||||
|
- name: Setup base
|
||||||
|
uses: ./.github/actions/setup_base
|
||||||
|
|
||||||
- name: Configure
|
- 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
|
- name: Compile
|
||||||
run: make config && make release
|
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:
|
matrix:
|
||||||
package:
|
package:
|
||||||
- hyprland
|
- hyprland
|
||||||
- hyprland-nvidia
|
|
||||||
- xdg-desktop-portal-hyprland
|
- xdg-desktop-portal-hyprland
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -27,4 +26,4 @@ jobs:
|
||||||
name: hyprland
|
name: hyprland
|
||||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||||
|
|
||||||
- run: nix build -L ${{ matrix.command }}
|
- run: nix build .#${{ matrix.package }} -L
|
||||||
|
|
7
.github/workflows/release.yaml
vendored
7
.github/workflows/release.yaml
vendored
|
@ -15,10 +15,15 @@ jobs:
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Generate version
|
||||||
|
id: genversion
|
||||||
|
run: |
|
||||||
|
bash -c scripts/generateVersion.sh
|
||||||
|
mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
|
||||||
|
|
||||||
- name: Create tarball with submodules
|
- name: Create tarball with submodules
|
||||||
id: tar
|
id: tar
|
||||||
run: |
|
run: |
|
||||||
sed -i "1s/^/#define GIT_COMMIT_HASH \"$(git rev-parse HEAD)\"\n#define GIT_TAG \"$(git describe --tags)\"\n/" ./src/macros.hpp
|
|
||||||
mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
|
mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
|
||||||
|
|
||||||
- id: whatrelease
|
- id: whatrelease
|
||||||
|
|
23
.github/workflows/security-checks.yml
vendored
23
.github/workflows/security-checks.yml
vendored
|
@ -42,32 +42,23 @@ jobs:
|
||||||
language: [ 'cpp' ]
|
language: [ 'cpp' ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository actions
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
sparse-checkout: .github/actions
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
- name: Init Hyprland build
|
- name: Setup base
|
||||||
run: |
|
uses: ./.github/actions/setup_base
|
||||||
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
|
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
INSTALL_XORG_PKGS: true
|
||||||
|
|
||||||
- name: Build Hyprland
|
- name: Build Hyprland
|
||||||
run: |
|
run: |
|
||||||
git submodule sync --recursive && git submodule update --init --force --recursive
|
|
||||||
make all
|
make all
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
|
|
28
.github/workflows/stale.yml
vendored
Normal file
28
.github/workflows/stale.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
|
||||||
|
#
|
||||||
|
# You can adjust the behavior by modifying this file.
|
||||||
|
# For more information, see:
|
||||||
|
# https://github.com/actions/stale
|
||||||
|
name: Mark stale issues and pull requests
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '7 */4 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v5
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.STALEBOT_PAT }}
|
||||||
|
stale-issue-label: 'stale'
|
||||||
|
stale-pr-label: 'stale'
|
||||||
|
operations-per-run: 40
|
||||||
|
days-before-close: -1
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -29,3 +29,5 @@ gmon.out
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
|
|
||||||
PKGBUILD
|
PKGBUILD
|
||||||
|
|
||||||
|
src/version.h
|
||||||
|
|
116
CMakeLists.txt
Normal file → Executable file
116
CMakeLists.txt
Normal file → Executable file
|
@ -21,37 +21,51 @@ message(STATUS "Gathering git info")
|
||||||
# Get git info
|
# Get git info
|
||||||
# hash and branch
|
# hash and branch
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND git rev-parse --abbrev-ref HEAD
|
COMMAND ./scripts/generateVersion.sh
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
OUTPUT_VARIABLE GIT_BRANCH
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND git rev-parse HEAD
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND sh -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g'"
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_COMMIT_MESSAGE
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND sh -c "git diff-index --quiet HEAD -- || echo \"dirty\""
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_DIRTY
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND sh -c "git describe --tags"
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_TAG
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# udis
|
||||||
|
add_subdirectory("subprojects/udis86")
|
||||||
|
|
||||||
|
# wlroots
|
||||||
|
message(STATUS "Setting up wlroots")
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE)
|
||||||
|
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
|
||||||
|
if(BUILDTYPE_LOWER STREQUAL "release")
|
||||||
|
# Pass.
|
||||||
|
elseif(BUILDTYPE_LOWER STREQUAL "debug")
|
||||||
|
# Pass.
|
||||||
|
elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
|
||||||
|
set(BUILDTYPE_LOWER "debugoptimized")
|
||||||
|
elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
|
||||||
|
set(BUILDTYPE_LOWER "minsize")
|
||||||
|
elseif(BUILDTYPE_LOWER STREQUAL "none")
|
||||||
|
set(BUILDTYPE_LOWER "plain")
|
||||||
|
else()
|
||||||
|
set(BUILDTYPE_LOWER "release")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(BUILDTYPE_LOWER "release")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
ExternalProject_Add(
|
||||||
|
wlroots
|
||||||
|
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||||
|
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||||
|
PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build
|
||||||
|
CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$<IF:$<BOOL:${NO_XWAYLAND}>,disabled,enabled> -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none>
|
||||||
|
BUILD_COMMAND ninja -C build
|
||||||
|
BUILD_ALWAYS true
|
||||||
|
BUILD_IN_SOURCE true
|
||||||
|
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032
|
||||||
|
INSTALL_COMMAND echo "wlroots: install not needed"
|
||||||
|
)
|
||||||
|
|
||||||
find_program(WaylandScanner NAMES wayland-scanner)
|
find_program(WaylandScanner NAMES wayland-scanner)
|
||||||
message(STATUS "Found WaylandScanner at ${WaylandScanner}")
|
message(STATUS "Found WaylandScanner at ${WaylandScanner}")
|
||||||
execute_process(
|
execute_process(
|
||||||
|
@ -85,14 +99,20 @@ set(CMAKE_ENABLE_EXPORTS TRUE)
|
||||||
message(STATUS "Checking deps...")
|
message(STATUS "Checking deps...")
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1) # we do not check for wlroots, as we provide it ourselves
|
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1) # we do not check for wlroots, as we provide it ourselves
|
||||||
|
|
||||||
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
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)
|
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
message(STATUS "Setting debug flags")
|
message(STATUS "Setting debug flags")
|
||||||
|
@ -101,7 +121,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
message(STATUS "Enabling ASan")
|
message(STATUS "Enabling ASan")
|
||||||
|
|
||||||
target_link_libraries(Hyprland asan)
|
target_link_libraries(Hyprland asan)
|
||||||
add_compile_options(-fsanitize=address)
|
target_compile_options(Hyprland PUBLIC -fsanitize=address)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(USE_TRACY)
|
if(USE_TRACY)
|
||||||
|
@ -123,6 +143,12 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
add_link_options(-pg -no-pie -fno-builtin)
|
add_link_options(-pg -no-pie -fno-builtin)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
check_include_file("execinfo.h" EXECINFOH)
|
||||||
|
if(EXECINFOH)
|
||||||
|
message(STATUS "Configuration supports execinfo")
|
||||||
|
add_compile_definitions(HAS_EXECINFO)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(CheckLibraryExists)
|
include(CheckLibraryExists)
|
||||||
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
|
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
|
||||||
if(HAVE_LIBEXECINFO)
|
if(HAVE_LIBEXECINFO)
|
||||||
|
@ -147,24 +173,21 @@ if(NO_SYSTEMD)
|
||||||
message(STATUS "SYSTEMD support is disabled...")
|
message(STATUS "SYSTEMD support is disabled...")
|
||||||
else()
|
else()
|
||||||
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined) checking deps...")
|
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined) checking deps...")
|
||||||
pkg_check_modules(LIBSYSTEMD libsystemd)
|
|
||||||
check_include_file("systemd/sd-daemon.h" SYSTEMDH)
|
check_include_file("systemd/sd-daemon.h" SYSTEMDH)
|
||||||
if(LIBSYSTEMD_FOUND AND SYSTEMDH)
|
if(SYSTEMDH)
|
||||||
|
pkg_check_modules(LIBSYSTEMD libsystemd)
|
||||||
|
if (LIBSYSTEMD_FOUND)
|
||||||
add_compile_definitions(USES_SYSTEMD)
|
add_compile_definitions(USES_SYSTEMD)
|
||||||
target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}")
|
target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}")
|
||||||
|
message(STATUS "Systemd found")
|
||||||
else()
|
else()
|
||||||
message(WARNING "Systemd support requested but libsystemd or systemd headers were not found")
|
message(WARNING "Systemd support requested but systemd libraries were not found")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(WARNING "Systemd support requested but systemd headers were not found")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_compile_definitions(Hyprland
|
|
||||||
PRIVATE
|
|
||||||
"GIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\""
|
|
||||||
"GIT_BRANCH=\"${GIT_BRANCH}\""
|
|
||||||
"GIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE}\""
|
|
||||||
"GIT_DIRTY=\"${GIT_DIRTY}\""
|
|
||||||
"GIT_TAG=\"${GIT_TAG}\"")
|
|
||||||
|
|
||||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
@ -198,11 +221,11 @@ function(protocol protoPath protoName external)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
target_link_libraries(Hyprland
|
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::EGL
|
||||||
OpenGL::GL
|
OpenGL::GL
|
||||||
Threads::Threads
|
Threads::Threads
|
||||||
${CMAKE_SOURCE_DIR}/subprojects/udis86/build/libudis86/liblibudis86.a
|
libudis86
|
||||||
)
|
)
|
||||||
|
|
||||||
protocol("protocols/idle.xml" "idle" true)
|
protocol("protocols/idle.xml" "idle" true)
|
||||||
|
@ -218,5 +241,10 @@ protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false)
|
||||||
protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false)
|
protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false)
|
||||||
protocol("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false)
|
protocol("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false)
|
||||||
protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
|
protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
|
||||||
|
protocol("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false)
|
||||||
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
|
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)
|
protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
|
||||||
|
|
||||||
|
# tools
|
||||||
|
add_subdirectory(hyprctl)
|
||||||
|
add_subdirectory(hyprpm)
|
||||||
|
|
84
Makefile
84
Makefile
|
@ -3,103 +3,76 @@ PREFIX = /usr/local
|
||||||
legacyrenderer:
|
legacyrenderer:
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
chmod -R 777 ./build
|
||||||
|
|
||||||
legacyrendererdebug:
|
legacyrendererdebug:
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
chmod -R 777 ./build
|
||||||
|
|
||||||
release:
|
release:
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
|
||||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
chmod -R 777 ./build
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -S . -B ./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -S . -B ./build -G Ninja
|
||||||
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
chmod -R 777 ./build
|
||||||
|
|
||||||
clear:
|
clear:
|
||||||
rm -rf build
|
rm -rf build
|
||||||
rm -f ./protocols/*-protocol.h ./protocols/*-protocol.c
|
rm -f ./protocols/*-protocol.h ./protocols/*-protocol.c
|
||||||
rm -f ./hyprctl/hyprctl
|
|
||||||
rm -rf ./subprojects/wlroots/build
|
rm -rf ./subprojects/wlroots/build
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
@if [[ "$EUID" = 0 ]]; then echo -en "Avoid running $(MAKE) all as sudo.\n"; fi
|
||||||
$(MAKE) clear
|
$(MAKE) clear
|
||||||
$(MAKE) fixwlr
|
|
||||||
cd ./subprojects/wlroots && meson setup build/ --buildtype=release && ninja -C build/ && mkdir -p ${PREFIX}/lib/ && cp ./build/libwlroots.so.12032 ${PREFIX}/lib/ || echo "Could not install libwlroots to ${PREFIX}/lib/libwlroots.so.12032"
|
|
||||||
cd subprojects/udis86 && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B./build -G Ninja && cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
|
||||||
$(MAKE) release
|
$(MAKE) release
|
||||||
$(MAKE) -C hyprctl all
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
$(MAKE) clear
|
@if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||||
$(MAKE) fixwlr
|
@echo -en "!NOTE: Please note make install does not compile Hyprland and only installs the already built files."
|
||||||
cd ./subprojects/wlroots && meson setup build/ --buildtype=release && ninja -C build/ && mkdir -p ${PREFIX}/lib/ && cp ./build/libwlroots.so.12032 ${PREFIX}/lib/ || echo "Could not install libwlroots to ${PREFIX}/lib/libwlroots.so.12032"
|
|
||||||
cd subprojects/udis86 && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B./build -G Ninja && cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` && cd ../..
|
|
||||||
$(MAKE) release
|
|
||||||
$(MAKE) -C hyprctl all
|
|
||||||
|
|
||||||
mkdir -p ${PREFIX}/share/wayland-sessions
|
mkdir -p ${PREFIX}/share/wayland-sessions
|
||||||
mkdir -p ${PREFIX}/bin
|
mkdir -p ${PREFIX}/bin
|
||||||
cp -f ./build/Hyprland ${PREFIX}/bin
|
cp -f ./build/Hyprland ${PREFIX}/bin
|
||||||
cp -f ./hyprctl/hyprctl ${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
|
||||||
|
cd ${PREFIX}/bin && ln -sf Hyprland hyprland
|
||||||
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
|
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
|
||||||
mkdir -p ${PREFIX}/share/hyprland
|
mkdir -p ${PREFIX}/share/hyprland
|
||||||
cp ./assets/wall_* ${PREFIX}/share/hyprland
|
cp ./assets/wall_* ${PREFIX}/share/hyprland
|
||||||
|
mkdir -p ${PREFIX}/share/xdg-desktop-portal
|
||||||
|
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
|
||||||
|
|
||||||
mkdir -p ${PREFIX}/share/man/man1
|
mkdir -p ${PREFIX}/share/man/man1
|
||||||
install -m644 ./docs/*.1 ${PREFIX}/share/man/man1
|
install -m644 ./docs/*.1 ${PREFIX}/share/man/man1
|
||||||
|
|
||||||
mkdir -p ${PREFIX}/include/hyprland
|
mkdir -p ${PREFIX}/lib/
|
||||||
mkdir -p ${PREFIX}/include/hyprland/protocols
|
cp ./subprojects/wlroots/build/libwlroots.so.13032 ${PREFIX}/lib/
|
||||||
mkdir -p ${PREFIX}/include/hyprland/wlroots
|
|
||||||
mkdir -p ${PREFIX}/share/pkgconfig
|
|
||||||
mkdir -p ${PREFIX}/share/xdg-desktop-portal
|
|
||||||
|
|
||||||
find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
|
$(MAKE) installheaders
|
||||||
cd subprojects/wlroots/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots && cd ../../..
|
|
||||||
cd subprojects/wlroots/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots && cd ../../../..
|
|
||||||
cp ./protocols/*-protocol.h ${PREFIX}/include/hyprland/protocols
|
|
||||||
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
|
|
||||||
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal/
|
|
||||||
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
|
|
||||||
|
|
||||||
cleaninstall:
|
|
||||||
echo -en "$(MAKE) cleaninstall has been DEPRECATED, you should avoid using it in the future.\nRunning $(MAKE) install instead...\n"
|
|
||||||
$(MAKE) install
|
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||||
rm -f ${PREFIX}/bin/Hyprland
|
rm -f ${PREFIX}/bin/Hyprland
|
||||||
rm -f ${PREFIX}/bin/hyprctl
|
rm -f ${PREFIX}/bin/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 -rf ${PREFIX}/share/hyprland
|
||||||
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
||||||
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
||||||
|
|
||||||
fixwlr:
|
|
||||||
sed -E -i -e 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
|
|
||||||
|
|
||||||
rm -rf ./subprojects/wlroots/build
|
|
||||||
|
|
||||||
config:
|
|
||||||
$(MAKE) fixwlr
|
|
||||||
|
|
||||||
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=release -Dwerror=false -Dexamples=false -Drenderers="gles2"
|
|
||||||
ninja -C subprojects/wlroots/build/
|
|
||||||
|
|
||||||
ninja -C subprojects/wlroots/build/ install
|
|
||||||
|
|
||||||
cd subprojects/udis86 && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja && cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
|
||||||
|
|
||||||
pluginenv:
|
pluginenv:
|
||||||
cd subprojects/udis86 && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja && cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
|
||||||
|
@exit 1
|
||||||
|
|
||||||
$(MAKE) fixwlr
|
installheaders:
|
||||||
|
@if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||||
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=release -Dwerror=false -Dexamples=false
|
|
||||||
ninja -C subprojects/wlroots/build/
|
|
||||||
|
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
|
|
||||||
|
|
||||||
mkdir -p ${PREFIX}/include/hyprland
|
mkdir -p ${PREFIX}/include/hyprland
|
||||||
mkdir -p ${PREFIX}/include/hyprland/protocols
|
mkdir -p ${PREFIX}/include/hyprland/protocols
|
||||||
|
@ -113,13 +86,8 @@ pluginenv:
|
||||||
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
|
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
|
||||||
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
|
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
|
||||||
|
|
||||||
configdebug:
|
chmod -R 755 ${PREFIX}/include/hyprland
|
||||||
$(MAKE) fixwlr
|
chmod 755 ${PREFIX}/share/pkgconfig
|
||||||
|
|
||||||
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=debug -Dwerror=false -Dexamples=false -Drenderers="gles2" -Db_sanitize=address
|
|
||||||
ninja -C subprojects/wlroots/build/
|
|
||||||
|
|
||||||
ninja -C subprojects/wlroots/build/ install
|
|
||||||
|
|
||||||
man:
|
man:
|
||||||
pandoc ./docs/Hyprland.1.rst \
|
pandoc ./docs/Hyprland.1.rst \
|
||||||
|
|
|
@ -41,6 +41,8 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
|
||||||
- Much more QoL stuff than other wlr-based compositors
|
- Much more QoL stuff than other wlr-based compositors
|
||||||
- Custom bezier curves for the best animations
|
- Custom bezier curves for the best animations
|
||||||
- Powerful plugin support
|
- Powerful plugin support
|
||||||
|
- Built-in plugin manager
|
||||||
|
- Tearing support for better gaming performance
|
||||||
- Easily expandable and readable codebase
|
- Easily expandable and readable codebase
|
||||||
- Fast and active development
|
- Fast and active development
|
||||||
- Not scared to provide bleeding-edge features
|
- Not scared to provide bleeding-edge features
|
||||||
|
@ -127,8 +129,8 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
|
||||||
<!----------------------------------{ Images }--------------------------------->
|
<!----------------------------------{ Images }--------------------------------->
|
||||||
|
|
||||||
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
||||||
[Preview A]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png
|
[Preview A]: https://i.ibb.co/C1yTb0r/falf.png
|
||||||
[Preview B]: https://i.ibb.co/SX7GbYR/winter-rice.png
|
[Preview B]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png
|
||||||
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
|
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[preferred]
|
[preferred]
|
||||||
default=hyprland
|
default=hyprland;gtk
|
|
@ -1,8 +0,0 @@
|
||||||
# compile with HYPRLAND_HEADERS=<path_to_hl> make all
|
|
||||||
# make sure that the path above is to the root hl repo directory, NOT src/
|
|
||||||
# and that you have ran `make protocols` in the hl dir.
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(CXX) -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g `pkg-config --cflags pixman-1 libdrm hyprland` -std=c++2b
|
|
||||||
clean:
|
|
||||||
rm ./examplePlugin.so
|
|
|
@ -1,74 +0,0 @@
|
||||||
#include "customDecoration.hpp"
|
|
||||||
#include <hyprland/src/Window.hpp>
|
|
||||||
#include <hyprland/src/Compositor.hpp>
|
|
||||||
#include "globals.hpp"
|
|
||||||
|
|
||||||
CCustomDecoration::CCustomDecoration(CWindow* pWindow) {
|
|
||||||
m_pWindow = pWindow;
|
|
||||||
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
|
||||||
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
|
||||||
}
|
|
||||||
|
|
||||||
CCustomDecoration::~CCustomDecoration() {
|
|
||||||
damageEntire();
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowDecorationExtents CCustomDecoration::getWindowDecorationExtents() {
|
|
||||||
return m_seExtents;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
|
|
||||||
if (!g_pCompositor->windowValidMapped(m_pWindow))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!m_pWindow->m_sSpecialRenderData.decorate)
|
|
||||||
return;
|
|
||||||
|
|
||||||
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color")->intValue;
|
|
||||||
static auto* const PROUNDING = &HyprlandAPI::getConfigValue(PHANDLE, "decoration:rounding")->intValue;
|
|
||||||
static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
|
|
||||||
|
|
||||||
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ?
|
|
||||||
0 :
|
|
||||||
(m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
|
|
||||||
|
|
||||||
// draw the border
|
|
||||||
wlr_box fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE),
|
|
||||||
(int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
|
|
||||||
|
|
||||||
fullBox.x -= pMonitor->vecPosition.x;
|
|
||||||
fullBox.y -= pMonitor->vecPosition.y;
|
|
||||||
|
|
||||||
m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2},
|
|
||||||
{fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2,
|
|
||||||
fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}};
|
|
||||||
|
|
||||||
fullBox.x += offset.x;
|
|
||||||
fullBox.y += offset.y;
|
|
||||||
|
|
||||||
if (fullBox.width < 1 || fullBox.height < 1)
|
|
||||||
return; // don't draw invisible shadows
|
|
||||||
|
|
||||||
g_pHyprOpenGL->scissor((wlr_box*)nullptr);
|
|
||||||
|
|
||||||
scaleBox(&fullBox, pMonitor->scale);
|
|
||||||
g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
eDecorationType CCustomDecoration::getDecorationType() {
|
|
||||||
return DECORATION_CUSTOM;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCustomDecoration::updateWindow(CWindow* pWindow) {
|
|
||||||
|
|
||||||
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
|
||||||
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
|
||||||
|
|
||||||
damageEntire();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCustomDecoration::damageEntire() {
|
|
||||||
wlr_box dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y),
|
|
||||||
(int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
|
|
||||||
g_pHyprRenderer->damageBox(&dm);
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define WLR_USE_UNSTABLE
|
|
||||||
|
|
||||||
#include <hyprland/src/render/decorations/IHyprWindowDecoration.hpp>
|
|
||||||
|
|
||||||
class CCustomDecoration : public IHyprWindowDecoration {
|
|
||||||
public:
|
|
||||||
CCustomDecoration(CWindow*);
|
|
||||||
virtual ~CCustomDecoration();
|
|
||||||
|
|
||||||
virtual SWindowDecorationExtents getWindowDecorationExtents();
|
|
||||||
|
|
||||||
virtual void draw(CMonitor*, float a, const Vector2D& offset);
|
|
||||||
|
|
||||||
virtual eDecorationType getDecorationType();
|
|
||||||
|
|
||||||
virtual void updateWindow(CWindow*);
|
|
||||||
|
|
||||||
virtual void damageEntire();
|
|
||||||
|
|
||||||
private:
|
|
||||||
SWindowDecorationExtents m_seExtents;
|
|
||||||
|
|
||||||
CWindow* m_pWindow = nullptr;
|
|
||||||
|
|
||||||
Vector2D m_vLastWindowPos;
|
|
||||||
Vector2D m_vLastWindowSize;
|
|
||||||
};
|
|
|
@ -1,80 +0,0 @@
|
||||||
#include "customLayout.hpp"
|
|
||||||
#include <hyprland/src/Compositor.hpp>
|
|
||||||
#include "globals.hpp"
|
|
||||||
|
|
||||||
void CHyprCustomLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
|
||||||
const auto SIZE = PMONITOR->vecSize;
|
|
||||||
|
|
||||||
// these are used for focus and move calculations, and are *required* to touch for moving focus to work properly.
|
|
||||||
pWindow->m_vPosition = Vector2D{(SIZE.x / 2.0) * (m_vWindowData.size() % 2), (SIZE.y / 2.0) * (int)(m_vWindowData.size() > 1)};
|
|
||||||
pWindow->m_vSize = SIZE / 2.0;
|
|
||||||
|
|
||||||
// this is the actual pos and size of the window (where it's rendered)
|
|
||||||
pWindow->m_vRealPosition = pWindow->m_vPosition + Vector2D{10, 10};
|
|
||||||
pWindow->m_vRealSize = pWindow->m_vSize - Vector2D{20, 20};
|
|
||||||
|
|
||||||
const auto PDATA = &m_vWindowData.emplace_back();
|
|
||||||
PDATA->pWindow = pWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
|
||||||
std::erase_if(m_vWindowData, [&](const auto& other) { return other.pWindow == pWindow; });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CHyprCustomLayout::isWindowTiled(CWindow* pWindow) {
|
|
||||||
return std::find_if(m_vWindowData.begin(), m_vWindowData.end(), [&](const auto& other) { return other.pWindow == pWindow; }) != m_vWindowData.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::recalculateMonitor(const int& eIdleInhibitMode) {
|
|
||||||
; // empty
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::recalculateWindow(CWindow* pWindow) {
|
|
||||||
; // empty
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::resizeActiveWindow(const Vector2D& delta, CWindow* pWindow) {
|
|
||||||
; // empty
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mode, bool on) {
|
|
||||||
; // empty
|
|
||||||
}
|
|
||||||
|
|
||||||
std::any CHyprCustomLayout::layoutMessage(SLayoutMessageHeader header, std::string content) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowRenderLayoutHints CHyprCustomLayout::requestRenderHints(CWindow* pWindow) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
|
|
||||||
; // empty
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
|
|
||||||
; // empty
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CHyprCustomLayout::getLayoutName() {
|
|
||||||
return "custom";
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
|
|
||||||
; // empty
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::onEnable() {
|
|
||||||
for (auto& w : g_pCompositor->m_vWindows) {
|
|
||||||
if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || w->m_bIsFloating)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
onWindowCreatedTiling(w.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHyprCustomLayout::onDisable() {
|
|
||||||
m_vWindowData.clear();
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define WLR_USE_UNSTABLE
|
|
||||||
|
|
||||||
#include <hyprland/src/layout/IHyprLayout.hpp>
|
|
||||||
|
|
||||||
struct SWindowData {
|
|
||||||
CWindow* pWindow = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CHyprCustomLayout : public IHyprLayout {
|
|
||||||
public:
|
|
||||||
virtual void onWindowCreatedTiling(CWindow*);
|
|
||||||
virtual void onWindowRemovedTiling(CWindow*);
|
|
||||||
virtual bool isWindowTiled(CWindow*);
|
|
||||||
virtual void recalculateMonitor(const int&);
|
|
||||||
virtual void recalculateWindow(CWindow*);
|
|
||||||
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
|
|
||||||
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
|
|
||||||
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
|
|
||||||
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
|
|
||||||
virtual void switchWindows(CWindow*, CWindow*);
|
|
||||||
virtual void alterSplitRatio(CWindow*, float, bool);
|
|
||||||
virtual std::string getLayoutName();
|
|
||||||
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
|
|
||||||
|
|
||||||
virtual void onEnable();
|
|
||||||
virtual void onDisable();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<SWindowData> m_vWindowData;
|
|
||||||
};
|
|
|
@ -1,5 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
|
||||||
|
|
||||||
inline HANDLE PHANDLE = nullptr;
|
|
|
@ -1,99 +0,0 @@
|
||||||
#define WLR_USE_UNSTABLE
|
|
||||||
|
|
||||||
#include "globals.hpp"
|
|
||||||
|
|
||||||
#include <hyprland/src/Window.hpp>
|
|
||||||
#include <hyprland/src/Compositor.hpp>
|
|
||||||
#include "customLayout.hpp"
|
|
||||||
#include "customDecoration.hpp"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
// Methods
|
|
||||||
inline std::unique_ptr<CHyprCustomLayout> g_pCustomLayout;
|
|
||||||
inline CFunctionHook* g_pFocusHook = nullptr;
|
|
||||||
inline CFunctionHook* g_pMotionHook = nullptr;
|
|
||||||
inline CFunctionHook* g_pMouseDownHook = nullptr;
|
|
||||||
typedef void (*origFocusWindow)(void*, CWindow*, wlr_surface*);
|
|
||||||
typedef void (*origMotion)(wlr_seat*, uint32_t, double, double);
|
|
||||||
typedef void (*origMouseDownNormal)(void*, wlr_pointer_button_event*);
|
|
||||||
|
|
||||||
// Do NOT change this function.
|
|
||||||
APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
|
||||||
return HYPRLAND_API_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void onActiveWindowChange(void* self, std::any data) {
|
|
||||||
try {
|
|
||||||
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
|
||||||
|
|
||||||
HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: " + (PWINDOW ? PWINDOW->m_szTitle : "None"), CColor{0.f, 0.5f, 1.f, 1.f}, 5000);
|
|
||||||
} catch (std::bad_any_cast& e) { HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: None", CColor{0.f, 0.5f, 1.f, 1.f}, 5000); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static void onNewWindow(void* self, std::any data) {
|
|
||||||
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
|
||||||
|
|
||||||
HyprlandAPI::addWindowDecoration(PHANDLE, PWINDOW, new CCustomDecoration(PWINDOW));
|
|
||||||
}
|
|
||||||
|
|
||||||
void hkFocusWindow(void* thisptr, CWindow* pWindow, wlr_surface* pSurface) {
|
|
||||||
// HyprlandAPI::addNotification(PHANDLE, getFormat("FocusWindow with %lx %lx", pWindow, pSurface), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
|
||||||
(*(origFocusWindow)g_pFocusHook->m_pOriginal)(thisptr, pWindow, pSurface);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hkNotifyMotion(wlr_seat* wlr_seat, uint32_t time_msec, double sx, double sy) {
|
|
||||||
// HyprlandAPI::addNotification(PHANDLE, getFormat("NotifyMotion with %lf %lf", sx, sy), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
|
||||||
(*(origMotion)g_pMotionHook->m_pOriginal)(wlr_seat, time_msec, sx, sy);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hkProcessMouseDownNormal(void* thisptr, wlr_pointer_button_event* e) {
|
|
||||||
// HyprlandAPI::addNotification(PHANDLE, "Mouse down normal!", CColor{0.8f, 0.2f, 0.5f, 1.0f}, 5000);
|
|
||||||
(*(origMouseDownNormal)g_pMouseDownHook->m_pOriginal)(thisptr, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|
||||||
PHANDLE = handle;
|
|
||||||
|
|
||||||
HyprlandAPI::addNotification(PHANDLE, "Hello World from an example plugin!", CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
|
||||||
|
|
||||||
HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, std::any data) { onActiveWindowChange(self, data); });
|
|
||||||
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, std::any data) { onNewWindow(self, data); });
|
|
||||||
|
|
||||||
g_pCustomLayout = std::make_unique<CHyprCustomLayout>();
|
|
||||||
|
|
||||||
HyprlandAPI::addLayout(PHANDLE, "custom", g_pCustomLayout.get());
|
|
||||||
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:example:border_color", SConfigValue{.intValue = configStringToInt("rgb(44ee44)")});
|
|
||||||
|
|
||||||
HyprlandAPI::addDispatcher(PHANDLE, "example", [](std::string arg) { HyprlandAPI::addNotification(PHANDLE, "Arg passed: " + arg, CColor{0.5f, 0.5f, 0.7f, 1.0f}, 5000); });
|
|
||||||
|
|
||||||
// Hook a public member
|
|
||||||
g_pFocusHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CCompositor::focusWindow, (void*)&hkFocusWindow);
|
|
||||||
// Hook a public non-member
|
|
||||||
g_pMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion);
|
|
||||||
// Hook a private member
|
|
||||||
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "processMouseDownNormal");
|
|
||||||
g_pMouseDownHook = HyprlandAPI::createFunctionHook(PHANDLE, METHODS[0].address, (void*)&hkProcessMouseDownNormal);
|
|
||||||
|
|
||||||
static auto* const PBORDERCOLOR = HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color");
|
|
||||||
|
|
||||||
// fancy notifications
|
|
||||||
HyprlandAPI::addNotificationV2(
|
|
||||||
PHANDLE,
|
|
||||||
{{"text", "Example hint, color " + std::to_string(PBORDERCOLOR->intValue)}, {"time", (uint64_t)10000}, {"color", CColor{PBORDERCOLOR->intValue}}, {"icon", ICON_HINT}});
|
|
||||||
|
|
||||||
// Enable our hooks
|
|
||||||
g_pFocusHook->hook();
|
|
||||||
g_pMotionHook->hook();
|
|
||||||
g_pMouseDownHook->hook();
|
|
||||||
|
|
||||||
HyprlandAPI::reloadConfig();
|
|
||||||
|
|
||||||
return {"ExamplePlugin", "An example plugin", "Vaxry", "1.0"};
|
|
||||||
}
|
|
||||||
|
|
||||||
APICALL EXPORT void PLUGIN_EXIT() {
|
|
||||||
HyprlandAPI::invokeHyprctlCommand("seterror", "disable");
|
|
||||||
}
|
|
|
@ -19,8 +19,14 @@ monitor=,preferred,auto,auto
|
||||||
# Source a file (multi-file configs)
|
# Source a file (multi-file configs)
|
||||||
# source = ~/.config/hypr/myColors.conf
|
# source = ~/.config/hypr/myColors.conf
|
||||||
|
|
||||||
|
# Set programs that you use
|
||||||
|
$terminal = kitty
|
||||||
|
$fileManager = dolphin
|
||||||
|
$menu = wofi --show drun
|
||||||
|
|
||||||
# Some default env vars.
|
# Some default env vars.
|
||||||
env = XCURSOR_SIZE,24
|
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/
|
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
||||||
input {
|
input {
|
||||||
|
@ -49,6 +55,9 @@ general {
|
||||||
col.inactive_border = rgba(595959aa)
|
col.inactive_border = rgba(595959aa)
|
||||||
|
|
||||||
layout = dwindle
|
layout = dwindle
|
||||||
|
|
||||||
|
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
||||||
|
allow_tearing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
decoration {
|
decoration {
|
||||||
|
@ -60,6 +69,8 @@ decoration {
|
||||||
enabled = true
|
enabled = true
|
||||||
size = 3
|
size = 3
|
||||||
passes = 1
|
passes = 1
|
||||||
|
|
||||||
|
vibrancy = 0.1696
|
||||||
}
|
}
|
||||||
|
|
||||||
drop_shadow = true
|
drop_shadow = true
|
||||||
|
@ -99,6 +110,11 @@ gestures {
|
||||||
workspace_swipe = false
|
workspace_swipe = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
misc {
|
||||||
|
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||||
|
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
|
||||||
|
}
|
||||||
|
|
||||||
# Example per-device config
|
# Example per-device config
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
|
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
|
||||||
device:epic-mouse-v1 {
|
device:epic-mouse-v1 {
|
||||||
|
@ -110,18 +126,19 @@ device:epic-mouse-v1 {
|
||||||
# Example windowrule v2
|
# Example windowrule v2
|
||||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
# 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
|
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||||
$mainMod = SUPER
|
$mainMod = SUPER
|
||||||
|
|
||||||
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
# 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, C, killactive,
|
||||||
bind = $mainMod, M, exit,
|
bind = $mainMod, M, exit,
|
||||||
bind = $mainMod, E, exec, dolphin
|
bind = $mainMod, E, exec, $fileManager
|
||||||
bind = $mainMod, V, togglefloating,
|
bind = $mainMod, V, togglefloating,
|
||||||
bind = $mainMod, R, exec, wofi --show drun
|
bind = $mainMod, R, exec, $menu
|
||||||
bind = $mainMod, P, pseudo, # dwindle
|
bind = $mainMod, P, pseudo, # dwindle
|
||||||
bind = $mainMod, J, togglesplit, # dwindle
|
bind = $mainMod, J, togglesplit, # dwindle
|
||||||
|
|
||||||
|
@ -155,6 +172,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
|
||||||
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
||||||
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
||||||
|
|
||||||
|
# Example special workspace (scratchpad)
|
||||||
|
bind = $mainMod, S, togglespecialworkspace, magic
|
||||||
|
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
|
||||||
|
|
||||||
# Scroll through existing workspaces with mainMod + scroll
|
# Scroll through existing workspaces with mainMod + scroll
|
||||||
bind = $mainMod, mouse_down, workspace, e+1
|
bind = $mainMod, mouse_down, workspace, e+1
|
||||||
bind = $mainMod, mouse_up, workspace, e-1
|
bind = $mainMod, mouse_up, workspace, e-1
|
||||||
|
|
42
flake.lock
42
flake.lock
|
@ -23,13 +23,34 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hyprlang": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"xdph",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1704287638,
|
||||||
|
"narHash": "sha256-TuRXJGwtK440AXQNl5eiqmQqY4LZ/9+z/R7xC0ie3iA=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprlang",
|
||||||
|
"rev": "6624f2bb66d4d27975766e81f77174adbe58ec97",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprlang",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1694767346,
|
"lastModified": 1705133751,
|
||||||
"narHash": "sha256-5uH27SiVFUwsTsqC5rs3kS7pBoNhtoy9QfTP9BmknGk=",
|
"narHash": "sha256-rCIsyE80jgiOU78gCWN3A0wE0tR2GI5nH6MlS+HaaSQ=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "ace5093e36ab1e95cb9463863491bee90d5a4183",
|
"rev": "9b19f5e77dd906cb52dade0b7bd280339d2a1f3d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -67,18 +88,18 @@
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"host": "gitlab.freedesktop.org",
|
"host": "gitlab.freedesktop.org",
|
||||||
"lastModified": 1695277534,
|
"lastModified": 1703963193,
|
||||||
"narHash": "sha256-LEIUGXvKR5DYFQUTavC3yifcObvG4XZUUHfxXmu8nEM=",
|
"narHash": "sha256-ke8drv6PTrdQDruWbajrRJffP9A9PU6FRyjJGNZRTs4=",
|
||||||
"owner": "wlroots",
|
"owner": "wlroots",
|
||||||
"repo": "wlroots",
|
"repo": "wlroots",
|
||||||
"rev": "98a745d926d8048bc30aef11b421df207a01c279",
|
"rev": "f81c3d93cd6f61b20ae784297679283438def8df",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"host": "gitlab.freedesktop.org",
|
"host": "gitlab.freedesktop.org",
|
||||||
"owner": "wlroots",
|
"owner": "wlroots",
|
||||||
"repo": "wlroots",
|
"repo": "wlroots",
|
||||||
"rev": "98a745d926d8048bc30aef11b421df207a01c279",
|
"rev": "f81c3d93cd6f61b20ae784297679283438def8df",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -87,6 +108,7 @@
|
||||||
"hyprland-protocols": [
|
"hyprland-protocols": [
|
||||||
"hyprland-protocols"
|
"hyprland-protocols"
|
||||||
],
|
],
|
||||||
|
"hyprlang": "hyprlang",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
],
|
||||||
|
@ -95,11 +117,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1694628480,
|
"lastModified": 1704659450,
|
||||||
"narHash": "sha256-Qg9hstRw0pvjGu5hStkr2UX1D73RYcQ9Ns/KnZMIm9w=",
|
"narHash": "sha256-3lyoUVtUWz1LuxbltAtkJSK2IlVXmKhxCRU2/0PYCms=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "xdg-desktop-portal-hyprland",
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
"rev": "8f45a6435069b9e24ebd3160eda736d7a391cbf2",
|
"rev": "6a5de92769d5b7038134044053f90e7458f6a197",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
10
flake.nix
10
flake.nix
|
@ -12,7 +12,7 @@
|
||||||
host = "gitlab.freedesktop.org";
|
host = "gitlab.freedesktop.org";
|
||||||
owner = "wlroots";
|
owner = "wlroots";
|
||||||
repo = "wlroots";
|
repo = "wlroots";
|
||||||
rev = "98a745d926d8048bc30aef11b421df207a01c279";
|
rev = "f81c3d93cd6f61b20ae784297679283438def8df";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,13 +62,16 @@
|
||||||
inherit
|
inherit
|
||||||
(pkgsFor.${system})
|
(pkgsFor.${system})
|
||||||
# hyprland-packages
|
# hyprland-packages
|
||||||
|
|
||||||
hyprland
|
hyprland
|
||||||
hyprland-unwrapped
|
hyprland-unwrapped
|
||||||
hyprland-debug
|
hyprland-debug
|
||||||
hyprland-nvidia
|
hyprland-legacy-renderer
|
||||||
# hyprland-extras
|
# hyprland-extras
|
||||||
|
|
||||||
xdg-desktop-portal-hyprland
|
xdg-desktop-portal-hyprland
|
||||||
# dependencies
|
# dependencies
|
||||||
|
|
||||||
hyprland-protocols
|
hyprland-protocols
|
||||||
wlroots-hyprland
|
wlroots-hyprland
|
||||||
udis86
|
udis86
|
||||||
|
@ -76,7 +79,8 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
devShells = eachSystem (system: {
|
devShells = eachSystem (system: {
|
||||||
default = pkgsFor.${system}.mkShell.override {
|
default =
|
||||||
|
pkgsFor.${system}.mkShell.override {
|
||||||
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
||||||
} {
|
} {
|
||||||
name = "hyprland-shell";
|
name = "hyprland-shell";
|
||||||
|
|
8
hyprctl/CMakeLists.txt
Normal file
8
hyprctl/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
|
project(
|
||||||
|
hyprctl
|
||||||
|
DESCRIPTION "Control utility for Hyprland"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(hyprctl "main.cpp")
|
|
@ -1,4 +1,4 @@
|
||||||
all:
|
all:
|
||||||
$(CXX) -std=c++2b ./main.cpp -o ./hyprctl
|
$(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl
|
||||||
clean:
|
clean:
|
||||||
rm ./hyprctl
|
rm ./hyprctl
|
||||||
|
|
|
@ -26,31 +26,35 @@
|
||||||
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
|
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
monitors
|
|
||||||
workspaces
|
|
||||||
activeworkspace
|
|
||||||
clients
|
|
||||||
activewindow
|
activewindow
|
||||||
layers
|
activeworkspace
|
||||||
devices
|
|
||||||
binds
|
binds
|
||||||
|
clients
|
||||||
|
cursorpos
|
||||||
|
decorations
|
||||||
|
devices
|
||||||
dispatch
|
dispatch
|
||||||
keyword
|
getoption
|
||||||
version
|
globalshortcuts
|
||||||
kill
|
|
||||||
splash
|
|
||||||
hyprpaper
|
hyprpaper
|
||||||
|
instances
|
||||||
|
keyword
|
||||||
|
kill
|
||||||
|
layers
|
||||||
|
layouts
|
||||||
|
monitors
|
||||||
|
notify
|
||||||
|
plugin
|
||||||
reload
|
reload
|
||||||
setcursor
|
setcursor
|
||||||
getoption
|
|
||||||
cursorpos
|
|
||||||
switchxkblayout
|
|
||||||
seterror
|
seterror
|
||||||
setprop
|
setprop
|
||||||
plugin
|
splash
|
||||||
notify
|
switchxkblayout
|
||||||
globalshortcuts
|
systeminfo
|
||||||
instances
|
version
|
||||||
|
workspacerules
|
||||||
|
workspaces
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
-j -> output in JSON
|
-j -> output in JSON
|
||||||
|
@ -273,7 +277,6 @@ bool isNumber(const std::string& str, bool allowfloat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
int bflag = 0, sflag = 0, index, c;
|
|
||||||
bool parseArgs = true;
|
bool parseArgs = true;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
|
@ -287,7 +290,7 @@ int main(int argc, char** argv) {
|
||||||
bool json = false;
|
bool json = false;
|
||||||
std::string overrideInstance = "";
|
std::string overrideInstance = "";
|
||||||
|
|
||||||
for (auto i = 0; i < ARGS.size(); ++i) {
|
for (std::size_t i = 0; i < ARGS.size(); ++i) {
|
||||||
if (ARGS[i] == "--") {
|
if (ARGS[i] == "--") {
|
||||||
// Stop parsing arguments after --
|
// Stop parsing arguments after --
|
||||||
parseArgs = false;
|
parseArgs = false;
|
||||||
|
@ -329,6 +332,12 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
fullRequest = fullArgs + "/" + fullRequest;
|
fullRequest = fullArgs + "/" + fullRequest;
|
||||||
|
|
||||||
|
// instances is HIS-independent
|
||||||
|
if (fullRequest.contains("/instances")) {
|
||||||
|
instancesRequest(json);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (overrideInstance.contains("_"))
|
if (overrideInstance.contains("_"))
|
||||||
instanceSignature = overrideInstance;
|
instanceSignature = overrideInstance;
|
||||||
else if (!overrideInstance.empty()) {
|
else if (!overrideInstance.empty()) {
|
||||||
|
@ -341,7 +350,7 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
const auto INSTANCES = instances();
|
const auto INSTANCES = instances();
|
||||||
|
|
||||||
if (INSTANCENO < 0 || INSTANCENO >= INSTANCES.size()) {
|
if (INSTANCENO < 0 || static_cast<std::size_t>(INSTANCENO) >= INSTANCES.size()) {
|
||||||
std::cout << "no such instance\n";
|
std::cout << "no such instance\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -370,6 +379,8 @@ int main(int argc, char** argv) {
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/activeworkspace"))
|
else if (fullRequest.contains("/activeworkspace"))
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/workspacerules"))
|
||||||
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/activewindow"))
|
else if (fullRequest.contains("/activewindow"))
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/layers"))
|
else if (fullRequest.contains("/layers"))
|
||||||
|
@ -378,6 +389,8 @@ int main(int argc, char** argv) {
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/kill"))
|
else if (fullRequest.contains("/kill"))
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/systeminfo"))
|
||||||
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/splash"))
|
else if (fullRequest.contains("/splash"))
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/devices"))
|
else if (fullRequest.contains("/devices"))
|
||||||
|
@ -394,8 +407,8 @@ int main(int argc, char** argv) {
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/globalshortcuts"))
|
else if (fullRequest.contains("/globalshortcuts"))
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/instances"))
|
else if (fullRequest.contains("/rollinglog"))
|
||||||
instancesRequest(json);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/switchxkblayout"))
|
else if (fullRequest.contains("/switchxkblayout"))
|
||||||
request(fullRequest, 2);
|
request(fullRequest, 2);
|
||||||
else if (fullRequest.contains("/seterror"))
|
else if (fullRequest.contains("/seterror"))
|
||||||
|
@ -414,8 +427,12 @@ int main(int argc, char** argv) {
|
||||||
request(fullRequest, 1);
|
request(fullRequest, 1);
|
||||||
else if (fullRequest.contains("/keyword"))
|
else if (fullRequest.contains("/keyword"))
|
||||||
request(fullRequest, 2);
|
request(fullRequest, 2);
|
||||||
|
else if (fullRequest.contains("/decorations"))
|
||||||
|
request(fullRequest, 1);
|
||||||
else if (fullRequest.contains("/hyprpaper"))
|
else if (fullRequest.contains("/hyprpaper"))
|
||||||
requestHyprpaper(fullRequest);
|
requestHyprpaper(fullRequest);
|
||||||
|
else if (fullRequest.contains("/layouts"))
|
||||||
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/--help"))
|
else if (fullRequest.contains("/--help"))
|
||||||
printf("%s", USAGE.c_str());
|
printf("%s", USAGE.c_str());
|
||||||
else {
|
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)
|
222
hyprpm/src/core/DataState.cpp
Normal file
222
hyprpm/src/core/DataState.cpp
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
#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},
|
||||||
|
{"failed", p.failed}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 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 FAILED = STATE[key]["failed"].value_or(false);
|
||||||
|
const auto FILENAME = STATE[key]["filename"].value_or("");
|
||||||
|
|
||||||
|
repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED, FAILED});
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
const auto FAILED = STATE[key]["failed"].value_or(false);
|
||||||
|
|
||||||
|
if (FAILED)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
(*STATE[key].as_table()).insert_or_assign("enabled", enabled);
|
||||||
|
|
||||||
|
std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
33
hyprpm/src/core/Manifest.hpp
Normal file
33
hyprpm/src/core/Manifest.hpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#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;
|
||||||
|
bool failed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
18
hyprpm/src/core/Plugin.hpp
Normal file
18
hyprpm/src/core/Plugin.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct SPlugin {
|
||||||
|
std::string name;
|
||||||
|
std::string filename;
|
||||||
|
bool enabled = false;
|
||||||
|
bool failed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SPluginRepository {
|
||||||
|
std::string url;
|
||||||
|
std::string name;
|
||||||
|
std::vector<SPlugin> plugins;
|
||||||
|
std::string hash;
|
||||||
|
};
|
731
hyprpm/src/core/PluginManager.cpp
Normal file
731
hyprpm/src/core/PluginManager.cpp
Normal file
|
@ -0,0 +1,731 @@
|
||||||
|
#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)) {
|
||||||
|
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Plugin " + p.name + " failed to build.\n");
|
||||||
|
|
||||||
|
if (m_bVerbose)
|
||||||
|
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
|
||||||
|
|
||||||
|
p.failed = true;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, p.failed});
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!p.failed)
|
||||||
|
std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n";
|
||||||
|
else
|
||||||
|
std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
17
meson.build
17
meson.build
|
@ -20,25 +20,19 @@ else
|
||||||
error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)')
|
error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
GIT_BRANCH = run_command('git', 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip()
|
|
||||||
GIT_COMMIT_HASH = run_command('git', 'rev-parse', 'HEAD', check: false).stdout().strip()
|
|
||||||
GIT_COMMIT_MESSAGE = run_command('sh', '-c', 'git show | head -n 5 | tail -n 1', check: false).stdout().strip()
|
|
||||||
GIT_DIRTY = run_command('sh', '-c', 'git diff-index --quiet HEAD -- || echo "dirty"', check: false).stdout().strip()
|
|
||||||
|
|
||||||
add_project_arguments(
|
add_project_arguments(
|
||||||
[
|
[
|
||||||
'-Wno-unused-parameter',
|
'-Wno-unused-parameter',
|
||||||
'-Wno-unused-value',
|
'-Wno-unused-value',
|
||||||
'-Wno-missing-field-initializers',
|
'-Wno-missing-field-initializers',
|
||||||
'-Wno-narrowing',
|
'-Wno-narrowing',
|
||||||
|
|
||||||
f'-DGIT_BRANCH="@GIT_BRANCH@"',
|
|
||||||
f'-DGIT_COMMIT_HASH="@GIT_COMMIT_HASH@"',
|
|
||||||
f'-DGIT_COMMIT_MESSAGE="@GIT_COMMIT_MESSAGE@"',
|
|
||||||
f'-DGIT_DIRTY="@GIT_DIRTY@"',
|
|
||||||
],
|
],
|
||||||
language: 'cpp')
|
language: 'cpp')
|
||||||
|
|
||||||
|
if cpp_compiler.check_header('execinfo.h')
|
||||||
|
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
|
wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
|
||||||
have_xwlr = wlroots.get_variable('features').get('xwayland')
|
have_xwlr = wlroots.get_variable('features').get('xwayland')
|
||||||
xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
||||||
|
@ -75,6 +69,8 @@ if get_option('buildtype') == 'debug'
|
||||||
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
|
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
version_h = run_command('sh', '-c', 'scripts/generateVersion.sh')
|
||||||
|
|
||||||
globber = run_command('find', 'src', '-name', '*.h*', check: true)
|
globber = run_command('find', 'src', '-name', '*.h*', check: true)
|
||||||
headers = globber.stdout().strip().split('\n')
|
headers = globber.stdout().strip().split('\n')
|
||||||
foreach file : headers
|
foreach file : headers
|
||||||
|
@ -84,6 +80,7 @@ endforeach
|
||||||
subdir('protocols')
|
subdir('protocols')
|
||||||
subdir('src')
|
subdir('src')
|
||||||
subdir('hyprctl')
|
subdir('hyprctl')
|
||||||
|
subdir('hyprpm/src')
|
||||||
subdir('assets')
|
subdir('assets')
|
||||||
subdir('example')
|
subdir('example')
|
||||||
subdir('docs')
|
subdir('docs')
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
git,
|
git,
|
||||||
hyprland-protocols,
|
hyprland-protocols,
|
||||||
jq,
|
jq,
|
||||||
|
libGL,
|
||||||
libdrm,
|
libdrm,
|
||||||
libinput,
|
libinput,
|
||||||
libxcb,
|
libxcb,
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
pango,
|
pango,
|
||||||
pciutils,
|
pciutils,
|
||||||
systemd,
|
systemd,
|
||||||
|
tomlplusplus,
|
||||||
udis86,
|
udis86,
|
||||||
wayland,
|
wayland,
|
||||||
wayland-protocols,
|
wayland-protocols,
|
||||||
|
@ -26,21 +28,23 @@
|
||||||
xcbutilwm,
|
xcbutilwm,
|
||||||
xwayland,
|
xwayland,
|
||||||
debug ? false,
|
debug ? false,
|
||||||
enableNvidiaPatches ? false,
|
|
||||||
enableXWayland ? true,
|
enableXWayland ? true,
|
||||||
legacyRenderer ? false,
|
legacyRenderer ? false,
|
||||||
withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
|
withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
|
||||||
wrapRuntimeDeps ? true,
|
wrapRuntimeDeps ? true,
|
||||||
version ? "git",
|
version ? "git",
|
||||||
commit,
|
commit,
|
||||||
|
date,
|
||||||
# deprecated flags
|
# deprecated flags
|
||||||
|
enableNvidiaPatches ? false,
|
||||||
nvidiaPatches ? false,
|
nvidiaPatches ? false,
|
||||||
hidpiXWayland ? 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";
|
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
pname = "hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}${lib.optionalString debug "-debug"}";
|
pname = "hyprland${lib.optionalString debug "-debug"}";
|
||||||
inherit version;
|
inherit version;
|
||||||
|
|
||||||
src = lib.cleanSourceWith {
|
src = lib.cleanSourceWith {
|
||||||
|
@ -68,19 +72,21 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||||
|
|
||||||
buildInputs =
|
buildInputs =
|
||||||
[
|
[
|
||||||
git
|
|
||||||
cairo
|
cairo
|
||||||
|
git
|
||||||
hyprland-protocols
|
hyprland-protocols
|
||||||
libdrm
|
libdrm
|
||||||
|
libGL
|
||||||
libinput
|
libinput
|
||||||
libxkbcommon
|
libxkbcommon
|
||||||
mesa
|
mesa
|
||||||
pango
|
pango
|
||||||
|
pciutils
|
||||||
|
tomlplusplus
|
||||||
udis86
|
udis86
|
||||||
wayland
|
wayland
|
||||||
wayland-protocols
|
wayland-protocols
|
||||||
pciutils
|
wlroots
|
||||||
(wlroots.override {inherit enableNvidiaPatches;})
|
|
||||||
]
|
]
|
||||||
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
|
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
|
||||||
++ lib.optionals withSystemd [systemd];
|
++ lib.optionals withSystemd [systemd];
|
||||||
|
@ -90,8 +96,9 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||||
then "debug"
|
then "debug"
|
||||||
else "release";
|
else "release";
|
||||||
|
|
||||||
|
mesonAutoFeatures = "disabled";
|
||||||
|
|
||||||
mesonFlags = builtins.concatLists [
|
mesonFlags = builtins.concatLists [
|
||||||
["-Dauto_features=disabled"]
|
|
||||||
(lib.optional enableXWayland "-Dxwayland=enabled")
|
(lib.optional enableXWayland "-Dxwayland=enabled")
|
||||||
(lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
|
(lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
|
||||||
(lib.optional withSystemd "-Dsystemd=enabled")
|
(lib.optional withSystemd "-Dsystemd=enabled")
|
||||||
|
@ -105,9 +112,16 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
# Fix hardcoded paths to /usr installation
|
# Fix hardcoded paths to /usr installation
|
||||||
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
||||||
substituteInPlace meson.build \
|
|
||||||
--replace "@GIT_COMMIT_HASH@" '${commit}' \
|
# Generate version.h
|
||||||
--replace "@GIT_DIRTY@" '${
|
cp src/version.h.in src/version.h
|
||||||
|
substituteInPlace src/version.h \
|
||||||
|
--replace "@HASH@" '${commit}' \
|
||||||
|
--replace "@BRANCH@" "" \
|
||||||
|
--replace "@MESSAGE@" "" \
|
||||||
|
--replace "@DATE@" "${date}" \
|
||||||
|
--replace "@TAG@" "" \
|
||||||
|
--replace "@DIRTY@" '${
|
||||||
if commit == ""
|
if commit == ""
|
||||||
then "dirty"
|
then "dirty"
|
||||||
else ""
|
else ""
|
||||||
|
@ -118,7 +132,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||||
ln -s ${wlroots}/include/wlr $dev/include/hyprland/wlroots
|
ln -s ${wlroots}/include/wlr $dev/include/hyprland/wlroots
|
||||||
${lib.optionalString wrapRuntimeDeps ''
|
${lib.optionalString wrapRuntimeDeps ''
|
||||||
wrapProgram $out/bin/Hyprland \
|
wrapProgram $out/bin/Hyprland \
|
||||||
--suffix PATH : ${lib.makeBinPath [binutils pciutils]}
|
--suffix PATH : ${lib.makeBinPath [
|
||||||
|
stdenv.cc
|
||||||
|
binutils
|
||||||
|
pciutils
|
||||||
|
]}
|
||||||
''}
|
''}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|
|
@ -4,174 +4,11 @@ self: {
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
cfg = config.wayland.windowManager.hyprland;
|
inherit (pkgs.stdenv.hostPlatform) system;
|
||||||
defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
|
|
||||||
enableXWayland = cfg.xwayland.enable;
|
package = self.packages.${system}.default;
|
||||||
inherit (cfg) enableNvidiaPatches;
|
|
||||||
};
|
|
||||||
in {
|
in {
|
||||||
disabledModules = ["services/window-managers/hyprland.nix"];
|
config = {
|
||||||
|
wayland.windowManager.hyprland.package = lib.mkDefault package;
|
||||||
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 = 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,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
options,
|
|
||||||
...
|
...
|
||||||
}:
|
}: let
|
||||||
with lib; let
|
|
||||||
cfg = config.programs.hyprland;
|
|
||||||
inherit (pkgs.stdenv.hostPlatform) system;
|
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;
|
hyprland = cfg.finalPackage;
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
# disables Nixpkgs Hyprland module to avoid conflicts
|
config = {
|
||||||
disabledModules = ["programs/hyprland.nix"];
|
programs.hyprland = {
|
||||||
|
package = lib.mkDefault package;
|
||||||
options.programs.hyprland = {
|
portalPackage = lib.mkDefault portalPackage;
|
||||||
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];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
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.wlroots-hyprland
|
||||||
self.overlays.udis86
|
self.overlays.udis86
|
||||||
# Hyprland packages themselves
|
# Hyprland packages themselves
|
||||||
(final: prev: {
|
(final: prev: let
|
||||||
|
date = mkDate (self.lastModifiedDate or "19700101");
|
||||||
|
in {
|
||||||
hyprland = final.callPackage ./default.nix {
|
hyprland = final.callPackage ./default.nix {
|
||||||
stdenv = final.gcc13Stdenv;
|
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;
|
wlroots = final.wlroots-hyprland;
|
||||||
commit = self.rev or "";
|
commit = self.rev or "";
|
||||||
inherit (final) udis86 hyprland-protocols;
|
inherit (final) udis86 hyprland-protocols;
|
||||||
|
inherit date;
|
||||||
};
|
};
|
||||||
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
|
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
|
||||||
hyprland-debug = final.hyprland.override {debug = true;};
|
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 =
|
hyprland-hidpi =
|
||||||
builtins.trace ''
|
builtins.trace ''
|
||||||
hyprland-hidpi was removed. Please use the hyprland package.
|
hyprland-hidpi was removed. Please use the hyprland package.
|
||||||
|
@ -65,30 +74,6 @@ in {
|
||||||
wlroots-hyprland = final.callPackage ./wlroots.nix {
|
wlroots-hyprland = final.callPackage ./wlroots.nix {
|
||||||
version = "${mkDate (inputs.wlroots.lastModifiedDate or "19700101")}_${inputs.wlroots.shortRev or "dirty"}";
|
version = "${mkDate (inputs.wlroots.lastModifiedDate or "19700101")}_${inputs.wlroots.shortRev or "dirty"}";
|
||||||
src = inputs.wlroots;
|
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,23 +1,11 @@
|
||||||
diff --git a/meson.build b/meson.build
|
diff --git a/meson.build b/meson.build
|
||||||
index f3802553..6a924a79 100644
|
index 1d2c7f9f..c5ef4e67 100644
|
||||||
--- a/meson.build
|
--- a/meson.build
|
||||||
+++ b/meson.build
|
+++ b/meson.build
|
||||||
@@ -21,9 +21,9 @@ else
|
@@ -33,20 +33,7 @@ if cpp_compiler.check_header('execinfo.h')
|
||||||
|
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
GIT_BRANCH = run_command('git', 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip()
|
|
||||||
-GIT_COMMIT_HASH = run_command('git', 'rev-parse', 'HEAD', check: false).stdout().strip()
|
|
||||||
+GIT_COMMIT_HASH = '@GIT_COMMIT_HASH@'
|
|
||||||
GIT_COMMIT_MESSAGE = run_command('sh', '-c', 'git show | head -n 5 | tail -n 1', check: false).stdout().strip()
|
|
||||||
-GIT_DIRTY = run_command('sh', '-c', 'git diff-index --quiet HEAD -- || echo "dirty"', check: false).stdout().strip()
|
|
||||||
+GIT_DIRTY = '@GIT_DIRTY@'
|
|
||||||
|
|
||||||
add_project_arguments(
|
|
||||||
[
|
|
||||||
@@ -39,21 +39,8 @@ add_project_arguments(
|
|
||||||
],
|
|
||||||
language: 'cpp')
|
|
||||||
|
|
||||||
-wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
|
-wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
|
||||||
-have_xwlr = wlroots.get_variable('features').get('xwayland')
|
-have_xwlr = wlroots.get_variable('features').get('xwayland')
|
||||||
-xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
-xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
||||||
|
@ -32,17 +20,24 @@ index f3802553..6a924a79 100644
|
||||||
-have_xwayland = xcb_dep.found() and have_xwlr
|
-have_xwayland = xcb_dep.found() and have_xwlr
|
||||||
-
|
-
|
||||||
-if not have_xwayland
|
-if not have_xwayland
|
||||||
- add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
|
||||||
+if get_option('xwayland').disabled()
|
+if get_option('xwayland').disabled()
|
||||||
+ add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
|
@@ -69,8 +56,6 @@ if get_option('buildtype') == 'debug'
|
||||||
|
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
|
-version_h = run_command('sh', '-c', 'scripts/generateVersion.sh')
|
||||||
|
-
|
||||||
|
globber = run_command('find', 'src', '-name', '*.h*', check: true)
|
||||||
|
headers = globber.stdout().strip().split('\n')
|
||||||
|
foreach file : headers
|
||||||
diff --git a/src/meson.build b/src/meson.build
|
diff --git a/src/meson.build b/src/meson.build
|
||||||
index 7b658d31..60aa4057 100644
|
index 0af864b9..38723b8c 100644
|
||||||
--- a/src/meson.build
|
--- a/src/meson.build
|
||||||
+++ b/src/meson.build
|
+++ b/src/meson.build
|
||||||
@@ -7,16 +7,16 @@ executable('Hyprland', src,
|
@@ -9,16 +9,16 @@ executable('Hyprland', src,
|
||||||
server_protos,
|
server_protos,
|
||||||
dependency('wayland-server'),
|
dependency('wayland-server'),
|
||||||
dependency('wayland-client'),
|
dependency('wayland-client'),
|
||||||
|
|
|
@ -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,
|
version,
|
||||||
src,
|
src,
|
||||||
wlroots,
|
wlroots,
|
||||||
hwdata,
|
|
||||||
libdisplay-info,
|
|
||||||
libliftoff,
|
|
||||||
enableXWayland ? true,
|
enableXWayland ? true,
|
||||||
enableNvidiaPatches ? false,
|
|
||||||
}:
|
}:
|
||||||
wlroots.overrideAttrs (old: {
|
wlroots.overrideAttrs (old: {
|
||||||
inherit version src enableXWayland;
|
inherit version src enableXWayland;
|
||||||
|
|
||||||
pname = "${old.pname}-hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}";
|
pname = "${old.pname}-hyprland";
|
||||||
|
|
||||||
patches =
|
patches = [ ]; # don't inherit old.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"
|
|
||||||
];
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"version": "0.30.0"
|
"version": "0.34.0"
|
||||||
}
|
}
|
|
@ -25,6 +25,7 @@ protocols = [
|
||||||
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
||||||
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
|
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
|
||||||
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
|
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
|
||||||
|
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
|
||||||
['wlr-foreign-toplevel-management-unstable-v1.xml'],
|
['wlr-foreign-toplevel-management-unstable-v1.xml'],
|
||||||
['wlr-layer-shell-unstable-v1.xml'],
|
['wlr-layer-shell-unstable-v1.xml'],
|
||||||
['wlr-output-power-management-unstable-v1.xml'],
|
['wlr-output-power-management-unstable-v1.xml'],
|
||||||
|
|
16
scripts/generateVersion.sh
Executable file
16
scripts/generateVersion.sh
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/sh
|
||||||
|
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
|
File diff suppressed because it is too large
Load diff
|
@ -27,9 +27,9 @@
|
||||||
#include "render/OpenGL.hpp"
|
#include "render/OpenGL.hpp"
|
||||||
#include "hyprerror/HyprError.hpp"
|
#include "hyprerror/HyprError.hpp"
|
||||||
#include "plugins/PluginSystem.hpp"
|
#include "plugins/PluginSystem.hpp"
|
||||||
|
#include "helpers/Watchdog.hpp"
|
||||||
|
|
||||||
enum eManagersInitStage
|
enum eManagersInitStage {
|
||||||
{
|
|
||||||
STAGE_PRIORITY = 0,
|
STAGE_PRIORITY = 0,
|
||||||
STAGE_LATE
|
STAGE_LATE
|
||||||
};
|
};
|
||||||
|
@ -53,7 +53,6 @@ class CCompositor {
|
||||||
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
|
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
|
||||||
wlr_xdg_activation_v1* m_sWLRXDGActivation;
|
wlr_xdg_activation_v1* m_sWLRXDGActivation;
|
||||||
wlr_output_layout* m_sWLROutputLayout;
|
wlr_output_layout* m_sWLROutputLayout;
|
||||||
wlr_idle* m_sWLRIdle;
|
|
||||||
wlr_idle_notifier_v1* m_sWLRIdleNotifier;
|
wlr_idle_notifier_v1* m_sWLRIdleNotifier;
|
||||||
wlr_layer_shell_v1* m_sWLRLayerShell;
|
wlr_layer_shell_v1* m_sWLRLayerShell;
|
||||||
wlr_xdg_shell* m_sWLRXDGShell;
|
wlr_xdg_shell* m_sWLRXDGShell;
|
||||||
|
@ -62,7 +61,6 @@ class CCompositor {
|
||||||
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
|
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
|
||||||
wlr_output_manager_v1* m_sWLROutputMgr;
|
wlr_output_manager_v1* m_sWLROutputMgr;
|
||||||
wlr_presentation* m_sWLRPresentation;
|
wlr_presentation* m_sWLRPresentation;
|
||||||
wlr_input_inhibit_manager* m_sWLRInhibitMgr;
|
|
||||||
wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr;
|
wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr;
|
||||||
wlr_egl* m_sWLREGL;
|
wlr_egl* m_sWLREGL;
|
||||||
int m_iDRMFD;
|
int m_iDRMFD;
|
||||||
|
@ -85,6 +83,7 @@ class CCompositor {
|
||||||
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
|
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
|
||||||
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
|
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
|
||||||
wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr;
|
wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr;
|
||||||
|
wlr_tearing_control_manager_v1* m_sWLRTearingControlMgr;
|
||||||
// ------------------------------------------------- //
|
// ------------------------------------------------- //
|
||||||
|
|
||||||
std::string m_szWLDisplaySocket = "";
|
std::string m_szWLDisplaySocket = "";
|
||||||
|
@ -120,7 +119,8 @@ class CCompositor {
|
||||||
bool m_bSessionActive = true;
|
bool m_bSessionActive = true;
|
||||||
bool m_bDPMSStateON = true;
|
bool m_bDPMSStateON = true;
|
||||||
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
|
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
|
||||||
wlr_output* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
|
bool m_bNextIsUnsafe = false; // because wlroots
|
||||||
|
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
|
||||||
bool m_bIsShuttingDown = false;
|
bool m_bIsShuttingDown = false;
|
||||||
|
|
||||||
// ------------------------------------------------- //
|
// ------------------------------------------------- //
|
||||||
|
@ -135,10 +135,10 @@ class CCompositor {
|
||||||
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
|
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
|
||||||
bool windowExists(CWindow*);
|
bool windowExists(CWindow*);
|
||||||
bool windowValidMapped(CWindow*);
|
bool windowValidMapped(CWindow*);
|
||||||
CWindow* vectorToWindow(const Vector2D&);
|
CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow"
|
||||||
CWindow* vectorToWindowIdeal(const Vector2D&); // used only for finding a window to focus on, basically a "findFocusableWindow"
|
|
||||||
CWindow* vectorToWindowTiled(const Vector2D&);
|
CWindow* vectorToWindowTiled(const Vector2D&);
|
||||||
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
|
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);
|
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
|
||||||
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
|
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
|
||||||
CWindow* windowFromCursor();
|
CWindow* windowFromCursor();
|
||||||
|
@ -165,16 +165,18 @@ class CCompositor {
|
||||||
void changeWindowZOrder(CWindow*, bool);
|
void changeWindowZOrder(CWindow*, bool);
|
||||||
void cleanupFadingOut(const int& monid);
|
void cleanupFadingOut(const int& monid);
|
||||||
CWindow* getWindowInDirection(CWindow*, char);
|
CWindow* getWindowInDirection(CWindow*, char);
|
||||||
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false, std::optional<bool> floating = {});
|
||||||
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false, std::optional<bool> floating = {});
|
||||||
int getNextAvailableNamedWorkspace();
|
int getNextAvailableNamedWorkspace();
|
||||||
bool isPointOnAnyMonitor(const Vector2D&);
|
bool isPointOnAnyMonitor(const Vector2D&);
|
||||||
|
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
|
||||||
CWindow* getConstraintWindow(SMouse*);
|
CWindow* getConstraintWindow(SMouse*);
|
||||||
CMonitor* getMonitorInDirection(const char&);
|
CMonitor* getMonitorInDirection(const char&);
|
||||||
void updateAllWindowsAnimatedDecorationValues();
|
void updateAllWindowsAnimatedDecorationValues();
|
||||||
|
void updateWorkspaceWindows(const int64_t& id);
|
||||||
void updateWindowAnimatedDecorationValues(CWindow*);
|
void updateWindowAnimatedDecorationValues(CWindow*);
|
||||||
int getNextAvailableMonitorID(std::string const& name);
|
int getNextAvailableMonitorID(std::string const& name);
|
||||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
|
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*, bool noWarpCursor = false);
|
||||||
void swapActiveWorkspaces(CMonitor*, CMonitor*);
|
void swapActiveWorkspaces(CMonitor*, CMonitor*);
|
||||||
CMonitor* getMonitorFromString(const std::string&);
|
CMonitor* getMonitorFromString(const std::string&);
|
||||||
bool workspaceIDOutOfBounds(const int64_t&);
|
bool workspaceIDOutOfBounds(const int64_t&);
|
||||||
|
@ -191,7 +193,6 @@ class CCompositor {
|
||||||
void closeWindow(CWindow*);
|
void closeWindow(CWindow*);
|
||||||
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
|
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
|
||||||
void forceReportSizesToWindowsOnWorkspace(const int&);
|
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!
|
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 renameWorkspace(const int&, const std::string& name = "");
|
||||||
void setActiveMonitor(CMonitor*);
|
void setActiveMonitor(CMonitor*);
|
||||||
|
@ -205,6 +206,9 @@ class CCompositor {
|
||||||
void arrangeMonitors();
|
void arrangeMonitors();
|
||||||
void enterUnsafeState();
|
void enterUnsafeState();
|
||||||
void leaveUnsafeState();
|
void leaveUnsafeState();
|
||||||
|
void setPreferredScaleForSurface(wlr_surface* pSurface, double scale);
|
||||||
|
void setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform);
|
||||||
|
void updateSuspendedStates();
|
||||||
|
|
||||||
std::string explicitConfigPath;
|
std::string explicitConfigPath;
|
||||||
|
|
||||||
|
@ -212,6 +216,7 @@ class CCompositor {
|
||||||
void initAllSignals();
|
void initAllSignals();
|
||||||
void setRandomSplash();
|
void setRandomSplash();
|
||||||
void initManagers(eManagersInitStage stage);
|
void initManagers(eManagersInitStage stage);
|
||||||
|
void prepareFallbackOutput();
|
||||||
|
|
||||||
uint64_t m_iHyprlandPID = 0;
|
uint64_t m_iHyprlandPID = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
enum eIcons
|
#include "helpers/Vector2D.hpp"
|
||||||
{
|
|
||||||
|
enum eIcons {
|
||||||
ICON_WARNING = 0,
|
ICON_WARNING = 0,
|
||||||
ICON_INFO,
|
ICON_INFO,
|
||||||
ICON_HINT,
|
ICON_HINT,
|
||||||
|
@ -11,8 +12,7 @@ enum eIcons
|
||||||
ICON_NONE
|
ICON_NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
enum eRenderStage
|
enum eRenderStage {
|
||||||
{
|
|
||||||
RENDER_PRE = 0, /* Before binding the gl context */
|
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_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 */
|
RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */
|
||||||
|
@ -23,3 +23,33 @@ enum eRenderStage
|
||||||
RENDER_PRE_WINDOW, /* Before rendering a window (any pass) Note some windows (e.g. tiled) may have 2 passes (main & popup) */
|
RENDER_PRE_WINDOW, /* Before rendering a window (any pass) Note some windows (e.g. tiled) may have 2 passes (main & popup) */
|
||||||
RENDER_POST_WINDOW, /* After rendering a window (any pass) */
|
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. */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SWindowDecorationExtents {
|
||||||
|
Vector2D topLeft;
|
||||||
|
Vector2D bottomRight;
|
||||||
|
|
||||||
|
//
|
||||||
|
SWindowDecorationExtents operator*(const double& scale) const {
|
||||||
|
return SWindowDecorationExtents{topLeft * scale, bottomRight * scale};
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowDecorationExtents round() {
|
||||||
|
return {topLeft.round(), bottomRight.round()};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const SWindowDecorationExtents& other) const {
|
||||||
|
return topLeft == other.topLeft && bottomRight == other.bottomRight;
|
||||||
|
}
|
||||||
|
};
|
276
src/Window.cpp
276
src/Window.cpp
|
@ -2,6 +2,7 @@
|
||||||
#include "Compositor.hpp"
|
#include "Compositor.hpp"
|
||||||
#include "render/decorations/CHyprDropShadowDecoration.hpp"
|
#include "render/decorations/CHyprDropShadowDecoration.hpp"
|
||||||
#include "render/decorations/CHyprGroupBarDecoration.hpp"
|
#include "render/decorations/CHyprGroupBarDecoration.hpp"
|
||||||
|
#include "render/decorations/CHyprBorderDecoration.hpp"
|
||||||
|
|
||||||
CWindow::CWindow() {
|
CWindow::CWindow() {
|
||||||
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||||
|
@ -13,7 +14,8 @@ CWindow::CWindow() {
|
||||||
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
|
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
|
||||||
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
|
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||||
|
|
||||||
m_dWindowDecorations.emplace_back(std::make_unique<CHyprDropShadowDecoration>(this)); // put the shadow so it's the first deco (has to be rendered first)
|
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
|
||||||
|
addWindowDeco(std::make_unique<CHyprBorderDecoration>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
CWindow::~CWindow() {
|
CWindow::~CWindow() {
|
||||||
|
@ -21,6 +23,12 @@ CWindow::~CWindow() {
|
||||||
g_pCompositor->m_pLastFocus = nullptr;
|
g_pCompositor->m_pLastFocus = nullptr;
|
||||||
g_pCompositor->m_pLastWindow = 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() {
|
SWindowDecorationExtents CWindow::getFullWindowExtents() {
|
||||||
|
@ -37,9 +45,7 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
|
||||||
|
|
||||||
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||||
|
|
||||||
for (auto& wd : m_dWindowDecorations) {
|
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this);
|
||||||
|
|
||||||
const auto EXTENTS = wd->getWindowDecorationExtents();
|
|
||||||
|
|
||||||
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
||||||
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
||||||
|
@ -52,15 +58,14 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
|
||||||
|
|
||||||
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
||||||
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
||||||
}
|
|
||||||
|
|
||||||
if (m_pWLSurface.exists() && !m_bIsX11) {
|
if (m_pWLSurface.exists() && !m_bIsX11) {
|
||||||
wlr_box surfaceExtents = {0, 0, 0, 0};
|
CBox surfaceExtents = {0, 0, 0, 0};
|
||||||
// TODO: this could be better, perhaps make a getFullWindowRegion?
|
// TODO: this could be better, perhaps make a getFullWindowRegion?
|
||||||
wlr_xdg_surface_for_each_popup_surface(
|
wlr_xdg_surface_for_each_popup_surface(
|
||||||
m_uSurface.xdg,
|
m_uSurface.xdg,
|
||||||
[](wlr_surface* surf, int sx, int sy, void* data) {
|
[](wlr_surface* surf, int sx, int sy, void* data) {
|
||||||
wlr_box* pSurfaceExtents = (wlr_box*)data;
|
CBox* pSurfaceExtents = (CBox*)data;
|
||||||
if (sx < pSurfaceExtents->x)
|
if (sx < pSurfaceExtents->x)
|
||||||
pSurfaceExtents->x = sx;
|
pSurfaceExtents->x = sx;
|
||||||
if (sy < pSurfaceExtents->y)
|
if (sy < pSurfaceExtents->y)
|
||||||
|
@ -88,7 +93,7 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
|
||||||
return maxExtents;
|
return maxExtents;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_box CWindow::getFullWindowBoundingBox() {
|
CBox CWindow::getFullWindowBoundingBox() {
|
||||||
if (m_sAdditionalConfigData.dimAround) {
|
if (m_sAdditionalConfigData.dimAround) {
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||||
|
@ -96,13 +101,13 @@ wlr_box CWindow::getFullWindowBoundingBox() {
|
||||||
|
|
||||||
auto maxExtents = getFullWindowExtents();
|
auto maxExtents = getFullWindowExtents();
|
||||||
|
|
||||||
wlr_box finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
||||||
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||||
|
|
||||||
return finalBox;
|
return finalBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
|
||||||
|
@ -113,7 +118,7 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||||
POS = PMONITOR->vecPosition;
|
POS = PMONITOR->vecPosition;
|
||||||
SIZE = PMONITOR->vecSize;
|
SIZE = PMONITOR->vecSize;
|
||||||
|
|
||||||
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
|
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
|
||||||
|
@ -131,10 +136,10 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||||
SIZE.y += PMONITOR->vecReservedBottomRight.y;
|
SIZE.y += PMONITOR->vecReservedBottomRight.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_box CWindow::getWindowInputBox() {
|
CBox CWindow::getWindowInputBox() {
|
||||||
const int BORDERSIZE = getRealBorderSize();
|
const int BORDERSIZE = getRealBorderSize();
|
||||||
|
|
||||||
if (m_sAdditionalConfigData.dimAround) {
|
if (m_sAdditionalConfigData.dimAround) {
|
||||||
|
@ -144,12 +149,7 @@ wlr_box CWindow::getWindowInputBox() {
|
||||||
|
|
||||||
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||||
|
|
||||||
for (auto& wd : m_dWindowDecorations) {
|
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
|
||||||
|
|
||||||
if (!wd->allowsInput())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto EXTENTS = wd->getWindowDecorationExtents();
|
|
||||||
|
|
||||||
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
||||||
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
||||||
|
@ -162,40 +162,32 @@ wlr_box CWindow::getWindowInputBox() {
|
||||||
|
|
||||||
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
||||||
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
||||||
}
|
|
||||||
|
|
||||||
// Add extents to the real base BB and return
|
// Add extents to the real base BB and return
|
||||||
wlr_box finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
||||||
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||||
|
|
||||||
return finalBox;
|
return finalBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
SWindowDecorationExtents CWindow::getFullWindowReservedArea() {
|
CBox CWindow::getWindowMainSurfaceBox() {
|
||||||
SWindowDecorationExtents extents;
|
return {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
|
||||||
|
|
||||||
for (auto& wd : m_dWindowDecorations) {
|
|
||||||
const auto RESERVED = wd->getWindowDecorationReservedArea();
|
|
||||||
|
|
||||||
if (RESERVED.bottomRight == Vector2D{} && RESERVED.topLeft == Vector2D{})
|
|
||||||
continue;
|
|
||||||
|
|
||||||
extents.topLeft = extents.topLeft + RESERVED.topLeft;
|
|
||||||
extents.bottomRight = extents.bottomRight + RESERVED.bottomRight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return extents;
|
SWindowDecorationExtents CWindow::getFullWindowReservedArea() {
|
||||||
|
return g_pDecorationPositioner->getWindowDecorationReserved(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::updateWindowDecos() {
|
void CWindow::updateWindowDecos() {
|
||||||
for (auto& wd : m_dWindowDecorations)
|
|
||||||
wd->updateWindow(this);
|
|
||||||
|
|
||||||
bool recalc = false;
|
bool recalc = false;
|
||||||
|
|
||||||
|
if (!m_bIsMapped || isHidden())
|
||||||
|
return;
|
||||||
|
|
||||||
for (auto& wd : m_vDecosToRemove) {
|
for (auto& wd : m_vDecosToRemove) {
|
||||||
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
|
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
|
||||||
if (it->get() == wd) {
|
if (it->get() == wd) {
|
||||||
|
g_pDecorationPositioner->uncacheDecoration(it->get());
|
||||||
it = m_dWindowDecorations.erase(it);
|
it = m_dWindowDecorations.erase(it);
|
||||||
recalc = true;
|
recalc = true;
|
||||||
if (it == m_dWindowDecorations.end())
|
if (it == m_dWindowDecorations.end())
|
||||||
|
@ -204,10 +196,54 @@ void CWindow::updateWindowDecos() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_pDecorationPositioner->onWindowUpdate(this);
|
||||||
|
|
||||||
if (recalc)
|
if (recalc)
|
||||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||||
|
|
||||||
m_vDecosToRemove.clear();
|
m_vDecosToRemove.clear();
|
||||||
|
|
||||||
|
for (auto& wd : m_dWindowDecorations) {
|
||||||
|
wd->updateWindow(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
pid_t CWindow::getPID() {
|
||||||
|
@ -219,6 +255,9 @@ pid_t CWindow::getPID() {
|
||||||
|
|
||||||
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
|
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
|
||||||
} else {
|
} else {
|
||||||
|
if (!m_bIsMapped)
|
||||||
|
return -1;
|
||||||
|
|
||||||
PID = m_uSurface.xwayland->pid;
|
PID = m_uSurface.xwayland->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +318,7 @@ void CWindow::destroyToplevelHandle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::updateToplevel() {
|
void CWindow::updateToplevel() {
|
||||||
updateSurfaceOutputs();
|
updateSurfaceScaleTransformDetails();
|
||||||
|
|
||||||
if (!m_phForeignToplevel)
|
if (!m_phForeignToplevel)
|
||||||
return;
|
return;
|
||||||
|
@ -306,8 +345,8 @@ void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
|
||||||
wlr_surface_send_leave(pSurface, OUTPUT);
|
wlr_surface_send_leave(pSurface, OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::updateSurfaceOutputs() {
|
void CWindow::updateSurfaceScaleTransformDetails() {
|
||||||
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden || !m_bMappedX11)
|
if (!m_bIsMapped || m_bHidden)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
|
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
|
||||||
|
@ -316,16 +355,24 @@ void CWindow::updateSurfaceOutputs() {
|
||||||
|
|
||||||
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
|
||||||
|
if (PNEWMONITOR != PLASTMONITOR) {
|
||||||
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
|
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
|
||||||
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
|
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
|
||||||
|
|
||||||
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
|
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
|
||||||
|
}
|
||||||
|
|
||||||
wlr_surface_for_each_surface(
|
wlr_surface_for_each_surface(
|
||||||
m_pWLSurface.wlr(),
|
m_pWLSurface.wlr(),
|
||||||
[](wlr_surface* surf, int x, int y, void* data) {
|
[](wlr_surface* surf, int x, int y, void* data) {
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
|
||||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
|
|
||||||
|
const auto PSURFACE = CWLSurface::surfaceFromWlr(surf);
|
||||||
|
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale);
|
||||||
|
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
|
||||||
},
|
},
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
|
@ -334,6 +381,10 @@ void CWindow::moveToWorkspace(int workspaceID) {
|
||||||
if (m_iWorkspaceID == workspaceID)
|
if (m_iWorkspaceID == workspaceID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
|
||||||
|
|
||||||
|
const int OLDWORKSPACE = m_iWorkspaceID;
|
||||||
|
|
||||||
m_iWorkspaceID = workspaceID;
|
m_iWorkspaceID = workspaceID;
|
||||||
|
|
||||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
|
||||||
|
@ -352,6 +403,15 @@ void CWindow::moveToWorkspace(int workspaceID) {
|
||||||
|
|
||||||
// update xwayland coords
|
// update xwayland coords
|
||||||
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec());
|
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec());
|
||||||
|
|
||||||
|
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) {
|
||||||
|
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE);
|
||||||
|
|
||||||
|
if (PWS) {
|
||||||
|
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWS->m_iMonitorID); PMONITOR)
|
||||||
|
PMONITOR->setSpecialWorkspace(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CWindow* CWindow::X11TransientFor() {
|
CWindow* CWindow::X11TransientFor() {
|
||||||
|
@ -414,11 +474,19 @@ void CWindow::onUnmap() {
|
||||||
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
|
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
|
||||||
PMONITOR->setSpecialWorkspace(nullptr);
|
PMONITOR->setSpecialWorkspace(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
|
||||||
|
if (PMONITOR && PMONITOR->solitaryClient == this)
|
||||||
|
PMONITOR->solitaryClient = nullptr;
|
||||||
|
|
||||||
|
g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::onMap() {
|
void CWindow::onMap() {
|
||||||
|
|
||||||
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this));
|
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this));
|
||||||
|
m_pWLSurface.m_pOwner = this;
|
||||||
|
|
||||||
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
|
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
|
||||||
m_vRealPosition.resetAllCallbacks();
|
m_vRealPosition.resetAllCallbacks();
|
||||||
|
@ -448,6 +516,8 @@ void CWindow::onMap() {
|
||||||
|
|
||||||
hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->surface->events.unmap : &m_uSurface.xdg->surface->events.unmap, &Events::listener_unmapWindow, this,
|
hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->surface->events.unmap : &m_uSurface.xdg->surface->events.unmap, &Events::listener_unmapWindow, this,
|
||||||
"CWindow");
|
"CWindow");
|
||||||
|
|
||||||
|
m_vReportedSize = m_vPendingReportedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::onBorderAngleAnimEnd(void* ptr) {
|
void CWindow::onBorderAngleAnimEnd(void* ptr) {
|
||||||
|
@ -472,6 +542,8 @@ void CWindow::setHidden(bool hidden) {
|
||||||
if (hidden && g_pCompositor->m_pLastWindow == this) {
|
if (hidden && g_pCompositor->m_pLastWindow == this) {
|
||||||
g_pCompositor->m_pLastWindow = nullptr;
|
g_pCompositor->m_pLastWindow = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSuspended(hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWindow::isHidden() {
|
bool CWindow::isHidden() {
|
||||||
|
@ -492,15 +564,19 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||||
} else if (r.szRule == "opaque") {
|
} else if (r.szRule == "opaque") {
|
||||||
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
|
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
|
||||||
m_sAdditionalConfigData.forceOpaque = true;
|
m_sAdditionalConfigData.forceOpaque = true;
|
||||||
} else if (r.szRule.find("rounding") == 0) {
|
} else if (r.szRule == "immediate") {
|
||||||
|
m_sAdditionalConfigData.forceTearing = true;
|
||||||
|
} else if (r.szRule == "nearestneighbor") {
|
||||||
|
m_sAdditionalConfigData.nearestNeighbor = true;
|
||||||
|
} else if (r.szRule.starts_with("rounding")) {
|
||||||
try {
|
try {
|
||||||
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||||
} catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
} catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||||
} else if (r.szRule.find("bordersize") == 0) {
|
} else if (r.szRule.starts_with("bordersize")) {
|
||||||
try {
|
try {
|
||||||
m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||||
} catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
} catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||||
} else if (r.szRule.find("opacity") == 0) {
|
} else if (r.szRule.starts_with("opacity")) {
|
||||||
try {
|
try {
|
||||||
CVarList vars(r.szRule, 0, ' ');
|
CVarList vars(r.szRule, 0, ' ');
|
||||||
|
|
||||||
|
@ -533,37 +609,78 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||||
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||||
} else if (r.szRule == "noanim") {
|
} else if (r.szRule == "noanim") {
|
||||||
m_sAdditionalConfigData.forceNoAnims = true;
|
m_sAdditionalConfigData.forceNoAnims = true;
|
||||||
} else if (r.szRule.find("animation") == 0) {
|
} else if (r.szRule.starts_with("animation")) {
|
||||||
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||||
m_sAdditionalConfigData.animationStyle = STYLE;
|
m_sAdditionalConfigData.animationStyle = STYLE;
|
||||||
} else if (r.szRule.find("bordercolor") == 0) {
|
} else if (r.szRule.starts_with("bordercolor")) {
|
||||||
try {
|
try {
|
||||||
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
// Each vector will only get used if it has at least one color
|
||||||
|
CGradientValueData activeBorderGradient = {};
|
||||||
|
CGradientValueData inactiveBorderGradient = {};
|
||||||
|
bool active = true;
|
||||||
|
CVarList colorsAndAngles = CVarList(removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
|
||||||
|
|
||||||
if (colorPart.contains(' ')) {
|
// Basic form has only two colors, everything else can be parsed as a gradient
|
||||||
// we have a space, 2 values
|
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
|
||||||
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart.substr(0, colorPart.find_first_of(' ')));
|
m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0])));
|
||||||
m_sSpecialRenderData.inactiveBorderColor = configStringToInt(colorPart.substr(colorPart.find_first_of(' ') + 1));
|
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1])));
|
||||||
} else {
|
return;
|
||||||
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
|
}
|
||||||
|
|
||||||
|
for (auto& token : colorsAndAngles) {
|
||||||
|
// The first angle, or an explicit "0deg", splits the two gradients
|
||||||
|
if (active && token.contains("deg")) {
|
||||||
|
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||||
|
active = false;
|
||||||
|
} else if (token.contains("deg"))
|
||||||
|
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||||
|
else if (active)
|
||||||
|
activeBorderGradient.m_vColors.push_back(configStringToInt(token));
|
||||||
|
else
|
||||||
|
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Includes sanity checks for the number of colors in each gradient
|
||||||
|
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
|
||||||
|
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
|
||||||
|
else if (activeBorderGradient.m_vColors.empty())
|
||||||
|
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
|
||||||
|
else if (inactiveBorderGradient.m_vColors.empty())
|
||||||
|
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
|
||||||
|
else {
|
||||||
|
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
|
||||||
|
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient;
|
||||||
}
|
}
|
||||||
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||||
} else if (r.szRule == "dimaround") {
|
} else if (r.szRule == "dimaround") {
|
||||||
m_sAdditionalConfigData.dimAround = true;
|
m_sAdditionalConfigData.dimAround = true;
|
||||||
} else if (r.szRule == "keepaspectratio") {
|
} else if (r.szRule == "keepaspectratio") {
|
||||||
m_sAdditionalConfigData.keepAspectRatio = true;
|
m_sAdditionalConfigData.keepAspectRatio = true;
|
||||||
} else if (r.szRule.find("xray") == 0) {
|
} else if (r.szRule.starts_with("xray")) {
|
||||||
CVarList vars(r.szRule, 0, ' ');
|
CVarList vars(r.szRule, 0, ' ');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_sAdditionalConfigData.xray = configStringToInt(vars[1]);
|
m_sAdditionalConfigData.xray = configStringToInt(vars[1]);
|
||||||
} catch (...) {}
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::updateDynamicRules() {
|
void CWindow::updateDynamicRules() {
|
||||||
m_sSpecialRenderData.activeBorderColor = -1;
|
m_sSpecialRenderData.activeBorderColor = CGradientValueData();
|
||||||
m_sSpecialRenderData.inactiveBorderColor = -1;
|
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData();
|
||||||
m_sSpecialRenderData.alpha = 1.f;
|
m_sSpecialRenderData.alpha = 1.f;
|
||||||
m_sSpecialRenderData.alphaInactive = -1.f;
|
m_sSpecialRenderData.alphaInactive = -1.f;
|
||||||
m_sAdditionalConfigData.forceNoBlur = false;
|
m_sAdditionalConfigData.forceNoBlur = false;
|
||||||
|
@ -580,6 +697,9 @@ void CWindow::updateDynamicRules() {
|
||||||
m_sAdditionalConfigData.borderSize = -1;
|
m_sAdditionalConfigData.borderSize = -1;
|
||||||
m_sAdditionalConfigData.keepAspectRatio = false;
|
m_sAdditionalConfigData.keepAspectRatio = false;
|
||||||
m_sAdditionalConfigData.xray = -1;
|
m_sAdditionalConfigData.xray = -1;
|
||||||
|
m_sAdditionalConfigData.forceTearing = false;
|
||||||
|
m_sAdditionalConfigData.nearestNeighbor = false;
|
||||||
|
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||||
|
|
||||||
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
|
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
|
||||||
for (auto& r : WINDOWRULES) {
|
for (auto& r : WINDOWRULES) {
|
||||||
|
@ -622,9 +742,9 @@ bool CWindow::isInCurvedCorner(double x, double y) {
|
||||||
void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) {
|
void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) {
|
||||||
const auto DATA = (SExtensionFindingData*)data;
|
const auto DATA = (SExtensionFindingData*)data;
|
||||||
|
|
||||||
wlr_box box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height};
|
CBox box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height};
|
||||||
|
|
||||||
if (wlr_box_contains_point(&box, DATA->vec.x, DATA->vec.y))
|
if (box.containsPoint(DATA->vec))
|
||||||
*DATA->found = surface;
|
*DATA->found = surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,14 +774,14 @@ void CWindow::createGroup() {
|
||||||
Debug::log(LOG, "createGroup: window:{:x},title:{} is denied as a group, ignored", (uintptr_t)this, this->m_szTitle);
|
Debug::log(LOG, "createGroup: window:{:x},title:{} is denied as a group, ignored", (uintptr_t)this, this->m_szTitle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_sGroupData.pNextWindow) {
|
if (!m_sGroupData.pNextWindow) {
|
||||||
m_sGroupData.pNextWindow = this;
|
m_sGroupData.pNextWindow = this;
|
||||||
m_sGroupData.head = true;
|
m_sGroupData.head = true;
|
||||||
m_sGroupData.locked = false;
|
m_sGroupData.locked = false;
|
||||||
m_sGroupData.deny = false;
|
m_sGroupData.deny = false;
|
||||||
|
|
||||||
m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(this));
|
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(this));
|
||||||
updateWindowDecos();
|
|
||||||
|
|
||||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||||
|
@ -735,6 +855,15 @@ int CWindow::getGroupSize() {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWindow::canBeGroupedInto(CWindow* pWindow) {
|
||||||
|
return !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
|
||||||
|
&& ((m_eGroupRules & GROUP_INVADE && m_bFirstMap) // window ignore local group locks, or
|
||||||
|
|| (!pWindow->getGroupHead()->m_sGroupData.locked // target unlocked
|
||||||
|
&& !(m_sGroupData.pNextWindow && getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group
|
||||||
|
&& !m_sGroupData.deny // source is not denied entry
|
||||||
|
&& !(m_eGroupRules & GROUP_BARRED && m_bFirstMap); // group rule doesn't prevent adding window
|
||||||
|
}
|
||||||
|
|
||||||
CWindow* CWindow::getGroupWindowByIndex(int index) {
|
CWindow* CWindow::getGroupWindowByIndex(int index) {
|
||||||
const int SIZE = getGroupSize();
|
const int SIZE = getGroupSize();
|
||||||
index = ((index % SIZE) + SIZE) % SIZE;
|
index = ((index % SIZE) + SIZE) % SIZE;
|
||||||
|
@ -791,6 +920,8 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
|
||||||
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode);
|
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode);
|
||||||
|
|
||||||
g_pHyprRenderer->damageWindow(pWindow);
|
g_pHyprRenderer->damageWindow(pWindow);
|
||||||
|
|
||||||
|
pWindow->updateWindowDecos();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::insertWindowToGroup(CWindow* pWindow) {
|
void CWindow::insertWindowToGroup(CWindow* pWindow) {
|
||||||
|
@ -798,7 +929,7 @@ void CWindow::insertWindowToGroup(CWindow* pWindow) {
|
||||||
const auto ENDAT = m_sGroupData.pNextWindow;
|
const auto ENDAT = m_sGroupData.pNextWindow;
|
||||||
|
|
||||||
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
|
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
|
||||||
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
|
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
|
||||||
|
|
||||||
if (!pWindow->m_sGroupData.pNextWindow) {
|
if (!pWindow->m_sGroupData.pNextWindow) {
|
||||||
BEGINAT->m_sGroupData.pNextWindow = pWindow;
|
BEGINAT->m_sGroupData.pNextWindow = pWindow;
|
||||||
|
@ -874,6 +1005,9 @@ bool CWindow::opaque() {
|
||||||
|
|
||||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
|
||||||
|
|
||||||
|
if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (PWORKSPACE->m_fAlpha.fl() != 1.f)
|
if (PWORKSPACE->m_fAlpha.fl() != 1.f)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -895,7 +1029,7 @@ float CWindow::rounding() {
|
||||||
|
|
||||||
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
|
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
|
||||||
|
|
||||||
return rounding;
|
return m_sSpecialRenderData.rounding ? rounding : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::updateSpecialRenderData() {
|
void CWindow::updateSpecialRenderData() {
|
||||||
|
@ -925,3 +1059,23 @@ int CWindow::getRealBorderSize() {
|
||||||
|
|
||||||
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ enum eGroupRules {
|
||||||
GROUP_OVERRIDE = 1 << 6, // Override other rules
|
GROUP_OVERRIDE = 1 << 6, // Override other rules
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IWindowTransformer;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class CWindowOverridableVar {
|
class CWindowOverridableVar {
|
||||||
public:
|
public:
|
||||||
|
@ -109,8 +111,8 @@ struct SWindowSpecialRenderData {
|
||||||
CWindowOverridableVar<bool> alphaInactiveOverride = false;
|
CWindowOverridableVar<bool> alphaInactiveOverride = false;
|
||||||
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
|
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
|
||||||
|
|
||||||
CWindowOverridableVar<int64_t> activeBorderColor = -1; // -1 means unset
|
CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset
|
||||||
CWindowOverridableVar<int64_t> inactiveBorderColor = -1; // -1 means unset
|
CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset
|
||||||
|
|
||||||
// set by the layout
|
// set by the layout
|
||||||
CWindowOverridableVar<int> borderSize = -1; // -1 means unset
|
CWindowOverridableVar<int> borderSize = -1; // -1 means unset
|
||||||
|
@ -138,6 +140,8 @@ struct SWindowAdditionalConfigData {
|
||||||
CWindowOverridableVar<bool> keepAspectRatio = false;
|
CWindowOverridableVar<bool> keepAspectRatio = false;
|
||||||
CWindowOverridableVar<int> xray = -1; // -1 means unset, takes precedence over the renderdata one
|
CWindowOverridableVar<int> xray = -1; // -1 means unset, takes precedence over the renderdata one
|
||||||
CWindowOverridableVar<int> borderSize = -1; // -1 means unset, takes precedence over the renderdata one
|
CWindowOverridableVar<int> borderSize = -1; // -1 means unset, takes precedence over the renderdata one
|
||||||
|
CWindowOverridableVar<bool> forceTearing = false;
|
||||||
|
CWindowOverridableVar<bool> nearestNeighbor = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SWindowRule {
|
struct SWindowRule {
|
||||||
|
@ -147,10 +151,14 @@ struct SWindowRule {
|
||||||
bool v2 = false;
|
bool v2 = false;
|
||||||
std::string szTitle;
|
std::string szTitle;
|
||||||
std::string szClass;
|
std::string szClass;
|
||||||
|
std::string szInitialTitle;
|
||||||
|
std::string szInitialClass;
|
||||||
int bX11 = -1; // -1 means "ANY"
|
int bX11 = -1; // -1 means "ANY"
|
||||||
int bFloating = -1;
|
int bFloating = -1;
|
||||||
int bFullscreen = -1;
|
int bFullscreen = -1;
|
||||||
int bPinned = -1;
|
int bPinned = -1;
|
||||||
|
int bFocus = -1;
|
||||||
|
int iOnWorkspace = -1;
|
||||||
std::string szWorkspace = ""; // empty means any
|
std::string szWorkspace = ""; // empty means any
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -179,6 +187,7 @@ class CWindow {
|
||||||
DYNLISTENER(setOverrideRedirect);
|
DYNLISTENER(setOverrideRedirect);
|
||||||
DYNLISTENER(associateX11);
|
DYNLISTENER(associateX11);
|
||||||
DYNLISTENER(dissociateX11);
|
DYNLISTENER(dissociateX11);
|
||||||
|
DYNLISTENER(ackConfigure);
|
||||||
// DYNLISTENER(newSubsurfaceWindow);
|
// DYNLISTENER(newSubsurfaceWindow);
|
||||||
|
|
||||||
CWLSurface m_pWLSurface;
|
CWLSurface m_pWLSurface;
|
||||||
|
@ -200,6 +209,9 @@ class CWindow {
|
||||||
// for not spamming the protocols
|
// for not spamming the protocols
|
||||||
Vector2D m_vReportedPosition;
|
Vector2D m_vReportedPosition;
|
||||||
Vector2D m_vReportedSize;
|
Vector2D m_vReportedSize;
|
||||||
|
Vector2D m_vPendingReportedSize;
|
||||||
|
std::optional<std::pair<uint32_t, Vector2D>> m_pPendingSizeAck;
|
||||||
|
std::vector<std::pair<uint32_t, Vector2D>> m_vPendingSizeAcks;
|
||||||
|
|
||||||
// for restoring floating statuses
|
// for restoring floating statuses
|
||||||
Vector2D m_vLastFloatingSize;
|
Vector2D m_vLastFloatingSize;
|
||||||
|
@ -229,7 +241,6 @@ class CWindow {
|
||||||
|
|
||||||
// XWayland stuff
|
// XWayland stuff
|
||||||
bool m_bIsX11 = false;
|
bool m_bIsX11 = false;
|
||||||
bool m_bMappedX11 = false;
|
|
||||||
CWindow* m_pX11Parent = nullptr;
|
CWindow* m_pX11Parent = nullptr;
|
||||||
uint64_t m_iX11Type = 0;
|
uint64_t m_iX11Type = 0;
|
||||||
bool m_bIsModal = false;
|
bool m_bIsModal = false;
|
||||||
|
@ -286,6 +297,9 @@ class CWindow {
|
||||||
SWindowSpecialRenderData m_sSpecialRenderData;
|
SWindowSpecialRenderData m_sSpecialRenderData;
|
||||||
SWindowAdditionalConfigData m_sAdditionalConfigData;
|
SWindowAdditionalConfigData m_sAdditionalConfigData;
|
||||||
|
|
||||||
|
// Transformers
|
||||||
|
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
|
||||||
|
|
||||||
// for alpha
|
// for alpha
|
||||||
CAnimatedVariable m_fActiveInactiveAlpha;
|
CAnimatedVariable m_fActiveInactiveAlpha;
|
||||||
|
|
||||||
|
@ -317,6 +331,8 @@ class CWindow {
|
||||||
} m_sGroupData;
|
} m_sGroupData;
|
||||||
uint16_t m_eGroupRules = GROUP_NONE;
|
uint16_t m_eGroupRules = GROUP_NONE;
|
||||||
|
|
||||||
|
bool m_bTearingHint = false;
|
||||||
|
|
||||||
// For the list lookup
|
// For the list lookup
|
||||||
bool operator==(const CWindow& rhs) {
|
bool operator==(const CWindow& rhs) {
|
||||||
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
|
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
|
||||||
|
@ -324,18 +340,23 @@ class CWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
wlr_box getFullWindowBoundingBox();
|
CBox getFullWindowBoundingBox();
|
||||||
SWindowDecorationExtents getFullWindowExtents();
|
SWindowDecorationExtents getFullWindowExtents();
|
||||||
wlr_box getWindowInputBox();
|
CBox getWindowInputBox();
|
||||||
wlr_box getWindowIdealBoundingBoxIgnoreReserved();
|
CBox getWindowMainSurfaceBox();
|
||||||
|
CBox getWindowIdealBoundingBoxIgnoreReserved();
|
||||||
|
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
|
||||||
void updateWindowDecos();
|
void updateWindowDecos();
|
||||||
|
void removeWindowDeco(IHyprWindowDecoration* deco);
|
||||||
|
void uncacheWindowDecos();
|
||||||
|
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
|
||||||
pid_t getPID();
|
pid_t getPID();
|
||||||
IHyprWindowDecoration* getDecorationByType(eDecorationType);
|
IHyprWindowDecoration* getDecorationByType(eDecorationType);
|
||||||
void removeDecorationByType(eDecorationType);
|
void removeDecorationByType(eDecorationType);
|
||||||
void createToplevelHandle();
|
void createToplevelHandle();
|
||||||
void destroyToplevelHandle();
|
void destroyToplevelHandle();
|
||||||
void updateToplevel();
|
void updateToplevel();
|
||||||
void updateSurfaceOutputs();
|
void updateSurfaceScaleTransformDetails();
|
||||||
void moveToWorkspace(int);
|
void moveToWorkspace(int);
|
||||||
CWindow* X11TransientFor();
|
CWindow* X11TransientFor();
|
||||||
void onUnmap();
|
void onUnmap();
|
||||||
|
@ -348,6 +369,9 @@ class CWindow {
|
||||||
Vector2D middle();
|
Vector2D middle();
|
||||||
bool opaque();
|
bool opaque();
|
||||||
float rounding();
|
float rounding();
|
||||||
|
bool canBeTorn();
|
||||||
|
bool shouldSendFullscreenState();
|
||||||
|
void setSuspended(bool suspend);
|
||||||
|
|
||||||
int getRealBorderSize();
|
int getRealBorderSize();
|
||||||
void updateSpecialRenderData();
|
void updateSpecialRenderData();
|
||||||
|
@ -365,6 +389,7 @@ class CWindow {
|
||||||
CWindow* getGroupPrevious();
|
CWindow* getGroupPrevious();
|
||||||
CWindow* getGroupWindowByIndex(int);
|
CWindow* getGroupWindowByIndex(int);
|
||||||
int getGroupSize();
|
int getGroupSize();
|
||||||
|
bool canBeGroupedInto(CWindow* pWindow);
|
||||||
void setGroupCurrent(CWindow* pWindow);
|
void setGroupCurrent(CWindow* pWindow);
|
||||||
void insertWindowToGroup(CWindow* pWindow);
|
void insertWindowToGroup(CWindow* pWindow);
|
||||||
void updateGroupOutputs();
|
void updateGroupOutputs();
|
||||||
|
@ -373,6 +398,7 @@ class CWindow {
|
||||||
private:
|
private:
|
||||||
// For hidden windows and stuff
|
// For hidden windows and stuff
|
||||||
bool m_bHidden = false;
|
bool m_bHidden = false;
|
||||||
|
bool m_bSuspended = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,7 @@ class ICustomConfigValueData {
|
||||||
|
|
||||||
class CGradientValueData : public ICustomConfigValueData {
|
class CGradientValueData : public ICustomConfigValueData {
|
||||||
public:
|
public:
|
||||||
|
CGradientValueData(){};
|
||||||
CGradientValueData(CColor col) {
|
CGradientValueData(CColor col) {
|
||||||
m_vColors.push_back(col);
|
m_vColors.push_back(col);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
#include "ConfigManager.hpp"
|
#include "ConfigManager.hpp"
|
||||||
#include "../managers/KeybindManager.hpp"
|
#include "../managers/KeybindManager.hpp"
|
||||||
|
|
||||||
|
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -19,10 +22,18 @@ CConfigManager::CConfigManager() {
|
||||||
configValues["general:col.inactive_border"].data = std::make_shared<CGradientValueData>(0xff444444);
|
configValues["general:col.inactive_border"].data = std::make_shared<CGradientValueData>(0xff444444);
|
||||||
configValues["general:col.nogroup_border"].data = std::make_shared<CGradientValueData>(0xffffaaff);
|
configValues["general:col.nogroup_border"].data = std::make_shared<CGradientValueData>(0xffffaaff);
|
||||||
configValues["general:col.nogroup_border_active"].data = std::make_shared<CGradientValueData>(0xffff00ff);
|
configValues["general:col.nogroup_border_active"].data = std::make_shared<CGradientValueData>(0xffff00ff);
|
||||||
configValues["general:col.group_border"].data = std::make_shared<CGradientValueData>(0x66777700);
|
|
||||||
configValues["general:col.group_border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
|
configValues["group:col.border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
|
||||||
configValues["general:col.group_border_locked"].data = std::make_shared<CGradientValueData>(0x66775500);
|
configValues["group:col.border_inactive"].data = std::make_shared<CGradientValueData>(0x66777700);
|
||||||
configValues["general:col.group_border_locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500);
|
configValues["group:col.border_locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500);
|
||||||
|
configValues["group:col.border_locked_inactive"].data = std::make_shared<CGradientValueData>(0x66775500);
|
||||||
|
|
||||||
|
configValues["group:groupbar:col.active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
|
||||||
|
configValues["group:groupbar:col.inactive"].data = std::make_shared<CGradientValueData>(0x66777700);
|
||||||
|
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();
|
setDefaultVars();
|
||||||
setDefaultAnimationVars();
|
setDefaultAnimationVars();
|
||||||
|
@ -37,12 +48,11 @@ CConfigManager::CConfigManager() {
|
||||||
|
|
||||||
std::string CConfigManager::getConfigDir() {
|
std::string CConfigManager::getConfigDir() {
|
||||||
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
|
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
|
||||||
std::string configPath;
|
|
||||||
if (!xdgConfigHome)
|
if (xdgConfigHome && std::filesystem::path(xdgConfigHome).is_absolute())
|
||||||
configPath = getenv("HOME") + std::string("/.config");
|
return xdgConfigHome;
|
||||||
else
|
|
||||||
configPath = xdgConfigHome;
|
return getenv("HOME") + std::string("/.config");
|
||||||
return configPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CConfigManager::getMainConfigPath() {
|
std::string CConfigManager::getMainConfigPath() {
|
||||||
|
@ -70,16 +80,14 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["general:apply_sens_to_raw"].intValue = 0;
|
configValues["general:apply_sens_to_raw"].intValue = 0;
|
||||||
configValues["general:border_size"].intValue = 1;
|
configValues["general:border_size"].intValue = 1;
|
||||||
configValues["general:no_border_on_floating"].intValue = 0;
|
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_in"].intValue = 5;
|
||||||
configValues["general:gaps_out"].intValue = 20;
|
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.active_border"].data.get())->reset(0xffffffff);
|
||||||
((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
|
((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
|
||||||
((CGradientValueData*)configValues["general:col.nogroup_border"].data.get())->reset(0xff444444);
|
((CGradientValueData*)configValues["general:col.nogroup_border"].data.get())->reset(0xff444444);
|
||||||
((CGradientValueData*)configValues["general:col.nogroup_border_active"].data.get())->reset(0xffff00ff);
|
((CGradientValueData*)configValues["general:col.nogroup_border_active"].data.get())->reset(0xffff00ff);
|
||||||
((CGradientValueData*)configValues["general:col.group_border"].data.get())->reset(0x66777700);
|
|
||||||
((CGradientValueData*)configValues["general:col.group_border_active"].data.get())->reset(0x66ffff00);
|
|
||||||
((CGradientValueData*)configValues["general:col.group_border_locked"].data.get())->reset(0x66775500);
|
|
||||||
((CGradientValueData*)configValues["general:col.group_border_locked_active"].data.get())->reset(0x66ff5500);
|
|
||||||
configValues["general:cursor_inactive_timeout"].intValue = 0;
|
configValues["general:cursor_inactive_timeout"].intValue = 0;
|
||||||
configValues["general:no_cursor_warps"].intValue = 0;
|
configValues["general:no_cursor_warps"].intValue = 0;
|
||||||
configValues["general:no_focus_fallback"].intValue = 0;
|
configValues["general:no_focus_fallback"].intValue = 0;
|
||||||
|
@ -87,11 +95,12 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["general:extend_border_grab_area"].intValue = 15;
|
configValues["general:extend_border_grab_area"].intValue = 15;
|
||||||
configValues["general:hover_icon_on_border"].intValue = 1;
|
configValues["general:hover_icon_on_border"].intValue = 1;
|
||||||
configValues["general:layout"].strValue = "dwindle";
|
configValues["general:layout"].strValue = "dwindle";
|
||||||
|
configValues["general:allow_tearing"].intValue = 0;
|
||||||
|
|
||||||
configValues["misc:disable_hyprland_logo"].intValue = 0;
|
configValues["misc:disable_hyprland_logo"].intValue = 0;
|
||||||
configValues["misc:disable_splash_rendering"].intValue = 0;
|
configValues["misc:disable_splash_rendering"].intValue = 0;
|
||||||
configValues["misc:disable_hypr_chan"].intValue = 0;
|
|
||||||
configValues["misc:force_hypr_chan"].intValue = 0;
|
configValues["misc:force_hypr_chan"].intValue = 0;
|
||||||
|
configValues["misc:force_default_wallpaper"].intValue = -1;
|
||||||
configValues["misc:vfr"].intValue = 1;
|
configValues["misc:vfr"].intValue = 1;
|
||||||
configValues["misc:vrr"].intValue = 0;
|
configValues["misc:vrr"].intValue = 0;
|
||||||
configValues["misc:mouse_move_enables_dpms"].intValue = 0;
|
configValues["misc:mouse_move_enables_dpms"].intValue = 0;
|
||||||
|
@ -113,26 +122,45 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["misc:cursor_zoom_factor"].floatValue = 1.f;
|
configValues["misc:cursor_zoom_factor"].floatValue = 1.f;
|
||||||
configValues["misc:cursor_zoom_rigid"].intValue = 0;
|
configValues["misc:cursor_zoom_rigid"].intValue = 0;
|
||||||
configValues["misc:allow_session_lock_restore"].intValue = 0;
|
configValues["misc:allow_session_lock_restore"].intValue = 0;
|
||||||
configValues["misc:groupbar_scrolling"].intValue = 1;
|
|
||||||
configValues["misc:group_insert_after_current"].intValue = 1;
|
|
||||||
configValues["misc:group_focus_removed_window"].intValue = 1;
|
|
||||||
configValues["misc:render_titles_in_groupbar"].intValue = 1;
|
|
||||||
configValues["misc:groupbar_titles_font_size"].intValue = 8;
|
|
||||||
configValues["misc:groupbar_gradients"].intValue = 1;
|
|
||||||
configValues["misc:close_special_on_empty"].intValue = 1;
|
configValues["misc:close_special_on_empty"].intValue = 1;
|
||||||
configValues["misc:groupbar_text_color"].intValue = 0xffffffff;
|
|
||||||
configValues["misc:background_color"].intValue = 0xff111111;
|
configValues["misc:background_color"].intValue = 0xff111111;
|
||||||
|
configValues["misc:new_window_takes_over_fullscreen"].intValue = 0;
|
||||||
|
|
||||||
|
((CGradientValueData*)configValues["group:col.border_active"].data.get())->reset(0x66ffff00);
|
||||||
|
((CGradientValueData*)configValues["group:col.border_inactive"].data.get())->reset(0x66777700);
|
||||||
|
((CGradientValueData*)configValues["group:col.border_locked_active"].data.get())->reset(0x66ff5500);
|
||||||
|
((CGradientValueData*)configValues["group:col.border_locked_inactive"].data.get())->reset(0x66775500);
|
||||||
|
|
||||||
|
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:height"].intValue = 14;
|
||||||
|
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;
|
||||||
|
|
||||||
|
((CGradientValueData*)configValues["group:groupbar:col.active"].data.get())->reset(0x66ffff00);
|
||||||
|
((CGradientValueData*)configValues["group:groupbar:col.inactive"].data.get())->reset(0x66777700);
|
||||||
|
((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:int"].intValue = 0;
|
||||||
configValues["debug:log_damage"].intValue = 0;
|
configValues["debug:log_damage"].intValue = 0;
|
||||||
configValues["debug:overlay"].intValue = 0;
|
configValues["debug:overlay"].intValue = 0;
|
||||||
configValues["debug:damage_blink"].intValue = 0;
|
configValues["debug:damage_blink"].intValue = 0;
|
||||||
configValues["debug:disable_logs"].intValue = 0;
|
configValues["debug:disable_logs"].intValue = 1;
|
||||||
configValues["debug:disable_time"].intValue = 1;
|
configValues["debug:disable_time"].intValue = 1;
|
||||||
configValues["debug:enable_stdout_logs"].intValue = 0;
|
configValues["debug:enable_stdout_logs"].intValue = 0;
|
||||||
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
|
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
|
||||||
configValues["debug:manual_crash"].intValue = 0;
|
configValues["debug:manual_crash"].intValue = 0;
|
||||||
configValues["debug:suppress_errors"].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:rounding"].intValue = 0;
|
||||||
configValues["decoration:blur:enabled"].intValue = 1;
|
configValues["decoration:blur:enabled"].intValue = 1;
|
||||||
|
@ -141,14 +169,17 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["decoration:blur:ignore_opacity"].intValue = 0;
|
configValues["decoration:blur:ignore_opacity"].intValue = 0;
|
||||||
configValues["decoration:blur:new_optimizations"].intValue = 1;
|
configValues["decoration:blur:new_optimizations"].intValue = 1;
|
||||||
configValues["decoration:blur:xray"].intValue = 0;
|
configValues["decoration:blur:xray"].intValue = 0;
|
||||||
configValues["decoration:blur:noise"].floatValue = 0.0117;
|
|
||||||
configValues["decoration:blur:contrast"].floatValue = 0.8916;
|
configValues["decoration:blur:contrast"].floatValue = 0.8916;
|
||||||
configValues["decoration:blur:brightness"].floatValue = 0.8172;
|
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: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:active_opacity"].floatValue = 1;
|
||||||
configValues["decoration:inactive_opacity"].floatValue = 1;
|
configValues["decoration:inactive_opacity"].floatValue = 1;
|
||||||
configValues["decoration:fullscreen_opacity"].floatValue = 1;
|
configValues["decoration:fullscreen_opacity"].floatValue = 1;
|
||||||
configValues["decoration:multisample_edges"].intValue = 1;
|
|
||||||
configValues["decoration:no_blur_on_oversized"].intValue = 0;
|
configValues["decoration:no_blur_on_oversized"].intValue = 0;
|
||||||
configValues["decoration:drop_shadow"].intValue = 1;
|
configValues["decoration:drop_shadow"].intValue = 1;
|
||||||
configValues["decoration:shadow_range"].intValue = 4;
|
configValues["decoration:shadow_range"].intValue = 4;
|
||||||
|
@ -168,7 +199,7 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["dwindle:force_split"].intValue = 0;
|
configValues["dwindle:force_split"].intValue = 0;
|
||||||
configValues["dwindle:permanent_direction_override"].intValue = 0;
|
configValues["dwindle:permanent_direction_override"].intValue = 0;
|
||||||
configValues["dwindle:preserve_split"].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:split_width_multiplier"].floatValue = 1.0f;
|
||||||
configValues["dwindle:no_gaps_when_only"].intValue = 0;
|
configValues["dwindle:no_gaps_when_only"].intValue = 0;
|
||||||
configValues["dwindle:use_active_for_splits"].intValue = 1;
|
configValues["dwindle:use_active_for_splits"].intValue = 1;
|
||||||
|
@ -176,7 +207,7 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["dwindle:smart_split"].intValue = 0;
|
configValues["dwindle:smart_split"].intValue = 0;
|
||||||
configValues["dwindle:smart_resizing"].intValue = 1;
|
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:mfact"].floatValue = 0.55f;
|
||||||
configValues["master:new_is_master"].intValue = 1;
|
configValues["master:new_is_master"].intValue = 1;
|
||||||
configValues["master:always_center_master"].intValue = 0;
|
configValues["master:always_center_master"].intValue = 0;
|
||||||
|
@ -186,11 +217,14 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["master:inherit_fullscreen"].intValue = 1;
|
configValues["master:inherit_fullscreen"].intValue = 1;
|
||||||
configValues["master:allow_small_split"].intValue = 0;
|
configValues["master:allow_small_split"].intValue = 0;
|
||||||
configValues["master:smart_resizing"].intValue = 1;
|
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:follow_mouse"].intValue = 1;
|
||||||
configValues["input:mouse_refocus"].intValue = 1;
|
configValues["input:mouse_refocus"].intValue = 1;
|
||||||
|
configValues["input:special_fallthrough"].intValue = 0;
|
||||||
configValues["input:sensitivity"].floatValue = 0.f;
|
configValues["input:sensitivity"].floatValue = 0.f;
|
||||||
configValues["input:accel_profile"].strValue = STRVAL_EMPTY;
|
configValues["input:accel_profile"].strValue = STRVAL_EMPTY;
|
||||||
configValues["input:kb_file"].strValue = STRVAL_EMPTY;
|
configValues["input:kb_file"].strValue = STRVAL_EMPTY;
|
||||||
|
@ -209,6 +243,7 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
|
configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
|
||||||
configValues["input:scroll_button"].intValue = 0;
|
configValues["input:scroll_button"].intValue = 0;
|
||||||
configValues["input:scroll_button_lock"].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:natural_scroll"].intValue = 0;
|
||||||
configValues["input:touchpad:disable_while_typing"].intValue = 1;
|
configValues["input:touchpad:disable_while_typing"].intValue = 1;
|
||||||
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
|
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
|
||||||
|
@ -222,13 +257,18 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY;
|
configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY;
|
||||||
configValues["input:tablet:transform"].intValue = 0;
|
configValues["input:tablet:transform"].intValue = 0;
|
||||||
configValues["input:tablet:output"].strValue = STRVAL_EMPTY;
|
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:pass_mouse_when_bound"].intValue = 0;
|
||||||
configValues["binds:scroll_event_delay"].intValue = 300;
|
configValues["binds:scroll_event_delay"].intValue = 300;
|
||||||
configValues["binds:workspace_back_and_forth"].intValue = 0;
|
configValues["binds:workspace_back_and_forth"].intValue = 0;
|
||||||
configValues["binds:allow_workspace_cycles"].intValue = 0;
|
configValues["binds:allow_workspace_cycles"].intValue = 0;
|
||||||
|
configValues["binds:workspace_center_on"].intValue = 1;
|
||||||
configValues["binds:focus_preferred_method"].intValue = 0;
|
configValues["binds:focus_preferred_method"].intValue = 0;
|
||||||
configValues["binds:ignore_group_lock"].intValue = 0;
|
configValues["binds:ignore_group_lock"].intValue = 0;
|
||||||
|
configValues["binds:movefocus_cycles_fullscreen"].intValue = 1;
|
||||||
|
|
||||||
configValues["gestures:workspace_swipe"].intValue = 0;
|
configValues["gestures:workspace_swipe"].intValue = 0;
|
||||||
configValues["gestures:workspace_swipe_fingers"].intValue = 3;
|
configValues["gestures:workspace_swipe_fingers"].intValue = 3;
|
||||||
|
@ -246,6 +286,8 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["xwayland:use_nearest_neighbor"].intValue = 1;
|
configValues["xwayland:use_nearest_neighbor"].intValue = 1;
|
||||||
configValues["xwayland:force_zero_scaling"].intValue = 0;
|
configValues["xwayland:force_zero_scaling"].intValue = 0;
|
||||||
|
|
||||||
|
configValues["opengl:nvidia_anti_flicker"].intValue = 1;
|
||||||
|
|
||||||
configValues["autogenerated"].intValue = 0;
|
configValues["autogenerated"].intValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,9 +317,13 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
|
||||||
cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
|
cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
|
||||||
cfgValues["scroll_button"].intValue = 0;
|
cfgValues["scroll_button"].intValue = 0;
|
||||||
cfgValues["scroll_button_lock"].intValue = 0;
|
cfgValues["scroll_button_lock"].intValue = 0;
|
||||||
|
cfgValues["scroll_points"].strValue = STRVAL_EMPTY;
|
||||||
cfgValues["transform"].intValue = 0;
|
cfgValues["transform"].intValue = 0;
|
||||||
cfgValues["output"].strValue = STRVAL_EMPTY;
|
cfgValues["output"].strValue = STRVAL_EMPTY;
|
||||||
cfgValues["enabled"].intValue = 1; // only for mice / touchpads
|
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() {
|
void CConfigManager::setDefaultAnimationVars() {
|
||||||
|
@ -347,14 +393,24 @@ void CConfigManager::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) {
|
void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) {
|
||||||
if (configValues.find(COMMAND) == configValues.end()) {
|
if (!configValues.contains(COMMAND)) {
|
||||||
if (COMMAND.find("device:") != 0 /* devices parsed later */ && COMMAND.find("plugin:") != 0 /* plugins parsed later */) {
|
if (!COMMAND.starts_with("device:") /* devices parsed later */ && !COMMAND.starts_with("plugin:") /* plugins parsed later */) {
|
||||||
if (COMMAND[0] == '$') {
|
if (COMMAND[0] == '$') {
|
||||||
// register a dynamic var
|
// register a dynamic var
|
||||||
|
bool found = false;
|
||||||
|
for (auto& [var, val] : configDynamicVars) {
|
||||||
|
if (var == COMMAND.substr(1)) {
|
||||||
|
Debug::log(LOG, "Registered new value for dynamic var \"{}\" -> {}", COMMAND, VALUE);
|
||||||
|
val = VALUE;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE);
|
Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE);
|
||||||
configDynamicVars.emplace_back(std::make_pair<>(COMMAND.substr(1), VALUE));
|
configDynamicVars.emplace_back(std::make_pair<>(COMMAND.substr(1), VALUE));
|
||||||
|
|
||||||
std::sort(configDynamicVars.begin(), configDynamicVars.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
|
std::sort(configDynamicVars.begin(), configDynamicVars.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
|
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
|
||||||
}
|
}
|
||||||
|
@ -365,7 +421,7 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
|
||||||
|
|
||||||
SConfigValue* CONFIGENTRY = nullptr;
|
SConfigValue* CONFIGENTRY = nullptr;
|
||||||
|
|
||||||
if (COMMAND.find("device:") == 0) {
|
if (COMMAND.starts_with("device:")) {
|
||||||
const auto DEVICE = COMMAND.substr(7).substr(0, COMMAND.find_last_of(':') - 7);
|
const auto DEVICE = COMMAND.substr(7).substr(0, COMMAND.find_last_of(':') - 7);
|
||||||
const auto CONFIGVAR = COMMAND.substr(COMMAND.find_last_of(':') + 1);
|
const auto CONFIGVAR = COMMAND.substr(COMMAND.find_last_of(':') + 1);
|
||||||
|
|
||||||
|
@ -385,7 +441,7 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIGENTRY = &it->second.at(CONFIGVAR);
|
CONFIGENTRY = &it->second.at(CONFIGVAR);
|
||||||
} else if (COMMAND.find("plugin:") == 0) {
|
} else if (COMMAND.starts_with("plugin:")) {
|
||||||
for (auto& [handle, pMap] : pluginConfigs) {
|
for (auto& [handle, pMap] : pluginConfigs) {
|
||||||
auto it = std::find_if(pMap->begin(), pMap->end(), [&](const auto& other) { return other.first == COMMAND; });
|
auto it = std::find_if(pMap->begin(), pMap->end(), [&](const auto& other) { return other.first == COMMAND; });
|
||||||
if (it == pMap->end()) {
|
if (it == pMap->end()) {
|
||||||
|
@ -495,7 +551,7 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (COMMAND == "decoration:screen_shader") {
|
if (COMMAND == "decoration:screen_shader" && VALUE != STRVAL_EMPTY) {
|
||||||
const auto PATH = absolutePath(VALUE, configCurrentPath);
|
const auto PATH = absolutePath(VALUE, configCurrentPath);
|
||||||
|
|
||||||
configPaths.push_back(PATH);
|
configPaths.push_back(PATH);
|
||||||
|
@ -623,11 +679,11 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS[1].find("pref") == 0) {
|
if (ARGS[1].starts_with("pref")) {
|
||||||
newrule.resolution = Vector2D();
|
newrule.resolution = Vector2D();
|
||||||
} else if (ARGS[1].find("highrr") == 0) {
|
} else if (ARGS[1].starts_with("highrr")) {
|
||||||
newrule.resolution = Vector2D(-1, -1);
|
newrule.resolution = Vector2D(-1, -1);
|
||||||
} else if (ARGS[1].find("highres") == 0) {
|
} else if (ARGS[1].starts_with("highres")) {
|
||||||
newrule.resolution = Vector2D(-1, -2);
|
newrule.resolution = Vector2D(-1, -2);
|
||||||
} else if (parseModeLine(ARGS[1], newrule.drmMode)) {
|
} else if (parseModeLine(ARGS[1], newrule.drmMode)) {
|
||||||
newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay);
|
newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay);
|
||||||
|
@ -640,14 +696,14 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
|
||||||
newrule.refreshRate = stof(ARGS[1].substr(ARGS[1].find_first_of('@') + 1));
|
newrule.refreshRate = stof(ARGS[1].substr(ARGS[1].find_first_of('@') + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS[2].find("auto") == 0) {
|
if (ARGS[2].starts_with("auto")) {
|
||||||
newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX);
|
newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX);
|
||||||
} else {
|
} else {
|
||||||
newrule.offset.x = stoi(ARGS[2].substr(0, ARGS[2].find_first_of('x')));
|
newrule.offset.x = stoi(ARGS[2].substr(0, ARGS[2].find_first_of('x')));
|
||||||
newrule.offset.y = stoi(ARGS[2].substr(ARGS[2].find_first_of('x') + 1));
|
newrule.offset.y = stoi(ARGS[2].substr(ARGS[2].find_first_of('x') + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS[3].find("auto") == 0) {
|
if (ARGS[3].starts_with("auto")) {
|
||||||
newrule.scale = -1;
|
newrule.scale = -1;
|
||||||
} else {
|
} else {
|
||||||
newrule.scale = stof(ARGS[3]);
|
newrule.scale = stof(ARGS[3]);
|
||||||
|
@ -810,6 +866,7 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
|
||||||
bool mouse = false;
|
bool mouse = false;
|
||||||
bool nonConsuming = false;
|
bool nonConsuming = false;
|
||||||
bool transparent = false;
|
bool transparent = false;
|
||||||
|
bool ignoreMods = false;
|
||||||
const auto BINDARGS = command.substr(4);
|
const auto BINDARGS = command.substr(4);
|
||||||
|
|
||||||
for (auto& arg : BINDARGS) {
|
for (auto& arg : BINDARGS) {
|
||||||
|
@ -825,6 +882,8 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
|
||||||
nonConsuming = true;
|
nonConsuming = true;
|
||||||
} else if (arg == 't') {
|
} else if (arg == 't') {
|
||||||
transparent = true;
|
transparent = true;
|
||||||
|
} else if (arg == 'i') {
|
||||||
|
ignoreMods = true;
|
||||||
} else {
|
} else {
|
||||||
parseError = "bind: invalid flag";
|
parseError = "bind: invalid flag";
|
||||||
return;
|
return;
|
||||||
|
@ -882,12 +941,13 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
|
||||||
|
|
||||||
if (KEY != "") {
|
if (KEY != "") {
|
||||||
if (isNumber(KEY) && std::stoi(KEY) > 9)
|
if (isNumber(KEY) && std::stoi(KEY) > 9)
|
||||||
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent});
|
|
||||||
else if (KEY.find("code:") == 0 && isNumber(KEY.substr(5)))
|
|
||||||
g_pKeybindManager->addKeybind(
|
g_pKeybindManager->addKeybind(
|
||||||
SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent});
|
SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
|
||||||
|
else if (KEY.starts_with("code:") && isNumber(KEY.substr(5)))
|
||||||
|
g_pKeybindManager->addKeybind(
|
||||||
|
SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
|
||||||
else
|
else
|
||||||
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent});
|
g_pKeybindManager->addKeybind(SKeybind{KEY, 0, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,17 +962,17 @@ void CConfigManager::handleUnbind(const std::string& command, const std::string&
|
||||||
}
|
}
|
||||||
|
|
||||||
bool windowRuleValid(const std::string& RULE) {
|
bool windowRuleValid(const std::string& RULE) {
|
||||||
return !(RULE != "float" && RULE != "tile" && RULE.find("opacity") != 0 && RULE.find("move") != 0 && RULE.find("size") != 0 && RULE.find("minsize") != 0 &&
|
return RULE == "float" || RULE == "tile" || RULE.starts_with("opacity") || RULE.starts_with("move") || RULE.starts_with("size") || RULE.starts_with("minsize") ||
|
||||||
RULE.find("maxsize") != 0 && RULE.find("pseudo") != 0 && RULE.find("monitor") != 0 && RULE.find("idleinhibit") != 0 && RULE != "nofocus" && RULE != "noblur" &&
|
RULE.starts_with("maxsize") || RULE.starts_with("pseudo") || RULE.starts_with("monitor") || RULE.starts_with("idleinhibit") || RULE == "nofocus" || RULE == "noblur" ||
|
||||||
RULE != "noshadow" && RULE != "nodim" && RULE != "noborder" && RULE != "opaque" && RULE != "forceinput" && RULE != "fullscreen" && RULE != "nofullscreenrequest" &&
|
RULE == "noshadow" || RULE == "nodim" || RULE == "noborder" || RULE == "opaque" || RULE == "forceinput" || RULE == "fullscreen" || RULE == "nofullscreenrequest" ||
|
||||||
RULE != "nomaximizerequest" && RULE != "fakefullscreen" && RULE != "nomaxsize" && RULE != "pin" && RULE != "noanim" && RULE != "dimaround" && RULE != "windowdance" &&
|
RULE == "nomaximizerequest" || RULE == "fakefullscreen" || RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" ||
|
||||||
RULE != "maximize" && RULE != "keepaspectratio" && RULE.find("animation") != 0 && RULE.find("rounding") != 0 && RULE.find("workspace") != 0 &&
|
RULE == "maximize" || RULE == "keepaspectratio" || RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") ||
|
||||||
RULE.find("bordercolor") != 0 && RULE != "forcergbx" && RULE != "noinitialfocus" && RULE != "stayfocused" && RULE.find("bordersize") != 0 && RULE.find("xray") != 0 &&
|
RULE.starts_with("bordercolor") || RULE == "forcergbx" || RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") ||
|
||||||
RULE.find("center") != 0 && RULE.find("group") != 0);
|
RULE.starts_with("center") || RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool layerRuleValid(const std::string& RULE) {
|
bool layerRuleValid(const std::string& RULE) {
|
||||||
return !(RULE != "noanim" && RULE != "blur" && RULE.find("ignorealpha") != 0 && RULE.find("ignorezero") != 0 && RULE.find("xray") != 0);
|
return RULE == "noanim" || RULE == "blur" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE.starts_with("xray");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
|
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
|
||||||
|
@ -936,7 +996,7 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RULE.find("size") == 0 || RULE.find("maxsize") == 0 || RULE.find("minsize") == 0)
|
if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
|
||||||
m_dWindowRules.push_front({RULE, VALUE});
|
m_dWindowRules.push_front({RULE, VALUE});
|
||||||
else
|
else
|
||||||
m_dWindowRules.push_back({RULE, VALUE});
|
m_dWindowRules.push_back({RULE, VALUE});
|
||||||
|
@ -987,14 +1047,29 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||||
|
|
||||||
const auto TITLEPOS = VALUE.find("title:");
|
const auto TITLEPOS = VALUE.find("title:");
|
||||||
const auto CLASSPOS = VALUE.find("class:");
|
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 X11POS = VALUE.find("xwayland:");
|
||||||
const auto FLOATPOS = VALUE.find("floating:");
|
const auto FLOATPOS = VALUE.find("floating:");
|
||||||
const auto FULLSCREENPOS = VALUE.find("fullscreen:");
|
const auto FULLSCREENPOS = VALUE.find("fullscreen:");
|
||||||
const auto PINNEDPOS = VALUE.find("pinned:");
|
const auto PINNEDPOS = VALUE.find("pinned:");
|
||||||
const auto WORKSPACEPOS = VALUE.find("workspace:");
|
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 &&
|
// find workspacepos that isn't onworkspacepos
|
||||||
PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos) {
|
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);
|
Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE);
|
||||||
parseError = "Invalid rulev2 syntax: " + VALUE;
|
parseError = "Invalid rulev2 syntax: " + VALUE;
|
||||||
return;
|
return;
|
||||||
|
@ -1009,6 +1084,10 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||||
min = TITLEPOS;
|
min = TITLEPOS;
|
||||||
if (CLASSPOS > pos && CLASSPOS < min)
|
if (CLASSPOS > pos && CLASSPOS < min)
|
||||||
min = CLASSPOS;
|
min = CLASSPOS;
|
||||||
|
if (INITIALTITLEPOS > pos && INITIALTITLEPOS < min)
|
||||||
|
min = INITIALTITLEPOS;
|
||||||
|
if (INITIALCLASSPOS > pos && INITIALCLASSPOS < min)
|
||||||
|
min = INITIALCLASSPOS;
|
||||||
if (X11POS > pos && X11POS < min)
|
if (X11POS > pos && X11POS < min)
|
||||||
min = X11POS;
|
min = X11POS;
|
||||||
if (FLOATPOS > pos && FLOATPOS < min)
|
if (FLOATPOS > pos && FLOATPOS < min)
|
||||||
|
@ -1017,8 +1096,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||||
min = FULLSCREENPOS;
|
min = FULLSCREENPOS;
|
||||||
if (PINNEDPOS > pos && PINNEDPOS < min)
|
if (PINNEDPOS > pos && PINNEDPOS < min)
|
||||||
min = PINNEDPOS;
|
min = PINNEDPOS;
|
||||||
|
if (ONWORKSPACEPOS > pos && ONWORKSPACEPOS < min)
|
||||||
|
min = ONWORKSPACEPOS;
|
||||||
if (WORKSPACEPOS > pos && WORKSPACEPOS < min)
|
if (WORKSPACEPOS > pos && WORKSPACEPOS < min)
|
||||||
min = PINNEDPOS;
|
min = WORKSPACEPOS;
|
||||||
|
if (FOCUSPOS > pos && FOCUSPOS < min)
|
||||||
|
min = FOCUSPOS;
|
||||||
|
|
||||||
result = result.substr(0, min - pos);
|
result = result.substr(0, min - pos);
|
||||||
|
|
||||||
|
@ -1036,6 +1119,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||||
if (TITLEPOS != std::string::npos)
|
if (TITLEPOS != std::string::npos)
|
||||||
rule.szTitle = extract(TITLEPOS + 6);
|
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)
|
if (X11POS != std::string::npos)
|
||||||
rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
|
rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
|
||||||
|
|
||||||
|
@ -1051,6 +1140,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||||
if (WORKSPACEPOS != std::string::npos)
|
if (WORKSPACEPOS != std::string::npos)
|
||||||
rule.szWorkspace = extract(WORKSPACEPOS + 10);
|
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") {
|
if (RULE == "unset") {
|
||||||
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
|
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
|
||||||
if (!other.v2) {
|
if (!other.v2) {
|
||||||
|
@ -1062,6 +1157,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||||
if (!rule.szTitle.empty() && rule.szTitle != other.szTitle)
|
if (!rule.szTitle.empty() && rule.szTitle != other.szTitle)
|
||||||
return false;
|
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)
|
if (rule.bX11 != -1 && rule.bX11 != other.bX11)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1077,20 +1178,26 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||||
if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace)
|
if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (rule.bFocus != -1 && rule.bFocus != other.bFocus)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (rule.iOnWorkspace != -1 && rule.iOnWorkspace != other.iOnWorkspace)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RULE.find("size") == 0 || RULE.find("maxsize") == 0 || RULE.find("minsize") == 0)
|
if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
|
||||||
m_dWindowRules.push_front(rule);
|
m_dWindowRules.push_front(rule);
|
||||||
else
|
else
|
||||||
m_dWindowRules.push_back(rule);
|
m_dWindowRules.push_back(rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBlur) {
|
void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBlur) {
|
||||||
const bool BYADDRESS = name.find("address:") == 0;
|
const bool BYADDRESS = name.starts_with("address:");
|
||||||
std::string matchName = name;
|
std::string matchName = name;
|
||||||
|
|
||||||
if (BYADDRESS) {
|
if (BYADDRESS) {
|
||||||
|
@ -1111,7 +1218,7 @@ void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBl
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
|
void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
|
||||||
if (value.find("remove,") == 0) {
|
if (value.starts_with("remove,")) {
|
||||||
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
|
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
|
||||||
if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; }))
|
if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; }))
|
||||||
updateBlurredLS(TOREMOVE, false);
|
updateBlurredLS(TOREMOVE, false);
|
||||||
|
@ -1133,13 +1240,13 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
|
||||||
auto rules = value.substr(FIRST_DELIM + 1);
|
auto rules = value.substr(FIRST_DELIM + 1);
|
||||||
SWorkspaceRule wsRule;
|
SWorkspaceRule wsRule;
|
||||||
wsRule.workspaceString = first_ident;
|
wsRule.workspaceString = first_ident;
|
||||||
if (id == INT_MAX) {
|
if (id == WORKSPACE_INVALID) {
|
||||||
// it could be the monitor. If so, second value MUST be
|
// it could be the monitor. If so, second value MUST be
|
||||||
// the workspace.
|
// the workspace.
|
||||||
const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
|
const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
|
||||||
auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
|
auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
|
||||||
id = getWorkspaceIDFromString(wsIdent, name);
|
id = getWorkspaceIDFromString(wsIdent, name);
|
||||||
if (id == INT_MAX) {
|
if (id == WORKSPACE_INVALID) {
|
||||||
Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
|
Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
|
||||||
parseError = "Invalid workspace identifier found: " + wsIdent;
|
parseError = "Invalid workspace identifier found: " + wsIdent;
|
||||||
return;
|
return;
|
||||||
|
@ -1150,6 +1257,9 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
|
||||||
rules = value.substr(WORKSPACE_DELIM + 1);
|
rules = value.substr(WORKSPACE_DELIM + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const static std::string ruleOnCreatedEmtpy = "on-created-empty:";
|
||||||
|
const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length();
|
||||||
|
|
||||||
auto assignRule = [&](std::string rule) {
|
auto assignRule = [&](std::string rule) {
|
||||||
size_t delim = std::string::npos;
|
size_t delim = std::string::npos;
|
||||||
if ((delim = rule.find("gapsin:")) != std::string::npos)
|
if ((delim = rule.find("gapsin:")) != std::string::npos)
|
||||||
|
@ -1170,6 +1280,24 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
|
||||||
wsRule.monitor = rule.substr(delim + 8);
|
wsRule.monitor = rule.substr(delim + 8);
|
||||||
else if ((delim = rule.find("default:")) != std::string::npos)
|
else if ((delim = rule.find("default:")) != std::string::npos)
|
||||||
wsRule.isDefault = configStringToInt(rule.substr(delim + 8));
|
wsRule.isDefault = configStringToInt(rule.substr(delim + 8));
|
||||||
|
else if ((delim = rule.find("persistent:")) != std::string::npos)
|
||||||
|
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;
|
size_t pos = 0;
|
||||||
|
@ -1217,7 +1345,12 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
|
||||||
for (size_t i = 0; i < glob_buf->gl_pathc; i++) {
|
for (size_t i = 0; i < glob_buf->gl_pathc; i++) {
|
||||||
auto value = absolutePath(glob_buf->gl_pathv[i], configCurrentPath);
|
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");
|
Debug::log(ERR, "source= file doesnt exist");
|
||||||
parseError = "source file " + value + " doesn't exist!";
|
parseError = "source file " + value + " doesn't exist!";
|
||||||
return;
|
return;
|
||||||
|
@ -1253,7 +1386,7 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
|
||||||
parseError += "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): Line parsing error.";
|
parseError += "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): Line parsing error.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parseError != "" && parseError.find("Config error at line") != 0) {
|
if (parseError != "" && !parseError.starts_with("Config error at line")) {
|
||||||
parseError = "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): " + parseError;
|
parseError = "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): " + parseError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1326,7 +1459,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||||
}
|
}
|
||||||
} else if (COMMAND == "monitor")
|
} else if (COMMAND == "monitor")
|
||||||
handleMonitor(COMMAND, VALUE);
|
handleMonitor(COMMAND, VALUE);
|
||||||
else if (COMMAND.find("bind") == 0)
|
else if (COMMAND.starts_with("bind"))
|
||||||
handleBind(COMMAND, VALUE);
|
handleBind(COMMAND, VALUE);
|
||||||
else if (COMMAND == "unbind")
|
else if (COMMAND == "unbind")
|
||||||
handleUnbind(COMMAND, VALUE);
|
handleUnbind(COMMAND, VALUE);
|
||||||
|
@ -1350,14 +1483,21 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||||
handleBlurLS(COMMAND, VALUE);
|
handleBlurLS(COMMAND, VALUE);
|
||||||
else if (COMMAND == "wsbind")
|
else if (COMMAND == "wsbind")
|
||||||
handleBindWS(COMMAND, VALUE);
|
handleBindWS(COMMAND, VALUE);
|
||||||
else if (COMMAND.find("env") == 0)
|
else if (COMMAND == "plugin")
|
||||||
handleEnv(COMMAND, VALUE);
|
|
||||||
else if (COMMAND.find("plugin") == 0)
|
|
||||||
handlePlugin(COMMAND, VALUE);
|
handlePlugin(COMMAND, VALUE);
|
||||||
|
else if (COMMAND.starts_with("env"))
|
||||||
|
handleEnv(COMMAND, VALUE);
|
||||||
else {
|
else {
|
||||||
|
// try config
|
||||||
|
const auto IT = std::find_if(pluginKeywords.begin(), pluginKeywords.end(), [&](const auto& other) { return other.name == COMMAND; });
|
||||||
|
|
||||||
|
if (IT != pluginKeywords.end()) {
|
||||||
|
IT->fn(COMMAND, VALUE);
|
||||||
|
} else {
|
||||||
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
|
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
|
||||||
needsLayoutRecalc = 2;
|
needsLayoutRecalc = 2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dynamic) {
|
if (dynamic) {
|
||||||
std::string retval = parseError;
|
std::string retval = parseError;
|
||||||
|
@ -1365,7 +1505,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||||
|
|
||||||
// invalidate layouts if they changed
|
// invalidate layouts if they changed
|
||||||
if (needsLayoutRecalc) {
|
if (needsLayoutRecalc) {
|
||||||
if (needsLayoutRecalc == 1 || COMMAND.contains("gaps_") || COMMAND.find("dwindle:") == 0 || COMMAND.find("master:") == 0) {
|
if (needsLayoutRecalc == 1 || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) {
|
||||||
for (auto& m : g_pCompositor->m_vMonitors)
|
for (auto& m : g_pCompositor->m_vMonitors)
|
||||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||||
}
|
}
|
||||||
|
@ -1395,12 +1535,15 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||||
void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equalsPlace) {
|
void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equalsPlace) {
|
||||||
auto dollarPlace = line.find_first_of('$', equalsPlace);
|
auto dollarPlace = line.find_first_of('$', equalsPlace);
|
||||||
|
|
||||||
|
int times = 0;
|
||||||
|
|
||||||
while (dollarPlace != std::string::npos) {
|
while (dollarPlace != std::string::npos) {
|
||||||
|
times++;
|
||||||
|
|
||||||
const auto STRAFTERDOLLAR = line.substr(dollarPlace + 1);
|
const auto STRAFTERDOLLAR = line.substr(dollarPlace + 1);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto& [var, value] : configDynamicVars) {
|
for (auto& [var, value] : configDynamicVars) {
|
||||||
if (STRAFTERDOLLAR.find(var) == 0) {
|
if (STRAFTERDOLLAR.starts_with(var)) {
|
||||||
line.replace(dollarPlace, var.length() + 1, value);
|
line.replace(dollarPlace, var.length() + 1, value);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
@ -1410,7 +1553,7 @@ void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equals
|
||||||
if (!found) {
|
if (!found) {
|
||||||
// maybe env?
|
// maybe env?
|
||||||
for (auto& [var, value] : environmentVariables) {
|
for (auto& [var, value] : environmentVariables) {
|
||||||
if (STRAFTERDOLLAR.find(var) == 0) {
|
if (STRAFTERDOLLAR.starts_with(var)) {
|
||||||
line.replace(dollarPlace, var.length() + 1, value);
|
line.replace(dollarPlace, var.length() + 1, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1418,6 +1561,13 @@ void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equals
|
||||||
}
|
}
|
||||||
|
|
||||||
dollarPlace = line.find_first_of('$', dollarPlace + 1);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1464,7 +1614,7 @@ void CConfigManager::parseLine(std::string& line) {
|
||||||
|
|
||||||
const auto LASTSEP = currentCategory.find_last_of(':');
|
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 = "";
|
currentCategory = "";
|
||||||
else
|
else
|
||||||
currentCategory = currentCategory.substr(0, LASTSEP);
|
currentCategory = currentCategory.substr(0, LASTSEP);
|
||||||
|
@ -1490,6 +1640,8 @@ void CConfigManager::parseLine(std::string& line) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConfigManager::loadConfigLoadVars() {
|
void CConfigManager::loadConfigLoadVars() {
|
||||||
|
EMIT_HOOK_EVENT("preConfigReload", nullptr);
|
||||||
|
|
||||||
Debug::log(LOG, "Reloading the config!");
|
Debug::log(LOG, "Reloading the config!");
|
||||||
parseError = ""; // reset the error
|
parseError = ""; // reset the error
|
||||||
currentCategory = ""; // reset the category
|
currentCategory = ""; // reset the category
|
||||||
|
@ -1515,8 +1667,9 @@ void CConfigManager::loadConfigLoadVars() {
|
||||||
std::string mainConfigPath = getMainConfigPath();
|
std::string mainConfigPath = getMainConfigPath();
|
||||||
Debug::log(LOG, "Using config: {}", mainConfigPath);
|
Debug::log(LOG, "Using config: {}", mainConfigPath);
|
||||||
configPaths.push_back(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 (g_pCompositor->explicitConfigPath.empty() && !std::filesystem::exists(mainConfigPath)) {
|
||||||
|
std::string configPath = std::filesystem::path(mainConfigPath).parent_path();
|
||||||
|
|
||||||
if (!std::filesystem::is_directory(configPath)) {
|
if (!std::filesystem::is_directory(configPath)) {
|
||||||
Debug::log(WARN, "Creating config home directory");
|
Debug::log(WARN, "Creating config home directory");
|
||||||
|
@ -1528,7 +1681,6 @@ void CConfigManager::loadConfigLoadVars() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!std::filesystem::exists(mainConfigPath)) {
|
|
||||||
Debug::log(WARN, "No config file found; attempting to generate.");
|
Debug::log(WARN, "No config file found; attempting to generate.");
|
||||||
std::ofstream ofs;
|
std::ofstream ofs;
|
||||||
ofs.open(mainConfigPath, std::ios::trunc);
|
ofs.open(mainConfigPath, std::ios::trunc);
|
||||||
|
@ -1540,10 +1692,16 @@ void CConfigManager::loadConfigLoadVars() {
|
||||||
ifs.open(mainConfigPath);
|
ifs.open(mainConfigPath);
|
||||||
|
|
||||||
if (!ifs.good()) {
|
if (!ifs.good()) {
|
||||||
Debug::log(WARN, "Config reading error. Attempting to generate, backing up old one if exists");
|
|
||||||
|
|
||||||
ifs.close();
|
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))
|
if (std::filesystem::exists(mainConfigPath))
|
||||||
std::filesystem::rename(mainConfigPath, mainConfigPath + ".backup");
|
std::filesystem::rename(mainConfigPath, mainConfigPath + ".backup");
|
||||||
|
|
||||||
|
@ -1576,7 +1734,7 @@ void CConfigManager::loadConfigLoadVars() {
|
||||||
parseError += "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): Line parsing error.";
|
parseError += "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): Line parsing error.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parseError != "" && parseError.find("Config error at line") != 0) {
|
if (parseError != "" && !parseError.starts_with("Config error at line")) {
|
||||||
parseError = "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): " + parseError;
|
parseError = "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): " + parseError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1586,6 +1744,10 @@ void CConfigManager::loadConfigLoadVars() {
|
||||||
ifs.close();
|
ifs.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& w : g_pCompositor->m_vWindows) {
|
||||||
|
w->uncacheWindowDecos();
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& m : g_pCompositor->m_vMonitors)
|
for (auto& m : g_pCompositor->m_vMonitors)
|
||||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||||
|
|
||||||
|
@ -1620,6 +1782,9 @@ void CConfigManager::loadConfigLoadVars() {
|
||||||
ensureVRR();
|
ensureVRR();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isFirstLaunch && !g_pCompositor->m_bUnsafeState)
|
||||||
|
refreshGroupBarGradients();
|
||||||
|
|
||||||
// Updates dynamic window and workspace rules
|
// Updates dynamic window and workspace rules
|
||||||
for (auto& w : g_pCompositor->m_vWindows) {
|
for (auto& w : g_pCompositor->m_vWindows) {
|
||||||
if (!w->m_bIsMapped)
|
if (!w->m_bIsMapped)
|
||||||
|
@ -1665,6 +1830,8 @@ void CConfigManager::loadConfigLoadVars() {
|
||||||
handlePluginLoads();
|
handlePluginLoads();
|
||||||
|
|
||||||
EMIT_HOOK_EVENT("configReloaded", nullptr);
|
EMIT_HOOK_EVENT("configReloaded", nullptr);
|
||||||
|
if (g_pEventManager)
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"configreloaded", ""});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConfigManager::tick() {
|
void CConfigManager::tick() {
|
||||||
|
@ -1737,6 +1904,10 @@ float CConfigManager::getFloat(const std::string& v) {
|
||||||
return getConfigValueSafe(v).floatValue;
|
return getConfigValueSafe(v).floatValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D CConfigManager::getVec(const std::string& v) {
|
||||||
|
return getConfigValueSafe(v).vecValue;
|
||||||
|
}
|
||||||
|
|
||||||
std::string CConfigManager::getString(const std::string& v) {
|
std::string CConfigManager::getString(const std::string& v) {
|
||||||
auto VAL = getConfigValueSafe(v).strValue;
|
auto VAL = getConfigValueSafe(v).strValue;
|
||||||
|
|
||||||
|
@ -1754,6 +1925,10 @@ float CConfigManager::getDeviceFloat(const std::string& dev, const std::string&
|
||||||
return getConfigValueSafeDevice(dev, v, fallback).floatValue;
|
return getConfigValueSafeDevice(dev, v, fallback).floatValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D CConfigManager::getDeviceVec(const std::string& dev, const std::string& v, const std::string& fallback) {
|
||||||
|
return getConfigValueSafeDevice(dev, v, fallback).vecValue;
|
||||||
|
}
|
||||||
|
|
||||||
std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v, const std::string& fallback) {
|
std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v, const std::string& fallback) {
|
||||||
auto VAL = getConfigValueSafeDevice(dev, v, fallback).strValue;
|
auto VAL = getConfigValueSafeDevice(dev, v, fallback).strValue;
|
||||||
|
|
||||||
|
@ -1771,6 +1946,10 @@ void CConfigManager::setFloat(const std::string& v, float val) {
|
||||||
configValues[v].floatValue = val;
|
configValues[v].floatValue = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CConfigManager::setVec(const std::string& v, Vector2D val) {
|
||||||
|
configValues[v].vecValue = val;
|
||||||
|
}
|
||||||
|
|
||||||
void CConfigManager::setString(const std::string& v, const std::string& val) {
|
void CConfigManager::setString(const std::string& v, const std::string& val) {
|
||||||
configValues[v].strValue = val;
|
configValues[v].strValue = val;
|
||||||
}
|
}
|
||||||
|
@ -1780,7 +1959,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const std::string& name, const st
|
||||||
|
|
||||||
for (auto& r : m_dMonitorRules) {
|
for (auto& r : m_dMonitorRules) {
|
||||||
if (r.name == name ||
|
if (r.name == name ||
|
||||||
(r.name.find("desc:") == 0 &&
|
(r.name.starts_with("desc:") &&
|
||||||
(r.name.substr(5) == displayName || r.name.substr(5) == removeBeginEndSpacesTabs(displayName.substr(0, displayName.find_first_of('(')))))) {
|
(r.name.substr(5) == displayName || r.name.substr(5) == removeBeginEndSpacesTabs(displayName.substr(0, displayName.find_first_of('(')))))) {
|
||||||
found = &r;
|
found = &r;
|
||||||
break;
|
break;
|
||||||
|
@ -1808,7 +1987,13 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const std::string& name, const st
|
||||||
}
|
}
|
||||||
|
|
||||||
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(CWorkspace* pWorkspace) {
|
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(CWorkspace* pWorkspace) {
|
||||||
const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) { return other.workspaceName == pWorkspace->m_szName; });
|
const auto WORKSPACEIDSTR = std::to_string(pWorkspace->m_iID);
|
||||||
|
const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) {
|
||||||
|
return other.workspaceName == pWorkspace->m_szName /* name matches */
|
||||||
|
|| (pWorkspace->m_bIsSpecialWorkspace && other.workspaceName.starts_with("special:") &&
|
||||||
|
other.workspaceName.substr(8) == pWorkspace->m_szName) /* special and special:name */
|
||||||
|
|| (pWorkspace->m_iID > 0 && WORKSPACEIDSTR == other.workspaceName); /* id matches and workspace is numerical */
|
||||||
|
});
|
||||||
if (IT == m_dWorkspaceRules.end())
|
if (IT == m_dWorkspaceRules.end())
|
||||||
return SWorkspaceRule{};
|
return SWorkspaceRule{};
|
||||||
return *IT;
|
return *IT;
|
||||||
|
@ -1833,7 +2018,7 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||||
// check if we have a matching rule
|
// check if we have a matching rule
|
||||||
if (!rule.v2) {
|
if (!rule.v2) {
|
||||||
try {
|
try {
|
||||||
if (rule.szValue.find("title:") == 0) {
|
if (rule.szValue.starts_with("title:")) {
|
||||||
// we have a title rule.
|
// we have a title rule.
|
||||||
std::regex RULECHECK(rule.szValue.substr(6));
|
std::regex RULECHECK(rule.szValue.substr(6));
|
||||||
|
|
||||||
|
@ -1865,6 +2050,20 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||||
continue;
|
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 (rule.bX11 != -1) {
|
||||||
if (pWindow->m_bIsX11 != rule.bX11)
|
if (pWindow->m_bIsX11 != rule.bX11)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1885,13 +2084,23 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||||
continue;
|
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()) {
|
if (!rule.szWorkspace.empty()) {
|
||||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||||
|
|
||||||
if (!PWORKSPACE)
|
if (!PWORKSPACE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (rule.szWorkspace.find("name:") == 0) {
|
if (rule.szWorkspace.starts_with("name:")) {
|
||||||
if (PWORKSPACE->m_szName != rule.szWorkspace.substr(5))
|
if (PWORKSPACE->m_szName != rule.szWorkspace.substr(5))
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1949,7 +2158,7 @@ std::vector<SLayerRule> CConfigManager::getMatchingRules(SLayerSurface* pLS) {
|
||||||
return returns;
|
return returns;
|
||||||
|
|
||||||
for (auto& lr : m_dLayerRules) {
|
for (auto& lr : m_dLayerRules) {
|
||||||
if (lr.targetNamespace.find("address:0x") == 0) {
|
if (lr.targetNamespace.starts_with("address:0x")) {
|
||||||
if (std::format("address:0x{:x}", (uintptr_t)pLS) != lr.targetNamespace)
|
if (std::format("address:0x{:x}", (uintptr_t)pLS) != lr.targetNamespace)
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1975,12 +2184,12 @@ void CConfigManager::dispatchExecOnce() {
|
||||||
|
|
||||||
// update dbus env
|
// update dbus env
|
||||||
if (g_pCompositor->m_sWLRSession)
|
if (g_pCompositor->m_sWLRSession)
|
||||||
handleRawExec(
|
handleRawExec("",
|
||||||
"",
|
|
||||||
#ifdef USES_SYSTEMD
|
#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
|
#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;
|
firstExecDispatched = true;
|
||||||
|
|
||||||
|
@ -2005,10 +2214,10 @@ void CConfigManager::performMonitorReload() {
|
||||||
bool overAgain = false;
|
bool overAgain = false;
|
||||||
|
|
||||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||||
if (!m->output)
|
if (!m->output || m->isUnsafeFallback)
|
||||||
continue;
|
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)) {
|
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
|
||||||
overAgain = true;
|
overAgain = true;
|
||||||
|
@ -2071,9 +2280,7 @@ bool CConfigManager::deviceConfigExists(const std::string& dev) {
|
||||||
auto copy = dev;
|
auto copy = dev;
|
||||||
std::replace(copy.begin(), copy.end(), ' ', '-');
|
std::replace(copy.begin(), copy.end(), ' ', '-');
|
||||||
|
|
||||||
const auto it = deviceConfigs.find(copy);
|
return deviceConfigs.contains(copy);
|
||||||
|
|
||||||
return it != deviceConfigs.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CConfigManager::shouldBlurLS(const std::string& ns) {
|
bool CConfigManager::shouldBlurLS(const std::string& ns) {
|
||||||
|
@ -2088,17 +2295,15 @@ bool CConfigManager::shouldBlurLS(const std::string& ns) {
|
||||||
|
|
||||||
void CConfigManager::ensureMonitorStatus() {
|
void CConfigManager::ensureMonitorStatus() {
|
||||||
for (auto& rm : g_pCompositor->m_vRealMonitors) {
|
for (auto& rm : g_pCompositor->m_vRealMonitors) {
|
||||||
if (!rm->output)
|
if (!rm->output || rm->isUnsafeFallback)
|
||||||
continue;
|
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) {
|
if (rule.disabled == rm->m_bEnabled)
|
||||||
rm->m_pThisWrap = &rm;
|
|
||||||
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
|
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void CConfigManager::ensureVRR(CMonitor* pMonitor) {
|
void CConfigManager::ensureVRR(CMonitor* pMonitor) {
|
||||||
static auto* const PVRR = &getConfigValuePtr("misc:vrr")->intValue;
|
static auto* const PVRR = &getConfigValuePtr("misc:vrr")->intValue;
|
||||||
|
@ -2194,7 +2399,7 @@ CMonitor* CConfigManager::getBoundMonitorForWS(const std::string& wsname) {
|
||||||
|
|
||||||
std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname) {
|
std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname) {
|
||||||
for (auto& wr : m_dWorkspaceRules) {
|
for (auto& wr : m_dWorkspaceRules) {
|
||||||
const auto WSNAME = wr.workspaceName.find("name:") == 0 ? wr.workspaceName.substr(5) : wr.workspaceName;
|
const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName;
|
||||||
|
|
||||||
if (WSNAME == wsname) {
|
if (WSNAME == wsname) {
|
||||||
return wr.monitor;
|
return wr.monitor;
|
||||||
|
@ -2262,8 +2467,13 @@ void CConfigManager::addPluginConfigVar(HANDLE handle, const std::string& name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CConfigManager::addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string&, const std::string&)> fn) {
|
||||||
|
pluginKeywords.emplace_back(SPluginKeyword{handle, name, fn});
|
||||||
|
}
|
||||||
|
|
||||||
void CConfigManager::removePluginConfig(HANDLE handle) {
|
void CConfigManager::removePluginConfig(HANDLE handle) {
|
||||||
std::erase_if(pluginConfigs, [&](const auto& other) { return other.first == handle; });
|
std::erase_if(pluginConfigs, [&](const auto& other) { return other.first == handle; });
|
||||||
|
std::erase_if(pluginKeywords, [&](const auto& other) { return other.handle == handle; });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) {
|
std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <functional>
|
||||||
#include <xf86drmMode.h>
|
#include <xf86drmMode.h>
|
||||||
#include "../Window.hpp"
|
#include "../Window.hpp"
|
||||||
#include "../helpers/WLClasses.hpp"
|
#include "../helpers/WLClasses.hpp"
|
||||||
|
@ -41,6 +42,7 @@ struct SWorkspaceRule {
|
||||||
std::string workspaceName = "";
|
std::string workspaceName = "";
|
||||||
int workspaceId = -1;
|
int workspaceId = -1;
|
||||||
bool isDefault = false;
|
bool isDefault = false;
|
||||||
|
bool isPersistent = false;
|
||||||
std::optional<int64_t> gapsIn;
|
std::optional<int64_t> gapsIn;
|
||||||
std::optional<int64_t> gapsOut;
|
std::optional<int64_t> gapsOut;
|
||||||
std::optional<int64_t> borderSize;
|
std::optional<int64_t> borderSize;
|
||||||
|
@ -48,6 +50,8 @@ struct SWorkspaceRule {
|
||||||
std::optional<int> rounding;
|
std::optional<int> rounding;
|
||||||
std::optional<int> decorate;
|
std::optional<int> decorate;
|
||||||
std::optional<int> shadow;
|
std::optional<int> shadow;
|
||||||
|
std::optional<std::string> onCreatedEmptyRunCmd;
|
||||||
|
std::map<std::string, std::string> layoutopts;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SMonitorAdditionalReservedArea {
|
struct SMonitorAdditionalReservedArea {
|
||||||
|
@ -69,6 +73,12 @@ struct SAnimationPropertyConfig {
|
||||||
SAnimationPropertyConfig* pParentAnimation = nullptr;
|
SAnimationPropertyConfig* pParentAnimation = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SPluginKeyword {
|
||||||
|
HANDLE handle = 0;
|
||||||
|
std::string name = "";
|
||||||
|
std::function<void(const std::string&, const std::string&)> fn;
|
||||||
|
};
|
||||||
|
|
||||||
struct SExecRequestedRule {
|
struct SExecRequestedRule {
|
||||||
std::string szRule = "";
|
std::string szRule = "";
|
||||||
uint64_t iPid = 0;
|
uint64_t iPid = 0;
|
||||||
|
@ -83,13 +93,16 @@ class CConfigManager {
|
||||||
|
|
||||||
int getInt(const std::string&);
|
int getInt(const std::string&);
|
||||||
float getFloat(const std::string&);
|
float getFloat(const std::string&);
|
||||||
|
Vector2D getVec(const std::string&);
|
||||||
std::string getString(const std::string&);
|
std::string getString(const std::string&);
|
||||||
void setFloat(const std::string&, float);
|
void setFloat(const std::string&, float);
|
||||||
void setInt(const std::string&, int);
|
void setInt(const std::string&, int);
|
||||||
|
void setVec(const std::string&, Vector2D);
|
||||||
void setString(const std::string&, const std::string&);
|
void setString(const std::string&, const std::string&);
|
||||||
|
|
||||||
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
|
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
|
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
|
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
bool deviceConfigExists(const std::string&);
|
bool deviceConfigExists(const std::string&);
|
||||||
bool shouldBlurLS(const std::string&);
|
bool shouldBlurLS(const std::string&);
|
||||||
|
@ -115,6 +128,7 @@ class CConfigManager {
|
||||||
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
|
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
|
||||||
|
|
||||||
void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
|
void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
|
||||||
|
void addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& cmd, const std::string& val)> fun);
|
||||||
void removePluginConfig(HANDLE handle);
|
void removePluginConfig(HANDLE handle);
|
||||||
|
|
||||||
// no-op when done.
|
// no-op when done.
|
||||||
|
@ -158,6 +172,7 @@ class CConfigManager {
|
||||||
|
|
||||||
std::vector<std::string> m_vDeclaredPlugins;
|
std::vector<std::string> m_vDeclaredPlugins;
|
||||||
std::unordered_map<HANDLE, std::unique_ptr<std::unordered_map<std::string, SConfigValue>>> pluginConfigs; // stores plugin configs
|
std::unordered_map<HANDLE, std::unique_ptr<std::unordered_map<std::string, SConfigValue>>> pluginConfigs; // stores plugin configs
|
||||||
|
std::vector<SPluginKeyword> pluginKeywords;
|
||||||
|
|
||||||
bool isFirstLaunch = true; // For exec-once
|
bool isFirstLaunch = true; // For exec-once
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,14 @@ monitor=,preferred,auto,auto
|
||||||
# Source a file (multi-file configs)
|
# Source a file (multi-file configs)
|
||||||
# source = ~/.config/hypr/myColors.conf
|
# source = ~/.config/hypr/myColors.conf
|
||||||
|
|
||||||
|
# Set programs that you use
|
||||||
|
$terminal = kitty
|
||||||
|
$fileManager = dolphin
|
||||||
|
$menu = wofi --show drun
|
||||||
|
|
||||||
# Some default env vars.
|
# Some default env vars.
|
||||||
env = XCURSOR_SIZE,24
|
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/
|
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
||||||
input {
|
input {
|
||||||
|
@ -58,6 +64,9 @@ general {
|
||||||
col.inactive_border = rgba(595959aa)
|
col.inactive_border = rgba(595959aa)
|
||||||
|
|
||||||
layout = dwindle
|
layout = dwindle
|
||||||
|
|
||||||
|
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
||||||
|
allow_tearing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
decoration {
|
decoration {
|
||||||
|
@ -108,6 +117,11 @@ gestures {
|
||||||
workspace_swipe = off
|
workspace_swipe = off
|
||||||
}
|
}
|
||||||
|
|
||||||
|
misc {
|
||||||
|
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||||
|
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
|
||||||
|
}
|
||||||
|
|
||||||
# Example per-device config
|
# Example per-device config
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
|
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
|
||||||
device:epic-mouse-v1 {
|
device:epic-mouse-v1 {
|
||||||
|
@ -119,18 +133,19 @@ device:epic-mouse-v1 {
|
||||||
# Example windowrule v2
|
# Example windowrule v2
|
||||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
# 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
|
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||||
$mainMod = SUPER
|
$mainMod = SUPER
|
||||||
|
|
||||||
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
# 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, C, killactive,
|
||||||
bind = $mainMod, M, exit,
|
bind = $mainMod, M, exit,
|
||||||
bind = $mainMod, E, exec, dolphin
|
bind = $mainMod, E, exec, $fileManager
|
||||||
bind = $mainMod, V, togglefloating,
|
bind = $mainMod, V, togglefloating,
|
||||||
bind = $mainMod, R, exec, wofi --show drun
|
bind = $mainMod, R, exec, $menu
|
||||||
bind = $mainMod, P, pseudo, # dwindle
|
bind = $mainMod, P, pseudo, # dwindle
|
||||||
bind = $mainMod, J, togglesplit, # dwindle
|
bind = $mainMod, J, togglesplit, # dwindle
|
||||||
|
|
||||||
|
@ -164,6 +179,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
|
||||||
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
||||||
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
||||||
|
|
||||||
|
# Example special workspace (scratchpad)
|
||||||
|
bind = $mainMod, S, togglespecialworkspace, magic
|
||||||
|
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
|
||||||
|
|
||||||
# Scroll through existing workspaces with mainMod + scroll
|
# Scroll through existing workspaces with mainMod + scroll
|
||||||
bind = $mainMod, mouse_down, workspace, e+1
|
bind = $mainMod, mouse_down, workspace, e+1
|
||||||
bind = $mainMod, mouse_up, workspace, e-1
|
bind = $mainMod, mouse_up, workspace, e-1
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "CrashReporter.hpp"
|
#include "CrashReporter.hpp"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <execinfo.h>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
@ -64,8 +63,8 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||||
struct utsname unameInfo;
|
struct utsname unameInfo;
|
||||||
uname(&unameInfo);
|
uname(&unameInfo);
|
||||||
|
|
||||||
finalCrashReport +=
|
finalCrashReport += std::format("\tSystem name: {}\n\tNode name: {}\n\tRelease: {}\n\tVersion: {}\n\n", std::string{unameInfo.sysname}, std::string{unameInfo.nodename},
|
||||||
std::format("\tSystem name: {}\n\tNode name: {}\n\tRelease: {}\n\tVersion: {}\n\n", unameInfo.sysname, unameInfo.nodename, unameInfo.release, unameInfo.version);
|
std::string{unameInfo.release}, std::string{unameInfo.version});
|
||||||
|
|
||||||
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||||
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
|
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
|
||||||
|
@ -120,7 +119,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||||
|
|
||||||
finalCrashReport += "\n\nLog tail:\n";
|
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 HOME = getenv("HOME");
|
||||||
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
|
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
|
||||||
|
@ -130,25 +129,19 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||||
|
|
||||||
std::ofstream ofs;
|
std::ofstream ofs;
|
||||||
std::string path;
|
std::string path;
|
||||||
if (!CACHE_HOME) {
|
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::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";
|
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||||
ofs.open(path, std::ios::trunc);
|
ofs.open(path, std::ios::trunc);
|
||||||
|
|
||||||
} else if (CACHE_HOME) {
|
} 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::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";
|
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||||
ofs.open(path, std::ios::trunc);
|
ofs.open(path, std::ios::trunc);
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ofs << finalCrashReport;
|
ofs << finalCrashReport;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -28,13 +29,22 @@ static std::string getWorkspaceNameFromSpecialID(const int workspaceID) {
|
||||||
return workspace->m_szName;
|
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 = "";
|
std::string result = "";
|
||||||
if (format == HyprCtl::FORMAT_JSON) {
|
if (format == HyprCtl::FORMAT_JSON) {
|
||||||
result += "[";
|
result += "[";
|
||||||
|
|
||||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
|
||||||
if (!m->output)
|
if (!m->output || m->ID == -1ull)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result += std::format(
|
result += std::format(
|
||||||
|
@ -63,35 +73,37 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
"transform": {},
|
"transform": {},
|
||||||
"focused": {},
|
"focused": {},
|
||||||
"dpmsStatus": {},
|
"dpmsStatus": {},
|
||||||
"vrr": {}
|
"vrr": {},
|
||||||
|
"activelyTearing": {}
|
||||||
}},)#",
|
}},)#",
|
||||||
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->output->description ? m->output->description : ""), (m->output->make ? m->output->make : ""),
|
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szDescription), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
|
||||||
(m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate,
|
(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
|
||||||
(int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName),
|
m->activeWorkspace, (m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID,
|
||||||
m->specialWorkspaceID, escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
|
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"),
|
(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->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"),
|
||||||
|
m->tearingState.activelyTearing ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
trimTrailingComma(result);
|
trimTrailingComma(result);
|
||||||
|
|
||||||
result += "]";
|
result += "]";
|
||||||
} else {
|
} else {
|
||||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
|
||||||
if (!m->output)
|
if (!m->output || m->ID == -1ull)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result +=
|
result +=
|
||||||
std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
|
std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
|
||||||
"workspace: {} ({})\n\treserved: {} "
|
"workspace: {} ({})\n\treserved: {} "
|
||||||
"{} {} {}\n\tscale: {:.2f}\n\ttransform: "
|
"{} {} {}\n\tscale: {:.2f}\n\ttransform: "
|
||||||
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\n",
|
"{}\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->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->description ? m->output->description : ""), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
|
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspace,
|
||||||
(m->output->serial ? m->output->serial : ""), m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName, m->specialWorkspaceID,
|
(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,
|
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->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));
|
(int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,33 +115,34 @@ static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat form
|
||||||
if (!w->m_sGroupData.pNextWindow)
|
if (!w->m_sGroupData.pNextWindow)
|
||||||
return isJson ? "" : "0";
|
return isJson ? "" : "0";
|
||||||
|
|
||||||
std::vector<CWindow*> groupMembers;
|
|
||||||
|
|
||||||
CWindow* curr = w;
|
|
||||||
do {
|
|
||||||
groupMembers.push_back(curr);
|
|
||||||
curr = curr->m_sGroupData.pNextWindow;
|
|
||||||
} while (curr != w);
|
|
||||||
|
|
||||||
const auto comma = isJson ? ", " : ",";
|
|
||||||
std::ostringstream result;
|
std::ostringstream result;
|
||||||
|
|
||||||
bool first = true;
|
CWindow* head = w->getGroupHead();
|
||||||
for (auto& gw : groupMembers) {
|
CWindow* curr = head;
|
||||||
if (first)
|
while (true) {
|
||||||
first = false;
|
|
||||||
else
|
|
||||||
result << comma;
|
|
||||||
if (isJson)
|
if (isJson)
|
||||||
result << std::format("\"0x{:x}\"", (uintptr_t)gw);
|
result << std::format("\"0x{:x}\"", (uintptr_t)curr);
|
||||||
else
|
else
|
||||||
result << std::format("{:x}", (uintptr_t)gw);
|
result << std::format("{:x}", (uintptr_t)curr);
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
// We've wrapped around to the start, break out without trailing comma
|
||||||
|
if (curr == head)
|
||||||
|
break;
|
||||||
|
result << (isJson ? ", " : ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.str();
|
return result.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
|
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
|
auto getFocusHistoryID = [](CWindow* wnd) -> int {
|
||||||
|
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) {
|
||||||
|
if (g_pCompositor->m_vWindowFocusHistory[i] == wnd)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
if (format == HyprCtl::FORMAT_JSON) {
|
if (format == HyprCtl::FORMAT_JSON) {
|
||||||
return std::format(
|
return std::format(
|
||||||
R"#({{
|
R"#({{
|
||||||
|
@ -155,7 +168,8 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
|
||||||
"fullscreenMode": {},
|
"fullscreenMode": {},
|
||||||
"fakeFullscreen": {},
|
"fakeFullscreen": {},
|
||||||
"grouped": [{}],
|
"grouped": [{}],
|
||||||
"swallowing": "0x{:x}"
|
"swallowing": "0x{:x}",
|
||||||
|
"focusHistoryID": {}
|
||||||
}},)#",
|
}},)#",
|
||||||
(uintptr_t)w, (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
|
(uintptr_t)w, (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
|
||||||
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID,
|
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID,
|
||||||
|
@ -166,13 +180,13 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
|
||||||
escapeJSONStrings(g_pXWaylandManager->getTitle(w)), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(),
|
escapeJSONStrings(g_pXWaylandManager->getTitle(w)), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(),
|
||||||
((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
|
((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
|
||||||
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? (int)g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
|
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? (int)g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
|
||||||
w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), (uintptr_t)w->m_pSwallowed);
|
w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), (uintptr_t)w->m_pSwallowed, getFocusHistoryID(w));
|
||||||
} else {
|
} else {
|
||||||
return std::format(
|
return std::format(
|
||||||
"Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
|
"Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
|
||||||
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
|
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
|
||||||
"{}\n\txwayland: {}\n\tpinned: "
|
"{}\n\txwayland: {}\n\tpinned: "
|
||||||
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\n",
|
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
|
||||||
(uintptr_t)w, w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
|
(uintptr_t)w, w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
|
||||||
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID,
|
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID,
|
||||||
(w->m_iWorkspaceID == -1 ? "" :
|
(w->m_iWorkspaceID == -1 ? "" :
|
||||||
|
@ -181,7 +195,7 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
|
||||||
(int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w), g_pXWaylandManager->getTitle(w), w->m_szInitialClass, w->m_szInitialTitle,
|
(int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w), g_pXWaylandManager->getTitle(w), w->m_szInitialClass, w->m_szInitialTitle,
|
||||||
w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
|
w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
|
||||||
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
|
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
|
||||||
(int)w->m_bFakeFullscreenState, getGroupedData(w, format), (uintptr_t)w->m_pSwallowed);
|
(int)w->m_bFakeFullscreenState, getGroupedData(w, format), (uintptr_t)w->m_pSwallowed, getFocusHistoryID(w));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,23 +227,70 @@ static std::string getWorkspaceData(CWorkspace* w, HyprCtl::eHyprCtlOutputFormat
|
||||||
"id": {},
|
"id": {},
|
||||||
"name": "{}",
|
"name": "{}",
|
||||||
"monitor": "{}",
|
"monitor": "{}",
|
||||||
|
"monitorID": {},
|
||||||
"windows": {},
|
"windows": {},
|
||||||
"hasfullscreen": {},
|
"hasfullscreen": {},
|
||||||
"lastwindow": "0x{:x}",
|
"lastwindow": "0x{:x}",
|
||||||
"lastwindowtitle": "{}"
|
"lastwindowtitle": "{}"
|
||||||
}})#",
|
}})#",
|
||||||
w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"), g_pCompositor->getWindowsOnWorkspace(w->m_iID),
|
w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"),
|
||||||
|
escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), g_pCompositor->getWindowsOnWorkspace(w->m_iID),
|
||||||
((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), (uintptr_t)PLASTW, PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
|
((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), (uintptr_t)PLASTW, PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
|
||||||
} else {
|
} else {
|
||||||
return std::format("workspace ID {} ({}) on monitor {}:\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID, w->m_szName,
|
return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID,
|
||||||
PMONITOR ? PMONITOR->szName : "?", g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow, (uintptr_t)PLASTW,
|
w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", g_pCompositor->getWindowsOnWorkspace(w->m_iID),
|
||||||
PLASTW ? PLASTW->m_szTitle : "");
|
(int)w->m_bHasFullscreenWindow, (uintptr_t)PLASTW, PLASTW ? PLASTW->m_szTitle : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
|
const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; };
|
||||||
|
if (format == HyprCtl::FORMAT_JSON) {
|
||||||
|
const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor));
|
||||||
|
const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : "";
|
||||||
|
const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : "";
|
||||||
|
const std::string gapsIn = (bool)(r.gapsIn) ? std::format(",\n \"gapsIn\": {}", r.gapsIn.value()) : "";
|
||||||
|
const std::string gapsOut = (bool)(r.gapsOut) ? std::format(",\n \"gapsOut\": {}", r.gapsOut.value()) : "";
|
||||||
|
const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : "";
|
||||||
|
const std::string border = (bool)(r.border) ? std::format(",\n \"border\": {}", boolToString(r.border.value())) : "";
|
||||||
|
const std::string rounding = (bool)(r.rounding) ? std::format(",\n \"rounding\": {}", boolToString(r.rounding.value())) : "";
|
||||||
|
const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : "";
|
||||||
|
const std::string shadow = (bool)(r.shadow) ? std::format(",\n \"shadow\": {}", boolToString(r.shadow.value())) : "";
|
||||||
|
|
||||||
|
std::string result = std::format(R"#({{
|
||||||
|
"workspaceString": "{}"{}{}{}{}{}{}{}{}
|
||||||
|
}})#",
|
||||||
|
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "<unset>" : escapeJSONStrings(r.monitor));
|
||||||
|
const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : "<unset>");
|
||||||
|
const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : "<unset>");
|
||||||
|
const std::string gapsIn = std::format("\tgapsIn: {}\n", (bool)(r.gapsIn) ? std::to_string(r.gapsIn.value()) : "<unset>");
|
||||||
|
const std::string gapsOut = std::format("\tgapsOut: {}\n", (bool)(r.gapsOut) ? std::to_string(r.gapsOut.value()) : "<unset>");
|
||||||
|
const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>");
|
||||||
|
const std::string border = std::format("\tborder: {}\n", (bool)(r.border) ? boolToString(r.border.value()) : "<unset>");
|
||||||
|
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.rounding) ? boolToString(r.rounding.value()) : "<unset>");
|
||||||
|
const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>");
|
||||||
|
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.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);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
|
if (!g_pCompositor->m_pLastMonitor)
|
||||||
|
return "unsafe state";
|
||||||
|
|
||||||
std::string result = "";
|
std::string result = "";
|
||||||
auto w = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
|
auto w = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
|
||||||
|
|
||||||
|
if (!w)
|
||||||
|
return "internal error";
|
||||||
|
|
||||||
return getWorkspaceData(w, format);
|
return getWorkspaceData(w, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +315,26 @@ std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
|
std::string result = "";
|
||||||
|
if (format == HyprCtl::FORMAT_JSON) {
|
||||||
|
result += "[";
|
||||||
|
for (auto& r : g_pConfigManager->getAllWorkspaceRules()) {
|
||||||
|
result += getWorkspaceRuleData(r, format);
|
||||||
|
result += ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
trimTrailingComma(result);
|
||||||
|
result += "]";
|
||||||
|
} else {
|
||||||
|
for (auto& r : g_pConfigManager->getAllWorkspaceRules()) {
|
||||||
|
result += getWorkspaceRuleData(r, format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
const auto PWINDOW = g_pCompositor->m_pLastWindow;
|
const auto PWINDOW = g_pCompositor->m_pLastWindow;
|
||||||
|
|
||||||
|
@ -342,6 +423,28 @@ std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
return result;
|
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 devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
std::string result = "";
|
std::string result = "";
|
||||||
|
|
||||||
|
@ -554,6 +657,20 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
return ret;
|
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 globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
std::string ret = "";
|
std::string ret = "";
|
||||||
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts();
|
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts();
|
||||||
|
@ -632,15 +749,12 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
|
|
||||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
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 +
|
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
|
#ifdef LEGACY_RENDERER
|
||||||
result += "legacyrenderer\n";
|
result += "legacyrenderer\n";
|
||||||
#endif
|
#endif
|
||||||
#ifndef NDEBUG
|
#ifndef ISDEBUG
|
||||||
result += "debug\n";
|
|
||||||
#endif
|
|
||||||
#ifdef HYPRLAND_DEBUG
|
|
||||||
result += "debug\n";
|
result += "debug\n";
|
||||||
#endif
|
#endif
|
||||||
#ifdef NO_XWAYLAND
|
#ifdef NO_XWAYLAND
|
||||||
|
@ -655,17 +769,15 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
"commit": "{}",
|
"commit": "{}",
|
||||||
"dirty": {},
|
"dirty": {},
|
||||||
"commit_message": "{}",
|
"commit_message": "{}",
|
||||||
|
"commit_date": "{}",
|
||||||
"tag": "{}",
|
"tag": "{}",
|
||||||
"flags": [)#",
|
"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
|
#ifdef LEGACY_RENDERER
|
||||||
result += "\"legacyrenderer\",";
|
result += "\"legacyrenderer\",";
|
||||||
#endif
|
#endif
|
||||||
#ifndef NDEBUG
|
#ifndef ISDEBUG
|
||||||
result += "\"debug\",";
|
|
||||||
#endif
|
|
||||||
#ifdef HYPRLAND_DEBUG
|
|
||||||
result += "\"debug\",";
|
result += "\"debug\",";
|
||||||
#endif
|
#endif
|
||||||
#ifdef NO_XWAYLAND
|
#ifdef NO_XWAYLAND
|
||||||
|
@ -682,6 +794,39 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
return ""; // make the compiler happy
|
return ""; // make the compiler happy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string systemInfoRequest() {
|
||||||
|
std::string result = versionRequest(HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL);
|
||||||
|
|
||||||
|
result += "\n\nSystem Information:\n";
|
||||||
|
|
||||||
|
struct utsname unameInfo;
|
||||||
|
|
||||||
|
uname(&unameInfo);
|
||||||
|
|
||||||
|
result += "System name: " + std::string{unameInfo.sysname} + "\n";
|
||||||
|
result += "Node name: " + std::string{unameInfo.nodename} + "\n";
|
||||||
|
result += "Release: " + std::string{unameInfo.release} + "\n";
|
||||||
|
result += "Version: " + std::string{unameInfo.version} + "\n";
|
||||||
|
|
||||||
|
result += "\n\n";
|
||||||
|
|
||||||
|
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||||
|
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
|
||||||
|
#else
|
||||||
|
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
|
||||||
|
#endif
|
||||||
|
result += "GPU information: \n" + GPUINFO + "\n\n";
|
||||||
|
|
||||||
|
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
|
||||||
|
|
||||||
|
result += "plugins:\n";
|
||||||
|
for (auto& pl : g_pPluginSystem->getAllPlugins()) {
|
||||||
|
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::string dispatchRequest(std::string in) {
|
std::string dispatchRequest(std::string in) {
|
||||||
// get rid of the dispatch keyword
|
// get rid of the dispatch keyword
|
||||||
in = in.substr(in.find_first_of(' ') + 1);
|
in = in.substr(in.find_first_of(' ') + 1);
|
||||||
|
@ -952,7 +1097,7 @@ std::string dispatchSetProp(std::string request) {
|
||||||
bool lock = false;
|
bool lock = false;
|
||||||
|
|
||||||
if (vars.size() > 4) {
|
if (vars.size() > 4) {
|
||||||
if (vars[4].find("lock") == 0) {
|
if (vars[4].starts_with("lock")) {
|
||||||
lock = true;
|
lock = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -993,15 +1138,19 @@ std::string dispatchSetProp(std::string request) {
|
||||||
} else if (PROP == "alphainactive") {
|
} else if (PROP == "alphainactive") {
|
||||||
PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock);
|
PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock);
|
||||||
} else if (PROP == "activebordercolor") {
|
} else if (PROP == "activebordercolor") {
|
||||||
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock);
|
||||||
} else if (PROP == "inactivebordercolor") {
|
} else if (PROP == "inactivebordercolor") {
|
||||||
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock);
|
||||||
} else if (PROP == "forcergbx") {
|
} else if (PROP == "forcergbx") {
|
||||||
PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||||
} else if (PROP == "bordersize") {
|
} else if (PROP == "bordersize") {
|
||||||
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||||
} else if (PROP == "keepaspectratio") {
|
} else if (PROP == "keepaspectratio") {
|
||||||
PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||||
|
} else if (PROP == "immediate") {
|
||||||
|
PWINDOW->m_sAdditionalConfigData.forceTearing.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||||
|
} else if (PROP == "nearestneighbor") {
|
||||||
|
PWINDOW->m_sAdditionalConfigData.nearestNeighbor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||||
} else {
|
} else {
|
||||||
return "prop not found";
|
return "prop not found";
|
||||||
}
|
}
|
||||||
|
@ -1059,6 +1208,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) {
|
void createOutputIter(wlr_backend* backend, void* data) {
|
||||||
const auto DATA = (std::pair<std::string, bool>*)data;
|
const auto DATA = (std::pair<std::string, bool>*)data;
|
||||||
|
|
||||||
|
@ -1155,7 +1330,7 @@ std::string dispatchPlugin(std::string request) {
|
||||||
const auto PLUGIN = g_pPluginSystem->loadPlugin(PATH);
|
const auto PLUGIN = g_pPluginSystem->loadPlugin(PATH);
|
||||||
|
|
||||||
if (!PLUGIN)
|
if (!PLUGIN)
|
||||||
return "error in loading plugin";
|
return "error in loading plugin, last error: " + g_pPluginSystem->m_szLastError;
|
||||||
} else if (OPERATION == "unload") {
|
} else if (OPERATION == "unload") {
|
||||||
if (vars.size() < 3)
|
if (vars.size() < 3)
|
||||||
return "not enough args";
|
return "not enough args";
|
||||||
|
@ -1227,13 +1402,20 @@ std::string getReply(std::string request) {
|
||||||
auto format = HyprCtl::FORMAT_NORMAL;
|
auto format = HyprCtl::FORMAT_NORMAL;
|
||||||
|
|
||||||
// process flags for non-batch requests
|
// process flags for non-batch requests
|
||||||
if (!request.contains("[[BATCH]]") && request.contains("/")) {
|
if (!request.starts_with("[[BATCH]]") && request.contains("/")) {
|
||||||
long unsigned int sepIndex = 0;
|
long unsigned int sepIndex = 0;
|
||||||
for (const auto& c : request) {
|
for (const auto& c : request) {
|
||||||
if (c == '/') { // stop at separator
|
if (c == '/') { // stop at separator
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// after whitespace assume the first word as a keyword,
|
||||||
|
// so its value can have slashes (e.g., a path)
|
||||||
|
if (c == ' ') {
|
||||||
|
sepIndex = request.size();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
sepIndex++;
|
sepIndex++;
|
||||||
|
|
||||||
if (c == 'j')
|
if (c == 'j')
|
||||||
|
@ -1244,10 +1426,12 @@ std::string getReply(std::string request) {
|
||||||
request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string
|
request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request == "monitors")
|
if (request.starts_with("monitors"))
|
||||||
return monitorsRequest(format);
|
return monitorsRequest(request, format);
|
||||||
else if (request == "workspaces")
|
else if (request == "workspaces")
|
||||||
return workspacesRequest(format);
|
return workspacesRequest(format);
|
||||||
|
else if (request == "workspacerules")
|
||||||
|
return workspaceRulesRequest(format);
|
||||||
else if (request == "activeworkspace")
|
else if (request == "activeworkspace")
|
||||||
return activeWorkspaceRequest(format);
|
return activeWorkspaceRequest(format);
|
||||||
else if (request == "clients")
|
else if (request == "clients")
|
||||||
|
@ -1260,7 +1444,7 @@ std::string getReply(std::string request) {
|
||||||
return layersRequest(format);
|
return layersRequest(format);
|
||||||
else if (request == "version")
|
else if (request == "version")
|
||||||
return versionRequest(format);
|
return versionRequest(format);
|
||||||
else if (request.find("reload") == 0)
|
else if (request.starts_with("reload"))
|
||||||
return reloadRequest(request);
|
return reloadRequest(request);
|
||||||
else if (request == "devices")
|
else if (request == "devices")
|
||||||
return devicesRequest(format);
|
return devicesRequest(format);
|
||||||
|
@ -1272,29 +1456,37 @@ std::string getReply(std::string request) {
|
||||||
return bindsRequest(format);
|
return bindsRequest(format);
|
||||||
else if (request == "globalshortcuts")
|
else if (request == "globalshortcuts")
|
||||||
return globalShortcutsRequest(format);
|
return globalShortcutsRequest(format);
|
||||||
|
else if (request == "systeminfo")
|
||||||
|
return systemInfoRequest();
|
||||||
else if (request == "animations")
|
else if (request == "animations")
|
||||||
return animationsRequest(format);
|
return animationsRequest(format);
|
||||||
else if (request.find("plugin") == 0)
|
else if (request == "rollinglog")
|
||||||
|
return rollinglogRequest(format);
|
||||||
|
else if (request == "layouts")
|
||||||
|
return layoutsRequest(format);
|
||||||
|
else if (request.starts_with("plugin"))
|
||||||
return dispatchPlugin(request);
|
return dispatchPlugin(request);
|
||||||
else if (request.find("notify") == 0)
|
else if (request.starts_with("notify"))
|
||||||
return dispatchNotify(request);
|
return dispatchNotify(request);
|
||||||
else if (request.find("setprop") == 0)
|
else if (request.starts_with("setprop"))
|
||||||
return dispatchSetProp(request);
|
return dispatchSetProp(request);
|
||||||
else if (request.find("seterror") == 0)
|
else if (request.starts_with("seterror"))
|
||||||
return dispatchSeterror(request);
|
return dispatchSeterror(request);
|
||||||
else if (request.find("switchxkblayout") == 0)
|
else if (request.starts_with("switchxkblayout"))
|
||||||
return switchXKBLayoutRequest(request);
|
return switchXKBLayoutRequest(request);
|
||||||
else if (request.find("output") == 0)
|
else if (request.starts_with("output"))
|
||||||
return dispatchOutput(request);
|
return dispatchOutput(request);
|
||||||
else if (request.find("dispatch") == 0)
|
else if (request.starts_with("dispatch"))
|
||||||
return dispatchRequest(request);
|
return dispatchRequest(request);
|
||||||
else if (request.find("keyword") == 0)
|
else if (request.starts_with("keyword"))
|
||||||
return dispatchKeyword(request);
|
return dispatchKeyword(request);
|
||||||
else if (request.find("setcursor") == 0)
|
else if (request.starts_with("setcursor"))
|
||||||
return dispatchSetCursor(request);
|
return dispatchSetCursor(request);
|
||||||
else if (request.find("getoption") == 0)
|
else if (request.starts_with("getoption"))
|
||||||
return dispatchGetOption(request, format);
|
return dispatchGetOption(request, format);
|
||||||
else if (request.find("[[BATCH]]") == 0)
|
else if (request.starts_with("decorations"))
|
||||||
|
return decorationRequest(request, format);
|
||||||
|
else if (request.starts_with("[[BATCH]]"))
|
||||||
return dispatchBatch(request);
|
return dispatchBatch(request);
|
||||||
|
|
||||||
return "unknown request";
|
return "unknown request";
|
||||||
|
@ -1313,7 +1505,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||||
|
|
||||||
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_ZERO(&fdset);
|
||||||
|
@ -1326,10 +1518,17 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024);
|
std::string request;
|
||||||
readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0';
|
while (true) {
|
||||||
|
readBuffer.fill(0);
|
||||||
std::string request(readBuffer);
|
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 = "";
|
std::string reply = "";
|
||||||
|
|
||||||
|
|
|
@ -233,6 +233,6 @@ void CHyprDebugOverlay::draw() {
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||||
|
|
||||||
wlr_box pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
||||||
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
|
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ class CHyprMonitorDebugOverlay {
|
||||||
std::deque<float> m_dLastAnimationTicks;
|
std::deque<float> m_dLastAnimationTicks;
|
||||||
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
|
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
|
||||||
CMonitor* m_pMonitor = nullptr;
|
CMonitor* m_pMonitor = nullptr;
|
||||||
wlr_box m_wbLastDrawnBox;
|
CBox m_wbLastDrawnBox;
|
||||||
|
|
||||||
friend class CHyprRenderer;
|
friend class CHyprRenderer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <pango/pangocairo.h>
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
||||||
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, std::any param) {
|
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
|
||||||
if (m_dNotifications.size() == 0)
|
if (m_dNotifications.size() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -44,9 +44,13 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC
|
||||||
PNOTIF->started.reset();
|
PNOTIF->started.reset();
|
||||||
PNOTIF->timeMs = timeMs;
|
PNOTIF->timeMs = timeMs;
|
||||||
PNOTIF->icon = icon;
|
PNOTIF->icon = icon;
|
||||||
|
|
||||||
|
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||||
|
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
||||||
static constexpr auto ANIM_DURATION_MS = 600.0;
|
static constexpr auto ANIM_DURATION_MS = 600.0;
|
||||||
static constexpr auto ANIM_LAG_MS = 100.0;
|
static constexpr auto ANIM_LAG_MS = 100.0;
|
||||||
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
|
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
|
||||||
|
@ -166,7 +170,7 @@ wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
||||||
// cleanup notifs
|
// cleanup notifs
|
||||||
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
|
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
|
||||||
|
|
||||||
return wlr_box{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
|
return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
|
void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
|
||||||
|
@ -197,7 +201,7 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
|
||||||
|
|
||||||
cairo_surface_flush(m_pCairoSurface);
|
cairo_surface_flush(m_pCairoSurface);
|
||||||
|
|
||||||
wlr_box damage = drawNotifications(pMonitor);
|
CBox damage = drawNotifications(pMonitor);
|
||||||
|
|
||||||
g_pHyprRenderer->damageBox(&damage);
|
g_pHyprRenderer->damageBox(&damage);
|
||||||
g_pHyprRenderer->damageBox(&m_bLastDamage);
|
g_pHyprRenderer->damageBox(&m_bLastDamage);
|
||||||
|
@ -220,6 +224,6 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||||
|
|
||||||
wlr_box pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
|
CBox pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
|
||||||
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
|
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
|
||||||
}
|
}
|
|
@ -10,16 +10,15 @@
|
||||||
|
|
||||||
#include <cairo/cairo.h>
|
#include <cairo/cairo.h>
|
||||||
|
|
||||||
enum eIconBackend
|
enum eIconBackend {
|
||||||
{
|
|
||||||
ICONS_BACKEND_NONE = 0,
|
ICONS_BACKEND_NONE = 0,
|
||||||
ICONS_BACKEND_NF,
|
ICONS_BACKEND_NF,
|
||||||
ICONS_BACKEND_FA
|
ICONS_BACKEND_FA
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
|
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>{"[!]", "[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>{"", "", "", "", "", ""}};
|
||||||
static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
|
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{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
|
||||||
CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
|
CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
|
||||||
|
@ -44,8 +43,8 @@ class CHyprNotificationOverlay {
|
||||||
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
|
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wlr_box drawNotifications(CMonitor* pMonitor);
|
CBox drawNotifications(CMonitor* pMonitor);
|
||||||
wlr_box m_bLastDamage;
|
CBox m_bLastDamage;
|
||||||
|
|
||||||
std::deque<std::unique_ptr<SNotification>> m_dNotifications;
|
std::deque<std::unique_ptr<SNotification>> m_dNotifications;
|
||||||
|
|
||||||
|
|
|
@ -10,19 +10,24 @@ void Debug::init(const std::string& IS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
|
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
|
||||||
char* outputStr = nullptr;
|
if (level > wlr_log_get_verbosity())
|
||||||
|
return;
|
||||||
|
|
||||||
std::ofstream ofs;
|
char* outputStr = nullptr;
|
||||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
|
||||||
|
|
||||||
vasprintf(&outputStr, fmt, args);
|
vasprintf(&outputStr, fmt, args);
|
||||||
|
|
||||||
std::string output = std::string(outputStr);
|
std::string output = std::string(outputStr);
|
||||||
free(outputStr);
|
free(outputStr);
|
||||||
|
|
||||||
ofs << "[wlr] " << output << "\n";
|
rollingLog += output + "\n";
|
||||||
|
|
||||||
|
if (!disableLogs || !*disableLogs) {
|
||||||
|
std::ofstream ofs;
|
||||||
|
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||||
|
ofs << "[wlr] " << output << "\n";
|
||||||
ofs.close();
|
ofs.close();
|
||||||
|
}
|
||||||
|
|
||||||
if (!disableStdout)
|
if (!disableStdout)
|
||||||
std::cout << output << "\n";
|
std::cout << output << "\n";
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <wlr/util/log.h>
|
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include "../includes.hpp"
|
||||||
#include "../helpers/MiscFunctions.hpp"
|
#include "../helpers/MiscFunctions.hpp"
|
||||||
|
|
||||||
#define LOGMESSAGESIZE 1024
|
#define LOGMESSAGESIZE 1024
|
||||||
|
#define ROLLING_LOG_SIZE 4096
|
||||||
|
|
||||||
enum LogLevel {
|
enum LogLevel {
|
||||||
NONE = -1,
|
NONE = -1,
|
||||||
|
@ -25,14 +26,17 @@ namespace Debug {
|
||||||
inline int64_t* disableTime = nullptr;
|
inline int64_t* disableTime = nullptr;
|
||||||
inline bool disableStdout = false;
|
inline bool disableStdout = false;
|
||||||
inline bool trace = 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);
|
void init(const std::string& IS);
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
|
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
|
||||||
if (disableLogs && *disableLogs)
|
if (level == TRACE && !trace)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (level == TRACE && !trace)
|
if (shuttingDown)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string logMsg = "";
|
std::string logMsg = "";
|
||||||
|
@ -47,10 +51,6 @@ namespace Debug {
|
||||||
default: break;
|
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
|
// print date and time to the ofs
|
||||||
if (disableTime && !*disableTime) {
|
if (disableTime && !*disableTime) {
|
||||||
#ifndef _LIBCPP_VERSION
|
#ifndef _LIBCPP_VERSION
|
||||||
|
@ -69,9 +69,18 @@ namespace Debug {
|
||||||
// 3. this is actually what std::format in stdlib does
|
// 3. this is actually what std::format in stdlib does
|
||||||
logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
|
logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
|
||||||
|
rollingLog += logMsg + "\n";
|
||||||
|
if (rollingLog.size() > ROLLING_LOG_SIZE)
|
||||||
|
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
|
||||||
|
|
||||||
|
if (!disableLogs || !*disableLogs) {
|
||||||
|
// log to a file
|
||||||
|
std::ofstream ofs;
|
||||||
|
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||||
ofs << logMsg << "\n";
|
ofs << logMsg << "\n";
|
||||||
|
|
||||||
ofs.close();
|
ofs.close();
|
||||||
|
}
|
||||||
|
|
||||||
// log it to the stdout too.
|
// log it to the stdout too.
|
||||||
if (!disableStdout)
|
if (!disableStdout)
|
||||||
|
|
|
@ -13,15 +13,6 @@ inline PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v;
|
||||||
|
|
||||||
#include "../../subprojects/tracy/public/tracy/TracyOpenGL.hpp"
|
#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_CONTEXT TracyGpuContext
|
||||||
#define TRACY_GPU_ZONE(e) TracyGpuZone(e)
|
#define TRACY_GPU_ZONE(e) TracyGpuZone(e)
|
||||||
#define TRACY_GPU_COLLECT TracyGpuCollect
|
#define TRACY_GPU_COLLECT TracyGpuCollect
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace Events {
|
||||||
DYNLISTENFUNC(repositionPopupXDG);
|
DYNLISTENFUNC(repositionPopupXDG);
|
||||||
|
|
||||||
// Surface XDG (window)
|
// Surface XDG (window)
|
||||||
LISTENER(newXDGSurface);
|
LISTENER(newXDGToplevel);
|
||||||
LISTENER(activateXDG);
|
LISTENER(activateXDG);
|
||||||
|
|
||||||
// Window events
|
// Window events
|
||||||
|
@ -62,6 +62,7 @@ namespace Events {
|
||||||
DYNLISTENFUNC(setOverrideRedirect);
|
DYNLISTENFUNC(setOverrideRedirect);
|
||||||
DYNLISTENFUNC(associateX11);
|
DYNLISTENFUNC(associateX11);
|
||||||
DYNLISTENFUNC(dissociateX11);
|
DYNLISTENFUNC(dissociateX11);
|
||||||
|
DYNLISTENFUNC(ackConfigure);
|
||||||
|
|
||||||
// Window subsurfaces
|
// Window subsurfaces
|
||||||
// LISTENER(newSubsurfaceWindow);
|
// LISTENER(newSubsurfaceWindow);
|
||||||
|
@ -120,10 +121,6 @@ namespace Events {
|
||||||
DYNLISTENFUNC(destroyDragIcon);
|
DYNLISTENFUNC(destroyDragIcon);
|
||||||
DYNLISTENFUNC(commitDragIcon);
|
DYNLISTENFUNC(commitDragIcon);
|
||||||
|
|
||||||
// Inhibit
|
|
||||||
LISTENER(InhibitActivate);
|
|
||||||
LISTENER(InhibitDeactivate);
|
|
||||||
|
|
||||||
// Deco XDG
|
// Deco XDG
|
||||||
LISTENER(NewXDGDeco);
|
LISTENER(NewXDGDeco);
|
||||||
|
|
||||||
|
@ -174,4 +171,7 @@ namespace Events {
|
||||||
|
|
||||||
// Cursor shape
|
// Cursor shape
|
||||||
LISTENER(setCursorShape);
|
LISTENER(setCursorShape);
|
||||||
|
|
||||||
|
// Tearing hints
|
||||||
|
LISTENER(newTearingHint);
|
||||||
};
|
};
|
||||||
|
|
|
@ -95,7 +95,7 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
|
||||||
PMONITOR->scheduledRecalc = true;
|
PMONITOR->scheduledRecalc = true;
|
||||||
|
|
||||||
// and damage
|
// and damage
|
||||||
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
||||||
layersurface->geometry.height};
|
layersurface->geometry.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||||
|
|
||||||
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
|
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
|
||||||
|
|
||||||
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive &&
|
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
|
||||||
// don't focus if constrained
|
// don't focus if constrained
|
||||||
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
|
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||||
|
|
||||||
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
|
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
|
||||||
|
|
||||||
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
||||||
layersurface->geometry.height};
|
layersurface->geometry.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||||
|
@ -171,7 +171,8 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
|
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
|
||||||
EMIT_HOOK_EVENT("openLayer", layersurface);
|
EMIT_HOOK_EVENT("openLayer", layersurface);
|
||||||
|
|
||||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
||||||
|
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||||
|
@ -246,13 +247,15 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
||||||
layersurface->geometry.height};
|
layersurface->geometry.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
|
|
||||||
geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y,
|
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};
|
(int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
|
|
||||||
|
g_pInputManager->sendMotionEventsToFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_commitLayerSurface(void* owner, void* data) {
|
void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||||
|
@ -269,7 +272,7 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||||
if (layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
|
if (layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
|
||||||
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
|
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
|
||||||
|
|
||||||
wlr_box geomFixed = {layersurface->geometry.x, layersurface->geometry.y, layersurface->geometry.width, layersurface->geometry.height};
|
CBox geomFixed = {layersurface->geometry.x, layersurface->geometry.y, layersurface->geometry.width, layersurface->geometry.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
|
|
||||||
// fix if it changed its mon
|
// fix if it changed its mon
|
||||||
|
@ -342,5 +345,6 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||||
|
|
||||||
g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y);
|
g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y);
|
||||||
|
|
||||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
||||||
|
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,20 +156,6 @@ void Events::listener_commitDragIcon(void* owner, void* data) {
|
||||||
Debug::log(LOG, "Drag icon committed.");
|
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) {
|
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
|
||||||
Debug::log(LOG, "!!Renderer destroyed!!");
|
Debug::log(LOG, "!!Renderer destroyed!!");
|
||||||
}
|
}
|
||||||
|
@ -237,3 +223,43 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
|
||||||
|
|
||||||
g_pInputManager->processMouseRequest(E);
|
g_pInputManager->processMouseRequest(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Events::listener_newTearingHint(wl_listener* listener, void* data) {
|
||||||
|
const auto TCTL = (wlr_tearing_control_v1*)data;
|
||||||
|
|
||||||
|
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface);
|
||||||
|
|
||||||
|
if (!PWINDOW) {
|
||||||
|
Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)data);
|
||||||
|
|
||||||
|
const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
|
||||||
|
NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
|
||||||
|
|
||||||
|
NEWCTRL->hyprListener_destroy.initCallback(
|
||||||
|
&NEWCTRL->pWlrHint->events.destroy,
|
||||||
|
[&](void* owner, void* data) {
|
||||||
|
Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
|
||||||
|
|
||||||
|
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
|
||||||
|
},
|
||||||
|
NEWCTRL, "TearingController");
|
||||||
|
|
||||||
|
NEWCTRL->hyprListener_set.initCallback(
|
||||||
|
&NEWCTRL->pWlrHint->events.set_hint,
|
||||||
|
[&](void* owner, void* data) {
|
||||||
|
const auto TEARINGHINT = (STearingController*)owner;
|
||||||
|
|
||||||
|
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
|
||||||
|
|
||||||
|
if (PWINDOW) {
|
||||||
|
PWINDOW->m_bTearingHint = (bool)TEARINGHINT->pWlrHint->current;
|
||||||
|
|
||||||
|
Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->current);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NEWCTRL, "TearingController");
|
||||||
|
}
|
||||||
|
|
|
@ -22,14 +22,18 @@ void Events::listener_change(wl_listener* listener, void* data) {
|
||||||
if (!CONFIG)
|
if (!CONFIG)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||||
if (!m->output)
|
if (!m->output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (g_pCompositor->m_pUnsafeOutput == m.get())
|
||||||
|
continue;
|
||||||
|
|
||||||
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output);
|
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output);
|
||||||
|
|
||||||
wlr_box BOX;
|
CBox BOX;
|
||||||
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, &BOX);
|
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, BOX.pWlr());
|
||||||
|
BOX.applyFromWlr();
|
||||||
|
|
||||||
//m->vecSize.x = BOX.width;
|
//m->vecSize.x = BOX.width;
|
||||||
// m->vecSize.y = BOX.height;
|
// m->vecSize.y = BOX.height;
|
||||||
|
@ -67,52 +71,31 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_pCompositor->m_bUnsafeState)
|
|
||||||
Debug::log(WARN, "Recovering from an unsafe state. May you be lucky.");
|
|
||||||
|
|
||||||
// add it to real
|
// add it to real
|
||||||
std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
|
std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
|
||||||
|
|
||||||
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
|
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
|
||||||
|
if (std::string("HEADLESS-1") == OUTPUT->name)
|
||||||
|
g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get();
|
||||||
|
|
||||||
(*PNEWMONITORWRAP)->ID = g_pCompositor->getNextAvailableMonitorID(OUTPUT->name);
|
(*PNEWMONITORWRAP)->output = OUTPUT;
|
||||||
|
const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false;
|
||||||
|
(*PNEWMONITORWRAP)->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name);
|
||||||
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
|
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
|
||||||
|
PNEWMONITOR->isUnsafeFallback = FALLBACK;
|
||||||
|
|
||||||
PNEWMONITOR->output = OUTPUT;
|
if (!FALLBACK)
|
||||||
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
|
|
||||||
|
|
||||||
PNEWMONITOR->onConnect(false);
|
PNEWMONITOR->onConnect(false);
|
||||||
|
|
||||||
|
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// ready to process if we have a real monitor
|
||||||
|
|
||||||
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
|
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
|
||||||
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
|
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
|
||||||
|
|
||||||
// wlroots will instantly call this handler before we get a return to the wlr_output* in CCompositor::enterUnsafeState
|
|
||||||
const bool PROBABLYFALLBACK = (g_pCompositor->m_bUnsafeState && !g_pCompositor->m_pUnsafeOutput) || OUTPUT == g_pCompositor->m_pUnsafeOutput;
|
|
||||||
|
|
||||||
// ready to process if we have a real monitor
|
|
||||||
if (PNEWMONITOR->m_bEnabled && !PROBABLYFALLBACK) {
|
|
||||||
// leave unsafe state
|
|
||||||
if (g_pCompositor->m_bUnsafeState) {
|
|
||||||
// recover workspaces
|
|
||||||
std::vector<CWorkspace*> wsp;
|
|
||||||
for (auto& ws : g_pCompositor->m_vWorkspaces) {
|
|
||||||
wsp.push_back(ws.get());
|
|
||||||
}
|
|
||||||
for (auto& ws : wsp) {
|
|
||||||
// because this can realloc the vec
|
|
||||||
g_pCompositor->moveWorkspaceToMonitor(ws, PNEWMONITOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
|
|
||||||
|
|
||||||
const auto POS = PNEWMONITOR->middle();
|
|
||||||
if (g_pCompositor->m_sSeat.mouse)
|
|
||||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, POS.x, POS.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_pCompositor->m_bReadyToProcess = true;
|
g_pCompositor->m_bReadyToProcess = true;
|
||||||
}
|
|
||||||
|
|
||||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||||
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
|
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
|
||||||
|
@ -126,7 +109,7 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
|
||||||
for (auto& w : g_pCompositor->m_vWindows) {
|
for (auto& w : g_pCompositor->m_vWindows) {
|
||||||
if (w->m_iMonitorID == PNEWMONITOR->ID) {
|
if (w->m_iMonitorID == PNEWMONITOR->ID) {
|
||||||
w->m_iLastSurfaceMonitorID = -1;
|
w->m_iLastSurfaceMonitorID = -1;
|
||||||
w->updateSurfaceOutputs();
|
w->updateSurfaceScaleTransformDetails();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +121,9 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||||
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
|
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
|
||||||
Debug::log(WARN, "Attempted to render frame on inactive session!");
|
Debug::log(WARN, "Attempted to render frame on inactive session!");
|
||||||
|
|
||||||
if (g_pCompositor->m_bUnsafeState && PMONITOR->output != g_pCompositor->m_pUnsafeOutput) {
|
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
|
||||||
|
return m->output != g_pCompositor->m_pUnsafeOutput->output;
|
||||||
|
})) {
|
||||||
// restore from unsafe state
|
// restore from unsafe state
|
||||||
g_pCompositor->leaveUnsafeState();
|
g_pCompositor->leaveUnsafeState();
|
||||||
}
|
}
|
||||||
|
@ -149,12 +134,25 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||||
if (!PMONITOR->m_bEnabled)
|
if (!PMONITOR->m_bEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
g_pHyprRenderer->recheckSolitaryForMonitor(PMONITOR);
|
||||||
|
|
||||||
|
PMONITOR->tearingState.busy = false;
|
||||||
|
|
||||||
|
if (PMONITOR->tearingState.activelyTearing && PMONITOR->solitaryClient /* can be invalidated by a recheck */) {
|
||||||
|
|
||||||
|
if (!PMONITOR->tearingState.frameScheduledWhileBusy)
|
||||||
|
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
|
||||||
|
|
||||||
|
PMONITOR->tearingState.nextRenderTorn = true;
|
||||||
|
PMONITOR->tearingState.frameScheduledWhileBusy = false;
|
||||||
|
}
|
||||||
|
|
||||||
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
|
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
|
||||||
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
|
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
|
||||||
|
|
||||||
PMONITOR->lastPresentationTimer.reset();
|
PMONITOR->lastPresentationTimer.reset();
|
||||||
|
|
||||||
if (*PENABLERAT) {
|
if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
|
||||||
if (!PMONITOR->RATScheduled) {
|
if (!PMONITOR->RATScheduled) {
|
||||||
// render
|
// render
|
||||||
g_pHyprRenderer->renderMonitor(PMONITOR);
|
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||||
|
@ -200,14 +198,11 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||||
|
|
||||||
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
|
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
|
||||||
|
|
||||||
pMonitor->onDisconnect();
|
pMonitor->onDisconnect(true);
|
||||||
|
|
||||||
pMonitor->output = nullptr;
|
pMonitor->output = nullptr;
|
||||||
pMonitor->m_bRenderingInitPassed = false;
|
pMonitor->m_bRenderingInitPassed = false;
|
||||||
|
|
||||||
if (g_pCompositor->m_pUnsafeOutput == OUTPUT)
|
|
||||||
g_pCompositor->m_pUnsafeOutput = nullptr;
|
|
||||||
|
|
||||||
Debug::log(LOG, "Removing monitor {} from realMonitors", pMonitor->szName);
|
Debug::log(LOG, "Removing monitor {} from realMonitors", pMonitor->szName);
|
||||||
|
|
||||||
std::erase_if(g_pCompositor->m_vRealMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; });
|
std::erase_if(g_pCompositor->m_vRealMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; });
|
||||||
|
@ -238,7 +233,7 @@ void Events::listener_monitorCommit(void* owner, void* data) {
|
||||||
|
|
||||||
const auto E = (wlr_output_event_commit*)data;
|
const auto E = (wlr_output_event_commit*)data;
|
||||||
|
|
||||||
if (E->committed & WLR_OUTPUT_STATE_BUFFER) {
|
if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
|
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
|
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,9 @@ void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||||
|
|
||||||
wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->vecSize.x, .height = PMONITOR->vecSize.y};
|
CBox box = {PMONITOR->vecPosition.x - pHyprPopup->lx, PMONITOR->vecPosition.y - pHyprPopup->ly, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||||
|
|
||||||
wlr_xdg_popup_unconstrain_from_box(popup, &box);
|
wlr_xdg_popup_unconstrain_from_box(popup, box.pWlr());
|
||||||
|
|
||||||
pHyprPopup->monitor = PMONITOR;
|
pHyprPopup->monitor = PMONITOR;
|
||||||
|
|
||||||
|
@ -159,13 +159,16 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||||
|
|
||||||
wlr_box extents;
|
CBox extents;
|
||||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||||
|
extents.applyFromWlr();
|
||||||
|
|
||||||
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
||||||
|
|
||||||
if (PPOPUP->monitor)
|
if (PPOPUP->monitor) {
|
||||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale);
|
g_pCompositor->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale);
|
||||||
|
g_pCompositor->setPreferredTransformForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->transform);
|
||||||
|
}
|
||||||
|
|
||||||
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree);
|
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree);
|
||||||
}
|
}
|
||||||
|
@ -178,11 +181,18 @@ void Events::listener_repositionPopupXDG(void* owner, void* data) {
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||||
|
|
||||||
wlr_box extents;
|
CBox extents;
|
||||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||||
|
extents.applyFromWlr();
|
||||||
|
|
||||||
PPOPUP->lastPos = {lx - extents.x, ly - extents.y};
|
PPOPUP->lastPos = {lx - extents.x, ly - extents.y};
|
||||||
PPOPUP->repositionRequested = true;
|
PPOPUP->repositionRequested = true;
|
||||||
|
|
||||||
|
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||||
|
|
||||||
|
CBox box = {PMONITOR->vecPosition.x - lx + PPOPUP->popup->current.geometry.x, PMONITOR->vecPosition.y - ly + PPOPUP->popup->current.geometry.y, PMONITOR->vecSize.x,
|
||||||
|
PMONITOR->vecSize.y};
|
||||||
|
wlr_xdg_popup_unconstrain_from_box(PPOPUP->popup, box.pWlr());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
||||||
|
@ -199,8 +209,9 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||||
|
|
||||||
wlr_box extents;
|
CBox extents;
|
||||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||||
|
extents.applyFromWlr();
|
||||||
|
|
||||||
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
||||||
|
|
||||||
|
@ -225,8 +236,9 @@ void Events::listener_commitPopupXDG(void* owner, void* data) {
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||||
|
|
||||||
wlr_box extents;
|
CBox extents;
|
||||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||||
|
extents.applyFromWlr();
|
||||||
|
|
||||||
if (PPOPUP->repositionRequested)
|
if (PPOPUP->repositionRequested)
|
||||||
g_pHyprRenderer->damageBox(PPOPUP->lastPos.x, PPOPUP->lastPos.y, extents.width + 2, extents.height + 2);
|
g_pHyprRenderer->damageBox(PPOPUP->lastPos.x, PPOPUP->lastPos.y, extents.width + 2, extents.height + 2);
|
||||||
|
|
|
@ -46,12 +46,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
static auto* const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
|
static auto* const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
|
||||||
static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
|
static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
|
||||||
static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex")->strValue;
|
static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex")->strValue;
|
||||||
|
static auto* const PNEWTAKESOVERFS = &g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen")->intValue;
|
||||||
|
|
||||||
auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||||
const auto PWORKSPACE =
|
const auto PWORKSPACE =
|
||||||
PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||||
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||||
PWINDOW->m_bMappedX11 = true;
|
|
||||||
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
||||||
PWINDOW->m_bIsMapped = true;
|
PWINDOW->m_bIsMapped = true;
|
||||||
PWINDOW->m_bReadyToDelete = false;
|
PWINDOW->m_bReadyToDelete = false;
|
||||||
|
@ -95,7 +95,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
|
|
||||||
if (PWORKSPACE->m_bDefaultPseudo) {
|
if (PWORKSPACE->m_bDefaultPseudo) {
|
||||||
PWINDOW->m_bIsPseudotiled = true;
|
PWINDOW->m_bIsPseudotiled = true;
|
||||||
wlr_box desiredGeometry = {0};
|
CBox desiredGeometry = {0};
|
||||||
g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry);
|
g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry);
|
||||||
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
|
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW);
|
PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW);
|
||||||
|
|
||||||
for (auto& r : WINDOWRULES) {
|
for (auto& r : WINDOWRULES) {
|
||||||
if (r.szRule.find("monitor") == 0) {
|
if (r.szRule.starts_with("monitor")) {
|
||||||
try {
|
try {
|
||||||
const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' ')));
|
const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' ')));
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
|
|
||||||
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
|
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
|
||||||
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
|
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
|
||||||
} else if (r.szRule.find("workspace") == 0) {
|
} else if (r.szRule.starts_with("workspace")) {
|
||||||
// check if it isnt unset
|
// check if it isnt unset
|
||||||
const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||||
|
|
||||||
|
@ -166,19 +166,19 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
requestedWorkspace = "";
|
requestedWorkspace = "";
|
||||||
|
|
||||||
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r.szValue);
|
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r.szValue);
|
||||||
} else if (r.szRule.find("float") == 0) {
|
} else if (r.szRule.starts_with("float")) {
|
||||||
PWINDOW->m_bIsFloating = true;
|
PWINDOW->m_bIsFloating = true;
|
||||||
} else if (r.szRule.find("tile") == 0) {
|
} else if (r.szRule.starts_with("tile")) {
|
||||||
PWINDOW->m_bIsFloating = false;
|
PWINDOW->m_bIsFloating = false;
|
||||||
} else if (r.szRule.find("pseudo") == 0) {
|
} else if (r.szRule.starts_with("pseudo")) {
|
||||||
PWINDOW->m_bIsPseudotiled = true;
|
PWINDOW->m_bIsPseudotiled = true;
|
||||||
} else if (r.szRule.find("nofocus") == 0) {
|
} else if (r.szRule.starts_with("nofocus")) {
|
||||||
PWINDOW->m_bNoFocus = true;
|
PWINDOW->m_bNoFocus = true;
|
||||||
} else if (r.szRule.find("noinitialfocus") == 0) {
|
} else if (r.szRule.starts_with("noinitialfocus")) {
|
||||||
PWINDOW->m_bNoInitialFocus = true;
|
PWINDOW->m_bNoInitialFocus = true;
|
||||||
} else if (r.szRule.find("nofullscreenrequest") == 0) {
|
} else if (r.szRule.starts_with("nofullscreenrequest")) {
|
||||||
PWINDOW->m_bNoFullscreenRequest = true;
|
PWINDOW->m_bNoFullscreenRequest = true;
|
||||||
} else if (r.szRule.find("nomaximizerequest") == 0) {
|
} else if (r.szRule.starts_with("nomaximizerequest")) {
|
||||||
PWINDOW->m_bNoMaximizeRequest = true;
|
PWINDOW->m_bNoMaximizeRequest = true;
|
||||||
} else if (r.szRule == "fullscreen") {
|
} else if (r.szRule == "fullscreen") {
|
||||||
requestsFullscreen = true;
|
requestsFullscreen = true;
|
||||||
|
@ -198,7 +198,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
overridingNoMaximize = true;
|
overridingNoMaximize = true;
|
||||||
} else if (r.szRule == "stayfocused") {
|
} else if (r.szRule == "stayfocused") {
|
||||||
PWINDOW->m_bStayFocused = true;
|
PWINDOW->m_bStayFocused = true;
|
||||||
} else if (r.szRule.find("group") == 0) {
|
} else if (r.szRule.starts_with("group")) {
|
||||||
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
|
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -245,31 +245,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
}
|
}
|
||||||
vPrev = v;
|
vPrev = v;
|
||||||
}
|
}
|
||||||
} else if (r.szRule.find("idleinhibit") == 0) {
|
|
||||||
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);
|
PWINDOW->applyDynamicRule(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
CWindow* pFullscreenWindow = nullptr;
|
|
||||||
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) {
|
|
||||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
|
||||||
pFullscreenWindow = PFULLWINDOW;
|
|
||||||
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, PWORKSPACE->m_efFullscreenMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
PWINDOW->updateSpecialRenderData();
|
PWINDOW->updateSpecialRenderData();
|
||||||
|
|
||||||
// disallow tiled pinned
|
// disallow tiled pinned
|
||||||
|
@ -279,13 +258,13 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
const CVarList WORKSPACEARGS = CVarList(requestedWorkspace, 0, ' ');
|
const CVarList WORKSPACEARGS = CVarList(requestedWorkspace, 0, ' ');
|
||||||
|
|
||||||
if (!WORKSPACEARGS[0].empty()) {
|
if (!WORKSPACEARGS[0].empty()) {
|
||||||
if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].find("silent") == 0)
|
if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].starts_with("silent"))
|
||||||
workspaceSilent = true;
|
workspaceSilent = true;
|
||||||
|
|
||||||
std::string requestedWorkspaceName;
|
std::string requestedWorkspaceName;
|
||||||
const int REQUESTEDWORKSPACEID = getWorkspaceIDFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0), 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);
|
auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID);
|
||||||
|
|
||||||
if (!pWorkspace)
|
if (!pWorkspace)
|
||||||
|
@ -315,7 +294,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
|
|
||||||
// size and move rules
|
// size and move rules
|
||||||
for (auto& r : WINDOWRULES) {
|
for (auto& r : WINDOWRULES) {
|
||||||
if (r.szRule.find("size") == 0) {
|
if (r.szRule.starts_with("size")) {
|
||||||
try {
|
try {
|
||||||
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
||||||
|
@ -337,7 +316,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
|
|
||||||
PWINDOW->setHidden(false);
|
PWINDOW->setHidden(false);
|
||||||
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
|
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||||
} else if (r.szRule.find("minsize") == 0) {
|
} else if (r.szRule.starts_with("minsize")) {
|
||||||
try {
|
try {
|
||||||
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
||||||
|
@ -351,7 +330,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
|
|
||||||
PWINDOW->setHidden(false);
|
PWINDOW->setHidden(false);
|
||||||
} catch (...) { Debug::log(LOG, "Rule minsize failed, rule: {} -> {}", r.szRule, r.szValue); }
|
} catch (...) { Debug::log(LOG, "Rule minsize failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||||
} else if (r.szRule.find("maxsize") == 0) {
|
} else if (r.szRule.starts_with("maxsize")) {
|
||||||
try {
|
try {
|
||||||
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
||||||
|
@ -365,16 +344,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
|
|
||||||
PWINDOW->setHidden(false);
|
PWINDOW->setHidden(false);
|
||||||
} catch (...) { Debug::log(LOG, "Rule maxsize failed, rule: {} -> {}", r.szRule, r.szValue); }
|
} catch (...) { Debug::log(LOG, "Rule maxsize failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||||
} else if (r.szRule.find("move") == 0) {
|
} else if (r.szRule.starts_with("move")) {
|
||||||
try {
|
try {
|
||||||
auto value = r.szRule.substr(r.szRule.find(' ') + 1);
|
auto value = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||||
|
|
||||||
const bool ONSCREEN = value.find("onscreen") == 0;
|
const bool ONSCREEN = value.starts_with("onscreen");
|
||||||
|
|
||||||
if (ONSCREEN)
|
if (ONSCREEN)
|
||||||
value = value.substr(value.find_first_of(' ') + 1);
|
value = value.substr(value.find_first_of(' ') + 1);
|
||||||
|
|
||||||
const bool CURSOR = value.find("cursor") == 0;
|
const bool CURSOR = value.starts_with("cursor");
|
||||||
|
|
||||||
if (CURSOR)
|
if (CURSOR)
|
||||||
value = value.substr(value.find_first_of(' ') + 1);
|
value = value.substr(value.find_first_of(' ') + 1);
|
||||||
|
@ -385,7 +364,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
int posX = 0;
|
int posX = 0;
|
||||||
int posY = 0;
|
int posY = 0;
|
||||||
|
|
||||||
if (POSXSTR.find("100%-") == 0) {
|
if (POSXSTR.starts_with("100%-")) {
|
||||||
const auto POSXRAW = POSXSTR.substr(5);
|
const auto POSXRAW = POSXSTR.substr(5);
|
||||||
posX =
|
posX =
|
||||||
PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
|
PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
|
||||||
|
@ -404,7 +383,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (POSYSTR.find("100%-") == 0) {
|
if (POSYSTR.starts_with("100%-")) {
|
||||||
const auto POSYRAW = POSYSTR.substr(5);
|
const auto POSYRAW = POSYSTR.substr(5);
|
||||||
posY =
|
posY =
|
||||||
PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
|
PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
|
||||||
|
@ -439,7 +418,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
|
|
||||||
PWINDOW->setHidden(false);
|
PWINDOW->setHidden(false);
|
||||||
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r.szRule, r.szValue); }
|
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||||
} else if (r.szRule.find("center") == 0) {
|
} else if (r.szRule.starts_with("center")) {
|
||||||
auto RESERVEDOFFSET = Vector2D();
|
auto RESERVEDOFFSET = Vector2D();
|
||||||
const auto ARGS = CVarList(r.szRule, 2, ' ');
|
const auto ARGS = CVarList(r.szRule, 2, ' ');
|
||||||
if (ARGS[1] == "1")
|
if (ARGS[1] == "1")
|
||||||
|
@ -474,6 +453,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
|
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
|
||||||
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
|
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
|
||||||
PWINDOW->m_bNoInitialFocus = true;
|
PWINDOW->m_bNoInitialFocus = true;
|
||||||
|
if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
|
||||||
|
if (*PNEWTAKESOVERFS == 0)
|
||||||
|
PWINDOW->m_bNoInitialFocus = true;
|
||||||
|
else if (*PNEWTAKESOVERFS == 2)
|
||||||
|
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID);
|
||||||
|
else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
|
||||||
|
requestsMaximize = true;
|
||||||
|
else
|
||||||
|
requestsFullscreen = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus &&
|
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus &&
|
||||||
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
|
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
|
||||||
|
@ -489,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);
|
Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree);
|
||||||
|
|
||||||
if (!PWINDOW->m_bIsX11) {
|
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_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_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,
|
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW,
|
||||||
|
@ -500,6 +488,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
PWINDOW->hyprListener_requestResize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_resize, &Events::listener_requestResize, PWINDOW, "XDG Window Late");
|
PWINDOW->hyprListener_requestResize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_resize, &Events::listener_requestResize, PWINDOW, "XDG Window Late");
|
||||||
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW,
|
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW,
|
||||||
"XDG Window Late");
|
"XDG Window Late");
|
||||||
|
PWINDOW->hyprListener_ackConfigure.initCallback(&PWINDOW->m_uSurface.xdg->events.ack_configure, &Events::listener_ackConfigure, PWINDOW, "XDG Window Late");
|
||||||
} else {
|
} else {
|
||||||
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW,
|
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW,
|
||||||
"XWayland Window Late");
|
"XWayland Window Late");
|
||||||
|
@ -515,14 +504,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
"XWayland Window Late");
|
"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)) ||
|
if ((requestsFullscreen && (!PWINDOW->m_bNoFullscreenRequest || overridingNoFullscreen)) || (requestsMaximize && (!PWINDOW->m_bNoMaximizeRequest || overridingNoMaximize)) ||
|
||||||
requestsFakeFullscreen) {
|
requestsFakeFullscreen) {
|
||||||
// fix fullscreen on requested (basically do a switcheroo)
|
// fix fullscreen on requested (basically do a switcheroo)
|
||||||
|
@ -543,10 +524,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pFullscreenWindow && workspaceSilent) {
|
|
||||||
g_pCompositor->setWindowFullscreen(pFullscreenWindow, true, PWORKSPACE->m_efFullscreenMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// recheck idle inhibitors
|
// recheck idle inhibitors
|
||||||
g_pInputManager->recheckIdleInhibitorStatus();
|
g_pInputManager->recheckIdleInhibitorStatus();
|
||||||
|
|
||||||
|
@ -640,10 +617,34 @@ 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)});
|
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, g_pXWaylandManager->getAppIDClass(PWINDOW), PWINDOW->m_szTitle)});
|
||||||
EMIT_HOOK_EVENT("openWindow", PWINDOW);
|
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
|
// recalc the values for this window
|
||||||
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
||||||
|
// avoid this window being visible
|
||||||
|
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating)
|
||||||
|
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
|
||||||
|
|
||||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
|
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
|
||||||
|
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
|
||||||
|
|
||||||
|
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) {
|
void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
|
@ -657,6 +658,13 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||||
|
if (PMONITOR) {
|
||||||
|
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
|
||||||
|
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
|
||||||
|
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
|
||||||
|
}
|
||||||
|
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
|
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
|
||||||
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
|
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
|
||||||
|
|
||||||
|
@ -664,7 +672,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
|
|
||||||
if (!PWINDOW->m_bIsX11) {
|
if (!PWINDOW->m_bIsX11) {
|
||||||
Debug::log(LOG, "Unregistered late callbacks XDG");
|
Debug::log(LOG, "Unregistered late callbacks XDG");
|
||||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
|
||||||
PWINDOW->hyprListener_setTitleWindow.removeCallback();
|
PWINDOW->hyprListener_setTitleWindow.removeCallback();
|
||||||
PWINDOW->hyprListener_newPopupXDG.removeCallback();
|
PWINDOW->hyprListener_newPopupXDG.removeCallback();
|
||||||
PWINDOW->hyprListener_requestMaximize.removeCallback();
|
PWINDOW->hyprListener_requestMaximize.removeCallback();
|
||||||
|
@ -672,6 +679,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
PWINDOW->hyprListener_requestMove.removeCallback();
|
PWINDOW->hyprListener_requestMove.removeCallback();
|
||||||
PWINDOW->hyprListener_requestResize.removeCallback();
|
PWINDOW->hyprListener_requestResize.removeCallback();
|
||||||
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
|
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
|
||||||
|
PWINDOW->hyprListener_ackConfigure.removeCallback();
|
||||||
} else {
|
} else {
|
||||||
Debug::log(LOG, "Unregistered late callbacks XWL");
|
Debug::log(LOG, "Unregistered late callbacks XWL");
|
||||||
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
|
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
|
||||||
|
@ -685,13 +693,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
if (PWINDOW->m_bIsFullscreen)
|
if (PWINDOW->m_bIsFullscreen)
|
||||||
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
|
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
|
||||||
if (PMONITOR) {
|
|
||||||
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
|
|
||||||
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
|
|
||||||
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow the renderer to catch the last frame.
|
// Allow the renderer to catch the last frame.
|
||||||
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
|
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
|
||||||
|
|
||||||
|
@ -712,8 +713,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
g_pInputManager->releaseAllMouseButtons();
|
g_pInputManager->releaseAllMouseButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
PWINDOW->m_bMappedX11 = false;
|
|
||||||
|
|
||||||
// remove the fullscreen window status from workspace if we closed it
|
// remove the fullscreen window status from workspace if we closed it
|
||||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
|
||||||
|
|
||||||
|
@ -731,13 +730,16 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
|
|
||||||
Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE);
|
Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE);
|
||||||
|
|
||||||
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow) {
|
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
|
||||||
if (!PWINDOWCANDIDATE)
|
|
||||||
g_pInputManager->simulateMouseMovement();
|
|
||||||
else
|
|
||||||
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
|
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
|
||||||
} else {
|
|
||||||
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) {
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ","});
|
||||||
|
EMIT_HOOK_EVENT("activeWindow", (CWindow*)nullptr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
|
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
|
||||||
|
@ -774,13 +776,32 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
PWINDOW->onUnmap();
|
PWINDOW->onUnmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Events::listener_ackConfigure(void* owner, void* data) {
|
||||||
|
CWindow* PWINDOW = (CWindow*)owner;
|
||||||
|
const auto E = (wlr_xdg_surface_configure*)data;
|
||||||
|
|
||||||
|
// find last matching serial
|
||||||
|
const auto SERIAL = std::find_if(PWINDOW->m_vPendingSizeAcks.rbegin(), PWINDOW->m_vPendingSizeAcks.rend(), [&](const auto& e) { return e.first == E->serial; });
|
||||||
|
|
||||||
|
if (SERIAL == PWINDOW->m_vPendingSizeAcks.rend())
|
||||||
|
return;
|
||||||
|
|
||||||
|
PWINDOW->m_pPendingSizeAck = *SERIAL;
|
||||||
|
std::erase_if(PWINDOW->m_vPendingSizeAcks, [&](const auto& el) { return el.first == SERIAL->first; });
|
||||||
|
}
|
||||||
|
|
||||||
void Events::listener_commitWindow(void* owner, void* data) {
|
void Events::listener_commitWindow(void* owner, void* data) {
|
||||||
CWindow* PWINDOW = (CWindow*)owner;
|
CWindow* PWINDOW = (CWindow*)owner;
|
||||||
|
|
||||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11))
|
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PWINDOW->updateSurfaceOutputs();
|
if (PWINDOW->m_bIsX11)
|
||||||
|
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
|
||||||
|
else if (PWINDOW->m_pPendingSizeAck.has_value()) {
|
||||||
|
PWINDOW->m_vReportedSize = PWINDOW->m_pPendingSizeAck->second;
|
||||||
|
PWINDOW->m_pPendingSizeAck.reset();
|
||||||
|
}
|
||||||
|
|
||||||
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
|
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
|
||||||
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
|
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
|
||||||
|
@ -788,22 +809,29 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||||
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
|
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto ISRIGID = PWINDOW->m_uSurface.xdg->toplevel->current.max_height == PWINDOW->m_uSurface.xdg->toplevel->current.min_height &&
|
const auto MINSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.min_width, 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 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;
|
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)
|
if (MAXSIZE.x < newSize.x)
|
||||||
return;
|
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_vRealPosition = PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0;
|
||||||
PWINDOW->m_vRealSize = REQUESTEDSIZE;
|
PWINDOW->m_vRealSize = newSize;
|
||||||
g_pXWaylandManager->setWindowSize(PWINDOW, REQUESTEDSIZE, true);
|
g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true);
|
||||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,6 +848,7 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||||
g_pCompositor->m_pLastFocus = nullptr;
|
g_pCompositor->m_pLastFocus = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||||
PWINDOW->hyprListener_mapWindow.removeCallback();
|
PWINDOW->hyprListener_mapWindow.removeCallback();
|
||||||
PWINDOW->hyprListener_unmapWindow.removeCallback();
|
PWINDOW->hyprListener_unmapWindow.removeCallback();
|
||||||
PWINDOW->hyprListener_destroyWindow.removeCallback();
|
PWINDOW->hyprListener_destroyWindow.removeCallback();
|
||||||
|
@ -839,8 +868,8 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||||
PWINDOW->m_bReadyToDelete = true;
|
PWINDOW->m_bReadyToDelete = true;
|
||||||
|
|
||||||
if (!PWINDOW->m_bFadingOut) {
|
if (!PWINDOW->m_bFadingOut) {
|
||||||
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
|
|
||||||
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
|
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
|
||||||
|
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -995,8 +1024,10 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||||
|
|
||||||
const auto E = (wlr_xwayland_surface_configure_event*)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);
|
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};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1021,8 +1052,11 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||||
|
|
||||||
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
|
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
|
||||||
if (*PXWLFORCESCALEZERO) {
|
if (*PXWLFORCESCALEZERO) {
|
||||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
|
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
|
||||||
|
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
|
||||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
|
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
|
||||||
|
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
|
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
|
||||||
|
@ -1030,6 +1064,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);
|
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;
|
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
|
||||||
|
|
||||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||||
|
@ -1040,14 +1082,12 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||||
g_pInputManager->refocus();
|
g_pInputManager->refocus();
|
||||||
|
|
||||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||||
|
|
||||||
PWINDOW->updateWindowDecos();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||||
CWindow* PWINDOW = (CWindow*)owner;
|
CWindow* PWINDOW = (CWindow*)owner;
|
||||||
|
|
||||||
if (!PWINDOW->m_bMappedX11)
|
if (!PWINDOW->m_bIsMapped)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto POS = PWINDOW->m_vRealPosition.goalv();
|
const auto POS = PWINDOW->m_vRealPosition.goalv();
|
||||||
|
@ -1080,8 +1120,11 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||||
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height));
|
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height));
|
||||||
|
|
||||||
if (*PXWLFORCESCALEZERO) {
|
if (*PXWLFORCESCALEZERO) {
|
||||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
|
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
|
||||||
|
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
|
||||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
|
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
|
||||||
|
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
|
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
|
||||||
|
@ -1092,6 +1135,10 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||||
PWINDOW->updateWindowDecos();
|
PWINDOW->updateWindowDecos();
|
||||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||||
|
|
||||||
|
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goalv();
|
||||||
|
PWINDOW->m_vReportedSize = PWINDOW->m_vRealSize.goalv();
|
||||||
|
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vReportedSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1107,12 +1154,14 @@ void Events::listener_associateX11(void* owner, void* data) {
|
||||||
const auto PWINDOW = (CWindow*)owner;
|
const auto PWINDOW = (CWindow*)owner;
|
||||||
|
|
||||||
PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW, "XWayland Window");
|
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) {
|
void Events::listener_dissociateX11(void* owner, void* data) {
|
||||||
const auto PWINDOW = (CWindow*)owner;
|
const auto PWINDOW = (CWindow*)owner;
|
||||||
|
|
||||||
PWINDOW->hyprListener_mapWindow.removeCallback();
|
PWINDOW->hyprListener_mapWindow.removeCallback();
|
||||||
|
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
|
void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
|
||||||
|
@ -1137,20 +1186,19 @@ void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
|
||||||
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW, "XWayland Window");
|
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
|
// 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)
|
Debug::log(LOG, "New XDG Toplevel created. (class: {})", XDGSURFACE->toplevel->app_id ? XDGSURFACE->toplevel->app_id : "null");
|
||||||
return;
|
|
||||||
|
|
||||||
Debug::log(LOG, "New XDG Surface 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();
|
const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(std::make_unique<CWindow>()).get();
|
||||||
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
|
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
|
||||||
|
|
||||||
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->surface->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window");
|
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_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) {
|
void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
|
||||||
|
@ -1173,7 +1221,7 @@ void Events::listener_requestMaximize(void* owner, void* data) {
|
||||||
|
|
||||||
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
|
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
|
||||||
} else {
|
} else {
|
||||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
|
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED);
|
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED);
|
||||||
|
@ -1186,7 +1234,7 @@ void Events::listener_requestMinimize(void* owner, void* data) {
|
||||||
Debug::log(LOG, "Minimize request for {}", PWINDOW);
|
Debug::log(LOG, "Minimize request for {}", PWINDOW);
|
||||||
|
|
||||||
if (PWINDOW->m_bIsX11) {
|
if (PWINDOW->m_bIsX11) {
|
||||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
|
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto E = (wlr_xwayland_minimize_event*)data;
|
const auto E = (wlr_xwayland_minimize_event*)data;
|
||||||
|
|
|
@ -6,17 +6,16 @@
|
||||||
#include "Vector2D.hpp"
|
#include "Vector2D.hpp"
|
||||||
#include "Color.hpp"
|
#include "Color.hpp"
|
||||||
#include "../macros.hpp"
|
#include "../macros.hpp"
|
||||||
|
#include "../debug/Log.hpp"
|
||||||
|
|
||||||
enum ANIMATEDVARTYPE
|
enum ANIMATEDVARTYPE {
|
||||||
{
|
|
||||||
AVARTYPE_INVALID = -1,
|
AVARTYPE_INVALID = -1,
|
||||||
AVARTYPE_FLOAT,
|
AVARTYPE_FLOAT,
|
||||||
AVARTYPE_VECTOR,
|
AVARTYPE_VECTOR,
|
||||||
AVARTYPE_COLOR
|
AVARTYPE_COLOR
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AVARDAMAGEPOLICY
|
enum AVARDAMAGEPOLICY {
|
||||||
{
|
|
||||||
AVARDAMAGE_NONE = -1,
|
AVARDAMAGE_NONE = -1,
|
||||||
AVARDAMAGE_ENTIRE = 0,
|
AVARDAMAGE_ENTIRE = 0,
|
||||||
AVARDAMAGE_BORDER,
|
AVARDAMAGE_BORDER,
|
||||||
|
|
129
src/helpers/Box.cpp
Normal file
129
src/helpers/Box.cpp
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#include "Box.hpp"
|
||||||
|
wlr_box CBox::wlr() {
|
||||||
|
CBox rounded = roundInternal();
|
||||||
|
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
|
||||||
|
return m_bWlrBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_box* CBox::pWlr() {
|
||||||
|
CBox rounded = roundInternal();
|
||||||
|
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
|
||||||
|
return &m_bWlrBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox& CBox::scale(double scale) {
|
||||||
|
x *= scale;
|
||||||
|
y *= scale;
|
||||||
|
w *= scale;
|
||||||
|
h *= scale;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox& CBox::scale(const Vector2D& scale) {
|
||||||
|
x *= scale.x;
|
||||||
|
y *= scale.y;
|
||||||
|
w *= scale.x;
|
||||||
|
h *= scale.y;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox& CBox::translate(const Vector2D& vec) {
|
||||||
|
x += vec.x;
|
||||||
|
y += vec.y;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2D CBox::middle() const {
|
||||||
|
return Vector2D{x + w / 2.0, y + h / 2.0};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CBox::containsPoint(const Vector2D& vec) const {
|
||||||
|
return VECINRECT(vec, x, y, x + w, y + h);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CBox::empty() const {
|
||||||
|
return w == 0 || h == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox& CBox::applyFromWlr() {
|
||||||
|
x = m_bWlrBox.x;
|
||||||
|
y = m_bWlrBox.y;
|
||||||
|
w = m_bWlrBox.width;
|
||||||
|
h = m_bWlrBox.height;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox& CBox::round() {
|
||||||
|
float newW = x + w - std::round(x);
|
||||||
|
float newH = y + h - std::round(y);
|
||||||
|
x = std::round(x);
|
||||||
|
y = std::round(y);
|
||||||
|
w = std::round(newW);
|
||||||
|
h = std::round(newH);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox& CBox::transform(const wl_output_transform t, double w, double h) {
|
||||||
|
wlr_box_transform(&m_bWlrBox, pWlr(), t, w, h);
|
||||||
|
applyFromWlr();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox& CBox::addExtents(const SWindowDecorationExtents& e) {
|
||||||
|
x -= e.topLeft.x;
|
||||||
|
y -= e.topLeft.y;
|
||||||
|
w += e.topLeft.x + e.bottomRight.x;
|
||||||
|
h += e.topLeft.y + e.bottomRight.y;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox& CBox::scaleFromCenter(double scale) {
|
||||||
|
double oldW = w, oldH = h;
|
||||||
|
|
||||||
|
w *= scale;
|
||||||
|
h *= scale;
|
||||||
|
|
||||||
|
x -= (w - oldW) / 2.0;
|
||||||
|
y -= (h - oldH) / 2.0;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox& CBox::expand(const double& value) {
|
||||||
|
x -= value;
|
||||||
|
y -= value;
|
||||||
|
w += value * 2.0;
|
||||||
|
h += value * 2.0;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox CBox::roundInternal() {
|
||||||
|
float newW = x + w - std::floor(x);
|
||||||
|
float newH = y + h - std::floor(y);
|
||||||
|
|
||||||
|
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};
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2D CBox::size() const {
|
||||||
|
return {w, h};
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowDecorationExtents CBox::extentsFrom(const CBox& small) {
|
||||||
|
return {{small.x - x, small.y - y}, {w - small.w - (small.x - x), h - small.h - (small.y - y)}};
|
||||||
|
}
|
87
src/helpers/Box.hpp
Normal file
87
src/helpers/Box.hpp
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Vector2D.hpp"
|
||||||
|
#include "../SharedDefs.hpp"
|
||||||
|
#include "../includes.hpp"
|
||||||
|
|
||||||
|
class CBox {
|
||||||
|
public:
|
||||||
|
CBox(double x_, double y_, double w_, double h_) {
|
||||||
|
x = x_;
|
||||||
|
y = y_;
|
||||||
|
w = w_;
|
||||||
|
h = h_;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox() {
|
||||||
|
w = 0;
|
||||||
|
h = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox(const wlr_box& box) {
|
||||||
|
x = box.x;
|
||||||
|
y = box.y;
|
||||||
|
w = box.width;
|
||||||
|
h = box.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox(const double d) {
|
||||||
|
x = d;
|
||||||
|
y = d;
|
||||||
|
w = d;
|
||||||
|
h = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox(const Vector2D& pos, const Vector2D& size) {
|
||||||
|
x = pos.x;
|
||||||
|
y = pos.y;
|
||||||
|
w = size.x;
|
||||||
|
h = size.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_box wlr();
|
||||||
|
wlr_box* pWlr();
|
||||||
|
|
||||||
|
CBox& applyFromWlr();
|
||||||
|
CBox& scale(double scale);
|
||||||
|
CBox& scaleFromCenter(double scale);
|
||||||
|
CBox& scale(const Vector2D& scale);
|
||||||
|
CBox& translate(const Vector2D& vec);
|
||||||
|
CBox& round();
|
||||||
|
CBox& transform(const wl_output_transform t, double w, double h);
|
||||||
|
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;
|
||||||
|
Vector2D pos() const;
|
||||||
|
Vector2D size() const;
|
||||||
|
|
||||||
|
bool containsPoint(const Vector2D& vec) const;
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
double x = 0, y = 0;
|
||||||
|
union {
|
||||||
|
double w;
|
||||||
|
double width;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
double h;
|
||||||
|
double height;
|
||||||
|
};
|
||||||
|
|
||||||
|
double rot = 0; /* rad, ccw */
|
||||||
|
|
||||||
|
//
|
||||||
|
bool operator==(const CBox& rhs) const {
|
||||||
|
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CBox roundInternal();
|
||||||
|
|
||||||
|
wlr_box m_bWlrBox;
|
||||||
|
};
|
|
@ -5,7 +5,7 @@
|
||||||
class CColor {
|
class CColor {
|
||||||
public:
|
public:
|
||||||
CColor();
|
CColor();
|
||||||
CColor(float, float, float, float);
|
CColor(float r, float g, float b, float a);
|
||||||
CColor(uint64_t);
|
CColor(uint64_t);
|
||||||
|
|
||||||
float r = 0, g = 0, b = 0, a = 1.f;
|
float r = 0, g = 0, b = 0, a = 1.f;
|
||||||
|
@ -27,4 +27,8 @@ class CColor {
|
||||||
bool operator==(const CColor& c2) const {
|
bool operator==(const CColor& c2) const {
|
||||||
return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
|
return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CColor stripA() const {
|
||||||
|
return {r, g, b, 1};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,11 +2,14 @@
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "../Compositor.hpp"
|
#include "../Compositor.hpp"
|
||||||
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#ifdef HAS_EXECINFO
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
|
@ -182,13 +185,6 @@ std::string escapeJSONStrings(const std::string& str) {
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void scaleBox(wlr_box* box, float scale) {
|
|
||||||
box->width = std::round(box->width * scale);
|
|
||||||
box->height = std::round(box->height * scale);
|
|
||||||
box->x = std::round(box->x * scale);
|
|
||||||
box->y = std::round(box->y * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string removeBeginEndSpacesTabs(std::string str) {
|
std::string removeBeginEndSpacesTabs(std::string str) {
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
return str;
|
return str;
|
||||||
|
@ -208,12 +204,12 @@ std::string removeBeginEndSpacesTabs(std::string str) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getPlusMinusKeywordResult(std::string source, float relative) {
|
std::optional<float> getPlusMinusKeywordResult(std::string source, float relative) {
|
||||||
try {
|
try {
|
||||||
return relative + stof(source);
|
return relative + stof(source);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
Debug::log(ERR, "Invalid arg \"{}\" in getPlusMinusKeywordResult!", source);
|
Debug::log(ERR, "Invalid arg \"{}\" in getPlusMinusKeywordResult!", source);
|
||||||
return INT_MAX;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,9 +242,13 @@ bool isDirection(const std::string& arg) {
|
||||||
return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b";
|
return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isDirection(const char& arg) {
|
||||||
|
return arg == 'l' || arg == 'r' || arg == 'u' || arg == 'd' || arg == 't' || arg == 'b';
|
||||||
|
}
|
||||||
|
|
||||||
int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||||
int result = INT_MAX;
|
int result = WORKSPACE_INVALID;
|
||||||
if (in.find("special") == 0) {
|
if (in.starts_with("special")) {
|
||||||
outName = "special";
|
outName = "special";
|
||||||
|
|
||||||
if (in.length() > 8) {
|
if (in.length() > 8) {
|
||||||
|
@ -262,7 +262,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return SPECIAL_WORKSPACE_START;
|
return SPECIAL_WORKSPACE_START;
|
||||||
} else if (in.find("name:") == 0) {
|
} else if (in.starts_with("name:")) {
|
||||||
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
|
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
|
||||||
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
|
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
|
||||||
if (!WORKSPACE) {
|
if (!WORKSPACE) {
|
||||||
|
@ -271,26 +271,26 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||||
result = WORKSPACE->m_iID;
|
result = WORKSPACE->m_iID;
|
||||||
}
|
}
|
||||||
outName = WORKSPACENAME;
|
outName = WORKSPACENAME;
|
||||||
} else if (in.find("empty") == 0) {
|
} else if (in.starts_with("empty")) {
|
||||||
int id = 0;
|
int id = 0;
|
||||||
while (++id < INT_MAX) {
|
while (++id < INT_MAX) {
|
||||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
|
||||||
if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0))
|
if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0))
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
} else if (in.find("prev") == 0) {
|
} else if (in.starts_with("prev")) {
|
||||||
if (!g_pCompositor->m_pLastMonitor)
|
if (!g_pCompositor->m_pLastMonitor)
|
||||||
return INT_MAX;
|
return WORKSPACE_INVALID;
|
||||||
|
|
||||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
|
||||||
|
|
||||||
if (!PWORKSPACE)
|
if (!PWORKSPACE)
|
||||||
return INT_MAX;
|
return WORKSPACE_INVALID;
|
||||||
|
|
||||||
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.iID);
|
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.iID);
|
||||||
|
|
||||||
if (!PLASTWORKSPACE)
|
if (!PLASTWORKSPACE)
|
||||||
return INT_MAX;
|
return WORKSPACE_INVALID;
|
||||||
|
|
||||||
outName = PLASTWORKSPACE->m_szName;
|
outName = PLASTWORKSPACE->m_szName;
|
||||||
return PLASTWORKSPACE->m_iID;
|
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 (in[0] == 'r' && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||||
if (!g_pCompositor->m_pLastMonitor) {
|
if (!g_pCompositor->m_pLastMonitor) {
|
||||||
Debug::log(ERR, "Relative monitor workspace on monitor null!");
|
Debug::log(ERR, "Relative monitor workspace on monitor null!");
|
||||||
result = INT_MAX;
|
return WORKSPACE_INVALID;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
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;
|
int remains = (int)result;
|
||||||
|
|
||||||
|
@ -389,12 +394,12 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||||
int beginID = finalWSID;
|
int beginID = finalWSID;
|
||||||
int curID = finalWSID;
|
int curID = finalWSID;
|
||||||
while (--curID > 0 && remainingWSes > 0) {
|
while (--curID > 0 && remainingWSes > 0) {
|
||||||
if (invalidWSes.find(curID) == invalidWSes.end()) {
|
if (!invalidWSes.contains(curID)) {
|
||||||
remainingWSes--;
|
remainingWSes--;
|
||||||
}
|
}
|
||||||
finalWSID = curID;
|
finalWSID = curID;
|
||||||
}
|
}
|
||||||
if (finalWSID <= 0 || invalidWSes.find(finalWSID) != invalidWSes.end()) {
|
if (finalWSID <= 0 || invalidWSes.contains(finalWSID)) {
|
||||||
if (namedWSes.size()) {
|
if (namedWSes.size()) {
|
||||||
// Go to the named workspaces
|
// Go to the named workspaces
|
||||||
// Need remainingWSes more
|
// Need remainingWSes more
|
||||||
|
@ -414,7 +419,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||||
if (walkDir == '+') {
|
if (walkDir == '+') {
|
||||||
int curID = finalWSID;
|
int curID = finalWSID;
|
||||||
while (++curID < INT32_MAX && remainingWSes > 0) {
|
while (++curID < INT32_MAX && remainingWSes > 0) {
|
||||||
if (invalidWSes.find(curID) == invalidWSes.end()) {
|
if (!invalidWSes.contains(curID)) {
|
||||||
remainingWSes--;
|
remainingWSes--;
|
||||||
}
|
}
|
||||||
finalWSID = curID;
|
finalWSID = curID;
|
||||||
|
@ -433,12 +438,16 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||||
|
|
||||||
if (!g_pCompositor->m_pLastMonitor) {
|
if (!g_pCompositor->m_pLastMonitor) {
|
||||||
Debug::log(ERR, "Relative monitor workspace on monitor null!");
|
Debug::log(ERR, "Relative monitor workspace on monitor null!");
|
||||||
result = INT_MAX;
|
return WORKSPACE_INVALID;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// monitor relative
|
// 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
|
// result now has +/- what we should move on mon
|
||||||
int remains = (int)result;
|
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;
|
outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName;
|
||||||
} else {
|
} else {
|
||||||
if (in[0] == '+' || in[0] == '-') {
|
if (in[0] == '+' || in[0] == '-') {
|
||||||
if (g_pCompositor->m_pLastMonitor)
|
if (g_pCompositor->m_pLastMonitor) {
|
||||||
result = std::max((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1);
|
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace);
|
||||||
else {
|
if (!PLUSMINUSRESULT.has_value())
|
||||||
|
return WORKSPACE_INVALID;
|
||||||
|
|
||||||
|
result = std::max((int)PLUSMINUSRESULT.value(), 1);
|
||||||
|
} else {
|
||||||
Debug::log(ERR, "Relative workspace on no mon!");
|
Debug::log(ERR, "Relative workspace on no mon!");
|
||||||
result = INT_MAX;
|
return WORKSPACE_INVALID;
|
||||||
}
|
}
|
||||||
} else if (isNumber(in))
|
} else if (isNumber(in))
|
||||||
result = std::max(std::stoi(in), 1);
|
result = std::max(std::stoi(in), 1);
|
||||||
|
@ -501,6 +514,43 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> cleanCmdForWorkspace(const std::string& inWorkspaceName, std::string dirtyCmd) {
|
||||||
|
|
||||||
|
std::string cmd = removeBeginEndSpacesTabs(dirtyCmd);
|
||||||
|
|
||||||
|
if (!cmd.empty()) {
|
||||||
|
std::string rules;
|
||||||
|
const std::string workspaceRule = "workspace " + inWorkspaceName;
|
||||||
|
|
||||||
|
if (cmd[0] == '[') {
|
||||||
|
const int closingBracketIdx = cmd.find_last_of(']');
|
||||||
|
auto tmpRules = cmd.substr(1, closingBracketIdx - 1);
|
||||||
|
cmd = cmd.substr(closingBracketIdx + 1);
|
||||||
|
|
||||||
|
auto rulesList = CVarList(tmpRules, 0, ';');
|
||||||
|
|
||||||
|
bool hadWorkspaceRule = false;
|
||||||
|
rulesList.map([&](std::string& rule) {
|
||||||
|
if (rule.find("workspace") == 0) {
|
||||||
|
rule = workspaceRule;
|
||||||
|
hadWorkspaceRule = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hadWorkspaceRule)
|
||||||
|
rulesList.append(workspaceRule);
|
||||||
|
|
||||||
|
rules = "[" + rulesList.join(";") + "]";
|
||||||
|
} else {
|
||||||
|
rules = "[" + workspaceRule + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::optional<std::string>(rules + " " + cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) {
|
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) {
|
||||||
const float DX = std::max({0.0, p1.x - vec.x, vec.x - p2.x});
|
const float DX = std::max({0.0, p1.x - vec.x, vec.x - p2.x});
|
||||||
const float DY = std::max({0.0, p1.y - vec.y, vec.y - p2.y});
|
const float DY = std::max({0.0, p1.y - vec.y, vec.y - p2.y});
|
||||||
|
@ -527,10 +577,10 @@ void logSystemInfo() {
|
||||||
|
|
||||||
uname(&unameInfo);
|
uname(&unameInfo);
|
||||||
|
|
||||||
Debug::log(LOG, "System name: {}", unameInfo.sysname);
|
Debug::log(LOG, "System name: {}", std::string{unameInfo.sysname});
|
||||||
Debug::log(LOG, "Node name: {}", unameInfo.nodename);
|
Debug::log(LOG, "Node name: {}", std::string{unameInfo.nodename});
|
||||||
Debug::log(LOG, "Release: {}", unameInfo.release);
|
Debug::log(LOG, "Release: {}", std::string{unameInfo.release});
|
||||||
Debug::log(LOG, "Version: {}", unameInfo.version);
|
Debug::log(LOG, "Version: {}", std::string{unameInfo.version});
|
||||||
|
|
||||||
Debug::log(NONE, "\n");
|
Debug::log(NONE, "\n");
|
||||||
|
|
||||||
|
@ -626,11 +676,11 @@ int64_t getPPIDof(int64_t pid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t configStringToInt(const std::string& VALUE) {
|
int64_t configStringToInt(const std::string& VALUE) {
|
||||||
if (VALUE.find("0x") == 0) {
|
if (VALUE.starts_with("0x")) {
|
||||||
// Values with 0x are hex
|
// Values with 0x are hex
|
||||||
const auto VALUEWITHOUTHEX = VALUE.substr(2);
|
const auto VALUEWITHOUTHEX = VALUE.substr(2);
|
||||||
return stol(VALUEWITHOUTHEX, nullptr, 16);
|
return stol(VALUEWITHOUTHEX, nullptr, 16);
|
||||||
} else if (VALUE.find("rgba(") == 0 && VALUE.find(')') == VALUE.length() - 1) {
|
} else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) {
|
||||||
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
|
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
|
||||||
|
|
||||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
|
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
|
||||||
|
@ -642,7 +692,7 @@ int64_t configStringToInt(const std::string& VALUE) {
|
||||||
|
|
||||||
// now we need to RGBA -> ARGB. The config holds ARGB only.
|
// now we need to RGBA -> ARGB. The config holds ARGB only.
|
||||||
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
|
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
|
||||||
} else if (VALUE.find("rgb(") == 0 && VALUE.find(')') == VALUE.length() - 1) {
|
} else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) {
|
||||||
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
|
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
|
||||||
|
|
||||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
|
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
|
||||||
|
@ -653,11 +703,15 @@ int64_t configStringToInt(const std::string& VALUE) {
|
||||||
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
|
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
|
||||||
|
|
||||||
return RGB + 0xFF000000; // 0xFF for opaque
|
return RGB + 0xFF000000; // 0xFF for opaque
|
||||||
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
|
} else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
|
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (VALUE.empty() || !isNumber(VALUE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
return std::stoll(VALUE);
|
return std::stoll(VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,6 +743,7 @@ std::string replaceInString(std::string subject, const std::string& search, cons
|
||||||
std::vector<SCallstackFrameInfo> getBacktrace() {
|
std::vector<SCallstackFrameInfo> getBacktrace() {
|
||||||
std::vector<SCallstackFrameInfo> callstack;
|
std::vector<SCallstackFrameInfo> callstack;
|
||||||
|
|
||||||
|
#ifdef HAS_EXECINFO
|
||||||
void* bt[1024];
|
void* bt[1024];
|
||||||
size_t btSize;
|
size_t btSize;
|
||||||
char** btSymbols;
|
char** btSymbols;
|
||||||
|
@ -699,6 +754,9 @@ std::vector<SCallstackFrameInfo> getBacktrace() {
|
||||||
for (size_t i = 0; i < btSize; ++i) {
|
for (size_t i = 0; i < btSize; ++i) {
|
||||||
callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}});
|
callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}});
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
callstack.emplace_back(SCallstackFrameInfo{nullptr, "configuration does not support execinfo.h"});
|
||||||
|
#endif
|
||||||
|
|
||||||
return callstack;
|
return callstack;
|
||||||
}
|
}
|
||||||
|
@ -707,3 +765,37 @@ void throwError(const std::string& err) {
|
||||||
Debug::log(CRIT, "Critical error thrown: {}", err);
|
Debug::log(CRIT, "Critical error thrown: {}", err);
|
||||||
throw std::runtime_error(err);
|
throw std::runtime_error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t drmFormatToGL(uint32_t drm) {
|
||||||
|
switch (drm) {
|
||||||
|
case DRM_FORMAT_XRGB8888:
|
||||||
|
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
|
||||||
|
case DRM_FORMAT_XRGB2101010:
|
||||||
|
case DRM_FORMAT_XBGR2101010:
|
||||||
|
#ifdef GLES2
|
||||||
|
return GL_RGB10_A2_EXT;
|
||||||
|
#else
|
||||||
|
return GL_RGB10_A2;
|
||||||
|
#endif
|
||||||
|
default: return GL_RGBA;
|
||||||
|
}
|
||||||
|
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";
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <wayland-server.h>
|
#include <wayland-server.h>
|
||||||
#include <wlr/util/box.h>
|
#include <wlr/util/box.h>
|
||||||
|
@ -15,22 +16,26 @@ struct SCallstackFrameInfo {
|
||||||
std::string absolutePath(const std::string&, const std::string&);
|
std::string absolutePath(const std::string&, const std::string&);
|
||||||
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
|
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
|
||||||
std::string escapeJSONStrings(const std::string& str);
|
std::string escapeJSONStrings(const std::string& str);
|
||||||
void scaleBox(wlr_box*, float);
|
|
||||||
std::string removeBeginEndSpacesTabs(std::string);
|
std::string removeBeginEndSpacesTabs(std::string);
|
||||||
bool isNumber(const std::string&, bool allowfloat = false);
|
bool isNumber(const std::string&, bool allowfloat = false);
|
||||||
bool isDirection(const std::string&);
|
bool isDirection(const std::string&);
|
||||||
|
bool isDirection(const char&);
|
||||||
int getWorkspaceIDFromString(const std::string&, std::string&);
|
int getWorkspaceIDFromString(const std::string&, std::string&);
|
||||||
|
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
|
||||||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
|
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
|
||||||
void logSystemInfo();
|
void logSystemInfo();
|
||||||
std::string execAndGet(const char*);
|
std::string execAndGet(const char*);
|
||||||
int64_t getPPIDof(int64_t pid);
|
int64_t getPPIDof(int64_t pid);
|
||||||
int64_t configStringToInt(const std::string&);
|
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);
|
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
|
||||||
double normalizeAngleRad(double ang);
|
double normalizeAngleRad(double ang);
|
||||||
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
|
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
|
||||||
std::vector<SCallstackFrameInfo> getBacktrace();
|
std::vector<SCallstackFrameInfo> getBacktrace();
|
||||||
void throwError(const std::string& err);
|
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>
|
template <typename... Args>
|
||||||
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {
|
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
|
|
@ -40,6 +40,8 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
|
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
|
||||||
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this);
|
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this);
|
||||||
|
|
||||||
|
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
|
||||||
|
|
||||||
if (m_bEnabled) {
|
if (m_bEnabled) {
|
||||||
wlr_output_enable(output, 1);
|
wlr_output_enable(output, 1);
|
||||||
wlr_output_commit(output);
|
wlr_output_commit(output);
|
||||||
|
@ -48,6 +50,10 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
|
|
||||||
szName = output->name;
|
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))
|
if (!wlr_backend_is_drm(output->backend))
|
||||||
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
|
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
|
||||||
|
|
||||||
|
@ -107,20 +113,20 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
m_bRenderingInitPassed = true;
|
m_bRenderingInitPassed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_pThisWrap) {
|
std::shared_ptr<CMonitor>* thisWrapper = nullptr;
|
||||||
|
|
||||||
// find the wrap
|
// find the wrap
|
||||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||||
if (m->ID == ID) {
|
if (m->ID == ID) {
|
||||||
m_pThisWrap = &m;
|
thisWrapper = &m;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()) {
|
RASSERT(thisWrapper->get(), "CMonitor::onConnect: Had no wrapper???");
|
||||||
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
|
|
||||||
}
|
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end())
|
||||||
|
g_pCompositor->m_vMonitors.push_back(*thisWrapper);
|
||||||
|
|
||||||
m_bEnabled = true;
|
m_bEnabled = true;
|
||||||
|
|
||||||
|
@ -130,6 +136,8 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
if (!noRule)
|
if (!noRule)
|
||||||
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
|
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
|
||||||
|
|
||||||
|
wlr_output_commit(output);
|
||||||
|
|
||||||
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
|
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
|
||||||
|
|
||||||
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
|
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
|
||||||
|
@ -150,8 +158,6 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
if (scale < 0.1)
|
if (scale < 0.1)
|
||||||
scale = getDefaultScale();
|
scale = getDefaultScale();
|
||||||
|
|
||||||
m_pThisWrap = nullptr;
|
|
||||||
|
|
||||||
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
|
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -182,9 +188,11 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
g_pCompositor->setActiveMonitor(this);
|
g_pCompositor->setActiveMonitor(this);
|
||||||
|
|
||||||
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
|
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
|
||||||
|
|
||||||
|
g_pCompositor->scheduleFrameForMonitor(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMonitor::onDisconnect() {
|
void CMonitor::onDisconnect(bool destroy) {
|
||||||
|
|
||||||
if (renderTimer) {
|
if (renderTimer) {
|
||||||
wl_event_source_remove(renderTimer);
|
wl_event_source_remove(renderTimer);
|
||||||
|
@ -219,9 +227,6 @@ void CMonitor::onDisconnect() {
|
||||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_bEnabled = false;
|
|
||||||
m_bRenderingInitPassed = false;
|
|
||||||
|
|
||||||
hyprListener_monitorFrame.removeCallback();
|
hyprListener_monitorFrame.removeCallback();
|
||||||
hyprListener_monitorDamage.removeCallback();
|
hyprListener_monitorDamage.removeCallback();
|
||||||
hyprListener_monitorNeedsFrame.removeCallback();
|
hyprListener_monitorNeedsFrame.removeCallback();
|
||||||
|
@ -246,6 +251,9 @@ void CMonitor::onDisconnect() {
|
||||||
g_pCompositor->enterUnsafeState();
|
g_pCompositor->enterUnsafeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_bEnabled = false;
|
||||||
|
m_bRenderingInitPassed = false;
|
||||||
|
|
||||||
if (BACKUPMON) {
|
if (BACKUPMON) {
|
||||||
// snap cursor
|
// snap cursor
|
||||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f,
|
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f,
|
||||||
|
@ -254,7 +262,7 @@ void CMonitor::onDisconnect() {
|
||||||
// move workspaces
|
// move workspaces
|
||||||
std::deque<CWorkspace*> wspToMove;
|
std::deque<CWorkspace*> wspToMove;
|
||||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||||
if (w->m_iMonitorID == ID) {
|
if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) {
|
||||||
wspToMove.push_back(w.get());
|
wspToMove.push_back(w.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,6 +280,7 @@ void CMonitor::onDisconnect() {
|
||||||
|
|
||||||
activeWorkspace = -1;
|
activeWorkspace = -1;
|
||||||
|
|
||||||
|
if (!destroy)
|
||||||
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
|
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
|
||||||
|
|
||||||
wlr_output_enable(output, false);
|
wlr_output_enable(output, false);
|
||||||
|
@ -294,7 +303,6 @@ void CMonitor::onDisconnect() {
|
||||||
|
|
||||||
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
|
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
|
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,14 +321,14 @@ void CMonitor::addDamage(const CRegion* rg) {
|
||||||
addDamage(const_cast<CRegion*>(rg)->pixman());
|
addDamage(const_cast<CRegion*>(rg)->pixman());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMonitor::addDamage(const wlr_box* box) {
|
void CMonitor::addDamage(const CBox* box) {
|
||||||
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
|
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
|
||||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
|
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
|
||||||
wlr_damage_ring_add_whole(&damage);
|
wlr_damage_ring_add_whole(&damage);
|
||||||
g_pCompositor->scheduleFrameForMonitor(this);
|
g_pCompositor->scheduleFrameForMonitor(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlr_damage_ring_add_box(&damage, box))
|
if (wlr_damage_ring_add_box(&damage, const_cast<CBox*>(box)->pWlr()))
|
||||||
g_pCompositor->scheduleFrameForMonitor(this);
|
g_pCompositor->scheduleFrameForMonitor(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +357,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
|
||||||
findAvailableDefaultWS() :
|
findAvailableDefaultWS() :
|
||||||
getWorkspaceIDFromString(g_pConfigManager->getDefaultWorkspaceFor(szName), newDefaultWorkspaceName);
|
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;
|
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
|
||||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||||
|
|
||||||
|
@ -412,19 +420,22 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||||
vecPosition = RULE.offset;
|
vecPosition = RULE.offset;
|
||||||
|
|
||||||
// push to mvmonitors
|
// push to mvmonitors
|
||||||
if (!m_pThisWrap) {
|
|
||||||
|
std::shared_ptr<CMonitor>* thisWrapper = nullptr;
|
||||||
|
|
||||||
// find the wrap
|
// find the wrap
|
||||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||||
if (m->ID == ID) {
|
if (m->ID == ID) {
|
||||||
m_pThisWrap = &m;
|
thisWrapper = &m;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
RASSERT(thisWrapper->get(), "CMonitor::setMirror: Had no wrapper???");
|
||||||
|
|
||||||
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) ==
|
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) ==
|
||||||
g_pCompositor->m_vMonitors.end()) {
|
g_pCompositor->m_vMonitors.end()) {
|
||||||
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
|
g_pCompositor->m_vMonitors.push_back(*thisWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
setupDefaultWS(RULE);
|
setupDefaultWS(RULE);
|
||||||
|
@ -491,7 +502,7 @@ float CMonitor::getDefaultScale() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove) {
|
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove, bool noFocus) {
|
||||||
if (!pWorkspace)
|
if (!pWorkspace)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -522,13 +533,11 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!noFocus && !g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
|
||||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||||
|
CWindow* pWindow = pWorkspace->getLastFocusedWindow();
|
||||||
|
|
||||||
if (const auto PLASTWINDOW = pWorkspace->getLastFocusedWindow(); PLASTWINDOW)
|
if (!pWindow) {
|
||||||
g_pCompositor->focusWindow(PLASTWINDOW);
|
|
||||||
else {
|
|
||||||
CWindow* pWindow = nullptr;
|
|
||||||
|
|
||||||
if (*PFOLLOWMOUSE == 1)
|
if (*PFOLLOWMOUSE == 1)
|
||||||
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
|
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
|
||||||
|
|
||||||
|
@ -537,9 +546,11 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
||||||
|
|
||||||
if (!pWindow)
|
if (!pWindow)
|
||||||
pWindow = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
|
pWindow = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
|
||||||
|
}
|
||||||
|
|
||||||
g_pCompositor->focusWindow(pWindow);
|
g_pCompositor->focusWindow(pWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!noMouseMove)
|
if (!noMouseMove)
|
||||||
g_pInputManager->simulateMouseMovement();
|
g_pInputManager->simulateMouseMovement();
|
||||||
|
|
||||||
|
@ -552,6 +563,10 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
||||||
g_pHyprRenderer->damageMonitor(this);
|
g_pHyprRenderer->damageMonitor(this);
|
||||||
|
|
||||||
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
|
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
|
||||||
|
|
||||||
|
g_pConfigManager->ensureVRR(this);
|
||||||
|
|
||||||
|
g_pCompositor->updateSuspendedStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMonitor::changeWorkspace(const int& id, bool internal) {
|
void CMonitor::changeWorkspace(const int& id, bool internal) {
|
||||||
|
@ -577,6 +592,8 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||||
else
|
else
|
||||||
g_pInputManager->refocus();
|
g_pInputManager->refocus();
|
||||||
|
|
||||||
|
g_pCompositor->updateSuspendedStates();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,7 +621,23 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||||
for (auto& w : g_pCompositor->m_vWindows) {
|
for (auto& w : g_pCompositor->m_vWindows) {
|
||||||
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
|
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
|
||||||
w->m_iMonitorID = ID;
|
w->m_iMonitorID = ID;
|
||||||
w->updateSurfaceOutputs();
|
w->updateSurfaceScaleTransformDetails();
|
||||||
|
|
||||||
|
const auto MIDDLE = w->middle();
|
||||||
|
if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) {
|
||||||
|
// if it's floating and the middle isnt on the current mon, move it to the center
|
||||||
|
const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE);
|
||||||
|
Vector2D pos = w->m_vRealPosition.goalv();
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,6 +651,8 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
|
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
|
||||||
|
|
||||||
g_pHyprRenderer->damageMonitor(this);
|
g_pHyprRenderer->damageMonitor(this);
|
||||||
|
|
||||||
|
g_pCompositor->updateSuspendedStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMonitor::setSpecialWorkspace(const int& id) {
|
void CMonitor::setSpecialWorkspace(const int& id) {
|
||||||
|
@ -634,3 +669,12 @@ void CMonitor::moveTo(const Vector2D& pos) {
|
||||||
Vector2D CMonitor::middle() {
|
Vector2D CMonitor::middle() {
|
||||||
return vecPosition + vecSize / 2.f;
|
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;
|
uint64_t ID = -1;
|
||||||
int activeWorkspace = -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 vecReservedTopLeft = Vector2D(0, 0);
|
||||||
Vector2D vecReservedBottomRight = Vector2D(0, 0);
|
Vector2D vecReservedBottomRight = Vector2D(0, 0);
|
||||||
|
@ -60,11 +62,14 @@ class CMonitor {
|
||||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
bool gammaChanged = false;
|
bool gammaChanged = false;
|
||||||
float xwaylandScale = 1.f;
|
float xwaylandScale = 1.f;
|
||||||
|
std::array<float, 9> projMatrix = {0};
|
||||||
|
|
||||||
bool dpmsStatus = true;
|
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 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 enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||||
bool createdByUser = false;
|
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 pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||||
bool renderingActive = false;
|
bool renderingActive = false;
|
||||||
|
@ -81,6 +86,18 @@ class CMonitor {
|
||||||
|
|
||||||
CRegion lastFrameDamage; // stores last frame damage
|
CRegion lastFrameDamage; // stores last frame damage
|
||||||
|
|
||||||
|
// for tearing
|
||||||
|
CWindow* solitaryClient = nullptr;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool canTear = false;
|
||||||
|
bool nextRenderTorn = false;
|
||||||
|
bool activelyTearing = false;
|
||||||
|
|
||||||
|
bool busy = false;
|
||||||
|
bool frameScheduledWhileBusy = false;
|
||||||
|
} tearingState;
|
||||||
|
|
||||||
// for the special workspace. 0 means not open.
|
// for the special workspace. 0 means not open.
|
||||||
int specialWorkspaceID = 0;
|
int specialWorkspaceID = 0;
|
||||||
|
|
||||||
|
@ -96,21 +113,21 @@ class CMonitor {
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
void onConnect(bool noRule);
|
void onConnect(bool noRule);
|
||||||
void onDisconnect();
|
void onDisconnect(bool destroy = false);
|
||||||
void addDamage(const pixman_region32_t* rg);
|
void addDamage(const pixman_region32_t* rg);
|
||||||
void addDamage(const CRegion* rg);
|
void addDamage(const CRegion* rg);
|
||||||
void addDamage(const wlr_box* box);
|
void addDamage(const CBox* box);
|
||||||
void setMirror(const std::string&);
|
void setMirror(const std::string&);
|
||||||
bool isMirror();
|
bool isMirror();
|
||||||
float getDefaultScale();
|
float getDefaultScale();
|
||||||
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false);
|
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
|
||||||
void changeWorkspace(const int& id, bool internal = false);
|
void changeWorkspace(const int& id, bool internal = false);
|
||||||
void setSpecialWorkspace(CWorkspace* const pWorkspace);
|
void setSpecialWorkspace(CWorkspace* const pWorkspace);
|
||||||
void setSpecialWorkspace(const int& id);
|
void setSpecialWorkspace(const int& id);
|
||||||
void moveTo(const Vector2D& pos);
|
void moveTo(const Vector2D& pos);
|
||||||
Vector2D middle();
|
Vector2D middle();
|
||||||
|
void updateMatrix();
|
||||||
|
|
||||||
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
|
|
||||||
bool m_bEnabled = false;
|
bool m_bEnabled = false;
|
||||||
bool m_bRenderingInitPassed = false;
|
bool m_bRenderingInitPassed = false;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,10 @@ CRegion::CRegion(wlr_box* box) {
|
||||||
pixman_region32_init_rect(&m_rRegion, box->x, box->y, box->width, box->height);
|
pixman_region32_init_rect(&m_rRegion, box->x, box->y, box->width, box->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CRegion::CRegion(const CBox& box) {
|
||||||
|
pixman_region32_init_rect(&m_rRegion, box.x, box.y, box.w, box.h);
|
||||||
|
}
|
||||||
|
|
||||||
CRegion::CRegion(pixman_box32_t* box) {
|
CRegion::CRegion(pixman_box32_t* box) {
|
||||||
pixman_region32_init_rect(&m_rRegion, box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1);
|
pixman_region32_init_rect(&m_rRegion, box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1);
|
||||||
}
|
}
|
||||||
|
@ -59,6 +63,11 @@ CRegion& CRegion::add(double x, double y, double w, double h) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CRegion& CRegion::add(const CBox& other) {
|
||||||
|
pixman_region32_union_rect(&m_rRegion, &m_rRegion, other.x, other.y, other.w, other.h);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
CRegion& CRegion::subtract(const CRegion& other) {
|
CRegion& CRegion::subtract(const CRegion& other) {
|
||||||
pixman_region32_subtract(&m_rRegion, &m_rRegion, const_cast<CRegion*>(&other)->pixman());
|
pixman_region32_subtract(&m_rRegion, &m_rRegion, const_cast<CRegion*>(&other)->pixman());
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -79,11 +88,25 @@ CRegion& CRegion::invert(pixman_box32_t* box) {
|
||||||
return *this;
|
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) {
|
CRegion& CRegion::translate(const Vector2D& vec) {
|
||||||
pixman_region32_translate(&m_rRegion, vec.x, vec.y);
|
pixman_region32_translate(&m_rRegion, vec.x, vec.y);
|
||||||
return *this;
|
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) {
|
CRegion& CRegion::scale(float scale) {
|
||||||
wlr_region_scale(&m_rRegion, &m_rRegion, scale);
|
wlr_region_scale(&m_rRegion, &m_rRegion, scale);
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -100,7 +123,7 @@ std::vector<pixman_box32_t> CRegion::getRects() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_box CRegion::getExtents() {
|
CBox CRegion::getExtents() {
|
||||||
pixman_box32_t* box = pixman_region32_extents(&m_rRegion);
|
pixman_box32_t* box = pixman_region32_extents(&m_rRegion);
|
||||||
return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1};
|
return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Vector2D.hpp"
|
#include "Vector2D.hpp"
|
||||||
|
#include "Box.hpp"
|
||||||
|
|
||||||
struct wlr_box;
|
struct wlr_box;
|
||||||
|
|
||||||
|
@ -15,6 +16,8 @@ class CRegion {
|
||||||
CRegion(double x, double y, double w, double h);
|
CRegion(double x, double y, double w, double h);
|
||||||
/* Create from a wlr_box */
|
/* Create from a wlr_box */
|
||||||
CRegion(wlr_box* box);
|
CRegion(wlr_box* box);
|
||||||
|
/* Create from a CBox */
|
||||||
|
CRegion(const CBox& box);
|
||||||
/* Create from a pixman_box32_t */
|
/* Create from a pixman_box32_t */
|
||||||
CRegion(pixman_box32_t* box);
|
CRegion(pixman_box32_t* box);
|
||||||
|
|
||||||
|
@ -37,16 +40,20 @@ class CRegion {
|
||||||
CRegion& set(const CRegion& other);
|
CRegion& set(const CRegion& other);
|
||||||
CRegion& add(const CRegion& other);
|
CRegion& add(const CRegion& other);
|
||||||
CRegion& add(double x, double y, double w, double h);
|
CRegion& add(double x, double y, double w, double h);
|
||||||
|
CRegion& add(const CBox& other);
|
||||||
CRegion& subtract(const CRegion& other);
|
CRegion& subtract(const CRegion& other);
|
||||||
CRegion& intersect(const CRegion& other);
|
CRegion& intersect(const CRegion& other);
|
||||||
CRegion& intersect(double x, double y, double w, double h);
|
CRegion& intersect(double x, double y, double w, double h);
|
||||||
CRegion& translate(const Vector2D& vec);
|
CRegion& translate(const Vector2D& vec);
|
||||||
|
CRegion& transform(const wl_output_transform t, double w, double h);
|
||||||
CRegion& invert(pixman_box32_t* box);
|
CRegion& invert(pixman_box32_t* box);
|
||||||
|
CRegion& invert(const CBox& box);
|
||||||
CRegion& scale(float scale);
|
CRegion& scale(float scale);
|
||||||
wlr_box getExtents();
|
CBox getExtents();
|
||||||
bool containsPoint(const Vector2D& vec) const;
|
bool containsPoint(const Vector2D& vec) const;
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
Vector2D closestPoint(const Vector2D& vec) const;
|
Vector2D closestPoint(const Vector2D& vec) const;
|
||||||
|
CRegion copy() const;
|
||||||
|
|
||||||
std::vector<pixman_box32_t> getRects() const;
|
std::vector<pixman_box32_t> getRects() const;
|
||||||
|
|
||||||
|
|
|
@ -98,8 +98,9 @@ void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
|
||||||
|
|
||||||
// damage
|
// damage
|
||||||
if (pNode->pSurface && pNode->pSurface->exists()) {
|
if (pNode->pSurface && pNode->pSurface->exists()) {
|
||||||
wlr_box extents = {};
|
CBox extents = {};
|
||||||
wlr_surface_get_extends(pNode->pSurface->wlr(), &extents);
|
wlr_surface_get_extends(pNode->pSurface->wlr(), extents.pWlr());
|
||||||
|
extents.applyFromWlr();
|
||||||
|
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addSurfaceGlobalOffset(pNode, &lx, &ly);
|
addSurfaceGlobalOffset(pNode, &lx, &ly);
|
||||||
|
@ -177,6 +178,9 @@ void Events::listener_mapSubsurface(void* owner, void* data) {
|
||||||
Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface);
|
Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface);
|
||||||
|
|
||||||
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
|
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
|
||||||
|
|
||||||
|
if (subsurface->pWindowOwner)
|
||||||
|
subsurface->pWindowOwner->updateSurfaceScaleTransformDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_unmapSubsurface(void* owner, void* data) {
|
void Events::listener_unmapSubsurface(void* owner, void* data) {
|
||||||
|
@ -198,7 +202,7 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addSurfaceGlobalOffset(PNODE, &lx, &ly);
|
addSurfaceGlobalOffset(PNODE, &lx, &ly);
|
||||||
|
|
||||||
wlr_box extents = {lx, ly, 0, 0};
|
CBox extents = {lx, ly, 0, 0};
|
||||||
|
|
||||||
extents.width = PNODE->pSurface->wlr()->current.width;
|
extents.width = PNODE->pSurface->wlr()->current.width;
|
||||||
extents.height = PNODE->pSurface->wlr()->current.height;
|
extents.height = PNODE->pSurface->wlr()->current.height;
|
||||||
|
@ -219,6 +223,8 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
|
||||||
|
|
||||||
// no damaging if it's not visible
|
// no damaging if it's not visible
|
||||||
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
|
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;
|
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
|
||||||
if (*PLOGDAMAGE)
|
if (*PLOGDAMAGE)
|
||||||
Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner);
|
Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner);
|
||||||
|
@ -243,8 +249,37 @@ 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);
|
g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE);
|
||||||
|
|
||||||
|
if (pNode->lastSize != Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} && pNode->pWindowOwner)
|
||||||
|
g_pHyprRenderer->damageWindow(pNode->pWindowOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pNode->pWindowOwner) {
|
||||||
|
if (pNode->pWindowOwner->m_bIsX11)
|
||||||
|
pNode->pWindowOwner->m_vReportedSize = pNode->pWindowOwner->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
|
||||||
|
|
||||||
|
// tearing: if solitary, redraw it. This still might be a single surface window
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID);
|
||||||
|
if (PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
|
||||||
|
pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
|
||||||
|
CRegion damageBox;
|
||||||
|
wlr_surface_get_effective_damage(pNode->pSurface->wlr(), damageBox.pixman());
|
||||||
|
|
||||||
|
if (!damageBox.empty()) {
|
||||||
|
|
||||||
|
if (PMONITOR->tearingState.busy) {
|
||||||
|
PMONITOR->tearingState.frameScheduledWhileBusy = true;
|
||||||
|
} else {
|
||||||
|
PMONITOR->tearingState.nextRenderTorn = true;
|
||||||
|
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_destroySubsurface(void* owner, void* data) {
|
void Events::listener_destroySubsurface(void* owner, void* data) {
|
||||||
|
|
|
@ -26,6 +26,8 @@ struct SSurfaceTreeNode {
|
||||||
void* globalOffsetData;
|
void* globalOffsetData;
|
||||||
CWindow* pWindowOwner = nullptr;
|
CWindow* pWindowOwner = nullptr;
|
||||||
|
|
||||||
|
Vector2D lastSize;
|
||||||
|
|
||||||
//
|
//
|
||||||
bool operator==(const SSurfaceTreeNode& rhs) const {
|
bool operator==(const SSurfaceTreeNode& rhs) const {
|
||||||
return pSurface == rhs.pSurface;
|
return pSurface == rhs.pSurface;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "../macros.hpp"
|
#include "../macros.hpp"
|
||||||
|
@ -20,6 +21,15 @@ class CVarList {
|
||||||
|
|
||||||
std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const;
|
std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const;
|
||||||
|
|
||||||
|
void map(std::function<void(std::string&)> func) {
|
||||||
|
for (auto& s : m_vArgs)
|
||||||
|
func(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const std::string arg) {
|
||||||
|
m_vArgs.emplace_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
std::string operator[](const size_t& idx) const {
|
std::string operator[](const size_t& idx) const {
|
||||||
if (idx >= m_vArgs.size())
|
if (idx >= m_vArgs.size())
|
||||||
return "";
|
return "";
|
||||||
|
@ -40,6 +50,15 @@ class CVarList {
|
||||||
return m_vArgs.end();
|
return m_vArgs.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool contains(const std::string& el) {
|
||||||
|
for (auto& a : m_vArgs) {
|
||||||
|
if (a == el)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> m_vArgs;
|
std::vector<std::string> m_vArgs;
|
||||||
};
|
};
|
|
@ -28,6 +28,10 @@ Vector2D Vector2D::floor() const {
|
||||||
return Vector2D(std::floor(x), std::floor(y));
|
return Vector2D(std::floor(x), std::floor(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D Vector2D::round() const {
|
||||||
|
return Vector2D(std::round(x), std::round(y));
|
||||||
|
}
|
||||||
|
|
||||||
Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const {
|
Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const {
|
||||||
return Vector2D(std::clamp(this->x, min.x, max.x < min.x ? INFINITY : max.x), std::clamp(this->y, min.y, max.y < min.y ? INFINITY : max.y));
|
return Vector2D(std::clamp(this->x, min.x, max.x < min.x ? INFINITY : max.x), std::clamp(this->y, min.y, max.y < min.y ? INFINITY : max.y));
|
||||||
}
|
}
|
||||||
|
@ -45,3 +49,7 @@ bool Vector2D::inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D
|
||||||
|
|
||||||
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
|
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Vector2D::size() const {
|
||||||
|
return std::sqrt(x * x + y * y);
|
||||||
|
}
|
||||||
|
|
|
@ -22,10 +22,13 @@ class Vector2D {
|
||||||
Vector2D operator-(const Vector2D& a) const {
|
Vector2D operator-(const Vector2D& a) const {
|
||||||
return Vector2D(this->x - a.x, this->y - a.y);
|
return Vector2D(this->x - a.x, this->y - a.y);
|
||||||
}
|
}
|
||||||
Vector2D operator*(const float& a) const {
|
Vector2D operator-() const {
|
||||||
|
return Vector2D(-this->x, -this->y);
|
||||||
|
}
|
||||||
|
Vector2D operator*(const double& a) const {
|
||||||
return Vector2D(this->x * a, this->y * a);
|
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);
|
return Vector2D(this->x / a, this->y / a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +55,43 @@ class Vector2D {
|
||||||
bool operator<(const Vector2D& a) const {
|
bool operator<(const Vector2D& a) const {
|
||||||
return this->x < a.x && this->y < a.y;
|
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 distance(const Vector2D& other) const;
|
||||||
|
double size() const;
|
||||||
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const;
|
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const;
|
||||||
|
|
||||||
Vector2D floor() const;
|
Vector2D floor() const;
|
||||||
|
Vector2D round() const;
|
||||||
|
|
||||||
bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const;
|
bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,14 @@ SLayerSurface::SLayerSurface() {
|
||||||
alpha.registerVar();
|
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() {
|
void SLayerSurface::applyRules() {
|
||||||
noAnimations = false;
|
noAnimations = false;
|
||||||
forceBlur = false;
|
forceBlur = false;
|
||||||
|
@ -20,7 +28,7 @@ void SLayerSurface::applyRules() {
|
||||||
noAnimations = true;
|
noAnimations = true;
|
||||||
else if (rule.rule == "blur")
|
else if (rule.rule == "blur")
|
||||||
forceBlur = true;
|
forceBlur = true;
|
||||||
else if (rule.rule.find("ignorealpha") == 0 || rule.rule.find("ignorezero") == 0) {
|
else if (rule.rule.starts_with("ignorealpha") || rule.rule.starts_with("ignorezero")) {
|
||||||
const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
|
const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
|
||||||
std::string alphaValue = "";
|
std::string alphaValue = "";
|
||||||
if (FIRST_SPACE_POS != std::string::npos)
|
if (FIRST_SPACE_POS != std::string::npos)
|
||||||
|
@ -31,7 +39,7 @@ void SLayerSurface::applyRules() {
|
||||||
if (!alphaValue.empty())
|
if (!alphaValue.empty())
|
||||||
ignoreAlphaValue = std::stof(alphaValue);
|
ignoreAlphaValue = std::stof(alphaValue);
|
||||||
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
|
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
|
||||||
} else if (rule.rule.find("xray") == 0) {
|
} else if (rule.rule.starts_with("xray")) {
|
||||||
CVarList vars{rule.rule, 0, ' '};
|
CVarList vars{rule.rule, 0, ' '};
|
||||||
try {
|
try {
|
||||||
xray = configStringToInt(vars[1]);
|
xray = configStringToInt(vars[1]);
|
||||||
|
|
|
@ -16,6 +16,7 @@ struct SLayerRule {
|
||||||
|
|
||||||
struct SLayerSurface {
|
struct SLayerSurface {
|
||||||
SLayerSurface();
|
SLayerSurface();
|
||||||
|
~SLayerSurface();
|
||||||
|
|
||||||
void applyRules();
|
void applyRules();
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ struct SLayerSurface {
|
||||||
DYNLISTENER(commitLayerSurface);
|
DYNLISTENER(commitLayerSurface);
|
||||||
DYNLISTENER(newPopup);
|
DYNLISTENER(newPopup);
|
||||||
|
|
||||||
wlr_box geometry = {0, 0, 0, 0};
|
CBox geometry = {0, 0, 0, 0};
|
||||||
Vector2D position;
|
Vector2D position;
|
||||||
zwlr_layer_shell_v1_layer layer;
|
zwlr_layer_shell_v1_layer layer;
|
||||||
|
|
||||||
|
@ -65,12 +66,12 @@ class CMonitor;
|
||||||
struct SRenderData {
|
struct SRenderData {
|
||||||
CMonitor* pMonitor;
|
CMonitor* pMonitor;
|
||||||
timespec* when;
|
timespec* when;
|
||||||
int x, y;
|
double x, y;
|
||||||
|
|
||||||
// for iters
|
// for iters
|
||||||
void* data = nullptr;
|
void* data = nullptr;
|
||||||
wlr_surface* surface = nullptr;
|
wlr_surface* surface = nullptr;
|
||||||
int w, h;
|
double w, h;
|
||||||
|
|
||||||
// for rounding
|
// for rounding
|
||||||
bool dontRound = true;
|
bool dontRound = true;
|
||||||
|
@ -96,6 +97,8 @@ struct SRenderData {
|
||||||
|
|
||||||
// for calculating UV
|
// for calculating UV
|
||||||
CWindow* pWindow = nullptr;
|
CWindow* pWindow = nullptr;
|
||||||
|
|
||||||
|
bool popup = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SExtensionFindingData {
|
struct SExtensionFindingData {
|
||||||
|
@ -169,7 +172,8 @@ struct SConstraint {
|
||||||
bool active = false;
|
bool active = false;
|
||||||
|
|
||||||
bool hintSet = false;
|
bool hintSet = false;
|
||||||
Vector2D positionHint = {-1, -1}; // the position hint, but will be set to the current cursor pos if not set.
|
Vector2D positionHint = {-1, -1}; // the position hint, but will use cursorPosOnActivate if unset
|
||||||
|
Vector2D cursorPosOnActivate = {-1, -1};
|
||||||
|
|
||||||
DYNLISTENER(setConstraintRegion);
|
DYNLISTENER(setConstraintRegion);
|
||||||
DYNLISTENER(destroyConstraint);
|
DYNLISTENER(destroyConstraint);
|
||||||
|
@ -178,6 +182,7 @@ struct SConstraint {
|
||||||
Vector2D getLogicConstraintPos();
|
Vector2D getLogicConstraintPos();
|
||||||
Vector2D getLogicConstraintSize();
|
Vector2D getLogicConstraintSize();
|
||||||
|
|
||||||
|
//
|
||||||
bool operator==(const SConstraint& b) const {
|
bool operator==(const SConstraint& b) const {
|
||||||
return constraint == b.constraint;
|
return constraint == b.constraint;
|
||||||
}
|
}
|
||||||
|
@ -250,6 +255,8 @@ struct STablet {
|
||||||
wlr_tablet_v2_tablet* wlrTabletV2 = nullptr;
|
wlr_tablet_v2_tablet* wlrTabletV2 = nullptr;
|
||||||
wlr_input_device* wlrDevice = nullptr;
|
wlr_input_device* wlrDevice = nullptr;
|
||||||
|
|
||||||
|
bool relativeInput = false;
|
||||||
|
|
||||||
std::string name = "";
|
std::string name = "";
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -392,3 +399,14 @@ struct SSwitchDevice {
|
||||||
return pWlrDevice == other.pWlrDevice;
|
return pWlrDevice == other.pWlrDevice;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct STearingController {
|
||||||
|
wlr_tearing_control_v1* pWlrHint = nullptr;
|
||||||
|
|
||||||
|
DYNLISTENER(set);
|
||||||
|
DYNLISTENER(destroy);
|
||||||
|
|
||||||
|
bool operator==(const STearingController& other) {
|
||||||
|
return pWlrHint == other.pWlrHint;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -2,11 +2,18 @@
|
||||||
#include "MiscFunctions.hpp"
|
#include "MiscFunctions.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "../debug/Log.hpp"
|
#include "../debug/Log.hpp"
|
||||||
|
#include "Watchdog.hpp"
|
||||||
|
|
||||||
void handleWrapped(wl_listener* listener, void* data) {
|
void handleWrapped(wl_listener* listener, void* data) {
|
||||||
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
|
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
|
||||||
|
|
||||||
|
g_pWatchdog->startWatching();
|
||||||
|
|
||||||
|
try {
|
||||||
pWrap->m_pSelf->emit(data);
|
pWrap->m_pSelf->emit(data);
|
||||||
|
} catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); }
|
||||||
|
|
||||||
|
g_pWatchdog->endWatching();
|
||||||
}
|
}
|
||||||
|
|
||||||
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {
|
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {
|
||||||
|
|
|
@ -27,17 +27,45 @@ wlr_surface* CWLSurface::wlr() const {
|
||||||
return m_pWLRSurface;
|
return m_pWLRSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWLSurface::small() const {
|
||||||
|
if (!m_pOwner || !exists())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return m_pOwner->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || m_pOwner->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2D CWLSurface::correctSmallVec() const {
|
||||||
|
if (!m_pOwner || !exists() || !small() || m_bFillIgnoreSmall)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto SIZE = getViewporterCorrectedSize();
|
||||||
|
|
||||||
|
return Vector2D{(m_pOwner->m_vReportedSize.x - SIZE.x) / 2, (m_pOwner->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) *
|
||||||
|
(m_pOwner->m_vRealSize.vec() / m_pOwner->m_vReportedSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2D CWLSurface::getViewporterCorrectedSize() const {
|
||||||
|
if (!exists())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} :
|
||||||
|
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
|
||||||
|
}
|
||||||
|
|
||||||
void CWLSurface::destroy() {
|
void CWLSurface::destroy() {
|
||||||
if (!m_pWLRSurface)
|
if (!m_pWLRSurface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hyprListener_destroy.removeCallback();
|
hyprListener_destroy.removeCallback();
|
||||||
m_pWLRSurface->data = nullptr;
|
m_pWLRSurface->data = nullptr;
|
||||||
|
m_pOwner = nullptr;
|
||||||
|
|
||||||
if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
|
if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
|
||||||
g_pCompositor->m_pLastFocus = nullptr;
|
g_pCompositor->m_pLastFocus = nullptr;
|
||||||
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
|
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
|
||||||
g_pInputManager->m_pLastMouseSurface = nullptr;
|
g_pInputManager->m_pLastMouseSurface = nullptr;
|
||||||
|
if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
|
||||||
|
g_pHyprRenderer->m_sLastCursorData.surf.reset();
|
||||||
|
|
||||||
m_pWLRSurface = nullptr;
|
m_pWLRSurface = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
|
|
||||||
|
class CWindow;
|
||||||
|
|
||||||
class CWLSurface {
|
class CWLSurface {
|
||||||
public:
|
public:
|
||||||
CWLSurface() = default;
|
CWLSurface() = default;
|
||||||
|
@ -17,7 +20,22 @@ class CWLSurface {
|
||||||
|
|
||||||
wlr_surface* wlr() const;
|
wlr_surface* wlr() const;
|
||||||
bool exists() const;
|
bool exists() const;
|
||||||
|
bool small() const; // means surface is smaller than the requested size
|
||||||
|
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
|
||||||
|
Vector2D getViewporterCorrectedSize() const;
|
||||||
|
|
||||||
|
// allow stretching. Useful for plugins.
|
||||||
|
bool m_bFillIgnoreSmall = false;
|
||||||
|
|
||||||
|
// if present, means this is a base surface of a window. Cleaned on unassign()
|
||||||
|
CWindow* m_pOwner = nullptr;
|
||||||
|
|
||||||
|
// track surface data and avoid dupes
|
||||||
|
float m_fLastScale = 0;
|
||||||
|
int m_iLastScale = 0;
|
||||||
|
wl_output_transform m_eLastTransform = (wl_output_transform)-1;
|
||||||
|
|
||||||
|
//
|
||||||
CWLSurface& operator=(wlr_surface* pSurface) {
|
CWLSurface& operator=(wlr_surface* pSurface) {
|
||||||
destroy();
|
destroy();
|
||||||
m_pWLRSurface = pSurface;
|
m_pWLRSurface = pSurface;
|
||||||
|
@ -38,6 +56,10 @@ class CWLSurface {
|
||||||
return exists();
|
return exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) {
|
||||||
|
return (CWLSurface*)pSurface->data;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wlr_surface* m_pWLRSurface = nullptr;
|
wlr_surface* m_pWLRSurface = nullptr;
|
||||||
|
|
||||||
|
|
59
src/helpers/Watchdog.cpp
Normal file
59
src/helpers/Watchdog.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#include "Watchdog.hpp"
|
||||||
|
#include <signal.h>
|
||||||
|
#include "config/ConfigManager.hpp"
|
||||||
|
|
||||||
|
CWatchdog::~CWatchdog() {
|
||||||
|
m_bExitThread = true;
|
||||||
|
m_bNotified = true;
|
||||||
|
m_cvWatchdogCondition.notify_all();
|
||||||
|
m_pWatchdog.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
CWatchdog::CWatchdog() {
|
||||||
|
m_iMainThreadPID = pthread_self();
|
||||||
|
|
||||||
|
m_pWatchdog = std::make_unique<std::thread>([this] {
|
||||||
|
static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
|
||||||
|
|
||||||
|
while (1337) {
|
||||||
|
std::unique_lock lk(m_mWatchdogMutex);
|
||||||
|
|
||||||
|
if (!m_bWillWatch)
|
||||||
|
m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified; });
|
||||||
|
else {
|
||||||
|
if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false)
|
||||||
|
pthread_kill(m_iMainThreadPID, SIGUSR1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_bExitThread)
|
||||||
|
break;
|
||||||
|
|
||||||
|
m_bWatching = false;
|
||||||
|
m_bNotified = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
m_pWatchdog->detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWatchdog::startWatching() {
|
||||||
|
static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
|
||||||
|
|
||||||
|
if (*PTIMEOUT == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_tTriggered = std::chrono::high_resolution_clock::now();
|
||||||
|
m_bWillWatch = true;
|
||||||
|
m_bWatching = true;
|
||||||
|
|
||||||
|
m_bNotified = true;
|
||||||
|
m_cvWatchdogCondition.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWatchdog::endWatching() {
|
||||||
|
m_bWatching = false;
|
||||||
|
m_bWillWatch = false;
|
||||||
|
|
||||||
|
m_bNotified = true;
|
||||||
|
m_cvWatchdogCondition.notify_all();
|
||||||
|
}
|
32
src/helpers/Watchdog.hpp
Normal file
32
src/helpers/Watchdog.hpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
class CWatchdog {
|
||||||
|
public:
|
||||||
|
// must be called from the main thread
|
||||||
|
CWatchdog();
|
||||||
|
~CWatchdog();
|
||||||
|
|
||||||
|
void startWatching();
|
||||||
|
void endWatching();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::chrono::high_resolution_clock::time_point m_tTriggered;
|
||||||
|
|
||||||
|
pthread_t m_iMainThreadPID = 0;
|
||||||
|
|
||||||
|
bool m_bWatching = false;
|
||||||
|
bool m_bWillWatch = false;
|
||||||
|
|
||||||
|
std::unique_ptr<std::thread> m_pWatchdog;
|
||||||
|
std::mutex m_mWatchdogMutex;
|
||||||
|
bool m_bNotified = false;
|
||||||
|
bool m_bExitThread = false;
|
||||||
|
std::condition_variable m_cvWatchdogCondition;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::unique_ptr<CWatchdog> g_pWatchdog;
|
|
@ -39,8 +39,9 @@ CWorkspace::~CWorkspace() {
|
||||||
|
|
||||||
void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
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.find("slidefade") == 0) {
|
if (ANIMSTYLE.starts_with("slidefade")) {
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
float movePerc = 100.f;
|
float movePerc = 100.f;
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||||
m_fAlpha.setValueAndWarp(1.f);
|
m_fAlpha.setValueAndWarp(1.f);
|
||||||
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
|
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
|
||||||
|
|
||||||
if (ANIMSTYLE.find("slidefadevert") == 0) {
|
if (ANIMSTYLE.starts_with("slidefadevert")) {
|
||||||
if (in) {
|
if (in) {
|
||||||
m_fAlpha.setValueAndWarp(0.f);
|
m_fAlpha.setValueAndWarp(0.f);
|
||||||
m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
|
m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
|
||||||
|
@ -90,26 +91,28 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||||
} else if (ANIMSTYLE == "slidevert") {
|
} else if (ANIMSTYLE == "slidevert") {
|
||||||
// fallback is slide
|
// fallback is slide
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
const auto PMONITOR = 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.
|
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
|
||||||
|
|
||||||
if (in) {
|
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);
|
m_vRenderOffset = Vector2D(0, 0);
|
||||||
} else {
|
} else {
|
||||||
m_vRenderOffset = Vector2D(0, left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y);
|
m_vRenderOffset = Vector2D(0, left ? -YDISTANCE : YDISTANCE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// fallback is slide
|
// 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.
|
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
|
||||||
|
|
||||||
if (in) {
|
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);
|
m_vRenderOffset = Vector2D(0, 0);
|
||||||
} else {
|
} else {
|
||||||
m_vRenderOffset = Vector2D(left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x, 0);
|
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
|
|
||||||
enum eFullscreenMode : uint8_t
|
enum eFullscreenMode : int8_t {
|
||||||
{
|
FULLSCREEN_INVALID = -1,
|
||||||
FULLSCREEN_FULL = 0,
|
FULLSCREEN_FULL = 0,
|
||||||
FULLSCREEN_MAXIMIZED
|
FULLSCREEN_MAXIMIZED
|
||||||
};
|
};
|
||||||
|
@ -49,12 +49,12 @@ class CWorkspace {
|
||||||
bool m_bDefaultFloating = false;
|
bool m_bDefaultFloating = false;
|
||||||
bool m_bDefaultPseudo = false;
|
bool m_bDefaultPseudo = false;
|
||||||
|
|
||||||
// don't destroy in sanity check
|
|
||||||
bool m_bIndestructible = false;
|
|
||||||
|
|
||||||
// last monitor (used on reconnect)
|
// last monitor (used on reconnect)
|
||||||
std::string m_szLastMonitor = "";
|
std::string m_szLastMonitor = "";
|
||||||
|
|
||||||
|
// Whether the user configured command for on-created-empty has been executed, if any
|
||||||
|
bool m_bOnCreatedEmptyExecuted = false;
|
||||||
|
|
||||||
void startAnim(bool in, bool left, bool instant = false);
|
void startAnim(bool in, bool left, bool instant = false);
|
||||||
void setActive(bool on);
|
void setActive(bool on);
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,7 @@ typedef struct {
|
||||||
} xcb_size_hints_t;
|
} xcb_size_hints_t;
|
||||||
typedef unsigned int xcb_window_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_ABOVE = 0,
|
||||||
XCB_STACK_MODE_BELOW = 1,
|
XCB_STACK_MODE_BELOW = 1,
|
||||||
XCB_STACK_MODE_TOP_IF = 2,
|
XCB_STACK_MODE_TOP_IF = 2,
|
||||||
|
|
|
@ -5,7 +5,7 @@ CHyprError::CHyprError() {
|
||||||
m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_NONE);
|
m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_NONE);
|
||||||
m_fFadeOpacity.registerVar();
|
m_fFadeOpacity.registerVar();
|
||||||
|
|
||||||
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, std::any param) {
|
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
|
||||||
if (!m_bIsCreated)
|
if (!m_bIsCreated)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ CHyprError::CHyprError() {
|
||||||
m_bMonitorChanged = true;
|
m_bMonitorChanged = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
g_pHookSystem->hookDynamic("preRender", [&](void* self, std::any param) {
|
g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any param) {
|
||||||
if (!m_bIsCreated)
|
if (!m_bIsCreated)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ void CHyprError::draw() {
|
||||||
|
|
||||||
const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor;
|
const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor;
|
||||||
|
|
||||||
wlr_box monbox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
CBox monbox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
||||||
|
|
||||||
m_bDamageBox.x = (int)PMONITOR->vecPosition.x;
|
m_bDamageBox.x = (int)PMONITOR->vecPosition.x;
|
||||||
m_bDamageBox.y = (int)PMONITOR->vecPosition.y;
|
m_bDamageBox.y = (int)PMONITOR->vecPosition.y;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue