This commit is contained in:
Kaley, Fischer 2024-03-02 13:47:11 +01:00
parent 9609ae0f28
commit 06011c4d3a
143 changed files with 6876 additions and 5627 deletions

View file

@ -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

View file

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

View file

@ -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
@ -45,6 +36,7 @@ jobs:
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 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

View file

@ -26,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

View file

@ -24,13 +24,13 @@ jobs:
uses: github/codeql-action/upload-sarif@v2 uses: github/codeql-action/upload-sarif@v2
with: with:
sarif_file: ${{github.workspace}}/flawfinder_results.sarif sarif_file: ${{github.workspace}}/flawfinder_results.sarif
codeql: codeql:
name: CodeQL name: CodeQL
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: archlinux image: archlinux
permissions: permissions:
actions: read actions: read
contents: read contents: read
@ -42,34 +42,25 @@ 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
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v2
with: with:

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

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

2
.gitignore vendored
View file

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

3
.gitmodules vendored
View file

@ -1,7 +1,6 @@
[submodule "wlroots"] [submodule "wlroots"]
path = subprojects/wlroots path = subprojects/wlroots
url = https://github.com/DRAGONTOS/wlroots.git url = https://gitlab.freedesktop.org/wlroots/wlroots.git
branch = 0.18.0-dev
[submodule "subprojects/hyprland-protocols"] [submodule "subprojects/hyprland-protocols"]
path = subprojects/hyprland-protocols path = subprojects/hyprland-protocols
url = https://github.com/hyprwm/hyprland-protocols url = https://github.com/hyprwm/hyprland-protocols

View file

@ -57,8 +57,8 @@ ExternalProject_Add(
wlroots wlroots
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
PATCH_COMMAND sed -E -i -e "s/(soversion = 13)([^032]|$$)/soversion = 13032/g" meson.build PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build
CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> --reconfigure 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_COMMAND ninja -C build
BUILD_ALWAYS true BUILD_ALWAYS true
BUILD_IN_SOURCE true BUILD_IN_SOURCE true
@ -101,7 +101,7 @@ 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 hyprlang>=0.3.2) # 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")

View file

@ -1,22 +1,22 @@
PREFIX = /usr/local 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 -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build 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 -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build 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 -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build 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 -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build chmod -R 777 ./build
@ -42,10 +42,10 @@ install:
chmod 755 ${PREFIX}/bin/Hyprland chmod 755 ${PREFIX}/bin/Hyprland
chmod 755 ${PREFIX}/bin/hyprctl chmod 755 ${PREFIX}/bin/hyprctl
chmod 755 ${PREFIX}/bin/hyprpm chmod 755 ${PREFIX}/bin/hyprpm
ln -s -r -f ${PREFIX}/bin/Hyprland ${PREFIX}/bin/hyprland cd ${PREFIX}/bin && ln -sf Hyprland hyprland
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi 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 mkdir -p ${PREFIX}/share/xdg-desktop-portal
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
@ -106,3 +106,24 @@ man:
--variable=section:1 \ --variable=section:1 \
--from rst \ --from rst \
--to man > ./docs/hyprctl.1 --to man > ./docs/hyprctl.1
asan:
@echo -en "!!WARNING!!\nOnly run this in the TTY.\n"
@pidof Hyprland > /dev/null && echo -ne "Refusing to run with Hyprland running.\n" || echo ""
@pidof Hyprland > /dev/null && exit 1 || echo ""
rm -rf ./wayland
git reset --hard
git clone --recursive https://gitlab.freedesktop.org/wayland/wayland
cd wayland && patch -p1 < ../scripts/waylandStatic.diff && meson setup build --buildtype=debug -Db_sanitize=address -Ddocumentation=false && ninja -C build && cd ..
cp ./wayland/build/src/libwayland-server.a .
@echo "Wayland done"
patch -p1 < ./scripts/hyprlandStaticAsan.diff
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DWITH_ASAN:STRING=True -DUSE_TRACY:STRING=False -DUSE_TRACY_GPU:STRING=False -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
@echo "Hyprland done"
ASAN_OPTIONS="detect_odr_violation=0,log_path=asan.log" HYPRLAND_NO_CRASHREPORTER=1 ./build/Hyprland -c ~/.config/hypr/hyprland.conf

View file

@ -41,6 +41,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
- Much more QoL stuff than other wlr-based compositors - 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 - Tearing support for better gaming performance
- Easily expandable and readable codebase - Easily expandable and readable codebase
- Fast and active development - Fast and active development

View file

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

BIN
assets/wall0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

BIN
assets/wall1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

BIN
assets/wall2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

View file

@ -47,7 +47,7 @@ basically, directories in /tmp/hypr are your sessions.
## Obtaining the Hyprland Crash Report (v0.22.0beta and up) ## Obtaining the Hyprland Crash Report (v0.22.0beta and up)
If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `~/.hyprland` If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `$HOME/.cache/hyprland`.
Go to the crash report directory and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed. Go to the crash report directory and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.

View file

@ -1,112 +1,32 @@
# This is an example Hyprland config file.
#
# Refer to the wiki for more information.
#
# Please note not all available settings / options are set here.
# For a full list, see the wiki
#
# See https://wiki.hyprland.org/Configuring/Monitors/
monitor=,preferred,auto,auto
# See https://wiki.hyprland.org/Configuring/Keywords/ for more # See https://wiki.hyprland.org/Configuring/Keywords/ for more
# Execute your favorite apps at launch
# exec-once = waybar & hyprpaper & firefox # exec-once = waybar & hyprpaper & firefox
# Source a file (multi-file configs) # Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf # source = ~/.config/hypr/myColors.conf
# Startup # Set programs that you use
#exec-once = waybar & hyprpaper & dunst $terminal = kitty
exec-once = /usr/libexec/polkit-gnome-authentication-agent-1 $fileManager = dolphin
exec-once = hyprpm reload -n $menu = wofi --show drun
#exec-once = wl-clip-persist --clipboard both
#exec-once = wl-paste -p -t text --watch clipman store -P --histpath="~/.local/share/clipman-primary.json"
# Plugins # Some default env vars.
#plugin { env = XCURSOR_SIZE,24
# split-monitor-workspaces { env = QT_QPA_PLATFORMTHEME,qt5ct # change to qt6ct if you have that
# count = 10
# }
# hy3 {
# # disable gaps when only one window is onscreen
# no_gaps_when_only = false # default: false
#
# # policy controlling what happens when a node is removed from a group,
# # leaving only a group
# # 0 = remove the nested group
# # 1 = keep the nested group
# # 2 = keep the nested group only if its parent is a tab group
# node_collapse_policy = 2 # default: 2
#
# # special workspace
# special_scale_factor = 0.95
#
# # offset from group split direction when only one window is in a group
# group_inset = 10 # default: 10
#
# # tab group settings
# tabs {
# # height of the tab bar
# height = 15 # default: 15
#
# # padding between the tab bar and its focused node
# padding = 5 # default: 5
#
# # the tab bar should animate in/out from the top instead of below the window
# from_top = false # default: false
#
# # rounding of tab bar corners
# rounding = 5 # default: 3
#
# # render the window title on the bar
# render_text = true # default: true
#
# # font to render the window title with
# text_font = Jetbrains Mono # default: Sans
#
# # height of the window title
# text_height = 8 # default: 8
#
# # left padding of the window title
# text_padding = 3 # default: 3
#
# # active tab bar segment color
# col.active = 0xFF8330DB # default: 0xff32b4ff
#
# # urgent tab bar segment color
# col.urgent = 0xffff4f4f # default: 0xffff4f4f
#
# # inactive tab bar segment color
# col.inactive = 0xFF4D4D4D # default: 0x80808080
#
# # active tab bar text color
# col.text.active = 0xffffffff # default: 0xff000000
#
# # urgent tab bar text color
# col.text.urgent = 0xffffffff # default: 0xff000000
#
# # inactive tab bar text color
# col.text.inactive = 0xffffffff # default: 0xff000000
# }
#
# # autotiling settings
# autotile {
# # enable autotile
# enable = false # default: false
#
# # make autotile-created groups ephemeral
# ephemeral_groups = true # default: true
#
# # if a window would be squished smaller than this width, a vertical split will be created
# # -1 = never automatically split vertically
# # 0 = always automatically split vertically
# # <number> = pixel height to split at
# trigger_width = 0 # default: 0
#
# # if a window would be squished smaller than this height, a horizontal split will be created
# # -1 = never automatically split horizontally
# # 0 = always automatically split horizontally
# # <number> = pixel height to split at
# trigger_height = 0 # default: 0
#
# # a space or comma separated list of workspace ids where autotile should be enabled
# # it's possible to create an exception rule by prefixing the definition with "not:"
# # workspaces = 1,2 # autotiling will only be enabled on workspaces 1 and 2
# # workspaces = not:1,2 # autotiling will be enabled on all workspaces except 1 and 2
# workspaces = all # default: all
# }
# }
#}
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/ # For all categories, see https://wiki.hyprland.org/Configuring/Variables/
input { input {
@ -119,7 +39,7 @@ input {
follow_mouse = 1 follow_mouse = 1
touchpad { touchpad {
natural_scroll = no natural_scroll = false
} }
sensitivity = 0 # -1.0 - 1.0, 0 means no modification. sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
@ -130,32 +50,37 @@ general {
gaps_in = 5 gaps_in = 5
gaps_out = 20 gaps_out = 20
border_size = 3 border_size = 2
col.active_border = 0xFF8330DB 0xFF3e136c col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
col.inactive_border = 0xFF4D4D4D 0xFF333333 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 {
# See https://wiki.hyprland.org/Configuring/Variables/ for more # See https://wiki.hyprland.org/Configuring/Variables/ for more
rounding = 10 rounding = 10
blur { blur {
enabled = true enabled = true
size = 1.5 size = 3
passes = 1 passes = 1
vibrancy = 0.1696
} }
drop_shadow = yes drop_shadow = true
shadow_range = 4 shadow_range = 4
shadow_render_power = 3 shadow_render_power = 3
col.shadow = rgba(1a1a1aee) col.shadow = rgba(1a1a1aee)
} }
animations { animations {
enabled = yes enabled = true
# Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more # Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
@ -164,14 +89,15 @@ animations {
animation = windows, 1, 7, myBezier animation = windows, 1, 7, myBezier
animation = windowsOut, 1, 7, default, popin 80% animation = windowsOut, 1, 7, default, popin 80%
animation = border, 1, 10, default animation = border, 1, 10, default
animation = borderangle, 1, 8, default
animation = fade, 1, 7, default animation = fade, 1, 7, default
animation = workspaces, 1, 4, default animation = workspaces, 1, 6, default
} }
dwindle { dwindle {
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
pseudotile = yes # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below pseudotile = true # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = yes # you probably want this preserve_split = true # you probably want this
} }
master { master {
@ -181,39 +107,41 @@ master {
gestures { gestures {
# See https://wiki.hyprland.org/Configuring/Variables/ for more # See https://wiki.hyprland.org/Configuring/Variables/ for more
workspace_swipe = off workspace_swipe = false
} }
# unscale XWayland misc {
xwayland { # See https://wiki.hyprland.org/Configuring/Variables/ for more
force_zero_scaling = true force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
} }
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
device {
name = epic-mouse-v1
sensitivity = -0.5
}
# Example windowrule v1
# windowrule = float, ^(kitty)$
# Example windowrule v2
# 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
windowrule = rounding 1,class:^(Wine)$ windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
windowrulev2 = opacity 0.8 0.8,class:^(kitty)$
windowrulev2=float,class:^(hyprland.share.picker)$
windowrule = float,^(Steamwebhelper)$
windowrule = float, title:^(Steamwebhelper)$
windowrule = float, title:^(pop-up)
windowrule = float, class:^(xdg-desktop-portal-kde)
windowrule = float, class:^(Wine)
# 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, RETURN, exec, $terminal bind = $mainMod, Q, exec, $terminal
bind = $mainMod, Q, killactive, bind = $mainMod, C, killactive,
bind = $mainMod SHIFT, Q, exit, bind = $mainMod, M, exit,
bind = $mainMod, F, fullscreen, bind = $mainMod, E, exec, $fileManager
bind = $mainMod, SPACE, togglefloating, bind = $mainMod, V, togglefloating,
bind = $mainMod, L, exec, gtklock bind = $mainMod, R, exec, $menu
bind = $mainMod CTRL, B, exec, killall waybar && waybar -c /home/$USER/.config/waybar/config-hypr
bind = $mainMod, D, exec, rofi -show run
bind = $mainMod, P, pseudo, # dwindle bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, togglesplit, # dwindle bind = $mainMod, J, togglesplit, # dwindle
bind = $mainMod, Print, exec, grim -g "$(slurp)" - | swappy -f - # take a screenshot
# Move focus with mainMod + arrow keys # Move focus with mainMod + arrow keys
bind = $mainMod, left, movefocus, l bind = $mainMod, left, movefocus, l
@ -221,12 +149,6 @@ bind = $mainMod, right, movefocus, r
bind = $mainMod, up, movefocus, u bind = $mainMod, up, movefocus, u
bind = $mainMod, down, movefocus, d bind = $mainMod, down, movefocus, d
# Move focused with mainMod + arrow keys
bind = $mainMod SHIFT, left, movewindow, l
bind = $mainMod SHIFT, right, movewindow, r
bind = $mainMod SHIFT, up, movewindow, u
bind = $mainMod SHIFT, down, movewindow, d
# Switch workspaces with mainMod + [0-9] # Switch workspaces with mainMod + [0-9]
bind = $mainMod, 1, workspace, 1 bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2 bind = $mainMod, 2, workspace, 2
@ -251,22 +173,9 @@ 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)
# vm fix bind = $mainMod, S, togglespecialworkspace, magic
bind=CTRL,ALT_L,submap,passthrough bind = $mainMod SHIFT, S, movetoworkspace, special:magic
submap=passthrough
bindr=CTRL,Escape,submap,reset
submap=reset
# Repeat this for each scratchpad you need
# BROWSER
animation=specialWorkspace,0,0,default
# kitty
#bind = $mainMod, y, togglespecialworkspace, kitty
#bind = $mainMod SHIFT, y, movetoworkspace, special:kitty
bind = $mainMod, x, exec, hyprctl dispatch togglespecialworkspace && hyprctl dispatch togglespecialworkspace
# 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

47
flake.lock generated
View file

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

View file

@ -12,7 +12,7 @@
host = "gitlab.freedesktop.org"; host = "gitlab.freedesktop.org";
owner = "wlroots"; owner = "wlroots";
repo = "wlroots"; repo = "wlroots";
rev = "5d639394f3e83b01596dcd166a44a9a1a2583350"; rev = "0cb091f1a2d345f37d2ee445f4ffd04f7f4ec9e5";
flake = false; flake = false;
}; };
@ -22,11 +22,18 @@
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
}; };
hyprlang = {
url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
xdph = { xdph = {
url = "github:hyprwm/xdg-desktop-portal-hyprland"; url = "github:hyprwm/xdg-desktop-portal-hyprland";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
inputs.hyprland-protocols.follows = "hyprland-protocols"; inputs.hyprland-protocols.follows = "hyprland-protocols";
inputs.hyprlang.follows = "hyprlang";
}; };
}; };
@ -86,6 +93,7 @@
name = "hyprland-shell"; name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [cmake python3]; nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
buildInputs = [self.packages.${system}.wlroots-hyprland]; buildInputs = [self.packages.${system}.wlroots-hyprland];
hardeningDisable = ["fortify"];
inputsFrom = [ inputsFrom = [
self.packages.${system}.wlroots-hyprland self.packages.${system}.wlroots-hyprland
self.packages.${system}.hyprland self.packages.${system}.hyprland

View file

@ -23,49 +23,42 @@
#include <filesystem> #include <filesystem>
#include <stdarg.h> #include <stdarg.h>
const std::string USAGE = R"#(usage: hyprctl [flags] [<command> [args]] const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
hyprctl --batch {<command 1> [args] ; <command 2> [args] ; ...}
LISTING COMMANDS: commands:
monitors: List outputs activewindow
workspaces: List all workspaces activeworkspace
activeworkspace: Get currently active workspace binds
clients: List clients (e.g. windows) clients
activewindow: Get currently active window cursorpos
layers: List layers decorations
animations: List animations and bezier curves in use devices
devices: List devices dispatch
binds: List registered binds getoption
instances: List running Hyprland instances globalshortcuts
layouts: List layouts hyprpaper
globalshortcuts: List global shortcuts instances
version: Print hyprland version keyword
CONFIGURATION COMMANDS: kill
keyword <keyword> [args]: Execute a keyword layers
getoption <option>: Get value of <option> layouts
reload: Reload configurations monitors
PLUGIN: notify
plugin list: List loaded plugins plugin
plugin load <path>: Load plugin from <path> reload
plugin unload <path>: Unload plugin at <path> setcursor
THEMING: seterror
hyprpaper <keywords> Issue hyprpaper keywords using IPC setprop
splash: Prints the current random splash splash
cursorpos: Get the current cursor position in global layout coordinates switchxkblayout
setcursor <theme> <size>: Set cursor theme and size, (except for GTK) systeminfo
ADDITIONAL COMMANDS: version
dispatch <name> [args]: Run a dispatcher workspacerules
kill: Enter kill mode, where you can kill an app by clicking on it, workspaces
use ESCAPE to quit kill mode
switchxkblayout <args>: Sets the xkb layout index for a keyboard, see wiki for details flags:
setprop <window> <prop>: Set window property, see wiki for details
seterror <color> <msg>: Display <msg> as a error message, will reset upon reloading config
seterror disable: Clear error message
notify <icon> <time_ms> <color> <message>:
Sends a notification using the built-in Hyprland notification system.
output <args>: Add and remove fake outputs to specified backend, see wiki for details.
FLAGS:
-j -> output in JSON -j -> output in JSON
--help -> display this help -r -> refresh state after issuing command (e.g. for updating variables)
--batch -> execute a batch of commands, separated by ';' --batch -> execute a batch of commands, separated by ';'
--instance (-i) -> use a specific instance. Can be either signature or index in hyprctl instances (0, 1, etc) --instance (-i) -> use a specific instance. Can be either signature or index in hyprctl instances (0, 1, etc)
)#"; )#";
@ -86,7 +79,7 @@ std::vector<SInstanceData> instances() {
std::vector<SInstanceData> result; std::vector<SInstanceData> result;
for (const auto& el : std::filesystem::directory_iterator("/tmp/hypr")) { for (const auto& el : std::filesystem::directory_iterator("/tmp/hypr")) {
if (el.is_directory()) if (el.is_directory() || !el.path().string().ends_with(".lock"))
continue; continue;
// read lock // read lock
@ -94,7 +87,9 @@ std::vector<SInstanceData> instances() {
data->id = el.path().string(); data->id = el.path().string();
data->id = data->id.substr(data->id.find_last_of('/') + 1, data->id.find(".lock") - data->id.find_last_of('/') - 1); data->id = data->id.substr(data->id.find_last_of('/') + 1, data->id.find(".lock") - data->id.find_last_of('/') - 1);
data->time = std::stoull(data->id.substr(data->id.find_first_of('_') + 1)); try {
data->time = std::stoull(data->id.substr(data->id.find_first_of('_') + 1));
} catch (std::exception& e) { continue; }
// read file // read file
std::ifstream ifs(el.path().string()); std::ifstream ifs(el.path().string());
@ -102,7 +97,9 @@ std::vector<SInstanceData> instances() {
int i = 0; int i = 0;
for (std::string line; std::getline(ifs, line); ++i) { for (std::string line; std::getline(ifs, line); ++i) {
if (i == 0) { if (i == 0) {
data->pid = std::stoull(line); try {
data->pid = std::stoull(line);
} catch (std::exception& e) { continue; }
} else if (i == 1) { } else if (i == 1) {
data->wlSocket = line; data->wlSocket = line;
} else } else
@ -309,6 +306,8 @@ int main(int argc, char** argv) {
if (ARGS[i] == "-j" && !fullArgs.contains("j")) { if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
fullArgs += "j"; fullArgs += "j";
json = true; json = true;
} else if (ARGS[i] == "-r" && !fullArgs.contains("r")) {
fullArgs += "r";
} else if (ARGS[i] == "--batch") { } else if (ARGS[i] == "--batch") {
fullRequest = "--batch "; fullRequest = "--batch ";
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") { } else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
@ -368,7 +367,7 @@ int main(int argc, char** argv) {
const auto ISIG = getenv("HYPRLAND_INSTANCE_SIGNATURE"); const auto ISIG = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!ISIG) { if (!ISIG) {
std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)"; std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)\n";
return 1; return 1;
} }
@ -379,42 +378,8 @@ int main(int argc, char** argv) {
if (fullRequest.contains("/--batch")) if (fullRequest.contains("/--batch"))
batchRequest(fullRequest); batchRequest(fullRequest);
else if (fullRequest.contains("/monitors")) else if (fullRequest.contains("/hyprpaper"))
request(fullRequest); requestHyprpaper(fullRequest);
else if (fullRequest.contains("/clients"))
request(fullRequest);
else if (fullRequest.contains("/workspaces"))
request(fullRequest);
else if (fullRequest.contains("/activeworkspace"))
request(fullRequest);
else if (fullRequest.contains("/workspacerules"))
request(fullRequest);
else if (fullRequest.contains("/activewindow"))
request(fullRequest);
else if (fullRequest.contains("/layers"))
request(fullRequest);
else if (fullRequest.contains("/version"))
request(fullRequest);
else if (fullRequest.contains("/kill"))
request(fullRequest);
else if (fullRequest.contains("/splash"))
request(fullRequest);
else if (fullRequest.contains("/devices"))
request(fullRequest);
else if (fullRequest.contains("/reload"))
request(fullRequest);
else if (fullRequest.contains("/getoption"))
request(fullRequest);
else if (fullRequest.contains("/binds"))
request(fullRequest);
else if (fullRequest.contains("/cursorpos"))
request(fullRequest);
else if (fullRequest.contains("/animations"))
request(fullRequest);
else if (fullRequest.contains("/globalshortcuts"))
request(fullRequest);
else if (fullRequest.contains("/rollinglog"))
request(fullRequest);
else if (fullRequest.contains("/switchxkblayout")) else if (fullRequest.contains("/switchxkblayout"))
request(fullRequest, 2); request(fullRequest, 2);
else if (fullRequest.contains("/seterror")) else if (fullRequest.contains("/seterror"))
@ -435,15 +400,10 @@ int main(int argc, char** argv) {
request(fullRequest, 2); request(fullRequest, 2);
else if (fullRequest.contains("/decorations")) else if (fullRequest.contains("/decorations"))
request(fullRequest, 1); request(fullRequest, 1);
else if (fullRequest.contains("/hyprpaper"))
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 {
printf("%s\n", USAGE.c_str()); request(fullRequest);
return 1;
} }
printf("\n"); printf("\n");

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,7 @@
#include "progress/CProgressBar.hpp" #include "progress/CProgressBar.hpp"
#include "helpers/Colors.hpp" #include "helpers/Colors.hpp"
#include "core/PluginManager.hpp" #include "core/PluginManager.hpp"
#include "core/DataState.hpp"
#include <iostream> #include <iostream>
#include <vector> #include <vector>
@ -8,21 +9,23 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
const std::string HELP = R"#(usage: hyprpm [flags] [<command> [args]] const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
LISTING COMMANDS: add [url] Install a new plugin repository from git
add: Install a new plugin repository from git remove [url/name] Remove an installed plugin repository
remove: Remove an installed plugin repository enable [name] Enable a plugin
enable: Enable a plugin disable [name] Disable a plugin
disable: Disable a plugin update Check and update all plugins if needed
update: Check and update all plugins if needed reload Reload hyprpm state. Ensure all enabled plugins are loaded.
reload: Rreload hyprpm state. Ensure all enabled plugins are loaded. list List all installed plugins
list: List all installed plugins
FLAGS: Flags:
--notify -> Send a hyprland notification for important events (e.g. load fail)
--help -> display this help --notify | -n Send a hyprland notification for important events (e.g. load fail)
--verbose -> Enable too much logging --help | -h Show this menu
--verbose | -v Enable too much logging
--force | -f Force an operation ignoring checks (e.g. update -f)
)#"; )#";
int main(int argc, char** argv, char** envp) { int main(int argc, char** argv, char** envp) {
@ -37,7 +40,7 @@ int main(int argc, char** argv, char** envp) {
} }
std::vector<std::string> command; std::vector<std::string> command;
bool notify = false, verbose = false; bool notify = false, verbose = false, force = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) { if (ARGS[i].starts_with("-")) {
@ -48,6 +51,9 @@ int main(int argc, char** argv, char** envp) {
notify = true; notify = true;
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") { } else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
verbose = true; verbose = true;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true;
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
} else { } else {
std::cerr << "Unrecognized option " << ARGS[i]; std::cerr << "Unrecognized option " << ARGS[i];
return 1; return 1;
@ -81,9 +87,13 @@ int main(int argc, char** argv, char** envp) {
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1; return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
} else if (command[0] == "update") { } else if (command[0] == "update") {
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK; bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
bool headers = g_pPluginManager->updateHeaders(); bool headers = g_pPluginManager->updateHeaders(force);
if (headers) { if (headers) {
bool ret1 = g_pPluginManager->updatePlugins(!headersValid); const auto HLVER = g_pPluginManager->getHyprlandVersion();
auto GLOBALSTATE = DataState::getGlobalState();
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
bool ret1 = g_pPluginManager->updatePlugins(!headersValid || force || COMPILEDOUTDATED);
if (!ret1) if (!ret1)
return 1; return 1;
@ -145,4 +155,4 @@ int main(int argc, char** argv, char** envp) {
} }
return 0; return 0;
} }

View file

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

View file

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

View file

@ -34,16 +34,17 @@ index 1d2c7f9f..c5ef4e67 100644
headers = globber.stdout().strip().split('\n') headers = globber.stdout().strip().split('\n')
foreach file : headers foreach file : headers
diff --git a/src/meson.build b/src/meson.build diff --git a/src/meson.build b/src/meson.build
index 0af864b9..38723b8c 100644 index 45701f5f..3505cefe 100644
--- a/src/meson.build --- a/src/meson.build
+++ b/src/meson.build +++ b/src/meson.build
@@ -9,16 +9,16 @@ executable('Hyprland', src, @@ -9,17 +9,17 @@ executable('Hyprland', src,
server_protos, server_protos,
dependency('wayland-server'), dependency('wayland-server'),
dependency('wayland-client'), dependency('wayland-client'),
- wlroots.get_variable('wlroots'), - wlroots.get_variable('wlroots'),
+ dependency('wlroots'), + dependency('wlroots'),
dependency('cairo'), dependency('cairo'),
dependency('hyprlang', version: '>= 0.3.2'),
dependency('libdrm'), dependency('libdrm'),
dependency('egl'), dependency('egl'),
dependency('xkbcommon'), dependency('xkbcommon'),

View file

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

View file

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

View file

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

View file

@ -0,0 +1,21 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 857e21de..122d6a78 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -101,7 +101,7 @@ message(STATUS "Checking deps...")
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED)
-pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2) # we do not check for wlroots, as we provide it ourselves
+pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2 libffi) # we do not check for wlroots, as we provide it ourselves
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
@@ -121,6 +121,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Enabling ASan")
target_link_libraries(Hyprland asan)
+ target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/libwayland-server.a)
target_compile_options(Hyprland PUBLIC -fsanitize=address)
endif()

View file

@ -0,0 +1,23 @@
diff --git a/src/meson.build b/src/meson.build
index 5d04334..6645eec 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -170,7 +170,7 @@ if get_option('libraries')
error('We probably need to bump the SONAME of libwayland-server and -client')
endif
- wayland_server = library(
+ wayland_server = static_library(
'wayland-server',
sources: [
wayland_server_protocol_core_h,
@@ -180,9 +180,6 @@ if get_option('libraries')
'wayland-shm.c',
'event-loop.c'
],
- # To avoid an unnecessary SONAME bump, wayland 1.x.y produces
- # libwayland-server.so.0.x.y.
- version: '.'.join(['0', wayland_version[1], wayland_version[2]]),
dependencies: [
epoll_dep,
ffi_dep,

File diff suppressed because it is too large Load diff

View file

@ -21,7 +21,7 @@
#include "debug/HyprDebugOverlay.hpp" #include "debug/HyprDebugOverlay.hpp"
#include "debug/HyprNotificationOverlay.hpp" #include "debug/HyprNotificationOverlay.hpp"
#include "helpers/Monitor.hpp" #include "helpers/Monitor.hpp"
#include "helpers/Workspace.hpp" #include "desktop/Workspace.hpp"
#include "Window.hpp" #include "Window.hpp"
#include "render/Renderer.hpp" #include "render/Renderer.hpp"
#include "render/OpenGL.hpp" #include "render/OpenGL.hpp"
@ -93,9 +93,7 @@ class CCompositor {
std::vector<std::shared_ptr<CMonitor>> m_vMonitors; std::vector<std::shared_ptr<CMonitor>> m_vMonitors;
std::vector<std::shared_ptr<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off std::vector<std::shared_ptr<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
std::vector<std::unique_ptr<CWindow>> m_vWindows; std::vector<std::unique_ptr<CWindow>> m_vWindows;
std::vector<std::unique_ptr<SXDGPopup>> m_vXDGPopups;
std::vector<std::unique_ptr<CWorkspace>> m_vWorkspaces; std::vector<std::unique_ptr<CWorkspace>> m_vWorkspaces;
std::vector<std::unique_ptr<SSubsurface>> m_vSubsurfaces;
std::vector<CWindow*> m_vWindowsFadingOut; std::vector<CWindow*> m_vWindowsFadingOut;
std::vector<SLayerSurface*> m_vSurfacesFadingOut; std::vector<SLayerSurface*> m_vSurfacesFadingOut;
@ -135,16 +133,14 @@ 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* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow" bool monitorExists(CMonitor*);
CWindow* vectorToWindowTiled(const Vector2D&); CWindow* vectorToWindowUnified(const Vector2D&, uint8_t properties, CWindow* pIgnoreWindow = nullptr);
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); 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* windowFloatingFromCursor();
CMonitor* getMonitorFromOutput(wlr_output*); CMonitor* getMonitorFromOutput(wlr_output*);
CWindow* getWindowForPopup(wlr_xdg_popup*); CMonitor* getRealMonitorFromOutput(wlr_output*);
CWindow* getWindowFromSurface(wlr_surface*); CWindow* getWindowFromSurface(wlr_surface*);
CWindow* getWindowFromHandle(uint32_t); CWindow* getWindowFromHandle(uint32_t);
CWindow* getWindowFromZWLRHandle(wl_resource*); CWindow* getWindowFromZWLRHandle(wl_resource*);
@ -172,11 +168,12 @@ class CCompositor {
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
CWindow* getConstraintWindow(SMouse*); CWindow* getConstraintWindow(SMouse*);
CMonitor* getMonitorInDirection(const char&); CMonitor* getMonitorInDirection(const char&);
CMonitor* getMonitorInDirection(CMonitor*, const char&);
void updateAllWindowsAnimatedDecorationValues(); void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const int64_t& id); 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&);
@ -214,6 +211,7 @@ class CCompositor {
private: private:
void initAllSignals(); void initAllSignals();
void removeAllSignals();
void setRandomSplash(); void setRandomSplash();
void initManagers(eManagersInitStage stage); void initManagers(eManagersInitStage stage);
void prepareFallbackOutput(); void prepareFallbackOutput();

View file

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

View file

@ -5,14 +5,14 @@
#include "render/decorations/CHyprBorderDecoration.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(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_vRealSize.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE); m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_fBorderFadeAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER); m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
m_fBorderAngleAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("borderangle"), (void*)this, AVARDAMAGE_BORDER); m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), (void*)this, AVARDAMAGE_BORDER);
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE); m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE); m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE);
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW); m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE); m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this)); addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
addWindowDeco(std::make_unique<CHyprBorderDecoration>(this)); addWindowDeco(std::make_unique<CHyprBorderDecoration>(this));
@ -39,8 +39,8 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
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 {{m_vRealPosition.vec().x - PMONITOR->vecPosition.x, m_vRealPosition.vec().y - PMONITOR->vecPosition.y}, return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition.vec().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.vec().y - PMONITOR->vecPosition.y)}}; {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
} }
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
@ -101,8 +101,8 @@ CBox CWindow::getFullWindowBoundingBox() {
auto maxExtents = getFullWindowExtents(); auto maxExtents = getFullWindowExtents();
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y, CBox finalBox = {m_vRealPosition.value().x - maxExtents.topLeft.x, m_vRealPosition.value().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.value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox; return finalBox;
} }
@ -139,39 +139,29 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
return CBox{(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};
} }
CBox CWindow::getWindowInputBox() { CBox CWindow::getWindowBoxUnified(uint64_t properties) {
const int BORDERSIZE = getRealBorderSize();
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};
} }
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; SWindowDecorationExtents EXTENTS = {{0, 0}, {0, 0}};
if (properties & RESERVED_EXTENTS)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(this));
if (properties & INPUT_EXTENTS)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, true));
if (properties & FULL_EXTENTS)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, false));
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true); CBox box = {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
box.addExtents(EXTENTS);
if (EXTENTS.topLeft.x > maxExtents.topLeft.x) return box;
maxExtents.topLeft.x = EXTENTS.topLeft.x;
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
// Add extents to the real base BB and return
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox;
} }
CBox CWindow::getWindowMainSurfaceBox() { CBox CWindow::getWindowMainSurfaceBox() {
return {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y}; return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
} }
SWindowDecorationExtents CWindow::getFullWindowReservedArea() { SWindowDecorationExtents CWindow::getFullWindowReservedArea() {
@ -318,7 +308,7 @@ void CWindow::destroyToplevelHandle() {
} }
void CWindow::updateToplevel() { void CWindow::updateToplevel() {
updateSurfaceOutputs(); updateSurfaceScaleTransformDetails();
if (!m_phForeignToplevel) if (!m_phForeignToplevel)
return; return;
@ -345,8 +335,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) if (!m_bIsMapped || m_bHidden)
return; return;
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID); const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
@ -355,16 +345,23 @@ void CWindow::updateSurfaceOutputs() {
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled) if (PNEWMONITOR != PLASTMONITOR) {
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output); if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output); wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
}
wlr_surface_for_each_surface( 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_pCompositor->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
const auto PSURFACE = CWLSurface::surfaceFromWlr(surf);
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
return;
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform); g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
}, },
this); this);
@ -374,7 +371,7 @@ 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; static auto* const PCLOSEONLASTSPECIAL = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty");
const int OLDWORKSPACE = m_iWorkspaceID; const int OLDWORKSPACE = m_iWorkspaceID;
@ -395,9 +392,9 @@ void CWindow::moveToWorkspace(int workspaceID) {
} }
// update xwayland coords // update xwayland coords
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec()); g_pXWaylandManager->setWindowSize(this, m_vRealSize.value());
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) { if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && **PCLOSEONLASTSPECIAL) {
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE); const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE);
if (PWS) { if (PWS) {
@ -436,11 +433,11 @@ void CWindow::removeDecorationByType(eDecorationType type) {
} }
void unregisterVar(void* ptr) { void unregisterVar(void* ptr) {
((CAnimatedVariable*)ptr)->unregister(); ((CBaseAnimatedVariable*)ptr)->unregister();
} }
void CWindow::onUnmap() { void CWindow::onUnmap() {
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue; static auto* const PCLOSEONLASTSPECIAL = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty");
if (g_pCompositor->m_pLastWindow == this) if (g_pCompositor->m_pLastWindow == this)
g_pCompositor->m_pLastWindow = nullptr; g_pCompositor->m_pLastWindow = nullptr;
@ -462,7 +459,7 @@ void CWindow::onUnmap() {
hyprListener_unmapWindow.removeCallback(); hyprListener_unmapWindow.removeCallback();
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(m_iWorkspaceID) == 0 && g_pCompositor->isWorkspaceSpecial(m_iWorkspaceID)) { if (**PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(m_iWorkspaceID) == 0 && g_pCompositor->isWorkspaceSpecial(m_iWorkspaceID)) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID) if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
@ -474,12 +471,17 @@ void CWindow::onUnmap() {
PMONITOR->solitaryClient = nullptr; PMONITOR->solitaryClient = nullptr;
g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID); g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID);
if (m_bIsX11)
return;
m_pSubsurfaceHead.reset();
m_pPopupHead.reset();
} }
void CWindow::onMap() { void CWindow::onMap() {
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this)); m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this), 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();
@ -511,10 +513,24 @@ void CWindow::onMap() {
"CWindow"); "CWindow");
m_vReportedSize = m_vPendingReportedSize; m_vReportedSize = m_vPendingReportedSize;
for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) {
if (ctrl->pWlrHint->surface != m_pWLSurface.wlr())
continue;
m_bTearingHint = ctrl->pWlrHint->current;
break;
}
if (m_bIsX11)
return;
m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
m_pPopupHead = std::make_unique<CPopup>(this);
} }
void CWindow::onBorderAngleAnimEnd(void* ptr) { void CWindow::onBorderAngleAnimEnd(void* ptr) {
const auto PANIMVAR = (CAnimatedVariable*)ptr; const auto PANIMVAR = (CAnimatedVariable<float>*)ptr;
const std::string STYLE = PANIMVAR->getConfig()->pValues->internalStyle; const std::string STYLE = PANIMVAR->getConfig()->pValues->internalStyle;
@ -625,23 +641,22 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
if (active && token.contains("deg")) { if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0); activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false; active = false;
} else if (token.contains("deg")) { } else if (token.contains("deg"))
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0); inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
} else if (active) { else if (active)
activeBorderGradient.m_vColors.push_back(configStringToInt(token)); activeBorderGradient.m_vColors.push_back(configStringToInt(token));
} else { else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token)); inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
}
} }
// Includes sanity checks for the number of colors in each gradient // Includes sanity checks for the number of colors in each gradient
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10) { 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); Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
} else if (activeBorderGradient.m_vColors.empty()) { else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule); Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
} else if (inactiveBorderGradient.m_vColors.empty()) { else if (inactiveBorderGradient.m_vColors.empty())
m_sSpecialRenderData.activeBorderColor = activeBorderGradient; m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
} else { else {
m_sSpecialRenderData.activeBorderColor = activeBorderGradient; m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient; m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient;
} }
@ -712,10 +727,10 @@ bool CWindow::isInCurvedCorner(double x, double y) {
return false; return false;
// (x0, y0), (x0, y1), ... are the center point of rounding at each corner // (x0, y0), (x0, y1), ... are the center point of rounding at each corner
double x0 = m_vRealPosition.vec().x + ROUNDING; double x0 = m_vRealPosition.value().x + ROUNDING;
double y0 = m_vRealPosition.vec().y + ROUNDING; double y0 = m_vRealPosition.value().y + ROUNDING;
double x1 = m_vRealPosition.vec().x + m_vRealSize.vec().x - ROUNDING; double x1 = m_vRealPosition.value().x + m_vRealSize.value().x - ROUNDING;
double y1 = m_vRealPosition.vec().y + m_vRealSize.vec().y - ROUNDING; double y1 = m_vRealPosition.value().y + m_vRealSize.value().y - ROUNDING;
if (x < x0 && y < y0) { if (x < x0 && y < y0) {
return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING; return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING;
@ -748,7 +763,7 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
return false; return false;
wlr_surface* resultSurf = nullptr; wlr_surface* resultSurf = nullptr;
Vector2D origin = m_vRealPosition.vec(); Vector2D origin = m_vRealPosition.value();
SExtensionFindingData data = {origin, pos, &resultSurf}; SExtensionFindingData data = {origin, pos, &resultSurf};
wlr_xdg_surface_for_each_popup_surface(m_uSurface.xdg, findExtensionForVector2D, &data); wlr_xdg_surface_for_each_popup_surface(m_uSurface.xdg, findExtensionForVector2D, &data);
@ -887,8 +902,8 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
const bool FULLSCREEN = PCURRENT->m_bIsFullscreen; const bool FULLSCREEN = PCURRENT->m_bIsFullscreen;
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PCURRENT->m_iWorkspaceID); const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PCURRENT->m_iWorkspaceID);
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goalv(); const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goalv(); const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow; const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow;
@ -982,19 +997,19 @@ void CWindow::updateGroupOutputs() {
curr->m_iMonitorID = m_iMonitorID; curr->m_iMonitorID = m_iMonitorID;
curr->moveToWorkspace(m_iWorkspaceID); curr->moveToWorkspace(m_iWorkspaceID);
curr->m_vRealPosition = m_vRealPosition.goalv(); curr->m_vRealPosition = m_vRealPosition.goal();
curr->m_vRealSize = m_vRealSize.goalv(); curr->m_vRealSize = m_vRealSize.goal();
curr = curr->m_sGroupData.pNextWindow; curr = curr->m_sGroupData.pNextWindow;
} }
} }
Vector2D CWindow::middle() { Vector2D CWindow::middle() {
return m_vRealPosition.goalv() + m_vRealSize.goalv() / 2.f; return m_vRealPosition.goal() + m_vRealSize.goal() / 2.f;
} }
bool CWindow::opaque() { bool CWindow::opaque() {
if (m_fAlpha.fl() != 1.f || m_fActiveInactiveAlpha.fl() != 1.f) if (m_fAlpha.value() != 1.f || m_fActiveInactiveAlpha.value() != 1.f)
return false; return false;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
@ -1002,7 +1017,7 @@ bool CWindow::opaque() {
if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall) if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall)
return false; return false;
if (PWORKSPACE->m_fAlpha.fl() != 1.f) if (PWORKSPACE->m_fAlpha.value() != 1.f)
return false; return false;
if (m_bIsX11) if (m_bIsX11)
@ -1019,19 +1034,21 @@ bool CWindow::opaque() {
} }
float CWindow::rounding() { float CWindow::rounding() {
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; static auto* const PROUNDING = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:rounding");
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying(); float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? **PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
return m_sSpecialRenderData.rounding ? rounding : 0; return m_sSpecialRenderData.rounding ? rounding : 0;
} }
void CWindow::updateSpecialRenderData() { void CWindow::updateSpecialRenderData() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
bool border = true; bool border = true;
if (m_bIsFloating && g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue == 1) static auto* const* PNOBORDERONFLOATING = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:no_border_on_floating");
if (m_bIsFloating && **PNOBORDERONFLOATING == 1)
border = false; border = false;
m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(border); m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(border);
@ -1051,16 +1068,18 @@ int CWindow::getRealBorderSize() {
if (m_sSpecialRenderData.borderSize.toUnderlying() != -1) if (m_sSpecialRenderData.borderSize.toUnderlying() != -1)
return m_sSpecialRenderData.borderSize.toUnderlying(); return m_sSpecialRenderData.borderSize.toUnderlying();
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; static auto* const* PBORDERSIZE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:border_size");
return **PBORDERSIZE;
} }
bool CWindow::canBeTorn() { bool CWindow::canBeTorn() {
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied; return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint);
} }
bool CWindow::shouldSendFullscreenState() { bool CWindow::shouldSendFullscreenState() {
const auto MODE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID)->m_efFullscreenMode; const auto MODE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID)->m_efFullscreenMode;
return m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL)); return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL)));
} }
void CWindow::setSuspended(bool suspend) { void CWindow::setSuspended(bool suspend) {

View file

@ -1,13 +1,14 @@
#pragma once #pragma once
#include "defines.hpp" #include "defines.hpp"
#include "helpers/SubsurfaceTree.hpp" #include "desktop/Subsurface.hpp"
#include "helpers/AnimatedVariable.hpp" #include "helpers/AnimatedVariable.hpp"
#include "render/decorations/IHyprWindowDecoration.hpp" #include "render/decorations/IHyprWindowDecoration.hpp"
#include <deque> #include <deque>
#include "config/ConfigDataValues.hpp" #include "config/ConfigDataValues.hpp"
#include "helpers/Vector2D.hpp" #include "helpers/Vector2D.hpp"
#include "helpers/WLSurface.hpp" #include "desktop/WLSurface.hpp"
#include "desktop/Popup.hpp"
#include "macros.hpp" #include "macros.hpp"
#include "managers/XWaylandManager.hpp" #include "managers/XWaylandManager.hpp"
@ -30,6 +31,24 @@ enum eGroupRules {
GROUP_OVERRIDE = 1 << 6, // Override other rules GROUP_OVERRIDE = 1 << 6, // Override other rules
}; };
enum eGetWindowProperties {
WINDOW_ONLY = 0,
RESERVED_EXTENTS = 1 << 0,
INPUT_EXTENTS = 1 << 1,
FULL_EXTENTS = 1 << 2,
FLOATING_ONLY = 1 << 3,
ALLOW_FLOATING = 1 << 4,
USE_PROP_TILED = 1 << 5,
};
enum eSuppressEvents {
SUPPRESS_NONE = 0,
SUPPRESS_FULLSCREEN = 1 << 0,
SUPPRESS_MAXIMIZE = 1 << 1,
SUPPRESS_ACTIVATE = 1 << 2,
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
};
class IWindowTransformer; class IWindowTransformer;
template <typename T> template <typename T>
@ -133,6 +152,7 @@ struct SWindowAdditionalConfigData {
CWindowOverridableVar<bool> forceNoBorder = false; CWindowOverridableVar<bool> forceNoBorder = false;
CWindowOverridableVar<bool> forceNoShadow = false; CWindowOverridableVar<bool> forceNoShadow = false;
CWindowOverridableVar<bool> forceNoDim = false; CWindowOverridableVar<bool> forceNoDim = false;
CWindowOverridableVar<bool> noFocus = false;
CWindowOverridableVar<bool> windowDanceCompat = false; CWindowOverridableVar<bool> windowDanceCompat = false;
CWindowOverridableVar<bool> noMaxSize = false; CWindowOverridableVar<bool> noMaxSize = false;
CWindowOverridableVar<bool> dimAround = false; CWindowOverridableVar<bool> dimAround = false;
@ -174,7 +194,6 @@ class CWindow {
DYNLISTENER(setTitleWindow); DYNLISTENER(setTitleWindow);
DYNLISTENER(setGeometryX11U); DYNLISTENER(setGeometryX11U);
DYNLISTENER(fullscreenWindow); DYNLISTENER(fullscreenWindow);
DYNLISTENER(newPopupXDG);
DYNLISTENER(requestMove); DYNLISTENER(requestMove);
DYNLISTENER(requestMinimize); DYNLISTENER(requestMinimize);
DYNLISTENER(requestMaximize); DYNLISTENER(requestMaximize);
@ -190,8 +209,7 @@ class CWindow {
DYNLISTENER(ackConfigure); DYNLISTENER(ackConfigure);
// DYNLISTENER(newSubsurfaceWindow); // DYNLISTENER(newSubsurfaceWindow);
CWLSurface m_pWLSurface; CWLSurface m_pWLSurface;
std::list<CWLSurface> m_lPopupSurfaces;
union { union {
wlr_xdg_surface* xdg; wlr_xdg_surface* xdg;
@ -203,8 +221,8 @@ class CWindow {
Vector2D m_vSize = Vector2D(0, 0); Vector2D m_vSize = Vector2D(0, 0);
// this is the real position and size used to draw the thing // this is the real position and size used to draw the thing
CAnimatedVariable m_vRealPosition; CAnimatedVariable<Vector2D> m_vRealPosition;
CAnimatedVariable m_vRealSize; CAnimatedVariable<Vector2D> m_vRealSize;
// for not spamming the protocols // for not spamming the protocols
Vector2D m_vReportedPosition; Vector2D m_vReportedPosition;
@ -221,16 +239,17 @@ class CWindow {
bool m_bIsPseudotiled = false; bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(0, 0); Vector2D m_vPseudoSize = Vector2D(0, 0);
bool m_bFirstMap = false; // for layouts bool m_bFirstMap = false; // for layouts
bool m_bIsFloating = false; bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bIsFullscreen = false; bool m_bIsFullscreen = false;
bool m_bWasMaximized = false; bool m_bDontSendFullscreen = false;
uint64_t m_iMonitorID = -1; bool m_bWasMaximized = false;
std::string m_szTitle = ""; uint64_t m_iMonitorID = -1;
std::string m_szInitialTitle = ""; std::string m_szTitle = "";
std::string m_szInitialClass = ""; std::string m_szInitialTitle = "";
int m_iWorkspaceID = -1; std::string m_szInitialClass = "";
int m_iWorkspaceID = -1;
bool m_bIsMapped = false; bool m_bIsMapped = false;
@ -250,24 +269,26 @@ class CWindow {
// //
// For nofocus // For nofocus
bool m_bNoFocus = false;
bool m_bNoInitialFocus = false; bool m_bNoInitialFocus = false;
// Fullscreen and Maximize // Fullscreen and Maximize
bool m_bWantsInitialFullscreen = false; bool m_bWantsInitialFullscreen = false;
bool m_bNoFullscreenRequest = false;
bool m_bNoMaximizeRequest = false;
SSurfaceTreeNode* m_pSurfaceTree = nullptr; // bitfield eSuppressEvents
uint64_t m_eSuppressedEvents = SUPPRESS_NONE;
// desktop components
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
std::unique_ptr<CPopup> m_pPopupHead;
// Animated border // Animated border
CGradientValueData m_cRealBorderColor = {0}; CGradientValueData m_cRealBorderColor = {0};
CGradientValueData m_cRealBorderColorPrevious = {0}; CGradientValueData m_cRealBorderColorPrevious = {0};
CAnimatedVariable m_fBorderFadeAnimationProgress; CAnimatedVariable<float> m_fBorderFadeAnimationProgress;
CAnimatedVariable m_fBorderAngleAnimationProgress; CAnimatedVariable<float> m_fBorderAngleAnimationProgress;
// Fade in-out // Fade in-out
CAnimatedVariable m_fAlpha; CAnimatedVariable<float> m_fAlpha;
bool m_bFadingOut = false; bool m_bFadingOut = false;
bool m_bReadyToDelete = false; bool m_bReadyToDelete = false;
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
@ -301,13 +322,13 @@ class CWindow {
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers; std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
// for alpha // for alpha
CAnimatedVariable m_fActiveInactiveAlpha; CAnimatedVariable<float> m_fActiveInactiveAlpha;
// animated shadow color // animated shadow color
CAnimatedVariable m_cRealShadowColor; CAnimatedVariable<CColor> m_cRealShadowColor;
// animated tint // animated tint
CAnimatedVariable m_fDimPercent; CAnimatedVariable<float> m_fDimPercent;
// swallowing // swallowing
CWindow* m_pSwallowed = nullptr; CWindow* m_pSwallowed = nullptr;
@ -342,7 +363,7 @@ class CWindow {
// methods // methods
CBox getFullWindowBoundingBox(); CBox getFullWindowBoundingBox();
SWindowDecorationExtents getFullWindowExtents(); SWindowDecorationExtents getFullWindowExtents();
CBox getWindowInputBox(); CBox getWindowBoxUnified(uint64_t props);
CBox getWindowMainSurfaceBox(); CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved(); CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco); void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
@ -356,7 +377,7 @@ class CWindow {
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();

View file

@ -1,10 +1,12 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/VarList.hpp"
#include <vector> #include <vector>
enum eConfigValueDataTypes { enum eConfigValueDataTypes {
CVD_TYPE_INVALID = -1, CVD_TYPE_INVALID = -1,
CVD_TYPE_GRADIENT = 0 CVD_TYPE_GRADIENT = 0,
CVD_TYPE_CSS_VALUE = 1
}; };
class ICustomConfigValueData { class ICustomConfigValueData {
@ -50,3 +52,55 @@ class CGradientValueData : public ICustomConfigValueData {
return true; return true;
} }
}; };
class CCssGapData : public ICustomConfigValueData {
public:
CCssGapData() : top(0), right(0), bottom(0), left(0){};
CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global){};
CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal){};
CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : top(top), right(horizontal), bottom(bottom), left(horizontal){};
CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : top(top), right(right), bottom(bottom), left(left){};
/* Css like directions */
int64_t top;
int64_t right;
int64_t bottom;
int64_t left;
void parseGapData(CVarList varlist) {
switch (varlist.size()) {
case 1: {
*this = CCssGapData(std::stoi(varlist[0]));
break;
}
case 2: {
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]));
break;
}
case 3: {
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]), std::stoi(varlist[2]));
break;
}
case 4: {
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]), std::stoi(varlist[2]), std::stoi(varlist[3]));
break;
}
default: {
Debug::log(WARN, "Too many arguments provided for gaps.");
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]), std::stoi(varlist[2]), std::stoi(varlist[3]));
break;
}
}
}
void reset(int64_t global) {
top = global;
right = global;
bottom = global;
left = global;
}
virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_CSS_VALUE;
}
};

