diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index 90bb9286..b6582979 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -9,12 +9,23 @@ body:
---
- - type: input
+ - type: textarea
id: ver
attributes:
label: Hyprland Version
- description: "Paste here the output of `hyprctl version`."
- placeholder: Hyprland, built from branch main at commit...
+ description: "Paste here the output of `hyprctl version`. For hyprland after 0.34.0, paste `hyprctl systeminfo` instead."
+ value: "
+ System/Version info
+
+
+ ```sh
+
+
+
+ ```
+
+
+ "
validations:
required: true
diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml
index 2985ce9a..8a33dd55 100644
--- a/.github/actions/setup_base/action.yml
+++ b/.github/actions/setup_base/action.yml
@@ -23,6 +23,7 @@ runs:
glm \
glslang \
go \
+ hyprlang \
jq \
libc++ \
libdisplay-info \
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index a78b7522..01bb43d1 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -8,29 +8,20 @@ jobs:
container:
image: archlinux
steps:
- - name: Get required pacman pkgs
- run: |
- sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
- pacman --noconfirm --noprogressbar -Syyu
- pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd python libliftoff
- - name: Set up user
- run: |
- useradd -m githubuser
- echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
- - name: Install libdisplay-info from the AUR
- run: |
- su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
- - name: Fix permissions for git
- run: |
- git config --global --add safe.directory /__w/Hyprland/Hyprland
- - name: Checkout Hyprland
- uses: actions/checkout@v3
+ - name: Checkout repository actions
+ uses: actions/checkout@v4
with:
- submodules: recursive
+ sparse-checkout: .github/actions
+
+ - name: Setup base
+ uses: ./.github/actions/setup_base
+ with:
+ INSTALL_XORG_PKGS: true
+
- name: Build Hyprland
run: |
- git submodule sync --recursive && git submodule update --init --force --recursive
make all
+
- name: Compress and package artifacts
run: |
mkdir x86_64-pc-linux-gnu
@@ -45,6 +36,7 @@ jobs:
cp -r example/ hyprland/
cp -r assets/ hyprland/
tar -cvf Hyprland.tar.xz hyprland
+
- name: Release
uses: actions/upload-artifact@v3
with:
@@ -57,28 +49,19 @@ jobs:
container:
image: archlinux
steps:
- - name: Download dependencies
- run: |
- sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
- pacman --noconfirm --noprogressbar -Syyu
- pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd cmake jq python libliftoff
- - name: Set up user
- run: |
- useradd -m githubuser
- echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
- - name: Install libdisplay-info from the AUR
- run: |
- su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
- - name: Checkout Hyprland
- uses: actions/checkout@v3
+ - name: Checkout repository actions
+ uses: actions/checkout@v4
with:
- submodules: true
+ sparse-checkout: .github/actions
+
+ - name: Setup base
+ uses: ./.github/actions/setup_base
+
- name: Configure
- run: |
- meson obj-x86_64-pc-linux-gnu \
- -Ddefault_library=static
+ run: meson setup build -Ddefault_library=static
+
- name: Compile
- run: ninja -C obj-x86_64-pc-linux-gnu
+ run: ninja -C build
noxwayland:
name: "Build Hyprland in pure Wayland (Arch)"
@@ -86,23 +69,36 @@ jobs:
container:
image: archlinux
steps:
- - name: Download dependencies
- run: |
- sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
- pacman --noconfirm --noprogressbar -Syyu
- pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd libliftoff
- - name: Set up user
- run: |
- useradd -m githubuser
- echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
- - name: Install libdisplay-info from the AUR
- run: |
- su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
- - name: Checkout Hyprland
- uses: actions/checkout@v3
+ - name: Checkout repository actions
+ uses: actions/checkout@v4
with:
- submodules: true
+ sparse-checkout: .github/actions
+
+ - name: Setup base
+ uses: ./.github/actions/setup_base
+
- name: Configure
- run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja
+ run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja
+
- name: Compile
run: make release
+
+ clang-format:
+ name: "Code Style (Arch)"
+ runs-on: ubuntu-latest
+ container:
+ image: archlinux
+ steps:
+ - name: Checkout repository actions
+ uses: actions/checkout@v4
+ with:
+ sparse-checkout: .github/actions
+
+ - name: Setup base
+ uses: ./.github/actions/setup_base
+
+ - name: Configure
+ run: meson setup build -Ddefault_library=static
+
+ - name: clang-format check
+ run: ninja -C build clang-format-check
diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml
index a1ea0f24..2c05d5e2 100644
--- a/.github/workflows/nix-build.yml
+++ b/.github/workflows/nix-build.yml
@@ -26,4 +26,4 @@ jobs:
name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- - run: nix build -L ${{ matrix.command }}
+ - run: nix build .#${{ matrix.package }} -L
diff --git a/.github/workflows/security-checks.yml b/.github/workflows/security-checks.yml
index 6b7d71e5..6a86f70e 100644
--- a/.github/workflows/security-checks.yml
+++ b/.github/workflows/security-checks.yml
@@ -24,13 +24,13 @@ jobs:
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
-
+
codeql:
name: CodeQL
runs-on: ubuntu-latest
container:
image: archlinux
-
+
permissions:
actions: read
contents: read
@@ -42,34 +42,25 @@ jobs:
language: [ 'cpp' ]
steps:
- - name: Checkout repository
- uses: actions/checkout@v3
+ - name: Checkout repository actions
+ uses: actions/checkout@v4
+ with:
+ sparse-checkout: .github/actions
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
- - name: Init Hyprland build
- run: |
- sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
- pacman --noconfirm --noprogressbar -Syyu
- pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd python libliftoff
- useradd -m githubuser
- echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
- su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
- git config --global --add safe.directory /__w/Hyprland/Hyprland
-
- - name: Checkout Hyprland
- uses: actions/checkout@v3
+ - name: Setup base
+ uses: ./.github/actions/setup_base
with:
- submodules: recursive
+ INSTALL_XORG_PKGS: true
- name: Build Hyprland
run: |
- git submodule sync --recursive && git submodule update --init --force --recursive
make all
-
+
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 00000000..51f6b91e
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -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
diff --git a/.gitignore b/.gitignore
index dfee530e..b8423e8f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,5 @@ gmon.out
PKGBUILD
src/version.h
+
+.direnv
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bedb7bbf..857e21de 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,8 +57,8 @@ ExternalProject_Add(
wlroots
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
- PATCH_COMMAND sed -E -i -e "s/(soversion = 13)([^032]|$$)/soversion = 13032/g" meson.build
- CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $,-Db_sanitize=address,-Db_sanitize=none> --reconfigure
+ PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build
+ CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$,disabled,enabled> -Dexamples=false -Drenderers=gles2 $,-Db_sanitize=address,-Db_sanitize=none>
BUILD_COMMAND ninja -C build
BUILD_ALWAYS true
BUILD_IN_SOURCE true
@@ -101,7 +101,7 @@ message(STATUS "Checking deps...")
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED)
-pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1) # we do not check for wlroots, as we provide it ourselves
+pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2) # we do not check for wlroots, as we provide it ourselves
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
diff --git a/Makefile b/Makefile
index 0a0ef8fa..9c5e94d5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,22 +1,22 @@
PREFIX = /usr/local
legacyrenderer:
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
legacyrendererdebug:
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
release:
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
debug:
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -S . -B ./build -G Ninja
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
@@ -42,10 +42,10 @@ install:
chmod 755 ${PREFIX}/bin/Hyprland
chmod 755 ${PREFIX}/bin/hyprctl
chmod 755 ${PREFIX}/bin/hyprpm
- ln -s -r -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
mkdir -p ${PREFIX}/share/hyprland
- cp ./assets/wall_* ${PREFIX}/share/hyprland
+ cp ./assets/wall* ${PREFIX}/share/hyprland
mkdir -p ${PREFIX}/share/xdg-desktop-portal
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
diff --git a/README.md b/README.md
index 82dd0731..9f4aa847 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
- Much more QoL stuff than other wlr-based compositors
- Custom bezier curves for the best animations
- Powerful plugin support
+- Built-in plugin manager
- Tearing support for better gaming performance
- Easily expandable and readable codebase
- Fast and active development
diff --git a/assets/meson.build b/assets/meson.build
index cdfafabb..8c4a60ec 100644
--- a/assets/meson.build
+++ b/assets/meson.build
@@ -1,9 +1,7 @@
-wallpaper_types = ['', 'anime_', 'anime2_']
+wallpapers = ['0', '1', '2']
-foreach type : wallpaper_types
- foreach size : [2, 4, 8]
- install_data(f'wall_@type@@size@K.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
- endforeach
+foreach type : wallpapers
+ install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
endforeach
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')
diff --git a/assets/wall0.png b/assets/wall0.png
new file mode 100644
index 00000000..73bdeef8
Binary files /dev/null and b/assets/wall0.png differ
diff --git a/assets/wall1.png b/assets/wall1.png
new file mode 100644
index 00000000..53e4c90d
Binary files /dev/null and b/assets/wall1.png differ
diff --git a/assets/wall2.png b/assets/wall2.png
new file mode 100644
index 00000000..9ade4720
Binary files /dev/null and b/assets/wall2.png differ
diff --git a/assets/wall_2K.png b/assets/wall_2K.png
deleted file mode 100644
index 5aea012a..00000000
Binary files a/assets/wall_2K.png and /dev/null differ
diff --git a/assets/wall_4K.png b/assets/wall_4K.png
deleted file mode 100644
index f835a978..00000000
Binary files a/assets/wall_4K.png and /dev/null differ
diff --git a/assets/wall_8K.png b/assets/wall_8K.png
deleted file mode 100644
index 539aa97d..00000000
Binary files a/assets/wall_8K.png and /dev/null differ
diff --git a/assets/wall_anime2_2K.png b/assets/wall_anime2_2K.png
deleted file mode 100644
index 5a465efa..00000000
Binary files a/assets/wall_anime2_2K.png and /dev/null differ
diff --git a/assets/wall_anime2_4K.png b/assets/wall_anime2_4K.png
deleted file mode 100644
index b04e6d00..00000000
Binary files a/assets/wall_anime2_4K.png and /dev/null differ
diff --git a/assets/wall_anime2_8K.png b/assets/wall_anime2_8K.png
deleted file mode 100644
index b8da18ef..00000000
Binary files a/assets/wall_anime2_8K.png and /dev/null differ
diff --git a/assets/wall_anime_2K.png b/assets/wall_anime_2K.png
deleted file mode 100644
index 202dc493..00000000
Binary files a/assets/wall_anime_2K.png and /dev/null differ
diff --git a/assets/wall_anime_4K.png b/assets/wall_anime_4K.png
deleted file mode 100644
index 687b79c3..00000000
Binary files a/assets/wall_anime_4K.png and /dev/null differ
diff --git a/assets/wall_anime_8K.png b/assets/wall_anime_8K.png
deleted file mode 100644
index 25c15cd7..00000000
Binary files a/assets/wall_anime_8K.png and /dev/null differ
diff --git a/docs/ISSUE_GUIDELINES.md b/docs/ISSUE_GUIDELINES.md
index be011608..c031fe85 100644
--- a/docs/ISSUE_GUIDELINES.md
+++ b/docs/ISSUE_GUIDELINES.md
@@ -47,7 +47,7 @@ basically, directories in /tmp/hypr are your sessions.
## Obtaining the Hyprland Crash Report (v0.22.0beta and up)
-If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `~/.hyprland`
+If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `$HOME/.cache/hyprland`.
Go to the crash report directory and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.
diff --git a/example/hyprland.conf b/example/hyprland.conf
index 56d04cae..452b308d 100644
--- a/example/hyprland.conf
+++ b/example/hyprland.conf
@@ -5,108 +5,14 @@
# Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf
-# Startup
-#exec-once = waybar & hyprpaper & dunst
-exec-once = /usr/libexec/polkit-gnome-authentication-agent-1
-exec-once = hyprpm reload -n
-#exec-once = wl-clip-persist --clipboard both
-#exec-once = wl-paste -p -t text --watch clipman store -P --histpath="~/.local/share/clipman-primary.json"
+# Set programs that you use
+$terminal = kitty
+$fileManager = dolphin
+$menu = wofi --show drun
-# Plugins
-#plugin {
-# split-monitor-workspaces {
-# 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
-# # = 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
-# # = 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
-# }
-# }
-#}
+# Some default env vars.
+env = XCURSOR_SIZE,24
+env = QT_QPA_PLATFORMTHEME,qt5ct # change to qt6ct if you have that
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
input {
@@ -184,33 +90,36 @@ gestures {
workspace_swipe = off
}
-# unscale XWayland
-xwayland {
- force_zero_scaling = true
+misc {
+ # See https://wiki.hyprland.org/Configuring/Variables/ for more
+ 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
-windowrule = rounding 1,class:^(Wine)$
-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)
+windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
+
+
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
$mainMod = SUPER
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
-bind = $mainMod, RETURN, exec, $terminal
-bind = $mainMod, Q, killactive,
-bind = $mainMod SHIFT, Q, exit,
-bind = $mainMod, F, fullscreen,
-bind = $mainMod, SPACE, togglefloating,
-bind = $mainMod, L, exec, gtklock
-bind = $mainMod CTRL, B, exec, killall waybar && waybar -c /home/$USER/.config/waybar/config-hypr
-
-bind = $mainMod, D, exec, rofi -show run
+bind = $mainMod, Q, exec, $terminal
+bind = $mainMod, C, killactive,
+bind = $mainMod, M, exit,
+bind = $mainMod, E, exec, $fileManager
+bind = $mainMod, V, togglefloating,
+bind = $mainMod, R, exec, $menu
bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, togglesplit, # dwindle
bind = $mainMod, Print, exec, grim -g "$(slurp)" - | swappy -f - # take a screenshot
diff --git a/flake.lock b/flake.lock
index f7761728..d5e00c3b 100644
--- a/flake.lock
+++ b/flake.lock
@@ -23,13 +23,36 @@
"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": {
"locked": {
- "lastModified": 1703438236,
- "narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
+ "lastModified": 1708807242,
+ "narHash": "sha256-sRTRkhMD4delO/hPxxi+XwLqPn8BuUq6nnj4JqLwOu0=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
+ "rev": "73de017ef2d18a04ac4bfd0c02650007ccb31c2a",
"type": "github"
},
"original": {
@@ -42,6 +65,7 @@
"root": {
"inputs": {
"hyprland-protocols": "hyprland-protocols",
+ "hyprlang": "hyprlang",
"nixpkgs": "nixpkgs",
"systems": "systems",
"wlroots": "wlroots",
@@ -67,18 +91,18 @@
"flake": false,
"locked": {
"host": "gitlab.freedesktop.org",
- "lastModified": 1701368958,
- "narHash": "sha256-7kvyoA91etzVEl9mkA/EJfB6z/PltxX7Xc4gcr7/xlo=",
+ "lastModified": 1708558866,
+ "narHash": "sha256-Mz6hCtommq7RQfcPnxLINigO4RYSNt23HeJHC6mVmWI=",
"owner": "wlroots",
"repo": "wlroots",
- "rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
+ "rev": "0cb091f1a2d345f37d2ee445f4ffd04f7f4ec9e5",
"type": "gitlab"
},
"original": {
"host": "gitlab.freedesktop.org",
"owner": "wlroots",
"repo": "wlroots",
- "rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
+ "rev": "0cb091f1a2d345f37d2ee445f4ffd04f7f4ec9e5",
"type": "gitlab"
}
},
@@ -87,6 +111,9 @@
"hyprland-protocols": [
"hyprland-protocols"
],
+ "hyprlang": [
+ "hyprlang"
+ ],
"nixpkgs": [
"nixpkgs"
],
@@ -95,11 +122,11 @@
]
},
"locked": {
- "lastModified": 1703514399,
- "narHash": "sha256-VRr5Xc4S/VPr/gU3fiOD3vSIL2+GJ+LUrmFTWTwnTz4=",
+ "lastModified": 1708696469,
+ "narHash": "sha256-shh5wmpeYy3MmsBfkm4f76yPsBDGk6OLYRVG+ARy2F0=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
- "rev": "0a318a7a217a6402b0b705837cd5b50b0e94b31b",
+ "rev": "1b713911c2f12b96c2574474686e4027ac4bf826",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 6807c0f3..675a6d92 100644
--- a/flake.nix
+++ b/flake.nix
@@ -12,7 +12,7 @@
host = "gitlab.freedesktop.org";
owner = "wlroots";
repo = "wlroots";
- rev = "5d639394f3e83b01596dcd166a44a9a1a2583350";
+ rev = "0cb091f1a2d345f37d2ee445f4ffd04f7f4ec9e5";
flake = false;
};
@@ -22,11 +22,18 @@
inputs.systems.follows = "systems";
};
+ hyprlang = {
+ url = "github:hyprwm/hyprlang";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.systems.follows = "systems";
+ };
+
xdph = {
url = "github:hyprwm/xdg-desktop-portal-hyprland";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprland-protocols.follows = "hyprland-protocols";
+ inputs.hyprlang.follows = "hyprlang";
};
};
@@ -86,6 +93,7 @@
name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
buildInputs = [self.packages.${system}.wlroots-hyprland];
+ hardeningDisable = ["fortify"];
inputsFrom = [
self.packages.${system}.wlroots-hyprland
self.packages.${system}.hyprland
diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp
index f11cac6e..11b571ac 100644
--- a/hyprctl/main.cpp
+++ b/hyprctl/main.cpp
@@ -86,7 +86,7 @@ std::vector instances() {
std::vector result;
for (const auto& el : std::filesystem::directory_iterator("/tmp/hypr")) {
- if (el.is_directory())
+ if (el.is_directory() || !el.path().string().ends_with(".lock"))
continue;
// read lock
@@ -94,7 +94,9 @@ std::vector instances() {
data->id = el.path().string();
data->id = data->id.substr(data->id.find_last_of('/') + 1, data->id.find(".lock") - data->id.find_last_of('/') - 1);
- 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
std::ifstream ifs(el.path().string());
@@ -102,7 +104,9 @@ std::vector instances() {
int i = 0;
for (std::string line; std::getline(ifs, line); ++i) {
if (i == 0) {
- data->pid = std::stoull(line);
+ try {
+ data->pid = std::stoull(line);
+ } catch (std::exception& e) { continue; }
} else if (i == 1) {
data->wlSocket = line;
} else
@@ -309,6 +313,8 @@ int main(int argc, char** argv) {
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
fullArgs += "j";
json = true;
+ } else if (ARGS[i] == "-r" && !fullArgs.contains("r")) {
+ fullArgs += "r";
} else if (ARGS[i] == "--batch") {
fullRequest = "--batch ";
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
@@ -368,7 +374,7 @@ int main(int argc, char** argv) {
const auto ISIG = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!ISIG) {
- std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)";
+ std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)\n";
return 1;
}
@@ -442,8 +448,7 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/--help"))
printf("%s", USAGE.c_str());
else {
- printf("%s\n", USAGE.c_str());
- return 1;
+ request(fullRequest);
}
printf("\n");
diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp
index d95f10bb..b4fc8dd5 100644
--- a/hyprpm/src/core/DataState.cpp
+++ b/hyprpm/src/core/DataState.cpp
@@ -20,11 +20,18 @@ std::string DataState::getDataStatePath() {
return std::string{HOME} + "/.local/share/hyprpm";
}
+std::string DataState::getHeadersPath() {
+ return getDataStatePath() + "/headersRoot";
+}
+
void DataState::ensureStateStoreExists() {
const auto PATH = getDataStatePath();
if (!std::filesystem::exists(PATH))
std::filesystem::create_directories(PATH);
+
+ if (!std::filesystem::exists(getHeadersPath()))
+ std::filesystem::create_directories(getHeadersPath());
}
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
@@ -47,7 +54,8 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
DATA.emplace(p.name, toml::table{
{"filename", p.name + ".so"},
- {"enabled", p.enabled}
+ {"enabled", p.enabled},
+ {"failed", p.failed}
});
}
// clang-format on
@@ -63,7 +71,10 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
const auto PATH = getDataStatePath();
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
- if (!entry.is_directory())
+ if (!entry.is_directory() || entry.path().stem() == "headersRoot")
+ continue;
+
+ if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@@ -84,7 +95,10 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
const auto PATH = getDataStatePath();
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
- if (!entry.is_directory())
+ if (!entry.is_directory() || entry.path().stem() == "headersRoot")
+ continue;
+
+ if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@@ -153,7 +167,10 @@ std::vector DataState::getAllRepositories() {
std::vector repos;
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
- if (!entry.is_directory())
+ if (!entry.is_directory() || entry.path().stem() == "headersRoot")
+ continue;
+
+ if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@@ -172,9 +189,10 @@ std::vector DataState::getAllRepositories() {
continue;
const auto ENABLED = STATE[key]["enabled"].value_or(false);
+ const auto FAILED = STATE[key]["failed"].value_or(false);
const auto FILENAME = STATE[key]["filename"].value_or("");
- repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED});
+ repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED, FAILED});
}
repos.push_back(repo);
@@ -189,7 +207,10 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
const auto PATH = getDataStatePath();
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
- if (!entry.is_directory())
+ if (!entry.is_directory() || entry.path().stem() == "headersRoot")
+ continue;
+
+ if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@@ -201,6 +222,11 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
if (key.str() != name)
continue;
+ const auto FAILED = STATE[key]["failed"].value_or(false);
+
+ if (FAILED)
+ return false;
+
(*STATE[key].as_table()).insert_or_assign("enabled", enabled);
std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
@@ -212,4 +238,4 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
}
return false;
-}
\ No newline at end of file
+}
diff --git a/hyprpm/src/core/DataState.hpp b/hyprpm/src/core/DataState.hpp
index ac81dae1..c4a7c12d 100644
--- a/hyprpm/src/core/DataState.hpp
+++ b/hyprpm/src/core/DataState.hpp
@@ -10,6 +10,7 @@ struct SGlobalState {
namespace DataState {
std::string getDataStatePath();
+ std::string getHeadersPath();
void ensureStateStoreExists();
void addNewPluginRepo(const SPluginRepository& repo);
void removePluginRepo(const std::string& urlOrName);
@@ -18,4 +19,4 @@ namespace DataState {
SGlobalState getGlobalState();
bool setPluginEnabled(const std::string& name, bool enabled);
std::vector getAllRepositories();
-};
\ No newline at end of file
+};
diff --git a/hyprpm/src/core/Manifest.hpp b/hyprpm/src/core/Manifest.hpp
index 63e1791f..10b326c0 100644
--- a/hyprpm/src/core/Manifest.hpp
+++ b/hyprpm/src/core/Manifest.hpp
@@ -19,6 +19,7 @@ class CManifest {
std::vector authors;
std::vector buildSteps;
std::string output;
+ bool failed = false;
};
struct {
@@ -29,4 +30,4 @@ class CManifest {
std::vector m_vPlugins;
bool m_bGood = true;
-};
\ No newline at end of file
+};
diff --git a/hyprpm/src/core/Plugin.hpp b/hyprpm/src/core/Plugin.hpp
index 32c02a49..edc7486a 100644
--- a/hyprpm/src/core/Plugin.hpp
+++ b/hyprpm/src/core/Plugin.hpp
@@ -6,7 +6,8 @@
struct SPlugin {
std::string name;
std::string filename;
- bool enabled;
+ bool enabled = false;
+ bool failed = false;
};
struct SPluginRepository {
@@ -14,4 +15,4 @@ struct SPluginRepository {
std::string name;
std::vector plugins;
std::string hash;
-};
\ No newline at end of file
+};
diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp
index e5904d66..4b026090 100644
--- a/hyprpm/src/core/PluginManager.cpp
+++ b/hyprpm/src/core/PluginManager.cpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
@@ -78,6 +79,8 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
bool CPluginManager::addNewPluginRepo(const std::string& url) {
+ const auto HLVER = getHyprlandVersion();
+
if (DataState::pluginRepoExists(url)) {
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
return false;
@@ -170,6 +173,22 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
message += " version " + pl.version;
progress.printMessageAbove(message);
}
+
+ if (!pManifest->m_sRepository.commitPins.empty()) {
+ // check commit pins
+
+ progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
+
+ for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) {
+ if (hl != HLVER.hash)
+ continue;
+
+ progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
+
+ execAndGet("cd /tmp/hyprpm/new/ && git reset --hard --recurse-submodules " + plugin);
+ }
+ }
+
progress.m_szCurrentMessage = "Verifying headers";
progress.print();
@@ -191,16 +210,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) {
- out += execAndGet("cd /tmp/hyprpm/new && " + bs) + "\n";
+ std::string cmd = std::format("cd /tmp/hyprpm/new && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", DataState::getHeadersPath(), bs);
+ out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
}
if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) {
- std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Plugin " << p.name << " failed to build.\n";
+ progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Plugin " + p.name + " failed to build.\n");
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
- return false;
+ p.failed = true;
+
+ continue;
}
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output);
@@ -220,7 +242,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
repo.url = url;
repo.hash = repohash;
for (auto& p : pManifest->m_vPlugins) {
- repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false});
+ repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false, p.failed});
}
DataState::addNewPluginRepo(repo);
@@ -263,8 +285,12 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
eHeadersErrors CPluginManager::headersValid() {
const auto HLVER = getHyprlandVersion();
+ if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc"))
+ return HEADERS_MISSING;
+
// find headers commit
- auto headers = execAndGet("pkg-config --cflags --keep-system-cflags hyprland");
+ std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkg-config --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
+ auto headers = execAndGet(cmd.c_str());
if (!headers.contains("-I/"))
return HEADERS_MISSING;
@@ -296,10 +322,6 @@ eHeadersErrors CPluginManager::headersValid() {
if (!ifs.good())
return HEADERS_CORRUPTED;
- if ((std::filesystem::exists("/usr/include/hyprland/src/version.h") && verHeader != "/usr/include/hyprland/src/version.h") ||
- (std::filesystem::exists("/usr/local/include/hyprland/src/version.h") && verHeader != "/usr/local/include/hyprland/src/version.h"))
- return HEADERS_DUPLICATED;
-
std::string verHeaderContent((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator()));
ifs.close();
@@ -314,7 +336,9 @@ eHeadersErrors CPluginManager::headersValid() {
return HEADERS_OK;
}
-bool CPluginManager::updateHeaders() {
+bool CPluginManager::updateHeaders(bool force) {
+
+ DataState::ensureStateStoreExists();
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);
}
- if (headersValid() == HEADERS_OK) {
- std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Your headers are already up-to-date.\n";
- auto GLOBALSTATE = DataState::getGlobalState();
- GLOBALSTATE.headersHashCompiled = HLVER.hash;
- DataState::updateGlobalState(GLOBALSTATE);
+ if (!force && headersValid() == HEADERS_OK) {
+ std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Headers up to date.\n";
return true;
}
@@ -342,9 +363,9 @@ bool CPluginManager::updateHeaders() {
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")) {
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");
- ret = execAndGet("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja");
+ if (m_bVerbose)
+ progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath());
+
+ ret = execAndGet(
+ std::format("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja",
+ DataState::getHeadersPath()));
+ if (m_bVerbose)
+ progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
+
// le hack. Wlroots has to generate its build/include
ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots && meson setup -Drenderers=gles2 -Dexamples=false build");
+ if (m_bVerbose)
+ progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret);
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " configured Hyprland");
progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources";
progress.print();
- progress.printMessageAbove(
- std::string{Colors::YELLOW} + "!" + Colors::RESET +
- " in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
+ // progress.printMessageAbove(
+ // std::string{Colors::YELLOW} + "!" + Colors::RESET +
+ // " in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
- ret = execAndGet("pkexec sh \"-c\" \"cd /tmp/hyprpm/hyprland && make installheaders\"");
+ std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" /tmp/hyprpm/hyprland/Makefile && cd /tmp/hyprpm/hyprland && make installheaders",
+ DataState::getHeadersPath());
+ if (m_bVerbose)
+ progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd);
+
+ ret = execAndGet(cmd);
if (m_bVerbose)
- std::cout << Colors::BLUE << "[v] " << Colors::RESET << "pkexec returned: " << ret << "\n";
+ std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n";
// remove build files
std::filesystem::remove_all("/tmp/hyprpm/hyprland");
@@ -397,10 +433,6 @@ bool CPluginManager::updateHeaders() {
progress.m_szCurrentMessage = "Done!";
progress.print();
- auto GLOBALSTATE = DataState::getGlobalState();
- GLOBALSTATE.headersHashCompiled = HLVER.hash;
- DataState::updateGlobalState(GLOBALSTATE);
-
std::cout << "\n";
} else {
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID));
@@ -434,7 +466,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
const auto HLVER = getHyprlandVersion();
CProgressBar progress;
- progress.m_iMaxSteps = REPOS.size() * 2 + 1;
+ progress.m_iMaxSteps = REPOS.size() * 2 + 2;
progress.m_iSteps = 0;
progress.m_szCurrentMessage = "Updating repositories";
progress.print();
@@ -528,7 +560,8 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) {
- out += execAndGet("cd /tmp/hyprpm/update && " + bs) + "\n";
+ std::string cmd = std::format("cd /tmp/hyprpm/update && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", DataState::getHeadersPath(), bs);
+ out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
}
if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) {
@@ -566,6 +599,14 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " updated " + repo.name);
}
+ progress.m_iSteps++;
+ progress.m_szCurrentMessage = "Updating global state...";
+ progress.print();
+
+ auto GLOBALSTATE = DataState::getGlobalState();
+ GLOBALSTATE.headersHashCompiled = HLVER.hash;
+ DataState::updateGlobalState(GLOBALSTATE);
+
progress.m_iSteps++;
progress.m_szCurrentMessage = "Done!";
progress.print();
@@ -696,8 +737,13 @@ void CPluginManager::listAllPlugins() {
std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n";
for (auto& p : r.plugins) {
- std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name + "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false")
- << Colors::RESET << "\n";
+
+ std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
+
+ if (!p.failed)
+ std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n";
+ else
+ std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n";
}
}
}
diff --git a/hyprpm/src/core/PluginManager.hpp b/hyprpm/src/core/PluginManager.hpp
index 3c5c7c5c..5e1eb6fb 100644
--- a/hyprpm/src/core/PluginManager.hpp
+++ b/hyprpm/src/core/PluginManager.hpp
@@ -40,7 +40,7 @@ class CPluginManager {
bool removePluginRepo(const std::string& urlOrName);
eHeadersErrors headersValid();
- bool updateHeaders();
+ bool updateHeaders(bool force = false);
bool updatePlugins(bool forceUpdateAll);
void listAllPlugins();
@@ -60,4 +60,4 @@ class CPluginManager {
std::string headerError(const eHeadersErrors err);
};
-inline std::unique_ptr g_pPluginManager;
\ No newline at end of file
+inline std::unique_ptr g_pPluginManager;
diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp
index 2acc3d39..c0697e29 100644
--- a/hyprpm/src/main.cpp
+++ b/hyprpm/src/main.cpp
@@ -1,6 +1,7 @@
#include "progress/CProgressBar.hpp"
#include "helpers/Colors.hpp"
#include "core/PluginManager.hpp"
+#include "core/DataState.hpp"
#include
#include
@@ -37,7 +38,7 @@ int main(int argc, char** argv, char** envp) {
}
std::vector command;
- bool notify = false, verbose = false;
+ bool notify = false, verbose = false, force = false;
for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) {
@@ -48,6 +49,9 @@ int main(int argc, char** argv, char** envp) {
notify = true;
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
verbose = true;
+ } else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
+ force = true;
+ std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
} else {
std::cerr << "Unrecognized option " << ARGS[i];
return 1;
@@ -81,9 +85,13 @@ int main(int argc, char** argv, char** envp) {
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
} else if (command[0] == "update") {
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
- bool headers = g_pPluginManager->updateHeaders();
+ bool headers = g_pPluginManager->updateHeaders(force);
if (headers) {
- bool ret1 = g_pPluginManager->updatePlugins(!headersValid);
+ const auto HLVER = g_pPluginManager->getHyprlandVersion();
+ auto GLOBALSTATE = DataState::getGlobalState();
+ const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
+
+ bool ret1 = g_pPluginManager->updatePlugins(!headersValid || force || COMPILEDOUTDATED);
if (!ret1)
return 1;
diff --git a/nix/default.nix b/nix/default.nix
index 751457ca..6062a215 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -9,6 +9,7 @@
cairo,
git,
hyprland-protocols,
+ hyprlang,
jq,
libGL,
libdrm,
@@ -75,6 +76,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
cairo
git
hyprland-protocols
+ hyprlang
libdrm
libGL
libinput
diff --git a/nix/overlays.nix b/nix/overlays.nix
index 5eb7b082..0a84d93e 100644
--- a/nix/overlays.nix
+++ b/nix/overlays.nix
@@ -10,21 +10,19 @@
(builtins.substring 4 2 longDate)
(builtins.substring 6 2 longDate)
]);
-
- mkJoinedOverlays = overlays: final: prev:
- lib.foldl' (attrs: overlay: attrs // (overlay final prev)) {} overlays;
in {
# Contains what a user is most likely to care about:
# Hyprland itself, XDPH and the Share Picker.
- default = mkJoinedOverlays (with self.overlays; [
+ default = lib.composeManyExtensions (with self.overlays; [
hyprland-packages
hyprland-extras
]);
# Packages for variations of Hyprland, dependencies included.
- hyprland-packages = mkJoinedOverlays [
+ hyprland-packages = lib.composeManyExtensions [
# Dependencies
inputs.hyprland-protocols.overlays.default
+ inputs.hyprlang.overlays.default
self.overlays.wlroots-hyprland
self.overlays.udis86
# Hyprland packages themselves
@@ -34,9 +32,9 @@ in {
hyprland = final.callPackage ./default.nix {
stdenv = final.gcc13Stdenv;
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
- wlroots = final.wlroots-hyprland;
commit = self.rev or "";
- inherit (final) udis86 hyprland-protocols;
+ wlroots = final.wlroots-hyprland; # explicit override until decided on breaking change of the name
+ udis86 = final.udis86-hyprland; # explicit override until decided on breaking change of the name
inherit date;
};
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
@@ -59,12 +57,12 @@ in {
# Packages for extra software recommended for usage with Hyprland,
# including forked or patched packages for compatibility.
- hyprland-extras = mkJoinedOverlays [
+ hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.xdg-desktop-portal-hyprland
];
udis86 = final: prev: {
- udis86 = final.callPackage ./udis86.nix {};
+ udis86-hyprland = final.callPackage ./udis86.nix {};
};
# Patched version of wlroots for Hyprland.
diff --git a/nix/patches/meson-build.patch b/nix/patches/meson-build.patch
index 844eacae..aefbf1bc 100644
--- a/nix/patches/meson-build.patch
+++ b/nix/patches/meson-build.patch
@@ -34,16 +34,17 @@ index 1d2c7f9f..c5ef4e67 100644
headers = globber.stdout().strip().split('\n')
foreach file : headers
diff --git a/src/meson.build b/src/meson.build
-index 0af864b9..38723b8c 100644
+index 45701f5f..3505cefe 100644
--- a/src/meson.build
+++ b/src/meson.build
-@@ -9,16 +9,16 @@ executable('Hyprland', src,
+@@ -9,17 +9,17 @@ executable('Hyprland', src,
server_protos,
dependency('wayland-server'),
dependency('wayland-client'),
- wlroots.get_variable('wlroots'),
+ dependency('wlroots'),
dependency('cairo'),
+ dependency('hyprlang', version: '>= 0.3.2'),
dependency('libdrm'),
dependency('egl'),
dependency('xkbcommon'),
diff --git a/nix/update-wlroots.sh b/nix/update-wlroots.sh
index addf2df2..01f5cd83 100755
--- a/nix/update-wlroots.sh
+++ b/nix/update-wlroots.sh
@@ -8,7 +8,7 @@ CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }')
if [ "$SUB_REV" != "$CRT_REV" ]; then
echo "Updating wlroots..."
# update wlroots to submodule revision
- sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix subprojects/wlroots.wrap
+ sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix
nix flake lock
echo "wlroots: $CRT_REV -> $SUB_REV"
diff --git a/props.json b/props.json
index 93c30160..557042f5 100644
--- a/props.json
+++ b/props.json
@@ -1,3 +1,3 @@
{
- "version": "0.34.0"
-}
\ No newline at end of file
+ "version": "0.36.0"
+}
diff --git a/protocols/meson.build b/protocols/meson.build
index cc111e98..857df50f 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -1,5 +1,5 @@
wayland_protos = dependency('wayland-protocols',
- version: '>=1.25',
+ version: '>=1.32',
fallback: 'wayland-protocols',
default_options: ['tests=false'],
)
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 5ac6b303..f0d7ca0f 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -81,26 +81,6 @@ CCompositor::CCompositor() {
CCompositor::~CCompositor() {
cleanup();
- g_pDecorationPositioner.reset();
- g_pPluginSystem.reset();
- g_pHyprNotificationOverlay.reset();
- g_pDebugOverlay.reset();
- g_pEventManager.reset();
- g_pSessionLockManager.reset();
- g_pProtocolManager.reset();
- g_pXWaylandManager.reset();
- g_pHyprRenderer.reset();
- g_pHyprOpenGL.reset();
- g_pInputManager.reset();
- g_pThreadManager.reset();
- g_pConfigManager.reset();
- g_pLayoutManager.reset();
- g_pHyprError.reset();
- g_pConfigManager.reset();
- g_pAnimationManager.reset();
- g_pKeybindManager.reset();
- g_pHookSystem.reset();
- g_pWatchdog.reset();
}
void CCompositor::setRandomSplash() {
@@ -119,8 +99,11 @@ void CCompositor::initServer() {
// register crit signal handler
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
- signal(SIGSEGV, handleUnrecoverableSignal);
- signal(SIGABRT, handleUnrecoverableSignal);
+
+ if (!envEnabled("HYPRLAND_NO_CRASHREPORTER")) {
+ signal(SIGSEGV, handleUnrecoverableSignal);
+ signal(SIGABRT, handleUnrecoverableSignal);
+ }
signal(SIGUSR1, handleUserSignal);
initManagers(STAGE_PRIORITY);
@@ -135,10 +118,10 @@ void CCompositor::initServer() {
else
wlr_log_init(WLR_ERROR, Debug::wlrLog);
- m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay, &m_sWLRSession);
+ m_sWLRBackend = wlr_backend_autocreate(m_sWLEventLoop, &m_sWLRSession);
if (!m_sWLRBackend) {
- Debug::log(CRIT, "m_sWLRBackend was NULL!");
+ Debug::log(CRIT, "m_sWLRBackend was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
throwError("wlr_backend_autocreate() failed!");
}
@@ -151,7 +134,7 @@ void CCompositor::initServer() {
m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD);
if (!m_sWLRRenderer) {
- Debug::log(CRIT, "m_sWLRRenderer was NULL!");
+ Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
throwError("wlr_gles2_renderer_create_with_drm_fd() failed!");
}
@@ -259,7 +242,7 @@ void CCompositor::initServer() {
m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay);
- m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLDisplay);
+ m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop);
m_sWLRSessionLockMgr = wlr_session_lock_manager_v1_create(m_sWLDisplay);
@@ -324,6 +307,7 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRGammaCtrlMgr->events.set_gamma, &Events::listen_setGamma, m_sWLRGammaCtrlMgr, "GammaCtrlMgr");
addWLSignal(&m_sWLRCursorShapeMgr->events.request_set_shape, &Events::listen_setCursorShape, m_sWLRCursorShapeMgr, "CursorShapeMgr");
addWLSignal(&m_sWLRTearingControlMgr->events.new_object, &Events::listen_newTearingHint, m_sWLRTearingControlMgr, "TearingControlMgr");
+ addWLSignal(&m_sWLRKbShInhibitMgr->events.new_inhibitor, &Events::listen_newShortcutInhibitor, m_sWLRKbShInhibitMgr, "ShortcutInhibitMgr");
if (m_sWRLDRMLeaseMgr)
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
@@ -332,10 +316,67 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
}
+void CCompositor::removeAllSignals() {
+ removeWLSignal(&Events::listen_newOutput);
+ removeWLSignal(&Events::listen_newXDGToplevel);
+ removeWLSignal(&Events::listen_mouseMove);
+ removeWLSignal(&Events::listen_mouseMoveAbsolute);
+ removeWLSignal(&Events::listen_mouseButton);
+ removeWLSignal(&Events::listen_mouseAxis);
+ removeWLSignal(&Events::listen_mouseFrame);
+ removeWLSignal(&Events::listen_swipeBegin);
+ removeWLSignal(&Events::listen_swipeUpdate);
+ removeWLSignal(&Events::listen_swipeEnd);
+ removeWLSignal(&Events::listen_pinchBegin);
+ removeWLSignal(&Events::listen_pinchUpdate);
+ removeWLSignal(&Events::listen_pinchEnd);
+ removeWLSignal(&Events::listen_touchBegin);
+ removeWLSignal(&Events::listen_touchEnd);
+ removeWLSignal(&Events::listen_touchUpdate);
+ removeWLSignal(&Events::listen_touchFrame);
+ removeWLSignal(&Events::listen_holdBegin);
+ removeWLSignal(&Events::listen_holdEnd);
+ removeWLSignal(&Events::listen_newInput);
+ removeWLSignal(&Events::listen_requestMouse);
+ removeWLSignal(&Events::listen_requestSetSel);
+ removeWLSignal(&Events::listen_requestDrag);
+ removeWLSignal(&Events::listen_startDrag);
+ removeWLSignal(&Events::listen_requestSetSel);
+ removeWLSignal(&Events::listen_requestSetPrimarySel);
+ removeWLSignal(&Events::listen_newLayerSurface);
+ removeWLSignal(&Events::listen_change);
+ removeWLSignal(&Events::listen_outputMgrApply);
+ removeWLSignal(&Events::listen_outputMgrTest);
+ removeWLSignal(&Events::listen_newConstraint);
+ removeWLSignal(&Events::listen_NewXDGDeco);
+ removeWLSignal(&Events::listen_newVirtPtr);
+ removeWLSignal(&Events::listen_newVirtualKeyboard);
+ removeWLSignal(&Events::listen_RendererDestroy);
+ removeWLSignal(&Events::listen_newIdleInhibitor);
+ removeWLSignal(&Events::listen_powerMgrSetMode);
+ removeWLSignal(&Events::listen_newIME);
+ removeWLSignal(&Events::listen_newTextInput);
+ removeWLSignal(&Events::listen_activateXDG);
+ removeWLSignal(&Events::listen_newSessionLock);
+ removeWLSignal(&Events::listen_setGamma);
+ removeWLSignal(&Events::listen_setCursorShape);
+ removeWLSignal(&Events::listen_newTearingHint);
+ removeWLSignal(&Events::listen_newShortcutInhibitor);
+
+ if (m_sWRLDRMLeaseMgr)
+ removeWLSignal(&Events::listen_leaseRequest);
+
+ if (m_sWLRSession)
+ removeWLSignal(&Events::listen_sessionActive);
+}
+
void CCompositor::cleanup() {
if (!m_sWLDisplay || m_bIsShuttingDown)
return;
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGSEGV, SIG_DFL);
+
removeLockFile();
m_bIsShuttingDown = true;
@@ -362,8 +403,8 @@ void CCompositor::cleanup() {
for (auto& m : m_vMonitors) {
g_pHyprOpenGL->destroyMonitorResources(m.get());
- wlr_output_enable(m->output, false);
- wlr_output_commit(m->output);
+ wlr_output_state_set_enabled(m->state.wlr(), false);
+ m->state.commit();
}
m_vMonitors.clear();
@@ -373,8 +414,32 @@ void CCompositor::cleanup() {
g_pXWaylandManager->m_sWLRXWayland = nullptr;
}
+ removeAllSignals();
+
+ g_pInputManager.reset();
+
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
+ g_pDecorationPositioner.reset();
+ g_pPluginSystem.reset();
+ g_pHyprNotificationOverlay.reset();
+ g_pDebugOverlay.reset();
+ g_pEventManager.reset();
+ g_pSessionLockManager.reset();
+ g_pProtocolManager.reset();
+ g_pHyprRenderer.reset();
+ g_pHyprOpenGL.reset();
+ g_pThreadManager.reset();
+ g_pConfigManager.reset();
+ g_pLayoutManager.reset();
+ g_pHyprError.reset();
+ g_pConfigManager.reset();
+ g_pAnimationManager.reset();
+ g_pKeybindManager.reset();
+ g_pHookSystem.reset();
+ g_pWatchdog.reset();
+ g_pXWaylandManager.reset();
+
wl_display_terminate(m_sWLDisplay);
m_sWLDisplay = nullptr;
@@ -408,6 +473,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the ThreadManager!");
g_pThreadManager = std::make_unique();
+ Debug::log(LOG, "Creating CHyprCtl");
+ g_pHyprCtl = std::make_unique();
+
Debug::log(LOG, "Creating the InputManager!");
g_pInputManager = std::make_unique();
@@ -629,72 +697,32 @@ bool CCompositor::windowExists(CWindow* pWindow) {
return false;
}
-CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
- const auto PMONITOR = getMonitorFromVector(pos);
-
- if (PMONITOR->specialWorkspaceID) {
- for (auto& w : m_vWindows) {
- CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
- if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint(pos) && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
- return w.get();
- }
+bool CCompositor::monitorExists(CMonitor* pMonitor) {
+ for (auto& m : m_vRealMonitors) {
+ if (m.get() == pMonitor)
+ return true;
}
- for (auto& w : m_vWindows) {
- CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
- if (w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
- return w.get();
- }
-
- return nullptr;
+ return false;
}
-CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreWindow) {
+CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, CWindow* pIgnoreWindow) {
const auto PMONITOR = getMonitorFromVector(pos);
- static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
- static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
- static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
- const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
+ static auto* const PRESIZEONBORDER = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:resize_on_border");
+ static auto* const PBORDERSIZE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:border_size");
+ static auto* const PBORDERGRABEXTEND = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area");
+ static auto* const PSPECIALFALLTHRU = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:special_fallthrough");
+ const auto BORDER_GRAB_AREA = **PRESIZEONBORDER ? **PBORDERSIZE + **PBORDERGRABEXTEND : 0;
// pinned windows on top of floating regardless
- for (auto& w : m_vWindows | std::views::reverse) {
- const auto BB = w->getWindowInputBox();
- CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
- if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
- if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
- return w.get();
-
- if (!w->m_bIsX11) {
- if (w->hasPopupAt(pos))
- return w.get();
- }
- }
- }
-
- auto windowForWorkspace = [&](bool special) -> CWindow* {
- // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
+ if (properties & ALLOW_FLOATING) {
for (auto& w : m_vWindows | std::views::reverse) {
-
- if (special && !isWorkspaceSpecial(w->m_iWorkspaceID)) // because special floating may creep up into regular
- continue;
-
- const auto BB = w->getWindowInputBox();
+ const auto BB = w->getWindowBoxUnified(properties);
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
- if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
- // OR windows should add focus to parent
- if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
- continue;
-
- if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
-
- if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
- // Override Redirect
- return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
- // TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
- }
-
+ if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus &&
+ w.get() != pIgnoreWindow) {
+ if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
return w.get();
- }
if (!w->m_bIsX11) {
if (w->hasPopupAt(pos))
@@ -702,6 +730,53 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
}
}
}
+ }
+
+ auto windowForWorkspace = [&](bool special) -> CWindow* {
+ auto floating = [&](bool aboveFullscreen) -> CWindow* {
+ for (auto& w : m_vWindows | std::views::reverse) {
+
+ if (special && !isWorkspaceSpecial(w->m_iWorkspaceID)) // because special floating may creep up into regular
+ continue;
+
+ const auto BB = w->getWindowBoxUnified(properties);
+ CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
+ if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus &&
+ w.get() != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
+ // OR windows should add focus to parent
+ if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
+ continue;
+
+ if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
+
+ if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
+ // Override Redirect
+ return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
+ // TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
+ }
+
+ return w.get();
+ }
+
+ if (!w->m_bIsX11) {
+ if (w->hasPopupAt(pos))
+ return w.get();
+ }
+ }
+ }
+
+ return nullptr;
+ };
+
+ if (properties & ALLOW_FLOATING) {
+ // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
+ auto found = floating(true);
+ if (found)
+ return found;
+ }
+
+ if (properties & FLOATING_ONLY)
+ return floating(false);
const int64_t WORKSPACEID = special ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID);
@@ -709,13 +784,17 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
if (PWORKSPACE->m_bHasFullscreenWindow)
return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
+ auto found = floating(false);
+ if (found)
+ return found;
+
// for windows, we need to check their extensions too, first.
for (auto& w : m_vWindows) {
if (special != isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
- if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus &&
- w.get() != pIgnoreWindow) {
+ if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
+ !w->m_sAdditionalConfigData.noFocus && w.get() != pIgnoreWindow) {
if (w->hasPopupAt(pos))
return w.get();
}
@@ -725,9 +804,9 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
if (special != isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
- CBox box = {w->m_vPosition, w->m_vSize};
- if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus &&
- w.get() != pIgnoreWindow)
+ CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize};
+ if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
+ !w->m_sAdditionalConfigData.noFocus && w.get() != pIgnoreWindow)
return w.get();
}
@@ -735,68 +814,17 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
};
// special workspace
- if (PMONITOR->specialWorkspaceID)
+ if (PMONITOR->specialWorkspaceID && !**PSPECIALFALLTHRU)
return windowForWorkspace(true);
- return windowForWorkspace(false);
-}
-
-CWindow* CCompositor::windowFromCursor() {
- const auto PMONITOR = getMonitorFromCursor();
-
if (PMONITOR->specialWorkspaceID) {
- for (auto& w : m_vWindows | std::views::reverse) {
- CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) &&
- !w->isHidden() && !w->m_bNoFocus)
- return w.get();
- }
+ const auto PWINDOW = windowForWorkspace(true);
- for (auto& w : m_vWindows) {
- CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
- if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && !w->m_bNoFocus)
- return w.get();
- }
+ if (PWINDOW)
+ return PWINDOW;
}
- // pinned
- for (auto& w : m_vWindows | std::views::reverse) {
- CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && w->m_bPinned && !w->m_bNoFocus)
- return w.get();
- }
-
- // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
- for (auto& w : m_vWindows | std::views::reverse) {
- CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bPinned && !w->m_bNoFocus)
- return w.get();
- }
-
- for (auto& w : m_vWindows) {
- CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
- if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bNoFocus)
- return w.get();
- }
-
- return nullptr;
-}
-
-CWindow* CCompositor::windowFloatingFromCursor() {
- for (auto& w : m_vWindows | std::views::reverse) {
- CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
- return w.get();
- }
-
- for (auto& w : m_vWindows | std::views::reverse) {
- CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() &&
- !w->m_bPinned && !w->m_bNoFocus)
- return w.get();
- }
-
- return nullptr;
+ return windowForWorkspace(false);
}
wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pWindow, Vector2D& sl) {
@@ -874,15 +902,31 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
return nullptr;
}
+CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) {
+ for (auto& m : m_vRealMonitors) {
+ if (m->output == out) {
+ return m.get();
+ }
+ }
+
+ return nullptr;
+}
+
void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
- static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
+ static auto* const PFOLLOWMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:follow_mouse");
+ static auto* const PSPECIALFALLTHROUGH = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:special_fallthrough");
if (g_pCompositor->m_sSeat.exclusiveClient) {
Debug::log(LOG, "Disallowing setting focus to a window due to there being an active input inhibitor layer.");
return;
}
+ if (!g_pInputManager->m_dExclusiveLSes.empty()) {
+ Debug::log(LOG, "Refusing a keyboard focus to a window because of an exclusive ls");
+ return;
+ }
+
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
if (!pWindow || !windowValidMapped(pWindow)) {
@@ -917,7 +961,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
return;
}
- if (pWindow->m_bNoFocus) {
+ if (pWindow->m_sAdditionalConfigData.noFocus) {
Debug::log(LOG, "Ignoring focus to nofocus window!");
return;
}
@@ -928,12 +972,13 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
if (pWindow->m_bPinned)
pWindow->m_iWorkspaceID = m_pLastMonitor->activeWorkspace;
+ const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID);
+
if (!isWorkspaceVisible(pWindow->m_iWorkspaceID)) {
+ const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID);
// This is to fix incorrect feedback on the focus history.
- const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID);
PWORKSPACE->m_pLastFocusedWindow = pWindow;
PWORKSPACE->rememberPrevWorkspace(getWorkspaceByID(m_pLastMonitor->activeWorkspace));
- const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID);
PMONITOR->changeWorkspace(PWORKSPACE, false, true);
// changeworkspace already calls focusWindow
return;
@@ -942,6 +987,11 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
const auto PLASTWINDOW = m_pLastWindow;
m_pLastWindow = pWindow;
+ /* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which
+ window focuses are "via keybinds" and which ones aren't. */
+ if (PMONITOR->specialWorkspaceID && PMONITOR->specialWorkspaceID != pWindow->m_iWorkspaceID && !pWindow->m_bPinned && !**PSPECIALFALLTHROUGH)
+ PMONITOR->setSpecialWorkspace(nullptr);
+
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
if (windowValidMapped(PLASTWINDOW)) {
PLASTWINDOW->updateDynamicRules();
@@ -1006,7 +1056,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1);
}
- if (*PFOLLOWMOUSE == 0)
+ if (**PFOLLOWMOUSE == 0)
g_pInputManager->sendMotionEventsToFocused();
}
@@ -1015,10 +1065,8 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
if (m_sSeat.seat->keyboard_state.focused_surface == pSurface || (pWindowOwner && m_sSeat.seat->keyboard_state.focused_surface == pWindowOwner->m_pWLSurface.wlr()))
return; // Don't focus when already focused on this.
- if (g_pSessionLockManager->isSessionLocked()) {
- wlr_seat_keyboard_clear_focus(m_sSeat.seat);
- m_pLastFocus = nullptr;
- }
+ if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface))
+ return;
// Unfocus last surface if should
if (m_pLastFocus && !pWindowOwner)
@@ -1089,14 +1137,6 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
auto SURFACEAT = wlr_layer_surface_v1_surface_at(ls->layerSurface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y);
- if (ls->layerSurface->current.keyboard_interactive && ls->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
- if (!SURFACEAT)
- SURFACEAT = ls->layerSurface->surface;
-
- *ppLayerSurfaceFound = ls.get();
- return SURFACEAT;
- }
-
if (SURFACEAT) {
if (!pixman_region32_not_empty(&SURFACEAT->input_region))
continue;
@@ -1483,7 +1523,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
return nullptr;
// 0 -> history, 1 -> shared length
- static auto* const PMETHOD = &g_pConfigManager->getConfigValuePtr("binds:focus_preferred_method")->intValue;
+ static auto* const PMETHOD = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:focus_preferred_method");
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -1545,7 +1585,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
break;
}
- if (*PMETHOD == 0 /* history */) {
+ if (**PMETHOD == 0 /* history */) {
if (intersectLength > 0) {
// get idx
@@ -1639,7 +1679,7 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
- if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
+ if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get();
}
@@ -1647,7 +1687,7 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
- if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
+ if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get();
}
@@ -1668,7 +1708,7 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
- if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
+ if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get();
}
@@ -1676,7 +1716,7 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
- if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
+ if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get();
}
@@ -1764,8 +1804,15 @@ CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) {
}
CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
- const auto POSA = m_pLastMonitor->vecPosition;
- const auto SIZEA = m_pLastMonitor->vecSize;
+ return this->getMonitorInDirection(m_pLastMonitor, dir);
+}
+
+CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const char& dir) {
+ if (!pSourceMonitor)
+ return nullptr;
+
+ const auto POSA = pSourceMonitor->vecPosition;
+ const auto SIZEA = pSourceMonitor->vecSize;
auto longestIntersect = -1;
CMonitor* longestIntersectMonitor = nullptr;
@@ -1844,21 +1891,30 @@ void CCompositor::updateWorkspaceWindows(const int64_t& id) {
void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
// optimization
- static auto* const ACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.active_border")->data.get();
- static auto* const INACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->data.get();
- static auto* const NOGROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border_active")->data.get();
- static auto* const NOGROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border")->data.get();
- static auto* const GROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_active")->data.get();
- static auto* const GROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_inactive")->data.get();
- static auto* const GROUPACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_active")->data.get();
- static auto* const GROUPINACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_inactive")->data.get();
- static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
- static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
- static auto* const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue;
- static auto* const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue;
- static auto* const PSHADOWCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive")->intValue;
- static auto* const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
- static auto* const PDIMENABLED = &g_pConfigManager->getConfigValuePtr("decoration:dim_inactive")->intValue;
+ static auto* const PACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:col.active_border");
+ static auto* const PINACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border");
+ static auto* const PNOGROUPACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border_active");
+ static auto* const PNOGROUPINACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border");
+ static auto* const PGROUPACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("group:col.border_active");
+ static auto* const PGROUPINACTIVECOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("group:col.border_inactive");
+ static auto* const PGROUPACTIVELOCKEDCOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_active");
+ static auto* const PGROUPINACTIVELOCKEDCOL = (Hyprlang::CUSTOMTYPE* const*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_inactive");
+ static auto* const PINACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity");
+ static auto* const PACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:active_opacity");
+ static auto* const PFULLSCREENALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity");
+ static auto* const PSHADOWCOL = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:col.shadow");
+ static auto* const PSHADOWCOLINACTIVE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive");
+ static auto* const PDIMSTRENGTH = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:dim_strength");
+ static auto* const PDIMENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:dim_inactive");
+
+ auto* const ACTIVECOL = (CGradientValueData*)(*PACTIVECOL)->getData();
+ auto* const INACTIVECOL = (CGradientValueData*)(*PINACTIVECOL)->getData();
+ auto* const NOGROUPACTIVECOL = (CGradientValueData*)(*PNOGROUPACTIVECOL)->getData();
+ auto* const NOGROUPINACTIVECOL = (CGradientValueData*)(*PNOGROUPINACTIVECOL)->getData();
+ auto* const GROUPACTIVECOL = (CGradientValueData*)(*PGROUPACTIVECOL)->getData();
+ auto* const GROUPINACTIVECOL = (CGradientValueData*)(*PGROUPINACTIVECOL)->getData();
+ auto* const GROUPACTIVELOCKEDCOL = (CGradientValueData*)(*PGROUPACTIVELOCKEDCOL)->getData();
+ auto* const GROUPINACTIVELOCKEDCOL = (CGradientValueData*)(*PGROUPINACTIVELOCKEDCOL)->getData();
auto setBorderColor = [&](CGradientValueData grad) -> void {
if (grad == pWindow->m_cRealBorderColor)
@@ -1896,31 +1952,31 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
// opacity
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
- pWindow->m_fActiveInactiveAlpha = *PFULLSCREENALPHA;
+ pWindow->m_fActiveInactiveAlpha = **PFULLSCREENALPHA;
} else {
if (pWindow == m_pLastWindow)
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alpha.toUnderlying() :
- pWindow->m_sSpecialRenderData.alpha.toUnderlying() * *PACTIVEALPHA;
+ pWindow->m_sSpecialRenderData.alpha.toUnderlying() * **PACTIVEALPHA;
else
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() != -1 ?
(pWindow->m_sSpecialRenderData.alphaInactiveOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() :
- pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() * *PINACTIVEALPHA) :
- *PINACTIVEALPHA;
+ pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() * **PINACTIVEALPHA) :
+ **PINACTIVEALPHA;
}
// dim
- if (pWindow == m_pLastWindow || pWindow->m_sAdditionalConfigData.forceNoDim || !*PDIMENABLED) {
+ if (pWindow == m_pLastWindow || pWindow->m_sAdditionalConfigData.forceNoDim || !**PDIMENABLED) {
pWindow->m_fDimPercent = 0;
} else {
- pWindow->m_fDimPercent = *PDIMSTRENGTH;
+ pWindow->m_fDimPercent = **PDIMSTRENGTH;
}
// shadow
if (pWindow->m_iX11Type != 2 && !pWindow->m_bX11DoesntWantBorders) {
if (pWindow == m_pLastWindow) {
- pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL);
+ pWindow->m_cRealShadowColor = CColor(**PSHADOWCOL);
} else {
- pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
+ pWindow->m_cRealShadowColor = CColor(**PSHADOWCOLINACTIVE != INT_MAX ? **PSHADOWCOLINACTIVE : **PSHADOWCOL);
}
} else {
pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow
@@ -2012,7 +2068,11 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
updateFullscreenFadeOnWorkspace(PWORKSPACEB);
updateFullscreenFadeOnWorkspace(PWORKSPACEA);
- g_pInputManager->sendMotionEventsToFocused();
+ if (pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID || pMonitorB->ID == g_pCompositor->m_pLastMonitor->ID) {
+ const auto LASTWIN = pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID ? PWORKSPACEB->getLastFocusedWindow() : PWORKSPACEA->getLastFocusedWindow();
+ g_pCompositor->focusWindow(LASTWIN ? LASTWIN :
+ (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING)));
+ }
// event
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName});
@@ -2022,7 +2082,11 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
}
CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
- if (name[0] == '+' || name[0] == '-') {
+ if (name == "current")
+ return g_pCompositor->m_pLastMonitor;
+ else if (isDirection(name))
+ return getMonitorInDirection(name[0]);
+ else if (name[0] == '+' || name[0] == '-') {
// relative
if (m_vMonitors.size() == 1)
@@ -2077,39 +2141,21 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1");
return nullptr;
}
- } else if (name.starts_with("desc:")) {
- const auto DESCRIPTION = name.substr(5);
-
+ } else {
for (auto& m : m_vMonitors) {
if (!m->output)
continue;
- if (m->szDescription.starts_with(DESCRIPTION)) {
+ if (m->matchesStaticSelector(name)) {
return m.get();
}
}
-
- return nullptr;
- } else {
- if (name == "current")
- return g_pCompositor->m_pLastMonitor;
-
- if (isDirection(name)) {
- const auto PMONITOR = getMonitorInDirection(name[0]);
- return PMONITOR;
- } else {
- for (auto& m : m_vMonitors) {
- if (m->szName == name) {
- return m.get();
- }
- }
- }
}
return nullptr;
}
-void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor) {
+void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor, bool noWarpCursor) {
// We trust the workspace and monitor to be correct.
@@ -2124,7 +2170,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
// fix old mon
int nextWorkspaceOnMonitorID = -1;
- if (!SWITCHINGISACTIVE)
+ if (!SWITCHINGISACTIVE || !POLDMON)
nextWorkspaceOnMonitorID = pWorkspace->m_iID;
else {
for (auto& w : m_vWorkspaces) {
@@ -2149,7 +2195,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
}
Debug::log(LOG, "moveWorkspaceToMonitor: Plugging gap with existing {}", nextWorkspaceOnMonitorID);
- POLDMON->changeWorkspace(nextWorkspaceOnMonitorID);
+ POLDMON->changeWorkspace(nextWorkspaceOnMonitorID, false, true, true);
}
// move the workspace
@@ -2190,12 +2236,14 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
if (const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace); PWORKSPACE)
getWorkspaceByID(pMonitor->activeWorkspace)->startAnim(false, false);
+ setActiveMonitor(pMonitor);
pMonitor->activeWorkspace = pWorkspace->m_iID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
pWorkspace->startAnim(true, true, true);
- wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
+ if (!noWarpCursor)
+ wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
g_pInputManager->sendMotionEventsToFocused();
}
@@ -2282,7 +2330,6 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->shouldSendFullscreenState());
- pWindow->updateDynamicRules();
updateWindowAnimatedDecorationValues(pWindow);
// make all windows on the same workspace under the fullscreen window
@@ -2415,9 +2462,9 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) {
// warpCursorTo should only be used for warps that
// should be disabled with no_cursor_warps
- static auto* const PNOWARPS = &g_pConfigManager->getConfigValuePtr("general:no_cursor_warps")->intValue;
+ static auto* const PNOWARPS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:no_cursor_warps");
- if (*PNOWARPS && !force)
+ if (**PNOWARPS && !force)
return;
if (!m_sSeat.mouse)
@@ -2583,7 +2630,7 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace);
- g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + PWORKSPACE->m_szName});
+ g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + (PWORKSPACE ? PWORKSPACE->m_szName : "?")});
EMIT_HOOK_EVENT("focusedMon", pMonitor);
m_pLastMonitor = pMonitor;
}
@@ -2604,11 +2651,7 @@ int CCompositor::getNewSpecialID() {
}
void CCompositor::performUserChecks() {
- if (g_pConfigManager->getInt("general:allow_tearing") == 1 && !envEnabled("WLR_DRM_NO_ATOMIC")) {
- g_pHyprNotificationOverlay->addNotification("You have enabled tearing, but immediate presentations are not available on your configuration. Try adding "
- "env = WLR_DRM_NO_ATOMIC,1 to your config.",
- CColor(0), 15000, ICON_WARNING);
- }
+ ; // intentional
}
void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) {
@@ -2684,7 +2727,7 @@ void CCompositor::setIdleActivityInhibit(bool enabled) {
wlr_idle_notifier_v1_set_inhibited(g_pCompositor->m_sWLRIdleNotifier, !enabled);
}
void CCompositor::arrangeMonitors() {
- 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");
std::vector toArrange;
std::vector arranged;
@@ -2733,9 +2776,9 @@ void CCompositor::arrangeMonitors() {
for (auto& m : m_vMonitors) {
Debug::log(LOG, "arrangeMonitors: {} xwayland [{}, {:.2f}]", m->szName, maxOffset, 0.f);
m->vecXWaylandPosition = {maxOffset, 0};
- maxOffset += (*PXWLFORCESCALEZERO ? m->vecTransformedSize.x : m->vecSize.x);
+ maxOffset += (**PXWLFORCESCALEZERO ? m->vecTransformedSize.x : m->vecSize.x);
- if (*PXWLFORCESCALEZERO)
+ if (**PXWLFORCESCALEZERO)
m->xwaylandScale = m->scale;
else
m->xwaylandScale = 1.f;
@@ -2783,10 +2826,27 @@ void CCompositor::leaveUnsafeState() {
void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) {
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(pSurface, scale);
wlr_surface_set_preferred_buffer_scale(pSurface, static_cast(std::ceil(scale)));
+
+ const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
+ if (!PSURFACE) {
+ Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface);
+ return;
+ }
+
+ PSURFACE->m_fLastScale = scale;
+ PSURFACE->m_iLastScale = static_cast(std::ceil(scale));
}
void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) {
wlr_surface_set_preferred_buffer_transform(pSurface, transform);
+
+ const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
+ if (!PSURFACE) {
+ Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface);
+ return;
+ }
+
+ PSURFACE->m_eLastTransform = transform;
}
void CCompositor::updateSuspendedStates() {
diff --git a/src/Compositor.hpp b/src/Compositor.hpp
index f954526c..c08a5931 100644
--- a/src/Compositor.hpp
+++ b/src/Compositor.hpp
@@ -135,15 +135,14 @@ class CCompositor {
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
bool windowExists(CWindow*);
bool windowValidMapped(CWindow*);
- CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow"
- CWindow* vectorToWindowTiled(const Vector2D&);
+ bool monitorExists(CMonitor*);
+ CWindow* vectorToWindowUnified(const Vector2D&, uint8_t properties, CWindow* pIgnoreWindow = nullptr);
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector>*, Vector2D*, SLayerSurface**);
SIMEPopup* vectorToIMEPopup(const Vector2D& pos, std::list& popups);
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
- CWindow* windowFromCursor();
- CWindow* windowFloatingFromCursor();
CMonitor* getMonitorFromOutput(wlr_output*);
+ CMonitor* getRealMonitorFromOutput(wlr_output*);
CWindow* getWindowForPopup(wlr_xdg_popup*);
CWindow* getWindowFromSurface(wlr_surface*);
CWindow* getWindowFromHandle(uint32_t);
@@ -172,11 +171,12 @@ class CCompositor {
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
CWindow* getConstraintWindow(SMouse*);
CMonitor* getMonitorInDirection(const char&);
+ CMonitor* getMonitorInDirection(CMonitor*, const char&);
void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const int64_t& id);
void updateWindowAnimatedDecorationValues(CWindow*);
int getNextAvailableMonitorID(std::string const& name);
- void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
+ void moveWorkspaceToMonitor(CWorkspace*, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&);
@@ -214,6 +214,7 @@ class CCompositor {
private:
void initAllSignals();
+ void removeAllSignals();
void setRandomSplash();
void initManagers(eManagersInitStage stage);
void prepareFallbackOutput();
diff --git a/src/SharedDefs.hpp b/src/SharedDefs.hpp
index da7f6938..55ce1f81 100644
--- a/src/SharedDefs.hpp
+++ b/src/SharedDefs.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "helpers/Vector2D.hpp"
+#include
enum eIcons {
ICON_WARNING = 0,
@@ -52,4 +53,20 @@ struct SWindowDecorationExtents {
bool operator==(const SWindowDecorationExtents& other) const {
return topLeft == other.topLeft && bottomRight == other.bottomRight;
}
-};
\ No newline at end of file
+
+ 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 fn;
+};
diff --git a/src/Window.cpp b/src/Window.cpp
index 978d1000..ece5b658 100644
--- a/src/Window.cpp
+++ b/src/Window.cpp
@@ -139,35 +139,25 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
}
-CBox CWindow::getWindowInputBox() {
- const int BORDERSIZE = getRealBorderSize();
+CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_sAdditionalConfigData.dimAround) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
}
- SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
+ SWindowDecorationExtents EXTENTS = {{0, 0}, {0, 0}};
+ if (properties & RESERVED_EXTENTS)
+ EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(this));
+ if (properties & INPUT_EXTENTS)
+ EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, true));
+ if (properties & FULL_EXTENTS)
+ EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, false));
- const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
+ CBox box = {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
+ box.addExtents(EXTENTS);
- if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
- maxExtents.topLeft.x = EXTENTS.topLeft.x;
-
- if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
- maxExtents.topLeft.y = EXTENTS.topLeft.y;
-
- if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
- maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
-
- if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
- maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
-
- // Add extents to the real base BB and return
- CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
- m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
-
- return finalBox;
+ return box;
}
CBox CWindow::getWindowMainSurfaceBox() {
@@ -318,7 +308,7 @@ void CWindow::destroyToplevelHandle() {
}
void CWindow::updateToplevel() {
- updateSurfaceOutputs();
+ updateSurfaceScaleTransformDetails();
if (!m_phForeignToplevel)
return;
@@ -345,8 +335,8 @@ void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
wlr_surface_send_leave(pSurface, OUTPUT);
}
-void CWindow::updateSurfaceOutputs() {
- if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden)
+void CWindow::updateSurfaceScaleTransformDetails() {
+ if (!m_bIsMapped || m_bHidden)
return;
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
@@ -355,16 +345,23 @@ void CWindow::updateSurfaceOutputs() {
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
- if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
- wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
+ if (PNEWMONITOR != PLASTMONITOR) {
+ if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
+ wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
- wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
+ wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
+ }
wlr_surface_for_each_surface(
m_pWLSurface.wlr(),
[](wlr_surface* surf, int x, int y, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
- g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
+
+ const auto PSURFACE = CWLSurface::surfaceFromWlr(surf);
+ if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
+ return;
+
+ g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
},
this);
@@ -374,7 +371,7 @@ void CWindow::moveToWorkspace(int workspaceID) {
if (m_iWorkspaceID == workspaceID)
return;
- static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
+ static auto* const PCLOSEONLASTSPECIAL = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty");
const int OLDWORKSPACE = m_iWorkspaceID;
@@ -397,7 +394,7 @@ void CWindow::moveToWorkspace(int workspaceID) {
// update xwayland coords
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec());
- 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);
if (PWS) {
@@ -440,7 +437,7 @@ void unregisterVar(void* ptr) {
}
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)
g_pCompositor->m_pLastWindow = nullptr;
@@ -462,7 +459,7 @@ void CWindow::onUnmap() {
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);
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
PMONITOR->setSpecialWorkspace(nullptr);
@@ -511,6 +508,14 @@ void CWindow::onMap() {
"CWindow");
m_vReportedSize = m_vPendingReportedSize;
+
+ for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) {
+ if (ctrl->pWlrHint->surface != m_pWLSurface.wlr())
+ continue;
+
+ m_bTearingHint = ctrl->pWlrHint->current;
+ break;
+ }
}
void CWindow::onBorderAngleAnimEnd(void* ptr) {
@@ -625,23 +630,22 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false;
- } else if (token.contains("deg")) {
+ } else if (token.contains("deg"))
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));
- } else {
+ else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
- }
}
- // Includes sanity checks for the number of colors in each gradient
- if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10) {
+ // Includes sanity checks for the number of colors in each gradient
+ if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
- } else if (activeBorderGradient.m_vColors.empty()) {
+ else if (activeBorderGradient.m_vColors.empty())
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;
- } else {
+ else {
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient;
}
@@ -1019,19 +1023,21 @@ bool CWindow::opaque() {
}
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;
}
void CWindow::updateSpecialRenderData() {
- const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
- const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
- bool border = true;
+ const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
+ const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
+ bool border = true;
- if (m_bIsFloating && g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue == 1)
+ static auto* const* PNOBORDERONFLOATING = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:no_border_on_floating");
+
+ if (m_bIsFloating && **PNOBORDERONFLOATING == 1)
border = false;
m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(border);
@@ -1051,16 +1057,18 @@ int CWindow::getRealBorderSize() {
if (m_sSpecialRenderData.borderSize.toUnderlying() != -1)
return m_sSpecialRenderData.borderSize.toUnderlying();
- return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
+ static auto* const* PBORDERSIZE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("general:border_size");
+
+ return **PBORDERSIZE;
}
bool CWindow::canBeTorn() {
- return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
+ return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint);
}
bool CWindow::shouldSendFullscreenState() {
const auto MODE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID)->m_efFullscreenMode;
- return m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL));
+ return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL)));
}
void CWindow::setSuspended(bool suspend) {
diff --git a/src/Window.hpp b/src/Window.hpp
index 93d7f203..f8ba4180 100644
--- a/src/Window.hpp
+++ b/src/Window.hpp
@@ -30,6 +30,24 @@ enum eGroupRules {
GROUP_OVERRIDE = 1 << 6, // Override other rules
};
+enum eGetWindowProperties {
+ WINDOW_ONLY = 0,
+ RESERVED_EXTENTS = 1 << 0,
+ INPUT_EXTENTS = 1 << 1,
+ FULL_EXTENTS = 1 << 2,
+ FLOATING_ONLY = 1 << 3,
+ ALLOW_FLOATING = 1 << 4,
+ USE_PROP_TILED = 1 << 5,
+};
+
+enum eSuppressEvents {
+ SUPPRESS_NONE = 0,
+ SUPPRESS_FULLSCREEN = 1 << 0,
+ SUPPRESS_MAXIMIZE = 1 << 1,
+ SUPPRESS_ACTIVATE = 1 << 2,
+ SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
+};
+
class IWindowTransformer;
template
@@ -133,6 +151,7 @@ struct SWindowAdditionalConfigData {
CWindowOverridableVar forceNoBorder = false;
CWindowOverridableVar forceNoShadow = false;
CWindowOverridableVar forceNoDim = false;
+ CWindowOverridableVar noFocus = false;
CWindowOverridableVar windowDanceCompat = false;
CWindowOverridableVar noMaxSize = false;
CWindowOverridableVar dimAround = false;
@@ -221,16 +240,17 @@ class CWindow {
bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(0, 0);
- bool m_bFirstMap = false; // for layouts
- bool m_bIsFloating = false;
- bool m_bDraggingTiled = false; // for dragging around tiled windows
- bool m_bIsFullscreen = false;
- bool m_bWasMaximized = false;
- uint64_t m_iMonitorID = -1;
- std::string m_szTitle = "";
- std::string m_szInitialTitle = "";
- std::string m_szInitialClass = "";
- int m_iWorkspaceID = -1;
+ bool m_bFirstMap = false; // for layouts
+ bool m_bIsFloating = false;
+ bool m_bDraggingTiled = false; // for dragging around tiled windows
+ bool m_bIsFullscreen = false;
+ bool m_bDontSendFullscreen = false;
+ bool m_bWasMaximized = false;
+ uint64_t m_iMonitorID = -1;
+ std::string m_szTitle = "";
+ std::string m_szInitialTitle = "";
+ std::string m_szInitialClass = "";
+ int m_iWorkspaceID = -1;
bool m_bIsMapped = false;
@@ -250,13 +270,13 @@ class CWindow {
//
// For nofocus
- bool m_bNoFocus = false;
bool m_bNoInitialFocus = false;
// Fullscreen and Maximize
- bool m_bWantsInitialFullscreen = false;
- bool m_bNoFullscreenRequest = false;
- bool m_bNoMaximizeRequest = false;
+ bool m_bWantsInitialFullscreen = false;
+
+ // bitfield eSuppressEvents
+ uint64_t m_eSuppressedEvents = SUPPRESS_NONE;
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
@@ -342,7 +362,7 @@ class CWindow {
// methods
CBox getFullWindowBoundingBox();
SWindowDecorationExtents getFullWindowExtents();
- CBox getWindowInputBox();
+ CBox getWindowBoxUnified(uint64_t props);
CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr deco);
@@ -356,7 +376,7 @@ class CWindow {
void createToplevelHandle();
void destroyToplevelHandle();
void updateToplevel();
- void updateSurfaceOutputs();
+ void updateSurfaceScaleTransformDetails();
void moveToWorkspace(int);
CWindow* X11TransientFor();
void onUnmap();
diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp
index 14b5e51d..accc92ab 100644
--- a/src/config/ConfigDataValues.hpp
+++ b/src/config/ConfigDataValues.hpp
@@ -1,10 +1,12 @@
#pragma once
#include "../defines.hpp"
+#include "../helpers/VarList.hpp"
#include
enum eConfigValueDataTypes {
- CVD_TYPE_INVALID = -1,
- CVD_TYPE_GRADIENT = 0
+ CVD_TYPE_INVALID = -1,
+ CVD_TYPE_GRADIENT = 0,
+ CVD_TYPE_CSS_VALUE = 1
};
class ICustomConfigValueData {
@@ -50,3 +52,55 @@ class CGradientValueData : public ICustomConfigValueData {
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;
+ }
+};
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index ee198ded..5cb18e0f 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -2,6 +2,8 @@
#include "../managers/KeybindManager.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
+#include "config/ConfigDataValues.hpp"
+#include "helpers/VarList.hpp"
#include
#include
@@ -15,35 +17,575 @@
#include
#include
-extern "C" char** environ;
+extern "C" char** environ;
+
+static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** data) {
+ std::string V = VALUE;
+
+ if (!*data)
+ *data = new CGradientValueData();
+
+ const auto DATA = reinterpret_cast(*data);
+
+ CVarList varlist(V, 0, ' ');
+ DATA->m_vColors.clear();
+
+ std::string parseError = "";
+
+ for (auto& var : varlist) {
+ if (var.find("deg") != std::string::npos) {
+ // last arg
+ try {
+ DATA->m_fAngle = std::stoi(var.substr(0, var.find("deg"))) * (PI / 180.0); // radians
+ } catch (...) {
+ Debug::log(WARN, "Error parsing gradient {}", V);
+ parseError = "Error parsing gradient " + V;
+ }
+
+ break;
+ }
+
+ if (DATA->m_vColors.size() >= 10) {
+ Debug::log(WARN, "Error parsing gradient {}: max colors is 10.", V);
+ parseError = "Error parsing gradient " + V + ": max colors is 10.";
+ break;
+ }
+
+ try {
+ DATA->m_vColors.push_back(CColor(configStringToInt(var)));
+ } catch (std::exception& e) {
+ Debug::log(WARN, "Error parsing gradient {}", V);
+ parseError = "Error parsing gradient " + V + ": " + e.what();
+ }
+ }
+
+ if (DATA->m_vColors.size() == 0) {
+ Debug::log(WARN, "Error parsing gradient {}", V);
+ parseError = "Error parsing gradient " + V + ": No colors?";
+
+ DATA->m_vColors.push_back(0); // transparent
+ }
+
+ Hyprlang::CParseResult result;
+ if (!parseError.empty())
+ result.setError(parseError.c_str());
+
+ return result;
+}
+
+static void configHandleGradientDestroy(void** data) {
+ if (*data)
+ delete reinterpret_cast(*data);
+}
+
+static Hyprlang::CParseResult configHandleGapSet(const char* VALUE, void** data) {
+ std::string V = VALUE;
+
+ if (!*data)
+ *data = new CCssGapData();
+
+ const auto DATA = reinterpret_cast(*data);
+ CVarList varlist(V);
+ Hyprlang::CParseResult result;
+
+ try {
+ DATA->parseGapData(varlist);
+ } catch (...) {
+ std::string parseError = "Error parsing gaps " + V;
+ result.setError(parseError.c_str());
+ }
+
+ return result;
+}
+
+static void configHandleGapDestroy(void** data) {
+ if (*data)
+ delete reinterpret_cast(*data);
+}
+
+static Hyprlang::CParseResult handleRawExec(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleRawExec(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleExecOnce(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleExecOnce(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleMonitor(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleMonitor(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleBezier(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleBezier(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleAnimation(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleAnimation(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleBind(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleBind(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleUnbind(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleUnbind(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleWindowRule(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleWindowRule(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleLayerRule(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleLayerRule(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleWindowRuleV2(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleWindowRuleV2(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleBlurLS(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleBlurLS(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleWorkspaceRules(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleWorkspaceRules(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleSubmap(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleSubmap(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleSource(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleSource(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handleEnv(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handleEnv(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
+
+static Hyprlang::CParseResult handlePlugin(const char* c, const char* v) {
+ const std::string VALUE = v;
+ const std::string COMMAND = c;
+
+ const auto RESULT = g_pConfigManager->handlePlugin(COMMAND, VALUE);
+
+ Hyprlang::CParseResult result;
+ if (RESULT.has_value())
+ result.setError(RESULT.value().c_str());
+ return result;
+}
CConfigManager::CConfigManager() {
- configValues["general:col.active_border"].data = std::make_shared(0xffffffff);
- configValues["general:col.inactive_border"].data = std::make_shared(0xff444444);
- configValues["general:col.nogroup_border"].data = std::make_shared(0xffffaaff);
- configValues["general:col.nogroup_border_active"].data = std::make_shared(0xffff00ff);
+ const auto ERR = verifyConfigExists();
- configValues["group:col.border_active"].data = std::make_shared(0x66ffff00);
- configValues["group:col.border_inactive"].data = std::make_shared(0x66777700);
- configValues["group:col.border_locked_active"].data = std::make_shared(0x66ff5500);
- configValues["group:col.border_locked_inactive"].data = std::make_shared(0x66775500);
+ configPaths.emplace_back(getMainConfigPath());
+ m_pConfig = std::make_unique(configPaths.begin()->c_str(), Hyprlang::SConfigOptions{.throwAllErrors = true, .allowMissingConfig = true});
- configValues["group:groupbar:col.active"].data = std::make_shared(0x66ffff00);
- configValues["group:groupbar:col.inactive"].data = std::make_shared(0x66777700);
- configValues["group:groupbar:col.locked_active"].data = std::make_shared(0x66ff5500);
- configValues["group:groupbar:col.locked_inactive"].data = std::make_shared(0x66775500);
+ m_pConfig->addConfigValue("general:sensitivity", {1.0f});
+ m_pConfig->addConfigValue("general:apply_sens_to_raw", {0L});
+ m_pConfig->addConfigValue("general:border_size", {1L});
+ m_pConfig->addConfigValue("general:no_border_on_floating", {0L});
+ m_pConfig->addConfigValue("general:border_part_of_window", {1L});
+ m_pConfig->addConfigValue("general:gaps_in", Hyprlang::CConfigCustomValueType{configHandleGapSet, configHandleGapDestroy, "5"});
+ m_pConfig->addConfigValue("general:gaps_out", Hyprlang::CConfigCustomValueType{configHandleGapSet, configHandleGapDestroy, "20"});
+ m_pConfig->addConfigValue("general:gaps_workspaces", {0L});
+ m_pConfig->addConfigValue("general:cursor_inactive_timeout", {0L});
+ m_pConfig->addConfigValue("general:no_cursor_warps", {0L});
+ m_pConfig->addConfigValue("general:no_focus_fallback", {0L});
+ m_pConfig->addConfigValue("general:resize_on_border", {0L});
+ m_pConfig->addConfigValue("general:extend_border_grab_area", {15L});
+ m_pConfig->addConfigValue("general:hover_icon_on_border", {1L});
+ m_pConfig->addConfigValue("general:layout", {"dwindle"});
+ m_pConfig->addConfigValue("general:allow_tearing", {0L});
+
+ m_pConfig->addConfigValue("misc:disable_hyprland_logo", {0L});
+ m_pConfig->addConfigValue("misc:disable_splash_rendering", {0L});
+ m_pConfig->addConfigValue("misc:col.splash", {0x55ffffffL});
+ m_pConfig->addConfigValue("misc:splash_font_family", {"Sans"});
+ m_pConfig->addConfigValue("misc:force_default_wallpaper", {-1L});
+ m_pConfig->addConfigValue("misc:vfr", {1L});
+ m_pConfig->addConfigValue("misc:vrr", {0L});
+ m_pConfig->addConfigValue("misc:mouse_move_enables_dpms", {0L});
+ m_pConfig->addConfigValue("misc:key_press_enables_dpms", {0L});
+ m_pConfig->addConfigValue("misc:always_follow_on_dnd", {1L});
+ m_pConfig->addConfigValue("misc:layers_hog_keyboard_focus", {1L});
+ m_pConfig->addConfigValue("misc:animate_manual_resizes", {0L});
+ m_pConfig->addConfigValue("misc:animate_mouse_windowdragging", {0L});
+ m_pConfig->addConfigValue("misc:disable_autoreload", {0L});
+ m_pConfig->addConfigValue("misc:enable_swallow", {0L});
+ m_pConfig->addConfigValue("misc:swallow_regex", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("misc:swallow_exception_regex", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("misc:focus_on_activate", {0L});
+ m_pConfig->addConfigValue("misc:no_direct_scanout", {1L});
+ m_pConfig->addConfigValue("misc:hide_cursor_on_touch", {1L});
+ m_pConfig->addConfigValue("misc:mouse_move_focuses_monitor", {1L});
+ m_pConfig->addConfigValue("misc:render_ahead_of_time", {0L});
+ m_pConfig->addConfigValue("misc:render_ahead_safezone", {1L});
+ m_pConfig->addConfigValue("misc:cursor_zoom_factor", {1.f});
+ m_pConfig->addConfigValue("misc:cursor_zoom_rigid", {0L});
+ m_pConfig->addConfigValue("misc:allow_session_lock_restore", {0L});
+ m_pConfig->addConfigValue("misc:close_special_on_empty", {1L});
+ m_pConfig->addConfigValue("misc:background_color", {0xff111111L});
+ m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", {0L});
+
+ m_pConfig->addConfigValue("group:insert_after_current", {1L});
+ m_pConfig->addConfigValue("group:focus_removed_window", {1L});
+ m_pConfig->addConfigValue("group:groupbar:enabled", {1L});
+ m_pConfig->addConfigValue("group:groupbar:font_family", {"Sans"});
+ m_pConfig->addConfigValue("group:groupbar:font_size", {8L});
+ m_pConfig->addConfigValue("group:groupbar:gradients", {1L});
+ m_pConfig->addConfigValue("group:groupbar:height", {14L});
+ m_pConfig->addConfigValue("group:groupbar:priority", {3L});
+ m_pConfig->addConfigValue("group:groupbar:render_titles", {1L});
+ m_pConfig->addConfigValue("group:groupbar:scrolling", {1L});
+ m_pConfig->addConfigValue("group:groupbar:text_color", {0xffffffffL});
+
+ m_pConfig->addConfigValue("debug:int", {0L});
+ m_pConfig->addConfigValue("debug:log_damage", {0L});
+ m_pConfig->addConfigValue("debug:overlay", {0L});
+ m_pConfig->addConfigValue("debug:damage_blink", {0L});
+ m_pConfig->addConfigValue("debug:disable_logs", {1L});
+ m_pConfig->addConfigValue("debug:disable_time", {1L});
+ m_pConfig->addConfigValue("debug:enable_stdout_logs", {0L});
+ m_pConfig->addConfigValue("debug:damage_tracking", {(Hyprlang::INT)DAMAGE_TRACKING_FULL});
+ m_pConfig->addConfigValue("debug:manual_crash", {0L});
+ m_pConfig->addConfigValue("debug:suppress_errors", {0L});
+ m_pConfig->addConfigValue("debug:watchdog_timeout", {5L});
+ m_pConfig->addConfigValue("debug:disable_scale_checks", {0L});
+
+ m_pConfig->addConfigValue("decoration:rounding", {0L});
+ m_pConfig->addConfigValue("decoration:blur:enabled", {1L});
+ m_pConfig->addConfigValue("decoration:blur:size", {8L});
+ m_pConfig->addConfigValue("decoration:blur:passes", {1L});
+ m_pConfig->addConfigValue("decoration:blur:ignore_opacity", {0L});
+ m_pConfig->addConfigValue("decoration:blur:new_optimizations", {1L});
+ m_pConfig->addConfigValue("decoration:blur:xray", {0L});
+ m_pConfig->addConfigValue("decoration:blur:contrast", {0.8916F});
+ m_pConfig->addConfigValue("decoration:blur:brightness", {1.0F});
+ m_pConfig->addConfigValue("decoration:blur:vibrancy", {0.1696F});
+ m_pConfig->addConfigValue("decoration:blur:vibrancy_darkness", {0.0F});
+ m_pConfig->addConfigValue("decoration:blur:noise", {0.0117F});
+ m_pConfig->addConfigValue("decoration:blur:special", {0L});
+ m_pConfig->addConfigValue("decoration:blur:popups", {0L});
+ m_pConfig->addConfigValue("decoration:blur:popups_ignorealpha", {0.2F});
+ m_pConfig->addConfigValue("decoration:active_opacity", {1.F});
+ m_pConfig->addConfigValue("decoration:inactive_opacity", {1.F});
+ m_pConfig->addConfigValue("decoration:fullscreen_opacity", {1.F});
+ m_pConfig->addConfigValue("decoration:no_blur_on_oversized", {0L});
+ m_pConfig->addConfigValue("decoration:drop_shadow", {1L});
+ m_pConfig->addConfigValue("decoration:shadow_range", {4L});
+ m_pConfig->addConfigValue("decoration:shadow_render_power", {3L});
+ m_pConfig->addConfigValue("decoration:shadow_ignore_window", {1L});
+ m_pConfig->addConfigValue("decoration:shadow_offset", Hyprlang::VEC2{0, 0});
+ m_pConfig->addConfigValue("decoration:shadow_scale", {1.f});
+ m_pConfig->addConfigValue("decoration:col.shadow", {0xee1a1a1aL});
+ m_pConfig->addConfigValue("decoration:col.shadow_inactive", {(Hyprlang::INT)INT_MAX});
+ m_pConfig->addConfigValue("decoration:dim_inactive", {0L});
+ m_pConfig->addConfigValue("decoration:dim_strength", {0.5f});
+ m_pConfig->addConfigValue("decoration:dim_special", {0.2f});
+ m_pConfig->addConfigValue("decoration:dim_around", {0.4f});
+ m_pConfig->addConfigValue("decoration:screen_shader", {STRVAL_EMPTY});
+
+ m_pConfig->addConfigValue("dwindle:pseudotile", {0L});
+ m_pConfig->addConfigValue("dwindle:force_split", {0L});
+ m_pConfig->addConfigValue("dwindle:permanent_direction_override", {0L});
+ m_pConfig->addConfigValue("dwindle:preserve_split", {0L});
+ m_pConfig->addConfigValue("dwindle:special_scale_factor", {1.f});
+ m_pConfig->addConfigValue("dwindle:split_width_multiplier", {1.0f});
+ m_pConfig->addConfigValue("dwindle:no_gaps_when_only", {0L});
+ m_pConfig->addConfigValue("dwindle:use_active_for_splits", {1L});
+ m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f});
+ m_pConfig->addConfigValue("dwindle:smart_split", {0L});
+ m_pConfig->addConfigValue("dwindle:smart_resizing", {1L});
+
+ m_pConfig->addConfigValue("master:special_scale_factor", {1.f});
+ m_pConfig->addConfigValue("master:mfact", {0.55f});
+ m_pConfig->addConfigValue("master:new_is_master", {1L});
+ m_pConfig->addConfigValue("master:always_center_master", {0L});
+ m_pConfig->addConfigValue("master:new_on_top", {0L});
+ m_pConfig->addConfigValue("master:no_gaps_when_only", {0L});
+ m_pConfig->addConfigValue("master:orientation", {"left"});
+ m_pConfig->addConfigValue("master:inherit_fullscreen", {1L});
+ m_pConfig->addConfigValue("master:allow_small_split", {0L});
+ m_pConfig->addConfigValue("master:smart_resizing", {1L});
+ m_pConfig->addConfigValue("master:drop_at_cursor", {1L});
+
+ m_pConfig->addConfigValue("animations:enabled", {1L});
+ m_pConfig->addConfigValue("animations:first_launch_animation", {1L});
+
+ m_pConfig->addConfigValue("input:follow_mouse", {1L});
+ m_pConfig->addConfigValue("input:mouse_refocus", {1L});
+ m_pConfig->addConfigValue("input:special_fallthrough", {0L});
+ m_pConfig->addConfigValue("input:sensitivity", {0.f});
+ m_pConfig->addConfigValue("input:accel_profile", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:kb_file", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:kb_layout", {"us"});
+ m_pConfig->addConfigValue("input:kb_variant", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:kb_options", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:kb_rules", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:kb_model", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:repeat_rate", {25L});
+ m_pConfig->addConfigValue("input:repeat_delay", {600L});
+ m_pConfig->addConfigValue("input:natural_scroll", {0L});
+ m_pConfig->addConfigValue("input:numlock_by_default", {0L});
+ m_pConfig->addConfigValue("input:resolve_binds_by_sym", {0L});
+ m_pConfig->addConfigValue("input:force_no_accel", {0L});
+ m_pConfig->addConfigValue("input:float_switch_override_focus", {1L});
+ m_pConfig->addConfigValue("input:left_handed", {0L});
+ m_pConfig->addConfigValue("input:scroll_method", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:scroll_button", {0L});
+ m_pConfig->addConfigValue("input:scroll_button_lock", {0L});
+ m_pConfig->addConfigValue("input:scroll_points", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:touchpad:natural_scroll", {0L});
+ m_pConfig->addConfigValue("input:touchpad:disable_while_typing", {1L});
+ m_pConfig->addConfigValue("input:touchpad:clickfinger_behavior", {0L});
+ m_pConfig->addConfigValue("input:touchpad:tap_button_map", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:touchpad:middle_button_emulation", {0L});
+ m_pConfig->addConfigValue("input:touchpad:tap-to-click", {1L});
+ m_pConfig->addConfigValue("input:touchpad:tap-and-drag", {1L});
+ m_pConfig->addConfigValue("input:touchpad:drag_lock", {0L});
+ m_pConfig->addConfigValue("input:touchpad:scroll_factor", {1.f});
+ m_pConfig->addConfigValue("input:touchdevice:transform", {0L});
+ m_pConfig->addConfigValue("input:touchdevice:output", {"[[Auto]]"});
+ m_pConfig->addConfigValue("input:touchdevice:enabled", {1L});
+ m_pConfig->addConfigValue("input:tablet:transform", {0L});
+ m_pConfig->addConfigValue("input:tablet:output", {STRVAL_EMPTY});
+ m_pConfig->addConfigValue("input:tablet:region_position", Hyprlang::VEC2{0, 0});
+ m_pConfig->addConfigValue("input:tablet:region_size", Hyprlang::VEC2{0, 0});
+ m_pConfig->addConfigValue("input:tablet:relative_input", {0L});
+
+ m_pConfig->addConfigValue("binds:pass_mouse_when_bound", {0L});
+ m_pConfig->addConfigValue("binds:scroll_event_delay", {300L});
+ m_pConfig->addConfigValue("binds:workspace_back_and_forth", {0L});
+ m_pConfig->addConfigValue("binds:allow_workspace_cycles", {0L});
+ m_pConfig->addConfigValue("binds:workspace_center_on", {1L});
+ m_pConfig->addConfigValue("binds:focus_preferred_method", {0L});
+ m_pConfig->addConfigValue("binds:ignore_group_lock", {0L});
+ m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", {1L});
+
+ m_pConfig->addConfigValue("gestures:workspace_swipe", {0L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_fingers", {3L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_distance", {300L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_invert", {1L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_min_speed_to_force", {30L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_cancel_ratio", {0.5f});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_create_new", {1L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_direction_lock", {1L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_direction_lock_threshold", {10L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_forever", {0L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_numbered", {0L});
+ m_pConfig->addConfigValue("gestures:workspace_swipe_use_r", {0L});
+
+ m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", {1L});
+ m_pConfig->addConfigValue("xwayland:force_zero_scaling", {0L});
+
+ m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", {1L});
+ m_pConfig->addConfigValue("opengl:force_introspection", {2L});
+
+ m_pConfig->addConfigValue("autogenerated", {0L});
+
+ m_pConfig->addConfigValue("general:col.active_border", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xffffffff"});
+ m_pConfig->addConfigValue("general:col.inactive_border", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xff444444"});
+ m_pConfig->addConfigValue("general:col.nogroup_border", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xffffaaff"});
+ m_pConfig->addConfigValue("general:col.nogroup_border_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xffff00ff"});
+
+ m_pConfig->addConfigValue("group:col.border_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ffff00"});
+ m_pConfig->addConfigValue("group:col.border_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66777700"});
+ m_pConfig->addConfigValue("group:col.border_locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"});
+ m_pConfig->addConfigValue("group:col.border_locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"});
+
+ m_pConfig->addConfigValue("group:groupbar:col.active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ffff00"});
+ m_pConfig->addConfigValue("group:groupbar:col.inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66777700"});
+ m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"});
+ m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"});
+
+ // devices
+ m_pConfig->addSpecialCategory("device", {"name"});
+ m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F});
+ m_pConfig->addSpecialConfigValue("device", "accel_profile", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "kb_file", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "kb_layout", {"us"});
+ m_pConfig->addSpecialConfigValue("device", "kb_variant", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "kb_options", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "kb_rules", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "kb_model", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "repeat_rate", {25L});
+ m_pConfig->addSpecialConfigValue("device", "repeat_delay", {600L});
+ m_pConfig->addSpecialConfigValue("device", "natural_scroll", {0L});
+ m_pConfig->addSpecialConfigValue("device", "tap_button_map", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "numlock_by_default", {0L});
+ m_pConfig->addSpecialConfigValue("device", "resolve_binds_by_sym", {0L});
+ m_pConfig->addSpecialConfigValue("device", "disable_while_typing", {1L});
+ m_pConfig->addSpecialConfigValue("device", "clickfinger_behavior", {0L});
+ m_pConfig->addSpecialConfigValue("device", "middle_button_emulation", {0L});
+ m_pConfig->addSpecialConfigValue("device", "tap-to-click", {1L});
+ m_pConfig->addSpecialConfigValue("device", "tap-and-drag", {1L});
+ m_pConfig->addSpecialConfigValue("device", "drag_lock", {0L});
+ m_pConfig->addSpecialConfigValue("device", "left_handed", {0L});
+ m_pConfig->addSpecialConfigValue("device", "scroll_method", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "scroll_button", {0L});
+ m_pConfig->addSpecialConfigValue("device", "scroll_button_lock", {0L});
+ m_pConfig->addSpecialConfigValue("device", "scroll_points", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "transform", {0L});
+ m_pConfig->addSpecialConfigValue("device", "output", {STRVAL_EMPTY});
+ m_pConfig->addSpecialConfigValue("device", "enabled", {1L}); // only for mice, touchpads, and touchdevices
+ m_pConfig->addSpecialConfigValue("device", "region_position", Hyprlang::VEC2{0, 0}); // only for tablets
+ m_pConfig->addSpecialConfigValue("device", "region_size", Hyprlang::VEC2{0, 0}); // only for tablets
+ m_pConfig->addSpecialConfigValue("device", "relative_input", {0L}); // only for tablets
+
+ // keywords
+ m_pConfig->registerHandler(&::handleRawExec, "exec", {false});
+ m_pConfig->registerHandler(&::handleExecOnce, "exec-once", {false});
+ m_pConfig->registerHandler(&::handleMonitor, "monitor", {false});
+ m_pConfig->registerHandler(&::handleBind, "bind", {true});
+ m_pConfig->registerHandler(&::handleUnbind, "unbind", {false});
+ m_pConfig->registerHandler(&::handleWorkspaceRules, "workspace", {false});
+ m_pConfig->registerHandler(&::handleWindowRule, "windowrule", {false});
+ m_pConfig->registerHandler(&::handleLayerRule, "layerrule", {false});
+ m_pConfig->registerHandler(&::handleWindowRuleV2, "windowrulev2", {false});
+ m_pConfig->registerHandler(&::handleBezier, "bezier", {false});
+ m_pConfig->registerHandler(&::handleAnimation, "animation", {false});
+ m_pConfig->registerHandler(&::handleSource, "source", {false});
+ m_pConfig->registerHandler(&::handleSubmap, "submap", {false});
+ m_pConfig->registerHandler(&::handleBlurLS, "blurls", {false});
+ m_pConfig->registerHandler(&::handlePlugin, "plugin", {false});
+ m_pConfig->registerHandler(&::handleEnv, "env", {true});
+
+ // pluginza
+ m_pConfig->addSpecialCategory("plugin", {nullptr, true});
+
+ m_pConfig->commence();
Debug::log(LOG, "NOTE: further logs to stdout / logfile are disabled by default. Use debug:disable_logs and debug:enable_stdout_logs to override this.");
- setDefaultVars();
setDefaultAnimationVars();
+ resetHLConfig();
- configPaths.emplace_back(getMainConfigPath());
+ Debug::disableLogs = reinterpret_cast(m_pConfig->getConfigValuePtr("debug:disable_logs")->getDataStaticPtr());
+ Debug::disableTime = reinterpret_cast(m_pConfig->getConfigValuePtr("debug:disable_time")->getDataStaticPtr());
- Debug::disableLogs = &configValues["debug:disable_logs"].intValue;
- Debug::disableTime = &configValues["debug:disable_time"].intValue;
-
- populateEnvironment();
+ if (ERR.has_value())
+ g_pHyprError->queueCreate(ERR.value(), CColor{1.0, 0.1, 0.1, 1.0});
}
std::string CConfigManager::getConfigDir() {
@@ -62,266 +604,13 @@ std::string CConfigManager::getMainConfigPath() {
return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf");
}
-void CConfigManager::populateEnvironment() {
- environmentVariables.clear();
- for (char** env = environ; *env; ++env) {
- const std::string ENVVAR = *env;
- const auto VARIABLE = ENVVAR.substr(0, ENVVAR.find_first_of('='));
- const auto VALUE = ENVVAR.substr(ENVVAR.find_first_of('=') + 1);
- environmentVariables.emplace_back(std::make_pair<>(VARIABLE, VALUE));
- }
-
- std::sort(environmentVariables.begin(), environmentVariables.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
-}
-
-void CConfigManager::setDefaultVars() {
- configValues["general:max_fps"].intValue = 60;
- configValues["general:sensitivity"].floatValue = 1.0f;
- configValues["general:apply_sens_to_raw"].intValue = 0;
- configValues["general:border_size"].intValue = 1;
- configValues["general:no_border_on_floating"].intValue = 0;
- configValues["general:border_part_of_window"].intValue = 1;
- configValues["general:gaps_in"].intValue = 5;
- configValues["general:gaps_out"].intValue = 20;
- configValues["general:gaps_workspaces"].intValue = 0;
- ((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff);
- ((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
- ((CGradientValueData*)configValues["general:col.nogroup_border"].data.get())->reset(0xff444444);
- ((CGradientValueData*)configValues["general:col.nogroup_border_active"].data.get())->reset(0xffff00ff);
- configValues["general:cursor_inactive_timeout"].intValue = 0;
- configValues["general:no_cursor_warps"].intValue = 0;
- configValues["general:no_focus_fallback"].intValue = 0;
- configValues["general:resize_on_border"].intValue = 0;
- configValues["general:extend_border_grab_area"].intValue = 15;
- configValues["general:hover_icon_on_border"].intValue = 1;
- configValues["general:layout"].strValue = "dwindle";
- configValues["general:allow_tearing"].intValue = 0;
-
- configValues["misc:disable_hyprland_logo"].intValue = 0;
- configValues["misc:disable_splash_rendering"].intValue = 0;
- configValues["misc:force_hypr_chan"].intValue = 0;
- configValues["misc:force_default_wallpaper"].intValue = -1;
- configValues["misc:vfr"].intValue = 1;
- configValues["misc:vrr"].intValue = 0;
- configValues["misc:mouse_move_enables_dpms"].intValue = 0;
- configValues["misc:key_press_enables_dpms"].intValue = 0;
- configValues["misc:always_follow_on_dnd"].intValue = 1;
- configValues["misc:layers_hog_keyboard_focus"].intValue = 1;
- configValues["misc:animate_manual_resizes"].intValue = 0;
- configValues["misc:animate_mouse_windowdragging"].intValue = 0;
- configValues["misc:disable_autoreload"].intValue = 0;
- configValues["misc:enable_swallow"].intValue = 0;
- configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
- configValues["misc:swallow_exception_regex"].strValue = STRVAL_EMPTY;
- configValues["misc:focus_on_activate"].intValue = 0;
- configValues["misc:no_direct_scanout"].intValue = 1;
- configValues["misc:hide_cursor_on_touch"].intValue = 1;
- configValues["misc:mouse_move_focuses_monitor"].intValue = 1;
- configValues["misc:render_ahead_of_time"].intValue = 0;
- configValues["misc:render_ahead_safezone"].intValue = 1;
- configValues["misc:cursor_zoom_factor"].floatValue = 1.f;
- configValues["misc:cursor_zoom_rigid"].intValue = 0;
- configValues["misc:allow_session_lock_restore"].intValue = 0;
- configValues["misc:close_special_on_empty"].intValue = 1;
- configValues["misc:background_color"].intValue = 0xff111111;
- configValues["misc:new_window_takes_over_fullscreen"].intValue = 0;
-
- ((CGradientValueData*)configValues["group:col.border_active"].data.get())->reset(0x66ffff00);
- ((CGradientValueData*)configValues["group:col.border_inactive"].data.get())->reset(0x66777700);
- ((CGradientValueData*)configValues["group:col.border_locked_active"].data.get())->reset(0x66ff5500);
- ((CGradientValueData*)configValues["group:col.border_locked_inactive"].data.get())->reset(0x66775500);
-
- configValues["group:insert_after_current"].intValue = 1;
- configValues["group:focus_removed_window"].intValue = 1;
-
- configValues["group:groupbar:enabled"].intValue = 1;
- configValues["group:groupbar:font_family"].strValue = "Sans";
- configValues["group:groupbar:font_size"].intValue = 8;
- configValues["group:groupbar:gradients"].intValue = 1;
- configValues["group:groupbar:priority"].intValue = 3;
- configValues["group:groupbar:render_titles"].intValue = 1;
- configValues["group:groupbar:scrolling"].intValue = 1;
- configValues["group:groupbar:text_color"].intValue = 0xffffffff;
-
- ((CGradientValueData*)configValues["group:groupbar:col.active"].data.get())->reset(0x66ffff00);
- ((CGradientValueData*)configValues["group:groupbar:col.inactive"].data.get())->reset(0x66777700);
- ((CGradientValueData*)configValues["group:groupbar:col.locked_active"].data.get())->reset(0x66ff5500);
- ((CGradientValueData*)configValues["group:groupbar:col.locked_inactive"].data.get())->reset(0x66775500);
-
- configValues["debug:int"].intValue = 0;
- configValues["debug:log_damage"].intValue = 0;
- configValues["debug:overlay"].intValue = 0;
- configValues["debug:damage_blink"].intValue = 0;
- configValues["debug:disable_logs"].intValue = 1;
- configValues["debug:disable_time"].intValue = 1;
- configValues["debug:enable_stdout_logs"].intValue = 0;
- configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
- configValues["debug:manual_crash"].intValue = 0;
- configValues["debug:suppress_errors"].intValue = 0;
- configValues["debug:watchdog_timeout"].intValue = 5;
- configValues["debug:disable_scale_checks"].intValue = 0;
-
- configValues["decoration:rounding"].intValue = 0;
- configValues["decoration:blur:enabled"].intValue = 1;
- configValues["decoration:blur:size"].intValue = 8;
- configValues["decoration:blur:passes"].intValue = 1;
- configValues["decoration:blur:ignore_opacity"].intValue = 0;
- configValues["decoration:blur:new_optimizations"].intValue = 1;
- configValues["decoration:blur:xray"].intValue = 0;
- configValues["decoration:blur:contrast"].floatValue = 0.8916;
- configValues["decoration:blur:brightness"].floatValue = 1.0;
- configValues["decoration:blur:vibrancy"].floatValue = 0.1696;
- configValues["decoration:blur:vibrancy_darkness"].floatValue = 0.0;
- configValues["decoration:blur:noise"].floatValue = 0.0117;
- configValues["decoration:blur:special"].intValue = 0;
- configValues["decoration:blur:popups"].intValue = 0;
- configValues["decoration:blur:popups_ignorealpha"].floatValue = 0.2;
- configValues["decoration:active_opacity"].floatValue = 1;
- configValues["decoration:inactive_opacity"].floatValue = 1;
- configValues["decoration:fullscreen_opacity"].floatValue = 1;
- configValues["decoration:no_blur_on_oversized"].intValue = 0;
- configValues["decoration:drop_shadow"].intValue = 1;
- configValues["decoration:shadow_range"].intValue = 4;
- configValues["decoration:shadow_render_power"].intValue = 3;
- configValues["decoration:shadow_ignore_window"].intValue = 1;
- configValues["decoration:shadow_offset"].vecValue = Vector2D();
- configValues["decoration:shadow_scale"].floatValue = 1.f;
- configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
- configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
- configValues["decoration:dim_inactive"].intValue = 0;
- configValues["decoration:dim_strength"].floatValue = 0.5f;
- configValues["decoration:dim_special"].floatValue = 0.2f;
- configValues["decoration:dim_around"].floatValue = 0.4f;
- configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
-
- configValues["dwindle:pseudotile"].intValue = 0;
- configValues["dwindle:force_split"].intValue = 0;
- configValues["dwindle:permanent_direction_override"].intValue = 0;
- configValues["dwindle:preserve_split"].intValue = 0;
- configValues["dwindle:special_scale_factor"].floatValue = 1.f;
- configValues["dwindle:split_width_multiplier"].floatValue = 1.0f;
- configValues["dwindle:no_gaps_when_only"].intValue = 0;
- configValues["dwindle:use_active_for_splits"].intValue = 1;
- configValues["dwindle:default_split_ratio"].floatValue = 1.f;
- configValues["dwindle:smart_split"].intValue = 0;
- configValues["dwindle:smart_resizing"].intValue = 1;
-
- configValues["master:special_scale_factor"].floatValue = 1.f;
- configValues["master:mfact"].floatValue = 0.55f;
- configValues["master:new_is_master"].intValue = 1;
- configValues["master:always_center_master"].intValue = 0;
- configValues["master:new_on_top"].intValue = 0;
- configValues["master:no_gaps_when_only"].intValue = 0;
- configValues["master:orientation"].strValue = "left";
- configValues["master:inherit_fullscreen"].intValue = 1;
- configValues["master:allow_small_split"].intValue = 0;
- configValues["master:smart_resizing"].intValue = 1;
- configValues["master:drop_at_cursor"].intValue = 1;
-
- configValues["animations:enabled"].intValue = 1;
- configValues["animations:first_launch_animation"].intValue = 1;
-
- configValues["input:follow_mouse"].intValue = 1;
- configValues["input:mouse_refocus"].intValue = 1;
- configValues["input:sensitivity"].floatValue = 0.f;
- configValues["input:accel_profile"].strValue = STRVAL_EMPTY;
- configValues["input:kb_file"].strValue = STRVAL_EMPTY;
- configValues["input:kb_layout"].strValue = "us";
- configValues["input:kb_variant"].strValue = STRVAL_EMPTY;
- configValues["input:kb_options"].strValue = STRVAL_EMPTY;
- configValues["input:kb_rules"].strValue = STRVAL_EMPTY;
- configValues["input:kb_model"].strValue = STRVAL_EMPTY;
- configValues["input:repeat_rate"].intValue = 25;
- configValues["input:repeat_delay"].intValue = 600;
- configValues["input:natural_scroll"].intValue = 0;
- configValues["input:numlock_by_default"].intValue = 0;
- configValues["input:force_no_accel"].intValue = 0;
- configValues["input:float_switch_override_focus"].intValue = 1;
- configValues["input:left_handed"].intValue = 0;
- configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
- configValues["input:scroll_button"].intValue = 0;
- configValues["input:scroll_button_lock"].intValue = 0;
- configValues["input:scroll_points"].strValue = STRVAL_EMPTY;
- configValues["input:touchpad:natural_scroll"].intValue = 0;
- configValues["input:touchpad:disable_while_typing"].intValue = 1;
- configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
- configValues["input:touchpad:tap_button_map"].strValue = STRVAL_EMPTY;
- configValues["input:touchpad:middle_button_emulation"].intValue = 0;
- configValues["input:touchpad:tap-to-click"].intValue = 1;
- configValues["input:touchpad:tap-and-drag"].intValue = 1;
- configValues["input:touchpad:drag_lock"].intValue = 0;
- configValues["input:touchpad:scroll_factor"].floatValue = 1.f;
- configValues["input:touchdevice:transform"].intValue = 0;
- configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY;
- configValues["input:tablet:transform"].intValue = 0;
- configValues["input:tablet:output"].strValue = STRVAL_EMPTY;
- configValues["input:tablet:region_position"].vecValue = Vector2D();
- configValues["input:tablet:region_size"].vecValue = Vector2D();
- configValues["input:tablet:relative_input"].intValue = 0;
-
- configValues["binds:pass_mouse_when_bound"].intValue = 0;
- configValues["binds:scroll_event_delay"].intValue = 300;
- configValues["binds:workspace_back_and_forth"].intValue = 0;
- configValues["binds:allow_workspace_cycles"].intValue = 0;
- configValues["binds:workspace_center_on"].intValue = 1;
- configValues["binds:focus_preferred_method"].intValue = 0;
- configValues["binds:ignore_group_lock"].intValue = 0;
- configValues["binds:movefocus_cycles_fullscreen"].intValue = 1;
-
- configValues["gestures:workspace_swipe"].intValue = 0;
- configValues["gestures:workspace_swipe_fingers"].intValue = 3;
- configValues["gestures:workspace_swipe_distance"].intValue = 300;
- configValues["gestures:workspace_swipe_invert"].intValue = 1;
- configValues["gestures:workspace_swipe_min_speed_to_force"].intValue = 30;
- configValues["gestures:workspace_swipe_cancel_ratio"].floatValue = 0.5f;
- configValues["gestures:workspace_swipe_create_new"].intValue = 1;
- configValues["gestures:workspace_swipe_direction_lock"].intValue = 1;
- configValues["gestures:workspace_swipe_direction_lock_threshold"].intValue = 10;
- configValues["gestures:workspace_swipe_forever"].intValue = 0;
- configValues["gestures:workspace_swipe_numbered"].intValue = 0;
- configValues["gestures:workspace_swipe_use_r"].intValue = 0;
-
- configValues["xwayland:use_nearest_neighbor"].intValue = 1;
- configValues["xwayland:force_zero_scaling"].intValue = 0;
-
- configValues["opengl:nvidia_anti_flicker"].intValue = 1;
-
- configValues["autogenerated"].intValue = 0;
-}
-
-void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
- auto& cfgValues = deviceConfigs[dev];
-
- cfgValues["sensitivity"].floatValue = 0.f;
- cfgValues["accel_profile"].strValue = STRVAL_EMPTY;
- cfgValues["kb_file"].strValue = STRVAL_EMPTY;
- cfgValues["kb_layout"].strValue = "us";
- cfgValues["kb_variant"].strValue = STRVAL_EMPTY;
- cfgValues["kb_options"].strValue = STRVAL_EMPTY;
- cfgValues["kb_rules"].strValue = STRVAL_EMPTY;
- cfgValues["kb_model"].strValue = STRVAL_EMPTY;
- cfgValues["repeat_rate"].intValue = 25;
- cfgValues["repeat_delay"].intValue = 600;
- cfgValues["natural_scroll"].intValue = 0;
- cfgValues["tap_button_map"].strValue = STRVAL_EMPTY;
- cfgValues["numlock_by_default"].intValue = 0;
- cfgValues["disable_while_typing"].intValue = 1;
- cfgValues["clickfinger_behavior"].intValue = 0;
- cfgValues["middle_button_emulation"].intValue = 0;
- cfgValues["tap-to-click"].intValue = 1;
- cfgValues["tap-and-drag"].intValue = 1;
- cfgValues["drag_lock"].intValue = 0;
- cfgValues["left_handed"].intValue = 0;
- cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
- cfgValues["scroll_button"].intValue = 0;
- cfgValues["scroll_button_lock"].intValue = 0;
- cfgValues["scroll_points"].strValue = STRVAL_EMPTY;
- cfgValues["transform"].intValue = 0;
- cfgValues["output"].strValue = STRVAL_EMPTY;
- cfgValues["enabled"].intValue = 1; // only for mice / touchpads
- cfgValues["region_position"].vecValue = Vector2D(); // only for tablets
- cfgValues["region_size"].vecValue = Vector2D(); // only for tablets
- cfgValues["relative_input"].intValue = 0; // only for tablets
+void CConfigManager::reload() {
+ EMIT_HOOK_EVENT("preConfigReload", nullptr);
+ setDefaultAnimationVars();
+ resetHLConfig();
+ configCurrentPath = getMainConfigPath();
+ const auto ERR = m_pConfig->parse();
+ postConfigReload(ERR);
}
void CConfigManager::setDefaultAnimationVars() {
@@ -373,1276 +662,38 @@ void CConfigManager::setDefaultAnimationVars() {
CREATEANIMCFG("specialWorkspace", "workspaces");
}
-void CConfigManager::init() {
+std::optional CConfigManager::verifyConfigExists() {
+ std::string mainConfigPath = getMainConfigPath();
- loadConfigLoadVars();
+ if (g_pCompositor->explicitConfigPath.empty() && !std::filesystem::exists(mainConfigPath)) {
+ std::string configPath = std::filesystem::path(mainConfigPath).parent_path();
- const std::string CONFIGPATH = getMainConfigPath();
+ if (!std::filesystem::is_directory(configPath)) {
+ Debug::log(WARN, "Creating config home directory");
+ try {
+ std::filesystem::create_directories(configPath);
+ } catch (...) { return "Broken config file! (Could not create config directory)"; }
+ }
- struct stat fileStat;
- int err = stat(CONFIGPATH.c_str(), &fileStat);
- if (err != 0) {
- Debug::log(WARN, "Error at statting config, error {}", errno);
+ Debug::log(WARN, "No config file found; attempting to generate.");
+ std::ofstream ofs;
+ ofs.open(mainConfigPath, std::ios::trunc);
+ ofs << AUTOCONFIG;
+ ofs.close();
}
- configModifyTimes[CONFIGPATH] = fileStat.st_mtime;
+ if (!std::filesystem::exists(mainConfigPath))
+ return "broken config dir?";
- isFirstLaunch = false;
+ return {};
}
-void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) {
- if (!configValues.contains(COMMAND)) {
- if (!COMMAND.starts_with("device:") /* devices parsed later */ && !COMMAND.starts_with("plugin:") /* plugins parsed later */) {
- if (COMMAND[0] == '$') {
- // register a dynamic var
- Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE);
- configDynamicVars.emplace_back(std::make_pair<>(COMMAND.substr(1), VALUE));
-
- std::sort(configDynamicVars.begin(), configDynamicVars.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
- } else {
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
- }
-
- return;
- }
- }
-
- SConfigValue* CONFIGENTRY = nullptr;
-
- if (COMMAND.starts_with("device:")) {
- const auto DEVICE = COMMAND.substr(7).substr(0, COMMAND.find_last_of(':') - 7);
- const auto CONFIGVAR = COMMAND.substr(COMMAND.find_last_of(':') + 1);
-
- if (!deviceConfigExists(DEVICE))
- setDeviceDefaultVars(DEVICE);
-
- auto it = deviceConfigs.find(DEVICE);
-
- if (it->second.find(CONFIGVAR) == it->second.end()) {
- if (it->second.contains("touch_output") || it->second.contains("touch_transform")) {
- parseError = "touch_output and touch_transform have been changed to output and transform respectively";
- return;
- }
-
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
- return;
- }
-
- CONFIGENTRY = &it->second.at(CONFIGVAR);
- } else if (COMMAND.starts_with("plugin:")) {
- for (auto& [handle, pMap] : pluginConfigs) {
- auto it = std::find_if(pMap->begin(), pMap->end(), [&](const auto& other) { return other.first == COMMAND; });
- if (it == pMap->end()) {
- continue; // May be in another plugin
- }
-
- CONFIGENTRY = &it->second;
- }
-
- if (!CONFIGENTRY) {
- m_vFailedPluginConfigValues.emplace_back(std::make_pair<>(COMMAND, VALUE));
- return; // silent ignore
- }
- } else {
- CONFIGENTRY = &configValues.at(COMMAND);
- }
-
- CONFIGENTRY->set = true;
-
- if (CONFIGENTRY->intValue != -INT64_MAX) {
- try {
- CONFIGENTRY->intValue = configStringToInt(VALUE);
- } catch (std::exception& e) {
- Debug::log(WARN, "Error reading value of {}", COMMAND);
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
- }
- } else if (CONFIGENTRY->floatValue != -__FLT_MAX__) {
- try {
- CONFIGENTRY->floatValue = stof(VALUE);
- } catch (...) {
- Debug::log(WARN, "Error reading value of {}", COMMAND);
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
- }
- } else if (CONFIGENTRY->strValue != "") {
- try {
- CONFIGENTRY->strValue = VALUE;
- } catch (...) {
- Debug::log(WARN, "Error reading value of {}", COMMAND);
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
- }
- } else if (CONFIGENTRY->vecValue != Vector2D(-__FLT_MAX__, -__FLT_MAX__)) {
- try {
- if (const auto SPACEPOS = VALUE.find(' '); SPACEPOS != std::string::npos) {
- const auto X = VALUE.substr(0, SPACEPOS);
- const auto Y = VALUE.substr(SPACEPOS + 1);
-
- if (isNumber(X, true) && isNumber(Y, true)) {
- CONFIGENTRY->vecValue = Vector2D(std::stof(X), std::stof(Y));
- }
- } else {
- Debug::log(WARN, "Error reading value of {}", COMMAND);
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
- }
- } catch (...) {
- Debug::log(WARN, "Error reading value of {}", COMMAND);
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
- }
- } else if (CONFIGENTRY->data.get() != nullptr) {
-
- switch (CONFIGENTRY->data->getDataType()) {
- case CVD_TYPE_GRADIENT: {
-
- CVarList varlist(VALUE, 0, ' ');
-
- CGradientValueData* data = (CGradientValueData*)CONFIGENTRY->data.get();
- data->m_vColors.clear();
-
- for (auto& var : varlist) {
- if (var.find("deg") != std::string::npos) {
- // last arg
- try {
- data->m_fAngle = std::stoi(var.substr(0, var.find("deg"))) * (PI / 180.0); // radians
- } catch (...) {
- Debug::log(WARN, "Error reading value of {}", COMMAND);
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
- }
-
- break;
- }
-
- if (data->m_vColors.size() >= 10) {
- Debug::log(WARN, "Error reading value of {}", COMMAND);
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. Max colors in a gradient is 10.";
- break;
- }
-
- try {
- data->m_vColors.push_back(CColor(configStringToInt(var)));
- } catch (std::exception& e) {
- Debug::log(WARN, "Error reading value of {}", COMMAND);
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
- }
- }
-
- if (data->m_vColors.size() == 0) {
- Debug::log(WARN, "Error reading value of {}", COMMAND);
- parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. No colors provided.";
-
- data->m_vColors.push_back(0); // transparent
- }
-
- break;
- }
- default: {
- UNREACHABLE();
- }
- }
- }
-
- if (COMMAND == "decoration:screen_shader") {
- const auto PATH = absolutePath(VALUE, configCurrentPath);
-
- configPaths.push_back(PATH);
-
- struct stat fileStat;
- int err = stat(PATH.c_str(), &fileStat);
- if (err != 0) {
- Debug::log(WARN, "Error at ticking config at {}, error {}: {}", PATH, err, strerror(err));
- return;
- }
-
- configModifyTimes[PATH] = fileStat.st_mtime;
- }
-}
-
-void CConfigManager::handleRawExec(const std::string& command, const std::string& args) {
- // Exec in the background dont wait for it.
- g_pKeybindManager->spawn(args);
-}
-
-static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) {
- auto args = CVarList(modeline, 0, 's');
-
- auto keyword = args[0];
- std::transform(keyword.begin(), keyword.end(), keyword.begin(), ::tolower);
-
- if (keyword != "modeline")
- return false;
-
- if (args.size() < 10) {
- Debug::log(ERR, "modeline parse error: expected at least 9 arguments, got {}", args.size() - 1);
- return false;
- }
-
- int argno = 1;
-
- mode.type = DRM_MODE_TYPE_USERDEF;
- mode.clock = std::stof(args[argno++]) * 1000;
- mode.hdisplay = std::stoi(args[argno++]);
- mode.hsync_start = std::stoi(args[argno++]);
- mode.hsync_end = std::stoi(args[argno++]);
- mode.htotal = std::stoi(args[argno++]);
- mode.vdisplay = std::stoi(args[argno++]);
- mode.vsync_start = std::stoi(args[argno++]);
- mode.vsync_end = std::stoi(args[argno++]);
- mode.vtotal = std::stoi(args[argno++]);
- mode.vrefresh = mode.clock * 1000.0 * 1000.0 / mode.htotal / mode.vtotal;
-
- static std::unordered_map flagsmap = {
- {"+hsync", DRM_MODE_FLAG_PHSYNC},
- {"-hsync", DRM_MODE_FLAG_NHSYNC},
- {"+vsync", DRM_MODE_FLAG_PVSYNC},
- {"-vsync", DRM_MODE_FLAG_NVSYNC},
- };
-
- for (; argno < static_cast(args.size()); argno++) {
- auto key = args[argno];
- std::transform(key.begin(), key.end(), key.begin(), ::tolower);
-
- auto it = flagsmap.find(key);
-
- if (it != flagsmap.end())
- mode.flags |= it->second;
- else
- Debug::log(ERR, "invalid flag {} in modeline", it->first);
- }
-
- snprintf(mode.name, sizeof(mode.name), "%dx%d@%d", mode.hdisplay, mode.vdisplay, mode.vrefresh / 1000);
-
- return true;
-}
-
-void CConfigManager::handleMonitor(const std::string& command, const std::string& args) {
-
- // get the monitor config
- SMonitorRule newrule;
-
- const auto ARGS = CVarList(args);
-
- newrule.name = ARGS[0];
-
- if (ARGS[1] == "disable" || ARGS[1] == "disabled" || ARGS[1] == "addreserved" || ARGS[1] == "transform") {
- if (ARGS[1] == "disable" || ARGS[1] == "disabled")
- newrule.disabled = true;
- else if (ARGS[1] == "transform") {
- const auto TSF = std::stoi(ARGS[2]);
- if (std::clamp(TSF, 0, 7) != TSF) {
- Debug::log(ERR, "invalid transform {} in monitor", TSF);
- parseError = "invalid transform";
- return;
- }
-
- const auto TRANSFORM = (wl_output_transform)TSF;
-
- // overwrite if exists
- for (auto& r : m_dMonitorRules) {
- if (r.name == newrule.name) {
- r.transform = TRANSFORM;
- return;
- }
- }
-
- return;
- } else if (ARGS[1] == "addreserved") {
- int top = std::stoi(ARGS[2]);
-
- int bottom = std::stoi(ARGS[3]);
-
- int left = std::stoi(ARGS[4]);
-
- int right = std::stoi(ARGS[5]);
-
- m_mAdditionalReservedAreas[newrule.name] = {top, bottom, left, right};
-
- return; // this is not a rule, ignore
- } else {
- Debug::log(ERR, "ConfigManager parseMonitor, curitem bogus???");
- return;
- }
-
- std::erase_if(m_dMonitorRules, [&](const auto& other) { return other.name == newrule.name; });
-
- m_dMonitorRules.push_back(newrule);
-
- return;
- }
-
- if (ARGS[1].starts_with("pref")) {
- newrule.resolution = Vector2D();
- } else if (ARGS[1].starts_with("highrr")) {
- newrule.resolution = Vector2D(-1, -1);
- } else if (ARGS[1].starts_with("highres")) {
- newrule.resolution = Vector2D(-1, -2);
- } else if (parseModeLine(ARGS[1], newrule.drmMode)) {
- newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay);
- newrule.refreshRate = newrule.drmMode.vrefresh / 1000;
- } else {
- newrule.resolution.x = stoi(ARGS[1].substr(0, ARGS[1].find_first_of('x')));
- newrule.resolution.y = stoi(ARGS[1].substr(ARGS[1].find_first_of('x') + 1, ARGS[1].find_first_of('@')));
-
- if (ARGS[1].contains("@"))
- newrule.refreshRate = stof(ARGS[1].substr(ARGS[1].find_first_of('@') + 1));
- }
-
- if (ARGS[2].starts_with("auto")) {
- newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX);
- } else {
- newrule.offset.x = stoi(ARGS[2].substr(0, ARGS[2].find_first_of('x')));
- newrule.offset.y = stoi(ARGS[2].substr(ARGS[2].find_first_of('x') + 1));
- }
-
- if (ARGS[3].starts_with("auto")) {
- newrule.scale = -1;
- } else {
- newrule.scale = stof(ARGS[3]);
-
- if (newrule.scale < 0.25f) {
- parseError = "not a valid scale.";
- newrule.scale = 1;
- }
- }
-
- int argno = 4;
-
- while (ARGS[argno] != "") {
- if (ARGS[argno] == "mirror") {
- newrule.mirrorOf = ARGS[argno + 1];
- argno++;
- } else if (ARGS[argno] == "bitdepth") {
- newrule.enable10bit = ARGS[argno + 1] == "10";
- argno++;
- } else if (ARGS[argno] == "transform") {
- newrule.transform = (wl_output_transform)std::stoi(ARGS[argno + 1]);
- argno++;
- } else if (ARGS[argno] == "vrr") {
- newrule.vrr = std::stoi(ARGS[argno + 1]);
- argno++;
- } else if (ARGS[argno] == "workspace") {
- std::string name = "";
- int wsId = getWorkspaceIDFromString(ARGS[argno + 1], name);
-
- SWorkspaceRule wsRule;
- wsRule.monitor = newrule.name;
- wsRule.workspaceString = ARGS[argno + 1];
- wsRule.workspaceName = name;
- wsRule.workspaceId = wsId;
-
- m_dWorkspaceRules.emplace_back(wsRule);
- argno++;
- } else {
- Debug::log(ERR, "Config error: invalid monitor syntax");
- parseError = "invalid syntax at \"" + ARGS[argno] + "\"";
- return;
- }
-
- argno++;
- }
-
- std::erase_if(m_dMonitorRules, [&](const auto& other) { return other.name == newrule.name; });
-
- m_dMonitorRules.push_back(newrule);
-}
-
-void CConfigManager::handleBezier(const std::string& command, const std::string& args) {
- const auto ARGS = CVarList(args);
-
- std::string bezierName = ARGS[0];
-
- if (ARGS[1] == "")
- parseError = "too few arguments";
- float p1x = std::stof(ARGS[1]);
-
- if (ARGS[2] == "")
- parseError = "too few arguments";
- float p1y = std::stof(ARGS[2]);
-
- if (ARGS[3] == "")
- parseError = "too few arguments";
- float p2x = std::stof(ARGS[3]);
-
- if (ARGS[4] == "")
- parseError = "too few arguments";
- float p2y = std::stof(ARGS[4]);
-
- if (ARGS[5] != "")
- parseError = "too many arguments";
-
- g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y));
-}
-
-void CConfigManager::setAnimForChildren(SAnimationPropertyConfig* const ANIM) {
- for (auto& [name, anim] : animationConfig) {
- if (anim.pParentAnimation == ANIM && !anim.overridden) {
- // if a child isnt overridden, set the values of the parent
- anim.pValues = ANIM->pValues;
-
- setAnimForChildren(&anim);
- }
- }
-};
-
-void CConfigManager::handleAnimation(const std::string& command, const std::string& args) {
- const auto ARGS = CVarList(args);
-
- // Master on/off
-
- // anim name
- const auto ANIMNAME = ARGS[0];
-
- const auto PANIM = animationConfig.find(ANIMNAME);
-
- if (PANIM == animationConfig.end()) {
- parseError = "no such animation";
- return;
- }
-
- PANIM->second.overridden = true;
- PANIM->second.pValues = &PANIM->second;
-
- // on/off
- PANIM->second.internalEnabled = ARGS[1] == "1";
-
- if (ARGS[1] != "0" && ARGS[1] != "1") {
- parseError = "invalid animation on/off state";
- }
-
- if (PANIM->second.internalEnabled) {
- // speed
- if (isNumber(ARGS[2], true)) {
- PANIM->second.internalSpeed = std::stof(ARGS[2]);
-
- if (PANIM->second.internalSpeed <= 0) {
- parseError = "invalid speed";
- PANIM->second.internalSpeed = 1.f;
- }
- } else {
- PANIM->second.internalSpeed = 10.f;
- parseError = "invalid speed";
- }
-
- // curve
- PANIM->second.internalBezier = ARGS[3];
-
- if (!g_pAnimationManager->bezierExists(ARGS[3])) {
- parseError = "no such bezier";
- PANIM->second.internalBezier = "default";
- }
-
- // style
- PANIM->second.internalStyle = ARGS[4];
-
- if (ARGS[4] != "") {
- const auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]);
-
- if (ERR != "")
- parseError = ERR;
- }
- }
-
- // now, check for children, recursively
- setAnimForChildren(&PANIM->second);
-}
-
-void CConfigManager::handleBind(const std::string& command, const std::string& value) {
- // example:
- // bind[fl]=SUPER,G,exec,dmenu_run
-
- // flags
- bool locked = false;
- bool release = false;
- bool repeat = false;
- bool mouse = false;
- bool nonConsuming = false;
- bool transparent = false;
- bool ignoreMods = false;
- const auto BINDARGS = command.substr(4);
-
- for (auto& arg : BINDARGS) {
- if (arg == 'l') {
- locked = true;
- } else if (arg == 'r') {
- release = true;
- } else if (arg == 'e') {
- repeat = true;
- } else if (arg == 'm') {
- mouse = true;
- } else if (arg == 'n') {
- nonConsuming = true;
- } else if (arg == 't') {
- transparent = true;
- } else if (arg == 'i') {
- ignoreMods = true;
- } else {
- parseError = "bind: invalid flag";
- return;
- }
- }
-
- if (release && repeat) {
- parseError = "flags r and e are mutually exclusive";
- return;
- }
-
- if (mouse && (repeat || release || locked)) {
- parseError = "flag m is exclusive";
- return;
- }
-
- const auto ARGS = CVarList(value, 4);
-
- if ((ARGS.size() < 3 && !mouse) || (ARGS.size() < 3 && mouse)) {
- parseError = "bind: too few args";
- return;
- } else if ((ARGS.size() > 4 && !mouse) || (ARGS.size() > 3 && mouse)) {
- parseError = "bind: too many args";
- return;
- }
-
- const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
- const auto MODSTR = ARGS[0];
-
- const auto KEY = ARGS[1];
-
- auto HANDLER = ARGS[2];
-
- const auto COMMAND = mouse ? HANDLER : ARGS[3];
-
- if (mouse)
- HANDLER = "mouse";
-
- // to lower
- std::transform(HANDLER.begin(), HANDLER.end(), HANDLER.begin(), ::tolower);
-
- const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(HANDLER);
-
- if (DISPATCHER == g_pKeybindManager->m_mDispatchers.end()) {
- Debug::log(ERR, "Invalid dispatcher!");
- parseError = "Invalid dispatcher, requested \"" + HANDLER + "\" does not exist";
- return;
- }
-
- if (MOD == 0 && MODSTR != "") {
- Debug::log(ERR, "Invalid mod!");
- parseError = "Invalid mod, requested mod \"" + MODSTR + "\" is not a valid mod.";
- return;
- }
-
- if (KEY != "") {
- if (isNumber(KEY) && std::stoi(KEY) > 9)
- g_pKeybindManager->addKeybind(
- SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
- else if (KEY.starts_with("code:") && isNumber(KEY.substr(5)))
- g_pKeybindManager->addKeybind(
- SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
- else
- g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
- }
-}
-
-void CConfigManager::handleUnbind(const std::string& command, const std::string& value) {
- const auto ARGS = CVarList(value);
-
- const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
-
- const auto KEY = ARGS[1];
-
- g_pKeybindManager->removeKeybind(MOD, KEY);
-}
-
-bool windowRuleValid(const std::string& RULE) {
- return RULE == "float" || RULE == "tile" || RULE.starts_with("opacity") || RULE.starts_with("move") || RULE.starts_with("size") || RULE.starts_with("minsize") ||
- RULE.starts_with("maxsize") || RULE.starts_with("pseudo") || RULE.starts_with("monitor") || RULE.starts_with("idleinhibit") || RULE == "nofocus" || RULE == "noblur" ||
- RULE == "noshadow" || RULE == "nodim" || RULE == "noborder" || RULE == "opaque" || RULE == "forceinput" || RULE == "fullscreen" || RULE == "nofullscreenrequest" ||
- RULE == "nomaximizerequest" || RULE == "fakefullscreen" || RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" ||
- RULE == "maximize" || RULE == "keepaspectratio" || RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") ||
- RULE.starts_with("bordercolor") || RULE == "forcergbx" || RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") ||
- RULE.starts_with("center") || RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor";
-}
-
-bool layerRuleValid(const std::string& RULE) {
- return RULE == "noanim" || RULE == "blur" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE.starts_with("xray");
-}
-
-void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
- const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
- const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
-
- // check rule and value
- if (RULE == "" || VALUE == "") {
- return;
- }
-
- if (RULE == "unset") {
- std::erase_if(m_dWindowRules, [&](const SWindowRule& other) { return other.szValue == VALUE; });
- return;
- }
-
- // verify we support a rule
- if (!windowRuleValid(RULE)) {
- Debug::log(ERR, "Invalid rule found: {}", RULE);
- parseError = "Invalid rule found: " + RULE;
- return;
- }
-
- if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
- m_dWindowRules.push_front({RULE, VALUE});
- else
- m_dWindowRules.push_back({RULE, VALUE});
-}
-
-void CConfigManager::handleLayerRule(const std::string& command, const std::string& value) {
- const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
- const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
-
- // check rule and value
- if (RULE == "" || VALUE == "")
- return;
-
- if (RULE == "unset") {
- std::erase_if(m_dLayerRules, [&](const SLayerRule& other) { return other.targetNamespace == VALUE; });
- return;
- }
-
- if (!layerRuleValid(RULE)) {
- Debug::log(ERR, "Invalid rule found: {}", RULE);
- parseError = "Invalid rule found: " + RULE;
- return;
- }
-
- m_dLayerRules.push_back({VALUE, RULE});
-
- for (auto& m : g_pCompositor->m_vMonitors)
- for (auto& lsl : m->m_aLayerSurfaceLayers)
- for (auto& ls : lsl)
- ls->applyRules();
-}
-
-void CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) {
- const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
- const auto VALUE = value.substr(value.find_first_of(',') + 1);
-
- if (!windowRuleValid(RULE) && RULE != "unset") {
- Debug::log(ERR, "Invalid rulev2 found: {}", RULE);
- parseError = "Invalid rulev2 found: " + RULE;
- return;
- }
-
- // now we estract shit from the value
- SWindowRule rule;
- rule.v2 = true;
- rule.szRule = RULE;
- rule.szValue = VALUE;
-
- const auto TITLEPOS = VALUE.find("title:");
- const auto CLASSPOS = VALUE.find("class:");
- const auto INITIALTITLEPOS = VALUE.find("initialTitle:");
- const auto INITIALCLASSPOS = VALUE.find("initialClass:");
- const auto X11POS = VALUE.find("xwayland:");
- const auto FLOATPOS = VALUE.find("floating:");
- const auto FULLSCREENPOS = VALUE.find("fullscreen:");
- const auto PINNEDPOS = VALUE.find("pinned:");
- const auto FOCUSPOS = VALUE.find("focus:");
- const auto ONWORKSPACEPOS = VALUE.find("onworkspace:");
-
- // find workspacepos that isn't onworkspacepos
- size_t WORKSPACEPOS = std::string::npos;
- size_t currentPos = VALUE.find("workspace:");
- while (currentPos != std::string::npos) {
- if (currentPos == 0 || VALUE[currentPos - 1] != 'n') {
- WORKSPACEPOS = currentPos;
- break;
- }
- currentPos = VALUE.find("workspace:", currentPos + 1);
- }
-
- if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && INITIALTITLEPOS == std::string::npos && INITIALCLASSPOS == std::string::npos &&
- X11POS == std::string::npos && FLOATPOS == std::string::npos && FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos &&
- FOCUSPOS == std::string::npos && ONWORKSPACEPOS == std::string::npos) {
- Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE);
- parseError = "Invalid rulev2 syntax: " + VALUE;
- return;
- }
-
- auto extract = [&](size_t pos) -> std::string {
- std::string result;
- result = VALUE.substr(pos);
-
- size_t min = 999999;
- if (TITLEPOS > pos && TITLEPOS < min)
- min = TITLEPOS;
- if (CLASSPOS > pos && CLASSPOS < min)
- min = CLASSPOS;
- if (INITIALTITLEPOS > pos && INITIALTITLEPOS < min)
- min = INITIALTITLEPOS;
- if (INITIALCLASSPOS > pos && INITIALCLASSPOS < min)
- min = INITIALCLASSPOS;
- if (X11POS > pos && X11POS < min)
- min = X11POS;
- if (FLOATPOS > pos && FLOATPOS < min)
- min = FLOATPOS;
- if (FULLSCREENPOS > pos && FULLSCREENPOS < min)
- min = FULLSCREENPOS;
- if (PINNEDPOS > pos && PINNEDPOS < min)
- min = PINNEDPOS;
- if (ONWORKSPACEPOS > pos && ONWORKSPACEPOS < min)
- min = ONWORKSPACEPOS;
- if (WORKSPACEPOS > pos && WORKSPACEPOS < min)
- min = WORKSPACEPOS;
- if (FOCUSPOS > pos && FOCUSPOS < min)
- min = FOCUSPOS;
-
- result = result.substr(0, min - pos);
-
- result = removeBeginEndSpacesTabs(result);
-
- if (result.back() == ',')
- result.pop_back();
-
- return result;
- };
-
- if (CLASSPOS != std::string::npos)
- rule.szClass = extract(CLASSPOS + 6);
-
- if (TITLEPOS != std::string::npos)
- rule.szTitle = extract(TITLEPOS + 6);
-
- if (INITIALCLASSPOS != std::string::npos)
- rule.szInitialClass = extract(INITIALCLASSPOS + 13);
-
- if (INITIALTITLEPOS != std::string::npos)
- rule.szInitialTitle = extract(INITIALTITLEPOS + 13);
-
- if (X11POS != std::string::npos)
- rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
-
- if (FLOATPOS != std::string::npos)
- rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
-
- if (FULLSCREENPOS != std::string::npos)
- rule.bFullscreen = extract(FULLSCREENPOS + 11) == "1" ? 1 : 0;
-
- if (PINNEDPOS != std::string::npos)
- rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0;
-
- if (WORKSPACEPOS != std::string::npos)
- rule.szWorkspace = extract(WORKSPACEPOS + 10);
-
- if (FOCUSPOS != std::string::npos)
- rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0;
-
- if (ONWORKSPACEPOS != std::string::npos)
- rule.iOnWorkspace = configStringToInt(extract(ONWORKSPACEPOS + 12));
-
- if (RULE == "unset") {
- std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
- if (!other.v2) {
- return other.szClass == rule.szClass && !rule.szClass.empty();
- } else {
- if (!rule.szClass.empty() && rule.szClass != other.szClass)
- return false;
-
- if (!rule.szTitle.empty() && rule.szTitle != other.szTitle)
- return false;
-
- if (!rule.szInitialClass.empty() && rule.szInitialClass != other.szInitialClass)
- return false;
-
- if (!rule.szInitialTitle.empty() && rule.szInitialTitle != other.szInitialTitle)
- return false;
-
- if (rule.bX11 != -1 && rule.bX11 != other.bX11)
- return false;
-
- if (rule.bFloating != -1 && rule.bFloating != other.bFloating)
- return false;
-
- if (rule.bFullscreen != -1 && rule.bFullscreen != other.bFullscreen)
- return false;
-
- if (rule.bPinned != -1 && rule.bPinned != other.bPinned)
- return false;
-
- if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace)
- return false;
-
- if (rule.bFocus != -1 && rule.bFocus != other.bFocus)
- return false;
-
- if (rule.iOnWorkspace != -1 && rule.iOnWorkspace != other.iOnWorkspace)
- return false;
-
- return true;
- }
- });
- return;
- }
-
- if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
- m_dWindowRules.push_front(rule);
- else
- m_dWindowRules.push_back(rule);
-}
-
-void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBlur) {
- const bool BYADDRESS = name.starts_with("address:");
- std::string matchName = name;
-
- if (BYADDRESS) {
- matchName = matchName.substr(8);
- }
-
- for (auto& m : g_pCompositor->m_vMonitors) {
- for (auto& lsl : m->m_aLayerSurfaceLayers) {
- for (auto& ls : lsl) {
- if (BYADDRESS) {
- if (std::format("0x{:x}", (uintptr_t)ls.get()) == matchName)
- ls->forceBlur = forceBlur;
- } else if (ls->szNamespace == matchName)
- ls->forceBlur = forceBlur;
- }
- }
- }
-}
-
-void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
- if (value.starts_with("remove,")) {
- const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
- if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; }))
- updateBlurredLS(TOREMOVE, false);
- return;
- }
-
- m_dBlurLSNamespaces.emplace_back(value);
- updateBlurredLS(value, true);
-}
-
-void CConfigManager::handleWorkspaceRules(const std::string& command, const std::string& value) {
- // This can either be the monitor or the workspace identifier
- const auto FIRST_DELIM = value.find_first_of(',');
-
- std::string name = "";
- auto first_ident = removeBeginEndSpacesTabs(value.substr(0, FIRST_DELIM));
- int id = getWorkspaceIDFromString(first_ident, name);
-
- auto rules = value.substr(FIRST_DELIM + 1);
- SWorkspaceRule wsRule;
- wsRule.workspaceString = first_ident;
- if (id == WORKSPACE_INVALID) {
- // it could be the monitor. If so, second value MUST be
- // the workspace.
- const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
- auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
- id = getWorkspaceIDFromString(wsIdent, name);
- if (id == WORKSPACE_INVALID) {
- Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
- parseError = "Invalid workspace identifier found: " + wsIdent;
- return;
- }
- wsRule.monitor = first_ident;
- wsRule.workspaceString = wsIdent;
- wsRule.isDefault = true; // backwards compat
- rules = value.substr(WORKSPACE_DELIM + 1);
- }
-
- const static std::string ruleOnCreatedEmtpy = "on-created-empty:";
- const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length();
-
- auto assignRule = [&](std::string rule) {
- size_t delim = std::string::npos;
- if ((delim = rule.find("gapsin:")) != std::string::npos)
- wsRule.gapsIn = std::stoi(rule.substr(delim + 7));
- else if ((delim = rule.find("gapsout:")) != std::string::npos)
- wsRule.gapsOut = std::stoi(rule.substr(delim + 8));
- else if ((delim = rule.find("bordersize:")) != std::string::npos)
- wsRule.borderSize = std::stoi(rule.substr(delim + 11));
- else if ((delim = rule.find("border:")) != std::string::npos)
- wsRule.border = configStringToInt(rule.substr(delim + 7));
- else if ((delim = rule.find("shadow:")) != std::string::npos)
- wsRule.shadow = configStringToInt(rule.substr(delim + 7));
- else if ((delim = rule.find("rounding:")) != std::string::npos)
- wsRule.rounding = configStringToInt(rule.substr(delim + 9));
- else if ((delim = rule.find("decorate:")) != std::string::npos)
- wsRule.decorate = configStringToInt(rule.substr(delim + 9));
- else if ((delim = rule.find("monitor:")) != std::string::npos)
- wsRule.monitor = rule.substr(delim + 8);
- else if ((delim = rule.find("default:")) != std::string::npos)
- wsRule.isDefault = configStringToInt(rule.substr(delim + 8));
- else if ((delim = rule.find("persistent:")) != std::string::npos)
- wsRule.isPersistent = configStringToInt(rule.substr(delim + 11));
- else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos)
- wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen));
- else if ((delim = rule.find("layoutopt:")) != std::string::npos) {
- std::string opt = rule.substr(delim + 10);
- if (!opt.contains(":")) {
- // invalid
- Debug::log(ERR, "Invalid workspace rule found: {}", rule);
- parseError = "Invalid workspace rule found: " + rule;
- return;
- }
-
- std::string val = opt.substr(opt.find(":") + 1);
- opt = opt.substr(0, opt.find(":"));
-
- wsRule.layoutopts[opt] = val;
- }
- };
-
- size_t pos = 0;
- std::string rule;
- while ((pos = rules.find(',')) != std::string::npos) {
- rule = rules.substr(0, pos);
- assignRule(rule);
- rules.erase(0, pos + 1);
- }
- assignRule(rules); // match remaining rule
-
- wsRule.workspaceId = id;
- wsRule.workspaceName = name;
-
- const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) { return other.workspaceString == wsRule.workspaceString; });
-
- if (IT == m_dWorkspaceRules.end())
- m_dWorkspaceRules.emplace_back(wsRule);
- else
- *IT = wsRule;
-}
-
-void CConfigManager::handleSubmap(const std::string& command, const std::string& submap) {
- if (submap == "reset")
- m_szCurrentSubmap = "";
- else
- m_szCurrentSubmap = submap;
-}
-
-void CConfigManager::handleSource(const std::string& command, const std::string& rawpath) {
- if (rawpath.length() < 2) {
- Debug::log(ERR, "source= path garbage");
- parseError = "source path " + rawpath + " bogus!";
- return;
- }
- std::unique_ptr glob_buf{new glob_t, [](glob_t* g) { globfree(g); }};
- memset(glob_buf.get(), 0, sizeof(glob_t));
-
- if (auto r = glob(absolutePath(rawpath, configCurrentPath).c_str(), GLOB_TILDE, nullptr, glob_buf.get()); r != 0) {
- parseError = std::format("source= globbing error: {}", r == GLOB_NOMATCH ? "found no match" : GLOB_ABORTED ? "read error" : "out of memory");
- Debug::log(ERR, "{}", parseError);
- return;
- }
-
- for (size_t i = 0; i < glob_buf->gl_pathc; i++) {
- auto value = absolutePath(glob_buf->gl_pathv[i], configCurrentPath);
-
- if (!std::filesystem::is_regular_file(value)) {
- if (std::filesystem::exists(value)) {
- Debug::log(WARN, "source= skipping non-file {}", value);
- continue;
- }
-
- Debug::log(ERR, "source= file doesnt exist");
- parseError = "source file " + value + " doesn't exist!";
- return;
- }
- configPaths.push_back(value);
-
- struct stat fileStat;
- int err = stat(value.c_str(), &fileStat);
- if (err != 0) {
- Debug::log(WARN, "Error at ticking config at {}, error {}: {}", value, err, strerror(err));
- return;
- }
-
- configModifyTimes[value] = fileStat.st_mtime;
-
- std::ifstream ifs;
- ifs.open(value);
-
- std::string line = "";
- int linenum = 1;
- if (ifs.is_open()) {
- auto configCurrentPathBackup = configCurrentPath;
-
- while (std::getline(ifs, line)) {
- // Read line by line.
- try {
- configCurrentPath = value;
- parseLine(line);
- } catch (...) {
- Debug::log(ERR, "Error reading line from config. Line:");
- Debug::log(NONE, "{}", line.c_str());
-
- parseError += "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): Line parsing error.";
- }
-
- if (parseError != "" && !parseError.starts_with("Config error at line")) {
- parseError = "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): " + parseError;
- }
-
- ++linenum;
- }
-
- ifs.close();
-
- configCurrentPath = configCurrentPathBackup;
- }
- }
-}
-
-void CConfigManager::handleBindWS(const std::string& command, const std::string& value) {
- parseError = "bindws has been deprecated in favor of workspace rules, see the wiki -> workspace rules";
-}
-
-void CConfigManager::handleEnv(const std::string& command, const std::string& value) {
- if (!isFirstLaunch)
- return;
-
- const auto ARGS = CVarList(value, 2);
-
- if (ARGS[0].empty()) {
- parseError = "env empty";
- return;
- }
-
- setenv(ARGS[0].c_str(), ARGS[1].c_str(), 1);
-
- if (command.back() == 'd') {
- // dbus
- const auto CMD =
-#ifdef USES_SYSTEMD
- "systemctl --user import-environment " + ARGS[0] +
- " && hash dbus-update-activation-environment 2>/dev/null && "
-#endif
- "dbus-update-activation-environment --systemd " +
- ARGS[0];
- handleRawExec("", CMD);
- }
-}
-
-void CConfigManager::handlePlugin(const std::string& command, const std::string& path) {
- if (std::find(m_vDeclaredPlugins.begin(), m_vDeclaredPlugins.end(), path) != m_vDeclaredPlugins.end()) {
- parseError = "plugin '" + path + "' declared twice";
- return;
- }
-
- m_vDeclaredPlugins.push_back(path);
-}
-
-std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE, bool dynamic) {
- if (dynamic) {
- parseError = "";
- currentCategory = "";
- }
-
- int needsLayoutRecalc = COMMAND == "monitor"; // 0 - no, 1 - yes, 2 - maybe
-
- if (COMMAND == "exec") {
- if (isFirstLaunch) {
- firstExecRequests.push_back(VALUE);
- } else {
- handleRawExec(COMMAND, VALUE);
- }
- } else if (COMMAND == "exec-once") {
- if (isFirstLaunch) {
- firstExecRequests.push_back(VALUE);
- }
- } else if (COMMAND == "monitor")
- handleMonitor(COMMAND, VALUE);
- else if (COMMAND.starts_with("bind"))
- handleBind(COMMAND, VALUE);
- else if (COMMAND == "unbind")
- handleUnbind(COMMAND, VALUE);
- else if (COMMAND == "workspace")
- handleWorkspaceRules(COMMAND, VALUE);
- else if (COMMAND == "windowrule")
- handleWindowRule(COMMAND, VALUE);
- else if (COMMAND == "windowrulev2")
- handleWindowRuleV2(COMMAND, VALUE);
- else if (COMMAND == "layerrule")
- handleLayerRule(COMMAND, VALUE);
- else if (COMMAND == "bezier")
- handleBezier(COMMAND, VALUE);
- else if (COMMAND == "animation")
- handleAnimation(COMMAND, VALUE);
- else if (COMMAND == "source")
- handleSource(COMMAND, VALUE);
- else if (COMMAND == "submap")
- handleSubmap(COMMAND, VALUE);
- else if (COMMAND == "blurls")
- handleBlurLS(COMMAND, VALUE);
- else if (COMMAND == "wsbind")
- handleBindWS(COMMAND, VALUE);
- else if (COMMAND == "plugin")
- handlePlugin(COMMAND, VALUE);
- else if (COMMAND.starts_with("env"))
- handleEnv(COMMAND, VALUE);
- else {
- // try config
- const auto IT = std::find_if(pluginKeywords.begin(), pluginKeywords.end(), [&](const auto& other) { return other.name == COMMAND; });
-
- if (IT != pluginKeywords.end()) {
- IT->fn(COMMAND, VALUE);
- } else {
- configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
- needsLayoutRecalc = 2;
- }
- }
-
- if (dynamic) {
- std::string retval = parseError;
- parseError = "";
-
- // invalidate layouts if they changed
- if (needsLayoutRecalc) {
- if (needsLayoutRecalc == 1 || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) {
- for (auto& m : g_pCompositor->m_vMonitors)
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
- }
- }
-
- // Update window border colors
- g_pCompositor->updateAllWindowsAnimatedDecorationValues();
-
- // manual crash
- if (configValues["debug:manual_crash"].intValue && !m_bManualCrashInitiated) {
- m_bManualCrashInitiated = true;
- if (g_pHyprNotificationOverlay) {
- g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000,
- ICON_INFO);
- }
- } else if (m_bManualCrashInitiated && !configValues["debug:manual_crash"].intValue) {
- // cowabunga it is
- g_pHyprRenderer->initiateManualCrash();
- }
-
- return retval;
- }
-
- return parseError;
-}
-
-void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equalsPlace) {
- auto dollarPlace = line.find_first_of('$', equalsPlace);
-
- int times = 0;
-
- while (dollarPlace != std::string::npos) {
- times++;
-
- const auto STRAFTERDOLLAR = line.substr(dollarPlace + 1);
- bool found = false;
- for (auto& [var, value] : configDynamicVars) {
- if (STRAFTERDOLLAR.starts_with(var)) {
- line.replace(dollarPlace, var.length() + 1, value);
- found = true;
- break;
- }
- }
-
- if (!found) {
- // maybe env?
- for (auto& [var, value] : environmentVariables) {
- if (STRAFTERDOLLAR.starts_with(var)) {
- line.replace(dollarPlace, var.length() + 1, value);
- break;
- }
- }
- }
-
- dollarPlace = line.find_first_of('$', dollarPlace + 1);
-
- if (times > 256 /* arbitrary limit */) {
- line = "";
- parseError = "Maximum variable recursion limit hit. Evaluating the line led to too many variable substitutions.";
- Debug::log(ERR, "Variable recursion limit hit in configmanager");
- break;
- }
- }
-}
-
-void CConfigManager::parseLine(std::string& line) {
- // first check if its not a comment
- if (line[0] == '#')
- return;
-
- // now, cut the comment off. ## is an escape.
- for (long unsigned int i = 1; i < line.length(); ++i) {
- if (line[i] == '#') {
- if (i + 1 < line.length() && line[i + 1] != '#') {
- line = line.substr(0, i);
- break; // no need to parse more
- }
-
- i++;
- }
- }
-
- size_t startPos = 0;
- while ((startPos = line.find("##", startPos)) != std::string::npos && startPos < line.length() - 1 && startPos > 0) {
- line.replace(startPos, 2, "#");
- startPos++;
- }
-
- line = removeBeginEndSpacesTabs(line);
-
- if (line.contains(" {")) {
- auto cat = line.substr(0, line.find(" {"));
- transform(cat.begin(), cat.end(), cat.begin(), ::tolower);
- std::replace(cat.begin(), cat.end(), ' ', '-');
- if (currentCategory.length() != 0) {
- currentCategory.push_back(':');
- currentCategory.append(cat);
- } else {
- currentCategory = cat;
- }
-
- return;
- }
-
- if (line.contains("}") && currentCategory != "") {
-
- const auto LASTSEP = currentCategory.find_last_of(':');
-
- if (LASTSEP == std::string::npos || currentCategory.starts_with("device"))
- currentCategory = "";
- else
- currentCategory = currentCategory.substr(0, LASTSEP);
-
- return;
- }
-
- // And parse
- // check if command
- const auto EQUALSPLACE = line.find_first_of('=');
-
- // apply vars
- applyUserDefinedVars(line, EQUALSPLACE);
-
- if (EQUALSPLACE == std::string::npos)
- return;
-
- const auto COMMAND = removeBeginEndSpacesTabs(line.substr(0, EQUALSPLACE));
- const auto VALUE = removeBeginEndSpacesTabs(line.substr(EQUALSPLACE + 1));
- //
-
- parseKeyword(COMMAND, VALUE);
-}
-
-void CConfigManager::loadConfigLoadVars() {
- EMIT_HOOK_EVENT("preConfigReload", nullptr);
-
- Debug::log(LOG, "Reloading the config!");
- parseError = ""; // reset the error
- currentCategory = ""; // reset the category
-
- // reset all vars before loading
- setDefaultVars();
+std::optional CConfigManager::resetHLConfig() {
m_dMonitorRules.clear();
m_dWindowRules.clear();
g_pKeybindManager->clearKeybinds();
g_pAnimationManager->removeAllBeziers();
m_mAdditionalReservedAreas.clear();
- configDynamicVars.clear();
- deviceConfigs.clear();
m_dBlurLSNamespaces.clear();
m_dWorkspaceRules.clear();
setDefaultAnimationVars(); // reset anims
@@ -1656,82 +707,12 @@ void CConfigManager::loadConfigLoadVars() {
Debug::log(LOG, "Using config: {}", mainConfigPath);
configPaths.push_back(mainConfigPath);
- if (g_pCompositor->explicitConfigPath.empty() && !std::filesystem::exists(mainConfigPath)) {
- std::string configPath = std::filesystem::path(mainConfigPath).parent_path();
+ const auto RET = verifyConfigExists();
- if (!std::filesystem::is_directory(configPath)) {
- Debug::log(WARN, "Creating config home directory");
- try {
- std::filesystem::create_directories(configPath);
- } catch (...) {
- parseError = "Broken config file! (Could not create config directory)";
- return;
- }
- }
-
- Debug::log(WARN, "No config file found; attempting to generate.");
- std::ofstream ofs;
- ofs.open(mainConfigPath, std::ios::trunc);
- ofs << AUTOCONFIG;
- ofs.close();
- }
-
- std::ifstream ifs;
- ifs.open(mainConfigPath);
-
- if (!ifs.good()) {
- ifs.close();
-
- if (!g_pCompositor->explicitConfigPath.empty()) {
- Debug::log(WARN, "Config reading error!");
- parseError = "Broken config file! (Could not read)";
- return;
- }
-
- Debug::log(WARN, "Config reading error. Attempting to generate, backing up old one if exists");
-
- if (std::filesystem::exists(mainConfigPath))
- std::filesystem::rename(mainConfigPath, mainConfigPath + ".backup");
-
- // Create default config
- std::ofstream ofs;
- ofs.open(mainConfigPath, std::ios::trunc);
- ofs << AUTOCONFIG;
- ofs.close();
-
- // Try to re-open
- ifs.open(mainConfigPath);
- if (!ifs.good()) {
- parseError = "Broken config file! (Could not open)";
- return;
- }
- }
-
- std::string line = "";
- int linenum = 1;
- if (ifs.is_open()) {
- while (std::getline(ifs, line)) {
- // Read line by line.
- try {
- configCurrentPath = mainConfigPath;
- parseLine(line);
- } catch (...) {
- Debug::log(ERR, "Error reading line from config. Line:");
- Debug::log(NONE, "{}", line);
-
- parseError += "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): Line parsing error.";
- }
-
- if (parseError != "" && !parseError.starts_with("Config error at line")) {
- parseError = "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): " + parseError;
- }
-
- ++linenum;
- }
-
- ifs.close();
- }
+ return RET;
+}
+void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
for (auto& w : g_pCompositor->m_vWindows) {
w->uncacheWindowDecos();
}
@@ -1751,10 +732,10 @@ void CConfigManager::loadConfigLoadVars() {
g_pHyprOpenGL->m_bReloadScreenShader = true;
// parseError will be displayed next frame
- if (parseError != "" && !configValues["debug:suppress_errors"].intValue)
- g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
- else if (configValues["autogenerated"].intValue == 1)
- g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + mainConfigPath + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland",
+ if (result.error && !std::any_cast(m_pConfig->getConfigValue("debug:suppress_errors")))
+ g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+ else if (std::any_cast(m_pConfig->getConfigValue("autogenerated")) == 1)
+ g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland",
CColor(1.0, 1.0, 70.0 / 255.0, 1.0));
else
g_pHyprError->destroy();
@@ -1786,18 +767,18 @@ void CConfigManager::loadConfigLoadVars() {
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
// update layout
- g_pLayoutManager->switchToLayout(configValues["general:layout"].strValue);
+ g_pLayoutManager->switchToLayout(std::any_cast(m_pConfig->getConfigValue("general:layout")));
// manual crash
- if (configValues["debug:manual_crash"].intValue && !m_bManualCrashInitiated) {
+ if (std::any_cast(m_pConfig->getConfigValue("debug:manual_crash")) && !m_bManualCrashInitiated) {
m_bManualCrashInitiated = true;
g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000, ICON_INFO);
- } else if (m_bManualCrashInitiated && !configValues["debug:manual_crash"].intValue) {
+ } else if (m_bManualCrashInitiated && !std::any_cast(m_pConfig->getConfigValue("debug:manual_crash"))) {
// cowabunga it is
g_pHyprRenderer->initiateManualCrash();
}
- Debug::disableStdout = !configValues["debug:enable_stdout_logs"].intValue;
+ Debug::disableStdout = !std::any_cast(m_pConfig->getConfigValue("debug:enable_stdout_logs"));
if (Debug::disableStdout && isFirstLaunch)
Debug::log(LOG, "Disabling stdout logs! Check the log for further logs.");
@@ -1822,6 +803,49 @@ void CConfigManager::loadConfigLoadVars() {
g_pEventManager->postEvent(SHyprIPCEvent{"configreloaded", ""});
}
+void CConfigManager::init() {
+
+ const std::string CONFIGPATH = getMainConfigPath();
+ reload();
+
+ struct stat fileStat;
+ int err = stat(CONFIGPATH.c_str(), &fileStat);
+ if (err != 0) {
+ Debug::log(WARN, "Error at statting config, error {}", errno);
+ }
+
+ configModifyTimes[CONFIGPATH] = fileStat.st_mtime;
+
+ isFirstLaunch = false;
+}
+
+std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE) {
+ const auto RET = m_pConfig->parseDynamic(COMMAND.c_str(), VALUE.c_str());
+
+ // invalidate layouts if they changed
+ if (COMMAND == "monitor" || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) {
+ for (auto& m : g_pCompositor->m_vMonitors)
+ g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
+ }
+
+ // Update window border colors
+ g_pCompositor->updateAllWindowsAnimatedDecorationValues();
+
+ // manual crash
+ if (std::any_cast(m_pConfig->getConfigValue("debug:manual_crash")) && !m_bManualCrashInitiated) {
+ m_bManualCrashInitiated = true;
+ if (g_pHyprNotificationOverlay) {
+ g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000,
+ ICON_INFO);
+ }
+ } else if (m_bManualCrashInitiated && !std::any_cast(m_pConfig->getConfigValue("debug:manual_crash"))) {
+ // cowabunga it is
+ g_pHyprRenderer->initiateManualCrash();
+ }
+
+ return RET.error ? RET.getError() : "";
+}
+
void CConfigManager::tick() {
std::string CONFIGPATH = getMainConfigPath();
if (!std::filesystem::exists(CONFIGPATH)) {
@@ -1849,76 +873,35 @@ void CConfigManager::tick() {
if (parse) {
m_bForceReload = false;
- loadConfigLoadVars();
+ reload();
}
}
-std::mutex configmtx;
-SConfigValue CConfigManager::getConfigValueSafe(const std::string& val) {
- std::lock_guard lg(configmtx);
+Hyprlang::CConfigValue* CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback) {
- SConfigValue copy = configValues[val];
+ const auto VAL = m_pConfig->getSpecialConfigValuePtr("device", val.c_str(), dev.c_str());
- return copy;
-}
-
-SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback) {
- std::lock_guard lg(configmtx);
-
- const auto it = deviceConfigs.find(dev);
-
- if (it == deviceConfigs.end()) {
- if (fallback.empty()) {
- Debug::log(ERR, "getConfigValueSafeDevice: No device config for {} found???", dev);
- return SConfigValue();
- }
- return configValues[fallback];
+ if ((!VAL || !VAL->m_bSetByUser) && !fallback.empty()) {
+ return m_pConfig->getConfigValuePtr(fallback.c_str());
}
- const SConfigValue DEVICECONFIG = it->second[val];
-
- if (!DEVICECONFIG.set && !fallback.empty()) {
- return configValues[fallback];
- }
-
- return DEVICECONFIG;
-}
-
-int CConfigManager::getInt(const std::string& v) {
- return getConfigValueSafe(v).intValue;
-}
-
-float CConfigManager::getFloat(const std::string& v) {
- return getConfigValueSafe(v).floatValue;
-}
-
-Vector2D CConfigManager::getVec(const std::string& v) {
- return getConfigValueSafe(v).vecValue;
-}
-
-std::string CConfigManager::getString(const std::string& v) {
- auto VAL = getConfigValueSafe(v).strValue;
-
- if (VAL == STRVAL_EMPTY)
- return "";
-
return VAL;
}
int CConfigManager::getDeviceInt(const std::string& dev, const std::string& v, const std::string& fallback) {
- return getConfigValueSafeDevice(dev, v, fallback).intValue;
+ return std::any_cast(getConfigValueSafeDevice(dev, v, fallback)->getValue());
}
float CConfigManager::getDeviceFloat(const std::string& dev, const std::string& v, const std::string& fallback) {
- return getConfigValueSafeDevice(dev, v, fallback).floatValue;
+ return std::any_cast(getConfigValueSafeDevice(dev, v, fallback)->getValue());
}
Vector2D CConfigManager::getDeviceVec(const std::string& dev, const std::string& v, const std::string& fallback) {
- return getConfigValueSafeDevice(dev, v, fallback).vecValue;
+ return std::any_cast(getConfigValueSafeDevice(dev, v, fallback)->getValue());
}
std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v, const std::string& fallback) {
- auto VAL = getConfigValueSafeDevice(dev, v, fallback).strValue;
+ const auto VAL = std::string{std::any_cast(getConfigValueSafeDevice(dev, v, fallback)->getValue())};
if (VAL == STRVAL_EMPTY)
return "";
@@ -1926,49 +909,21 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s
return VAL;
}
-void CConfigManager::setInt(const std::string& v, int val) {
- configValues[v].intValue = val;
-}
-
-void CConfigManager::setFloat(const std::string& v, float val) {
- configValues[v].floatValue = val;
-}
-
-void CConfigManager::setVec(const std::string& v, Vector2D val) {
- configValues[v].vecValue = val;
-}
-
-void CConfigManager::setString(const std::string& v, const std::string& val) {
- configValues[v].strValue = val;
-}
-
-SMonitorRule CConfigManager::getMonitorRuleFor(const std::string& name, const std::string& displayName) {
- SMonitorRule* found = nullptr;
-
+SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) {
for (auto& r : m_dMonitorRules) {
- if (r.name == name ||
- (r.name.starts_with("desc:") &&
- (r.name.substr(5) == displayName || r.name.substr(5) == removeBeginEndSpacesTabs(displayName.substr(0, displayName.find_first_of('(')))))) {
- found = &r;
- break;
+ if (PMONITOR.matchesStaticSelector(r.name)) {
+ return r;
}
}
- if (found)
- return *found;
-
- Debug::log(WARN, "No rule found for {}, trying to use the first.", name);
+ Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName);
for (auto& r : m_dMonitorRules) {
if (r.name == "") {
- found = &r;
- break;
+ return r;
}
}
- if (found)
- return *found;
-
Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
return SMonitorRule{.name = "", .resolution = Vector2D(0, 0), .offset = Vector2D(-INT32_MAX, -INT32_MAX), .scale = -1}; // 0, 0 is preferred and -1, -1 is auto
@@ -1987,7 +942,7 @@ SWorkspaceRule CConfigManager::getWorkspaceRuleFor(CWorkspace* pWorkspace) {
return *IT;
}
-std::vector CConfigManager::getMatchingRules(CWindow* pWindow) {
+std::vector CConfigManager::getMatchingRules(CWindow* pWindow, bool dynamic) {
if (!g_pCompositor->windowValidMapped(pWindow))
return std::vector();
@@ -2113,6 +1068,9 @@ std::vector CConfigManager::getMatchingRules(CWindow* pWindow) {
returns.push_back(rule);
+ if (dynamic)
+ continue;
+
if (rule.szRule == "float")
hasFloating = true;
else if (rule.szRule == "fullscreen")
@@ -2205,7 +1163,7 @@ void CConfigManager::performMonitorReload() {
if (!m->output || m->isUnsafeFallback)
continue;
- auto rule = getMonitorRuleFor(m->szName, m->szDescription);
+ auto rule = getMonitorRuleFor(*m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
overAgain = true;
@@ -2226,49 +1184,25 @@ void CConfigManager::performMonitorReload() {
EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr);
}
-SConfigValue* CConfigManager::getConfigValuePtr(const std::string& val) {
- return &configValues[val];
+void* const* CConfigManager::getConfigValuePtr(const std::string& val) {
+ const auto VAL = m_pConfig->getConfigValuePtr(val.c_str());
+ if (!VAL)
+ return nullptr;
+ return VAL->getDataStaticPtr();
}
-SConfigValue* CConfigManager::getConfigValuePtrSafe(const std::string& val) {
- if (val.starts_with("device:")) {
- const auto DEVICE = val.substr(7, val.find_last_of(':') - 7);
- const auto CONFIGVAR = val.substr(val.find_last_of(':') + 1);
+Hyprlang::CConfigValue* CConfigManager::getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat) {
+ if (!specialCat.empty())
+ return m_pConfig->getSpecialConfigValuePtr(specialCat.c_str(), name.c_str(), nullptr);
- const auto DEVICECONF = deviceConfigs.find(DEVICE);
- if (DEVICECONF == deviceConfigs.end())
- return nullptr;
-
- const auto IT = DEVICECONF->second.find(CONFIGVAR);
-
- if (IT == DEVICECONF->second.end())
- return nullptr;
-
- return &IT->second;
- } else if (val.starts_with("plugin:")) {
- for (auto& [pl, pMap] : pluginConfigs) {
- const auto IT = pMap->find(val);
-
- if (IT != pMap->end())
- return &IT->second;
- }
-
- return nullptr;
- }
-
- const auto IT = configValues.find(val);
-
- if (IT == configValues.end())
- return nullptr;
-
- return &(IT->second);
+ return m_pConfig->getConfigValuePtr(name.c_str());
}
bool CConfigManager::deviceConfigExists(const std::string& dev) {
auto copy = dev;
std::replace(copy.begin(), copy.end(), ' ', '-');
- return deviceConfigs.contains(copy);
+ return m_pConfig->specialCategoryExistsForKey("device", copy.c_str());
}
bool CConfigManager::shouldBlurLS(const std::string& ns) {
@@ -2286,7 +1220,7 @@ void CConfigManager::ensureMonitorStatus() {
if (!rm->output || rm->isUnsafeFallback)
continue;
- auto rule = getMonitorRuleFor(rm->szName, rm->szDescription);
+ auto rule = getMonitorRuleFor(*rm);
if (rule.disabled == rm->m_bEnabled)
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
@@ -2294,33 +1228,33 @@ void CConfigManager::ensureMonitorStatus() {
}
void CConfigManager::ensureVRR(CMonitor* pMonitor) {
- static auto* const PVRR = &getConfigValuePtr("misc:vrr")->intValue;
+ static auto* const PVRR = reinterpret_cast(getConfigValuePtr("misc:vrr"));
static auto ensureVRRForDisplay = [&](CMonitor* m) -> void {
- if (!m->output)
+ if (!m->output || m->createdByUser)
return;
- const auto USEVRR = m->activeMonitorRule.vrr.has_value() ? m->activeMonitorRule.vrr.value() : *PVRR;
+ const auto USEVRR = m->activeMonitorRule.vrr.has_value() ? m->activeMonitorRule.vrr.value() : **PVRR;
if (USEVRR == 0) {
if (m->vrrActive) {
- wlr_output_enable_adaptive_sync(m->output, 0);
+ wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
- if (!wlr_output_commit(m->output))
+ if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
}
m->vrrActive = false;
return;
} else if (USEVRR == 1) {
if (!m->vrrActive) {
- wlr_output_enable_adaptive_sync(m->output, 1);
+ wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
- if (!wlr_output_test(m->output)) {
+ if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
- wlr_output_enable_adaptive_sync(m->output, 0);
+ wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
}
- if (!wlr_output_commit(m->output))
+ if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
}
m->vrrActive = true;
@@ -2337,20 +1271,20 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) {
- wlr_output_enable_adaptive_sync(m->output, 1);
+ wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
- if (!wlr_output_test(m->output)) {
+ if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
- wlr_output_enable_adaptive_sync(m->output, 0);
+ wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
}
- if (!wlr_output_commit(m->output))
+ if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) {
- wlr_output_enable_adaptive_sync(m->output, 0);
+ wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
- if (!wlr_output_commit(m->output))
+ if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
}
}
@@ -2371,10 +1305,7 @@ SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::
}
void CConfigManager::addParseError(const std::string& err) {
- if (parseError == "")
- parseError = err;
-
- g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+ g_pHyprError->queueCreate(err + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
}
CMonitor* CConfigManager::getBoundMonitorForWS(const std::string& wsname) {
@@ -2438,30 +1369,41 @@ std::unordered_map CConfigManager::getAni
return animationConfig;
}
-void CConfigManager::addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value) {
- auto CONFIGMAPIT = std::find_if(pluginConfigs.begin(), pluginConfigs.end(), [&](const auto& other) { return other.first == handle; });
-
- if (CONFIGMAPIT == pluginConfigs.end()) {
- pluginConfigs.emplace(
- std::pair>>(handle, std::make_unique>()));
- CONFIGMAPIT = std::find_if(pluginConfigs.begin(), pluginConfigs.end(), [&](const auto& other) { return other.first == handle; });
- }
-
- (*CONFIGMAPIT->second)[name] = value;
-
- if (const auto IT = std::find_if(m_vFailedPluginConfigValues.begin(), m_vFailedPluginConfigValues.end(), [&](const auto& other) { return other.first == name; });
- IT != m_vFailedPluginConfigValues.end()) {
- configSetValueSafe(IT->first, IT->second);
- }
+void onPluginLoadUnload(const std::string& name, bool load) {
+ //
}
-void CConfigManager::addPluginKeyword(HANDLE handle, const std::string& name, std::function fn) {
+void CConfigManager::addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value) {
+ if (!name.starts_with("plugin:"))
+ return;
+
+ std::string field = name.substr(7);
+
+ m_pConfig->addSpecialConfigValue("plugin", field.c_str(), value);
+ pluginVariables.push_back({handle, field});
+}
+
+void CConfigManager::addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fn, Hyprlang::SHandlerOptions opts) {
pluginKeywords.emplace_back(SPluginKeyword{handle, name, fn});
+ m_pConfig->registerHandler(fn, name.c_str(), opts);
}
void CConfigManager::removePluginConfig(HANDLE handle) {
- std::erase_if(pluginConfigs, [&](const auto& other) { return other.first == handle; });
+ for (auto& k : pluginKeywords) {
+ if (k.handle != handle)
+ continue;
+
+ m_pConfig->unregisterHandler(k.name.c_str());
+ }
+
std::erase_if(pluginKeywords, [&](const auto& other) { return other.handle == handle; });
+ for (auto& [h, n] : pluginVariables) {
+ if (h != handle)
+ continue;
+
+ m_pConfig->removeSpecialConfigValue("plugin", n.c_str());
+ }
+ std::erase_if(pluginVariables, [handle](const auto& other) { return other.handle == handle; });
}
std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) {
@@ -2478,3 +1420,876 @@ std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) {
}
return "";
}
+
+std::optional CConfigManager::handleRawExec(const std::string& command, const std::string& args) {
+ if (isFirstLaunch) {
+ firstExecRequests.push_back(args);
+ return {};
+ }
+
+ g_pKeybindManager->spawn(args);
+ return {};
+}
+
+std::optional CConfigManager::handleExecOnce(const std::string& command, const std::string& args) {
+ if (isFirstLaunch)
+ firstExecRequests.push_back(args);
+
+ return {};
+}
+
+static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) {
+ auto args = CVarList(modeline, 0, 's');
+
+ auto keyword = args[0];
+ std::transform(keyword.begin(), keyword.end(), keyword.begin(), ::tolower);
+
+ if (keyword != "modeline")
+ return false;
+
+ if (args.size() < 10) {
+ Debug::log(ERR, "modeline parse error: expected at least 9 arguments, got {}", args.size() - 1);
+ return false;
+ }
+
+ int argno = 1;
+
+ mode.type = DRM_MODE_TYPE_USERDEF;
+ mode.clock = std::stof(args[argno++]) * 1000;
+ mode.hdisplay = std::stoi(args[argno++]);
+ mode.hsync_start = std::stoi(args[argno++]);
+ mode.hsync_end = std::stoi(args[argno++]);
+ mode.htotal = std::stoi(args[argno++]);
+ mode.vdisplay = std::stoi(args[argno++]);
+ mode.vsync_start = std::stoi(args[argno++]);
+ mode.vsync_end = std::stoi(args[argno++]);
+ mode.vtotal = std::stoi(args[argno++]);
+ mode.vrefresh = mode.clock * 1000.0 * 1000.0 / mode.htotal / mode.vtotal;
+
+ // clang-format off
+ static std::unordered_map flagsmap = {
+ {"+hsync", DRM_MODE_FLAG_PHSYNC},
+ {"-hsync", DRM_MODE_FLAG_NHSYNC},
+ {"+vsync", DRM_MODE_FLAG_PVSYNC},
+ {"-vsync", DRM_MODE_FLAG_NVSYNC},
+ {"Interlace", DRM_MODE_FLAG_INTERLACE},
+ };
+ // clang-format on
+
+ for (; argno < static_cast(args.size()); argno++) {
+ auto key = args[argno];
+ std::transform(key.begin(), key.end(), key.begin(), ::tolower);
+
+ auto it = flagsmap.find(key);
+
+ if (it != flagsmap.end())
+ mode.flags |= it->second;
+ else
+ Debug::log(ERR, "invalid flag {} in modeline", it->first);
+ }
+
+ snprintf(mode.name, sizeof(mode.name), "%dx%d@%d", mode.hdisplay, mode.vdisplay, mode.vrefresh / 1000);
+
+ return true;
+}
+
+std::optional CConfigManager::handleMonitor(const std::string& command, const std::string& args) {
+
+ // get the monitor config
+ SMonitorRule newrule;
+
+ const auto ARGS = CVarList(args);
+
+ newrule.name = ARGS[0];
+
+ if (ARGS[1] == "disable" || ARGS[1] == "disabled" || ARGS[1] == "addreserved" || ARGS[1] == "transform") {
+ if (ARGS[1] == "disable" || ARGS[1] == "disabled")
+ newrule.disabled = true;
+ else if (ARGS[1] == "transform") {
+ const auto TSF = std::stoi(ARGS[2]);
+ if (std::clamp(TSF, 0, 7) != TSF) {
+ Debug::log(ERR, "invalid transform {} in monitor", TSF);
+ return "invalid transform";
+ }
+
+ const auto TRANSFORM = (wl_output_transform)TSF;
+
+ // overwrite if exists
+ for (auto& r : m_dMonitorRules) {
+ if (r.name == newrule.name) {
+ r.transform = TRANSFORM;
+ return {};
+ }
+ }
+
+ return {};
+ } else if (ARGS[1] == "addreserved") {
+ int top = std::stoi(ARGS[2]);
+
+ int bottom = std::stoi(ARGS[3]);
+
+ int left = std::stoi(ARGS[4]);
+
+ int right = std::stoi(ARGS[5]);
+
+ m_mAdditionalReservedAreas[newrule.name] = {top, bottom, left, right};
+
+ return {};
+ } else {
+ Debug::log(ERR, "ConfigManager parseMonitor, curitem bogus???");
+ return "parse error: curitem bogus";
+ }
+
+ std::erase_if(m_dMonitorRules, [&](const auto& other) { return other.name == newrule.name; });
+
+ m_dMonitorRules.push_back(newrule);
+
+ return {};
+ }
+
+ if (ARGS[1].starts_with("pref")) {
+ newrule.resolution = Vector2D();
+ } else if (ARGS[1].starts_with("highrr")) {
+ newrule.resolution = Vector2D(-1, -1);
+ } else if (ARGS[1].starts_with("highres")) {
+ newrule.resolution = Vector2D(-1, -2);
+ } else if (parseModeLine(ARGS[1], newrule.drmMode)) {
+ newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay);
+ newrule.refreshRate = newrule.drmMode.vrefresh / 1000;
+ } else {
+ newrule.resolution.x = stoi(ARGS[1].substr(0, ARGS[1].find_first_of('x')));
+ newrule.resolution.y = stoi(ARGS[1].substr(ARGS[1].find_first_of('x') + 1, ARGS[1].find_first_of('@')));
+
+ if (ARGS[1].contains("@"))
+ newrule.refreshRate = stof(ARGS[1].substr(ARGS[1].find_first_of('@') + 1));
+ }
+
+ if (ARGS[2].starts_with("auto")) {
+ newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX);
+ } else {
+ newrule.offset.x = stoi(ARGS[2].substr(0, ARGS[2].find_first_of('x')));
+ newrule.offset.y = stoi(ARGS[2].substr(ARGS[2].find_first_of('x') + 1));
+ }
+
+ std::string error = "";
+
+ if (ARGS[3].starts_with("auto")) {
+ newrule.scale = -1;
+ } else {
+ newrule.scale = stof(ARGS[3]);
+
+ if (newrule.scale < 0.25f) {
+ error = "invalid scale";
+ newrule.scale = 1;
+ }
+ }
+
+ int argno = 4;
+
+ while (ARGS[argno] != "") {
+ if (ARGS[argno] == "mirror") {
+ newrule.mirrorOf = ARGS[argno + 1];
+ argno++;
+ } else if (ARGS[argno] == "bitdepth") {
+ newrule.enable10bit = ARGS[argno + 1] == "10";
+ argno++;
+ } else if (ARGS[argno] == "transform") {
+ newrule.transform = (wl_output_transform)std::stoi(ARGS[argno + 1]);
+ argno++;
+ } else if (ARGS[argno] == "vrr") {
+ newrule.vrr = std::stoi(ARGS[argno + 1]);
+ argno++;
+ } else if (ARGS[argno] == "workspace") {
+ std::string name = "";
+ int wsId = getWorkspaceIDFromString(ARGS[argno + 1], name);
+
+ SWorkspaceRule wsRule;
+ wsRule.monitor = newrule.name;
+ wsRule.workspaceString = ARGS[argno + 1];
+ wsRule.workspaceName = name;
+ wsRule.workspaceId = wsId;
+
+ m_dWorkspaceRules.emplace_back(wsRule);
+ argno++;
+ } else {
+ Debug::log(ERR, "Config error: invalid monitor syntax");
+ return "invalid syntax at \"" + ARGS[argno] + "\"";
+ }
+
+ argno++;
+ }
+
+ std::erase_if(m_dMonitorRules, [&](const auto& other) { return other.name == newrule.name; });
+
+ m_dMonitorRules.push_back(newrule);
+
+ if (error.empty())
+ return {};
+ return error;
+}
+
+std::optional CConfigManager::handleBezier(const std::string& command, const std::string& args) {
+ const auto ARGS = CVarList(args);
+
+ std::string bezierName = ARGS[0];
+
+ if (ARGS[1] == "")
+ return "too few arguments";
+ float p1x = std::stof(ARGS[1]);
+
+ if (ARGS[2] == "")
+ return "too few arguments";
+ float p1y = std::stof(ARGS[2]);
+
+ if (ARGS[3] == "")
+ return "too few arguments";
+ float p2x = std::stof(ARGS[3]);
+
+ if (ARGS[4] == "")
+ return "too few arguments";
+ float p2y = std::stof(ARGS[4]);
+
+ if (ARGS[5] != "")
+ return "too many arguments";
+
+ g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y));
+
+ return {};
+}
+
+void CConfigManager::setAnimForChildren(SAnimationPropertyConfig* const ANIM) {
+ for (auto& [name, anim] : animationConfig) {
+ if (anim.pParentAnimation == ANIM && !anim.overridden) {
+ // if a child isnt overridden, set the values of the parent
+ anim.pValues = ANIM->pValues;
+
+ setAnimForChildren(&anim);
+ }
+ }
+};
+
+std::optional CConfigManager::handleAnimation(const std::string& command, const std::string& args) {
+ const auto ARGS = CVarList(args);
+
+ // Master on/off
+
+ // anim name
+ const auto ANIMNAME = ARGS[0];
+
+ const auto PANIM = animationConfig.find(ANIMNAME);
+
+ if (PANIM == animationConfig.end())
+ return "no such animation";
+
+ PANIM->second.overridden = true;
+ PANIM->second.pValues = &PANIM->second;
+
+ // on/off
+ PANIM->second.internalEnabled = ARGS[1] == "1";
+
+ if (ARGS[1] != "0" && ARGS[1] != "1")
+ return "invalid animation on/off state";
+
+ if (PANIM->second.internalEnabled) {
+ // speed
+ if (isNumber(ARGS[2], true)) {
+ PANIM->second.internalSpeed = std::stof(ARGS[2]);
+
+ if (PANIM->second.internalSpeed <= 0) {
+ PANIM->second.internalSpeed = 1.f;
+ return "invalid speed";
+ }
+ } else {
+ PANIM->second.internalSpeed = 10.f;
+ return "invalid speed";
+ }
+
+ // curve
+ PANIM->second.internalBezier = ARGS[3];
+
+ if (!g_pAnimationManager->bezierExists(ARGS[3])) {
+ PANIM->second.internalBezier = "default";
+ return "no such bezier";
+ }
+
+ // style
+ PANIM->second.internalStyle = ARGS[4];
+
+ if (ARGS[4] != "") {
+ const auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]);
+
+ if (ERR != "")
+ return ERR;
+ }
+ }
+
+ // now, check for children, recursively
+ setAnimForChildren(&PANIM->second);
+
+ return {};
+}
+
+std::optional CConfigManager::handleBind(const std::string& command, const std::string& value) {
+ // example:
+ // bind[fl]=SUPER,G,exec,dmenu_run
+
+ // flags
+ bool locked = false;
+ bool release = false;
+ bool repeat = false;
+ bool mouse = false;
+ bool nonConsuming = false;
+ bool transparent = false;
+ bool ignoreMods = false;
+ const auto BINDARGS = command.substr(4);
+
+ for (auto& arg : BINDARGS) {
+ if (arg == 'l') {
+ locked = true;
+ } else if (arg == 'r') {
+ release = true;
+ } else if (arg == 'e') {
+ repeat = true;
+ } else if (arg == 'm') {
+ mouse = true;
+ } else if (arg == 'n') {
+ nonConsuming = true;
+ } else if (arg == 't') {
+ transparent = true;
+ } else if (arg == 'i') {
+ ignoreMods = true;
+ } else {
+ return "bind: invalid flag";
+ }
+ }
+
+ if (release && repeat)
+ return "flags r and e are mutually exclusive";
+
+ if (mouse && (repeat || release || locked))
+ return "flag m is exclusive";
+
+ const auto ARGS = CVarList(value, 4);
+
+ if ((ARGS.size() < 3 && !mouse) || (ARGS.size() < 3 && mouse))
+ return "bind: too few args";
+ else if ((ARGS.size() > 4 && !mouse) || (ARGS.size() > 3 && mouse))
+ return "bind: too many args";
+
+ const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
+ const auto MODSTR = ARGS[0];
+
+ const auto KEY = ARGS[1];
+
+ auto HANDLER = ARGS[2];
+
+ const auto COMMAND = mouse ? HANDLER : ARGS[3];
+
+ if (mouse)
+ HANDLER = "mouse";
+
+ // to lower
+ std::transform(HANDLER.begin(), HANDLER.end(), HANDLER.begin(), ::tolower);
+
+ const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(HANDLER);
+
+ if (DISPATCHER == g_pKeybindManager->m_mDispatchers.end()) {
+ Debug::log(ERR, "Invalid dispatcher!");
+ return "Invalid dispatcher, requested \"" + HANDLER + "\" does not exist";
+ }
+
+ if (MOD == 0 && MODSTR != "") {
+ Debug::log(ERR, "Invalid mod!");
+ return "Invalid mod, requested mod \"" + MODSTR + "\" is not a valid mod.";
+ }
+
+ if (KEY != "") {
+ if (isNumber(KEY) && std::stoi(KEY) > 9)
+ g_pKeybindManager->addKeybind(
+ SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
+ else if (KEY.starts_with("code:") && isNumber(KEY.substr(5)))
+ g_pKeybindManager->addKeybind(
+ SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
+ else
+ g_pKeybindManager->addKeybind(SKeybind{KEY, 0, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
+ }
+
+ return {};
+}
+
+std::optional CConfigManager::handleUnbind(const std::string& command, const std::string& value) {
+ const auto ARGS = CVarList(value);
+
+ const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
+
+ const auto KEY = ARGS[1];
+
+ g_pKeybindManager->removeKeybind(MOD, KEY);
+
+ return {};
+}
+
+bool windowRuleValid(const std::string& RULE) {
+ return RULE == "float" || RULE == "tile" || RULE.starts_with("opacity") || RULE.starts_with("move") || RULE.starts_with("size") || RULE.starts_with("minsize") ||
+ RULE.starts_with("maxsize") || RULE.starts_with("pseudo") || RULE.starts_with("monitor") || RULE.starts_with("idleinhibit") || RULE == "nofocus" || RULE == "noblur" ||
+ RULE == "noshadow" || RULE == "nodim" || RULE == "noborder" || RULE == "opaque" || RULE == "forceinput" || RULE == "fullscreen" || RULE == "fakefullscreen" ||
+ RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" || RULE == "maximize" || RULE == "keepaspectratio" ||
+ RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") || RULE.starts_with("bordercolor") || RULE == "forcergbx" ||
+ RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") || RULE.starts_with("center") ||
+ RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor" || RULE.starts_with("suppressevent");
+}
+
+bool layerRuleValid(const std::string& RULE) {
+ return RULE == "noanim" || RULE == "blur" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE.starts_with("xray");
+}
+
+std::optional CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
+ const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
+ const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
+
+ // check rule and value
+ if (RULE == "" || VALUE == "")
+ return "empty rule?";
+
+ if (RULE == "unset") {
+ std::erase_if(m_dWindowRules, [&](const SWindowRule& other) { return other.szValue == VALUE; });
+ return {};
+ }
+
+ // verify we support a rule
+ if (!windowRuleValid(RULE)) {
+ Debug::log(ERR, "Invalid rule found: {}", RULE);
+ return "Invalid rule: " + RULE;
+ }
+
+ if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
+ m_dWindowRules.push_front({RULE, VALUE});
+ else
+ m_dWindowRules.push_back({RULE, VALUE});
+
+ return {};
+}
+
+std::optional CConfigManager::handleLayerRule(const std::string& command, const std::string& value) {
+ const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
+ const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
+
+ // check rule and value
+ if (RULE == "" || VALUE == "")
+ return "empty rule?";
+
+ if (RULE == "unset") {
+ std::erase_if(m_dLayerRules, [&](const SLayerRule& other) { return other.targetNamespace == VALUE; });
+ return {};
+ }
+
+ if (!layerRuleValid(RULE)) {
+ Debug::log(ERR, "Invalid rule found: {}", RULE);
+ return "Invalid rule found: " + RULE;
+ }
+
+ m_dLayerRules.push_back({VALUE, RULE});
+
+ for (auto& m : g_pCompositor->m_vMonitors)
+ for (auto& lsl : m->m_aLayerSurfaceLayers)
+ for (auto& ls : lsl)
+ ls->applyRules();
+
+ return {};
+}
+
+std::optional CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) {
+ const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
+ const auto VALUE = value.substr(value.find_first_of(',') + 1);
+
+ if (!windowRuleValid(RULE) && RULE != "unset") {
+ Debug::log(ERR, "Invalid rulev2 found: {}", RULE);
+ return "Invalid rulev2 found: " + RULE;
+ }
+
+ // now we estract shit from the value
+ SWindowRule rule;
+ rule.v2 = true;
+ rule.szRule = RULE;
+ rule.szValue = VALUE;
+
+ const auto TITLEPOS = VALUE.find("title:");
+ const auto CLASSPOS = VALUE.find("class:");
+ const auto INITIALTITLEPOS = VALUE.find("initialTitle:");
+ const auto INITIALCLASSPOS = VALUE.find("initialClass:");
+ const auto X11POS = VALUE.find("xwayland:");
+ const auto FLOATPOS = VALUE.find("floating:");
+ const auto FULLSCREENPOS = VALUE.find("fullscreen:");
+ const auto PINNEDPOS = VALUE.find("pinned:");
+ const auto FOCUSPOS = VALUE.find("focus:");
+ const auto ONWORKSPACEPOS = VALUE.find("onworkspace:");
+
+ // find workspacepos that isn't onworkspacepos
+ size_t WORKSPACEPOS = std::string::npos;
+ size_t currentPos = VALUE.find("workspace:");
+ while (currentPos != std::string::npos) {
+ if (currentPos == 0 || VALUE[currentPos - 1] != 'n') {
+ WORKSPACEPOS = currentPos;
+ break;
+ }
+ currentPos = VALUE.find("workspace:", currentPos + 1);
+ }
+
+ if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && INITIALTITLEPOS == std::string::npos && INITIALCLASSPOS == std::string::npos &&
+ X11POS == std::string::npos && FLOATPOS == std::string::npos && FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos &&
+ FOCUSPOS == std::string::npos && ONWORKSPACEPOS == std::string::npos) {
+ Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE);
+ return "Invalid rulev2 syntax: " + VALUE;
+ }
+
+ auto extract = [&](size_t pos) -> std::string {
+ std::string result;
+ result = VALUE.substr(pos);
+
+ size_t min = 999999;
+ if (TITLEPOS > pos && TITLEPOS < min)
+ min = TITLEPOS;
+ if (CLASSPOS > pos && CLASSPOS < min)
+ min = CLASSPOS;
+ if (INITIALTITLEPOS > pos && INITIALTITLEPOS < min)
+ min = INITIALTITLEPOS;
+ if (INITIALCLASSPOS > pos && INITIALCLASSPOS < min)
+ min = INITIALCLASSPOS;
+ if (X11POS > pos && X11POS < min)
+ min = X11POS;
+ if (FLOATPOS > pos && FLOATPOS < min)
+ min = FLOATPOS;
+ if (FULLSCREENPOS > pos && FULLSCREENPOS < min)
+ min = FULLSCREENPOS;
+ if (PINNEDPOS > pos && PINNEDPOS < min)
+ min = PINNEDPOS;
+ if (ONWORKSPACEPOS > pos && ONWORKSPACEPOS < min)
+ min = ONWORKSPACEPOS;
+ if (WORKSPACEPOS > pos && WORKSPACEPOS < min)
+ min = WORKSPACEPOS;
+ if (FOCUSPOS > pos && FOCUSPOS < min)
+ min = FOCUSPOS;
+
+ result = result.substr(0, min - pos);
+
+ result = removeBeginEndSpacesTabs(result);
+
+ if (result.back() == ',')
+ result.pop_back();
+
+ return result;
+ };
+
+ if (CLASSPOS != std::string::npos)
+ rule.szClass = extract(CLASSPOS + 6);
+
+ if (TITLEPOS != std::string::npos)
+ rule.szTitle = extract(TITLEPOS + 6);
+
+ if (INITIALCLASSPOS != std::string::npos)
+ rule.szInitialClass = extract(INITIALCLASSPOS + 13);
+
+ if (INITIALTITLEPOS != std::string::npos)
+ rule.szInitialTitle = extract(INITIALTITLEPOS + 13);
+
+ if (X11POS != std::string::npos)
+ rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
+
+ if (FLOATPOS != std::string::npos)
+ rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
+
+ if (FULLSCREENPOS != std::string::npos)
+ rule.bFullscreen = extract(FULLSCREENPOS + 11) == "1" ? 1 : 0;
+
+ if (PINNEDPOS != std::string::npos)
+ rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0;
+
+ if (WORKSPACEPOS != std::string::npos)
+ rule.szWorkspace = extract(WORKSPACEPOS + 10);
+
+ if (FOCUSPOS != std::string::npos)
+ rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0;
+
+ if (ONWORKSPACEPOS != std::string::npos)
+ rule.iOnWorkspace = configStringToInt(extract(ONWORKSPACEPOS + 12));
+
+ if (RULE == "unset") {
+ std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
+ if (!other.v2) {
+ return other.szClass == rule.szClass && !rule.szClass.empty();
+ } else {
+ if (!rule.szClass.empty() && rule.szClass != other.szClass)
+ return false;
+
+ if (!rule.szTitle.empty() && rule.szTitle != other.szTitle)
+ return false;
+
+ if (!rule.szInitialClass.empty() && rule.szInitialClass != other.szInitialClass)
+ return false;
+
+ if (!rule.szInitialTitle.empty() && rule.szInitialTitle != other.szInitialTitle)
+ return false;
+
+ if (rule.bX11 != -1 && rule.bX11 != other.bX11)
+ return false;
+
+ if (rule.bFloating != -1 && rule.bFloating != other.bFloating)
+ return false;
+
+ if (rule.bFullscreen != -1 && rule.bFullscreen != other.bFullscreen)
+ return false;
+
+ if (rule.bPinned != -1 && rule.bPinned != other.bPinned)
+ return false;
+
+ if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace)
+ return false;
+
+ if (rule.bFocus != -1 && rule.bFocus != other.bFocus)
+ return false;
+
+ if (rule.iOnWorkspace != -1 && rule.iOnWorkspace != other.iOnWorkspace)
+ return false;
+
+ return true;
+ }
+ });
+ return {};
+ }
+
+ if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
+ m_dWindowRules.push_front(rule);
+ else
+ m_dWindowRules.push_back(rule);
+
+ return {};
+}
+
+void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBlur) {
+ const bool BYADDRESS = name.starts_with("address:");
+ std::string matchName = name;
+
+ if (BYADDRESS) {
+ matchName = matchName.substr(8);
+ }
+
+ for (auto& m : g_pCompositor->m_vMonitors) {
+ for (auto& lsl : m->m_aLayerSurfaceLayers) {
+ for (auto& ls : lsl) {
+ if (BYADDRESS) {
+ if (std::format("0x{:x}", (uintptr_t)ls.get()) == matchName)
+ ls->forceBlur = forceBlur;
+ } else if (ls->szNamespace == matchName)
+ ls->forceBlur = forceBlur;
+ }
+ }
+ }
+}
+
+std::optional CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
+ if (value.starts_with("remove,")) {
+ const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
+ if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; }))
+ updateBlurredLS(TOREMOVE, false);
+ return {};
+ }
+
+ m_dBlurLSNamespaces.emplace_back(value);
+ updateBlurredLS(value, true);
+
+ return {};
+}
+
+std::optional CConfigManager::handleWorkspaceRules(const std::string& command, const std::string& value) {
+ // This can either be the monitor or the workspace identifier
+ const auto FIRST_DELIM = value.find_first_of(',');
+
+ std::string name = "";
+ auto first_ident = removeBeginEndSpacesTabs(value.substr(0, FIRST_DELIM));
+ int id = getWorkspaceIDFromString(first_ident, name);
+
+ auto rules = value.substr(FIRST_DELIM + 1);
+ SWorkspaceRule wsRule;
+ wsRule.workspaceString = first_ident;
+ if (id == WORKSPACE_INVALID) {
+ // it could be the monitor. If so, second value MUST be
+ // the workspace.
+ const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
+ auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
+ id = getWorkspaceIDFromString(wsIdent, name);
+ if (id == WORKSPACE_INVALID) {
+ Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
+ return "Invalid workspace identifier found: " + wsIdent;
+ }
+ wsRule.monitor = first_ident;
+ wsRule.workspaceString = wsIdent;
+ wsRule.isDefault = true; // backwards compat
+ rules = value.substr(WORKSPACE_DELIM + 1);
+ }
+
+ const static std::string ruleOnCreatedEmtpy = "on-created-empty:";
+ const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length();
+
+ auto assignRule = [&](std::string rule) -> std::optional {
+ size_t delim = std::string::npos;
+ if ((delim = rule.find("gapsin:")) != std::string::npos) {
+ CVarList varlist = CVarList(rule.substr(delim + 7), 0, ' ');
+ wsRule.gapsIn = CCssGapData();
+ try {
+ wsRule.gapsIn->parseGapData(varlist);
+ } catch (...) { return "Error parsing workspace rule gaps: {}", rule.substr(delim + 7); }
+ } else if ((delim = rule.find("gapsout:")) != std::string::npos) {
+ CVarList varlist = CVarList(rule.substr(delim + 8), 0, ' ');
+ wsRule.gapsOut = CCssGapData();
+ try {
+ wsRule.gapsOut->parseGapData(varlist);
+ } catch (...) { return "Error parsing workspace rule gaps: {}", rule.substr(delim + 8); }
+ } else if ((delim = rule.find("bordersize:")) != std::string::npos)
+ try {
+ wsRule.borderSize = std::stoi(rule.substr(delim + 11));
+ } catch (...) { return "Error parsing workspace rule bordersize: {}", rule.substr(delim + 11); }
+ else if ((delim = rule.find("border:")) != std::string::npos)
+ wsRule.border = configStringToInt(rule.substr(delim + 7));
+ else if ((delim = rule.find("shadow:")) != std::string::npos)
+ wsRule.shadow = configStringToInt(rule.substr(delim + 7));
+ else if ((delim = rule.find("rounding:")) != std::string::npos)
+ wsRule.rounding = configStringToInt(rule.substr(delim + 9));
+ else if ((delim = rule.find("decorate:")) != std::string::npos)
+ wsRule.decorate = configStringToInt(rule.substr(delim + 9));
+ else if ((delim = rule.find("monitor:")) != std::string::npos)
+ wsRule.monitor = rule.substr(delim + 8);
+ else if ((delim = rule.find("default:")) != std::string::npos)
+ wsRule.isDefault = configStringToInt(rule.substr(delim + 8));
+ else if ((delim = rule.find("persistent:")) != std::string::npos)
+ wsRule.isPersistent = configStringToInt(rule.substr(delim + 11));
+ else if ((delim = rule.find("defaultName:")) != std::string::npos)
+ wsRule.defaultName = rule.substr(delim + 12);
+ else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos)
+ wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen));
+ else if ((delim = rule.find("layoutopt:")) != std::string::npos) {
+ std::string opt = rule.substr(delim + 10);
+ if (!opt.contains(":")) {
+ // invalid
+ Debug::log(ERR, "Invalid workspace rule found: {}", rule);
+ return "Invalid workspace rule found: " + rule;
+ }
+
+ std::string val = opt.substr(opt.find(":") + 1);
+ opt = opt.substr(0, opt.find(":"));
+
+ wsRule.layoutopts[opt] = val;
+ }
+
+ return {};
+ };
+
+ CVarList rulesList{rules, 0, ',', true};
+ for (auto& r : rulesList) {
+ const auto R = assignRule(r);
+ if (R.has_value())
+ return R;
+ }
+
+ wsRule.workspaceId = id;
+ wsRule.workspaceName = name;
+
+ const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) { return other.workspaceString == wsRule.workspaceString; });
+
+ if (IT == m_dWorkspaceRules.end())
+ m_dWorkspaceRules.emplace_back(wsRule);
+ else
+ *IT = wsRule;
+
+ return {};
+}
+
+std::optional CConfigManager::handleSubmap(const std::string& command, const std::string& submap) {
+ if (submap == "reset")
+ m_szCurrentSubmap = "";
+ else
+ m_szCurrentSubmap = submap;
+
+ return {};
+}
+
+std::optional CConfigManager::handleSource(const std::string& command, const std::string& rawpath) {
+ if (rawpath.length() < 2) {
+ Debug::log(ERR, "source= path garbage");
+ return "source path " + rawpath + " bogus!";
+ }
+ std::unique_ptr glob_buf{new glob_t, [](glob_t* g) { globfree(g); }};
+ memset(glob_buf.get(), 0, sizeof(glob_t));
+
+ if (auto r = glob(absolutePath(rawpath, configCurrentPath).c_str(), GLOB_TILDE, nullptr, glob_buf.get()); r != 0) {
+ std::string err = std::format("source= globbing error: {}", r == GLOB_NOMATCH ? "found no match" : GLOB_ABORTED ? "read error" : "out of memory");
+ Debug::log(ERR, "{}", err);
+ return err;
+ }
+
+ for (size_t i = 0; i < glob_buf->gl_pathc; i++) {
+ auto value = absolutePath(glob_buf->gl_pathv[i], configCurrentPath);
+
+ if (!std::filesystem::is_regular_file(value)) {
+ if (std::filesystem::exists(value)) {
+ Debug::log(WARN, "source= skipping non-file {}", value);
+ continue;
+ }
+
+ Debug::log(ERR, "source= file doesnt exist");
+ return "source file " + value + " doesn't exist!";
+ }
+ configPaths.push_back(value);
+
+ struct stat fileStat;
+ int err = stat(value.c_str(), &fileStat);
+ if (err != 0) {
+ Debug::log(WARN, "Error at ticking config at {}, error {}: {}", value, err, strerror(err));
+ return {};
+ }
+
+ configModifyTimes[value] = fileStat.st_mtime;
+ auto configCurrentPathBackup = configCurrentPath;
+ configCurrentPath = value;
+
+ m_pConfig->parseFile(value.c_str());
+
+ configCurrentPath = configCurrentPathBackup;
+ }
+
+ return {};
+}
+
+std::optional CConfigManager::handleEnv(const std::string& command, const std::string& value) {
+ if (!isFirstLaunch)
+ return {};
+
+ const auto ARGS = CVarList(value, 2);
+
+ if (ARGS[0].empty())
+ return "env empty";
+
+ setenv(ARGS[0].c_str(), ARGS[1].c_str(), 1);
+
+ if (command.back() == 'd') {
+ // dbus
+ const auto CMD =
+#ifdef USES_SYSTEMD
+ "systemctl --user import-environment " + ARGS[0] +
+ " && hash dbus-update-activation-environment 2>/dev/null && "
+#endif
+ "dbus-update-activation-environment --systemd " +
+ ARGS[0];
+ handleRawExec("", CMD);
+ }
+
+ return {};
+}
+
+std::optional CConfigManager::handlePlugin(const std::string& command, const std::string& path) {
+ if (std::find(m_vDeclaredPlugins.begin(), m_vDeclaredPlugins.end(), path) != m_vDeclaredPlugins.end())
+ return "plugin '" + path + "' declared twice";
+
+ m_vDeclaredPlugins.push_back(path);
+
+ return {};
+}
diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp
index d5957cd5..fbc61059 100644
--- a/src/config/ConfigManager.hpp
+++ b/src/config/ConfigManager.hpp
@@ -21,21 +21,13 @@
#include "defaultConfig.hpp"
#include "ConfigDataValues.hpp"
+#include
+
#define INITANIMCFG(name) animationConfig[name] = {}
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
#define HANDLE void*
-struct SConfigValue {
- int64_t intValue = -INT64_MAX;
- float floatValue = -__FLT_MAX__;
- std::string strValue = "";
- Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
- std::shared_ptr data;
-
- bool set = false; // used for device configs
-};
-
struct SWorkspaceRule {
std::string monitor = "";
std::string workspaceString = "";
@@ -43,14 +35,15 @@ struct SWorkspaceRule {
int workspaceId = -1;
bool isDefault = false;
bool isPersistent = false;
- std::optional gapsIn;
- std::optional gapsOut;
+ std::optional gapsIn;
+ std::optional gapsOut;
std::optional borderSize;
std::optional border;
std::optional rounding;
std::optional decorate;
std::optional shadow;
std::optional onCreatedEmptyRunCmd;
+ std::optional defaultName;
std::map layoutopts;
};
@@ -74,9 +67,14 @@ struct SAnimationPropertyConfig {
};
struct SPluginKeyword {
- HANDLE handle = 0;
- std::string name = "";
- std::function fn;
+ HANDLE handle = 0;
+ std::string name = "";
+ Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
+};
+
+struct SPluginVariable {
+ HANDLE handle = 0;
+ std::string name = "";
};
struct SExecRequestedRule {
@@ -91,28 +89,21 @@ class CConfigManager {
void tick();
void init();
- int getInt(const std::string&);
- float getFloat(const std::string&);
- Vector2D getVec(const std::string&);
- std::string getString(const std::string&);
- void setFloat(const std::string&, float);
- void setInt(const std::string&, int);
- void setVec(const std::string&, Vector2D);
- void setString(const std::string&, const std::string&);
-
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
bool deviceConfigExists(const std::string&);
+ Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
bool shouldBlurLS(const std::string&);
- SConfigValue* getConfigValuePtr(const std::string&);
- SConfigValue* getConfigValuePtrSafe(const std::string&);
+ void* const* getConfigValuePtr(const std::string&);
+ Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
+ void onPluginLoadUnload(const std::string& name, bool load);
static std::string getConfigDir();
static std::string getMainConfigPath();
- SMonitorRule getMonitorRuleFor(const std::string&, const std::string& displayName = "");
+ SMonitorRule getMonitorRuleFor(const CMonitor&);
SWorkspaceRule getWorkspaceRuleFor(CWorkspace*);
std::string getDefaultWorkspaceFor(const std::string&);
@@ -120,15 +111,15 @@ class CConfigManager {
std::string getBoundMonitorStringForWS(const std::string&);
const std::deque& getAllWorkspaceRules();
- std::vector getMatchingRules(CWindow*);
+ std::vector getMatchingRules(CWindow*, bool dynamic = true);
std::vector getMatchingRules(SLayerSurface*);
std::unordered_map m_mAdditionalReservedAreas;
std::unordered_map getAnimationConfig();
- void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
- void addPluginKeyword(HANDLE handle, const std::string& name, std::function fun);
+ void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value);
+ void addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fun, Hyprlang::SHandlerOptions opts = {});
void removePluginConfig(HANDLE handle);
// no-op when done.
@@ -141,7 +132,7 @@ class CConfigManager {
void ensureMonitorStatus();
void ensureVRR(CMonitor* pMonitor = nullptr);
- std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
+ std::string parseKeyword(const std::string&, const std::string&);
void addParseError(const std::string&);
@@ -151,77 +142,65 @@ class CConfigManager {
void handlePluginLoads();
- std::string configCurrentPath;
+ // keywords
+ std::optional handleRawExec(const std::string&, const std::string&);
+ std::optional handleExecOnce(const std::string&, const std::string&);
+ std::optional handleMonitor(const std::string&, const std::string&);
+ std::optional handleBind(const std::string&, const std::string&);
+ std::optional handleUnbind(const std::string&, const std::string&);
+ std::optional handleWindowRule(const std::string&, const std::string&);
+ std::optional handleLayerRule(const std::string&, const std::string&);
+ std::optional handleWindowRuleV2(const std::string&, const std::string&);
+ std::optional handleWorkspaceRules(const std::string&, const std::string&);
+ std::optional handleBezier(const std::string&, const std::string&);
+ std::optional handleAnimation(const std::string&, const std::string&);
+ std::optional handleSource(const std::string&, const std::string&);
+ std::optional handleSubmap(const std::string&, const std::string&);
+ std::optional handleBlurLS(const std::string&, const std::string&);
+ std::optional handleBindWS(const std::string&, const std::string&);
+ std::optional handleEnv(const std::string&, const std::string&);
+ std::optional handlePlugin(const std::string&, const std::string&);
+
+ std::string configCurrentPath;
private:
- std::deque configPaths; // stores all the config paths
- std::unordered_map configModifyTimes; // stores modify times
- std::vector> configDynamicVars; // stores dynamic vars declared by the user
- std::unordered_map configValues;
- std::unordered_map> deviceConfigs; // stores device configs
+ std::unique_ptr m_pConfig;
- std::unordered_map animationConfig; // stores all the animations with their set values
+ std::deque configPaths; // stores all the config paths
+ std::unordered_map configModifyTimes; // stores modify times
- std::string currentCategory = ""; // For storing the category of the current item
+ std::unordered_map 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 execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
- std::vector execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
+ std::vector m_vDeclaredPlugins;
+ std::vector pluginKeywords;
+ std::vector pluginVariables;
- std::vector m_vDeclaredPlugins;
- std::unordered_map>> pluginConfigs; // stores plugin configs
- std::vector pluginKeywords;
+ bool isFirstLaunch = true; // For exec-once
- bool isFirstLaunch = true; // For exec-once
+ std::deque m_dMonitorRules;
+ std::deque m_dWorkspaceRules;
+ std::deque m_dWindowRules;
+ std::deque m_dLayerRules;
+ std::deque m_dBlurLSNamespaces;
- std::deque m_dMonitorRules;
- std::deque m_dWorkspaceRules;
- std::deque m_dWindowRules;
- std::deque m_dLayerRules;
- std::deque m_dBlurLSNamespaces;
+ bool firstExecDispatched = false;
+ bool m_bManualCrashInitiated = false;
+ std::deque firstExecRequests;
- bool firstExecDispatched = false;
- bool m_bManualCrashInitiated = false;
- std::deque firstExecRequests;
-
- std::vector> environmentVariables;
-
- std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
+ std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
// internal methods
- void setDefaultVars();
- void setDefaultAnimationVars();
- void setDeviceDefaultVars(const std::string&);
- void populateEnvironment();
-
- void setAnimForChildren(SAnimationPropertyConfig* const);
- void updateBlurredLS(const std::string&, const bool);
-
- void applyUserDefinedVars(std::string&, const size_t);
- void loadConfigLoadVars();
- SConfigValue getConfigValueSafe(const std::string&);
- SConfigValue getConfigValueSafeDevice(const std::string&, const std::string&, const std::string& fallback = "");
- void parseLine(std::string&);
- void configSetValueSafe(const std::string&, const std::string&);
- void handleDeviceConfig(const std::string&, const std::string&);
- void handleRawExec(const std::string&, const std::string&);
- void handleMonitor(const std::string&, const std::string&);
- void handleBind(const std::string&, const std::string&);
- void handleUnbind(const std::string&, const std::string&);
- void handleWindowRule(const std::string&, const std::string&);
- void handleLayerRule(const std::string&, const std::string&);
- void handleWindowRuleV2(const std::string&, const std::string&);
- void handleWorkspaceRules(const std::string&, const std::string&);
- void handleBezier(const std::string&, const std::string&);
- void handleAnimation(const std::string&, const std::string&);
- void handleSource(const std::string&, const std::string&);
- void handleSubmap(const std::string&, const std::string&);
- void handleBlurLS(const std::string&, const std::string&);
- void handleBindWS(const std::string&, const std::string&);
- void handleEnv(const std::string&, const std::string&);
- void handlePlugin(const std::string&, const std::string&);
+ void setAnimForChildren(SAnimationPropertyConfig* const);
+ void updateBlurredLS(const std::string&, const bool);
+ void setDefaultAnimationVars();
+ std::optional resetHLConfig();
+ std::optional verifyConfigExists();
+ void postConfigReload(const Hyprlang::CParseResult& result);
+ void reload();
};
inline std::unique_ptr g_pConfigManager;
diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp
index 1e149a7a..6d1d9751 100644
--- a/src/config/defaultConfig.hpp
+++ b/src/config/defaultConfig.hpp
@@ -3,11 +3,11 @@
#include
inline const std::string AUTOCONFIG = R"#(
-########################################################################################
-AUTOGENERATED HYPR CONFIG.
-PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
-OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
-########################################################################################
+# #######################################################################################
+# AUTOGENERATED HYPR CONFIG.
+# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
+# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
+# #######################################################################################
#
# Please note not all available settings / options are set here.
@@ -51,7 +51,7 @@ input {
natural_scroll = no
}
- sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
+ sensitivity = 0 # -1.0 to 1.0, 0 means no modification.
}
general {
@@ -119,12 +119,13 @@ gestures {
misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
- force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
+ force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
}
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
-device:epic-mouse-v1 {
+device {
+ name = epic-mouse-v1
sensitivity = -0.5
}
@@ -133,7 +134,7 @@ device:epic-mouse-v1 {
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
-windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
+windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp
index 65b31399..cf648191 100644
--- a/src/debug/CrashReporter.cpp
+++ b/src/debug/CrashReporter.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include "../plugins/PluginSystem.hpp"
@@ -105,21 +106,38 @@ void CrashReporter::createAndSaveCrash(int sig) {
const auto FPATH = std::filesystem::canonical("/proc/self/exe");
#endif
+ std::string addrs = "";
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
- finalCrashReport += std::format("\t#{} | {}\n", i, CALLSTACK[i].desc);
+ // 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__
- 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
- 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
- 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 += Debug::rollingLog;
+ finalCrashReport += Debug::rollingLog.substr(Debug::rollingLog.find("\n") + 1);
const auto HOME = getenv("HOME");
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
@@ -128,21 +146,18 @@ void CrashReporter::createAndSaveCrash(int sig) {
return;
std::ofstream ofs;
- std::string path;
- if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
- if (!std::filesystem::exists(std::string(HOME) + "/.hyprland"))
- std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
+ std::string reportDir;
- path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
- ofs.open(path, std::ios::trunc);
+ if (!CACHE_HOME || std::string(CACHE_HOME).empty())
+ reportDir = std::string(HOME) + "/.cache/hyprland";
+ else
+ reportDir = std::string(CACHE_HOME) + "/hyprland";
- } else {
- if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland"))
- std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
+ if (!std::filesystem::exists(reportDir))
+ std::filesystem::create_directory(reportDir);
+ const auto path = reportDir + "/hyprlandCrashReport" + std::to_string(PID) + ".txt";
- path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
- ofs.open(path, std::ios::trunc);
- }
+ ofs.open(path, std::ios::trunc);
ofs << finalCrashReport;
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index ab15ceae..8f29ae72 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -7,12 +7,13 @@
#include
#include
#include
+#include
#include
#include
-#include
#include
#include
+#include
static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',')
@@ -28,7 +29,7 @@ static std::string getWorkspaceNameFromSpecialID(const int workspaceID) {
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, ' ');
auto allMonitors = false;
@@ -39,7 +40,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
allMonitors = true;
std::string result = "";
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
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": {},
"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->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,
@@ -97,7 +98,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
"workspace: {} ({})\n\treserved: {} "
"{} {} {}\n\tscale: {:.2f}\n\ttransform: "
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\n",
- m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->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->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,
@@ -109,8 +110,8 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
return result;
}
-static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
- const bool isJson = format == HyprCtl::FORMAT_JSON;
+static std::string getGroupedData(CWindow* w, eHyprCtlOutputFormat format) {
+ const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON;
if (!w->m_sGroupData.pNextWindow)
return isJson ? "" : "0";
@@ -133,7 +134,7 @@ static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat form
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 {
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) {
if (g_pCompositor->m_vWindowFocusHistory[i] == wnd)
@@ -142,7 +143,7 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
return -1;
};
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
return std::format(
R"#({{
"address": "0x{:x}",
@@ -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 = "";
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& w : g_pCompositor->m_vWindows) {
@@ -218,10 +219,10 @@ std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
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 PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID);
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
return std::format(R"#({{
"id": {},
"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"; };
- 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 default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : "";
const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : "";
- const std::string gapsIn = (bool)(r.gapsIn) ? std::format(",\n \"gapsIn\": {}", r.gapsIn.value()) : "";
- const std::string gapsOut = (bool)(r.gapsOut) ? std::format(",\n \"gapsOut\": {}", r.gapsOut.value()) : "";
+ const std::string gapsIn = (bool)(r.gapsIn) ?
+ 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 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())) : "";
@@ -266,8 +271,12 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "" : escapeJSONStrings(r.monitor));
const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : "");
const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : "");
- const std::string gapsIn = std::format("\tgapsIn: {}\n", (bool)(r.gapsIn) ? std::to_string(r.gapsIn.value()) : "");
- const std::string gapsOut = std::format("\tgapsOut: {}\n", (bool)(r.gapsOut) ? std::to_string(r.gapsOut.value()) : "");
+ 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),
+ std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) :
+ std::format("\tgapsIn: \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: \n");
const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "");
const std::string border = std::format("\tborder: {}\n", (bool)(r.border) ? boolToString(r.border.value()) : "");
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.rounding) ? boolToString(r.rounding.value()) : "");
@@ -280,7 +289,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
return result;
}
}
-std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
if (!g_pCompositor->m_pLastMonitor)
return "unsafe state";
@@ -293,10 +302,10 @@ std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
return getWorkspaceData(w, format);
}
-std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getWorkspaceData(w.get(), format);
@@ -314,9 +323,9 @@ std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
-std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& r : g_pConfigManager->getAllWorkspaceRules()) {
result += getWorkspaceRuleData(r, format);
@@ -334,24 +343,24 @@ std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
-std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
- return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid";
+ return format == eHyprCtlOutputFormat::FORMAT_JSON ? "{}" : "Invalid";
auto result = getWindowData(PWINDOW, format);
- if (format == HyprCtl::FORMAT_JSON)
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON)
result.pop_back();
return result;
}
-std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n";
for (auto& mon : g_pCompositor->m_vMonitors) {
@@ -422,9 +431,9 @@ std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
-std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& m : g_pLayoutManager->getAllLayoutNames()) {
@@ -444,10 +453,10 @@ std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
-std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n";
result += "\"mice\": [\n";
@@ -603,9 +612,9 @@ std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
-std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
- if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
+ if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
ret += "animations:\n";
for (auto& ac : g_pConfigManager->getAnimationConfig()) {
@@ -656,10 +665,10 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret;
}
-std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[\n\"log\":\"";
result += escapeJSONStrings(Debug::rollingLog);
result += "\"]";
@@ -670,10 +679,10 @@ std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result;
}
-std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts();
- if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
+ if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto& sh : SHORTCUTS)
ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description);
} else {
@@ -693,9 +702,9 @@ std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret;
}
-std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
- if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
+ if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto& kb : g_pKeybindManager->m_lKeybinds) {
ret += "bind";
if (kb.locked)
@@ -741,12 +750,12 @@ std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret;
}
-std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
+std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
auto commitMsg = removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE);
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 +
").\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
}
-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
in = in.substr(in.find_first_of(' ') + 1);
@@ -814,7 +856,7 @@ std::string dispatchRequest(std::string in) {
return "ok";
}
-std::string dispatchKeyword(std::string in) {
+std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
// get rid of the keyword keyword
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);
- 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
- if (COMMAND.contains("input") || COMMAND.contains("device:")) {
+ if (COMMAND.contains("input") || COMMAND.contains("device") || COMMAND == "source") {
g_pInputManager->setKeyboardLayout(); // update kb layout
g_pInputManager->setPointerConfigs(); // update mouse cfgs
g_pInputManager->setTouchDeviceConfigs(); // update touch device cfgs
g_pInputManager->setTabletConfigs(); // update tablets
}
- if (COMMAND.contains("general:layout"))
- g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout
+ static auto* const PLAYOUT = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("general: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;
- if (COMMAND.contains("blur")) {
+ if (COMMAND.contains("blur") || COMMAND == "source") {
for (auto& [m, rd] : g_pHyprOpenGL->m_mMonitorRenderResources) {
rd.blurFBDirty = true;
}
}
// 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) {
g_pHyprRenderer->damageMonitor(m.get());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
@@ -862,7 +907,7 @@ std::string dispatchKeyword(std::string in) {
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);
@@ -877,20 +922,20 @@ std::string reloadRequest(const std::string& request) {
return "ok";
}
-std::string killRequest() {
+std::string killRequest(eHyprCtlOutputFormat format, std::string request) {
g_pInputManager->setClickMode(CLICKMODE_KILL);
return "ok";
}
-std::string splashRequest() {
+std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
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();
- if (format == HyprCtl::FORMAT_NORMAL) {
+ if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
return std::format("{}, {}", (int)CURSORPOS.x, (int)CURSORPOS.y);
} else {
return std::format(R"#(
@@ -905,9 +950,7 @@ std::string cursorPosRequest(HyprCtl::eHyprCtlOutputFormat format) {
return "error";
}
-std::string getReply(std::string);
-
-std::string dispatchBatch(std::string request) {
+std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
// split by ;
request = request.substr(9);
@@ -930,8 +973,8 @@ std::string dispatchBatch(std::string request) {
nextItem();
- while (curitem != "") {
- reply += getReply(curitem);
+ while (curitem != "" || request != "") {
+ reply += g_pHyprCtl->getReply(curitem);
nextItem();
}
@@ -939,7 +982,7 @@ std::string dispatchBatch(std::string request) {
return reply;
}
-std::string dispatchSetCursor(std::string request) {
+std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
const auto SIZESTR = vars[vars.size() - 1];
@@ -971,7 +1014,7 @@ std::string dispatchSetCursor(std::string request) {
return "ok";
}
-std::string switchXKBLayoutRequest(const std::string& request) {
+std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
const auto KB = vars[1];
@@ -1017,7 +1060,7 @@ std::string switchXKBLayoutRequest(const std::string& request) {
return "ok";
}
-std::string dispatchSeterror(std::string request) {
+std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
std::string errorMessage = "";
@@ -1046,13 +1089,14 @@ std::string dispatchSeterror(std::string request) {
return "ok";
}
-std::string dispatchSetProp(std::string request) {
+std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
if (vars.size() < 4)
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)
return "window not found";
@@ -1060,6 +1104,8 @@ std::string dispatchSetProp(std::string request) {
const auto PROP = vars[2];
const auto VAL = vars[3];
+ auto noFocus = PWINDOW->m_sAdditionalConfigData.noFocus;
+
bool lock = false;
if (vars.size() > 4) {
@@ -1089,6 +1135,8 @@ std::string dispatchSetProp(std::string request) {
PWINDOW->m_sAdditionalConfigData.forceNoShadow.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenodim") {
PWINDOW->m_sAdditionalConfigData.forceNoDim.forceSetIgnoreLocked(configStringToInt(VAL), lock);
+ } else if (PROP == "nofocus") {
+ PWINDOW->m_sAdditionalConfigData.noFocus.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "windowdancecompat") {
PWINDOW->m_sAdditionalConfigData.windowDanceCompat.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nomaxsize") {
@@ -1124,13 +1172,19 @@ std::string dispatchSetProp(std::string request) {
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)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
return "ok";
}
-std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
+std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
std::string curitem = "";
auto nextItem = [&]() {
@@ -1150,31 +1204,43 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
nextItem();
nextItem();
- const auto PCFGOPT = g_pConfigManager->getConfigValuePtrSafe(curitem);
+ const auto VAR = g_pConfigManager->getHyprlangConfigValuePtr(curitem);
- if (!PCFGOPT)
+ if (!VAR)
return "no such option";
- if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL)
- return std::format("option {}\n\tint: {}\n\tfloat: {:.5f}\n\tstr: \"{}\"\n\tdata: {:x}\n\tset: {}", curitem, PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue,
- (uintptr_t)PCFGOPT->data.get(), PCFGOPT->set);
- else {
- return std::format(
- R"#(
-{{
- "option": "{}",
- "int": {},
- "float": {:.5f},
- "str": "{}",
- "data": "0x{:x}",
- "set": {}
-}}
-)#",
- curitem, PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue, (uintptr_t)PCFGOPT->data.get(), PCFGOPT->set);
+ const auto VAL = VAR->getValue();
+ const auto TYPE = std::type_index(VAL.type());
+
+ if (format == FORMAT_NORMAL) {
+ if (TYPE == typeid(Hyprlang::INT))
+ return std::format("int: {}\nset: {}", std::any_cast(VAL), VAR->m_bSetByUser);
+ else if (TYPE == typeid(Hyprlang::FLOAT))
+ return std::format("float: {:2f}\nset: {}", std::any_cast(VAL), VAR->m_bSetByUser);
+ else if (TYPE == typeid(Hyprlang::VEC2))
+ return std::format("vec2: [{}, {}]\nset: {}", std::any_cast(VAL).x, std::any_cast(VAL).y, VAR->m_bSetByUser);
+ else if (TYPE == typeid(Hyprlang::STRING))
+ return std::format("str: {}\nset: {}", std::any_cast(VAL), VAR->m_bSetByUser);
+ else if (TYPE == typeid(Hyprlang::CUSTOMTYPE*))
+ return std::format("custom type at: {:x}\nset: {}", (uintptr_t)std::any_cast(VAL), VAR->m_bSetByUser);
+ } else {
+ if (TYPE == typeid(Hyprlang::INT))
+ return std::format("{{\"option\": \"{}\", \"int\": {}, \"set\": {} }}", curitem, std::any_cast(VAL), VAR->m_bSetByUser);
+ else if (TYPE == typeid(Hyprlang::FLOAT))
+ return std::format("{{\"option\": \"{}\", \"float\": {:2f}, \"set\": {} }}", curitem, std::any_cast(VAL), VAR->m_bSetByUser);
+ else if (TYPE == typeid(Hyprlang::VEC2))
+ return std::format("{{\"option\": \"{}\", \"vec2\": [{},{}], \"set\": {} }}", curitem, std::any_cast(VAL).x, std::any_cast(VAL).y,
+ VAR->m_bSetByUser);
+ else if (TYPE == typeid(Hyprlang::STRING))
+ return std::format("{{\"option\": \"{}\", \"str\": \"{}\", \"set\": {} }}", curitem, escapeJSONStrings(std::any_cast(VAL)), VAR->m_bSetByUser);
+ else if (TYPE == typeid(Hyprlang::CUSTOMTYPE*))
+ return std::format("{{\"option\": \"{}\", \"custom\": \"{:x}\", \"set\": {} }}", curitem, (uintptr_t)std::any_cast(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, ' ');
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
@@ -1182,7 +1248,7 @@ std::string decorationRequest(std::string request, HyprCtl::eHyprCtlOutputFormat
return "none";
std::string result = "";
- if (format == HyprCtl::FORMAT_JSON) {
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& wd : PWINDOW->m_dWindowDecorations) {
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 = "";
auto nextItem = [&]() {
@@ -1280,7 +1346,7 @@ std::string dispatchOutput(std::string request) {
return "ok";
}
-std::string dispatchPlugin(std::string request) {
+std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
if (vars.size() < 2)
@@ -1323,7 +1389,7 @@ std::string dispatchPlugin(std::string request) {
return "ok";
}
-std::string dispatchNotify(std::string request) {
+std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
if (vars.size() < 5)
@@ -1364,92 +1430,137 @@ std::string dispatchNotify(std::string request) {
return "ok";
}
-std::string getReply(std::string request) {
- auto format = HyprCtl::FORMAT_NORMAL;
+CHyprCtl::CHyprCtl() {
+ 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 CHyprCtl::registerCommand(SHyprCtlCommand cmd) {
+ return m_vCommands.emplace_back(std::make_shared(cmd));
+}
+
+void CHyprCtl::unregisterCommand(const std::shared_ptr& 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
- if (!request.contains("[[BATCH]]") && request.contains("/")) {
+ if (!request.starts_with("[[BATCH]]") && request.contains("/")) {
long unsigned int sepIndex = 0;
for (const auto& c : request) {
if (c == '/') { // stop at separator
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++;
if (c == 'j')
- format = HyprCtl::FORMAT_JSON;
+ format = eHyprCtlOutputFormat::FORMAT_JSON;
+ if (c == 'r')
+ reloadAll = true;
}
if (sepIndex < request.size())
request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string
}
- if (request.starts_with("monitors"))
- 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);
+ std::string result = "";
- 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);
}
@@ -1460,7 +1571,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
sockaddr_in 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 readBuffer;
@@ -1490,7 +1601,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
std::string reply = "";
try {
- reply = getReply(request);
+ reply = g_pHyprCtl->getReply(request);
} catch (std::exception& e) {
Debug::log(ERR, "Error in request: {}", e.what());
reply = "Err: " + std::string(e.what());
@@ -1500,18 +1611,17 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
close(ACCEPTEDCONNECTION);
- if (g_pConfigManager->m_bWantsMonitorReload) {
+ if (g_pConfigManager->m_bWantsMonitorReload)
g_pConfigManager->ensureMonitorStatus();
- }
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.");
return;
}
@@ -1522,15 +1632,15 @@ void HyprCtl::startHyprCtlSocket() {
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.");
return;
}
// 10 max queued.
- listen(iSocketFD, 10);
+ listen(m_iSocketFD, 10);
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);
}
diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp
index 00cf7c5b..339acd1b 100644
--- a/src/debug/HyprCtl.hpp
+++ b/src/debug/HyprCtl.hpp
@@ -3,24 +3,23 @@
#include "../Compositor.hpp"
#include
#include "../helpers/MiscFunctions.hpp"
+#include
-namespace HyprCtl {
- void startHyprCtlSocket();
- std::string makeDynamicCall(const std::string& input);
+class CHyprCtl {
+ public:
+ CHyprCtl();
- // very simple thread-safe request method
- inline bool requestMade = false;
- inline bool requestReady = false;
- inline std::string request = "";
+ std::string makeDynamicCall(const std::string& input);
+ std::shared_ptr registerCommand(SHyprCtlCommand cmd);
+ void unregisterCommand(const std::shared_ptr& cmd);
+ 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> m_vCommands;
+};
- enum eHyprCtlOutputFormat {
- FORMAT_NORMAL = 0,
- FORMAT_JSON
- };
-};
\ No newline at end of file
+inline std::unique_ptr g_pHyprCtl;
\ No newline at end of file
diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp
index 12f7a575..2968134b 100644
--- a/src/debug/HyprNotificationOverlay.cpp
+++ b/src/debug/HyprNotificationOverlay.cpp
@@ -226,4 +226,8 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
CBox pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
+}
+
+bool CHyprNotificationOverlay::hasAny() {
+ return !m_dNotifications.empty();
}
\ No newline at end of file
diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp
index 84e61f80..7a883f15 100644
--- a/src/debug/HyprNotificationOverlay.hpp
+++ b/src/debug/HyprNotificationOverlay.hpp
@@ -41,6 +41,7 @@ class CHyprNotificationOverlay {
void draw(CMonitor* pMonitor);
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
+ bool hasAny();
private:
CBox drawNotifications(CMonitor* pMonitor);
diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp
index 404904a2..66c430d5 100644
--- a/src/debug/Log.cpp
+++ b/src/debug/Log.cpp
@@ -22,7 +22,7 @@ void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
rollingLog += output + "\n";
- if (!disableLogs || !*disableLogs) {
+ if (!disableLogs || !**disableLogs) {
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
ofs << "[wlr] " << output << "\n";
diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp
index 3d2ed48c..a43d6fee 100644
--- a/src/debug/Log.hpp
+++ b/src/debug/Log.hpp
@@ -21,16 +21,16 @@ enum LogLevel {
};
namespace Debug {
- inline std::string logFile;
- inline int64_t* disableLogs = nullptr;
- inline int64_t* disableTime = nullptr;
- inline bool disableStdout = false;
- inline bool trace = false;
- inline bool shuttingDown = false;
+ inline std::string logFile;
+ inline int64_t* const* disableLogs = nullptr;
+ inline int64_t* const* disableTime = nullptr;
+ inline bool disableStdout = false;
+ inline bool trace = false;
+ inline bool shuttingDown = false;
- inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
+ 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
void log(LogLevel level, std::format_string fmt, Args&&... args) {
if (level == TRACE && !trace)
@@ -52,7 +52,7 @@ namespace Debug {
}
// print date and time to the ofs
- if (disableTime && !*disableTime) {
+ if (disableTime && !**disableTime) {
#ifndef _LIBCPP_VERSION
logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor(std::chrono::system_clock::now())});
#else
@@ -73,7 +73,7 @@ namespace Debug {
if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
- if (!disableLogs || !*disableLogs) {
+ if (!disableLogs || !**disableLogs) {
// log to a file
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
diff --git a/src/events/Events.hpp b/src/events/Events.hpp
index 777bdf9f..8b737f32 100644
--- a/src/events/Events.hpp
+++ b/src/events/Events.hpp
@@ -174,4 +174,7 @@ namespace Events {
// Tearing hints
LISTENER(newTearingHint);
+
+ // Shortcut inhibitor
+ LISTENER(newShortcutInhibitor);
};
diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp
index d6e21d9d..9ef9b025 100644
--- a/src/events/Layers.cpp
+++ b/src/events/Layers.cpp
@@ -142,6 +142,9 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
+ if (layersurface->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
+ g_pInputManager->m_dExclusiveLSes.push_back(layersurface);
+
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
@@ -183,6 +186,11 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
EMIT_HOOK_EVENT("closeLayer", layersurface);
+ std::erase(g_pInputManager->m_dExclusiveLSes, layersurface);
+
+ if (!g_pInputManager->m_dExclusiveLSes.empty())
+ g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface);
+
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp
index 91a0ebda..35721832 100644
--- a/src/events/Misc.cpp
+++ b/src/events/Misc.cpp
@@ -128,6 +128,8 @@ void Events::listener_destroyDrag(void* owner, void* data) {
g_pInputManager->m_sDrag.drag = nullptr;
g_pInputManager->m_sDrag.dragIcon = nullptr;
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
+
+ g_pCompositor->focusWindow(g_pCompositor->m_pLastWindow, g_pCompositor->m_pLastWindow ? g_pXWaylandManager->getWindowSurface(g_pCompositor->m_pLastWindow) : nullptr);
}
void Events::listener_mapDragIcon(void* owner, void* data) {
@@ -175,11 +177,17 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
Debug::log(LOG, "PowerMgr set mode!");
- const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
+ const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
+ const auto PMONITOR = g_pCompositor->getMonitorFromOutput(EVENT->output);
- wlr_output_enable(EVENT->output, EVENT->mode == 1);
+ if (!PMONITOR) {
+ Debug::log(ERR, "Invalid powerMgrSetMode output");
+ return;
+ }
- if (!wlr_output_commit(EVENT->output))
+ wlr_output_state_set_enabled(PMONITOR->state.wlr(), EVENT->mode == 1);
+
+ if (!PMONITOR->state.commit())
Debug::log(ERR, "Couldn't set power mode");
}
@@ -225,16 +233,7 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
}
void Events::listener_newTearingHint(wl_listener* listener, void* data) {
- const auto TCTL = (wlr_tearing_control_v1*)data;
-
- const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface);
-
- if (!PWINDOW) {
- Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
- return;
- }
-
- Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)data);
+ Debug::log(LOG, "New tearing hint at {:x}", (uintptr_t)data);
const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique()).get();
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->pWlrHint->events.destroy,
[&](void* owner, void* data) {
- Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
+ Debug::log(LOG, "Destroyed {:x} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
},
@@ -256,10 +255,27 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
if (PWINDOW) {
- PWINDOW->m_bTearingHint = TEARINGHINT->pWlrHint->hint;
+ PWINDOW->m_bTearingHint = (bool)TEARINGHINT->pWlrHint->current;
- Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->hint);
+ Debug::log(LOG, "Hint {:x} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->current);
}
},
NEWCTRL, "TearingController");
}
+
+void Events::listener_newShortcutInhibitor(wl_listener* listener, void* data) {
+ const auto INHIBITOR = (wlr_keyboard_shortcuts_inhibitor_v1*)data;
+
+ const auto PINH = &g_pKeybindManager->m_lShortcutInhibitors.emplace_back();
+ PINH->hyprListener_destroy.initCallback(
+ &INHIBITOR->events.destroy,
+ [](void* owner, void* data) {
+ const auto OWNER = (SShortcutInhibitor*)owner;
+ g_pKeybindManager->m_lShortcutInhibitors.remove(*OWNER);
+ },
+ PINH, "ShortcutInhibitor");
+
+ PINH->pWlrInhibitor = INHIBITOR;
+
+ Debug::log(LOG, "New shortcut inhibitor for surface {:x}", (uintptr_t)INHIBITOR->surface);
+}
diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp
index 13f3f829..01ea24f8 100644
--- a/src/events/Monitors.cpp
+++ b/src/events/Monitors.cpp
@@ -109,7 +109,7 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) {
w->m_iLastSurfaceMonitorID = -1;
- w->updateSurfaceOutputs();
+ w->updateSurfaceScaleTransformDetails();
}
}
}
@@ -147,12 +147,12 @@ void Events::listener_monitorFrame(void* owner, void* data) {
PMONITOR->tearingState.frameScheduledWhileBusy = false;
}
- static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
- static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
+ static auto* const PENABLERAT = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time");
+ static auto* const PRATSAFE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone");
PMONITOR->lastPresentationTimer.reset();
- if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
+ if (**PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
if (!PMONITOR->RATScheduled) {
// render
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);
- if (max + *PRATSAFE > 1000.0 / PMONITOR->refreshRate)
+ if (max + **PRATSAFE > 1000.0 / PMONITOR->refreshRate)
return;
const auto MSLEFT = 1000.0 / PMONITOR->refreshRate - PMONITOR->lastPresentationTimer.getMillis();
PMONITOR->RATScheduled = true;
- const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE);
+ const auto ESTRENDERTIME = std::ceil(avg + **PRATSAFE);
const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
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 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) {
diff --git a/src/events/Popups.cpp b/src/events/Popups.cpp
index bcdb1808..41707b6a 100644
--- a/src/events/Popups.cpp
+++ b/src/events/Popups.cpp
@@ -55,7 +55,7 @@ void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
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_destroyPopupXDG.initCallback(&popup->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");
@@ -228,6 +228,11 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
void Events::listener_commitPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
+ if (PPOPUP->popup->base->initial_commit) {
+ wlr_xdg_surface_schedule_configure(PPOPUP->popup->base);
+ return;
+ }
+
if (g_pCompositor->windowValidMapped(PPOPUP->parentWindow)) {
PPOPUP->lx = PPOPUP->parentWindow->m_vRealPosition.vec().x;
PPOPUP->ly = PPOPUP->parentWindow->m_vRealPosition.vec().y;
diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp
index ce5103ee..81c5c800 100644
--- a/src/events/Windows.cpp
+++ b/src/events/Windows.cpp
@@ -40,17 +40,16 @@ void setAnimToMove(void* data) {
void Events::listener_mapWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
- static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
- static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
- static auto* const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
- static auto* const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
- static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
- static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex")->strValue;
- static auto* const PNEWTAKESOVERFS = &g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen")->intValue;
+ static auto* const PINACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity");
+ static auto* const PACTIVEALPHA = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:active_opacity");
+ static auto* const PDIMSTRENGTH = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("decoration:dim_strength");
+ static auto* const PSWALLOW = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:enable_swallow");
+ static auto* const PSWALLOWREGEX = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("misc:swallow_regex");
+ static auto* const PSWALLOWEXREGEX = (Hyprlang::STRING const*)g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex");
+ static auto* const PNEWTAKESOVERFS = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen");
auto PMONITOR = g_pCompositor->m_pLastMonitor;
- const auto PWORKSPACE =
- PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
+ auto PWORKSPACE = PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
PWINDOW->m_iMonitorID = PMONITOR->ID;
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
PWINDOW->m_bIsMapped = true;
@@ -101,7 +100,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
// window rules
- const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
+ const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW, false);
std::string requestedWorkspace = "";
bool workspaceSilent = false;
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen ||
@@ -173,13 +172,23 @@ void Events::listener_mapWindow(void* owner, void* data) {
} else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.starts_with("nofocus")) {
- PWINDOW->m_bNoFocus = true;
+ PWINDOW->m_sAdditionalConfigData.noFocus = true;
} else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true;
- } else if (r.szRule.starts_with("nofullscreenrequest")) {
- PWINDOW->m_bNoFullscreenRequest = true;
- } else if (r.szRule.starts_with("nomaximizerequest")) {
- PWINDOW->m_bNoMaximizeRequest = true;
+ } else if (r.szRule.starts_with("suppressevent")) {
+ CVarList vars(r.szRule, 0, 's', true);
+ for (size_t i = 1; i < vars.size(); ++i) {
+ if (vars[i] == "fullscreen")
+ PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN;
+ else if (vars[i] == "maximize")
+ PWINDOW->m_eSuppressedEvents |= SUPPRESS_MAXIMIZE;
+ else if (vars[i] == "activate")
+ PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
+ else if (vars[i] == "activatefocus")
+ PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
+ else
+ Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
+ }
} else if (r.szRule == "fullscreen") {
requestsFullscreen = true;
overridingNoFullscreen = true;
@@ -270,6 +279,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!pWorkspace)
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName);
+ PWORKSPACE = pWorkspace;
+
PWINDOW->m_iWorkspaceID = pWorkspace->m_iID;
PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID;
@@ -443,9 +454,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow;
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) {
- PWINDOW->m_bNoFocus = false;
- PWINDOW->m_bNoInitialFocus = false;
- PWINDOW->m_bX11ShouldntFocus = false;
+ PWINDOW->m_sAdditionalConfigData.noFocus = false;
+ PWINDOW->m_bNoInitialFocus = false;
+ PWINDOW->m_bX11ShouldntFocus = false;
}
// check LS focus grab
@@ -454,9 +465,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
PWINDOW->m_bNoInitialFocus = true;
if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
- if (*PNEWTAKESOVERFS == 0)
+ if (**PNEWTAKESOVERFS == 0)
PWINDOW->m_bNoInitialFocus = true;
- else if (*PNEWTAKESOVERFS == 2)
+ else if (**PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID);
else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
requestsMaximize = true;
@@ -464,14 +475,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
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 &&
(!PFORCEFOCUS || PFORCEFOCUS == PWINDOW)) {
g_pCompositor->focusWindow(PWINDOW);
- PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
- PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH);
+ PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(**PACTIVEALPHA);
+ PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : **PDIMSTRENGTH);
} else {
- PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
+ PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(**PINACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(0);
}
@@ -504,8 +515,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
"XWayland Window Late");
}
- if ((requestsFullscreen && (!PWINDOW->m_bNoFullscreenRequest || overridingNoFullscreen)) || (requestsMaximize && (!PWINDOW->m_bNoMaximizeRequest || overridingNoMaximize)) ||
- requestsFakeFullscreen) {
+ if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) ||
+ (requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) {
// fix fullscreen on requested (basically do a switcheroo)
if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
@@ -540,7 +551,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
// verify swallowing
- if (*PSWALLOW && *PSWALLOWREGEX != STRVAL_EMPTY) {
+ if (**PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) {
// don't swallow ourselves
std::regex rgx(*PSWALLOWREGEX);
if (!std::regex_match(g_pXWaylandManager->getAppIDClass(PWINDOW), rgx)) {
@@ -587,7 +598,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (finalFound) {
bool valid = std::regex_match(g_pXWaylandManager->getAppIDClass(finalFound), rgx);
- if (*PSWALLOWEXREGEX != STRVAL_EMPTY) {
+ if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) {
std::regex exc(*PSWALLOWEXREGEX);
valid = valid && !std::regex_match(g_pXWaylandManager->getTitle(finalFound), exc);
@@ -639,7 +650,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
- 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
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
@@ -793,6 +805,11 @@ void Events::listener_ackConfigure(void* owner, void* data) {
void Events::listener_commitWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
+ if (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->initial_commit) {
+ wlr_xdg_toplevel_set_size(PWINDOW->m_uSurface.xdg->toplevel, 0, 0);
+ return;
+ }
+
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
return;
@@ -803,8 +820,6 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_pPendingSizeAck.reset();
}
- PWINDOW->updateSurfaceOutputs();
-
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
@@ -906,7 +921,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
return;
}
- if (PWINDOW->isHidden() || PWINDOW->m_bNoFullscreenRequest)
+ if (PWINDOW->isHidden() || (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
return;
bool requestedFullState = false;
@@ -960,7 +975,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
void Events::listener_activateXDG(wl_listener* listener, void* data) {
const auto E = (wlr_xdg_activation_v1_request_activate_event*)data;
- static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
+ static auto* 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);
@@ -969,7 +984,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(E->surface);
- if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow)
+ if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE))
return;
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
@@ -977,7 +992,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
PWINDOW->m_bIsUrgent = true;
- if (!*PFOCUSONACTIVATE)
+ if (!**PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY))
return;
if (PWINDOW->m_bIsFloating)
@@ -990,7 +1005,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
void Events::listener_activateX11(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner;
- static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
+ static auto* const PFOCUSONACTIVATE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("misc:focus_on_activate");
Debug::log(LOG, "X11 Activate request for window {}", PWINDOW);
@@ -1001,17 +1016,20 @@ void Events::listener_activateX11(void* owner, void* data) {
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID())
return;
+ if (!wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))
+ return;
+
g_pCompositor->focusWindow(PWINDOW);
return;
}
- if (PWINDOW == g_pCompositor->m_pLastWindow)
+ if (PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE))
return;
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
EMIT_HOOK_EVENT("urgent", PWINDOW);
- if (!*PFOCUSONACTIVATE)
+ if (!**PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY))
return;
if (PWINDOW->m_bIsFloating)
@@ -1052,13 +1070,10 @@ void Events::listener_configureX11(void* owner, void* data) {
PWINDOW->m_vRealPosition.setValueAndWarp(LOGICALPOS);
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height));
- static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
- if (*PXWLFORCESCALEZERO) {
- if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
- const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
+ static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling");
+ if (**PXWLFORCESCALEZERO) {
+ if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
- PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
- }
}
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
@@ -1106,7 +1121,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
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});
@@ -1121,7 +1136,7 @@ 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)
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) {
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
@@ -1139,8 +1154,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goalv();
- PWINDOW->m_vReportedSize = PWINDOW->m_vRealSize.goalv();
- PWINDOW->m_vPendingReportedSize = PWINDOW->m_vReportedSize;
+ PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goalv();
}
}
@@ -1211,7 +1225,7 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
void Events::listener_requestMaximize(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner;
- if (PWINDOW->m_bNoMaximizeRequest)
+ if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)
return;
Debug::log(LOG, "Maximize request for {}", PWINDOW);
diff --git a/src/helpers/AnimatedVariable.cpp b/src/helpers/AnimatedVariable.cpp
index 50de0149..740e604f 100644
--- a/src/helpers/AnimatedVariable.cpp
+++ b/src/helpers/AnimatedVariable.cpp
@@ -75,6 +75,9 @@ float CAnimatedVariable::getPercent() {
}
float CAnimatedVariable::getCurveValue() {
+ if (!m_bIsBeingAnimated)
+ return 1.f;
+
const auto SPENT = getPercent();
if (SPENT >= 1.f)
diff --git a/src/helpers/Box.cpp b/src/helpers/Box.cpp
index 3d57bc79..59578f23 100644
--- a/src/helpers/Box.cpp
+++ b/src/helpers/Box.cpp
@@ -1,4 +1,8 @@
#include "Box.hpp"
+
+#include
+#include
+
wlr_box CBox::wlr() {
CBox rounded = roundInternal();
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
@@ -105,6 +109,13 @@ CBox& CBox::expand(const double& value) {
return *this;
}
+CBox& CBox::noNegativeSize() {
+ std::clamp(w, 0.0, std::numeric_limits::infinity());
+ std::clamp(h, 0.0, std::numeric_limits::infinity());
+
+ return *this;
+}
+
CBox CBox::roundInternal() {
float newW = x + w - std::floor(x);
float newH = y + h - std::floor(y);
diff --git a/src/helpers/Box.hpp b/src/helpers/Box.hpp
index 5cb7f17f..fd31a7b7 100644
--- a/src/helpers/Box.hpp
+++ b/src/helpers/Box.hpp
@@ -51,6 +51,7 @@ class CBox {
CBox& transform(const wl_output_transform t, double w, double h);
CBox& addExtents(const SWindowDecorationExtents& e);
CBox& expand(const double& value);
+ CBox& noNegativeSize();
CBox copy() const;
@@ -73,6 +74,8 @@ class CBox {
double height;
};
+ double rot = 0; /* rad, ccw */
+
//
bool operator==(const CBox& rhs) const {
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp
index 5eb99bfd..2905ce2b 100644
--- a/src/helpers/MiscFunctions.cpp
+++ b/src/helpers/MiscFunctions.cpp
@@ -159,6 +159,13 @@ void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, const
Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString);
}
+void removeWLSignal(wl_listener* pListener) {
+ wl_list_remove(&pListener->link);
+ wl_list_init(&pListener->link);
+
+ Debug::log(LOG, "Removed listener {:x}", (uintptr_t)pListener);
+}
+
void handleNoop(struct wl_listener* listener, void* data) {
// Do nothing
}
diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp
index 1ccbdc0e..23fc6e5a 100644
--- a/src/helpers/MiscFunctions.hpp
+++ b/src/helpers/MiscFunctions.hpp
@@ -15,6 +15,7 @@ struct SCallstackFrameInfo {
std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
+void removeWLSignal(wl_listener*);
std::string escapeJSONStrings(const std::string& str);
std::string removeBeginEndSpacesTabs(std::string);
bool isNumber(const std::string&, bool allowfloat = false);
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index 3b4f4016..2dd2a2d9 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -1,5 +1,7 @@
#include "Monitor.hpp"
+#include "MiscFunctions.hpp"
+
#include "../Compositor.hpp"
int ratHandler(void* data) {
@@ -8,7 +10,7 @@ int ratHandler(void* data) {
return 1;
}
-CMonitor::CMonitor() {
+CMonitor::CMonitor() : state(this) {
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
if (m_bEnabled) {
- wlr_output_enable(output, 1);
- wlr_output_commit(output);
+ wlr_output_state_set_enabled(state.wlr(), true);
+ state.commit();
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
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))
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
// get monitor rule that matches
- SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");
+ SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
- wlr_output_set_scale(output, 1);
- wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
+ wlr_output_state_set_scale(state.wlr(), 1);
+ wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
auto PREFSTATE = wlr_output_preferred_mode(output);
@@ -72,9 +78,9 @@ void CMonitor::onConnect(bool noRule) {
wlr_output_mode* mode;
wl_list_for_each(mode, &output->modes, link) {
- wlr_output_set_mode(output, PREFSTATE);
+ wlr_output_state_set_mode(state.wlr(), mode);
- if (!wlr_output_test(output))
+ if (!wlr_output_test_state(output, state.wlr()))
continue;
PREFSTATE = mode;
@@ -83,13 +89,13 @@ void CMonitor::onConnect(bool noRule) {
}
if (PREFSTATE)
- wlr_output_set_mode(output, PREFSTATE);
+ wlr_output_state_set_mode(state.wlr(), PREFSTATE);
else
Debug::log(WARN, "No mode found for disabled output {}", output->name);
- wlr_output_enable(output, 0);
+ wlr_output_state_set_enabled(state.wlr(), 0);
- if (!wlr_output_commit(output))
+ if (!state.commit())
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
m_bEnabled = false;
@@ -130,13 +136,28 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true;
- wlr_output_enable(output, 1);
+ wlr_output_state_set_enabled(state.wlr(), 1);
// set mode, also applies
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
- wlr_output_commit(output);
+ for (const auto& PTOUCHDEV : g_pInputManager->m_lTouchDevices) {
+ if (matchesStaticSelector(PTOUCHDEV.boundOutput)) {
+ Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV.name, szName);
+ wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTOUCHDEV.pWlrDevice, output);
+ }
+ }
+
+ for (const auto& PTABLET : g_pInputManager->m_lTablets) {
+ if (matchesStaticSelector(PTABLET.boundOutput)) {
+ Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName);
+ wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output);
+ }
+ }
+
+ if (!state.commit())
+ Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
@@ -162,6 +183,7 @@ void CMonitor::onConnect(bool noRule) {
//
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
+ g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)});
EMIT_HOOK_EVENT("monitorAdded", this);
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
@@ -283,9 +305,10 @@ void CMonitor::onDisconnect(bool destroy) {
if (!destroy)
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
- wlr_output_enable(output, false);
+ wlr_output_state_set_enabled(state.wlr(), false);
- wlr_output_commit(output);
+ if (!state.commit())
+ Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor == this)
g_pCompositor->setActiveMonitor(BACKUPMON);
@@ -307,13 +330,11 @@ void CMonitor::onDisconnect(bool destroy) {
}
void CMonitor::addDamage(const pixman_region32_t* rg) {
- static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
- if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
+ static auto* const PZOOMFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor");
+ if (**PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
wlr_damage_ring_add_whole(&damage);
g_pCompositor->scheduleFrameForMonitor(this);
- }
-
- if (wlr_damage_ring_add(&damage, rg))
+ } else if (wlr_damage_ring_add(&damage, rg))
g_pCompositor->scheduleFrameForMonitor(this);
}
@@ -322,8 +343,8 @@ void CMonitor::addDamage(const CRegion* rg) {
}
void CMonitor::addDamage(const CBox* box) {
- static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
- if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
+ static auto* const PZOOMFACTOR = (Hyprlang::FLOAT* const*)g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor");
+ if (**PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
wlr_damage_ring_add_whole(&damage);
g_pCompositor->scheduleFrameForMonitor(this);
}
@@ -336,6 +357,19 @@ bool CMonitor::isMirror() {
return pMirrorOf != nullptr;
}
+bool CMonitor::matchesStaticSelector(const std::string& selector) const {
+ if (selector.starts_with("desc:")) {
+ // match by description
+ const auto DESCRIPTIONSELECTOR = selector.substr(5);
+ 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() {
for (size_t i = 1; i < INT32_MAX; ++i) {
if (g_pCompositor->getWorkspaceByID(i))
@@ -415,7 +449,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = nullptr;
// set rule
- const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName, this->output->description ? this->output->description : "");
+ const auto RULE = g_pConfigManager->getMonitorRuleFor(*this);
vecPosition = RULE.offset;
@@ -502,7 +536,7 @@ float CMonitor::getDefaultScale() {
return 1;
}
-void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove) {
+void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove, bool noFocus) {
if (!pWorkspace)
return;
@@ -533,13 +567,13 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
}
}
- if (!g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
- static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
+ if (!noFocus && !g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
+ static auto* const PFOLLOWMOUSE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("input:follow_mouse");
CWindow* pWindow = pWorkspace->getLastFocusedWindow();
if (!pWindow) {
- if (*PFOLLOWMOUSE == 1)
- pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
+ if (**PFOLLOWMOUSE == 1)
+ pWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!pWindow)
pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
@@ -569,8 +603,8 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
g_pCompositor->updateSuspendedStates();
}
-void CMonitor::changeWorkspace(const int& id, bool internal) {
- changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal);
+void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) {
+ changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus);
}
void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
@@ -621,7 +655,7 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
w->m_iMonitorID = ID;
- w->updateSurfaceOutputs();
+ w->updateSurfaceScaleTransformDetails();
const auto MIDDLE = w->middle();
if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) {
@@ -678,3 +712,32 @@ void CMonitor::updateMatrix() {
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
}
}
+
+CMonitorState::CMonitorState(CMonitor* owner) {
+ m_pOwner = owner;
+ wlr_output_state_init(&m_state);
+}
+
+CMonitorState::~CMonitorState() {
+ wlr_output_state_finish(&m_state);
+}
+
+wlr_output_state* CMonitorState::wlr() {
+ return &m_state;
+}
+
+void CMonitorState::clear() {
+ wlr_output_state_finish(&m_state);
+ m_state = {0};
+ wlr_output_state_init(&m_state);
+}
+
+bool CMonitorState::commit() {
+ bool ret = wlr_output_commit_state(m_pOwner->output, &m_state);
+ clear();
+ return ret;
+}
+
+bool CMonitorState::test() {
+ return wlr_output_test_state(m_pOwner->output, &m_state);
+}
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 2b196c96..051c5305 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -25,6 +25,25 @@ struct SMonitorRule {
std::optional