File diff suppressed because it is too large Load diff

View file

@ -21,21 +21,13 @@
#include "defaultConfig.hpp" #include "defaultConfig.hpp"
#include "ConfigDataValues.hpp" #include "ConfigDataValues.hpp"
#include <hyprlang.hpp>
#define INITANIMCFG(name) animationConfig[name] = {} #define INITANIMCFG(name) animationConfig[name] = {}
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]} #define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
#define HANDLE void* #define HANDLE void*
struct SConfigValue {
int64_t intValue = -INT64_MAX;
float floatValue = -__FLT_MAX__;
std::string strValue = "";
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
std::shared_ptr<ICustomConfigValueData> data;
bool set = false; // used for device configs
};
struct SWorkspaceRule { struct SWorkspaceRule {
std::string monitor = ""; std::string monitor = "";
std::string workspaceString = ""; std::string workspaceString = "";
@ -43,14 +35,15 @@ struct SWorkspaceRule {
int workspaceId = -1; int workspaceId = -1;
bool isDefault = false; bool isDefault = false;
bool isPersistent = false; bool isPersistent = false;
std::optional<int64_t> gapsIn; std::optional<CCssGapData> gapsIn;
std::optional<int64_t> gapsOut; std::optional<CCssGapData> gapsOut;
std::optional<int64_t> borderSize; std::optional<int64_t> borderSize;
std::optional<int> border; std::optional<int> border;
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::optional<std::string> onCreatedEmptyRunCmd;
std::optional<std::string> defaultName;
std::map<std::string, std::string> layoutopts; std::map<std::string, std::string> layoutopts;
}; };
@ -74,9 +67,14 @@ struct SAnimationPropertyConfig {
}; };
struct SPluginKeyword { struct SPluginKeyword {
HANDLE handle = 0; HANDLE handle = 0;
std::string name = ""; std::string name = "";
std::function<void(const std::string&, const std::string&)> fn; Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
};
struct SPluginVariable {
HANDLE handle = 0;
std::string name = "";
}; };
struct SExecRequestedRule { struct SExecRequestedRule {
@ -91,28 +89,21 @@ class CConfigManager {
void tick(); void tick();
void init(); void init();
int getInt(const std::string&);
float getFloat(const std::string&);
Vector2D getVec(const std::string&);
std::string getString(const std::string&);
void setFloat(const std::string&, float);
void setInt(const std::string&, int);
void setVec(const std::string&, Vector2D);
void setString(const std::string&, const std::string&);
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = ""); 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 = ""); 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&);
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
bool shouldBlurLS(const std::string&); bool shouldBlurLS(const std::string&);
SConfigValue* getConfigValuePtr(const std::string&); void* const* getConfigValuePtr(const std::string&);
SConfigValue* getConfigValuePtrSafe(const std::string&); Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load);
static std::string getConfigDir(); static std::string getConfigDir();
static std::string getMainConfigPath(); static std::string getMainConfigPath();
SMonitorRule getMonitorRuleFor(const std::string&, const std::string& displayName = ""); SMonitorRule getMonitorRuleFor(const CMonitor&);
SWorkspaceRule getWorkspaceRuleFor(CWorkspace*); SWorkspaceRule getWorkspaceRuleFor(CWorkspace*);
std::string getDefaultWorkspaceFor(const std::string&); std::string getDefaultWorkspaceFor(const std::string&);
@ -120,15 +111,15 @@ class CConfigManager {
std::string getBoundMonitorStringForWS(const std::string&); std::string getBoundMonitorStringForWS(const std::string&);
const std::deque<SWorkspaceRule>& getAllWorkspaceRules(); const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
std::vector<SWindowRule> getMatchingRules(CWindow*); std::vector<SWindowRule> getMatchingRules(CWindow*, bool dynamic = true);
std::vector<SLayerRule> getMatchingRules(SLayerSurface*); std::vector<SLayerRule> getMatchingRules(SLayerSurface*);
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas; std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
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 Hyprlang::CConfigValue& value);
void addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& cmd, const std::string& val)> fun); void addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fun, Hyprlang::SHandlerOptions opts = {});
void removePluginConfig(HANDLE handle); void removePluginConfig(HANDLE handle);
// no-op when done. // no-op when done.
@ -141,7 +132,7 @@ class CConfigManager {
void ensureMonitorStatus(); void ensureMonitorStatus();
void ensureVRR(CMonitor* pMonitor = nullptr); void ensureVRR(CMonitor* pMonitor = nullptr);
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false); std::string parseKeyword(const std::string&, const std::string&);
void addParseError(const std::string&); void addParseError(const std::string&);
@ -151,77 +142,65 @@ class CConfigManager {
void handlePluginLoads(); void handlePluginLoads();
std::string configCurrentPath; // keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::string configCurrentPath;
private: private:
std::deque<std::string> configPaths; // stores all the config paths std::unique_ptr<Hyprlang::CConfig> m_pConfig;
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
std::vector<std::pair<std::string, std::string>> configDynamicVars; // stores dynamic vars declared by the user
std::unordered_map<std::string, SConfigValue> configValues;
std::unordered_map<std::string, std::unordered_map<std::string, SConfigValue>> deviceConfigs; // stores device configs
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
std::string currentCategory = ""; // For storing the category of the current item std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
std::string parseError = ""; // For storing a parse error to display later std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty std::vector<std::string> m_vDeclaredPlugins;
std::vector<SPluginKeyword> pluginKeywords;
std::vector<SPluginVariable> pluginVariables;
std::vector<std::string> m_vDeclaredPlugins; bool isFirstLaunch = true; // For exec-once
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 std::deque<SMonitorRule> m_dMonitorRules;
std::deque<SWorkspaceRule> m_dWorkspaceRules;
std::deque<SWindowRule> m_dWindowRules;
std::deque<SLayerRule> m_dLayerRules;
std::deque<std::string> m_dBlurLSNamespaces;
std::deque<SMonitorRule> m_dMonitorRules; bool firstExecDispatched = false;
std::deque<SWorkspaceRule> m_dWorkspaceRules; bool m_bManualCrashInitiated = false;
std::deque<SWindowRule> m_dWindowRules; std::deque<std::string> firstExecRequests;
std::deque<SLayerRule> m_dLayerRules;
std::deque<std::string> m_dBlurLSNamespaces;
bool firstExecDispatched = false; std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
bool m_bManualCrashInitiated = false;
std::deque<std::string> firstExecRequests;
std::vector<std::pair<std::string, std::string>> environmentVariables;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
// internal methods // internal methods
void setDefaultVars(); void setAnimForChildren(SAnimationPropertyConfig* const);
void setDefaultAnimationVars(); void updateBlurredLS(const std::string&, const bool);
void setDeviceDefaultVars(const std::string&); void setDefaultAnimationVars();
void populateEnvironment(); std::optional<std::string> resetHLConfig();
std::optional<std::string> verifyConfigExists();
void setAnimForChildren(SAnimationPropertyConfig* const); void postConfigReload(const Hyprlang::CParseResult& result);
void updateBlurredLS(const std::string&, const bool); void reload();
void applyUserDefinedVars(std::string&, const size_t);
void loadConfigLoadVars();
SConfigValue getConfigValueSafe(const std::string&);
SConfigValue getConfigValueSafeDevice(const std::string&, const std::string&, const std::string& fallback = "");
void parseLine(std::string&);
void configSetValueSafe(const std::string&, const std::string&);
void handleDeviceConfig(const std::string&, const std::string&);
void handleRawExec(const std::string&, const std::string&);
void handleMonitor(const std::string&, const std::string&);
void handleBind(const std::string&, const std::string&);
void handleUnbind(const std::string&, const std::string&);
void handleWindowRule(const std::string&, const std::string&);
void handleLayerRule(const std::string&, const std::string&);
void handleWindowRuleV2(const std::string&, const std::string&);
void handleWorkspaceRules(const std::string&, const std::string&);
void handleBezier(const std::string&, const std::string&);
void handleAnimation(const std::string&, const std::string&);
void handleSource(const std::string&, const std::string&);
void handleSubmap(const std::string&, const std::string&);
void handleBlurLS(const std::string&, const std::string&);
void handleBindWS(const std::string&, const std::string&);
void handleEnv(const std::string&, const std::string&);
void handlePlugin(const std::string&, const std::string&);
}; };
inline std::unique_ptr<CConfigManager> g_pConfigManager; inline std::unique_ptr<CConfigManager> g_pConfigManager;

View file

@ -3,11 +3,11 @@
#include <string> #include <string>
inline const std::string AUTOCONFIG = R"#( inline const std::string AUTOCONFIG = R"#(
######################################################################################## # #######################################################################################
AUTOGENERATED HYPR CONFIG. # AUTOGENERATED HYPR CONFIG.
PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT, # PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS. # OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
######################################################################################## # #######################################################################################
# #
# Please note not all available settings / options are set here. # Please note not all available settings / options are set here.
@ -51,7 +51,7 @@ input {
natural_scroll = no natural_scroll = no
} }
sensitivity = 0 # -1.0 - 1.0, 0 means no modification. sensitivity = 0 # -1.0 to 1.0, 0 means no modification.
} }
general { general {
@ -119,12 +119,13 @@ gestures {
misc { misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more # See https://wiki.hyprland.org/Configuring/Variables/ for more
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
} }
# Example per-device config # 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 {
name = epic-mouse-v1
sensitivity = -0.5 sensitivity = -0.5
} }
@ -133,7 +134,7 @@ 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. windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
# See https://wiki.hyprland.org/Configuring/Keywords/ for more # See https://wiki.hyprland.org/Configuring/Keywords/ for more

View file

@ -3,6 +3,7 @@
#include <sys/utsname.h> #include <sys/utsname.h>
#include <fstream> #include <fstream>
#include <signal.h> #include <signal.h>
#include <link.h>
#include "../plugins/PluginSystem.hpp" #include "../plugins/PluginSystem.hpp"
@ -105,21 +106,38 @@ void CrashReporter::createAndSaveCrash(int sig) {
const auto FPATH = std::filesystem::canonical("/proc/self/exe"); const auto FPATH = std::filesystem::canonical("/proc/self/exe");
#endif #endif
std::string addrs = "";
for (size_t i = 0; i < CALLSTACK.size(); ++i) { for (size_t i = 0; i < CALLSTACK.size(); ++i) {
finalCrashReport += std::format("\t#{} | {}\n", i, CALLSTACK[i].desc); // convert in memory address to VMA address
Dl_info info;
struct link_map* linkMap;
dladdr1((void*)CALLSTACK[i].adr, &info, (void**)&linkMap, RTLD_DL_LINKMAP);
size_t vmaAddr = (size_t)CALLSTACK[i].adr - linkMap->l_addr;
addrs += std::format("0x{:x} ", vmaAddr);
}
#ifdef __clang__ #ifdef __clang__
const auto CMD = std::format("llvm-addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr); const auto CMD = std::format("llvm-addr2line -e {} -Cf {}", FPATH.c_str(), addrs);
#else #else
const auto CMD = std::format("addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr); const auto CMD = std::format("addr2line -e {} -Cf {}", FPATH.c_str(), addrs);
#endif #endif
const auto ADDR2LINE = replaceInString(execAndGet(CMD.c_str()), "\n", "\n\t\t");
finalCrashReport += "\t\t" + ADDR2LINE.substr(0, ADDR2LINE.length() - 2); const auto ADDR2LINE = execAndGet(CMD.c_str());
std::stringstream ssin(ADDR2LINE);
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
finalCrashReport += std::format("\t#{} | {}", i, CALLSTACK[i].desc);
std::string functionInfo;
std::string fileLineInfo;
std::getline(ssin, functionInfo);
std::getline(ssin, fileLineInfo);
finalCrashReport += std::format("\n\t\t{}\n\t\t{}\n", functionInfo, fileLineInfo);
} }
finalCrashReport += "\n\nLog tail:\n"; finalCrashReport += "\n\nLog tail:\n";
finalCrashReport += Debug::rollingLog; finalCrashReport += Debug::rollingLog.substr(Debug::rollingLog.find("\n") + 1);
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");
@ -128,21 +146,18 @@ void CrashReporter::createAndSaveCrash(int sig) {
return; return;
std::ofstream ofs; std::ofstream ofs;
std::string path; std::string reportDir;
if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland"))
std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt"; if (!CACHE_HOME || std::string(CACHE_HOME).empty())
ofs.open(path, std::ios::trunc); reportDir = std::string(HOME) + "/.cache/hyprland";
else
reportDir = std::string(CACHE_HOME) + "/hyprland";
} else { if (!std::filesystem::exists(reportDir))
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) std::filesystem::create_directory(reportDir);
std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland"); const auto path = reportDir + "/hyprlandCrashReport" + std::to_string(PID) + ".txt";
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt"; ofs.open(path, std::ios::trunc);
ofs.open(path, std::ios::trunc);
}
ofs << finalCrashReport; ofs << finalCrashReport;

View file

@ -7,12 +7,13 @@
#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 <sstream> #include <sstream>
#include <string> #include <string>
#include <typeindex>
static void trimTrailingComma(std::string& str) { static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',') if (!str.empty() && str.back() == ',')
@ -28,7 +29,7 @@ static std::string getWorkspaceNameFromSpecialID(const int workspaceID) {
return workspace->m_szName; return workspace->m_szName;
} }
std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) { std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
auto allMonitors = false; auto allMonitors = false;
@ -39,7 +40,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
allMonitors = true; allMonitors = true;
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
@ -75,7 +76,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
"vrr": {}, "vrr": {},
"activelyTearing": {} "activelyTearing": {}
}},)#", }},)#",
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szDescription), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, (m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
m->activeWorkspace, (m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID, m->activeWorkspace, (m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID,
escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
@ -97,7 +98,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
"workspace: {} ({})\n\treserved: {} " "workspace: {} ({})\n\treserved: {} "
"{} {} {}\n\tscale: {:.2f}\n\ttransform: " "{} {} {}\n\tscale: {:.2f}\n\ttransform: "
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\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->szDescription, m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspace, (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspace,
(m->activeWorkspace == -1 ? "" : g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName), m->specialWorkspaceID, (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,
@ -109,8 +110,8 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
return result; return result;
} }
static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) { static std::string getGroupedData(CWindow* w, eHyprCtlOutputFormat format) {
const bool isJson = format == HyprCtl::FORMAT_JSON; const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON;
if (!w->m_sGroupData.pNextWindow) if (!w->m_sGroupData.pNextWindow)
return isJson ? "" : "0"; return isJson ? "" : "0";
@ -133,7 +134,7 @@ static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat form
return result.str(); return result.str();
} }
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) { static std::string getWindowData(CWindow* w, eHyprCtlOutputFormat format) {
auto getFocusHistoryID = [](CWindow* wnd) -> int { auto getFocusHistoryID = [](CWindow* wnd) -> int {
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) { for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) {
if (g_pCompositor->m_vWindowFocusHistory[i] == wnd) if (g_pCompositor->m_vWindowFocusHistory[i] == wnd)
@ -142,7 +143,7 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
return -1; return -1;
}; };
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
return std::format( return std::format(
R"#({{ R"#({{
"address": "0x{:x}", "address": "0x{:x}",
@ -170,8 +171,8 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
"swallowing": "0x{:x}", "swallowing": "0x{:x}",
"focusHistoryID": {} "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.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_iWorkspaceID,
escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" :
g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName :
std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))), std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))),
@ -186,8 +187,8 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
"{}\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\tfocusHistoryID: {}\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.goal().x, (int)w->m_vRealPosition.goal().y, (int)w->m_vRealSize.goal().x,
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID, (int)w->m_vRealSize.goal().y, w->m_iWorkspaceID,
(w->m_iWorkspaceID == -1 ? "" : (w->m_iWorkspaceID == -1 ? "" :
g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName :
std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))), std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))),
@ -198,9 +199,9 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
} }
} }
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
@ -218,10 +219,10 @@ std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result; return result;
} }
static std::string getWorkspaceData(CWorkspace* w, HyprCtl::eHyprCtlOutputFormat format) { static std::string getWorkspaceData(CWorkspace* w, eHyprCtlOutputFormat format) {
const auto PLASTW = w->getLastFocusedWindow(); const auto PLASTW = w->getLastFocusedWindow();
const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID);
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
return std::format(R"#({{ return std::format(R"#({{
"id": {}, "id": {},
"name": "{}", "name": "{}",
@ -242,14 +243,18 @@ static std::string getWorkspaceData(CWorkspace* w, HyprCtl::eHyprCtlOutputFormat
} }
} }
static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprCtlOutputFormat format) { static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputFormat format) {
const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; }; const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; };
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor)); const std::string 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 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 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 gapsIn = (bool)(r.gapsIn) ?
const std::string gapsOut = (bool)(r.gapsOut) ? std::format(",\n \"gapsOut\": {}", r.gapsOut.value()) : ""; std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().top, r.gapsIn.value().right, r.gapsIn.value().bottom, r.gapsIn.value().left) :
"";
const std::string gapsOut = (bool)(r.gapsOut) ?
std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) :
"";
const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : ""; const std::string 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 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 rounding = (bool)(r.rounding) ? std::format(",\n \"rounding\": {}", boolToString(r.rounding.value())) : "";
@ -266,8 +271,12 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "<unset>" : escapeJSONStrings(r.monitor)); const std::string 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 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 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 gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().top), std::to_string(r.gapsIn.value().right),
const std::string gapsOut = std::format("\tgapsOut: {}\n", (bool)(r.gapsOut) ? std::to_string(r.gapsOut.value()) : "<unset>"); std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) :
std::format("\tgapsIn: <unset>\n");
const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().top), std::to_string(r.gapsOut.value().right),
std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) :
std::format("\tgapsOut: <unset>\n");
const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>"); const std::string 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 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 rounding = std::format("\trounding: {}\n", (bool)(r.rounding) ? boolToString(r.rounding.value()) : "<unset>");
@ -280,7 +289,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
return result; return result;
} }
} }
std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_pLastMonitor)
return "unsafe state"; return "unsafe state";
@ -293,10 +302,10 @@ std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
return getWorkspaceData(w, format); return getWorkspaceData(w, format);
} }
std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getWorkspaceData(w.get(), format); result += getWorkspaceData(w.get(), format);
@ -314,9 +323,9 @@ std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result; return result;
} }
std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto& r : g_pConfigManager->getAllWorkspaceRules()) { for (auto& r : g_pConfigManager->getAllWorkspaceRules()) {
result += getWorkspaceRuleData(r, format); result += getWorkspaceRuleData(r, format);
@ -334,24 +343,24 @@ std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result; return result;
} }
std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) {
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!g_pCompositor->windowValidMapped(PWINDOW))
return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid"; return format == eHyprCtlOutputFormat::FORMAT_JSON ? "{}" : "Invalid";
auto result = getWindowData(PWINDOW, format); auto result = getWindowData(PWINDOW, format);
if (format == HyprCtl::FORMAT_JSON) if (format == eHyprCtlOutputFormat::FORMAT_JSON)
result.pop_back(); result.pop_back();
return result; return result;
} }
std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n"; result += "{\n";
for (auto& mon : g_pCompositor->m_vMonitors) { for (auto& mon : g_pCompositor->m_vMonitors) {
@ -422,9 +431,9 @@ std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result; return result;
} }
std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto& m : g_pLayoutManager->getAllLayoutNames()) { for (auto& m : g_pLayoutManager->getAllLayoutNames()) {
@ -444,10 +453,10 @@ std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result; return result;
} }
std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n"; result += "{\n";
result += "\"mice\": [\n"; result += "\"mice\": [\n";
@ -603,9 +612,9 @@ std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result; return result;
} }
std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = ""; std::string ret = "";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
ret += "animations:\n"; ret += "animations:\n";
for (auto& ac : g_pConfigManager->getAnimationConfig()) { for (auto& ac : g_pConfigManager->getAnimationConfig()) {
@ -656,10 +665,10 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret; return ret;
} }
std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[\n\"log\":\""; result += "[\n\"log\":\"";
result += escapeJSONStrings(Debug::rollingLog); result += escapeJSONStrings(Debug::rollingLog);
result += "\"]"; result += "\"]";
@ -670,10 +679,10 @@ std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result; return result;
} }
std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = ""; std::string ret = "";
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts(); const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts();
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto& sh : SHORTCUTS) for (auto& sh : SHORTCUTS)
ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description);
} else { } else {
@ -693,9 +702,9 @@ std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret; return ret;
} }
std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = ""; std::string ret = "";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto& kb : g_pKeybindManager->m_lKeybinds) { for (auto& kb : g_pKeybindManager->m_lKeybinds) {
ret += "bind"; ret += "bind";
if (kb.locked) if (kb.locked)
@ -741,12 +750,12 @@ std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret; return ret;
} }
std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
auto commitMsg = removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE); auto commitMsg = removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE);
std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' ');
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg +
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + "\n\nflags: (if any)\n"; ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + "\n\nflags: (if any)\n";
@ -793,7 +802,40 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ""; // make the compiler happy return ""; // make the compiler happy
} }
std::string dispatchRequest(std::string in) { std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "");
result += "\n\nSystem Information:\n";
struct utsname unameInfo;
uname(&unameInfo);
result += "System name: " + std::string{unameInfo.sysname} + "\n";
result += "Node name: " + std::string{unameInfo.nodename} + "\n";
result += "Release: " + std::string{unameInfo.release} + "\n";
result += "Version: " + std::string{unameInfo.version} + "\n";
result += "\n\n";
#if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
#else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif
result += "GPU information: \n" + GPUINFO + "\n\n";
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
result += "plugins:\n";
for (auto& pl : g_pPluginSystem->getAllPlugins()) {
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
}
return result;
}
std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) {
// get rid of the dispatch keyword // get rid of the dispatch keyword
in = in.substr(in.find_first_of(' ') + 1); in = in.substr(in.find_first_of(' ') + 1);
@ -814,7 +856,7 @@ std::string dispatchRequest(std::string in) {
return "ok"; return "ok";
} }
std::string dispatchKeyword(std::string in) { std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
// get rid of the keyword keyword // get rid of the keyword keyword
in = in.substr(in.find_first_of(' ') + 1); in = in.substr(in.find_first_of(' ') + 1);
@ -822,32 +864,35 @@ std::string dispatchKeyword(std::string in) {
const auto VALUE = in.substr(in.find_first_of(' ') + 1); const auto VALUE = in.substr(in.find_first_of(' ') + 1);
std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE, true); std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE);
if (COMMAND == "monitor") // if we are executing a dynamic source we have to reload everything, so every if will have a check for source.
if (COMMAND == "monitor" || COMMAND == "source")
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords
if (COMMAND.contains("input") || COMMAND.contains("device:")) { if (COMMAND.contains("input") || COMMAND.contains("device") || COMMAND == "source") {
g_pInputManager->setKeyboardLayout(); // update kb layout g_pInputManager->setKeyboardLayout(); // update kb layout
g_pInputManager->setPointerConfigs(); // update mouse cfgs g_pInputManager->setPointerConfigs(); // update mouse cfgs
g_pInputManager->setTouchDeviceConfigs(); // update touch device cfgs g_pInputManager->setTouchDeviceConfigs(); // update touch device cfgs
g_pInputManager->setTabletConfigs(); // update tablets g_pInputManager->setTabletConfigs(); // update tablets
} }
if (COMMAND.contains("general:layout")) static auto* const PLAYOUT = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("general:layout");
g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout
if (COMMAND.contains("decoration:screen_shader")) if (COMMAND.contains("general:layout"))
g_pLayoutManager->switchToLayout(*PLAYOUT); // update layout
if (COMMAND.contains("decoration:screen_shader") || COMMAND == "source")
g_pHyprOpenGL->m_bReloadScreenShader = true; g_pHyprOpenGL->m_bReloadScreenShader = true;
if (COMMAND.contains("blur")) { if (COMMAND.contains("blur") || COMMAND == "source") {
for (auto& [m, rd] : g_pHyprOpenGL->m_mMonitorRenderResources) { for (auto& [m, rd] : g_pHyprOpenGL->m_mMonitorRenderResources) {
rd.blurFBDirty = true; rd.blurFBDirty = true;
} }
} }
// decorations will probably need a repaint // decorations will probably need a repaint
if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("cursor_zoom_factor")) { if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("cursor_zoom_factor") || COMMAND == "source") {
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
g_pHyprRenderer->damageMonitor(m.get()); g_pHyprRenderer->damageMonitor(m.get());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
@ -862,7 +907,7 @@ std::string dispatchKeyword(std::string in) {
return retval; return retval;
} }
std::string reloadRequest(const std::string& request) { std::string reloadRequest(eHyprCtlOutputFormat format, std::string request) {
const auto REQMODE = request.substr(request.find_last_of(' ') + 1); const auto REQMODE = request.substr(request.find_last_of(' ') + 1);
@ -877,20 +922,20 @@ std::string reloadRequest(const std::string& request) {
return "ok"; return "ok";
} }
std::string killRequest() { std::string killRequest(eHyprCtlOutputFormat format, std::string request) {
g_pInputManager->setClickMode(CLICKMODE_KILL); g_pInputManager->setClickMode(CLICKMODE_KILL);
return "ok"; return "ok";
} }
std::string splashRequest() { std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
return g_pCompositor->m_szCurrentSplash; return g_pCompositor->m_szCurrentSplash;
} }
std::string cursorPosRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) {
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal().floor(); const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal().floor();
if (format == HyprCtl::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
return std::format("{}, {}", (int)CURSORPOS.x, (int)CURSORPOS.y); return std::format("{}, {}", (int)CURSORPOS.x, (int)CURSORPOS.y);
} else { } else {
return std::format(R"#( return std::format(R"#(
@ -905,9 +950,7 @@ std::string cursorPosRequest(HyprCtl::eHyprCtlOutputFormat format) {
return "error"; return "error";
} }
std::string getReply(std::string); std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
std::string dispatchBatch(std::string request) {
// split by ; // split by ;
request = request.substr(9); request = request.substr(9);
@ -930,8 +973,8 @@ std::string dispatchBatch(std::string request) {
nextItem(); nextItem();
while (curitem != "") { while (curitem != "" || request != "") {
reply += getReply(curitem); reply += g_pHyprCtl->getReply(curitem);
nextItem(); nextItem();
} }
@ -939,7 +982,7 @@ std::string dispatchBatch(std::string request) {
return reply; return reply;
} }
std::string dispatchSetCursor(std::string request) { std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
const auto SIZESTR = vars[vars.size() - 1]; const auto SIZESTR = vars[vars.size() - 1];
@ -971,7 +1014,7 @@ std::string dispatchSetCursor(std::string request) {
return "ok"; return "ok";
} }
std::string switchXKBLayoutRequest(const std::string& request) { std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
const auto KB = vars[1]; const auto KB = vars[1];
@ -1017,7 +1060,7 @@ std::string switchXKBLayoutRequest(const std::string& request) {
return "ok"; return "ok";
} }
std::string dispatchSeterror(std::string request) { std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
std::string errorMessage = ""; std::string errorMessage = "";
@ -1046,13 +1089,14 @@ std::string dispatchSeterror(std::string request) {
return "ok"; return "ok";
} }
std::string dispatchSetProp(std::string request) { std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
if (vars.size() < 4) if (vars.size() < 4)
return "not enough args"; return "not enough args";
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
if (!PWINDOW) if (!PWINDOW)
return "window not found"; return "window not found";
@ -1060,6 +1104,8 @@ std::string dispatchSetProp(std::string request) {
const auto PROP = vars[2]; const auto PROP = vars[2];
const auto VAL = vars[3]; const auto VAL = vars[3];
auto noFocus = PWINDOW->m_sAdditionalConfigData.noFocus;
bool lock = false; bool lock = false;
if (vars.size() > 4) { if (vars.size() > 4) {
@ -1089,6 +1135,8 @@ std::string dispatchSetProp(std::string request) {
PWINDOW->m_sAdditionalConfigData.forceNoShadow.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sAdditionalConfigData.forceNoShadow.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenodim") { } else if (PROP == "forcenodim") {
PWINDOW->m_sAdditionalConfigData.forceNoDim.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sAdditionalConfigData.forceNoDim.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nofocus") {
PWINDOW->m_sAdditionalConfigData.noFocus.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "windowdancecompat") { } else if (PROP == "windowdancecompat") {
PWINDOW->m_sAdditionalConfigData.windowDanceCompat.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sAdditionalConfigData.windowDanceCompat.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nomaxsize") { } else if (PROP == "nomaxsize") {
@ -1124,13 +1172,19 @@ std::string dispatchSetProp(std::string request) {
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!(PWINDOW->m_sAdditionalConfigData.noFocus.toUnderlying() == noFocus.toUnderlying())) {
g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->focusWindow(PLASTWINDOW);
}
for (auto& m : g_pCompositor->m_vMonitors) for (auto& m : g_pCompositor->m_vMonitors)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
return "ok"; return "ok";
} }
std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) { std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
std::string curitem = ""; std::string curitem = "";
auto nextItem = [&]() { auto nextItem = [&]() {
@ -1150,31 +1204,43 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
nextItem(); nextItem();
nextItem(); nextItem();
const auto PCFGOPT = g_pConfigManager->getConfigValuePtrSafe(curitem); const auto VAR = g_pConfigManager->getHyprlangConfigValuePtr(curitem);
if (!PCFGOPT) if (!VAR)
return "no such option"; return "no such option";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) const auto VAL = VAR->getValue();
return std::format("option {}\n\tint: {}\n\tfloat: {:.5f}\n\tstr: \"{}\"\n\tdata: {:x}\n\tset: {}", curitem, PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue, const auto TYPE = std::type_index(VAL.type());
(uintptr_t)PCFGOPT->data.get(), PCFGOPT->set);
else { if (format == FORMAT_NORMAL) {
return std::format( if (TYPE == typeid(Hyprlang::INT))
R"#( return std::format("int: {}\nset: {}", std::any_cast<Hyprlang::INT>(VAL), VAR->m_bSetByUser);
{{ else if (TYPE == typeid(Hyprlang::FLOAT))
"option": "{}", return std::format("float: {:2f}\nset: {}", std::any_cast<Hyprlang::FLOAT>(VAL), VAR->m_bSetByUser);
"int": {}, else if (TYPE == typeid(Hyprlang::VEC2))
"float": {:.5f}, return std::format("vec2: [{}, {}]\nset: {}", std::any_cast<Hyprlang::VEC2>(VAL).x, std::any_cast<Hyprlang::VEC2>(VAL).y, VAR->m_bSetByUser);
"str": "{}", else if (TYPE == typeid(Hyprlang::STRING))
"data": "0x{:x}", return std::format("str: {}\nset: {}", std::any_cast<Hyprlang::STRING>(VAL), VAR->m_bSetByUser);
"set": {} else if (TYPE == typeid(Hyprlang::CUSTOMTYPE*))
}} return std::format("custom type at: {:x}\nset: {}", (uintptr_t)std::any_cast<Hyprlang::CUSTOMTYPE*>(VAL), VAR->m_bSetByUser);
)#", } else {
curitem, PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue, (uintptr_t)PCFGOPT->data.get(), PCFGOPT->set); if (TYPE == typeid(Hyprlang::INT))
return std::format("{{\"option\": \"{}\", \"int\": {}, \"set\": {} }}", curitem, std::any_cast<Hyprlang::INT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::FLOAT))
return std::format("{{\"option\": \"{}\", \"float\": {:2f}, \"set\": {} }}", curitem, std::any_cast<Hyprlang::FLOAT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::VEC2))
return std::format("{{\"option\": \"{}\", \"vec2\": [{},{}], \"set\": {} }}", curitem, std::any_cast<Hyprlang::VEC2>(VAL).x, std::any_cast<Hyprlang::VEC2>(VAL).y,
VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::STRING))
return std::format("{{\"option\": \"{}\", \"str\": \"{}\", \"set\": {} }}", curitem, escapeJSONStrings(std::any_cast<Hyprlang::STRING>(VAL)), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::CUSTOMTYPE*))
return std::format("{{\"option\": \"{}\", \"custom\": \"{:x}\", \"set\": {} }}", curitem, (uintptr_t)std::any_cast<Hyprlang::CUSTOMTYPE*>(VAL), VAR->m_bSetByUser);
} }
return "invalid type (internal error)";
} }
std::string decorationRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) { std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
@ -1182,7 +1248,7 @@ std::string decorationRequest(std::string request, HyprCtl::eHyprCtlOutputFormat
return "none"; return "none";
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto& wd : PWINDOW->m_dWindowDecorations) { for (auto& wd : PWINDOW->m_dWindowDecorations) {
result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},"; result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},";
@ -1231,7 +1297,7 @@ void createOutputIter(wlr_backend* backend, void* data) {
} }
} }
std::string dispatchOutput(std::string request) { std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
std::string curitem = ""; std::string curitem = "";
auto nextItem = [&]() { auto nextItem = [&]() {
@ -1280,7 +1346,7 @@ std::string dispatchOutput(std::string request) {
return "ok"; return "ok";
} }
std::string dispatchPlugin(std::string request) { std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
if (vars.size() < 2) if (vars.size() < 2)
@ -1323,7 +1389,7 @@ std::string dispatchPlugin(std::string request) {
return "ok"; return "ok";
} }
std::string dispatchNotify(std::string request) { std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
if (vars.size() < 5) if (vars.size() < 5)
@ -1364,92 +1430,137 @@ std::string dispatchNotify(std::string request) {
return "ok"; return "ok";
} }
std::string getReply(std::string request) { CHyprCtl::CHyprCtl() {
auto format = HyprCtl::FORMAT_NORMAL; registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
registerCommand(SHyprCtlCommand{"activeworkspace", true, activeWorkspaceRequest});
registerCommand(SHyprCtlCommand{"clients", true, clientsRequest});
registerCommand(SHyprCtlCommand{"kill", true, killRequest});
registerCommand(SHyprCtlCommand{"activewindow", true, activeWindowRequest});
registerCommand(SHyprCtlCommand{"layers", true, layersRequest});
registerCommand(SHyprCtlCommand{"version", true, versionRequest});
registerCommand(SHyprCtlCommand{"devices", true, devicesRequest});
registerCommand(SHyprCtlCommand{"splash", true, splashRequest});
registerCommand(SHyprCtlCommand{"cursorpos", true, cursorPosRequest});
registerCommand(SHyprCtlCommand{"binds", true, bindsRequest});
registerCommand(SHyprCtlCommand{"globalshortcuts", true, globalShortcutsRequest});
registerCommand(SHyprCtlCommand{"systeminfo", true, systemInfoRequest});
registerCommand(SHyprCtlCommand{"animations", true, animationsRequest});
registerCommand(SHyprCtlCommand{"rollinglog", true, rollinglogRequest});
registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
registerCommand(SHyprCtlCommand{"plugin", false, dispatchPlugin});
registerCommand(SHyprCtlCommand{"notify", false, dispatchNotify});
registerCommand(SHyprCtlCommand{"setprop", false, dispatchSetProp});
registerCommand(SHyprCtlCommand{"seterror", false, dispatchSeterror});
registerCommand(SHyprCtlCommand{"switchxkblayout", false, switchXKBLayoutRequest});
registerCommand(SHyprCtlCommand{"output", false, dispatchOutput});
registerCommand(SHyprCtlCommand{"dispatch", false, dispatchRequest});
registerCommand(SHyprCtlCommand{"keyword", false, dispatchKeyword});
registerCommand(SHyprCtlCommand{"setcursor", false, dispatchSetCursor});
registerCommand(SHyprCtlCommand{"getoption", false, dispatchGetOption});
registerCommand(SHyprCtlCommand{"decorations", false, decorationRequest});
registerCommand(SHyprCtlCommand{"[[BATCH]]", false, dispatchBatch});
startHyprCtlSocket();
}
std::shared_ptr<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) {
return m_vCommands.emplace_back(std::make_shared<SHyprCtlCommand>(cmd));
}
void CHyprCtl::unregisterCommand(const std::shared_ptr<SHyprCtlCommand>& cmd) {
std::erase(m_vCommands, cmd);
}
std::string CHyprCtl::getReply(std::string request) {
auto format = eHyprCtlOutputFormat::FORMAT_NORMAL;
bool reloadAll = false;
// process flags for non-batch requests // 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')
format = HyprCtl::FORMAT_JSON; format = eHyprCtlOutputFormat::FORMAT_JSON;
if (c == 'r')
reloadAll = true;
} }
if (sepIndex < request.size()) if (sepIndex < request.size())
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.starts_with("monitors")) std::string result = "";
return monitorsRequest(request, format);
else if (request == "workspaces")
return workspacesRequest(format);
else if (request == "workspacerules")
return workspaceRulesRequest(format);
else if (request == "activeworkspace")
return activeWorkspaceRequest(format);
else if (request == "clients")
return clientsRequest(format);
else if (request == "kill")
return killRequest();
else if (request == "activewindow")
return activeWindowRequest(format);
else if (request == "layers")
return layersRequest(format);
else if (request == "version")
return versionRequest(format);
else if (request.starts_with("reload"))
return reloadRequest(request);
else if (request == "devices")
return devicesRequest(format);
else if (request == "splash")
return splashRequest();
else if (request == "cursorpos")
return cursorPosRequest(format);
else if (request == "binds")
return bindsRequest(format);
else if (request == "globalshortcuts")
return globalShortcutsRequest(format);
else if (request == "animations")
return animationsRequest(format);
else if (request == "rollinglog")
return rollinglogRequest(format);
else if (request == "layouts")
return layoutsRequest(format);
else if (request.starts_with("plugin"))
return dispatchPlugin(request);
else if (request.starts_with("notify"))
return dispatchNotify(request);
else if (request.starts_with("setprop"))
return dispatchSetProp(request);
else if (request.starts_with("seterror"))
return dispatchSeterror(request);
else if (request.starts_with("switchxkblayout"))
return switchXKBLayoutRequest(request);
else if (request.starts_with("output"))
return dispatchOutput(request);
else if (request.starts_with("dispatch"))
return dispatchRequest(request);
else if (request.starts_with("keyword"))
return dispatchKeyword(request);
else if (request.starts_with("setcursor"))
return dispatchSetCursor(request);
else if (request.starts_with("getoption"))
return dispatchGetOption(request, format);
else if (request.starts_with("decorations"))
return decorationRequest(request, format);
else if (request.starts_with("[[BATCH]]"))
return dispatchBatch(request);
return "unknown request"; // parse exact cmds first, then non-exact.
for (auto& cmd : m_vCommands) {
if (!cmd->exact)
continue;
if (cmd->name == request) {
result = cmd->fn(format, request);
break;
}
}
if (result.empty())
for (auto& cmd : m_vCommands) {
if (cmd->exact)
continue;
if (request.starts_with(cmd->name)) {
result = cmd->fn(format, request);
break;
}
}
if (result.empty())
return "unknown request";
if (reloadAll) {
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords
g_pInputManager->setKeyboardLayout(); // update kb layout
g_pInputManager->setPointerConfigs(); // update mouse cfgs
g_pInputManager->setTouchDeviceConfigs(); // update touch device cfgs
g_pInputManager->setTabletConfigs(); // update tablets
static auto* const PLAYOUT = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("general:layout");
g_pLayoutManager->switchToLayout(*PLAYOUT); // update layout
g_pHyprOpenGL->m_bReloadScreenShader = true;
for (auto& [m, rd] : g_pHyprOpenGL->m_mMonitorRenderResources) {
rd.blurFBDirty = true;
}
for (auto& m : g_pCompositor->m_vMonitors) {
g_pHyprRenderer->damageMonitor(m.get());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
}
}
return result;
} }
std::string HyprCtl::makeDynamicCall(const std::string& input) { std::string CHyprCtl::makeDynamicCall(const std::string& input) {
return getReply(input); return getReply(input);
} }
@ -1460,7 +1571,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
sockaddr_in clientAddress; sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress); socklen_t clientSize = sizeof(clientAddress);
const auto ACCEPTEDCONNECTION = accept4(HyprCtl::iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
std::array<char, 1024> readBuffer; std::array<char, 1024> readBuffer;
@ -1490,7 +1601,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
std::string reply = ""; std::string reply = "";
try { try {
reply = getReply(request); reply = g_pHyprCtl->getReply(request);
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Error in request: {}", e.what()); Debug::log(ERR, "Error in request: {}", e.what());
reply = "Err: " + std::string(e.what()); reply = "Err: " + std::string(e.what());
@ -1500,18 +1611,17 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
close(ACCEPTEDCONNECTION); close(ACCEPTEDCONNECTION);
if (g_pConfigManager->m_bWantsMonitorReload) { if (g_pConfigManager->m_bWantsMonitorReload)
g_pConfigManager->ensureMonitorStatus(); g_pConfigManager->ensureMonitorStatus();
}
return 0; return 0;
} }
void HyprCtl::startHyprCtlSocket() { void CHyprCtl::startHyprCtlSocket() {
iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (iSocketFD < 0) { if (m_iSocketFD < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
return; return;
} }
@ -1522,15 +1632,15 @@ void HyprCtl::startHyprCtlSocket() {
strcpy(SERVERADDRESS.sun_path, socketPath.c_str()); strcpy(SERVERADDRESS.sun_path, socketPath.c_str());
if (bind(iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work.");
return; return;
} }
// 10 max queued. // 10 max queued.
listen(iSocketFD, 10); listen(m_iSocketFD, 10);
Debug::log(LOG, "Hypr socket started at {}", socketPath); Debug::log(LOG, "Hypr socket started at {}", socketPath);
wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
} }

View file

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

View file

@ -226,4 +226,8 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
CBox 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);
}
bool CHyprNotificationOverlay::hasAny() {
return !m_dNotifications.empty();
} }

View file

@ -41,6 +41,7 @@ class CHyprNotificationOverlay {
void draw(CMonitor* pMonitor); void draw(CMonitor* pMonitor);
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE); void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
bool hasAny();
private: private:
CBox drawNotifications(CMonitor* pMonitor); CBox drawNotifications(CMonitor* pMonitor);

View file

@ -22,7 +22,7 @@ void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
rollingLog += output + "\n"; rollingLog += output + "\n";
if (!disableLogs || !*disableLogs) { if (!disableLogs || !**disableLogs) {
std::ofstream ofs; std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app); ofs.open(logFile, std::ios::out | std::ios::app);
ofs << "[wlr] " << output << "\n"; ofs << "[wlr] " << output << "\n";

View file

@ -21,16 +21,16 @@ enum LogLevel {
}; };
namespace Debug { namespace Debug {
inline std::string logFile; inline std::string logFile;
inline int64_t* disableLogs = nullptr; inline int64_t* const* disableLogs = nullptr;
inline int64_t* disableTime = nullptr; inline int64_t* const* disableTime = nullptr;
inline bool disableStdout = false; inline bool disableStdout = false;
inline bool trace = false; inline bool trace = false;
inline bool shuttingDown = false; inline bool shuttingDown = false;
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
void init(const std::string& IS); void init(const std::string& IS);
template <typename... Args> 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 (level == TRACE && !trace) if (level == TRACE && !trace)
@ -52,7 +52,7 @@ namespace Debug {
} }
// 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
logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())}); logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())});
#else #else
@ -73,7 +73,7 @@ namespace Debug {
if (rollingLog.size() > ROLLING_LOG_SIZE) if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE); rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
if (!disableLogs || !*disableLogs) { if (!disableLogs || !**disableLogs) {
// log to a file // log to a file
std::ofstream ofs; std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app); ofs.open(logFile, std::ios::out | std::ios::app);

236
src/desktop/Popup.cpp Normal file
View file

@ -0,0 +1,236 @@
#include "Popup.hpp"
#include "../Compositor.hpp"
CPopup::CPopup(CWindow* pOwner) : m_pWindowOwner(pOwner) {
initAllSignals();
}
CPopup::CPopup(SLayerSurface* pOwner) : m_pLayerOwner(pOwner) {
initAllSignals();
}
CPopup::CPopup(wlr_xdg_popup* popup, CPopup* pOwner) : m_pParent(pOwner), m_pWLR(popup) {
m_pWLR->base->data = this;
m_sWLSurface.assign(popup->base->surface, this);
m_pLayerOwner = pOwner->m_pLayerOwner;
m_pWindowOwner = pOwner->m_pWindowOwner;
m_vLastSize = {m_pWLR->current.geometry.width, m_pWLR->current.geometry.height};
unconstrain();
initAllSignals();
}
CPopup::~CPopup() {
m_sWLSurface.unassign();
if (m_pWLR)
m_pWLR->base->data = nullptr;
hyprListener_commitPopup.removeCallback();
hyprListener_repositionPopup.removeCallback();
hyprListener_mapPopup.removeCallback();
hyprListener_unmapPopup.removeCallback();
hyprListener_newPopup.removeCallback();
hyprListener_destroyPopup.removeCallback();
}
static void onNewPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onNewPopup((wlr_xdg_popup*)data);
}
static void onMapPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onMap();
}
static void onDestroyPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onDestroy();
}
static void onUnmapPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onUnmap();
}
static void onCommitPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onCommit();
}
static void onRepositionPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onReposition();
}
void CPopup::initAllSignals() {
if (!m_pWLR) {
if (m_pWindowOwner)
hyprListener_newPopup.initCallback(&m_pWindowOwner->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head");
else if (m_pLayerOwner)
hyprListener_newPopup.initCallback(&m_pLayerOwner->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head");
else
ASSERT(false);
return;
}
hyprListener_repositionPopup.initCallback(&m_pWLR->events.reposition, ::onRepositionPopup, this, "CPopup");
hyprListener_destroyPopup.initCallback(&m_pWLR->events.destroy, ::onDestroyPopup, this, "CPopup");
hyprListener_mapPopup.initCallback(&m_sWLSurface.wlr()->events.map, ::onMapPopup, this, "CPopup");
hyprListener_unmapPopup.initCallback(&m_sWLSurface.wlr()->events.unmap, ::onUnmapPopup, this, "CPopup");
hyprListener_commitPopup.initCallback(&m_sWLSurface.wlr()->events.commit, ::onCommitPopup, this, "CPopup");
hyprListener_newPopup.initCallback(&m_pWLR->base->events.new_popup, ::onNewPopup, this, "CPopup");
}
void CPopup::onNewPopup(wlr_xdg_popup* popup) {
const auto POPUP = m_vChildren.emplace_back(std::make_unique<CPopup>(popup, this)).get();
Debug::log(LOG, "New popup at wlr {:x} and hl {:x}", (uintptr_t)popup, (uintptr_t)POPUP);
}
void CPopup::onDestroy() {
m_bInert = true;
if (!m_pParent)
return; // head node
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
}
void CPopup::onMap() {
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
const auto COORDS = coordsGlobal();
CBox box;
wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr());
box.applyFromWlr().translate(COORDS);
g_pHyprRenderer->damageBox(&box);
m_vLastPos = coordsRelativeToParent();
g_pInputManager->simulateMouseMovement();
m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
unconstrain();
}
void CPopup::onUnmap() {
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
const auto COORDS = coordsGlobal();
CBox box;
wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr());
box.applyFromWlr().translate(COORDS);
g_pHyprRenderer->damageBox(&box);
m_pSubsurfaceHead.reset();
g_pInputManager->simulateMouseMovement();
}
void CPopup::onCommit() {
if (m_pWLR->base->initial_commit) {
wlr_xdg_surface_schedule_configure(m_pWLR->base);
return;
}
const auto COORDS = coordsGlobal();
const auto COORDSLOCAL = coordsRelativeToParent();
if (m_vLastSize != Vector2D{m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height} || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) {
CBox box = {localToGlobal(m_vLastPos), m_vLastSize};
g_pHyprRenderer->damageBox(&box);
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
m_vLastPos = COORDSLOCAL;
}
m_pSubsurfaceHead->recheckDamageForSubsurfaces();
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
m_bRequestedReposition = false;
}
void CPopup::onReposition() {
Debug::log(LOG, "Popup {:x} requests reposition", (uintptr_t)this);
m_bRequestedReposition = true;
m_vLastPos = coordsRelativeToParent();
unconstrain();
}
void CPopup::unconstrain() {
const auto COORDS = t1ParentCoords();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
if (!PMONITOR)
return;
CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(m_pWLR, box.pWlr());
}
Vector2D CPopup::coordsRelativeToParent() {
Vector2D offset;
CPopup* current = this;
offset -= {m_pWLR->base->current.geometry.x, m_pWLR->base->current.geometry.y};
while (current->m_pParent) {
offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy};
offset += {current->m_pWLR->current.geometry.x, current->m_pWLR->current.geometry.y};
current = current->m_pParent;
}
return offset;
}
Vector2D CPopup::coordsGlobal() {
return localToGlobal(coordsRelativeToParent());
}
Vector2D CPopup::localToGlobal(const Vector2D& rel) {
return t1ParentCoords() + rel;
}
Vector2D CPopup::t1ParentCoords() {
if (m_pWindowOwner)
return m_pWindowOwner->m_vRealPosition.value();
if (m_pLayerOwner)
return m_pLayerOwner->realPosition.value();
ASSERT(false);
return {};
}
void CPopup::recheckTree() {
CPopup* curr = this;
while (curr->m_pParent) {
curr = curr->m_pParent;
}
curr->recheckChildrenRecursive();
}
void CPopup::recheckChildrenRecursive() {
for (auto& c : m_vChildren) {
c->onCommit();
c->recheckChildrenRecursive();
}
}
Vector2D CPopup::size() {
return m_vLastSize;
}

71
src/desktop/Popup.hpp Normal file
View file

@ -0,0 +1,71 @@
#pragma once
#include <vector>
#include <memory>
#include "Subsurface.hpp"
struct SLayerSurface;
class CPopup {
public:
// dummy head nodes
CPopup(CWindow* pOwner);
CPopup(SLayerSurface* pOwner);
// real nodes
CPopup(wlr_xdg_popup* popup, CPopup* pOwner);
~CPopup();
Vector2D coordsRelativeToParent();
Vector2D coordsGlobal();
Vector2D size();
void onNewPopup(wlr_xdg_popup* popup);
void onDestroy();
void onMap();
void onUnmap();
void onCommit();
void onReposition();
void recheckTree();
CWLSurface m_sWLSurface;
private:
// T1 owners, each popup has to have one of these
CWindow* m_pWindowOwner = nullptr;
SLayerSurface* m_pLayerOwner = nullptr;
// T2 owners
CPopup* m_pParent = nullptr;
wlr_xdg_popup* m_pWLR = nullptr;
Vector2D m_vLastSize = {};
Vector2D m_vLastPos = {};
bool m_bRequestedReposition = false;
bool m_bInert = false;
//
std::vector<std::unique_ptr<CPopup>> m_vChildren;
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
// signals
DYNLISTENER(newPopup);
DYNLISTENER(destroyPopup);
DYNLISTENER(mapPopup);
DYNLISTENER(unmapPopup);
DYNLISTENER(commitPopup);
DYNLISTENER(repositionPopup);
void initAllSignals();
void unconstrain();
void recheckChildrenRecursive();
Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords();
};

261
src/desktop/Subsurface.cpp Normal file
View file

@ -0,0 +1,261 @@
#include "Subsurface.hpp"
#include "../events/Events.hpp"
#include "../Compositor.hpp"
static void onNewSubsurface(void* owner, void* data);
CSubsurface::CSubsurface(CWindow* pOwner) : m_pWindowParent(pOwner) {
initSignals();
wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &pOwner->m_pWLSurface.wlr()->current.subsurfaces_below, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
wl_list_for_each(wlrSubsurface, &pOwner->m_pWLSurface.wlr()->current.subsurfaces_above, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
}
CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) {
initSignals();
wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &pOwner->m_sWLSurface.wlr()->current.subsurfaces_below, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
wl_list_for_each(wlrSubsurface, &pOwner->m_sWLSurface.wlr()->current.subsurfaces_above, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
}
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) {
m_sWLSurface.assign(pSubsurface->surface, this);
initSignals();
initExistingSubsurfaces();
}
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
m_sWLSurface.assign(pSubsurface->surface, this);
initSignals();
initExistingSubsurfaces();
}
CSubsurface::~CSubsurface() {
hyprListener_newSubsurface.removeCallback();
if (!m_pSubsurface)
return;
hyprListener_commitSubsurface.removeCallback();
hyprListener_destroySubsurface.removeCallback();
}
static void onNewSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onNewSubsurface((wlr_subsurface*)data);
}
static void onDestroySubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onDestroy();
}
static void onCommitSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onCommit();
}
static void onMapSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onMap();
}
static void onUnmapSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onUnmap();
}
void CSubsurface::initSignals() {
if (m_pSubsurface) {
hyprListener_commitSubsurface.initCallback(&m_pSubsurface->surface->events.commit, &onCommitSubsurface, this, "CSubsurface");
hyprListener_destroySubsurface.initCallback(&m_pSubsurface->events.destroy, &onDestroySubsurface, this, "CSubsurface");
hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface");
hyprListener_mapSubsurface.initCallback(&m_pSubsurface->surface->events.map, &onMapSubsurface, this, "CSubsurface");
hyprListener_unmapSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface");
} else {
if (m_pWindowParent)
hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
else if (m_pPopupParent)
hyprListener_newSubsurface.initCallback(&m_pPopupParent->m_sWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
else
RASSERT(false, "CSubsurface::initSignals empty subsurface");
}
}
void CSubsurface::checkSiblingDamage() {
if (!m_pParent)
return; // ??????????
const double SCALE = m_pWindowParent && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0;
for (auto& n : m_pParent->m_vChildren) {
if (n.get() == this)
continue;
const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE);
}
}
void CSubsurface::recheckDamageForSubsurfaces() {
for (auto& n : m_vChildren) {
const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y);
}
}
void CSubsurface::onCommit() {
// no damaging if it's not visible
if (!g_pHyprRenderer->shouldRenderWindow(m_pWindowParent)) {
m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
static auto* const PLOGDAMAGE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("debug:log_damage");
if (**PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_pWindowParent);
return;
}
const auto COORDS = coordsGlobal();
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
if (m_pPopupParent)
m_pPopupParent->recheckTree();
if (m_pWindowParent) // I hate you firefox why are you doing this
m_pWindowParent->m_pPopupHead->recheckTree();
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
checkSiblingDamage();
if (m_vLastSize != Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}) {
CBox box{COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
}
if (m_pWindowParent) {
// tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_pWindowParent->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient == m_pWindowParent && m_pWindowParent->canBeTorn() && PMONITOR->tearingState.canTear &&
m_sWLSurface.wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
CRegion damageBox{&m_sWLSurface.wlr()->buffer_damage};
if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) {
PMONITOR->tearingState.frameScheduledWhileBusy = true;
} else {
PMONITOR->tearingState.nextRenderTorn = true;
g_pHyprRenderer->renderMonitor(PMONITOR);
}
}
}
}
}
void CSubsurface::onDestroy() {
// destroy children
m_vChildren.clear();
m_bInert = true;
if (!m_pSubsurface)
return; // dummy node, nothing to do, it's the parent dying
// kill ourselves
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
}
void CSubsurface::onNewSubsurface(wlr_subsurface* pSubsurface) {
CSubsurface* PSUBSURFACE = nullptr;
if (m_pWindowParent)
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pWindowParent)).get();
else if (m_pPopupParent)
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pPopupParent)).get();
PSUBSURFACE->m_pParent = this;
ASSERT(PSUBSURFACE);
}
void CSubsurface::onMap() {
m_vLastSize = {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
if (m_pWindowParent)
m_pWindowParent->updateSurfaceScaleTransformDetails();
}
void CSubsurface::onUnmap() {
const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
if (m_sWLSurface.wlr() == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons();
if (m_pWindowParent)
m_pWindowParent->updateSurfaceScaleTransformDetails();
g_pInputManager->simulateMouseMovement();
// TODO: should this remove children? Currently it won't, only on .destroy
}
Vector2D CSubsurface::coordsRelativeToParent() {
Vector2D offset;
CSubsurface* current = this;
while (current->m_pParent) {
offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy};
offset += {current->m_pSubsurface->current.x, current->m_pSubsurface->current.y};
current = current->m_pParent;
}
return offset;
}
Vector2D CSubsurface::coordsGlobal() {
Vector2D coords = coordsRelativeToParent();
if (m_pWindowParent)
coords += m_pWindowParent->m_vRealPosition.value();
else if (m_pPopupParent)
coords += m_pPopupParent->coordsGlobal();
return coords;
}
void CSubsurface::initExistingSubsurfaces() {
if (m_pWindowParent)
return;
wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_below, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_above, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
}
Vector2D CSubsurface::size() {
return {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
}

View file

@ -0,0 +1,59 @@
#pragma once
#include "../defines.hpp"
#include <vector>
#include "WLSurface.hpp"
class CWindow;
class CPopup;
class CSubsurface {
public:
// root dummy nodes
CSubsurface(CWindow* pOwner);
CSubsurface(CPopup* pOwner);
// real nodes
CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner);
CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner);
~CSubsurface();
Vector2D coordsRelativeToParent();
Vector2D coordsGlobal();
Vector2D size();
void onCommit();
void onDestroy();
void onNewSubsurface(wlr_subsurface* pSubsurface);
void onMap();
void onUnmap();
void recheckDamageForSubsurfaces();
private:
DYNLISTENER(destroySubsurface);
DYNLISTENER(commitSubsurface);
DYNLISTENER(newSubsurface);
DYNLISTENER(mapSubsurface);
DYNLISTENER(unmapSubsurface);
wlr_subsurface* m_pSubsurface = nullptr;
CWLSurface m_sWLSurface;
Vector2D m_vLastSize = {};
// if nullptr, means it's a dummy node
CSubsurface* m_pParent = nullptr;
CWindow* m_pWindowParent = nullptr;
CPopup* m_pPopupParent = nullptr;
std::vector<std::unique_ptr<CSubsurface>> m_vChildren;
bool m_bInert = false;
void initSignals();
void initExistingSubsurfaces();
void checkSiblingDamage();
};

174
src/desktop/WLSurface.cpp Normal file
View file

@ -0,0 +1,174 @@
#include "WLSurface.hpp"
#include "../Compositor.hpp"
void CWLSurface::assign(wlr_surface* pSurface) {
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, CWindow* pOwner) {
m_pWindowOwner = pOwner;
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, SLayerSurface* pOwner) {
m_pLayerOwner = pOwner;
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, CSubsurface* pOwner) {
m_pSubsurfaceOwner = pOwner;
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, CPopup* pOwner) {
m_pPopupOwner = pOwner;
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::unassign() {
destroy();
}
CWLSurface::~CWLSurface() {
destroy();
}
bool CWLSurface::exists() const {
return m_pWLRSurface;
}
wlr_surface* CWLSurface::wlr() const {
return m_pWLRSurface;
}
bool CWLSurface::small() const {
if (!m_pWindowOwner || !exists())
return false;
return m_pWindowOwner->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || m_pWindowOwner->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1;
}
Vector2D CWLSurface::correctSmallVec() const {
if (!m_pWindowOwner || !exists() || !small() || m_bFillIgnoreSmall)
return {};
const auto SIZE = getViewporterCorrectedSize();
return Vector2D{(m_pWindowOwner->m_vReportedSize.x - SIZE.x) / 2, (m_pWindowOwner->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) *
(m_pWindowOwner->m_vRealSize.value() / m_pWindowOwner->m_vReportedSize);
}
Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists())
return {};
return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} :
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
}
CRegion CWLSurface::logicalDamage() const {
CRegion damage{&m_pWLRSurface->buffer_damage};
damage.transform(m_pWLRSurface->current.transform, m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height);
damage.scale(1.0 / m_pWLRSurface->current.scale);
const auto VPSIZE = getViewporterCorrectedSize();
const auto CORRECTVEC = correctSmallVec();
if (m_pWLRSurface->current.viewport.has_src) {
damage.intersect(CBox{std::floor(m_pWLRSurface->current.viewport.src.x), std::floor(m_pWLRSurface->current.viewport.src.y),
std::ceil(m_pWLRSurface->current.viewport.src.width), std::ceil(m_pWLRSurface->current.viewport.src.height)});
}
const auto SCALEDSRCSIZE = m_pWLRSurface->current.viewport.has_src ?
Vector2D{m_pWLRSurface->current.viewport.src.width, m_pWLRSurface->current.viewport.src.height} * m_pWLRSurface->current.scale :
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y});
damage.translate(CORRECTVEC);
return damage;
}
void CWLSurface::destroy() {
if (!m_pWLRSurface)
return;
hyprListener_destroy.removeCallback();
m_pWLRSurface->data = nullptr;
m_pWindowOwner = nullptr;
m_pLayerOwner = nullptr;
m_pPopupOwner = nullptr;
m_pSubsurfaceOwner = nullptr;
m_bInert = true;
if (g_pCompositor && g_pCompositor->m_pLastFocus == m_pWLRSurface)
g_pCompositor->m_pLastFocus = nullptr;
if (g_pInputManager && g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_pWLRSurface = nullptr;
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
}
void CWLSurface::init() {
if (!m_pWLRSurface)
return;
RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!");
m_pWLRSurface->data = this;
hyprListener_destroy.initCallback(
&m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
}
CWindow* CWLSurface::getWindow() {
return m_pWindowOwner;
}
SLayerSurface* CWLSurface::getLayer() {
return m_pLayerOwner;
}
CPopup* CWLSurface::getPopup() {
return m_pPopupOwner;
}
CSubsurface* CWLSurface::getSubsurface() {
return m_pSubsurfaceOwner;
}
bool CWLSurface::desktopComponent() {
return m_pLayerOwner || m_pWindowOwner || m_pSubsurfaceOwner || m_pPopupOwner;
}
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() {
if (!desktopComponent())
return {};
if (m_pWindowOwner)
return m_pWindowOwner->getWindowMainSurfaceBox();
if (m_pLayerOwner)
return m_pLayerOwner->geometry;
if (m_pPopupOwner)
return CBox{m_pPopupOwner->coordsGlobal(), m_pPopupOwner->size()};
if (m_pSubsurfaceOwner)
return CBox{m_pSubsurfaceOwner->coordsGlobal(), m_pSubsurfaceOwner->size()};
return {};
}

View file

@ -1,16 +1,24 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/Region.hpp"
class CWindow; class CWindow;
struct SLayerSurface;
class CSubsurface;
class CPopup;
class CWLSurface { class CWLSurface {
public: public:
CWLSurface() = default; CWLSurface() = default;
CWLSurface(wlr_surface* pSurface);
~CWLSurface(); ~CWLSurface();
// anonymous surfaces are non-desktop components, e.g. a cursor surface or a DnD
void assign(wlr_surface* pSurface); void assign(wlr_surface* pSurface);
void assign(wlr_surface* pSurface, CWindow* pOwner);
void assign(wlr_surface* pSurface, SLayerSurface* pOwner);
void assign(wlr_surface* pSurface, CSubsurface* pOwner);
void assign(wlr_surface* pSurface, CPopup* pOwner);
void unassign(); void unassign();
CWLSurface(const CWLSurface&) = delete; CWLSurface(const CWLSurface&) = delete;
@ -23,13 +31,26 @@ class CWLSurface {
bool small() const; // means surface is smaller than the requested size bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D getViewporterCorrectedSize() const; Vector2D getViewporterCorrectedSize() const;
CRegion logicalDamage() const;
// getters for owners.
CWindow* getWindow();
SLayerSurface* getLayer();
CPopup* getPopup();
CSubsurface* getSubsurface();
// desktop components misc utils
std::optional<CBox> getSurfaceBoxGlobal();
// allow stretching. Useful for plugins. // allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false; bool m_bFillIgnoreSmall = false;
// if present, means this is a base surface of a window. Cleaned on unassign() // track surface data and avoid dupes
CWindow* m_pOwner = nullptr; 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;
@ -55,10 +76,18 @@ class CWLSurface {
} }
private: private:
wlr_surface* m_pWLRSurface = nullptr; bool m_bInert = true;
void destroy(); wlr_surface* m_pWLRSurface = nullptr;
void init();
CWindow* m_pWindowOwner = nullptr;
SLayerSurface* m_pLayerOwner = nullptr;
CPopup* m_pPopupOwner = nullptr;
CSubsurface* m_pSubsurfaceOwner = nullptr;
void destroy();
void init();
bool desktopComponent();
DYNLISTENER(destroy); DYNLISTENER(destroy);
}; };

View file

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

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include <string> #include <string>
#include "../defines.hpp" #include "../defines.hpp"
@ -35,9 +35,9 @@ class CWorkspace {
wl_array m_wlrCoordinateArr; wl_array m_wlrCoordinateArr;
// for animations // for animations
CAnimatedVariable m_vRenderOffset; CAnimatedVariable<Vector2D> m_vRenderOffset;
CAnimatedVariable m_fAlpha; CAnimatedVariable<float> m_fAlpha;
bool m_bForceRendering = false; bool m_bForceRendering = false;
// "scratchpad" // "scratchpad"
bool m_bIsSpecialWorkspace = false; bool m_bIsSpecialWorkspace = false;

View file

@ -22,25 +22,6 @@ namespace Events {
DYNLISTENFUNC(unmapLayerSurface); DYNLISTENFUNC(unmapLayerSurface);
DYNLISTENFUNC(commitLayerSurface); DYNLISTENFUNC(commitLayerSurface);
// Subsurfaces
DYNLISTENFUNC(newSubsurfaceNode);
DYNLISTENFUNC(destroySubsurfaceNode);
DYNLISTENFUNC(mapSubsurface);
DYNLISTENFUNC(unmapSubsurface);
DYNLISTENFUNC(destroySubsurface);
DYNLISTENFUNC(commitSubsurface);
// Popups
DYNLISTENFUNC(newPopup); // LayerSurface
DYNLISTENFUNC(newPopupXDG);
DYNLISTENFUNC(mapPopupXDG);
DYNLISTENFUNC(unmapPopupXDG);
DYNLISTENFUNC(destroyPopupXDG);
DYNLISTENFUNC(commitPopupXDG);
DYNLISTENFUNC(newPopupFromPopupXDG);
DYNLISTENFUNC(repositionPopupXDG);
// Surface XDG (window) // Surface XDG (window)
LISTENER(newXDGToplevel); LISTENER(newXDGToplevel);
LISTENER(activateXDG); LISTENER(activateXDG);
@ -174,4 +155,7 @@ namespace Events {
// Tearing hints // Tearing hints
LISTENER(newTearingHint); LISTENER(newTearingHint);
// Shortcut inhibitor
LISTENER(newShortcutInhibitor);
}; };

View file

@ -46,7 +46,6 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface"); layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface"); layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_unmapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.unmap, &Events::listener_unmapLayerSurface, layerSurface, "layerSurface"); layerSurface->hyprListener_unmapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.unmap, &Events::listener_unmapLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_newPopup.initCallback(&WLRLAYERSURFACE->events.new_popup, &Events::listener_newPopup, layerSurface, "layerSurface");
layerSurface->layerSurface = WLRLAYERSURFACE; layerSurface->layerSurface = WLRLAYERSURFACE;
layerSurface->layer = WLRLAYERSURFACE->current.layer; layerSurface->layer = WLRLAYERSURFACE->current.layer;
@ -87,7 +86,6 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
layersurface->hyprListener_destroyLayerSurface.removeCallback(); layersurface->hyprListener_destroyLayerSurface.removeCallback();
layersurface->hyprListener_mapLayerSurface.removeCallback(); layersurface->hyprListener_mapLayerSurface.removeCallback();
layersurface->hyprListener_unmapLayerSurface.removeCallback(); layersurface->hyprListener_unmapLayerSurface.removeCallback();
layersurface->hyprListener_newPopup.removeCallback();
// rearrange to fix the reserved areas // rearrange to fix the reserved areas
if (PMONITOR) { if (PMONITOR) {
@ -113,8 +111,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive; layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive;
layersurface->surface = layersurface->layerSurface->surface; layersurface->surface = layersurface->layerSurface->surface;
// anim layersurface->popupHead = std::make_unique<CPopup>(layersurface);
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
// fix if it changed its mon // fix if it changed its mon
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output); const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
@ -142,6 +139,9 @@ 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);
if (layersurface->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(layersurface);
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && 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);
@ -163,8 +163,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
layersurface->alpha.setValue(0); layersurface->startAnimation(!(layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
layersurface->alpha = ((layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS) ? 0.f : 1.f);
layersurface->readyToDelete = false; layersurface->readyToDelete = false;
layersurface->fadingOut = false; layersurface->fadingOut = false;
@ -183,6 +182,13 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")}); g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
EMIT_HOOK_EVENT("closeLayer", layersurface); EMIT_HOOK_EVENT("closeLayer", layersurface);
std::erase(g_pInputManager->m_dExclusiveLSes, layersurface);
layersurface->popupHead.reset();
if (!g_pInputManager->m_dExclusiveLSes.empty())
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface);
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) { if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
@ -190,23 +196,17 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
layersurface->mapped = false; layersurface->mapped = false;
layersurface->fadingOut = true; layersurface->startAnimation(false);
layersurface->alpha.setValueAndWarp(0.f);
return; return;
} }
// anim
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut"));
// make a snapshot and start fade // make a snapshot and start fade
g_pHyprOpenGL->makeLayerSnapshot(layersurface); g_pHyprOpenGL->makeLayerSnapshot(layersurface);
layersurface->alpha = 0.f;
layersurface->startAnimation(false);
layersurface->mapped = false; layersurface->mapped = false;
layersurface->fadingOut = true;
g_pCompositor->addToFadingOutSafe(layersurface); g_pCompositor->addToFadingOutSafe(layersurface);
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output); const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
@ -327,6 +327,19 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
} }
} }
if (layersurface->realPosition.goal() != layersurface->geometry.pos()) {
if (layersurface->realPosition.isBeingAnimated())
layersurface->realPosition = layersurface->geometry.pos();
else
layersurface->realPosition.setValueAndWarp(layersurface->geometry.pos());
}
if (layersurface->realSize.goal() != layersurface->geometry.size()) {
if (layersurface->realSize.isBeingAnimated())
layersurface->realSize = layersurface->geometry.size();
else
layersurface->realSize.setValueAndWarp(layersurface->geometry.size());
}
if (layersurface->layerSurface->current.keyboard_interactive && if (layersurface->layerSurface->current.keyboard_interactive &&
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) // don't focus if constrained (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) // don't focus if constrained
&& !layersurface->keyboardExclusive && layersurface->mapped) { && !layersurface->keyboardExclusive && layersurface->mapped) {

View file

@ -128,6 +128,8 @@ void Events::listener_destroyDrag(void* owner, void* data) {
g_pInputManager->m_sDrag.drag = nullptr; g_pInputManager->m_sDrag.drag = nullptr;
g_pInputManager->m_sDrag.dragIcon = nullptr; g_pInputManager->m_sDrag.dragIcon = nullptr;
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback(); g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
g_pCompositor->focusWindow(g_pCompositor->m_pLastWindow, g_pCompositor->m_pLastWindow ? g_pXWaylandManager->getWindowSurface(g_pCompositor->m_pLastWindow) : nullptr);
} }
void Events::listener_mapDragIcon(void* owner, void* data) { void Events::listener_mapDragIcon(void* owner, void* data) {
@ -175,11 +177,17 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) { void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
Debug::log(LOG, "PowerMgr set mode!"); Debug::log(LOG, "PowerMgr set mode!");
const auto EVENT = (wlr_output_power_v1_set_mode_event*)data; const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(EVENT->output);
wlr_output_enable(EVENT->output, EVENT->mode == 1); if (!PMONITOR) {
Debug::log(ERR, "Invalid powerMgrSetMode output");
return;
}
if (!wlr_output_commit(EVENT->output)) wlr_output_state_set_enabled(PMONITOR->state.wlr(), EVENT->mode == 1);
if (!PMONITOR->state.commit())
Debug::log(ERR, "Couldn't set power mode"); Debug::log(ERR, "Couldn't set power mode");
} }
@ -225,16 +233,7 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
} }
void Events::listener_newTearingHint(wl_listener* listener, void* data) { void Events::listener_newTearingHint(wl_listener* listener, void* data) {
const auto TCTL = (wlr_tearing_control_v1*)data; Debug::log(LOG, "New tearing hint at {:x}", (uintptr_t)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(); const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data; NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
@ -242,7 +241,7 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
NEWCTRL->hyprListener_destroy.initCallback( NEWCTRL->hyprListener_destroy.initCallback(
&NEWCTRL->pWlrHint->events.destroy, &NEWCTRL->pWlrHint->events.destroy,
[&](void* owner, void* data) { [&](void* owner, void* data) {
Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint); Debug::log(LOG, "Destroyed {:x} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; }); std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
}, },
@ -256,10 +255,27 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface); const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
if (PWINDOW) { if (PWINDOW) {
PWINDOW->m_bTearingHint = TEARINGHINT->pWlrHint->hint; PWINDOW->m_bTearingHint = (bool)TEARINGHINT->pWlrHint->current;
Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->hint); Debug::log(LOG, "Hint {:x} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->current);
} }
}, },
NEWCTRL, "TearingController"); NEWCTRL, "TearingController");
} }
void Events::listener_newShortcutInhibitor(wl_listener* listener, void* data) {
const auto INHIBITOR = (wlr_keyboard_shortcuts_inhibitor_v1*)data;
const auto PINH = &g_pKeybindManager->m_lShortcutInhibitors.emplace_back();
PINH->hyprListener_destroy.initCallback(
&INHIBITOR->events.destroy,
[](void* owner, void* data) {
const auto OWNER = (SShortcutInhibitor*)owner;
g_pKeybindManager->m_lShortcutInhibitors.remove(*OWNER);
},
PINH, "ShortcutInhibitor");
PINH->pWlrInhibitor = INHIBITOR;
Debug::log(LOG, "New shortcut inhibitor for surface {:x}", (uintptr_t)INHIBITOR->surface);
}

View file

@ -109,7 +109,7 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
for (auto& w : g_pCompositor->m_vWindows) { 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();
} }
} }
} }
@ -147,12 +147,12 @@ void Events::listener_monitorFrame(void* owner, void* data) {
PMONITOR->tearingState.frameScheduledWhileBusy = false; PMONITOR->tearingState.frameScheduledWhileBusy = false;
} }
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue; static auto* const PENABLERAT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time");
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue; static auto* const PRATSAFE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone");
PMONITOR->lastPresentationTimer.reset(); PMONITOR->lastPresentationTimer.reset();
if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) { if (**PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
if (!PMONITOR->RATScheduled) { if (!PMONITOR->RATScheduled) {
// render // render
g_pHyprRenderer->renderMonitor(PMONITOR); g_pHyprRenderer->renderMonitor(PMONITOR);
@ -162,14 +162,14 @@ void Events::listener_monitorFrame(void* owner, void* data) {
const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR); const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR);
if (max + *PRATSAFE > 1000.0 / PMONITOR->refreshRate) if (max + **PRATSAFE > 1000.0 / PMONITOR->refreshRate)
return; return;
const auto MSLEFT = 1000.0 / PMONITOR->refreshRate - PMONITOR->lastPresentationTimer.getMillis(); const auto MSLEFT = 1000.0 / PMONITOR->refreshRate - PMONITOR->lastPresentationTimer.getMillis();
PMONITOR->RATScheduled = true; PMONITOR->RATScheduled = true;
const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE); const auto ESTRENDERTIME = std::ceil(avg + **PRATSAFE);
const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME); const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1) if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1)
@ -212,7 +212,17 @@ void Events::listener_monitorStateRequest(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner; const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_request_state*)data; const auto E = (wlr_output_event_request_state*)data;
wlr_output_commit_state(PMONITOR->output, E->state); if (!PMONITOR->createdByUser)
return;
const auto SIZE = E->state->mode ? Vector2D{E->state->mode->width, E->state->mode->height} : Vector2D{E->state->custom_mode.width, E->state->custom_mode.height};
PMONITOR->forceSize = SIZE;
SMonitorRule rule = PMONITOR->activeMonitorRule;
rule.resolution = SIZE;
g_pHyprRenderer->applyMonitorRule(PMONITOR, &rule);
} }
void Events::listener_monitorDamage(void* owner, void* data) { void Events::listener_monitorDamage(void* owner, void* data) {

View file

@ -1,264 +0,0 @@
#include "Events.hpp"
#include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
// --------------------------------------------- //
// _____ ____ _____ _ _ _____ _____ //
// | __ \ / __ \| __ \| | | | __ \ / ____| //
// | |__) | | | | |__) | | | | |__) | (___ //
// | ___/| | | | ___/| | | | ___/ \___ \ //
// | | | |__| | | | |__| | | ____) | //
// |_| \____/|_| \____/|_| |_____/ //
// //
// --------------------------------------------- //
void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
SXDGPopup* const PPOPUP = (SXDGPopup*)pPopup;
auto curPopup = PPOPUP;
int px = 0;
int py = 0;
while (true) {
px += curPopup->popup->current.geometry.x;
py += curPopup->popup->current.geometry.y;
if (curPopup == PPOPUP && PPOPUP->parentWindow) {
px -= curPopup->popup->base->current.geometry.x;
py -= curPopup->popup->base->current.geometry.y;
}
if (curPopup->popup && !curPopup->parentPopup && !curPopup->parentWindow) {
const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->popup->base->surface->input_region);
px -= EXTENTSSURFACE->x1;
py -= EXTENTSSURFACE->y1;
}
if (curPopup->parentPopup) {
curPopup = curPopup->parentPopup;
} else {
break;
}
}
px += PPOPUP->lx;
py += PPOPUP->ly;
*x += px;
*y += py;
}
void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
pHyprPopup->popup = popup;
pHyprPopup->hyprListener_destroyPopupXDG.initCallback(&popup->base->events.destroy, &Events::listener_destroyPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_mapPopupXDG.initCallback(&popup->base->surface->events.map, &Events::listener_mapPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_unmapPopupXDG.initCallback(&popup->base->surface->events.unmap, &Events::listener_unmapPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_newPopupFromPopupXDG.initCallback(&popup->base->events.new_popup, &Events::listener_newPopupFromPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_commitPopupXDG.initCallback(&popup->base->surface->events.commit, &Events::listener_commitPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_repositionPopupXDG.initCallback(&popup->events.reposition, &Events::listener_repositionPopupXDG, pHyprPopup, "HyprPopup");
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
CBox box = {PMONITOR->vecPosition.x - pHyprPopup->lx, PMONITOR->vecPosition.y - pHyprPopup->ly, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(popup, box.pWlr());
pHyprPopup->monitor = PMONITOR;
Debug::log(LOG, "Popup: Unconstrained from lx ly: {:j5}, pHyprPopup lx ly: {:.5f} {:.5f}", PMONITOR->vecPosition, (float)pHyprPopup->lx, (float)pHyprPopup->ly);
}
void Events::listener_newPopup(void* owner, void* data) {
SLayerSurface* layersurface = (SLayerSurface*)owner;
ASSERT(layersurface);
Debug::log(LOG, "New layer popup created from surface {:x}", (uintptr_t)layersurface);
const auto WLRPOPUP = (wlr_xdg_popup*)data;
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
PNEWPOPUP->popup = WLRPOPUP;
PNEWPOPUP->lx = layersurface->position.x;
PNEWPOPUP->ly = layersurface->position.y;
PNEWPOPUP->monitor = PMONITOR;
PNEWPOPUP->parentLS = layersurface;
createNewPopup(WLRPOPUP, PNEWPOPUP);
}
void Events::listener_newPopupXDG(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
ASSERT(PWINDOW);
if (!PWINDOW->m_bIsMapped)
return;
Debug::log(LOG, "New layer popup created from XDG window {}", PWINDOW);
const auto WLRPOPUP = (wlr_xdg_popup*)data;
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
PNEWPOPUP->popup = WLRPOPUP;
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x;
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y;
PNEWPOPUP->parentWindow = PWINDOW;
PNEWPOPUP->monitor = PMONITOR;
createNewPopup(WLRPOPUP, PNEWPOPUP);
}
void Events::listener_newPopupFromPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
ASSERT(PPOPUP);
if (PPOPUP->parentWindow)
Debug::log(LOG, "New popup created from XDG Window popup {:x} -> {}", (uintptr_t)PPOPUP, PPOPUP->parentWindow);
else
Debug::log(LOG, "New popup created from Non-Window popup {:x}", (uintptr_t)PPOPUP);
const auto WLRPOPUP = (wlr_xdg_popup*)data;
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
PNEWPOPUP->popup = WLRPOPUP;
PNEWPOPUP->parentPopup = PPOPUP;
PNEWPOPUP->lx = PPOPUP->lx;
PNEWPOPUP->ly = PPOPUP->ly;
PNEWPOPUP->parentWindow = PPOPUP->parentWindow;
PNEWPOPUP->monitor = PPOPUP->monitor;
createNewPopup(WLRPOPUP, PNEWPOPUP);
}
void Events::listener_mapPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
ASSERT(PPOPUP);
Debug::log(LOG, "New XDG Popup mapped at {} {}", (int)PPOPUP->lx, (int)PPOPUP->ly);
if (PPOPUP->parentWindow)
PPOPUP->parentWindow->m_lPopupSurfaces.emplace_back(PPOPUP->popup->base->surface);
else if (PPOPUP->parentLS)
PPOPUP->parentLS->popupSurfaces.emplace_back(PPOPUP->popup->base->surface);
PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow);
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
if (PPOPUP->monitor) {
g_pCompositor->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale);
g_pCompositor->setPreferredTransformForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->transform);
}
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree);
}
void Events::listener_repositionPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
Debug::log(LOG, "XDG Popup {:x} asks for a reposition", (uintptr_t)PPOPUP);
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
PPOPUP->lastPos = {lx - extents.x, ly - extents.y};
PPOPUP->repositionRequested = true;
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
CBox box = {PMONITOR->vecPosition.x - lx + PPOPUP->popup->current.geometry.x, PMONITOR->vecPosition.y - ly + PPOPUP->popup->current.geometry.y, PMONITOR->vecSize.x,
PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(PPOPUP->popup, box.pWlr());
}
void Events::listener_unmapPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
Debug::log(LOG, "XDG Popup unmapped");
ASSERT(PPOPUP);
if (PPOPUP->popup->base->surface == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons();
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
if (PPOPUP->parentWindow)
std::erase(PPOPUP->parentWindow->m_lPopupSurfaces, PPOPUP->popup->base->surface);
else if (PPOPUP->parentLS)
std::erase(PPOPUP->parentLS->popupSurfaces, PPOPUP->popup->base->surface);
PPOPUP->pSurfaceTree = nullptr;
g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface
}
void Events::listener_commitPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
if (g_pCompositor->windowValidMapped(PPOPUP->parentWindow)) {
PPOPUP->lx = PPOPUP->parentWindow->m_vRealPosition.vec().x;
PPOPUP->ly = PPOPUP->parentWindow->m_vRealPosition.vec().y;
}
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
if (PPOPUP->repositionRequested)
g_pHyprRenderer->damageBox(PPOPUP->lastPos.x, PPOPUP->lastPos.y, extents.width + 2, extents.height + 2);
PPOPUP->repositionRequested = false;
g_pHyprRenderer->damageSurface(PPOPUP->popup->base->surface, lx, ly);
}
void Events::listener_destroyPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
ASSERT(PPOPUP);
Debug::log(LOG, "Destroyed popup XDG {:x}", (uintptr_t)PPOPUP);
if (PPOPUP->pSurfaceTree) {
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
PPOPUP->pSurfaceTree = nullptr;
}
std::erase_if(g_pCompositor->m_vXDGPopups, [&](std::unique_ptr<SXDGPopup>& el) { return el.get() == PPOPUP; });
}

View file

@ -17,8 +17,8 @@
void addViewCoords(void* pWindow, int* x, int* y) { void addViewCoords(void* pWindow, int* x, int* y) {
const auto PWINDOW = (CWindow*)pWindow; const auto PWINDOW = (CWindow*)pWindow;
*x += PWINDOW->m_vRealPosition.goalv().x; *x += PWINDOW->m_vRealPosition.goal().x;
*y += PWINDOW->m_vRealPosition.goalv().y; *y += PWINDOW->m_vRealPosition.goal().y;
if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) { if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) {
wlr_box geom; wlr_box geom;
@ -30,9 +30,9 @@ void addViewCoords(void* pWindow, int* x, int* y) {
} }
void setAnimToMove(void* data) { void setAnimToMove(void* data) {
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove"); auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
CAnimatedVariable* animvar = (CAnimatedVariable*)data; CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data;
animvar->setConfig(PANIMCFG); animvar->setConfig(PANIMCFG);
} }
@ -40,17 +40,16 @@ void setAnimToMove(void* data) {
void Events::listener_mapWindow(void* owner, void* data) { void Events::listener_mapWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; CWindow* PWINDOW = (CWindow*)owner;
static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue; static auto* const PINACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity");
static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue; static auto* const PACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:active_opacity");
static auto* const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue; static auto* const PDIMSTRENGTH = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:dim_strength");
static auto* const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue; static auto* const PSWALLOW = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:enable_swallow");
static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue; static auto* const PSWALLOWREGEX = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("misc:swallow_regex");
static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex")->strValue; static auto* const PSWALLOWEXREGEX = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex");
static auto* const PNEWTAKESOVERFS = &g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen")->intValue; static auto* const PNEWTAKESOVERFS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen");
auto PMONITOR = g_pCompositor->m_pLastMonitor; auto PMONITOR = g_pCompositor->m_pLastMonitor;
const auto PWORKSPACE = 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_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace; PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
PWINDOW->m_bIsMapped = true; PWINDOW->m_bIsMapped = true;
@ -101,7 +100,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
// window rules // window rules
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW); const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW, false);
std::string requestedWorkspace = ""; std::string requestedWorkspace = "";
bool workspaceSilent = false; bool workspaceSilent = false;
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen ||
@ -173,13 +172,23 @@ void Events::listener_mapWindow(void* owner, void* data) {
} else if (r.szRule.starts_with("pseudo")) { } else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true; PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.starts_with("nofocus")) { } else if (r.szRule.starts_with("nofocus")) {
PWINDOW->m_bNoFocus = true; PWINDOW->m_sAdditionalConfigData.noFocus = true;
} else if (r.szRule.starts_with("noinitialfocus")) { } else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.starts_with("nofullscreenrequest")) { } else if (r.szRule.starts_with("suppressevent")) {
PWINDOW->m_bNoFullscreenRequest = true; CVarList vars(r.szRule, 0, 's', true);
} else if (r.szRule.starts_with("nomaximizerequest")) { for (size_t i = 1; i < vars.size(); ++i) {
PWINDOW->m_bNoMaximizeRequest = true; if (vars[i] == "fullscreen")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN;
else if (vars[i] == "maximize")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_MAXIMIZE;
else if (vars[i] == "activate")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
else if (vars[i] == "activatefocus")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
else
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
}
} else if (r.szRule == "fullscreen") { } else if (r.szRule == "fullscreen") {
requestsFullscreen = true; requestsFullscreen = true;
overridingNoFullscreen = true; overridingNoFullscreen = true;
@ -270,6 +279,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!pWorkspace) if (!pWorkspace)
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName); pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName);
PWORKSPACE = pWorkspace;
PWINDOW->m_iWorkspaceID = pWorkspace->m_iID; PWINDOW->m_iWorkspaceID = pWorkspace->m_iID;
PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID; PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID;
@ -312,7 +323,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
Debug::log(LOG, "Rule size, applying to {}", PWINDOW); Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY); PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
PWINDOW->setHidden(false); 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); }
@ -323,10 +334,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto SIZE = const auto SIZE =
Vector2D(std::max((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::max((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goalv().y)); Vector2D(std::max((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goal().x), std::max((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goal().y));
PWINDOW->m_vRealSize = SIZE; PWINDOW->m_vRealSize = SIZE;
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
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); }
@ -337,10 +348,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto SIZE = const auto SIZE =
Vector2D(std::min((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::min((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goalv().y)); Vector2D(std::min((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goal().x), std::min((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goal().y));
PWINDOW->m_vRealSize = SIZE; PWINDOW->m_vRealSize = SIZE;
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
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); }
@ -379,7 +390,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x; posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
} else { } else {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x + posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().x); (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
} }
} }
@ -398,7 +409,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y; posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
} else { } else {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y + posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().y); (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
} }
} }
@ -406,10 +417,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
int borderSize = PWINDOW->getRealBorderSize(); int borderSize = PWINDOW->getRealBorderSize();
posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize), posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goalv().x - borderSize)); (int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize));
posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize), posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goalv().y - borderSize)); (int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize));
} }
Debug::log(LOG, "Rule move, applying to {}", PWINDOW); Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
@ -424,28 +435,28 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (ARGS[1] == "1") if (ARGS[1] == "1")
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f; RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goalv() / 2.f + RESERVEDOFFSET; PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.value() / 2.f + RESERVEDOFFSET;
} }
} }
// set the pseudo size to the GOAL of our current size // set the pseudo size to the GOAL of our current size
// because the windows are animated on RealSize // because the windows are animated on RealSize
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv(); PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal();
g_pCompositor->changeWindowZOrder(PWINDOW, true); g_pCompositor->changeWindowZOrder(PWINDOW, true);
} else { } else {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
// Set the pseudo size here too so that it doesnt end up being 0x0 // Set the pseudo size here too so that it doesnt end up being 0x0
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10, 10); PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10);
} }
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow; const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow;
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) { if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) {
PWINDOW->m_bNoFocus = false; PWINDOW->m_sAdditionalConfigData.noFocus = false;
PWINDOW->m_bNoInitialFocus = false; PWINDOW->m_bNoInitialFocus = false;
PWINDOW->m_bX11ShouldntFocus = false; PWINDOW->m_bX11ShouldntFocus = false;
} }
// check LS focus grab // check LS focus grab
@ -454,9 +465,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
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 (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
if (*PNEWTAKESOVERFS == 0) if (**PNEWTAKESOVERFS == 0)
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
else if (*PNEWTAKESOVERFS == 2) else if (**PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID); g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID);
else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
requestsMaximize = true; requestsMaximize = true;
@ -464,22 +475,19 @@ void Events::listener_mapWindow(void* owner, void* data) {
requestsFullscreen = true; requestsFullscreen = true;
} }
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus && if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus &&
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent && (PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
(!PFORCEFOCUS || PFORCEFOCUS == PWINDOW)) { (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW)) {
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(**PACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH); PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : **PDIMSTRENGTH);
} else { } else {
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(**PINACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(0); PWINDOW->m_fDimPercent.setValueAndWarp(0);
} }
Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree);
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW, PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW,
"XDG Window Late"); "XDG Window Late");
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW, PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW,
@ -504,8 +512,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
"XWayland Window Late"); "XWayland Window Late");
} }
if ((requestsFullscreen && (!PWINDOW->m_bNoFullscreenRequest || overridingNoFullscreen)) || (requestsMaximize && (!PWINDOW->m_bNoMaximizeRequest || overridingNoMaximize)) || if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) ||
requestsFakeFullscreen) { (requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) {
// fix fullscreen on requested (basically do a switcheroo) // fix fullscreen on requested (basically do a switcheroo)
if (PWORKSPACE->m_bHasFullscreenWindow) { if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
@ -527,8 +535,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
// recheck idle inhibitors // recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(PWINDOW->m_pWLSurface.wlr(), addViewCoords, PWINDOW, PWINDOW);
PWINDOW->updateToplevel(); PWINDOW->updateToplevel();
if (workspaceSilent) { if (workspaceSilent) {
@ -540,7 +546,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
// verify swallowing // verify swallowing
if (*PSWALLOW && *PSWALLOWREGEX != STRVAL_EMPTY) { if (**PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) {
// don't swallow ourselves // don't swallow ourselves
std::regex rgx(*PSWALLOWREGEX); std::regex rgx(*PSWALLOWREGEX);
if (!std::regex_match(g_pXWaylandManager->getAppIDClass(PWINDOW), rgx)) { if (!std::regex_match(g_pXWaylandManager->getAppIDClass(PWINDOW), rgx)) {
@ -587,7 +593,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (finalFound) { if (finalFound) {
bool valid = std::regex_match(g_pXWaylandManager->getAppIDClass(finalFound), rgx); bool valid = std::regex_match(g_pXWaylandManager->getAppIDClass(finalFound), rgx);
if (*PSWALLOWEXREGEX != STRVAL_EMPTY) { if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) {
std::regex exc(*PSWALLOWEXREGEX); std::regex exc(*PSWALLOWEXREGEX);
valid = valid && !std::regex_match(g_pXWaylandManager->getTitle(finalFound), exc); valid = valid && !std::regex_match(g_pXWaylandManager->getTitle(finalFound), exc);
@ -611,7 +617,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bFirstMap = false; PWINDOW->m_bFirstMap = false;
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goalv(), PWINDOW->m_vRealSize.goalv()); Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goal(), PWINDOW->m_vRealSize.goal());
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName; auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
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)});
@ -639,12 +645,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pCompositor->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_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
g_pInputManager->sendMotionEventsToFocused(); if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->constraintActive)
g_pInputManager->sendMotionEventsToFocused();
// fix some xwayland apps that don't behave nicely // fix some xwayland apps that don't behave nicely
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID); g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
if (PMONITOR && PWINDOW->m_iX11Type == 2)
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
} }
void Events::listener_unmapWindow(void* owner, void* data) { void Events::listener_unmapWindow(void* owner, void* data) {
@ -660,8 +670,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR) { if (PMONITOR) {
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition; PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec(); PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value();
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents(); PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
} }
@ -673,7 +683,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_setTitleWindow.removeCallback(); PWINDOW->hyprListener_setTitleWindow.removeCallback();
PWINDOW->hyprListener_newPopupXDG.removeCallback();
PWINDOW->hyprListener_requestMaximize.removeCallback(); PWINDOW->hyprListener_requestMaximize.removeCallback();
PWINDOW->hyprListener_requestMinimize.removeCallback(); PWINDOW->hyprListener_requestMinimize.removeCallback();
PWINDOW->hyprListener_requestMove.removeCallback(); PWINDOW->hyprListener_requestMove.removeCallback();
@ -745,19 +754,14 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus."); Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
} }
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window {}", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
PWINDOW->m_pSurfaceTree = nullptr;
PWINDOW->m_bFadingOut = true; PWINDOW->m_bFadingOut = true;
g_pCompositor->addToFadingOutSafe(PWINDOW); g_pCompositor->addToFadingOutSafe(PWINDOW);
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.vec() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
// anims // anims
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true); g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true);
@ -793,6 +797,30 @@ void Events::listener_ackConfigure(void* owner, void* data) {
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_bIsX11 && PWINDOW->m_uSurface.xdg->initial_commit) {
Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow();
if (g_pXWaylandManager->shouldBeFloated(PWINDOW, true))
predSize = {};
Vector2D maxSize = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->pending.max_width, PWINDOW->m_uSurface.xdg->toplevel->pending.max_height};
if ((maxSize.x > 0 && maxSize.x < predSize.x) || (maxSize.y > 0 && maxSize.y < predSize.y))
predSize = {};
for (auto& r : g_pConfigManager->getMatchingRules(PWINDOW)) {
if (r.szRule == "float") {
predSize = {};
break;
}
}
Debug::log(LOG, "Layout predicts size {} for {}", predSize, PWINDOW);
wlr_xdg_toplevel_set_size(PWINDOW->m_uSurface.xdg->toplevel, predSize.x, predSize.y);
return;
}
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden()) if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
return; return;
@ -803,11 +831,14 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_pPendingSizeAck.reset(); PWINDOW->m_pPendingSizeAck.reset();
} }
PWINDOW->updateSurfaceOutputs(); g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().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);
if (!PWINDOW->m_bIsX11) {
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
PWINDOW->m_pPopupHead->recheckTree();
}
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
return; return;
@ -817,7 +848,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
if (MAXSIZE < Vector2D{1, 1}) if (MAXSIZE < Vector2D{1, 1})
return; return;
const auto REALSIZE = PWINDOW->m_vRealSize.goalv(); const auto REALSIZE = PWINDOW->m_vRealSize.goal();
Vector2D newSize = REALSIZE; Vector2D newSize = REALSIZE;
if (MAXSIZE.x < newSize.x) if (MAXSIZE.x < newSize.x)
@ -831,7 +862,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
const Vector2D DELTA = REALSIZE - newSize; const Vector2D DELTA = REALSIZE - newSize;
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0; PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0;
PWINDOW->m_vRealSize = newSize; PWINDOW->m_vRealSize = newSize;
g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true); g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true);
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
@ -861,14 +892,10 @@ void Events::listener_destroyWindow(void* owner, void* data) {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
if (PWINDOW->m_pSurfaceTree) {
Debug::log(LOG, "Destroying Subsurface tree of {} in destroyWindow", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
PWINDOW->m_pSurfaceTree = nullptr;
}
PWINDOW->m_bReadyToDelete = true; PWINDOW->m_bReadyToDelete = true;
PWINDOW->m_uSurface.xdg = nullptr;
if (!PWINDOW->m_bFadingOut) { if (!PWINDOW->m_bFadingOut) {
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW); Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
@ -906,7 +933,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
return; return;
} }
if (PWINDOW->isHidden() || PWINDOW->m_bNoFullscreenRequest) if (PWINDOW->isHidden() || (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
return; return;
bool requestedFullState = false; bool requestedFullState = false;
@ -960,7 +987,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
void Events::listener_activateXDG(wl_listener* listener, void* data) { void Events::listener_activateXDG(wl_listener* listener, void* data) {
const auto E = (wlr_xdg_activation_v1_request_activate_event*)data; const auto E = (wlr_xdg_activation_v1_request_activate_event*)data;
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue; static auto* const PFOCUSONACTIVATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:focus_on_activate");
Debug::log(LOG, "Activate request for surface at {:x}", (uintptr_t)E->surface); Debug::log(LOG, "Activate request for surface at {:x}", (uintptr_t)E->surface);
@ -969,7 +996,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(E->surface); const auto PWINDOW = g_pCompositor->getWindowFromSurface(E->surface);
if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow) if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE))
return; return;
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)}); g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
@ -977,7 +1004,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
PWINDOW->m_bIsUrgent = true; PWINDOW->m_bIsUrgent = true;
if (!*PFOCUSONACTIVATE) if (!**PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY))
return; return;
if (PWINDOW->m_bIsFloating) if (PWINDOW->m_bIsFloating)
@ -990,7 +1017,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
void Events::listener_activateX11(void* owner, void* data) { void Events::listener_activateX11(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner; const auto PWINDOW = (CWindow*)owner;
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue; static auto* const PFOCUSONACTIVATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:focus_on_activate");
Debug::log(LOG, "X11 Activate request for window {}", PWINDOW); Debug::log(LOG, "X11 Activate request for window {}", PWINDOW);
@ -1001,17 +1028,20 @@ void Events::listener_activateX11(void* owner, void* data) {
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID()) if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID())
return; return;
if (!wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))
return;
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
return; return;
} }
if (PWINDOW == g_pCompositor->m_pLastWindow) if (PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE))
return; return;
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)}); g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
EMIT_HOOK_EVENT("urgent", PWINDOW); EMIT_HOOK_EVENT("urgent", PWINDOW);
if (!*PFOCUSONACTIVATE) if (!**PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY))
return; return;
if (PWINDOW->m_bIsFloating) if (PWINDOW->m_bIsFloating)
@ -1030,13 +1060,15 @@ void Events::listener_configureX11(void* owner, void* data) {
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height); 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_vPendingReportedSize = {E->width, E->height};
PWINDOW->m_vReportedSize = {E->width, E->height}; PWINDOW->m_vReportedSize = {E->width, E->height};
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
return; return;
} }
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == PWINDOW) { if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == PWINDOW) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
return; return;
@ -1052,17 +1084,16 @@ void Events::listener_configureX11(void* owner, void* data) {
PWINDOW->m_vRealPosition.setValueAndWarp(LOGICALPOS); PWINDOW->m_vRealPosition.setValueAndWarp(LOGICALPOS);
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height)); PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height));
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue; static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling");
if (*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.goal() / PMONITOR->scale);
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale); PWINDOW->m_fX11SurfaceScaledBy = 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.value();
PWINDOW->m_vSize = PWINDOW->m_vRealSize.vec(); PWINDOW->m_vSize = PWINDOW->m_vRealSize.value();
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);
@ -1074,7 +1105,7 @@ void Events::listener_configureX11(void* owner, void* data) {
if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_iWorkspaceID)) if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_iWorkspaceID))
return; // further things are only for visible windows return; // further things are only for visible windows
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace; PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(PWINDOW, true); g_pCompositor->changeWindowZOrder(PWINDOW, true);
@ -1092,8 +1123,8 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
if (!PWINDOW->m_bIsMapped) if (!PWINDOW->m_bIsMapped)
return; return;
const auto POS = PWINDOW->m_vRealPosition.goalv(); const auto POS = PWINDOW->m_vRealPosition.goal();
const auto SIZ = PWINDOW->m_vRealSize.goalv(); const auto SIZ = PWINDOW->m_vRealSize.goal();
if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1) if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1)
PWINDOW->setHidden(false); PWINDOW->setHidden(false);
@ -1101,12 +1132,12 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->setHidden(true); PWINDOW->setHidden(true);
if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
return; return;
} }
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue; static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling");
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y}); const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y});
@ -1121,26 +1152,25 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
if (abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) if (abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2)
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height)); 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; const Vector2D DELTA = PWINDOW->m_vRealSize.goal() - PWINDOW->m_vRealSize.goal() / PMONITOR->scale;
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale); PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0); PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goal() + DELTA / 2.0);
} }
} }
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv(); PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal();
PWINDOW->m_vSize = PWINDOW->m_vRealSize.goalv(); PWINDOW->m_vSize = PWINDOW->m_vRealSize.goal();
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace; PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(PWINDOW, true); 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_vReportedPosition = PWINDOW->m_vRealPosition.goal();
PWINDOW->m_vReportedSize = PWINDOW->m_vRealSize.goalv(); PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal();
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vReportedSize;
} }
} }
@ -1211,7 +1241,7 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
void Events::listener_requestMaximize(void* owner, void* data) { void Events::listener_requestMaximize(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner; const auto PWINDOW = (CWindow*)owner;
if (PWINDOW->m_bNoMaximizeRequest) if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)
return; return;
Debug::log(LOG, "Maximize request for {}", PWINDOW); Debug::log(LOG, "Maximize request for {}", PWINDOW);

View file

@ -2,12 +2,11 @@
#include "../managers/AnimationManager.hpp" #include "../managers/AnimationManager.hpp"
#include "../config/ConfigManager.hpp" #include "../config/ConfigManager.hpp"
CAnimatedVariable::CAnimatedVariable() { CBaseAnimatedVariable::CBaseAnimatedVariable(ANIMATEDVARTYPE type) : m_Type(type) {
; // dummy var ; // dummy var
} }
void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) { void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
m_eVarType = type;
m_eDamagePolicy = policy; m_eDamagePolicy = policy;
m_pConfig = pAnimConfig; m_pConfig = pAnimConfig;
m_pWindow = pWindow; m_pWindow = pWindow;
@ -15,42 +14,11 @@ void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* p
m_bDummy = false; m_bDummy = false;
} }
void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) { CBaseAnimatedVariable::~CBaseAnimatedVariable() {
create(type, pAnimConfig, pWindow, policy);
try {
switch (type) {
case AVARTYPE_FLOAT: {
const auto V = std::any_cast<float>(val);
m_fValue = V;
m_fGoal = V;
break;
}
case AVARTYPE_VECTOR: {
const auto V = std::any_cast<Vector2D>(val);
m_vValue = V;
m_vGoal = V;
break;
}
case AVARTYPE_COLOR: {
const auto V = std::any_cast<CColor>(val);
m_cValue = V;
m_cGoal = V;
break;
}
default: ASSERT(false); break;
}
} catch (std::exception& e) {
Debug::log(ERR, "CAnimatedVariable create error: {}", e.what());
RASSERT(false, "CAnimatedVariable create error: {}", e.what());
}
}
CAnimatedVariable::~CAnimatedVariable() {
unregister(); unregister();
} }
void CAnimatedVariable::unregister() { void CBaseAnimatedVariable::unregister() {
if (!g_pAnimationManager) if (!g_pAnimationManager)
return; return;
std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; }); std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; });
@ -58,23 +26,26 @@ void CAnimatedVariable::unregister() {
disconnectFromActive(); disconnectFromActive();
} }
void CAnimatedVariable::registerVar() { void CBaseAnimatedVariable::registerVar() {
if (!m_bIsRegistered) if (!m_bIsRegistered)
g_pAnimationManager->m_vAnimatedVariables.push_back(this); g_pAnimationManager->m_vAnimatedVariables.push_back(this);
m_bIsRegistered = true; m_bIsRegistered = true;
} }
int CAnimatedVariable::getDurationLeftMs() { int CBaseAnimatedVariable::getDurationLeftMs() {
return std::max( return std::max(
(int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0); (int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0);
} }
float CAnimatedVariable::getPercent() { float CBaseAnimatedVariable::getPercent() {
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(); const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count();
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f); return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
} }
float CAnimatedVariable::getCurveValue() { float CBaseAnimatedVariable::getCurveValue() {
if (!m_bIsBeingAnimated)
return 1.f;
const auto SPENT = getPercent(); const auto SPENT = getPercent();
if (SPENT >= 1.f) if (SPENT >= 1.f)
@ -83,7 +54,7 @@ float CAnimatedVariable::getCurveValue() {
return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT); return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT);
} }
void CAnimatedVariable::connectToActive() { void CBaseAnimatedVariable::connectToActive() {
g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up
if (!m_bIsConnectedToActive) if (!m_bIsConnectedToActive)
@ -92,7 +63,7 @@ void CAnimatedVariable::connectToActive() {
m_bIsConnectedToActive = true; m_bIsConnectedToActive = true;
} }
void CAnimatedVariable::disconnectFromActive() { void CBaseAnimatedVariable::disconnectFromActive() {
std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; }); std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; });
m_bIsConnectedToActive = false; m_bIsConnectedToActive = false;
} }

View file

@ -3,6 +3,7 @@
#include <functional> #include <functional>
#include <any> #include <any>
#include <chrono> #include <chrono>
#include <type_traits>
#include "Vector2D.hpp" #include "Vector2D.hpp"
#include "Color.hpp" #include "Color.hpp"
#include "../macros.hpp" #include "../macros.hpp"
@ -15,6 +16,30 @@ enum ANIMATEDVARTYPE {
AVARTYPE_COLOR AVARTYPE_COLOR
}; };
// Utility to bind a type with its corresponding ANIMATEDVARTYPE
template <class T>
struct typeToANIMATEDVARTYPE_t {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_INVALID;
};
template <>
struct typeToANIMATEDVARTYPE_t<float> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_FLOAT;
};
template <>
struct typeToANIMATEDVARTYPE_t<Vector2D> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_VECTOR;
};
template <>
struct typeToANIMATEDVARTYPE_t<CColor> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_COLOR;
};
template <class T>
inline constexpr ANIMATEDVARTYPE typeToANIMATEDVARTYPE = typeToANIMATEDVARTYPE_t<T>::value;
enum AVARDAMAGEPOLICY { enum AVARDAMAGEPOLICY {
AVARDAMAGE_NONE = -1, AVARDAMAGE_NONE = -1,
AVARDAMAGE_ENTIRE = 0, AVARDAMAGE_ENTIRE = 0,
@ -28,174 +53,34 @@ struct SLayerSurface;
struct SAnimationPropertyConfig; struct SAnimationPropertyConfig;
class CHyprRenderer; class CHyprRenderer;
class CAnimatedVariable { // Utility to define a concept as a list of possible type
template <class T, class... U>
concept OneOf = (... or std::same_as<T, U>);
// Concept to describe which type can be placed into CAnimatedVariable
// This is mainly to get better errors if we put a type that's not supported
// Otherwise template errors are ugly
template <class T>
concept Animable = OneOf<T, Vector2D, float, CColor>;
class CBaseAnimatedVariable {
public: public:
CAnimatedVariable(); // dummy var CBaseAnimatedVariable(ANIMATEDVARTYPE type);
void create(SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy);
void create(ANIMATEDVARTYPE, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY); CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
void create(ANIMATEDVARTYPE, std::any val, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY); CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
CBaseAnimatedVariable& operator=(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable& operator=(CBaseAnimatedVariable&&) = delete;
CAnimatedVariable(const CAnimatedVariable&) = delete; virtual ~CBaseAnimatedVariable();
CAnimatedVariable(CAnimatedVariable&&) = delete;
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
~CAnimatedVariable(); void unregister();
void registerVar();
void unregister(); virtual void warp(bool endCallback = true) = 0;
void registerVar();
// gets the current vector value (real time)
const Vector2D& vec() const {
return m_vValue;
}
// gets the current float value (real time)
const float& fl() const {
return m_fValue;
}
// gets the current color value (real time)
const CColor& col() const {
return m_cValue;
}
// gets the goal vector value
const Vector2D& goalv() const {
return m_vGoal;
}
// gets the goal float value
const float& goalf() const {
return m_fGoal;
}
// gets the goal color value
const CColor& goalc() const {
return m_cGoal;
}
CAnimatedVariable& operator=(const Vector2D& v) {
if (v == m_vGoal)
return *this;
m_vGoal = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
return *this;
}
CAnimatedVariable& operator=(const float& v) {
if (v == m_fGoal)
return *this;
m_fGoal = v;
animationBegin = std::chrono::system_clock::now();
m_fBegun = m_fValue;
onAnimationBegin();
return *this;
}
CAnimatedVariable& operator=(const CColor& v) {
if (v == m_cGoal)
return *this;
m_cGoal = v;
animationBegin = std::chrono::system_clock::now();
m_cBegun = m_cValue;
onAnimationBegin();
return *this;
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const Vector2D& v) {
if (v == m_vValue)
return;
m_vValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const float& v) {
if (v == m_fValue)
return;
m_fValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const CColor& v) {
if (v == m_cValue)
return;
m_cValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
// Sets the actual value and goal
void setValueAndWarp(const Vector2D& v) {
m_vGoal = v;
warp();
}
// Sets the actual value and goal
void setValueAndWarp(const float& v) {
m_fGoal = v;
warp();
}
// Sets the actual value and goal
void setValueAndWarp(const CColor& v) {
m_cGoal = v;
warp();
}
// checks if an animation is in progress
inline bool isBeingAnimated() {
return m_bIsBeingAnimated;
}
void warp(bool endCallback = true) {
switch (m_eVarType) {
case AVARTYPE_FLOAT: {
m_fValue = m_fGoal;
break;
}
case AVARTYPE_VECTOR: {
m_vValue = m_vGoal;
break;
}
case AVARTYPE_COLOR: {
m_cValue = m_cGoal;
break;
}
default: UNREACHABLE();
}
m_bIsBeingAnimated = false;
if (endCallback)
onAnimationEnd();
}
//
void setConfig(SAnimationPropertyConfig* pConfig) { void setConfig(SAnimationPropertyConfig* pConfig) {
m_pConfig = pConfig; m_pConfig = pConfig;
} }
@ -212,6 +97,11 @@ class CAnimatedVariable {
/* returns the current curve value */ /* returns the current curve value */
float getCurveValue(); float getCurveValue();
// checks if an animation is in progress
inline bool isBeingAnimated() {
return m_bIsBeingAnimated;
}
/* sets a function to be ran when the animation finishes. /* sets a function to be ran when the animation finishes.
if an animation is not running, runs instantly. if an animation is not running, runs instantly.
if "remove" is set to true, will remove the callback when ran. */ if "remove" is set to true, will remove the callback when ran. */
@ -245,20 +135,7 @@ class CAnimatedVariable {
m_bRemoveEndAfterRan = false; m_bRemoveEndAfterRan = false;
} }
private: protected:
Vector2D m_vValue = Vector2D(0, 0);
float m_fValue = 0;
CColor m_cValue;
Vector2D m_vGoal = Vector2D(0, 0);
float m_fGoal = 0;
CColor m_cGoal;
Vector2D m_vBegun = Vector2D(0, 0);
float m_fBegun = 0;
CColor m_cBegun;
// owners
void* m_pWindow = nullptr; void* m_pWindow = nullptr;
void* m_pWorkspace = nullptr; void* m_pWorkspace = nullptr;
void* m_pLayer = nullptr; void* m_pLayer = nullptr;
@ -271,8 +148,8 @@ class CAnimatedVariable {
std::chrono::system_clock::time_point animationBegin; std::chrono::system_clock::time_point animationBegin;
ANIMATEDVARTYPE m_eVarType = AVARTYPE_INVALID;
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE; AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE;
ANIMATEDVARTYPE m_Type;
bool m_bRemoveEndAfterRan = true; bool m_bRemoveEndAfterRan = true;
bool m_bRemoveBeginAfterRan = true; bool m_bRemoveBeginAfterRan = true;
@ -281,7 +158,9 @@ class CAnimatedVariable {
std::function<void(void* thisptr)> m_fUpdateCallback; std::function<void(void* thisptr)> m_fUpdateCallback;
bool m_bIsConnectedToActive = false; bool m_bIsConnectedToActive = false;
void connectToActive(); void connectToActive();
void disconnectFromActive(); void disconnectFromActive();
// methods // methods
@ -314,3 +193,85 @@ class CAnimatedVariable {
friend struct SLayerSurface; friend struct SLayerSurface;
friend class CHyprRenderer; friend class CHyprRenderer;
}; };
template <Animable VarType>
class CAnimatedVariable : public CBaseAnimatedVariable {
public:
CAnimatedVariable() : CBaseAnimatedVariable(typeToANIMATEDVARTYPE<VarType>) {} // dummy var
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pWindow, policy);
m_Value = value;
}
using CBaseAnimatedVariable::create;
CAnimatedVariable(const CAnimatedVariable&) = delete;
CAnimatedVariable(CAnimatedVariable&&) = delete;
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
~CAnimatedVariable() = default;
// gets the current vector value (real time)
const VarType& value() const {
return m_Value;
}
// gets the goal vector value
const VarType& goal() const {
return m_Goal;
}
CAnimatedVariable& operator=(const VarType& v) {
if (v == m_Goal)
return *this;
m_Goal = v;
animationBegin = std::chrono::system_clock::now();
m_Begun = m_Value;
onAnimationBegin();
return *this;
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const VarType& v) {
if (v == m_Value)
return;
m_Value = v;
animationBegin = std::chrono::system_clock::now();
m_Begun = m_Value;
onAnimationBegin();
}
// Sets the actual value and goal
void setValueAndWarp(const VarType& v) {
m_Goal = v;
warp();
}
void warp(bool endCallback = true) override {
m_Value = m_Goal;
m_bIsBeingAnimated = false;
if (endCallback)
onAnimationEnd();
}
private:
VarType m_Value{};
VarType m_Goal{};
VarType m_Begun{};
// owners
friend class CAnimationManager;
friend class CWorkspace;
friend struct SLayerSurface;
friend class CHyprRenderer;
};

View file

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

View file

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

View file

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

View file

@ -15,6 +15,7 @@ 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);
void removeWLSignal(wl_listener*);
std::string escapeJSONStrings(const std::string& str); std::string escapeJSONStrings(const std::string& str);
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);

View file

@ -1,5 +1,7 @@
#include "Monitor.hpp" #include "Monitor.hpp"
#include "MiscFunctions.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
int ratHandler(void* data) { int ratHandler(void* data) {
@ -8,7 +10,7 @@ int ratHandler(void* data) {
return 1; return 1;
} }
CMonitor::CMonitor() { CMonitor::CMonitor() : state(this) {
wlr_damage_ring_init(&damage); wlr_damage_ring_init(&damage);
} }
@ -43,8 +45,8 @@ void CMonitor::onConnect(bool noRule) {
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm 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_state_set_enabled(state.wlr(), true);
wlr_output_commit(output); state.commit();
return; return;
} }
@ -54,17 +56,21 @@ void CMonitor::onConnect(bool noRule) {
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description // 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()); szDescription.erase(std::remove(szDescription.begin(), szDescription.end(), ','), szDescription.end());
// field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix
szShortDescription =
removeBeginEndSpacesTabs(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : ""));
if (!wlr_backend_is_drm(output->backend)) 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
// get monitor rule that matches // get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : ""); SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { if (monitorRule.disabled) {
wlr_output_set_scale(output, 1); wlr_output_state_set_scale(state.wlr(), 1);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
auto PREFSTATE = wlr_output_preferred_mode(output); auto PREFSTATE = wlr_output_preferred_mode(output);
@ -72,9 +78,9 @@ void CMonitor::onConnect(bool noRule) {
wlr_output_mode* mode; wlr_output_mode* mode;
wl_list_for_each(mode, &output->modes, link) { wl_list_for_each(mode, &output->modes, link) {
wlr_output_set_mode(output, PREFSTATE); wlr_output_state_set_mode(state.wlr(), mode);
if (!wlr_output_test(output)) if (!wlr_output_test_state(output, state.wlr()))
continue; continue;
PREFSTATE = mode; PREFSTATE = mode;
@ -83,13 +89,13 @@ void CMonitor::onConnect(bool noRule) {
} }
if (PREFSTATE) if (PREFSTATE)
wlr_output_set_mode(output, PREFSTATE); wlr_output_state_set_mode(state.wlr(), PREFSTATE);
else else
Debug::log(WARN, "No mode found for disabled output {}", output->name); Debug::log(WARN, "No mode found for disabled output {}", output->name);
wlr_output_enable(output, 0); wlr_output_state_set_enabled(state.wlr(), 0);
if (!wlr_output_commit(output)) if (!state.commit())
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name); Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
m_bEnabled = false; m_bEnabled = false;
@ -130,13 +136,28 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true; m_bEnabled = true;
wlr_output_enable(output, 1); wlr_output_state_set_enabled(state.wlr(), 1);
// set mode, also applies // set mode, also applies
if (!noRule) if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
wlr_output_commit(output); for (const auto& PTOUCHDEV : g_pInputManager->m_lTouchDevices) {
if (matchesStaticSelector(PTOUCHDEV.boundOutput)) {
Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV.name, szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTOUCHDEV.pWlrDevice, output);
}
}
for (const auto& PTABLET : g_pInputManager->m_lTablets) {
if (matchesStaticSelector(PTABLET.boundOutput)) {
Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output);
}
}
if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y); wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
@ -162,6 +183,7 @@ void CMonitor::onConnect(bool noRule) {
// //
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)});
EMIT_HOOK_EVENT("monitorAdded", this); EMIT_HOOK_EVENT("monitorAdded", this);
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
@ -283,9 +305,10 @@ void CMonitor::onDisconnect(bool destroy) {
if (!destroy) 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_state_set_enabled(state.wlr(), false);
wlr_output_commit(output); if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor == this) if (g_pCompositor->m_pLastMonitor == this)
g_pCompositor->setActiveMonitor(BACKUPMON); g_pCompositor->setActiveMonitor(BACKUPMON);
@ -307,13 +330,11 @@ void CMonitor::onDisconnect(bool destroy) {
} }
void CMonitor::addDamage(const pixman_region32_t* rg) { void CMonitor::addDamage(const pixman_region32_t* rg) {
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue; static auto* const PZOOMFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor");
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);
} } else if (wlr_damage_ring_add(&damage, rg))
if (wlr_damage_ring_add(&damage, rg))
g_pCompositor->scheduleFrameForMonitor(this); g_pCompositor->scheduleFrameForMonitor(this);
} }
@ -322,8 +343,8 @@ void CMonitor::addDamage(const CRegion* rg) {
} }
void CMonitor::addDamage(const CBox* box) { void CMonitor::addDamage(const CBox* box) {
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue; static auto* const PZOOMFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor");
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);
} }
@ -336,6 +357,19 @@ bool CMonitor::isMirror() {
return pMirrorOf != nullptr; return pMirrorOf != nullptr;
} }
bool CMonitor::matchesStaticSelector(const std::string& selector) const {
if (selector.starts_with("desc:")) {
// match by description
const auto DESCRIPTIONSELECTOR = selector.substr(5);
const auto DESCRIPTION = removeBeginEndSpacesTabs(szDescription.substr(0, szDescription.find_first_of('(')));
return DESCRIPTIONSELECTOR == szDescription || DESCRIPTIONSELECTOR == DESCRIPTION;
} else {
// match by selector
return szName == selector;
}
}
int CMonitor::findAvailableDefaultWS() { int CMonitor::findAvailableDefaultWS() {
for (size_t i = 1; i < INT32_MAX; ++i) { for (size_t i = 1; i < INT32_MAX; ++i) {
if (g_pCompositor->getWorkspaceByID(i)) if (g_pCompositor->getWorkspaceByID(i))
@ -415,7 +449,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = nullptr; pMirrorOf = nullptr;
// set rule // set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName, this->output->description ? this->output->description : ""); const auto RULE = g_pConfigManager->getMonitorRuleFor(*this);
vecPosition = RULE.offset; vecPosition = RULE.offset;
@ -502,7 +536,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;
@ -533,13 +567,13 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
} }
} }
if (!g_pCompositor->m_pLastMonitor->specialWorkspaceID) { if (!noFocus && !g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue; static auto* const PFOLLOWMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:follow_mouse");
CWindow* pWindow = pWorkspace->getLastFocusedWindow(); CWindow* pWindow = pWorkspace->getLastFocusedWindow();
if (!pWindow) { if (!pWindow) {
if (*PFOLLOWMOUSE == 1) if (**PFOLLOWMOUSE == 1)
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()); pWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!pWindow) if (!pWindow)
pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID); pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
@ -569,8 +603,8 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
g_pCompositor->updateSuspendedStates(); g_pCompositor->updateSuspendedStates();
} }
void CMonitor::changeWorkspace(const int& id, bool internal) { void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) {
changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal); changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus);
} }
void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) { void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
@ -621,17 +655,17 @@ 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(); 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 (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 // if it's floating and the middle isnt on the current mon, move it to the center
const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE); const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE);
Vector2D pos = w->m_vRealPosition.goalv(); Vector2D pos = w->m_vRealPosition.goal();
if (!VECINRECT(MIDDLE, PMONFROMMIDDLE->vecPosition.x, PMONFROMMIDDLE->vecPosition.y, PMONFROMMIDDLE->vecPosition.x + PMONFROMMIDDLE->vecSize.x, if (!VECINRECT(MIDDLE, PMONFROMMIDDLE->vecPosition.x, PMONFROMMIDDLE->vecPosition.y, PMONFROMMIDDLE->vecPosition.x + PMONFROMMIDDLE->vecSize.x,
PMONFROMMIDDLE->vecPosition.y + PMONFROMMIDDLE->vecSize.y)) { PMONFROMMIDDLE->vecPosition.y + PMONFROMMIDDLE->vecSize.y)) {
// not on any monitor, center // not on any monitor, center
pos = middle() / 2.f - w->m_vRealSize.goalv() / 2.f; pos = middle() / 2.f - w->m_vRealSize.goal() / 2.f;
} else } else
pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition; pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition;
@ -678,3 +712,32 @@ void CMonitor::updateMatrix() {
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0); wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
} }
} }
CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
wlr_output_state_init(&m_state);
}
CMonitorState::~CMonitorState() {
wlr_output_state_finish(&m_state);
}
wlr_output_state* CMonitorState::wlr() {
return &m_state;
}
void CMonitorState::clear() {
wlr_output_state_finish(&m_state);
m_state = {0};
wlr_output_state_init(&m_state);
}
bool CMonitorState::commit() {
bool ret = wlr_output_commit_state(m_pOwner->output, &m_state);
clear();
return ret;
}
bool CMonitorState::test() {
return wlr_output_test_state(m_pOwner->output, &m_state);
}

View file

@ -25,6 +25,25 @@ struct SMonitorRule {
std::optional<int> vrr; std::optional<int> vrr;
}; };
class CMonitor;
// Class for wrapping the wlr state
class CMonitorState {
public:
CMonitorState(CMonitor* owner);
~CMonitorState();
wlr_output_state* wlr();
void clear();
// commit() will also clear()
bool commit();
bool test();
private:
wlr_output_state m_state = {0};
CMonitor* m_pOwner;
};
class CMonitor { class CMonitor {
public: public:
CMonitor(); CMonitor();
@ -43,49 +62,51 @@ class CMonitor {
float setScale = 1; // scale set by cfg float setScale = 1; // scale set by cfg
float scale = 1; // real scale float scale = 1; // real scale
std::string szName = ""; std::string szName = "";
std::string szDescription = ""; std::string szDescription = "";
std::string szShortDescription = "";
Vector2D vecReservedTopLeft = Vector2D(0, 0); Vector2D vecReservedTopLeft = Vector2D(0, 0);
Vector2D vecReservedBottomRight = Vector2D(0, 0); Vector2D vecReservedBottomRight = Vector2D(0, 0);
drmModeModeInfo customDrmMode = {}; drmModeModeInfo customDrmMode = {};
CMonitorState state;
// WLR stuff // WLR stuff
wlr_damage_ring damage; wlr_damage_ring damage;
wlr_output* output = nullptr; wlr_output* output = nullptr;
float refreshRate = 60; float refreshRate = 60;
int framesToSkip = 0; int framesToSkip = 0;
int forceFullFrames = 0; int forceFullFrames = 0;
bool noFrameSchedule = false; bool noFrameSchedule = false;
bool scheduledRecalc = false; bool scheduledRecalc = false;
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}; std::array<float, 9> projMatrix = {0};
std::optional<Vector2D> forceSize;
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; uint32_t drmFormat = DRM_FORMAT_INVALID;
bool isUnsafeFallback = false; 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;
wl_event_source* renderTimer = nullptr; // for RAT wl_event_source* renderTimer = nullptr; // for RAT
bool RATScheduled = false; bool RATScheduled = false;
CTimer lastPresentationTimer; CTimer lastPresentationTimer;
SMonitorRule activeMonitorRule; SMonitorRule activeMonitorRule;
// mirroring // mirroring
CMonitor* pMirrorOf = nullptr; CMonitor* pMirrorOf = nullptr;
std::vector<CMonitor*> mirrors; std::vector<CMonitor*> mirrors;
CRegion lastFrameDamage; // stores last frame damage
// for tearing // for tearing
CWindow* solitaryClient = nullptr; CWindow* solitaryClient = nullptr;
@ -119,9 +140,10 @@ class CMonitor {
void addDamage(const CBox* box); void addDamage(const CBox* box);
void setMirror(const std::string&); void setMirror(const std::string&);
bool isMirror(); bool isMirror();
bool matchesStaticSelector(const std::string& selector) const;
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, bool noMouseMove = false, bool noFocus = 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);

View file

@ -112,6 +112,11 @@ CRegion& CRegion::scale(float scale) {
return *this; return *this;
} }
CRegion& CRegion::scale(const Vector2D& scale) {
wlr_region_scale_xy(&m_rRegion, &m_rRegion, scale.x, scale.y);
return *this;
}
std::vector<pixman_box32_t> CRegion::getRects() const { std::vector<pixman_box32_t> CRegion::getRects() const {
std::vector<pixman_box32_t> result; std::vector<pixman_box32_t> result;

View file

@ -49,6 +49,7 @@ class CRegion {
CRegion& invert(pixman_box32_t* box); CRegion& invert(pixman_box32_t* box);
CRegion& invert(const CBox& box); CRegion& invert(const CBox& box);
CRegion& scale(float scale); CRegion& scale(float scale);
CRegion& scale(const Vector2D& scale);
CBox getExtents(); CBox getExtents();
bool containsPoint(const Vector2D& vec) const; bool containsPoint(const Vector2D& vec) const;
bool empty() const; bool empty() const;
@ -57,7 +58,8 @@ class CRegion {
std::vector<pixman_box32_t> getRects() const; std::vector<pixman_box32_t> getRects() const;
pixman_region32_t* pixman() { //
pixman_region32_t* pixman() {
return &m_rRegion; return &m_rRegion;
} }

View file

@ -19,6 +19,21 @@ inline const std::vector<std::string> SPLASHES = {
"Compile, wait for 20 minutes, notice a new commit, compile again.", "Compile, wait for 20 minutes, notice a new commit, compile again.",
"To rice, or not to rice, that is the question.", "To rice, or not to rice, that is the question.",
"Now available on Fedora!", "Now available on Fedora!",
"\"Hyprland is so good it starts with a capital letter\" - Hazel",
"\"please make this message a splash\" - eriedaberrie",
"\"the only wayland compositor powered by fried chicken\" - raf",
"\"This will never get into Hyprland\" - Flafy",
"\"Hyprland only gives you up on -git\" - fazzi",
"Segmentation fault (core dumped)",
"\"disabling hyprland logo is a war crime\" - vaxry",
"some basic startup code",
"\"I think I am addicted to hyprland\" - mathisbuilder",
"\"hyprland is the most important package in the arch repos\" - jacekpoz",
"Thanks Brodie!",
"Thanks fufexan!",
"Thanks raf!",
"You can't use --splash to change this message :)",
"Hyprland will overtake Gnome in popularity by [insert year]",
// music reference / quote section // music reference / quote section
"J'remue le ciel, le jour, la nuit.", "J'remue le ciel, le jour, la nuit.",
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!", "aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
@ -26,23 +41,6 @@ inline const std::vector<std::string> SPLASHES = {
"I see a red door and I want it painted black.", "I see a red door and I want it painted black.",
"Take on me, take me on...", "Take on me, take me on...",
"You spin me right round baby right round", "You spin me right round baby right round",
"Through the fire and the flames, we carry on!",
"Life could be a dream, sweetheart",
"We're off to never-never land",
"Just remember ALL CAPS when you spell the man name",
"The cake is a lie The cake is a lie The cake is a lie The cake is a lie",
"WE'RE SHAMELESS",
"Now I only want you gone",
"You Forget A Thousand Things Every Day Pal. Make Sure This Is One Of 'Em."
"The right man in the wrong place can make all the difference in the world."
"Truth Is, The Game Was Rigged From The Start."
"It's said war, war never changes. Men do, through the roads they walk."
"Victory shall be ours, it shall be swift, and it will be honest; purchased with blood."
"Patrolling the Mojave almost makes you wish for a nuclear winter."
"When life gives you lemons, dont make lemonade…"
"You Picked The Wrong House, Fool!"
"I suck at life, but I bowl like an angel."
"Swaying to the symphony... of destruction!",
"Stayin' alive, stayin' alive", "Stayin' alive, stayin' alive",
"Say no way, say no way ya, no way!", "Say no way, say no way ya, no way!",
"Ground control to Major Tom...", "Ground control to Major Tom...",
@ -79,4 +77,4 @@ inline const std::vector<std::string> SPLASHES = {
"The AUR packages always work, except for the times they don't.", "The AUR packages always work, except for the times they don't.",
"Funny animation compositor woo" "Funny animation compositor woo"
// clang-format on // clang-format on
}; };

View file

@ -1,311 +0,0 @@
#include "SubsurfaceTree.hpp"
#include "../events/Events.hpp"
#include "../Compositor.hpp"
void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
if (!node->pSurface || !node->pSurface->exists())
return;
*lx += node->pSurface->wlr()->current.dx;
*ly += node->pSurface->wlr()->current.dy;
if (node->offsetfn) {
// This is the root node
RASSERT(!node->pSubsurface, "Node had no subsurface!");
node->offsetfn(node->globalOffsetData, lx, ly);
} else {
RASSERT(node->pSubsurface, "Node had no subsurface!");
*lx += node->pSubsurface->pSubsurface->current.x;
*ly += node->pSubsurface->pSubsurface->current.y;
addSurfaceGlobalOffset(node->pParent, lx, ly);
}
}
SSurfaceTreeNode* createTree(wlr_surface* pSurface, CWindow* pWindow) {
const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.emplace_back();
if (pSurface->data)
PNODE->pSurface = (CWLSurface*)pSurface->data;
else {
PNODE->pInternalSurface = pSurface;
PNODE->pSurface = &PNODE->pInternalSurface;
}
PNODE->pWindowOwner = pWindow;
PNODE->hyprListener_newSubsurface.initCallback(&pSurface->events.new_subsurface, &Events::listener_newSubsurfaceNode, PNODE, "SurfaceTreeNode");
PNODE->hyprListener_commit.initCallback(&pSurface->events.commit, &Events::listener_commitSubsurface, PNODE, "SurfaceTreeNode");
PNODE->hyprListener_destroy.initCallback(&pSurface->events.destroy, &Events::listener_destroySubsurfaceNode, PNODE, "SurfaceTreeNode");
wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_below, current.link) {
Events::listener_newSubsurfaceNode(PNODE, wlrSubsurface);
}
wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_above, current.link) {
Events::listener_newSubsurfaceNode(PNODE, wlrSubsurface);
}
return PNODE;
}
SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* pSubsurface, wlr_surface* surface, CWindow* pWindow) {
const auto PNODE = createTree(surface, pWindow);
PNODE->pParent = pParent;
PNODE->pSubsurface = pSubsurface;
Debug::log(LOG, "Creating a subsurface Node! {}", pWindow);
return PNODE;
}
SSurfaceTreeNode* SubsurfaceTree::createTreeRoot(wlr_surface* pSurface, applyGlobalOffsetFn fn, void* data, CWindow* pWindow) {
const auto PNODE = createTree(pSurface, pWindow);
Debug::log(LOG, "Creating a surfaceTree Root! {}", pWindow);
PNODE->offsetfn = fn;
PNODE->globalOffsetData = data;
return PNODE;
}
void destroySubsurface(SSubsurface* pSubsurface);
void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
bool exists = false;
for (auto& n : surfaceTreeNodes) {
if (&n == pNode) {
exists = true;
break;
}
}
if (!exists) {
Debug::log(ERR, "Tried to remove a SurfaceTreeNode that doesn't exist?? (Node {:x})", (uintptr_t)pNode);
return;
}
for (auto& c : pNode->childSubsurfaces)
destroySubsurface(&c);
pNode->childSubsurfaces.clear();
pNode->hyprListener_commit.removeCallback();
pNode->hyprListener_destroy.removeCallback();
pNode->hyprListener_newSubsurface.removeCallback();
// damage
if (pNode->pSurface && pNode->pSurface->exists()) {
CBox extents = {};
wlr_surface_get_extends(pNode->pSurface->wlr(), extents.pWlr());
extents.applyFromWlr();
int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly);
extents.x += lx;
extents.y += ly;
g_pHyprRenderer->damageBox(&extents);
}
// remove references to this node
for (auto& tn : surfaceTreeNodes) {
for (auto& cs : tn.childSubsurfaces) {
if (cs.pChild == pNode)
cs.pChild = nullptr;
}
}
surfaceTreeNodes.remove(*pNode);
Debug::log(LOG, "SurfaceTree Node removed");
}
void destroySubsurface(SSubsurface* pSubsurface) {
if (pSubsurface->pChild) {
SubsurfaceTree::destroySurfaceTree(pSubsurface->pChild);
pSubsurface->pChild = nullptr;
}
pSubsurface->hyprListener_destroy.removeCallback();
pSubsurface->hyprListener_map.removeCallback();
pSubsurface->hyprListener_unmap.removeCallback();
}
//
// Subsurface listeners
//
void Events::listener_newSubsurfaceNode(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
const auto PSUBSURFACE = (wlr_subsurface*)data;
const auto PNEWSUBSURFACE = &pNode->childSubsurfaces.emplace_back();
Debug::log(LOG, "Added a new subsurface {:x}", (uintptr_t)PSUBSURFACE);
PNEWSUBSURFACE->pSubsurface = PSUBSURFACE;
PNEWSUBSURFACE->pParent = pNode;
PNEWSUBSURFACE->hyprListener_map.initCallback(&PSUBSURFACE->surface->events.map, &Events::listener_mapSubsurface, PNEWSUBSURFACE, "Subsurface");
PNEWSUBSURFACE->hyprListener_unmap.initCallback(&PSUBSURFACE->surface->events.unmap, &Events::listener_unmapSubsurface, PNEWSUBSURFACE, "Subsurface");
PNEWSUBSURFACE->hyprListener_destroy.initCallback(&PSUBSURFACE->events.destroy, &Events::listener_destroySubsurface, PNEWSUBSURFACE, "Subsurface");
PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner;
if (PSUBSURFACE->surface->mapped)
listener_mapSubsurface(PNEWSUBSURFACE, nullptr);
wlr_subsurface* existingWlrSubsurface;
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) {
listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
}
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_above, current.link) {
listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
}
}
void Events::listener_mapSubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
if (subsurface->pChild)
return;
Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface);
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
}
void Events::listener_unmapSubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
Debug::log(LOG, "Subsurface {:x} unmapped", (uintptr_t)subsurface);
if (subsurface->pSubsurface->surface == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons();
if (subsurface->pChild) {
const auto PNODE = subsurface->pChild;
const auto IT =
std::find_if(SubsurfaceTree::surfaceTreeNodes.begin(), SubsurfaceTree::surfaceTreeNodes.end(), [&](const SSurfaceTreeNode& other) { return &other == PNODE; });
if (IT != SubsurfaceTree::surfaceTreeNodes.end()) {
if (PNODE->pSurface && PNODE->pSurface->exists()) {
int lx = 0, ly = 0;
addSurfaceGlobalOffset(PNODE, &lx, &ly);
CBox extents = {lx, ly, 0, 0};
extents.width = PNODE->pSurface->wlr()->current.width;
extents.height = PNODE->pSurface->wlr()->current.height;
g_pHyprRenderer->damageBox(&extents);
}
// SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
// subsurface->pChild = nullptr;
}
}
g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface
}
void Events::listener_commitSubsurface(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
// no damaging if it's not visible
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner);
return;
}
int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly);
const double SCALE = pNode->pWindowOwner && pNode->pWindowOwner->m_bIsX11 ? 1.0 / pNode->pWindowOwner->m_fX11SurfaceScaledBy : 1.0;
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
// What this does is that basically, if the pNode is a child of some other node, on commit,
// it will also damage (check & damage if needed) all its siblings.
if (pNode->pParent)
for (auto& cs : pNode->pParent->childSubsurfaces) {
const auto NODECOORDS = pNode->pSubsurface ? Vector2D(pNode->pSubsurface->pSubsurface->current.x, pNode->pSubsurface->pSubsurface->current.y) : Vector2D();
if (&cs != pNode->pSubsurface && cs.pSubsurface) {
g_pHyprRenderer->damageSurface(cs.pSubsurface->surface, lx - NODECOORDS.x + cs.pSubsurface->current.x, ly - NODECOORDS.y + cs.pSubsurface->current.y, SCALE);
}
}
if (pNode->pSurface && pNode->pSurface->exists()) {
g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE);
if (pNode->lastSize != Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} && pNode->pWindowOwner)
g_pHyprRenderer->damageWindow(pNode->pWindowOwner);
}
if (pNode->pWindowOwner) {
if (pNode->pWindowOwner->m_bIsX11)
pNode->pWindowOwner->m_vReportedSize = pNode->pWindowOwner->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
// tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID);
if (PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
CRegion damageBox;
wlr_surface_get_effective_damage(pNode->pSurface->wlr(), damageBox.pixman());
if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) {
PMONITOR->tearingState.frameScheduledWhileBusy = true;
} else {
PMONITOR->tearingState.nextRenderTorn = true;
g_pHyprRenderer->renderMonitor(PMONITOR);
}
}
}
}
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
}
void Events::listener_destroySubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
if (subsurface->pChild) {
SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
}
Debug::log(LOG, "Subsurface {:x} destroyed", (uintptr_t)subsurface);
subsurface->hyprListener_destroy.removeCallback();
subsurface->hyprListener_map.removeCallback();
subsurface->hyprListener_unmap.removeCallback();
subsurface->pParent->childSubsurfaces.remove(*subsurface);
}
void Events::listener_destroySubsurfaceNode(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
Debug::log(LOG, "Subsurface Node {:x} destroyed", (uintptr_t)pNode);
for (auto& c : pNode->childSubsurfaces)
destroySubsurface(&c);
pNode->hyprListener_commit.removeCallback();
pNode->hyprListener_newSubsurface.removeCallback();
pNode->hyprListener_destroy.removeCallback();
SubsurfaceTree::surfaceTreeNodes.remove(*pNode);
}

View file

@ -1,60 +0,0 @@
#pragma once
#include "../defines.hpp"
#include <list>
#include "WLSurface.hpp"
struct SSubsurface;
class CWindow;
typedef void (*applyGlobalOffsetFn)(void*, int*, int*);
struct SSurfaceTreeNode {
CWLSurface* pSurface = nullptr; // actual surface
CWLSurface pInternalSurface; // not present for head nodes to not dupe wlr_surface ownership
DYNLISTENER(newSubsurface);
DYNLISTENER(commit);
DYNLISTENER(destroy);
SSurfaceTreeNode* pParent = nullptr;
SSubsurface* pSubsurface = nullptr;
std::list<SSubsurface> childSubsurfaces;
applyGlobalOffsetFn offsetfn;
void* globalOffsetData;
CWindow* pWindowOwner = nullptr;
Vector2D lastSize;
//
bool operator==(const SSurfaceTreeNode& rhs) const {
return pSurface == rhs.pSurface;
}
};
struct SSubsurface {
wlr_subsurface* pSubsurface = nullptr;
SSurfaceTreeNode* pParent = nullptr;
SSurfaceTreeNode* pChild = nullptr;
DYNLISTENER(map);
DYNLISTENER(unmap);
DYNLISTENER(destroy);
CWindow* pWindowOwner = nullptr;
//
bool operator==(const SSubsurface& rhs) const {
return pSubsurface == rhs.pSubsurface;
}
};
namespace SubsurfaceTree {
SSurfaceTreeNode* createTreeRoot(wlr_surface*, applyGlobalOffsetFn, void*, CWindow* pWindow = nullptr);
void destroySurfaceTree(SSurfaceTreeNode*);
inline std::list<SSurfaceTreeNode> surfaceTreeNodes;
};

View file

@ -12,6 +12,11 @@ Vector2D::Vector2D() {
y = 0; y = 0;
} }
Vector2D::Vector2D(const Hyprlang::VEC2& ref) {
x = ref.x;
y = ref.y;
}
Vector2D::~Vector2D() {} Vector2D::~Vector2D() {}
double Vector2D::normalize() { double Vector2D::normalize() {
@ -42,14 +47,10 @@ double Vector2D::distance(const Vector2D& other) const {
return std::sqrt(dx * dx + dy * dy); return std::sqrt(dx * dx + dy * dy);
} }
bool Vector2D::inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const {
const auto a = ((p2.y - p3.y) * (x - p3.x) + (p3.x - p2.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
const auto b = ((p3.y - p1.y) * (x - p3.x) + (p1.x - p3.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
const auto c = 1 - a - b;
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
}
double Vector2D::size() const { double Vector2D::size() const {
return std::sqrt(x * x + y * y); return std::sqrt(x * x + y * y);
} }
Vector2D Vector2D::getComponentMax(const Vector2D& other) const {
return Vector2D(std::max(this->x, other.x), std::max(this->y, other.y));
}

View file

@ -3,12 +3,14 @@
#include <cmath> #include <cmath>
#include <format> #include <format>
#include "../macros.hpp" #include "../macros.hpp"
#include <hyprlang.hpp>
class Vector2D { class Vector2D {
public: public:
Vector2D(double, double); Vector2D(double, double);
Vector2D(); Vector2D();
~Vector2D(); ~Vector2D();
Vector2D(const Hyprlang::VEC2&);
double x = 0; double x = 0;
double y = 0; double y = 0;
@ -88,12 +90,12 @@ class Vector2D {
double distance(const Vector2D& other) const; double distance(const Vector2D& other) const;
double size() const; double size() const;
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const; Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D{-1, -1}) const;
Vector2D floor() const; Vector2D floor() const;
Vector2D round() const; Vector2D round() const;
bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const; Vector2D getComponentMax(const Vector2D& other) const;
}; };
/** /**

View file

@ -3,9 +3,17 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
SLayerSurface::SLayerSurface() { SLayerSurface::SLayerSurface() {
alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE); alpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeLayers"), nullptr, AVARDAMAGE_ENTIRE);
alpha.m_pLayer = this; realPosition.create(g_pConfigManager->getAnimationPropertyConfig("layers"), nullptr, AVARDAMAGE_ENTIRE);
realSize.create(g_pConfigManager->getAnimationPropertyConfig("layers"), nullptr, AVARDAMAGE_ENTIRE);
alpha.m_pLayer = this;
realPosition.m_pLayer = this;
realSize.m_pLayer = this;
alpha.registerVar(); alpha.registerVar();
realPosition.registerVar();
realSize.registerVar();
alpha.setValueAndWarp(0.f);
} }
SLayerSurface::~SLayerSurface() { SLayerSurface::~SLayerSurface() {
@ -22,6 +30,7 @@ void SLayerSurface::applyRules() {
ignoreAlpha = false; ignoreAlpha = false;
ignoreAlphaValue = 0.f; ignoreAlphaValue = 0.f;
xray = -1; xray = -1;
animationStyle.reset();
for (auto& rule : g_pConfigManager->getMatchingRules(this)) { for (auto& rule : g_pConfigManager->getMatchingRules(this)) {
if (rule.rule == "noanim") if (rule.rule == "noanim")
@ -44,10 +53,120 @@ void SLayerSurface::applyRules() {
try { try {
xray = configStringToInt(vars[1]); xray = configStringToInt(vars[1]);
} catch (...) {} } catch (...) {}
} else if (rule.rule.starts_with("animation")) {
CVarList vars{rule.rule, 2, 's'};
animationStyle = vars[1];
} }
} }
} }
void SLayerSurface::startAnimation(bool in, bool instant) {
const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle);
if (ANIMSTYLE == "slide") {
// get closest edge
const auto MIDDLE = geometry.middle();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE);
const std::array<Vector2D, 4> edgePoints = {
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y},
PMONITOR->vecPosition + Vector2D{0, PMONITOR->vecSize.y},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2},
};
float closest = std::numeric_limits<float>::max();
size_t leader = 0;
for (size_t i = 0; i < 4; ++i) {
float dist = MIDDLE.distance(edgePoints[i]);
if (dist < closest) {
leader = i;
closest = dist;
}
}
realSize.setValueAndWarp(geometry.size());
alpha.setValueAndWarp(1.f);
Vector2D prePos;
switch (leader) {
case 0:
// TOP
prePos = {geometry.x, PMONITOR->vecPosition.y - geometry.h};
break;
case 1:
// BOTTOM
prePos = {geometry.x, PMONITOR->vecPosition.y + PMONITOR->vecPosition.y};
break;
case 2:
// LEFT
prePos = {PMONITOR->vecPosition.x - geometry.w, geometry.y};
break;
case 3:
// RIGHT
prePos = {PMONITOR->vecPosition.x + PMONITOR->vecSize.x, geometry.y};
break;
default: UNREACHABLE();
}
if (in) {
realPosition.setValueAndWarp(prePos);
realPosition = geometry.pos();
} else {
realPosition.setValueAndWarp(geometry.pos());
realPosition = prePos;
}
} else if (ANIMSTYLE.starts_with("popin")) {
float minPerc = 0.f;
if (ANIMSTYLE.find("%") != std::string::npos) {
try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) {
; // oops
}
}
minPerc *= 0.01;
const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5});
const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f;
alpha.setValueAndWarp(in ? 0.f : 1.f);
alpha = in ? 1.f : 0.f;
if (in) {
realSize.setValueAndWarp(GOALSIZE);
realPosition.setValueAndWarp(GOALPOS);
realSize = geometry.size();
realPosition = geometry.pos();
} else {
realSize.setValueAndWarp(geometry.size());
realPosition.setValueAndWarp(geometry.pos());
realSize = GOALSIZE;
realPosition = GOALPOS;
}
} else {
// fade
realPosition.setValueAndWarp(geometry.pos());
realSize.setValueAndWarp(geometry.size());
alpha = in ? 1.f : 0.f;
}
if (!in)
fadingOut = true;
}
bool SLayerSurface::isFadedOut() {
if (!fadingOut)
return false;
return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated();
}
CRegion SConstraint::getLogicCoordsRegion() { CRegion SConstraint::getLogicCoordsRegion() {
CRegion result; CRegion result;
@ -62,11 +181,11 @@ CRegion SConstraint::getLogicCoordsRegion() {
result.add(&constraint->region); // surface-local coords result.add(&constraint->region); // surface-local coords
if (!PWINDOWOWNER->m_bIsX11) { if (!PWINDOWOWNER->m_bIsX11) {
result.translate(PWINDOWOWNER->m_vRealPosition.goalv()); result.translate(PWINDOWOWNER->m_vRealPosition.goal());
return result; return result;
} }
const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() : const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goal() :
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y}); g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y});
const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : g_pCompositor->getMonitorFromVector(COORDS); const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : g_pCompositor->getMonitorFromVector(COORDS);
@ -91,9 +210,9 @@ Vector2D SConstraint::getLogicConstraintPos() {
return {}; return {};
if (!PWINDOWOWNER->m_bIsX11) if (!PWINDOWOWNER->m_bIsX11)
return PWINDOWOWNER->m_vRealPosition.goalv(); return PWINDOWOWNER->m_vRealPosition.goal();
const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() : const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goal() :
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y}); g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y});
return COORDS; return COORDS;
@ -109,7 +228,7 @@ Vector2D SConstraint::getLogicConstraintSize() {
return {}; return {};
if (!PWINDOWOWNER->m_bIsX11) if (!PWINDOWOWNER->m_bIsX11)
return PWINDOWOWNER->m_vRealSize.goalv(); return PWINDOWOWNER->m_vRealSize.goal();
const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ?
g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) :
@ -118,8 +237,72 @@ Vector2D SConstraint::getLogicConstraintSize() {
if (!PMONITOR) if (!PMONITOR)
return {}; return {};
const auto SIZE = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealSize.goalv() : const auto SIZE = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealSize.goal() :
Vector2D{PWINDOWOWNER->m_uSurface.xwayland->width, PWINDOWOWNER->m_uSurface.xwayland->height} * PMONITOR->xwaylandScale; Vector2D{PWINDOWOWNER->m_uSurface.xwayland->width, PWINDOWOWNER->m_uSurface.xwayland->height} * PMONITOR->xwaylandScale;
return SIZE; return SIZE;
} }
void SKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkb_state_unref(xkbTranslationState);
if (keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
xkbTranslationState = xkb_state_new(keymap);
return;
}
const auto WLRKB = wlr_keyboard_from_input_device(keyboard);
const auto KEYMAP = WLRKB->keymap;
const auto STATE = WLRKB->xkb_state;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE)) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an active index {}", (uintptr_t)this, i);
CVarList keyboardLayouts(currentRules.layout, 0, ',');
CVarList keyboardModels(currentRules.model, 0, ',');
CVarList keyboardVariants(currentRules.variant, 0, ',');
xkb_rule_names rules = {.rules = "", .model = "", .layout = "", .variant = "", .options = ""};
std::string layout, model, variant;
layout = keyboardLayouts[i % keyboardLayouts.size()];
model = keyboardModels[i % keyboardLayouts.size()];
variant = keyboardVariants[i % keyboardLayouts.size()];
rules.layout = layout.c_str();
rules.model = model.c_str();
rules.variant = variant.c_str();
const auto KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkbTranslationState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT);
return;
}
}
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an unknown index", (uintptr_t)this);
xkb_rule_names rules = {
.rules = currentRules.rules.c_str(),
.model = currentRules.model.c_str(),
.layout = currentRules.layout.c_str(),
.variant = currentRules.variant.c_str(),
.options = currentRules.options.c_str(),
};
const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkbTranslationState = xkb_state_new(NEWKEYMAP);
xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT);
}

View file

@ -4,9 +4,10 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "wlr-layer-shell-unstable-v1-protocol.h" #include "wlr-layer-shell-unstable-v1-protocol.h"
#include "../Window.hpp" #include "../Window.hpp"
#include "SubsurfaceTree.hpp" #include "../desktop/Subsurface.hpp"
#include "../desktop/Popup.hpp"
#include "AnimatedVariable.hpp" #include "AnimatedVariable.hpp"
#include "WLSurface.hpp" #include "../desktop/WLSurface.hpp"
#include "Region.hpp" #include "Region.hpp"
struct SLayerRule { struct SLayerRule {
@ -18,42 +19,50 @@ struct SLayerSurface {
SLayerSurface(); SLayerSurface();
~SLayerSurface(); ~SLayerSurface();
void applyRules(); void applyRules();
void startAnimation(bool in, bool instant = false);
bool isFadedOut();
wlr_layer_surface_v1* layerSurface; CAnimatedVariable<Vector2D> realPosition;
wl_list link; CAnimatedVariable<Vector2D> realSize;
bool keyboardExclusive = false; wlr_layer_surface_v1* layerSurface;
wl_list link;
CWLSurface surface; bool keyboardExclusive = false;
std::list<CWLSurface> popupSurfaces;
CWLSurface surface;
// desktop components
std::unique_ptr<CPopup> popupHead;
DYNLISTENER(destroyLayerSurface); DYNLISTENER(destroyLayerSurface);
DYNLISTENER(mapLayerSurface); DYNLISTENER(mapLayerSurface);
DYNLISTENER(unmapLayerSurface); DYNLISTENER(unmapLayerSurface);
DYNLISTENER(commitLayerSurface); DYNLISTENER(commitLayerSurface);
DYNLISTENER(newPopup);
CBox 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;
bool mapped = false; bool mapped = false;
int monitorID = -1; int monitorID = -1;
std::string szNamespace = ""; std::string szNamespace = "";
CAnimatedVariable alpha; CAnimatedVariable<float> alpha;
bool fadingOut = false; bool fadingOut = false;
bool readyToDelete = false; bool readyToDelete = false;
bool noProcess = false; bool noProcess = false;
bool noAnimations = false; bool noAnimations = false;
bool forceBlur = false; bool forceBlur = false;
int xray = -1; int xray = -1;
bool ignoreAlpha = false; bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f; float ignoreAlphaValue = 0.f;
std::optional<std::string> animationStyle;
// For the list lookup // For the list lookup
bool operator==(const SLayerSurface& rhs) const { bool operator==(const SLayerSurface& rhs) const {
@ -127,15 +136,19 @@ struct SKeyboard {
bool active = false; bool active = false;
bool enabled = true; bool enabled = true;
xkb_layout_index_t activeLayout = 0; xkb_layout_index_t activeLayout = 0;
xkb_state* xkbTranslationState = nullptr;
std::string name = ""; std::string name = "";
std::string xkbFilePath = ""; std::string xkbFilePath = "";
SStringRuleNames currentRules; SStringRuleNames currentRules;
int repeatRate = 0; int repeatRate = 0;
int repeatDelay = 0; int repeatDelay = 0;
int numlockOn = -1; int numlockOn = -1;
bool resolveBindsBySym = false;
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
// For the list lookup // For the list lookup
bool operator==(const SKeyboard& rhs) const { bool operator==(const SKeyboard& rhs) const {
@ -190,34 +203,6 @@ struct SConstraint {
class CMonitor; class CMonitor;
struct SXDGPopup {
CWindow* parentWindow = nullptr;
SLayerSurface* parentLS = nullptr;
SXDGPopup* parentPopup = nullptr;
wlr_xdg_popup* popup = nullptr;
CMonitor* monitor = nullptr;
DYNLISTENER(newPopupFromPopupXDG);
DYNLISTENER(destroyPopupXDG);
DYNLISTENER(mapPopupXDG);
DYNLISTENER(unmapPopupXDG);
DYNLISTENER(commitPopupXDG);
DYNLISTENER(repositionPopupXDG);
double lx;
double ly;
Vector2D lastPos = {};
bool repositionRequested = false;
SSurfaceTreeNode* pSurfaceTree = nullptr;
// For the list lookup
bool operator==(const SXDGPopup& rhs) const {
return popup == rhs.popup;
}
};
struct SSeat { struct SSeat {
wlr_seat* seat = nullptr; wlr_seat* seat = nullptr;
wl_client* exclusiveClient = nullptr; wl_client* exclusiveClient = nullptr;
@ -259,6 +244,8 @@ struct STablet {
std::string name = ""; std::string name = "";
std::string boundOutput = "";
// //
bool operator==(const STablet& b) const { bool operator==(const STablet& b) const {
return wlrDevice == b.wlrDevice; return wlrDevice == b.wlrDevice;
@ -406,7 +393,17 @@ struct STearingController {
DYNLISTENER(set); DYNLISTENER(set);
DYNLISTENER(destroy); DYNLISTENER(destroy);
bool operator==(const STearingController& other) { bool operator==(const STearingController& other) const {
return pWlrHint == other.pWlrHint; return pWlrHint == other.pWlrHint;
} }
}; };
struct SShortcutInhibitor {
wlr_keyboard_shortcuts_inhibitor_v1* pWlrInhibitor = nullptr;
DYNLISTENER(destroy);
bool operator==(const SShortcutInhibitor& other) const {
return pWlrInhibitor == other.pWlrInhibitor;
}
};

View file

@ -7,13 +7,15 @@
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(); if (g_pWatchdog)
g_pWatchdog->startWatching();
try { 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); } } catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); }
g_pWatchdog->endWatching(); if (g_pWatchdog)
g_pWatchdog->endWatching();
} }
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) { CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {

View file

@ -1,87 +0,0 @@
#include "WLSurface.hpp"
#include "../Compositor.hpp"
CWLSurface::CWLSurface(wlr_surface* pSurface) {
m_pWLRSurface = pSurface;
init();
}
void CWLSurface::assign(wlr_surface* pSurface) {
m_pWLRSurface = pSurface;
init();
}
void CWLSurface::unassign() {
destroy();
}
CWLSurface::~CWLSurface() {
destroy();
}
bool CWLSurface::exists() const {
return m_pWLRSurface;
}
wlr_surface* CWLSurface::wlr() const {
return m_pWLRSurface;
}
bool CWLSurface::small() const {
if (!m_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() {
if (!m_pWLRSurface)
return;
hyprListener_destroy.removeCallback();
m_pWLRSurface->data = nullptr;
m_pOwner = nullptr;
if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
g_pCompositor->m_pLastFocus = nullptr;
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_pWLRSurface = nullptr;
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
}
void CWLSurface::init() {
if (!m_pWLRSurface)
return;
RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!");
m_pWLRSurface->data = this;
hyprListener_destroy.initCallback(
&m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
}

View file

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

View file

@ -139,7 +139,7 @@ void CHyprError::draw() {
if (m_bQueuedDestroy) { if (m_bQueuedDestroy) {
if (!m_fFadeOpacity.isBeingAnimated()) { if (!m_fFadeOpacity.isBeingAnimated()) {
if (m_fFadeOpacity.fl() == 0.f) { if (m_fFadeOpacity.value() == 0.f) {
m_bQueuedDestroy = false; m_bQueuedDestroy = false;
m_tTexture.destroyTexture(); m_tTexture.destroyTexture();
m_bIsCreated = false; m_bIsCreated = false;
@ -164,7 +164,7 @@ void CHyprError::draw() {
m_bMonitorChanged = false; m_bMonitorChanged = false;
g_pHyprOpenGL->renderTexture(m_tTexture, &monbox, m_fFadeOpacity.fl(), 0); g_pHyprOpenGL->renderTexture(m_tTexture, &monbox, m_fFadeOpacity.value(), 0);
} }
void CHyprError::destroy() { void CHyprError::destroy() {

View file

@ -16,16 +16,16 @@ class CHyprError {
void destroy(); void destroy();
private: private:
void createQueued(); void createQueued();
std::string m_szQueued = ""; std::string m_szQueued = "";
CColor m_cQueued; CColor m_cQueued;
bool m_bQueuedDestroy = false; bool m_bQueuedDestroy = false;
bool m_bIsCreated = false; bool m_bIsCreated = false;
CTexture m_tTexture; CTexture m_tTexture;
CAnimatedVariable m_fFadeOpacity; CAnimatedVariable<float> m_fFadeOpacity;
CBox m_bDamageBox = {0, 0, 0, 0}; CBox m_bDamageBox = {0, 0, 0, 0};
bool m_bMonitorChanged = false; bool m_bMonitorChanged = false;
}; };
inline std::unique_ptr<CHyprError> g_pHyprError; // This is a full-screen error. Treat it with respect, and there can only be one at a time. inline std::unique_ptr<CHyprError> g_pHyprError; // This is a full-screen error. Treat it with respect, and there can only be one at a time.

View file

@ -4,13 +4,12 @@
void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) { void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) {
if (children[0]) { if (children[0]) {
static auto* const PSMARTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:smart_split")->intValue; static auto* const PSMARTSPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:smart_split");
static auto* const PPRESERVESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:preserve_split")->intValue; static auto* const PPRESERVESPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:preserve_split");
static auto* const PFLMULT = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue; static auto* const PFLMULT = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier");
if (*PPRESERVESPLIT == 0 && *PSMARTSPLIT == 0) { if (**PPRESERVESPLIT == 0 && **PSMARTSPLIT == 0)
splitTop = box.h * *PFLMULT > box.w; splitTop = box.h * **PFLMULT > box.w;
}
if (verticalOverride == true) if (verticalOverride == true)
splitTop = true; splitTop = true;
@ -22,13 +21,13 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
if (SPLITSIDE) { if (SPLITSIDE) {
// split left/right // split left/right
const float FIRSTSIZE = box.w / 2.0 * splitRatio; const float FIRSTSIZE = box.w / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h}; children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h}.noNegativeSize();
children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h}; children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h}.noNegativeSize();
} else { } else {
// split top/bottom // split top/bottom
const float FIRSTSIZE = box.h / 2.0 * splitRatio; const float FIRSTSIZE = box.h / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE}; children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE}.noNegativeSize();
children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE}; children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE}.noNegativeSize();
} }
children[0]->recalcSizePosRecursive(force); children[0]->recalcSizePosRecursive(force);
@ -64,6 +63,21 @@ SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) {
return nullptr; return nullptr;
} }
SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const int& id, const Vector2D& point) {
SDwindleNodeData* res = nullptr;
double distClosest = -1;
for (auto& n : m_lDwindleNodesData) {
if (n.workspaceID == id && n.pWindow && g_pCompositor->windowValidMapped(n.pWindow)) {
auto distAnother = vecToRectDistanceSquared(point, n.box.pos(), n.box.pos() + n.box.size());
if (!res || distAnother < distClosest) {
res = &n;
distClosest = distAnother;
}
}
}
return res;
}
SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(CWindow* pWindow) { SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(CWindow* pWindow) {
for (auto& n : m_lDwindleNodesData) { for (auto& n : m_lDwindleNodesData) {
if (n.pWindow == pWindow && !n.isNode) if (n.pWindow == pWindow && !n.isNode)
@ -113,27 +127,29 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
const auto PWINDOW = pNode->pWindow; const auto PWINDOW = pNode->pWindow;
// get specific gaps and rules for this workspace, // get specific gaps and rules for this workspace,
// if user specified them in config // if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(pNode->workspaceID));
if (!g_pCompositor->windowExists(PWINDOW)) {
Debug::log(ERR, "Node {} holding invalid {}!!", pNode, PWINDOW);
onWindowRemovedTiling(PWINDOW);
return;
}
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return; return;
PWINDOW->updateSpecialRenderData(); PWINDOW->updateSpecialRenderData();
static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue; static auto* const PNOGAPSWHENONLY = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:no_gaps_when_only");
static auto* const PGAPSOUT = &g_pConfigManager->getConfigValuePtr("general:gaps_out")->intValue; static auto* const PGAPSINDATA = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:gaps_in");
static auto* const PNOGAPSWHENONLY = &g_pConfigManager->getConfigValuePtr("dwindle:no_gaps_when_only")->intValue; static auto* const PGAPSOUTDATA = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:gaps_out");
auto* const PGAPSIN = (CCssGapData*)(*PGAPSINDATA)->getData();
auto* const PGAPSOUT = (CCssGapData*)(*PGAPSOUTDATA)->getData();
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN); auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT); auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
if (!g_pCompositor->windowExists(PWINDOW) || !PWINDOW->m_bIsMapped) { CBox nodeBox = pNode->box;
Debug::log(ERR, "Node {} holding invalid {}!!", pNode, PWINDOW);
onWindowRemovedTiling(PWINDOW);
return;
}
CBox nodeBox = pNode->box;
nodeBox.round(); nodeBox.round();
PWINDOW->m_vSize = nodeBox.size(); PWINDOW->m_vSize = nodeBox.size();
@ -141,10 +157,10 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID); const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID);
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && if (**PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) &&
(NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { (NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2); PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(**PNOGAPSWHENONLY == 2);
PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true); PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true);
PWINDOW->m_sSpecialRenderData.rounding = false; PWINDOW->m_sSpecialRenderData.rounding = false;
PWINDOW->m_sSpecialRenderData.shadow = false; PWINDOW->m_sSpecialRenderData.shadow = false;
@ -156,7 +172,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft; PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft;
PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight); PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
return; return;
} }
@ -164,9 +180,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
auto calcPos = PWINDOW->m_vPosition; auto calcPos = PWINDOW->m_vPosition;
auto calcSize = PWINDOW->m_vSize; auto calcSize = PWINDOW->m_vSize;
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut : gapsIn, DISPLAYTOP ? gapsOut : gapsIn); const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut.left : gapsIn.left, DISPLAYTOP ? gapsOut.top : gapsIn.top);
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? gapsOut : gapsIn, DISPLAYBOTTOM ? gapsOut : gapsIn); const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? gapsOut.right : gapsIn.right, DISPLAYBOTTOM ? gapsOut.bottom : gapsIn.bottom);
calcPos = calcPos + OFFSETTOPLEFT; calcPos = calcPos + OFFSETTOPLEFT;
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT; calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
@ -201,9 +217,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) { if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
// if special, we adjust the coords a bit // if special, we adjust the coords a bit
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue; static auto* const PSCALEFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor");
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR}; CBox wb = {calcPos + (calcSize - calcSize * **PSCALEFACTOR) / 2.f, calcSize * **PSCALEFACTOR};
wb.round(); // avoid rounding mess wb.round(); // avoid rounding mess
PWINDOW->m_vRealPosition = wb.pos(); PWINDOW->m_vRealPosition = wb.pos();
@ -211,10 +227,13 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
} else { } else {
PWINDOW->m_vRealSize = calcSize; CBox wb = {calcPos, calcSize};
PWINDOW->m_vRealPosition = calcPos; wb.round(); // avoid rounding mess
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize); PWINDOW->m_vRealSize = wb.size();
PWINDOW->m_vRealPosition = wb.pos();
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
} }
if (force) { if (force) {
@ -238,8 +257,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
static auto* const PUSEACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:use_active_for_splits")->intValue; static auto* const PUSEACTIVE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:use_active_for_splits");
static auto* const PDEFAULTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:default_split_ratio")->floatValue; static auto* const PDEFAULTSPLIT = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("dwindle:default_split_ratio");
if (direction != DIRECTION_DEFAULT && overrideDirection == DIRECTION_DEFAULT) if (direction != DIRECTION_DEFAULT && overrideDirection == DIRECTION_DEFAULT)
overrideDirection = direction; overrideDirection = direction;
@ -254,26 +273,25 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal()); const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS); const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);
const auto TARGETCOORDS = PMONITOR->ID == MONFROMCURSOR->ID && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR) ? pWindow->middle() : MOUSECOORDS;
if (PMONITOR->ID == MONFROMCURSOR->ID && if (PMONITOR->ID == MONFROMCURSOR->ID &&
(PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) { (PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !**PUSEACTIVE) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS)); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS));
// happens on reserved area if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0) OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS);
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
} else if (*PUSEACTIVE) { } else if (**PUSEACTIVE) {
if (g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow && if (g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow &&
g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) { g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) {
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow); OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
} else { } else {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS)); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS));
} }
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0) if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace); OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS);
} else } else
OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID); OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID);
@ -325,8 +343,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
&& pWindow->canBeGroupedInto(OPENINGON->pWindow) && !m_vOverrideFocalPoint) { // we are not moving window && pWindow->canBeGroupedInto(OPENINGON->pWindow) && !m_vOverrideFocalPoint) { // we are not moving window
m_lDwindleNodesData.remove(*PNODE); m_lDwindleNodesData.remove(*PNODE);
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue; static const auto* USECURRPOS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("group:insert_after_current");
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); (**USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow); OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules(); pWindow->applyGroupRules();
@ -349,17 +367,17 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
NEWPARENT->workspaceID = OPENINGON->workspaceID; NEWPARENT->workspaceID = OPENINGON->workspaceID;
NEWPARENT->pParent = OPENINGON->pParent; NEWPARENT->pParent = OPENINGON->pParent;
NEWPARENT->isNode = true; // it is a node NEWPARENT->isNode = true; // it is a node
NEWPARENT->splitRatio = std::clamp(*PDEFAULTSPLIT, 0.1f, 1.9f); NEWPARENT->splitRatio = std::clamp(**PDEFAULTSPLIT, 0.1f, 1.9f);
const auto PWIDTHMULTIPLIER = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue; const auto PWIDTHMULTIPLIER = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier");
// if cursor over first child, make it first, etc // if cursor over first child, make it first, etc
const auto SIDEBYSIDE = NEWPARENT->box.w > NEWPARENT->box.h * *PWIDTHMULTIPLIER; const auto SIDEBYSIDE = NEWPARENT->box.w > NEWPARENT->box.h * **PWIDTHMULTIPLIER;
NEWPARENT->splitTop = !SIDEBYSIDE; NEWPARENT->splitTop = !SIDEBYSIDE;
static auto* const PFORCESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:force_split")->intValue; static auto* const PFORCESPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:force_split");
static auto* const PERMANENTDIRECTIONOVERRIDE = &g_pConfigManager->getConfigValuePtr("dwindle:permanent_direction_override")->intValue; static auto* const PERMANENTDIRECTIONOVERRIDE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:permanent_direction_override");
static auto* const PSMARTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:smart_split")->intValue; static auto* const PSMARTSPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:smart_split");
bool horizontalOverride = false; bool horizontalOverride = false;
bool verticalOverride = false; bool verticalOverride = false;
@ -383,37 +401,44 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
} }
// whether or not the override persists after opening one window // whether or not the override persists after opening one window
if (*PERMANENTDIRECTIONOVERRIDE == 0) if (**PERMANENTDIRECTIONOVERRIDE == 0)
overrideDirection = DIRECTION_DEFAULT; overrideDirection = DIRECTION_DEFAULT;
} else if (*PSMARTSPLIT == 1) { } else if (**PSMARTSPLIT == 1) {
const auto tl = NEWPARENT->box.pos(); const auto PARENT_CENTER = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
const auto tr = NEWPARENT->box.pos() + Vector2D(NEWPARENT->box.w, 0); const auto PARENT_PROPORTIONS = NEWPARENT->box.h / NEWPARENT->box.w;
const auto bl = NEWPARENT->box.pos() + Vector2D(0, NEWPARENT->box.h); const auto DELTA = MOUSECOORDS - PARENT_CENTER;
const auto br = NEWPARENT->box.pos() + NEWPARENT->box.size(); const auto DELTA_SLOPE = DELTA.y / DELTA.x;
const auto cc = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
if (TARGETCOORDS.inTriangle(tl, tr, cc)) { if (abs(DELTA_SLOPE) < PARENT_PROPORTIONS) {
NEWPARENT->splitTop = true; if (DELTA.x > 0) {
NEWPARENT->children[0] = PNODE; // right
NEWPARENT->children[1] = OPENINGON; NEWPARENT->splitTop = false;
} else if (TARGETCOORDS.inTriangle(tr, cc, br)) { NEWPARENT->children[0] = OPENINGON;
NEWPARENT->splitTop = false; NEWPARENT->children[1] = PNODE;
NEWPARENT->children[0] = OPENINGON; } else {
NEWPARENT->children[1] = PNODE; // left
} else if (TARGETCOORDS.inTriangle(br, bl, cc)) { NEWPARENT->splitTop = false;
NEWPARENT->splitTop = true; NEWPARENT->children[0] = PNODE;
NEWPARENT->children[0] = OPENINGON; NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[1] = PNODE; }
} else { } else {
NEWPARENT->splitTop = false; if (DELTA.y > 0) {
NEWPARENT->children[0] = PNODE; // bottom
NEWPARENT->children[1] = OPENINGON; NEWPARENT->splitTop = true;
NEWPARENT->children[0] = OPENINGON;
NEWPARENT->children[1] = PNODE;
} else {
// top
NEWPARENT->splitTop = true;
NEWPARENT->children[0] = PNODE;
NEWPARENT->children[1] = OPENINGON;
}
} }
} else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) { } else if (**PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
if ((SIDEBYSIDE && if ((SIDEBYSIDE &&
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) || VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / **PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
(!SIDEBYSIDE && (!SIDEBYSIDE &&
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) { VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / **PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
// we are hovering over the first node, make PNODE first. // we are hovering over the first node, make PNODE first.
NEWPARENT->children[1] = OPENINGON; NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[0] = PNODE; NEWPARENT->children[0] = PNODE;
@ -423,7 +448,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
NEWPARENT->children[1] = PNODE; NEWPARENT->children[1] = PNODE;
} }
} else { } else {
if (*PFORCESPLIT == 1) { if (**PFORCESPLIT == 1) {
NEWPARENT->children[1] = OPENINGON; NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[0] = PNODE; NEWPARENT->children[0] = PNODE;
} else { } else {
@ -442,7 +467,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
} }
// Update the children // Update the children
if (!verticalOverride && (NEWPARENT->box.w * *PWIDTHMULTIPLIER > NEWPARENT->box.h || horizontalOverride)) { if (!verticalOverride && (NEWPARENT->box.w * **PWIDTHMULTIPLIER > NEWPARENT->box.h || horizontalOverride)) {
// split left/right -> forced // split left/right -> forced
OPENINGON->box = {NEWPARENT->box.pos(), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)}; OPENINGON->box = {NEWPARENT->box.pos(), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
PNODE->box = {Vector2D(NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)}; PNODE->box = {Vector2D(NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
@ -581,13 +606,13 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
const auto PNODE = getNodeFromWindow(PWINDOW); const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) { if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0)); PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goal() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goal() + pixResize).y, 20.0));
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
return; return;
} }
const auto PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue; const auto PANIMATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes");
const auto PSMARTRESIZING = &g_pConfigManager->getConfigValuePtr("dwindle:smart_resizing")->intValue; const auto PSMARTRESIZING = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:smart_resizing");
// get some data about our window // get some data about our window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
@ -600,7 +625,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (!m_PseudoDragFlags.started) { if (!m_PseudoDragFlags.started) {
m_PseudoDragFlags.started = true; m_PseudoDragFlags.started = true;
const auto pseudoSize = PWINDOW->m_vRealSize.goalv(); const auto pseudoSize = PWINDOW->m_vRealSize.goal();
const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->box.pos() + ((PNODE->box.size() / 2) - (pseudoSize / 2))); const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->box.pos() + ((PNODE->box.size() / 2) - (pseudoSize / 2)));
if (mouseOffset.x > 0 && mouseOffset.x < pseudoSize.x && mouseOffset.y > 0 && mouseOffset.y < pseudoSize.y) { if (mouseOffset.x > 0 && mouseOffset.x < pseudoSize.x && mouseOffset.y > 0 && mouseOffset.y < pseudoSize.y) {
@ -624,11 +649,13 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
else else
PWINDOW->m_vPseudoSize.y -= pixResize.y * 2; PWINDOW->m_vPseudoSize.y -= pixResize.y * 2;
PWINDOW->m_vPseudoSize.x = std::clamp(PWINDOW->m_vPseudoSize.x, 30.0, PNODE->box.w); CBox wbox = PNODE->box;
PWINDOW->m_vPseudoSize.y = std::clamp(PWINDOW->m_vPseudoSize.y, 30.0, PNODE->box.h); wbox.round();
PWINDOW->m_vPseudoSize = {std::clamp(PWINDOW->m_vPseudoSize.x, 30.0, wbox.w), std::clamp(PWINDOW->m_vPseudoSize.y, 30.0, wbox.h)};
PWINDOW->m_vLastFloatingSize = PWINDOW->m_vPseudoSize; PWINDOW->m_vLastFloatingSize = PWINDOW->m_vPseudoSize;
PNODE->recalcSizePosRecursive(*PANIMATE == 0); PNODE->recalcSizePosRecursive(**PANIMATE == 0);
return; return;
} }
@ -642,7 +669,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (DISPLAYBOTTOM && DISPLAYTOP) if (DISPLAYBOTTOM && DISPLAYTOP)
allowedMovement.y = 0; allowedMovement.y = 0;
if (*PSMARTRESIZING == 1) { if (**PSMARTRESIZING == 1) {
// Identify inner and outer nodes for both directions // Identify inner and outer nodes for both directions
SDwindleNodeData* PVOUTER = nullptr; SDwindleNodeData* PVOUTER = nullptr;
SDwindleNodeData* PVINNER = nullptr; SDwindleNodeData* PVINNER = nullptr;
@ -676,14 +703,14 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (PHINNER) { if (PHINNER) {
const auto ORIGINAL = PHINNER->box.w; const auto ORIGINAL = PHINNER->box.w;
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PHOUTER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
if (PHINNER->pParent->children[0] == PHINNER) if (PHINNER->pParent->children[0] == PHINNER)
PHINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9); PHINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9);
else else
PHINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9); PHINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9);
PHINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PHINNER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
} else } else
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PHOUTER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
} }
if (PVOUTER) { if (PVOUTER) {
@ -691,14 +718,14 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (PVINNER) { if (PVINNER) {
const auto ORIGINAL = PVINNER->box.h; const auto ORIGINAL = PVINNER->box.h;
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PVOUTER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
if (PVINNER->pParent->children[0] == PVINNER) if (PVINNER->pParent->children[0] == PVINNER)
PVINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9); PVINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9);
else else
PVINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9); PVINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9);
PVINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PVINNER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
} else } else
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PVOUTER->pParent->recalcSizePosRecursive(**PANIMATE == 0);
} }
} else { } else {
// get the correct containers to apply splitratio to // get the correct containers to apply splitratio to
@ -717,11 +744,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (PARENTSIDEBYSIDE) { if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->box.w; allowedMovement.x *= 2.f / PPARENT->box.w;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9); PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0); PPARENT->recalcSizePosRecursive(**PANIMATE == 0);
} else { } else {
allowedMovement.y *= 2.f / PPARENT->box.h; allowedMovement.y *= 2.f / PPARENT->box.h;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9); PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0); PPARENT->recalcSizePosRecursive(**PANIMATE == 0);
} }
return; return;
@ -736,11 +763,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (PARENTSIDEBYSIDE) { if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->box.w; allowedMovement.x *= 2.f / PPARENT->box.w;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9); PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0); PPARENT->recalcSizePosRecursive(**PANIMATE == 0);
} else { } else {
allowedMovement.y *= 2.f / PPARENT->box.h; allowedMovement.y *= 2.f / PPARENT->box.h;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9); PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0); PPARENT->recalcSizePosRecursive(**PANIMATE == 0);
} }
return; return;
@ -755,8 +782,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, 0.1, 1.9); SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, 0.1, 1.9);
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, 0.1, 1.9); TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, 0.1, 1.9);
SIDECONTAINER->recalcSizePosRecursive(*PANIMATE == 0); SIDECONTAINER->recalcSizePosRecursive(**PANIMATE == 0);
TOPCONTAINER->recalcSizePosRecursive(*PANIMATE == 0); TOPCONTAINER->recalcSizePosRecursive(**PANIMATE == 0);
} }
} }
@ -776,10 +803,21 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
return; return;
} }
// save position and size if floating
if (pWindow->m_bIsFloating && on) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vSize = pWindow->m_vRealSize.goal();
}
// otherwise, accept it. // otherwise, accept it.
pWindow->m_bIsFullscreen = on; pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
pWindow->updateDynamicRules();
pWindow->updateWindowDecos();
g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)}); g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)});
EMIT_HOOK_EVENT("fullscreen", pWindow); EMIT_HOOK_EVENT("fullscreen", pWindow);
@ -800,14 +838,6 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
PWORKSPACE->m_efFullscreenMode = fullscreenMode; PWORKSPACE->m_efFullscreenMode = fullscreenMode;
// save position and size if floating
if (pWindow->m_bIsFloating) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
}
// apply new pos and size being monitors' box // apply new pos and size being monitors' box
if (fullscreenMode == FULLSCREEN_FULL) { if (fullscreenMode == FULLSCREEN_FULL) {
pWindow->m_vRealPosition = PMONITOR->vecPosition; pWindow->m_vRealPosition = PMONITOR->vecPosition;
@ -824,13 +854,13 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
pWindow->m_vPosition = fakeNode.box.pos(); pWindow->m_vPosition = fakeNode.box.pos();
pWindow->m_vSize = fakeNode.box.size(); pWindow->m_vSize = fakeNode.box.size();
applyNodeDataToWindow(&fakeNode); applyNodeDataToWindow(&fakeNode, true);
} }
} }
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal());
g_pCompositor->changeWindowZOrder(pWindow, true); g_pCompositor->changeWindowZOrder(pWindow, true);
@ -967,6 +997,8 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str
const auto ARGS = CVarList(message, 0, ' '); const auto ARGS = CVarList(message, 0, ' ');
if (ARGS[0] == "togglesplit") { if (ARGS[0] == "togglesplit") {
toggleSplit(header.pWindow); toggleSplit(header.pWindow);
} else if (ARGS[0] == "swapsplit") {
swapSplit(header.pWindow);
} else if (ARGS[0] == "preselect") { } else if (ARGS[0] == "preselect") {
std::string direction = ARGS[1]; std::string direction = ARGS[1];
@ -1020,6 +1052,20 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) {
PNODE->pParent->recalcSizePosRecursive(); PNODE->pParent->recalcSizePosRecursive();
} }
void CHyprDwindleLayout::swapSplit(CWindow* pWindow) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE || !PNODE->pParent)
return;
if (pWindow->m_bIsFullscreen)
return;
std::swap(PNODE->pParent->children[0], PNODE->pParent->children[1]);
PNODE->pParent->recalcSizePosRecursive();
}
void CHyprDwindleLayout::replaceWindowDataWith(CWindow* from, CWindow* to) { void CHyprDwindleLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
const auto PNODE = getNodeFromWindow(from); const auto PNODE = getNodeFromWindow(from);
@ -1047,3 +1093,53 @@ void CHyprDwindleLayout::onEnable() {
void CHyprDwindleLayout::onDisable() { void CHyprDwindleLayout::onDisable() {
m_lDwindleNodesData.clear(); m_lDwindleNodesData.clear();
} }
Vector2D CHyprDwindleLayout::predictSizeForNewWindow() {
if (!g_pCompositor->m_pLastMonitor)
return {};
// get window candidate
CWindow* candidate = g_pCompositor->m_pLastWindow;
if (!candidate)
candidate = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace);
// create a fake node
SDwindleNodeData node;
if (!candidate)
return g_pCompositor->m_pLastMonitor->vecSize;
else {
const auto PNODE = getNodeFromWindow(candidate);
if (!PNODE)
return {};
node = *PNODE;
node.pWindow = nullptr;
CBox box = PNODE->box;
static auto* const PSMARTSPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:smart_split");
static auto* const PPRESERVESPLIT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("dwindle:preserve_split");
static auto* const PFLMULT = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier");
bool splitTop = false;
if (**PPRESERVESPLIT == 0 && **PSMARTSPLIT == 0)
splitTop = box.h * **PFLMULT > box.w;
const auto SPLITSIDE = !splitTop;
if (SPLITSIDE)
node.box = {{}, {box.w / 2.0, box.h}};
else
node.box = {{}, {box.w, box.h / 2.0}};
// TODO: make this better and more accurate
return node.box.size();
}
return {};
}

View file

@ -59,6 +59,7 @@ class CHyprDwindleLayout : public IHyprLayout {
virtual void alterSplitRatio(CWindow*, float, bool); virtual void alterSplitRatio(CWindow*, float, bool);
virtual std::string getLayoutName(); virtual std::string getLayoutName();
virtual void replaceWindowDataWith(CWindow* from, CWindow* to); virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
virtual Vector2D predictSizeForNewWindow();
virtual void onEnable(); virtual void onEnable();
virtual void onDisable(); virtual void onDisable();
@ -79,9 +80,11 @@ class CHyprDwindleLayout : public IHyprLayout {
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false); void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
SDwindleNodeData* getNodeFromWindow(CWindow*); SDwindleNodeData* getNodeFromWindow(CWindow*);
SDwindleNodeData* getFirstNodeOnWorkspace(const int&); SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&);
SDwindleNodeData* getMasterNodeOnWorkspace(const int&); SDwindleNodeData* getMasterNodeOnWorkspace(const int&);
void toggleSplit(CWindow*); void toggleSplit(CWindow*);
void swapSplit(CWindow*);
eDirection overrideDirection = DIRECTION_DEFAULT; eDirection overrideDirection = DIRECTION_DEFAULT;

View file

@ -87,7 +87,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
desiredGeometry.y = xy.y; desiredGeometry.y = xy.y;
} }
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue; static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling");
if (!PMONITOR) { if (!PMONITOR) {
Debug::log(ERR, "{:m} has an invalid monitor in onWindowCreatedFloating!!!", pWindow); Debug::log(ERR, "{:m} has an invalid monitor in onWindowCreatedFloating!!!", pWindow);
@ -105,7 +105,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
} }
// reject any windows with size <= 5x5 // reject any windows with size <= 5x5
if (pWindow->m_vRealSize.goalv().x <= 5 || pWindow->m_vRealSize.goalv().y <= 5) if (pWindow->m_vRealSize.goal().x <= 5 || pWindow->m_vRealSize.goal().y <= 5)
pWindow->m_vRealSize = PMONITOR->vecSize / 2.f; pWindow->m_vRealSize = PMONITOR->vecSize / 2.f;
if (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect) { if (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect) {
@ -113,11 +113,11 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
if (pWindow->m_uSurface.xwayland->x != 0 && pWindow->m_uSurface.xwayland->y != 0) if (pWindow->m_uSurface.xwayland->x != 0 && pWindow->m_uSurface.xwayland->y != 0)
pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords({pWindow->m_uSurface.xwayland->x, pWindow->m_uSurface.xwayland->y}); pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords({pWindow->m_uSurface.xwayland->x, pWindow->m_uSurface.xwayland->y});
else else
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goalv().x) / 2.f, pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f,
PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goalv().y) / 2.f); PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f);
} else { } else {
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goalv().x) / 2.f, pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f,
PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goalv().y) / 2.f); PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f);
} }
} else { } else {
// we respect the size. // we respect the size.
@ -151,8 +151,8 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
} }
} }
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11) if (**PXWLFORCESCALEZERO && pWindow->m_bIsX11)
pWindow->m_vRealSize = pWindow->m_vRealSize.goalv() / PMONITOR->scale; pWindow->m_vRealSize = pWindow->m_vRealSize.goal() / PMONITOR->scale;
if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect)) { if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect)) {
pWindow->m_vRealPosition.warp(); pWindow->m_vRealPosition.warp();
@ -160,11 +160,11 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
} }
if (pWindow->m_iX11Type != 2) { if (pWindow->m_iX11Type != 2) {
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal());
g_pCompositor->changeWindowZOrder(pWindow, true); g_pCompositor->changeWindowZOrder(pWindow, true);
} else { } else {
pWindow->m_vPendingReportedSize = pWindow->m_vRealSize.goalv(); pWindow->m_vPendingReportedSize = pWindow->m_vRealSize.goal();
pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize; pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize;
} }
} }
@ -200,18 +200,18 @@ void IHyprLayout::onBeginDragWindow() {
if (!DRAGGINGWINDOW->m_bIsFloating) { if (!DRAGGINGWINDOW->m_bIsFloating) {
if (g_pInputManager->dragMode == MBIND_MOVE) { if (g_pInputManager->dragMode == MBIND_MOVE) {
DRAGGINGWINDOW->m_vLastFloatingSize = (DRAGGINGWINDOW->m_vRealSize.goalv() * 0.8489).clamp(Vector2D{5, 5}, Vector2D{}).floor(); DRAGGINGWINDOW->m_vLastFloatingSize = (DRAGGINGWINDOW->m_vRealSize.goal() * 0.8489).clamp(Vector2D{5, 5}, Vector2D{}).floor();
changeWindowFloatingMode(DRAGGINGWINDOW); changeWindowFloatingMode(DRAGGINGWINDOW);
DRAGGINGWINDOW->m_bIsFloating = true; DRAGGINGWINDOW->m_bIsFloating = true;
DRAGGINGWINDOW->m_bDraggingTiled = true; DRAGGINGWINDOW->m_bDraggingTiled = true;
DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize.goalv() / 2.f; DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize.goal() / 2.f;
} }
} }
m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal(); m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal();
m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goalv(); m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goal();
m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goalv(); m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goal();
m_vLastDragXY = m_vBeginDragXY; m_vLastDragXY = m_vBeginDragXY;
// get the grab corner // get the grab corner
@ -268,15 +268,15 @@ void IHyprLayout::onEndDragWindow() {
} else if (g_pInputManager->dragMode == MBIND_MOVE) { } else if (g_pInputManager->dragMode == MBIND_MOVE) {
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS, DRAGGINGWINDOW); CWindow* pWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING | FLOATING_ONLY, DRAGGINGWINDOW);
if (pWindow && pWindow->m_bIsFloating) { if (pWindow) {
if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW)) if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW))
return; return;
if (pWindow->m_sGroupData.pNextWindow && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) { if (pWindow->m_sGroupData.pNextWindow && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) {
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue; static const auto* USECURRPOS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("group:insert_after_current");
(*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); (**USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
pWindow->setGroupCurrent(DRAGGINGWINDOW); pWindow->setGroupCurrent(DRAGGINGWINDOW);
DRAGGINGWINDOW->updateWindowDecos(); DRAGGINGWINDOW->updateWindowDecos();
@ -309,13 +309,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y); const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y);
const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y); const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y);
static auto* const PANIMATEMOUSE = &g_pConfigManager->getConfigValuePtr("misc:animate_mouse_windowdragging")->intValue; static auto* const PANIMATEMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:animate_mouse_windowdragging");
static auto* const PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue; static auto* const PANIMATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes");
if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) || if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) ||
(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count() < (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count() <
1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate && 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate))
(*PANIMATEMOUSE || *PANIMATE)))
return; return;
TIMER = std::chrono::high_resolution_clock::now(); TIMER = std::chrono::high_resolution_clock::now();
@ -326,15 +325,15 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (g_pInputManager->dragMode == MBIND_MOVE) { if (g_pInputManager->dragMode == MBIND_MOVE) {
CBox wb = {m_vBeginDragPositionXY + DELTA, DRAGGINGWINDOW->m_vRealSize.goalv()}; CBox wb = {m_vBeginDragPositionXY + DELTA, DRAGGINGWINDOW->m_vRealSize.goal()};
wb.round(); wb.round();
if (*PANIMATEMOUSE) if (**PANIMATEMOUSE)
DRAGGINGWINDOW->m_vRealPosition = wb.pos(); DRAGGINGWINDOW->m_vRealPosition = wb.pos();
else else
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos()); DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos());
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal());
} else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) {
if (DRAGGINGWINDOW->m_bIsFloating) { if (DRAGGINGWINDOW->m_bIsFloating) {
@ -387,7 +386,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
CBox wb = {newPos, newSize}; CBox wb = {newPos, newSize};
wb.round(); wb.round();
if (*PANIMATE) { if (**PANIMATE) {
DRAGGINGWINDOW->m_vRealSize = wb.size(); DRAGGINGWINDOW->m_vRealSize = wb.size();
DRAGGINGWINDOW->m_vRealPosition = wb.pos(); DRAGGINGWINDOW->m_vRealPosition = wb.pos();
} else { } else {
@ -395,14 +394,14 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos()); DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos());
} }
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal());
} else { } else {
resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW); resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW);
} }
} }
// get middle point // get middle point
Vector2D middle = DRAGGINGWINDOW->m_vRealPosition.vec() + DRAGGINGWINDOW->m_vRealSize.vec() / 2.f; Vector2D middle = DRAGGINGWINDOW->m_vRealPosition.value() + DRAGGINGWINDOW->m_vRealSize.value() / 2.f;
// and check its monitor // and check its monitor
const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle); const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle);
@ -436,18 +435,18 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
EMIT_HOOK_EVENT("changeFloatingMode", pWindow); EMIT_HOOK_EVENT("changeFloatingMode", pWindow);
if (!TILED) { if (!TILED) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f); const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID; pWindow->m_iMonitorID = PNEWMON->ID;
pWindow->moveToWorkspace(PNEWMON->specialWorkspaceID != 0 ? PNEWMON->specialWorkspaceID : PNEWMON->activeWorkspace); pWindow->moveToWorkspace(PNEWMON->specialWorkspaceID != 0 ? PNEWMON->specialWorkspaceID : PNEWMON->activeWorkspace);
pWindow->updateGroupOutputs(); pWindow->updateGroupOutputs();
// save real pos cuz the func applies the default 5,5 mid // save real pos cuz the func applies the default 5,5 mid
const auto PSAVEDPOS = pWindow->m_vRealPosition.goalv(); const auto PSAVEDPOS = pWindow->m_vRealPosition.goal();
const auto PSAVEDSIZE = pWindow->m_vRealSize.goalv(); const auto PSAVEDSIZE = pWindow->m_vRealSize.goal();
// if the window is pseudo, update its size // if the window is pseudo, update its size
if (!pWindow->m_bDraggingTiled) if (!pWindow->m_bDraggingTiled)
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv(); pWindow->m_vPseudoSize = pWindow->m_vRealSize.goal();
pWindow->m_vLastFloatingSize = PSAVEDSIZE; pWindow->m_vLastFloatingSize = PSAVEDSIZE;
@ -469,16 +468,19 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
g_pCompositor->changeWindowZOrder(pWindow, true); g_pCompositor->changeWindowZOrder(pWindow, true);
if (DELTALESSTHAN(pWindow->m_vRealSize.vec().x, pWindow->m_vLastFloatingSize.x, 10) && DELTALESSTHAN(pWindow->m_vRealSize.vec().y, pWindow->m_vLastFloatingSize.y, 10)) { CBox wb = {pWindow->m_vRealPosition.goal() + (pWindow->m_vRealSize.goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize};
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f + Vector2D{10, 10}; wb.round();
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize - Vector2D{20, 20};
if (DELTALESSTHAN(pWindow->m_vRealSize.value().x, pWindow->m_vLastFloatingSize.x, 10) &&
DELTALESSTHAN(pWindow->m_vRealSize.value().y, pWindow->m_vLastFloatingSize.y, 10)) {
wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}};
} }
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f; pWindow->m_vRealPosition = wb.pos();
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->m_vRealSize = wb.size();
pWindow->m_vSize = pWindow->m_vRealSize.goalv(); pWindow->m_vSize = wb.pos();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv(); pWindow->m_vPosition = wb.size();
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
@ -504,7 +506,7 @@ void IHyprLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) {
return; return;
} }
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + delta; PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + delta;
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
} }
@ -529,7 +531,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
// find whether there is a floating window below this one // find whether there is a floating window below this one
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus && if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus &&
!w->m_bNoFocus && w.get() != pWindow) { !w->m_sAdditionalConfigData.noFocus && w.get() != pWindow) {
if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x,
w->m_vPosition.y + w->m_vSize.y)) { w->m_vPosition.y + w->m_vSize.y)) {
return w.get(); return w.get();
@ -542,13 +544,14 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
return m_pLastTiledWindow; return m_pLastTiledWindow;
// if we don't, let's try to find any window that is in the middle // if we don't, let's try to find any window that is in the middle
if (const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(pWindow->middle()); PWINDOWCANDIDATE && PWINDOWCANDIDATE != pWindow) if (const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
PWINDOWCANDIDATE && PWINDOWCANDIDATE != pWindow)
return PWINDOWCANDIDATE; return PWINDOWCANDIDATE;
// if not, floating window // if not, floating window
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus && if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus &&
!w->m_bNoFocus && w.get() != pWindow) !w->m_sAdditionalConfigData.noFocus && w.get() != pWindow)
return w.get(); return w.get();
} }
@ -557,7 +560,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
} }
// if it was a tiled window, we first try to find the window that will replace it. // if it was a tiled window, we first try to find the window that will replace it.
auto pWindowCandidate = g_pCompositor->vectorToWindowIdeal(pWindow->middle()); auto pWindowCandidate = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!pWindowCandidate) if (!pWindowCandidate)
pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->m_iWorkspaceID); pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->m_iWorkspaceID);
@ -591,4 +594,8 @@ void IHyprLayout::requestFocusForWindow(CWindow* pWindow) {
g_pCompositor->focusWindow(pWindow); g_pCompositor->focusWindow(pWindow);
} }
Vector2D IHyprLayout::predictSizeForNewWindow() {
return Vector2D{};
}
IHyprLayout::~IHyprLayout() {} IHyprLayout::~IHyprLayout() {}

View file

@ -181,6 +181,12 @@ class IHyprLayout {
*/ */
virtual void requestFocusForWindow(CWindow*); virtual void requestFocusForWindow(CWindow*);
/*
Called to predict the size of a newly opened window to send it a configure.
Return 0,0 if unpredictable
*/
virtual Vector2D predictSizeForNewWindow();
private: private:
Vector2D m_vBeginDragXY; Vector2D m_vBeginDragXY;
Vector2D m_vLastDragXY; Vector2D m_vLastDragXY;

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