Compare commits

..

10 Commits

Author SHA1 Message Date
Vaxry
4520b30d49 version: bump to 0.44.1 2024-10-09 13:54:39 +01:00
trianta
8405aa111d output: update state even if no owner exists (#8044) 2024-10-09 13:47:52 +01:00
Vaxry
ad46257cce output/xdg-output: avoid sending events to released globals
ref #6835
2024-10-09 13:47:52 +01:00
Vaxry
0cfbe618b5 keyboard: update group state on change for the sym resolve state
fixes #8038
2024-10-09 13:47:52 +01:00
Vaxry
7d0944acdf defaultConfig: add a nofocus rule for weird X windows
ref #6543
2024-10-09 13:47:52 +01:00
Vaxry
b9990468f3 pointer: expand sw cursor damage box
fixes #8031

just a bit, rounding errors I guess
2024-10-09 13:47:52 +01:00
vaxerski
736a8735b3 keybinds: fixup xkb_states for resolve_by_sym
fixes #7750
2024-10-09 13:47:52 +01:00
Vaxry
b54eecbd79 config: give simple help for super+q not working
only on default config :P
2024-10-09 13:47:52 +01:00
Ikalco
657aeb3946 screencopy: fix screencopy frames not being cleaned up (#8017)
---------

Co-authored-by: Vaxry <vaxry@vaxry.net>
2024-10-09 13:47:52 +01:00
Aqa-Ib
6807430b18 layout: fix auto group when opening a new window in a non-focused workspace using window rules (#8006) 2024-10-09 13:47:52 +01:00
257 changed files with 4589 additions and 8206 deletions

View File

@@ -1,101 +0,0 @@
WarningsAsErrors: '*'
HeaderFilterRegex: '.*\.hpp'
FormatStyle: file
Checks: >
-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
-bugprone-forward-declararion-namespace,
-bugprone-forward-declararion-namespace,
-bugprone-macro-parentheses,
-bugprone-narrowing-conversions,
-bugprone-branch-clone,
-bugprone-assignment-in-if-condition,
concurrency-*,
-concurrency-mt-unsafe,
cppcoreguidelines-*,
-cppcoreguidelines-owning-memory,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-avoid-const-or-ref-data-members,
-cppcoreguidelines-non-private-member-variables-in-classes,
-cppcoreguidelines-avoid-goto,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-special-member-functions,
-cppcoreguidelines-explicit-virtual-functions,
-cppcoreguidelines-avoid-c-arrays,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-narrowing-conversions,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-member-init,
-cppcoreguidelines-macro-usage,
-cppcoreguidelines-macro-to-enum,
-cppcoreguidelines-init-variables,
-cppcoreguidelines-pro-type-cstyle-cast,
-cppcoreguidelines-pro-type-vararg,
-cppcoreguidelines-pro-type-reinterpret-cast,
google-global-names-in-headers,
-google-readability-casting,
google-runtime-operator,
misc-*,
-misc-unused-parameters,
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
-misc-include-cleaner,
-misc-use-anonymous-namespace,
-misc-const-correctness,
modernize-*,
-modernize-return-braced-init-list,
-modernize-use-trailing-return-type,
-modernize-use-using,
-modernize-use-override,
-modernize-avoid-c-arrays,
-modernize-macro-to-enum,
-modernize-loop-convert,
-modernize-use-nodiscard,
-modernize-pass-by-value,
-modernize-use-auto,
performance-*,
-performance-avoid-endl,
-performance-unnecessary-value-param,
portability-std-allocator-const,
readability-*,
-readability-function-cognitive-complexity,
-readability-function-size,
-readability-identifier-length,
-readability-magic-numbers,
-readability-uppercase-literal-suffix,
-readability-braces-around-statements,
-readability-redundant-access-specifiers,
-readability-else-after-return,
-readability-container-data-pointer,
-readability-implicit-bool-conversion,
-readability-avoid-nested-conditional-operator,
-readability-redundant-member-init,
-readability-redundant-string-init,
-readability-avoid-const-params-in-decls,
-readability-named-parameter,
-readability-convert-member-functions-to-static,
-readability-qualified-auto,
-readability-make-member-function-const,
-readability-isolate-declaration,
-readability-inconsistent-declaration-parameter-name,
-clang-diagnostic-error,
CheckOptions:
performance-for-range-copy.WarnOnAllAutoCopies: true
performance-inefficient-string-concatenation.StrictMode: true
readability-braces-around-statements.ShortStatementLines: 0
readability-identifier-naming.ClassCase: CamelCase
readability-identifier-naming.ClassIgnoredRegexp: I.*
readability-identifier-naming.ClassPrefix: C # We can't use regex here?!?!?!?
readability-identifier-naming.EnumCase: CamelCase
readability-identifier-naming.EnumPrefix: e
readability-identifier-naming.EnumConstantCase: UPPER_CASE
readability-identifier-naming.FunctionCase: camelBack
readability-identifier-naming.NamespaceCase: CamelCase
readability-identifier-naming.NamespacePrefix: N
readability-identifier-naming.StructPrefix: S
readability-identifier-naming.StructCase: CamelCase

View File

@@ -33,9 +33,7 @@ runs:
libfontenc \ libfontenc \
libglvnd \ libglvnd \
libinput \ libinput \
libjxl \
libliftoff \ libliftoff \
libwebp \
libxcursor \ libxcursor \
libxcvt \ libxcvt \
libxfont2 \ libxfont2 \
@@ -60,8 +58,7 @@ runs:
xcb-util \ xcb-util \
xcb-util-image \ xcb-util-image \
libzip \ libzip \
librsvg \ librsvg
re2
- name: Get hyprwayland-scanner-git - name: Get hyprwayland-scanner-git
shell: bash shell: bash
@@ -72,11 +69,6 @@ runs:
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
cmake --install build cmake --install build
- name: Get hyprgraphics-git
shell: bash
run: |
git clone https://github.com/hyprwm/hyprgraphics && cd hyprgraphics && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprgraphics && cmake --install build
- name: Get hyprutils-git - name: Get hyprutils-git
shell: bash shell: bash
run: | run: |

View File

@@ -1,9 +1,3 @@
<!--
BEFORE you submit your PR, please check out the PR guidelines
on our wiki: https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/
-->
#### Describe your PR, what does it fix/add? #### Describe your PR, what does it fix/add?

View File

@@ -39,7 +39,7 @@ jobs:
tar -cvf Hyprland.tar.xz hyprland tar -cvf Hyprland.tar.xz hyprland
- name: Release - name: Release
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: Build archive name: Build archive
path: Hyprland.tar.xz path: Hyprland.tar.xz

View File

@@ -17,14 +17,14 @@ jobs:
run: sudo apt install pandoc run: sudo apt install pandoc
- name: Clone repository - name: Clone repository
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
token: ${{ secrets.PAT }} token: ${{ secrets.PAT }}
- name: Build man pages - name: Build man pages
run: make man run: make man
- uses: stefanzweifel/git-auto-commit-action@v5 - uses: stefanzweifel/git-auto-commit-action@v4
name: Commit name: Commit
with: with:
commit_message: "[gha] build man pages" commit_message: "[gha] build man pages"

View File

@@ -12,8 +12,7 @@ jobs:
matrix: matrix:
package: package:
- hyprland - hyprland
# - hyprland-cross # cross compiling fails due to qt - hyprland-cross
# failure chain: hyprland-qtutils -> qt6.qtsvg -> qt6.qtbase -> psqlodbc & qt6.qttranslations
- xdg-desktop-portal-hyprland - xdg-desktop-portal-hyprland
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clone repository - name: Clone repository
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
token: ${{ secrets.PAT }} token: ${{ secrets.PAT }}
@@ -22,6 +22,6 @@ jobs:
run: nix/update-inputs.sh run: nix/update-inputs.sh
- name: Commit - name: Commit
uses: stefanzweifel/git-auto-commit-action@v5 uses: stefanzweifel/git-auto-commit-action@v4
with: with:
commit_message: "[gha] Nix: update inputs" commit_message: "[gha] Nix: update inputs"

View File

@@ -11,7 +11,7 @@ jobs:
steps: steps:
- name: Checkout Hyprland - name: Checkout Hyprland
id: checkout id: checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
@@ -20,6 +20,7 @@ jobs:
run: | run: |
git fetch --unshallow || echo "failed unshallowing" git fetch --unshallow || echo "failed unshallowing"
bash -c scripts/generateVersion.sh bash -c scripts/generateVersion.sh
mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
- name: Create tarball with submodules - name: Create tarball with submodules
id: tar id: tar

View File

@@ -13,7 +13,7 @@ jobs:
security-events: write security-events: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Scan with Flawfinder - name: Scan with Flawfinder
uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c

View File

@@ -19,7 +19,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v5
with: with:
repo-token: ${{ secrets.STALEBOT_PAT }} repo-token: ${{ secrets.STALEBOT_PAT }}
stale-issue-label: "stale" stale-issue-label: "stale"

4
.gitignore vendored
View File

@@ -14,7 +14,6 @@ _deps
build/ build/
result* result*
/.pre-commit-config.yaml
/.vscode/ /.vscode/
/.idea/ /.idea/
.envrc .envrc
@@ -40,6 +39,3 @@ PKGBUILD
src/version.h src/version.h
hyprpm/Makefile hyprpm/Makefile
hyprctl/Makefile hyprctl/Makefile
**/.#*.*
**/#*.*#

View File

@@ -15,7 +15,6 @@ include(GNUInstallDirs)
set(HYPRLAND_VERSION ${VER}) set(HYPRLAND_VERSION ${VER})
set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(PREFIX ${CMAKE_INSTALL_PREFIX})
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
set(BINDIR ${CMAKE_INSTALL_BINDIR})
configure_file(hyprland.pc.in hyprland.pc @ONLY) configure_file(hyprland.pc.in hyprland.pc @ONLY)
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
@@ -72,8 +71,6 @@ else()
message(STATUS "Configuring Hyprland in Release with CMake") message(STATUS "Configuring Hyprland in Release with CMake")
endif() endif()
add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}")
include_directories(. "src/" "protocols/") include_directories(. "src/" "protocols/")
set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD 26)
@@ -101,17 +98,11 @@ else()
endif() endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1)
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2)
pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine)
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.2.3)
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}")
add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}")
add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}")
add_compile_definitions(HYPRGRAPHICS_VERSION="${hyprgraphics_dep_VERSION}")
pkg_check_modules( pkg_check_modules(
deps deps
@@ -130,7 +121,9 @@ pkg_check_modules(
libinput libinput
gbm gbm
gio-2.0 gio-2.0
re2) hyprlang>=0.3.2
hyprcursor>=0.1.7
hyprutils>=0.2.3)
find_package(hyprwayland-scanner 0.3.10 REQUIRED) find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -226,15 +219,6 @@ if(NO_SYSTEMD)
else() else()
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
add_compile_definitions(USES_SYSTEMD) add_compile_definitions(USES_SYSTEMD)
# session file -uwsm
if(NO_UWSM)
message(STATUS "UWSM support is disabled...")
else()
message(STATUS "UWSM support is enabled (NO_UWSM not defined)...")
install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
endif()
endif() endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})
@@ -248,7 +232,7 @@ target_precompile_headers(Hyprland PRIVATE
message(STATUS "Setting link libraries") message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::hyprgraphics_dep PkgConfig::deps) target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps)
if(udis_dep_FOUND) if(udis_dep_FOUND)
target_link_libraries(Hyprland PkgConfig::udis_dep) target_link_libraries(Hyprland PkgConfig::udis_dep)
else() else()
@@ -290,7 +274,7 @@ endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.4.0) pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0)
if(hyprland_protocols_dep_FOUND) if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
@@ -317,8 +301,6 @@ protocolnew("protocols" "wlr-data-control-unstable-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true)
protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
protocolnew("protocols" "wayland-drm" true) protocolnew("protocols" "wayland-drm" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true)
protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/tearing-control" "tearing-control-v1" false)
protocolnew("staging/fractional-scale" "fractional-scale-v1" false) protocolnew("staging/fractional-scale" "fractional-scale-v1" false)
protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false) protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false)
@@ -349,7 +331,6 @@ protocolnew("staging/drm-lease" "drm-lease-v1" false)
protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false) protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
protocolnew("staging/security-context" "security-context-v1" false)
protocolwayland() protocolwayland()

View File

@@ -1,15 +1,12 @@
PREFIX = /usr/local PREFIX = /usr/local
stub:
@echo "Do not run $(MAKE) directly without any arguments. Please refer to the wiki on how to compile Hyprland."
legacyrenderer: legacyrenderer:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./buildZ
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
legacyrendererdebug: legacyrendererdebug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
release: release:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build

View File

@@ -100,7 +100,7 @@ easy IPC, much more QoL stuff than other compositors and more...
<!-----------------------------------------------------------------------------> <!----------------------------------------------------------------------------->
[Configure]: https://wiki.hyprland.org/Configuring/ [Configure]: https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
[Stars]: https://starchart.cc/hyprwm/Hyprland [Stars]: https://starchart.cc/hyprwm/Hyprland
[Hypr]: https://github.com/hyprwm/Hypr [Hypr]: https://github.com/hyprwm/Hypr

View File

@@ -1 +1 @@
0.46.1 0.44.1

View File

@@ -3,7 +3,7 @@
First of all, please remember to: First of all, please remember to:
- Check that your issue is not a duplicate - Check that your issue is not a duplicate
- Read the [FAQ](https://wiki.hyprland.org/FAQ/) - Read the [FAQ](https://wiki.hyprland.org/FAQ/)
- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/) - Read the [Configuring Page](https://wiki.hyprland.org/Configuring/Configuring-Hyprland)
<br/> <br/>

View File

@@ -0,0 +1,14 @@
[Unit]
Description=Hyprland - Tiling compositor with the looks
Documentation=man:Hyprland(1)
BindsTo=graphical-session.target
Before=graphical-session.target
Wants=graphical-session-pre.target
After=graphical-session-pre.target
[Service]
Type=notify
ExecStart=/usr/bin/Hyprland
ExecStop=/usr/bin/hyprctl dispatch exit
Restart=on-failure
Slice=session.slice

View File

@@ -1,6 +1,5 @@
[Desktop Entry] [Desktop Entry]
Name=Hyprland (uwsm-managed) Name=Hyprland
Comment=An intelligent dynamic tiling Wayland compositor Comment=An intelligent dynamic tiling Wayland compositor
Exec=uwsm start -- hyprland.desktop Exec=systemctl --user start --wait hyprland-session
DesktopNames=Hyprland
Type=Application Type=Application

View File

@@ -1,6 +1,6 @@
# This is an example Hyprland config file. # This is an example Hyprland config file.
# Refer to the wiki for more information. # Refer to the wiki for more information.
# https://wiki.hyprland.org/Configuring/ # https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
# Please note not all available settings / options are set here. # Please note not all available settings / options are set here.
# For a full list, see the wiki # For a full list, see the wiki
@@ -86,12 +86,10 @@ decoration {
active_opacity = 1.0 active_opacity = 1.0
inactive_opacity = 1.0 inactive_opacity = 1.0
shadow { drop_shadow = true
enabled = true shadow_range = 4
range = 4 shadow_render_power = 3
render_power = 3 col.shadow = rgba(1a1a1aee)
color = rgba(1a1a1aee)
}
# https://wiki.hyprland.org/Configuring/Variables/#blur # https://wiki.hyprland.org/Configuring/Variables/#blur
blur { blur {
@@ -105,44 +103,20 @@ decoration {
# https://wiki.hyprland.org/Configuring/Variables/#animations # https://wiki.hyprland.org/Configuring/Variables/#animations
animations { animations {
enabled = yes, please :) enabled = true
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = easeOutQuint,0.23,1,0.32,1 bezier = myBezier, 0.05, 0.9, 0.1, 1.05
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = global, 1, 10, default animation = windows, 1, 7, myBezier
animation = border, 1, 5.39, easeOutQuint animation = windowsOut, 1, 7, default, popin 80%
animation = windows, 1, 4.79, easeOutQuint animation = border, 1, 10, default
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% animation = borderangle, 1, 8, default
animation = windowsOut, 1, 1.49, linear, popin 87% animation = fade, 1, 7, default
animation = fadeIn, 1, 1.73, almostLinear animation = workspaces, 1, 6, default
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, fade
animation = workspacesIn, 1, 1.21, almostLinear, fade
animation = workspacesOut, 1, 1.94, almostLinear, fade
} }
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below

View File

@@ -2,6 +2,4 @@
Name=Hyprland Name=Hyprland
Comment=An intelligent dynamic tiling Wayland compositor Comment=An intelligent dynamic tiling Wayland compositor
Exec=Hyprland Exec=Hyprland
Type=Application Type=Application
DesktopNames=Hyprland
Keywords=tiling;wayland;compositor;

168
flake.lock generated
View File

@@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734364797, "lastModified": 1727261104,
"narHash": "sha256-2h1c+P0v3l0Z/ypUSsAPhU/yiSRgFwjVFODWp0S3d/w=", "narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "8e77618b403a82fde2105a8e3cd7cabe7ef00952", "rev": "b82fdaff917582a9d568969e15e61b398c71e990",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -29,43 +29,6 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"hyprcursor": { "hyprcursor": {
"inputs": { "inputs": {
"hyprlang": [ "hyprlang": [
@@ -79,11 +42,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734364709, "lastModified": 1727532803,
"narHash": "sha256-+2bZJL2u5hva7rSp65OfKJBK+k03T6GB/NCvpoS1OOo=", "narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "f388aacd22be4a6e4d634fbaf6f75eb0713d239a", "rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -92,32 +55,6 @@
"type": "github" "type": "github"
} }
}, },
"hyprgraphics": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1733684019,
"narHash": "sha256-2kYREgmSmbLsmDpLEq96hxVAU3qz8aCvVhF65yCFZHY=",
"owner": "hyprwm",
"repo": "hyprgraphics",
"rev": "fb2c0268645a77403af3b8a4ce8fa7ba5917f15d",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprgraphics",
"type": "github"
}
},
"hyprland-protocols": { "hyprland-protocols": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -128,11 +65,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1728345020, "lastModified": 1727451107,
"narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=", "narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "a7c183800e74f337753de186522b9017a07a8cee", "rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -141,29 +78,28 @@
"type": "github" "type": "github"
} }
}, },
"hyprland-qtutils": { "hyprland-protocols_2": {
"inputs": { "inputs": {
"hyprutils": [
"hyprutils"
],
"nixpkgs": [ "nixpkgs": [
"xdph",
"nixpkgs" "nixpkgs"
], ],
"systems": [ "systems": [
"xdph",
"systems" "systems"
] ]
}, },
"locked": { "locked": {
"lastModified": 1733940128, "lastModified": 1721326555,
"narHash": "sha256-hmfXWj2GA9cj1QUkPFYtAAeohhs615zL4E3APy3FnvQ=", "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-qtutils", "repo": "hyprland-protocols",
"rev": "3833097e50473a152dd614d4b468886840b4ea78", "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-qtutils", "repo": "hyprland-protocols",
"type": "github" "type": "github"
} }
}, },
@@ -180,11 +116,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734364628, "lastModified": 1725997860,
"narHash": "sha256-ii8fzJfI953n/EmIxVvq64ZAwhvwuuPHWfGd61/mJG8=", "narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "16e59c1eb13d9fb6de066f54e7555eb5e8a4aba5", "rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -203,11 +139,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1733502241, "lastModified": 1727300645,
"narHash": "sha256-KAUNC4Dgq8WQjYov5auBw/usaHixhacvb7cRDd0AG/k=", "narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "104117aed6dd68561be38b50f218190aa47f2cd8", "rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -241,11 +177,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1734119587, "lastModified": 1727348695,
"narHash": "sha256-AKU6qqskl0yf2+JdRdD0cfxX4b9x3KKV5RqA6wijmPM=", "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "3566ab7246670a43abd2ffa913cc62dad9cdf7d5", "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -255,57 +191,15 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-stable": {
"locked": {
"lastModified": 1730741070,
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1734279981,
"narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"aquamarine": "aquamarine", "aquamarine": "aquamarine",
"hyprcursor": "hyprcursor", "hyprcursor": "hyprcursor",
"hyprgraphics": "hyprgraphics",
"hyprland-protocols": "hyprland-protocols", "hyprland-protocols": "hyprland-protocols",
"hyprland-qtutils": "hyprland-qtutils",
"hyprlang": "hyprlang", "hyprlang": "hyprlang",
"hyprutils": "hyprutils", "hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner", "hyprwayland-scanner": "hyprwayland-scanner",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks",
"systems": "systems", "systems": "systems",
"xdph": "xdph" "xdph": "xdph"
} }
@@ -327,9 +221,7 @@
}, },
"xdph": { "xdph": {
"inputs": { "inputs": {
"hyprland-protocols": [ "hyprland-protocols": "hyprland-protocols_2",
"hyprland-protocols"
],
"hyprlang": [ "hyprlang": [
"hyprlang" "hyprlang"
], ],
@@ -347,11 +239,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734124279, "lastModified": 1727524473,
"narHash": "sha256-YNpFfiQjYt2o6LGcMN9NkjVvprC8ELrIpLHlbZbclRM=", "narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "0c6861f819f6d31f6195c9864709b2556f00b5cf", "rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -22,26 +22,12 @@
inputs.hyprlang.follows = "hyprlang"; inputs.hyprlang.follows = "hyprlang";
}; };
hyprgraphics = {
url = "github:hyprwm/hyprgraphics";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
};
hyprland-protocols = { hyprland-protocols = {
url = "github:hyprwm/hyprland-protocols"; url = "github:hyprwm/hyprland-protocols";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
}; };
hyprland-qtutils = {
url = "github:hyprwm/hyprland-qtutils";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
};
hyprlang = { hyprlang = {
url = "github:hyprwm/hyprlang"; url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@@ -65,16 +51,10 @@
url = "github:hyprwm/xdg-desktop-portal-hyprland"; url = "github:hyprwm/xdg-desktop-portal-hyprland";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
inputs.hyprland-protocols.follows = "hyprland-protocols";
inputs.hyprlang.follows = "hyprlang"; inputs.hyprlang.follows = "hyprlang";
inputs.hyprutils.follows = "hyprutils"; inputs.hyprutils.follows = "hyprutils";
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
}; };
pre-commit-hooks = {
url = "github:cachix/git-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = inputs @ { outputs = inputs @ {
@@ -96,7 +76,7 @@
pkgsCrossFor = eachSystem (system: crossSystem: pkgsCrossFor = eachSystem (system: crossSystem:
import nixpkgs { import nixpkgs {
localSystem = system; localSystem = system;
inherit crossSystem; crossSystem = crossSystem;
overlays = with self.overlays; [ overlays = with self.overlays; [
hyprland-packages hyprland-packages
hyprland-extras hyprland-extras
@@ -111,18 +91,6 @@
self.packages.${system}) self.packages.${system})
// { // {
inherit (self.packages.${system}) xdg-desktop-portal-hyprland; inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run {
src = ./.;
hooks = {
hyprland-treewide-formatter = {
enable = true;
entry = "${self.formatter.${system}}/bin/hyprland-treewide-formatter";
pass_filenames = false;
excludes = ["subprojects"];
always_run = true;
};
};
};
}); });
packages = eachSystem (system: { packages = eachSystem (system: {
@@ -130,11 +98,13 @@
inherit inherit
(pkgsFor.${system}) (pkgsFor.${system})
# hyprland-packages # hyprland-packages
hyprland hyprland
hyprland-debug hyprland-debug
hyprland-legacy-renderer hyprland-legacy-renderer
hyprland-unwrapped hyprland-unwrapped
# hyprland-extras # hyprland-extras
xdg-desktop-portal-hyprland xdg-desktop-portal-hyprland
; ;
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland; hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
@@ -149,11 +119,10 @@
hardeningDisable = ["fortify"]; hardeningDisable = ["fortify"];
inputsFrom = [pkgsFor.${system}.hyprland]; inputsFrom = [pkgsFor.${system}.hyprland];
packages = [pkgsFor.${system}.clang-tools]; packages = [pkgsFor.${system}.clang-tools];
inherit (self.checks.${system}.pre-commit-check) shellHook;
}; };
}); });
formatter = eachSystem (system: pkgsFor.${system}.callPackage ./nix/formatter.nix {}); formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
nixosModules.default = import ./nix/module.nix inputs; nixosModules.default = import ./nix/module.nix inputs;
homeManagerModules.default = import ./nix/hm-module.nix self; homeManagerModules.default = import ./nix/hm-module.nix self;

View File

@@ -5,7 +5,7 @@ project(
DESCRIPTION "Control utility for Hyprland" DESCRIPTION "Control utility for Hyprland"
) )
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.4 re2) pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1)
add_executable(hyprctl "main.cpp") add_executable(hyprctl "main.cpp")

View File

@@ -1,7 +1,5 @@
#pragma once #pragma once
#include <string_view>
const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help] const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help]
commands: commands:

View File

@@ -1,5 +1,3 @@
#include <re2/re2.h>
#include <cctype> #include <cctype>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
@@ -19,12 +17,13 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <print>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <deque>
#include <filesystem> #include <filesystem>
#include <cstdarg> #include <cstdarg>
#include <regex>
#include <sys/socket.h> #include <sys/socket.h>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <cstring> #include <cstring>
@@ -45,24 +44,18 @@ struct SInstanceData {
bool valid = true; bool valid = true;
}; };
void log(const std::string& str) { void log(std::string str) {
if (quiet) if (quiet)
return; return;
std::println("{}", str); std::cout << str << "\n";
}
static int getUID() {
const auto UID = getuid();
const auto PWUID = getpwuid(UID);
return PWUID ? PWUID->pw_uid : UID;
} }
std::string getRuntimeDir() { std::string getRuntimeDir() {
const auto XDG = getenv("XDG_RUNTIME_DIR"); const auto XDG = getenv("XDG_RUNTIME_DIR");
if (!XDG) { if (!XDG) {
const std::string USERID = std::to_string(getUID()); const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
return "/run/user/" + USERID + "/hypr"; return "/run/user/" + USERID + "/hypr";
} }
@@ -72,11 +65,6 @@ std::string getRuntimeDir() {
std::vector<SInstanceData> instances() { std::vector<SInstanceData> instances() {
std::vector<SInstanceData> result; std::vector<SInstanceData> result;
try {
if (!std::filesystem::exists(getRuntimeDir()))
return {};
} catch (std::exception& e) { return {}; }
for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) { for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) {
if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock")) if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock"))
continue; continue;
@@ -117,7 +105,7 @@ std::vector<SInstanceData> instances() {
static volatile bool sigintReceived = false; static volatile bool sigintReceived = false;
void intHandler(int sig) { void intHandler(int sig) {
sigintReceived = true; sigintReceived = true;
std::println("[hyprctl] SIGINT received, closing connection"); std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl;
} }
int rollingRead(const int socket) { int rollingRead(const int socket) {
@@ -127,12 +115,12 @@ int rollingRead(const int socket) {
constexpr size_t BUFFER_SIZE = 8192; constexpr size_t BUFFER_SIZE = 8192;
std::array<char, BUFFER_SIZE> buffer = {0}; std::array<char, BUFFER_SIZE> buffer = {0};
long sizeWritten = 0; long sizeWritten = 0;
std::println("[hyprctl] reading from socket following up log:"); std::cout << "[hyprctl] reading from socket following up log:" << std::endl;
while (!sigintReceived) { while (!sigintReceived) {
sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
if (sizeWritten < 0 && errno != EAGAIN) { if (sizeWritten < 0 && errno != EAGAIN) {
if (errno != EINTR) if (errno != EINTR)
std::println("Couldn't read (5): {}: {}", strerror(errno), errno); std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl;
close(socket); close(socket);
return 5; return 5;
} }
@@ -141,7 +129,7 @@ int rollingRead(const int socket) {
break; break;
if (sizeWritten > 0) { if (sizeWritten > 0) {
std::println("{}", std::string(buffer.data(), sizeWritten)); std::cout << std::string(buffer.data(), sizeWritten);
buffer.fill('\0'); buffer.fill('\0');
} }
@@ -174,7 +162,7 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
return 2; return 2;
} }
const std::string USERID = std::to_string(getUID()); const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
sockaddr_un serverAddress = {0}; sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX; serverAddress.sun_family = AF_UNIX;
@@ -244,7 +232,7 @@ int requestHyprpaper(std::string arg) {
sockaddr_un serverAddress = {0}; sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX; serverAddress.sun_family = AF_UNIX;
const std::string USERID = std::to_string(getUID()); const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock"; std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock";
@@ -282,10 +270,11 @@ int requestHyprpaper(std::string arg) {
} }
void batchRequest(std::string arg, bool json) { void batchRequest(std::string arg, bool json) {
std::string commands = arg.substr(arg.find_first_of(' ') + 1); std::string commands = arg.substr(arg.find_first_of(" ") + 1);
if (json) if (json) {
RE2::GlobalReplace(&commands, ";\\s*", ";j/"); commands = "j/" + std::regex_replace(commands, std::regex(";\\s*"), ";j/");
}
std::string rq = "[[BATCH]]" + commands; std::string rq = "[[BATCH]]" + commands;
request(rq); request(rq);
@@ -321,11 +310,11 @@ void instancesRequest(bool json) {
log(result + "\n"); log(result + "\n");
} }
std::vector<std::string> splitArgs(int argc, char** argv) { std::deque<std::string> splitArgs(int argc, char** argv) {
std::vector<std::string> result; std::deque<std::string> result;
for (auto i = 1 /* skip the executable */; i < argc; ++i) for (auto i = 1 /* skip the executable */; i < argc; ++i)
result.emplace_back(argv[i]); result.push_back(std::string(argv[i]));
return result; return result;
} }
@@ -334,7 +323,7 @@ int main(int argc, char** argv) {
bool parseArgs = true; bool parseArgs = true;
if (argc < 2) { if (argc < 2) {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -371,7 +360,7 @@ int main(int argc, char** argv) {
++i; ++i;
if (i >= ARGS.size()) { if (i >= ARGS.size()) {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -382,24 +371,24 @@ int main(int argc, char** argv) {
const std::string& cmd = ARGS[0]; const std::string& cmd = ARGS[0];
if (cmd == "hyprpaper") { if (cmd == "hyprpaper") {
std::println("{}", HYPRPAPER_HELP); std::cout << HYPRPAPER_HELP << std::endl;
} else if (cmd == "notify") { } else if (cmd == "notify") {
std::println("{}", NOTIFY_HELP); std::cout << NOTIFY_HELP << std::endl;
} else if (cmd == "output") { } else if (cmd == "output") {
std::println("{}", OUTPUT_HELP); std::cout << OUTPUT_HELP << std::endl;
} else if (cmd == "plugin") { } else if (cmd == "plugin") {
std::println("{}", PLUGIN_HELP); std::cout << PLUGIN_HELP << std::endl;
} else if (cmd == "setprop") { } else if (cmd == "setprop") {
std::println("{}", SETPROP_HELP); std::cout << SETPROP_HELP << std::endl;
} else if (cmd == "switchxkblayout") { } else if (cmd == "switchxkblayout") {
std::println("{}", SWITCHXKBLAYOUT_HELP); std::cout << SWITCHXKBLAYOUT_HELP << std::endl;
} else { } else {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
} }
return 1; return 1;
} else { } else {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -410,7 +399,7 @@ int main(int argc, char** argv) {
} }
if (fullRequest.empty()) { if (fullRequest.empty()) {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -487,7 +476,7 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/decorations")) else if (fullRequest.contains("/decorations"))
exitStatus = request(fullRequest, 1); exitStatus = request(fullRequest, 1);
else if (fullRequest.contains("/--help")) else if (fullRequest.contains("/--help"))
std::println("{}", USAGE); std::cout << USAGE << std::endl;
else if (fullRequest.contains("/rollinglog") && needRoll) else if (fullRequest.contains("/rollinglog") && needRoll)
exitStatus = request(fullRequest, 0, true); exitStatus = request(fullRequest, 0, true);
else { else {

View File

@@ -3,7 +3,6 @@ executable(
'main.cpp', 'main.cpp',
dependencies: [ dependencies: [
dependency('hyprutils', version: '>= 0.1.1'), dependency('hyprutils', version: '>= 0.1.1'),
dependency('re2', required: true)
], ],
install: true, install: true,
) )

View File

@@ -9,11 +9,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4) pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1)
add_executable(hyprpm ${SRCFILES}) add_executable(hyprpm ${SRCFILES})
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps) target_link_libraries(hyprpm PUBLIC PkgConfig::deps)
# binary # binary
install(TARGETS hyprpm) install(TARGETS hyprpm)

View File

@@ -1,6 +1,6 @@
#include "DataState.hpp" #include "DataState.hpp"
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <print> #include <iostream>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include "PluginManager.hpp" #include "PluginManager.hpp"
@@ -8,7 +8,7 @@
std::string DataState::getDataStatePath() { std::string DataState::getDataStatePath() {
const auto HOME = getenv("HOME"); const auto HOME = getenv("HOME");
if (!HOME) { if (!HOME) {
std::println(stderr, "DataState: no $HOME"); std::cerr << "DataState: no $HOME\n";
throw std::runtime_error("no $HOME"); throw std::runtime_error("no $HOME");
return ""; return "";
} }
@@ -242,4 +242,4 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
} }
return false; return false;
} }

View File

@@ -1,15 +1,12 @@
#include "PluginManager.hpp" #include "PluginManager.hpp"
#include "../helpers/Colors.hpp" #include "../helpers/Colors.hpp"
#include "../helpers/StringUtils.hpp"
#include "../progress/CProgressBar.hpp" #include "../progress/CProgressBar.hpp"
#include "Manifest.hpp" #include "Manifest.hpp"
#include "DataState.hpp" #include "DataState.hpp"
#include <cstdio>
#include <iostream> #include <iostream>
#include <array> #include <array>
#include <filesystem> #include <filesystem>
#include <print>
#include <thread> #include <thread>
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
@@ -23,56 +20,37 @@
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <hyprutils/os/Process.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::OS;
static std::string execAndGet(std::string cmd) { static std::string execAndGet(std::string cmd) {
cmd += " 2>&1"; cmd += " 2>&1";
std::array<char, 128> buffer;
std::string result;
using PcloseType = int (*)(FILE*);
const std::unique_ptr<FILE, PcloseType> pipe(popen(cmd.c_str(), "r"), static_cast<PcloseType>(pclose));
if (!pipe)
return "";
CProcess proc("/bin/sh", {"-c", cmd}); while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
if (!proc.runSync())
return "error";
return proc.stdOut();
}
static std::string getTempRoot() {
static auto ENV = getenv("XDG_RUNTIME_DIR");
if (!ENV) {
std::cerr << "\nERROR: XDG_RUNTIME_DIR not set!\n";
exit(1);
} }
return result;
const auto STR = ENV + std::string{"/hyprpm/"};
return STR;
} }
SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) { SHyprlandVersion CPluginManager::getHyprlandVersion() {
static bool onceRunning = false; static SHyprlandVersion ver;
static bool onceInstalled = false; static bool once = false;
static SHyprlandVersion verRunning;
static SHyprlandVersion verInstalled;
if (onceRunning && running) if (once)
return verRunning; return ver;
if (onceInstalled && !running) once = true;
return verInstalled; const auto HLVERCALL = execAndGet("hyprctl version");
if (running)
onceRunning = true;
else
onceInstalled = true;
const auto HLVERCALL = running ? execAndGet("hyprctl version") : execAndGet("Hyprland --version");
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("{} version returned: {}", running ? "running" : "installed", HLVERCALL)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "version returned: " << HLVERCALL << "\n";
if (!HLVERCALL.contains("Tag:")) { if (!HLVERCALL.contains("Tag:")) {
std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland.")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " You don't seem to be running Hyprland.";
return SHyprlandVersion{}; return SHyprlandVersion{};
} }
@@ -98,20 +76,14 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
} catch (...) { ; } } catch (...) { ; }
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << " on " << hldate << ", commits " << commits << "\n";
auto ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
if (running)
verRunning = ver;
else
verInstalled = ver;
ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
return ver; return ver;
} }
bool CPluginManager::createSafeDirectory(const std::string& path) { bool CPluginManager::createSafeDirectory(const std::string& path) {
if (path.empty() || !path.starts_with(getTempRoot())) if (path.empty() || !path.starts_with("/tmp"))
return false; return false;
if (std::filesystem::exists(path)) if (std::filesystem::exists(path))
@@ -130,21 +102,20 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) { if (!hasDeps()) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
return false; return false;
} }
if (DataState::pluginRepoExists(url)) { if (DataState::pluginRepoExists(url)) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Repository already installed.")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
return false; return false;
} }
auto GLOBALSTATE = DataState::getGlobalState(); auto GLOBALSTATE = DataState::getGlobalState();
if (!GLOBALSTATE.dontWarnInstall) { if (!GLOBALSTATE.dontWarnInstall) {
std::println("{}!{} Disclaimer: {}", Colors::YELLOW, Colors::RED, Colors::RESET); std::cout << Colors::YELLOW << "!" << Colors::RED << " Disclaimer:\n " << Colors::RESET
std::println("plugins, especially not official, have no guarantee of stability, availablity or security.\n" << "plugins, especially not official, have no guarantee of stability, availablity or security.\n Run them at your own risk.\n "
"Run them at your own risk.\n" << "This message will not appear again.\n";
"This message will not appear again.");
GLOBALSTATE.dontWarnInstall = true; GLOBALSTATE.dontWarnInstall = true;
DataState::updateGlobalState(GLOBALSTATE); DataState::updateGlobalState(GLOBALSTATE);
} }
@@ -158,7 +129,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::getline(std::cin, input); std::getline(std::cin, input);
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
std::println(stderr, "Aborting."); std::cout << "Aborting.\n";
return false; return false;
} }
@@ -169,72 +140,72 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.print(); progress.print();
if (!std::filesystem::exists(getTempRoot())) { if (!std::filesystem::exists("/tmp/hyprpm")) {
std::filesystem::create_directory(getTempRoot()); std::filesystem::create_directory("/tmp/hyprpm");
std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace); std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
} else if (!std::filesystem::is_directory(getTempRoot())) { } else if (!std::filesystem::is_directory("/tmp/hyprpm")) {
std::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for hyprpm\n";
return false; return false;
} }
const std::string USERNAME = getpwuid(getuid())->pw_name; const std::string USERNAME = getpwuid(getuid())->pw_name;
m_szWorkingPluginDirectory = getTempRoot() + USERNAME; m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
if (!createSafeDirectory(m_szWorkingPluginDirectory)) { if (!createSafeDirectory(m_szWorkingPluginDirectory)) {
std::println(stderr, "\n{}", failureString("Could not prepare working dir for repo")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for repo\n";
return false; return false;
} }
progress.printMessageAbove(infoString("Cloning {}", url)); progress.printMessageAbove(std::string{Colors::RESET} + "Cloning " + url);
std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), url, USERNAME)); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME);
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret)); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. shell returned:\n" << ret << "\n";
return false; return false;
} }
if (!rev.empty()) { if (!rev.empty()) {
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev); std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev);
if (ret.compare(0, 6, "fatal:") == 0) { if (ret.compare(0, 6, "fatal:") == 0) {
std::println(stderr, "\n{}", failureString("Could not check out revision {}. shell returned:\n{}", rev, ret)); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n";
return false; return false;
} }
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("git submodule update --init returned: {}", ret)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
} }
progress.m_iSteps = 1; progress.m_iSteps = 1;
progress.printMessageAbove(successString("cloned")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " cloned");
progress.m_szCurrentMessage = "Reading the manifest"; progress.m_szCurrentMessage = "Reading the manifest";
progress.print(); progress.print();
std::unique_ptr<CManifest> pManifest; std::unique_ptr<CManifest> pManifest;
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
progress.printMessageAbove(successString("found hyprpm manifest")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprpm manifest");
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
progress.printMessageAbove(successString("found hyprload manifest")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprload manifest");
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
} }
if (!pManifest) { if (!pManifest) {
std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
return false; return false;
} }
if (!pManifest->m_bGood) { if (!pManifest->m_bGood) {
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
return false; return false;
} }
progress.m_iSteps = 2; progress.m_iSteps = 2;
progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:");
for (auto const& pl : pManifest->m_vPlugins) { for (auto const& pl : pManifest->m_vPlugins) {
std::string message = "" + pl.name + " by "; std::string message = std::string{Colors::RESET} + " " + pl.name + " by ";
for (auto const& a : pl.authors) { for (auto const& a : pl.authors) {
message += a + ", "; message += a + ", ";
} }
@@ -249,19 +220,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
if (!pManifest->m_sRepository.commitPins.empty()) { if (!pManifest->m_sRepository.commitPins.empty()) {
// check commit pins // check commit pins
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); progress.printMessageAbove(std::string{Colors::RESET} + "Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("git submodule update --init returned: {}", ret)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
break; break;
} }
@@ -273,12 +244,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HEADERSSTATUS = headersValid(); const auto HEADERSSTATUS = headersValid();
if (HEADERSSTATUS != HEADERS_OK) { if (HEADERSSTATUS != HEADERS_OK) {
std::println("\n{}", headerError(HEADERSSTATUS)); std::cerr << "\n" << headerError(HEADERSSTATUS);
return false; return false;
} }
progress.m_iSteps = 3; progress.m_iSteps = 3;
progress.printMessageAbove(successString("Hyprland headers OK")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " Hyprland headers OK");
progress.m_szCurrentMessage = "Building plugin(s)"; progress.m_szCurrentMessage = "Building plugin(s)";
progress.print(); progress.print();
@@ -286,36 +257,35 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) { if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) {
progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name)); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(infoString("Building {}", p.name)); progress.printMessageAbove(std::string{Colors::RESET} + "Building " + p.name);
for (auto const& bs : p.buildSteps) { for (auto const& bs : p.buildSteps) {
const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("shell returned: {}", out)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
progress.printMessageAbove(failureString("Plugin {} failed to build.\n" progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Plugin " + p.name + " failed to build.\n" +
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update "
" If you are on -git, update first\n" "first.\n Try re-running with -v to see "
" Try re-running with -v to see more verbose output.\n", "more verbose output.\n");
p.name));
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(successString("built {} into {}", p.name, p.output)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output);
} }
progress.printMessageAbove(successString("all plugins built")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " all plugins built");
progress.m_iSteps = 4; progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing repository"; progress.m_szCurrentMessage = "Installing repository";
progress.print(); progress.print();
@@ -334,13 +304,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
} }
DataState::addNewPluginRepo(repo); DataState::addNewPluginRepo(repo);
progress.printMessageAbove(successString("installed repository")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " installed repository");
progress.printMessageAbove(successString("you can now enable the plugin(s) with hyprpm enable")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " you can now enable the plugin(s) with hyprpm enable");
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
std::print("\n"); std::cout << "\n";
// remove build files // remove build files
std::filesystem::remove_all(m_szWorkingPluginDirectory); std::filesystem::remove_all(m_szWorkingPluginDirectory);
@@ -350,7 +320,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
bool CPluginManager::removePluginRepo(const std::string& urlOrName) { bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
if (!DataState::pluginRepoExists(urlOrName)) { if (!DataState::pluginRepoExists(urlOrName)) {
std::println(stderr, "\n{}", failureString("Could not remove the repository. Repository is not installed.")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not remove the repository. Repository is not installed.\n";
return false; return false;
} }
@@ -361,7 +331,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
std::getline(std::cin, input); std::getline(std::cin, input);
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
std::println("Aborting."); std::cout << "Aborting.\n";
return false; return false;
} }
@@ -371,21 +341,21 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
} }
eHeadersErrors CPluginManager::headersValid() { eHeadersErrors CPluginManager::headersValid() {
const auto HLVER = getHyprlandVersion(false); const auto HLVER = getHyprlandVersion();
if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc")) if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc"))
return HEADERS_MISSING; return HEADERS_MISSING;
// find headers commit // find headers commit
const std::string& cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath()); std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
auto headers = execAndGet(cmd.c_str()); auto headers = execAndGet(cmd.c_str());
if (!headers.contains("-I/")) if (!headers.contains("-I/"))
return HEADERS_MISSING; return HEADERS_MISSING;
headers.pop_back(); // pop newline headers.pop_back(); // pop newline
std::string verHeader; std::string verHeader = "";
while (!headers.empty()) { while (!headers.empty()) {
const auto PATH = headers.substr(0, headers.find(" -I/", 3)); const auto PATH = headers.substr(0, headers.find(" -I/", 3));
@@ -433,20 +403,20 @@ bool CPluginManager::updateHeaders(bool force) {
DataState::ensureStateStoreExists(); DataState::ensureStateStoreExists();
const auto HLVER = getHyprlandVersion(false); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) { if (!hasDeps()) {
std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
return false; return false;
} }
if (!std::filesystem::exists(getTempRoot())) { if (!std::filesystem::exists("/tmp/hyprpm")) {
std::filesystem::create_directory(getTempRoot()); std::filesystem::create_directory("/tmp/hyprpm");
std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace); std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
} }
if (!force && headersValid() == HEADERS_OK) { if (!force && headersValid() == HEADERS_OK) {
std::println("\n{}", successString("Headers up to date.")); std::cout << "\n" << std::string{Colors::GREEN} + "" + Colors::RESET + " Headers up to date.\n";
return true; return true;
} }
@@ -457,76 +427,77 @@ bool CPluginManager::updateHeaders(bool force) {
progress.print(); progress.print();
const std::string USERNAME = getpwuid(getuid())->pw_name; const std::string USERNAME = getpwuid(getuid())->pw_name;
const auto WORKINGDIR = getTempRoot() + "hyprland-" + USERNAME; const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME;
if (!createSafeDirectory(WORKINGDIR)) { if (!createSafeDirectory(WORKINGDIR)) {
std::println("\n{}", failureString("Could not prepare working dir for hl")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for hl\n";
return false; return false;
} }
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/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.");
const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow; const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow;
// let us give a bit of leg-room for shallowing // let us give a bit of leg-room for shallowing
// due to timezones, etc. // due to timezones, etc.
const std::string SHALLOW_DATE = trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+%a %b %d %H:%M:%S %Y'"); const std::string SHALLOW_DATE =
trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'");
if (m_bVerbose && bShallow) if (m_bVerbose && bShallow)
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE);
std::string ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-{}{}", getTempRoot(), USERNAME, std::string ret =
(bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""))); execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""));
if (!std::filesystem::exists(WORKINGDIR)) { if (!std::filesystem::exists(WORKINGDIR)) {
progress.printMessageAbove(failureString("Clone failed. Retrying without shallow.")); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Clone failed. Retrying without shallow.");
ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/hyprland hyprland-{}", getTempRoot(), USERNAME)); ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME);
} }
if (!std::filesystem::exists(WORKINGDIR + "/.git")) { if (!std::filesystem::exists(WORKINGDIR + "/.git")) {
std::println(stderr, "\n{}", failureString("Could not clone the Hyprland repository. shell returned:\n{}", ret)); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n";
return false; return false;
} }
progress.printMessageAbove(successString("Hyprland cloned")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " cloned");
progress.m_iSteps = 2; progress.m_iSteps = 2;
progress.m_szCurrentMessage = "Checking out sources"; progress.m_szCurrentMessage = "Checking out sources";
progress.print(); progress.print();
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("will run: cd {} && git checkout {} 2>&1", WORKINGDIR, HLVER.hash)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
if (ret.contains("fatal: unable to read tree")) { if (ret.contains("fatal: unable to read tree")) {
std::println(stderr, "\n{}", std::cerr << "\n"
failureString("Could not checkout the running Hyprland commit. If you are on -git, try updating.\n" << Colors::RED << "" << Colors::RESET
"You can also try re-running hyprpm update with --no-shallow.")); << " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n";
return false; return false;
} }
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("git returned (co): {}", ret)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret);
ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash); ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("git returned (rs): {}", ret)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret);
progress.printMessageAbove(successString("checked out to running ver")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " checked out to running ver");
progress.m_iSteps = 3; progress.m_iSteps = 3;
progress.m_szCurrentMessage = "Building Hyprland"; progress.m_szCurrentMessage = "Building Hyprland";
progress.print(); progress.print();
progress.printMessageAbove(statusString("!", Colors::YELLOW, "configuring Hyprland")); progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland");
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("setting PREFIX for cmake to {}", DataState::getHeadersPath())); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath());
ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR, ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR,
DataState::getHeadersPath())); DataState::getHeadersPath()));
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("cmake returned: {}", ret)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
if (ret.contains("CMake Error at")) { if (ret.contains("CMake Error at")) {
// missing deps, let the user know. // missing deps, let the user know.
@@ -535,46 +506,48 @@ bool CPluginManager::updateHeaders(bool force) {
missing = missing.substr(0, missing.find("-- Configuring incomplete")); missing = missing.substr(0, missing.find("-- Configuring incomplete"));
missing = missing.substr(0, missing.find_last_of('\n')); missing = missing.substr(0, missing.find_last_of('\n'));
std::println(stderr, "\n{}", std::cerr << "\n"
failureString("Could not configure the hyprland source, cmake complained:\n{}\n\n" << Colors::RED << "" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n"
"This likely means that you are missing the above dependencies or they are out of date.", << missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n";
missing));
return false; return false;
} }
progress.printMessageAbove(successString("configured Hyprland")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland");
progress.m_iSteps = 4; progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";
progress.print(); progress.print();
const std::string& cmd = std::string cmd =
std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR); std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("installation will run: {}", cmd)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd);
ret = execAndGet(cmd); ret = execAndGet(cmd);
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("installer returned: {}", ret)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n";
// remove build files // remove build files
std::filesystem::remove_all(WORKINGDIR); std::filesystem::remove_all(WORKINGDIR);
auto HEADERSVALID = headersValid(); auto HEADERSVALID = headersValid();
if (HEADERSVALID == HEADERS_OK) { if (HEADERSVALID == HEADERS_OK) {
progress.printMessageAbove(successString("installed headers")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " installed headers");
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
std::print("\n"); std::cout << "\n";
} else { } else {
progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID))); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" +
headerErrorShort(HEADERSVALID) + ")");
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Failed"; progress.m_szCurrentMessage = "Failed";
progress.print(); progress.print();
std::print(stderr, "\n\n{}", headerError(HEADERSVALID)); std::cout << "\n";
std::cerr << "\n" << headerError(HEADERSVALID);
return false; return false;
} }
@@ -584,18 +557,18 @@ bool CPluginManager::updateHeaders(bool force) {
bool CPluginManager::updatePlugins(bool forceUpdateAll) { bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (headersValid() != HEADERS_OK) { if (headersValid() != HEADERS_OK) {
std::println("{}", failureString("headers are not up-to-date, please run hyprpm update.")); std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
return false; return false;
} }
const auto REPOS = DataState::getAllRepositories(); const auto REPOS = DataState::getAllRepositories();
if (REPOS.size() < 1) { if (REPOS.size() < 1) {
std::println("{}", failureString("No repos to update.")); std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " No repos to update.\n";
return true; return true;
} }
const auto HLVER = getHyprlandVersion(false); const auto HLVER = getHyprlandVersion();
CProgressBar progress; CProgressBar progress;
progress.m_iMaxSteps = REPOS.size() * 2 + 2; progress.m_iMaxSteps = REPOS.size() * 2 + 2;
@@ -604,7 +577,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.print(); progress.print();
const std::string USERNAME = getpwuid(getuid())->pw_name; const std::string USERNAME = getpwuid(getuid())->pw_name;
m_szWorkingPluginDirectory = getTempRoot() + USERNAME; m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
for (auto const& repo : REPOS) { for (auto const& repo : REPOS) {
bool update = forceUpdateAll; bool update = forceUpdateAll;
@@ -613,26 +586,25 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.m_szCurrentMessage = "Updating " + repo.name; progress.m_szCurrentMessage = "Updating " + repo.name;
progress.print(); progress.print();
progress.printMessageAbove(infoString("checking for updates for {}", repo.name)); progress.printMessageAbove(std::string{Colors::RESET} + "checking for updates for " + repo.name);
createSafeDirectory(m_szWorkingPluginDirectory); createSafeDirectory(m_szWorkingPluginDirectory);
progress.printMessageAbove(infoString("Cloning {}", repo.url)); progress.printMessageAbove(std::string{Colors::RESET} + "Cloning " + repo.url);
std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), repo.url, USERNAME)); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME);
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::println("{}", failureString("could not clone repo: shell returned: {}", ret)); std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not clone repo: shell returned:\n" + ret;
return false; return false;
} }
if (!repo.rev.empty()) { if (!repo.rev.empty()) {
progress.printMessageAbove(infoString("Plugin has revision set, resetting: {}", repo.rev)); progress.printMessageAbove(std::string{Colors::RESET} + "Plugin has revision set, resetting: " + repo.rev);
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev); std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev);
if (ret.compare(0, 6, "fatal:") == 0) { if (ret.compare(0, 6, "fatal:") == 0) {
std::println(stderr, "\n{}", failureString("could not check out revision {}: shell returned:\n{}", repo.rev, ret)); std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret;
return false; return false;
} }
} }
@@ -648,7 +620,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (!update) { if (!update) {
std::filesystem::remove_all(m_szWorkingPluginDirectory); std::filesystem::remove_all(m_szWorkingPluginDirectory);
progress.printMessageAbove(successString("repository {} is up-to-date.", repo.name)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " repository " + repo.name + " is up-to-date.");
progress.m_iSteps++; progress.m_iSteps++;
progress.print(); progress.print();
continue; continue;
@@ -656,41 +628,41 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
// we need to update // we need to update
progress.printMessageAbove(successString("repository {} has updates.", repo.name)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " repository " + repo.name + " has updates.");
progress.printMessageAbove(infoString("Building {}", repo.name)); progress.printMessageAbove(std::string{Colors::RESET} + "Building " + repo.name);
progress.m_iSteps++; progress.m_iSteps++;
progress.print(); progress.print();
std::unique_ptr<CManifest> pManifest; std::unique_ptr<CManifest> pManifest;
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
progress.printMessageAbove(successString("found hyprpm manifest")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprpm manifest");
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
progress.printMessageAbove(successString("found hyprload manifest")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprload manifest");
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
} }
if (!pManifest) { if (!pManifest) {
std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
continue; continue;
} }
if (!pManifest->m_bGood) { if (!pManifest->m_bGood) {
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
continue; continue;
} }
if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) { if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) {
// check commit pins unless a revision is specified // check commit pins unless a revision is specified
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); progress.printMessageAbove(std::string{Colors::RESET} + "Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
} }
@@ -700,33 +672,32 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) { if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) {
progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name)); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(infoString("Building {}", p.name)); progress.printMessageAbove(std::string{Colors::RESET} + "Building " + p.name);
for (auto const& bs : p.buildSteps) { for (auto const& bs : p.buildSteps) {
const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("shell returned: {}", out)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
std::println(stderr, std::cerr << "\n"
"\n{}\n" << Colors::RED << "" << Colors::RESET << " Plugin " << p.name << " failed to build.\n"
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" << " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update first.\n Try "
"If you are on -git, update first.\n" "re-running with -v to see more verbose "
"Try re-running with -v to see more verbose output.", "output.\n";
failureString("Plugin {} failed to build.", p.name));
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(successString("built {} into {}", p.name, p.output)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output);
} }
// add repo toml to DataState // add repo toml to DataState
@@ -747,7 +718,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
std::filesystem::remove_all(m_szWorkingPluginDirectory); std::filesystem::remove_all(m_szWorkingPluginDirectory);
progress.printMessageAbove(successString("updated {}", repo.name)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " updated " + repo.name);
} }
progress.m_iSteps++; progress.m_iSteps++;
@@ -762,7 +733,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
std::print("\n"); std::cout << "\n";
return true; return true;
} }
@@ -770,27 +741,27 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
bool CPluginManager::enablePlugin(const std::string& name) { bool CPluginManager::enablePlugin(const std::string& name) {
bool ret = DataState::setPluginEnabled(name, true); bool ret = DataState::setPluginEnabled(name, true);
if (ret) if (ret)
std::println("{}", successString("Enabled {}", name)); std::cout << Colors::GREEN << "" << Colors::RESET << " Enabled " << name << "\n";
return ret; return ret;
} }
bool CPluginManager::disablePlugin(const std::string& name) { bool CPluginManager::disablePlugin(const std::string& name) {
bool ret = DataState::setPluginEnabled(name, false); bool ret = DataState::setPluginEnabled(name, false);
if (ret) if (ret)
std::println("{}", successString("Disabled {}", name)); std::cout << Colors::GREEN << "" << Colors::RESET << " Disabled " << name << "\n";
return ret; return ret;
} }
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (headersValid() != HEADERS_OK) { if (headersValid() != HEADERS_OK) {
std::println(stderr, "\n{}", failureString("headers are not up-to-date, please run hyprpm update.")); std::cerr << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
return LOADSTATE_HEADERS_OUTDATED; return LOADSTATE_HEADERS_OUTDATED;
} }
const auto HOME = getenv("HOME"); const auto HOME = getenv("HOME");
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE"); const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!HOME || !HIS) { if (!HOME || !HIS) {
std::println(stderr, "PluginManager: no $HOME or HIS"); std::cerr << "PluginManager: no $HOME or HIS\n";
return LOADSTATE_FAIL; return LOADSTATE_FAIL;
} }
const auto HYPRPMPATH = DataState::getDataStatePath() + "/"; const auto HYPRPMPATH = DataState::getDataStatePath() + "/";
@@ -799,14 +770,14 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
std::vector<std::string> loadedPlugins; std::vector<std::string> loadedPlugins;
std::println("{}", successString("Ensuring plugin load state")); std::cout << Colors::GREEN << "" << Colors::RESET << " Ensuring plugin load state\n";
// iterate line by line // iterate line by line
while (!pluginLines.empty()) { while (!pluginLines.empty()) {
auto plLine = pluginLines.substr(0, pluginLines.find('\n')); auto plLine = pluginLines.substr(0, pluginLines.find("\n"));
if (pluginLines.find('\n') != std::string::npos) if (pluginLines.find("\n") != std::string::npos)
pluginLines = pluginLines.substr(pluginLines.find('\n') + 1); pluginLines = pluginLines.substr(pluginLines.find("\n") + 1);
else else
pluginLines = ""; pluginLines = "";
@@ -844,20 +815,12 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
return ""; return "";
}; };
// if any of the loadUnloadPlugin calls return false, this is true
// bcs that means the header version doesn't match the running version
// (and Hyprland needs to restart)
bool hyprlandVersionMismatch = false;
// unload disabled plugins // unload disabled plugins
for (auto const& p : loadedPlugins) { for (auto const& p : loadedPlugins) {
if (!enabled(p)) { if (!enabled(p)) {
// unload // unload
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false)) { loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false);
std::println("{}", infoString("{} will be unloaded after restarting Hyprland", p)); std::cout << Colors::GREEN << "" << Colors::RESET << " Unloaded " << p << "\n";
hyprlandVersionMismatch = true;
} else
std::println("{}", successString("Unloaded {}", p));
} }
} }
@@ -870,28 +833,17 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end()) if (std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end())
continue; continue;
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true)) { loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true);
std::println("{}", infoString("{} will be loaded after restarting Hyprland", p.name)); std::cout << Colors::GREEN << "" << Colors::RESET << " Loaded " << p.name << "\n";
hyprlandVersionMismatch = true;
} else
std::println("{}", successString("Loaded {}", p.name));
} }
} }
std::println("{}", successString("Plugin load state ensured")); std::cout << Colors::GREEN << "" << Colors::RESET << " Plugin load state ensured\n";
return hyprlandVersionMismatch ? LOADSTATE_HYPRLAND_UPDATED : LOADSTATE_OK; return LOADSTATE_OK;
} }
bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) { bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
auto state = DataState::getGlobalState();
auto HLVER = getHyprlandVersion(true);
if (state.headersHashCompiled != HLVER.hash) {
std::println("{}", infoString("Running Hyprland version differs from plugin state, please restart Hyprland."));
return false;
}
if (load) if (load)
execAndGet("hyprctl plugin load " + path); execAndGet("hyprctl plugin load " + path);
else else
@@ -904,17 +856,16 @@ void CPluginManager::listAllPlugins() {
const auto REPOS = DataState::getAllRepositories(); const auto REPOS = DataState::getAllRepositories();
for (auto const& r : REPOS) { for (auto const& r : REPOS) {
std::println("{}", infoString("Repository {}:", r.name)); std::cout << std::string{Colors::RESET} + "Repository " + r.name + ":\n";
for (auto const& p : r.plugins) { for (auto const& p : r.plugins) {
std::println(" │ Plugin {}", p.name);
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
if (!p.failed) if (!p.failed)
std::println(" └─ enabled: {}", (p.enabled ? std::string{Colors::GREEN} + "true" : std::string{Colors::RED} + "false")); std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n";
else else
std::println(" └─ enabled: {}Plugin failed to build", Colors::RED); std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n";
std::println("{}", Colors::RESET);
} }
} }
} }
@@ -925,19 +876,19 @@ void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int duratio
std::string CPluginManager::headerError(const eHeadersErrors err) { std::string CPluginManager::headerError(const eHeadersErrors err) {
switch (err) { switch (err) {
case HEADERS_CORRUPTED: return failureString("Headers corrupted. Please run hyprpm update to fix those.\n"); case HEADERS_CORRUPTED: return std::string{Colors::RED} + "" + Colors::RESET + " Headers corrupted. Please run hyprpm update to fix those.\n";
case HEADERS_MISMATCHED: return failureString("Headers version mismatch. Please run hyprpm update to fix those.\n"); case HEADERS_MISMATCHED: return std::string{Colors::RED} + "" + Colors::RESET + " Headers version mismatch. Please run hyprpm update to fix those.\n";
case HEADERS_NOT_HYPRLAND: return failureString("It doesn't seem you are running on hyprland.\n"); case HEADERS_NOT_HYPRLAND: return std::string{Colors::RED} + "" + Colors::RESET + " It doesn't seem you are running on hyprland.\n";
case HEADERS_MISSING: return failureString("Headers missing. Please run hyprpm update to fix those.\n"); case HEADERS_MISSING: return std::string{Colors::RED} + "" + Colors::RESET + " Headers missing. Please run hyprpm update to fix those.\n";
case HEADERS_DUPLICATED: { case HEADERS_DUPLICATED: {
return failureString("Headers duplicated!!! This is a very bad sign.\n" return std::string{Colors::RED} + "" + Colors::RESET + " Headers duplicated!!! This is a very bad sign.\n" +
"This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" " This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" +
"If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n"); " If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n";
} }
default: break; default: break;
} }
return failureString("Unknown header error. Please run hyprpm update to fix those.\n"); return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n";
} }
std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {

View File

@@ -2,7 +2,6 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
enum eHeadersErrors { enum eHeadersErrors {
HEADERS_OK = 0, HEADERS_OK = 0,
@@ -27,8 +26,7 @@ enum ePluginLoadStateReturn {
LOADSTATE_OK = 0, LOADSTATE_OK = 0,
LOADSTATE_FAIL, LOADSTATE_FAIL,
LOADSTATE_PARTIAL_FAIL, LOADSTATE_PARTIAL_FAIL,
LOADSTATE_HEADERS_OUTDATED, LOADSTATE_HEADERS_OUTDATED
LOADSTATE_HYPRLAND_UPDATED
}; };
struct SHyprlandVersion { struct SHyprlandVersion {
@@ -54,7 +52,7 @@ class CPluginManager {
ePluginLoadStateReturn ensurePluginsLoadState(); ePluginLoadStateReturn ensurePluginsLoadState();
bool loadUnloadPlugin(const std::string& path, bool load); bool loadUnloadPlugin(const std::string& path, bool load);
SHyprlandVersion getHyprlandVersion(bool running = true); SHyprlandVersion getHyprlandVersion();
void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message); void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message);
@@ -70,7 +68,7 @@ class CPluginManager {
std::string headerError(const eHeadersErrors err); std::string headerError(const eHeadersErrors err);
std::string headerErrorShort(const eHeadersErrors err); std::string headerErrorShort(const eHeadersErrors err);
std::string m_szWorkingPluginDirectory; std::string m_szWorkingPluginDirectory = "";
}; };
inline std::unique_ptr<CPluginManager> g_pPluginManager; inline std::unique_ptr<CPluginManager> g_pPluginManager;

View File

@@ -1,32 +0,0 @@
#pragma once
#include <format>
#include <string>
#include "Colors.hpp"
template <typename... Args>
std::string statusString(const std::string_view emoji, const std::string_view color, const std::string_view fmt, Args&&... args) {
std::string ret = std::format("{}{}{} ", color, emoji, Colors::RESET);
ret += std::vformat(fmt, std::make_format_args(args...));
return ret;
}
template <typename... Args>
std::string successString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::GREEN, fmt, args...);
}
template <typename... Args>
std::string failureString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::RED, fmt, args...);
}
template <typename... Args>
std::string verboseString(const std::string_view fmt, Args&&... args) {
return statusString("[v]", Colors::BLUE, fmt, args...);
}
template <typename... Args>
std::string infoString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::RESET, fmt, args...);
}

View File

@@ -1,16 +1,15 @@
#include "progress/CProgressBar.hpp"
#include "helpers/Colors.hpp" #include "helpers/Colors.hpp"
#include "helpers/StringUtils.hpp"
#include "core/PluginManager.hpp" #include "core/PluginManager.hpp"
#include "core/DataState.hpp" #include "core/DataState.hpp"
#include <cstdio> #include <iostream>
#include <vector> #include <vector>
#include <string> #include <string>
#include <print>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
add [url] [git rev] Install a new plugin repository from git. Git revision add [url] [git rev] Install a new plugin repository from git. Git revision
is optional, when set, commit locks are ignored. is optional, when set, commit locks are ignored.
@@ -23,8 +22,7 @@ constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
Flags: Flags:
--notify | -n Send a hyprland notification for important events (including both successes and fail events) --notify | -n Send a hyprland notification for important events (e.g. load fail)
--notify-fail | -nn Send a hyprland notification for fail events only
--help | -h Show this menu --help | -h Show this menu
--verbose | -v Enable too much logging --verbose | -v Enable too much logging
--force | -f Force an operation ignoring checks (e.g. update -f) --force | -f Force an operation ignoring checks (e.g. update -f)
@@ -32,38 +30,36 @@ constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
)#"; )#";
int main(int argc, char** argv, char** envp) { int main(int argc, char** argv, char** envp) {
std::vector<std::string> ARGS{argc}; std::vector<std::string> ARGS{argc};
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
ARGS[i] = std::string{argv[i]}; ARGS[i] = std::string{argv[i]};
} }
if (ARGS.size() < 2) { if (ARGS.size() < 2) {
std::println(stderr, "{}", HELP); std::cout << HELP;
return 1; return 1;
} }
std::vector<std::string> command; std::vector<std::string> command;
bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false; bool notify = false, verbose = false, force = false, noShallow = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) { if (ARGS[i].starts_with("-")) {
if (ARGS[i] == "--help" || ARGS[i] == "-h") { if (ARGS[i] == "--help" || ARGS[i] == "-h") {
std::println("{}", HELP); std::cout << HELP;
return 0; return 0;
} else if (ARGS[i] == "--notify" || ARGS[i] == "-n") { } else if (ARGS[i] == "--notify" || ARGS[i] == "-n") {
notify = true; notify = true;
} else if (ARGS[i] == "--notify-fail" || ARGS[i] == "-nn") {
notifyFail = notify = true;
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") { } else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
verbose = true; verbose = true;
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") { } else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
noShallow = true; noShallow = true;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") { } else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true; force = true;
std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing.")); std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
} else { } else {
std::println(stderr, "Unrecognized option {}", ARGS[i]); std::cerr << "Unrecognized option " << ARGS[i] << "\n";
return 1; return 1;
} }
} else { } else {
@@ -72,7 +68,7 @@ int main(int argc, char** argv, char** envp) {
} }
if (command.empty()) { if (command.empty()) {
std::println(stderr, "{}", HELP); std::cout << HELP;
return 0; return 0;
} }
@@ -82,7 +78,7 @@ int main(int argc, char** argv, char** envp) {
if (command[0] == "add") { if (command[0] == "add") {
if (command.size() < 2) { if (command.size() < 2) {
std::println(stderr, "{}", failureString("Not enough args for add.")); std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for add.\n";
return 1; return 1;
} }
@@ -94,7 +90,7 @@ int main(int argc, char** argv, char** envp) {
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1; return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
} else if (command[0] == "remove") { } else if (command[0] == "remove") {
if (ARGS.size() < 2) { if (ARGS.size() < 2) {
std::println(stderr, "{}", failureString("Not enough args for remove.")); std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for remove.\n";
return 1; return 1;
} }
@@ -103,7 +99,7 @@ int main(int argc, char** argv, char** envp) {
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK; bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
bool headers = g_pPluginManager->updateHeaders(force); bool headers = g_pPluginManager->updateHeaders(force);
if (headers) { if (headers) {
const auto HLVER = g_pPluginManager->getHyprlandVersion(false); const auto HLVER = g_pPluginManager->getHyprlandVersion();
auto GLOBALSTATE = DataState::getGlobalState(); auto GLOBALSTATE = DataState::getGlobalState();
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled; const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
@@ -114,39 +110,32 @@ int main(int argc, char** argv, char** envp) {
auto ret2 = g_pPluginManager->ensurePluginsLoadState(); auto ret2 = g_pPluginManager->ensurePluginsLoadState();
if (ret2 == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Updated plugins, but Hyprland was updated. Please restart Hyprland.");
if (ret2 != LOADSTATE_OK) if (ret2 != LOADSTATE_OK)
return 1; return 1;
} else if (notify) } else if (notify)
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers"); g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers");
} else if (command[0] == "enable") { } else if (command[0] == "enable") {
if (ARGS.size() < 2) { if (ARGS.size() < 2) {
std::println(stderr, "{}", failureString("Not enough args for enable.")); std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for enable.\n";
return 1; return 1;
} }
if (!g_pPluginManager->enablePlugin(command[1])) { if (!g_pPluginManager->enablePlugin(command[1])) {
std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)")); std::cerr << Colors::RED << "" << Colors::RESET << " Couldn't enable plugin (missing?)\n";
return 1; return 1;
} }
auto ret = g_pPluginManager->ensurePluginsLoadState(); auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland.");
if (ret != LOADSTATE_OK) if (ret != LOADSTATE_OK)
return 1; return 1;
} else if (command[0] == "disable") { } else if (command[0] == "disable") {
if (command.size() < 2) { if (command.size() < 2) {
std::println(stderr, "{}", failureString("Not enough args for disable.")); std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for disable.\n";
return 1; return 1;
} }
if (!g_pPluginManager->disablePlugin(command[1])) { if (!g_pPluginManager->disablePlugin(command[1])) {
std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)")); std::cerr << Colors::RED << "" << Colors::RESET << " Couldn't disable plugin (missing?)\n";
return 1; return 1;
} }
@@ -165,15 +154,15 @@ int main(int argc, char** argv, char** envp) {
break; break;
default: break; default: break;
} }
} else if (notify && !notifyFail) { } else if (notify) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins"); g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
} }
} else if (command[0] == "list") { } else if (command[0] == "list") {
g_pPluginManager->listAllPlugins(); g_pPluginManager->listAllPlugins();
} else { } else {
std::println(stderr, "{}", HELP); std::cout << HELP;
return 1; return 1;
} }
return 0; return 0;
} }

View File

@@ -1,11 +1,11 @@
#include "CProgressBar.hpp" #include "CProgressBar.hpp"
#include <sys/ioctl.h> #include <iostream>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <format> #include <format>
#include <print> #include <sys/ioctl.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@@ -16,12 +16,11 @@ void CProgressBar::printMessageAbove(const std::string& msg) {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
std::string spaces; std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) { for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' '; spaces += ' ';
} }
std::println("\r{}\r{}", spaces, msg); std::cout << "\r" << spaces << "\r" << msg << "\n";
print(); print();
} }
@@ -30,16 +29,15 @@ void CProgressBar::print() {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (m_bFirstPrint) if (m_bFirstPrint)
std::print("\n"); std::cout << "\n";
m_bFirstPrint = false; m_bFirstPrint = false;
std::string spaces; std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) { for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' '; spaces += ' ';
} }
std::print("\r{}\r", spaces); std::cout << "\r" << spaces << "\r";
std::string message = ""; std::string message = "";
@@ -76,7 +74,7 @@ void CProgressBar::print() {
message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " "; message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " ";
// draw message // draw message
std::print("{} {}", message, m_szCurrentMessage); std::cout << message + " " + m_szCurrentMessage;
std::fflush(stdout); std::fflush(stdout);
} }

View File

@@ -14,4 +14,4 @@ class CProgressBar {
private: private:
bool m_bFirstPrint = true; bool m_bFirstPrint = true;
}; };

View File

@@ -21,7 +21,6 @@ add_project_arguments(
'-Wno-missing-field-initializers', '-Wno-missing-field-initializers',
'-Wno-narrowing', '-Wno-narrowing',
'-Wno-pointer-arith', datarootdir, '-Wno-pointer-arith', datarootdir,
'-DHYPRLAND_VERSION="' + meson.project_version() + '"',
], ],
language: 'cpp', language: 'cpp',
) )
@@ -31,16 +30,8 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif endif
aquamarine = dependency('aquamarine', version: '>=0.4.5') aquamarine = dependency('aquamarine')
hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
hyprlang = dependency('hyprlang', version: '>= 0.3.2')
hyprutils = dependency('hyprutils', version: '>= 0.2.3')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp')
add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp')
add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp')
add_project_arguments(['-DHYPRUTILS_VERSION="@0@"'.format(hyprutils.version())], language: 'cpp')
xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_dep = dependency('xcb', required: get_option('xwayland'))
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
@@ -59,17 +50,9 @@ endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false) backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs
re2 = dependency('re2', required: true)
# Handle options # Handle options
systemd_option = get_option('systemd') if get_option('systemd').enabled()
systemd = dependency('systemd', required: systemd_option)
systemd_option.enable_auto_if(systemd.found())
if (systemd_option.enabled())
message('Enabling systemd integration')
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp') add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
subdir('systemd')
endif endif
if get_option('legacy_renderer').enabled() if get_option('legacy_renderer').enabled()
@@ -96,8 +79,6 @@ if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized'
warning('Profiling builds should set -- buildtype = debugoptimized') warning('Profiling builds should set -- buildtype = debugoptimized')
endif endif
subdir('protocols') subdir('protocols')
subdir('src') subdir('src')
subdir('hyprctl') subdir('hyprctl')

View File

@@ -1,5 +1,4 @@
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration') option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration')
option('uwsm', type: 'feature', value: 'enabled', description: 'Enable uwsm integration (only if systemd is enabled)')
option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer') option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer')
option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling') option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling')

View File

@@ -12,9 +12,7 @@
cairo, cairo,
git, git,
hyprcursor, hyprcursor,
hyprgraphics,
hyprland-protocols, hyprland-protocols,
hyprland-qtutils,
hyprlang, hyprlang,
hyprutils, hyprutils,
hyprwayland-scanner, hyprwayland-scanner,
@@ -27,7 +25,6 @@
mesa, mesa,
pango, pango,
pciutils, pciutils,
re2,
systemd, systemd,
tomlplusplus, tomlplusplus,
udis86-hyprland, udis86-hyprland,
@@ -59,7 +56,6 @@
adapters = flatten [ adapters = flatten [
stdenvAdapters.useMoldLinker stdenvAdapters.useMoldLinker
(lib.optional debug stdenvAdapters.keepDebugInfo)
]; ];
customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters; customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters;
@@ -67,12 +63,12 @@ in
assert assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; assert assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
assert assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; assert assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
assert assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; assert assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
customStdenv.mkDerivation (finalAttrs: { customStdenv.mkDerivation {
pname = "hyprland${optionalString debug "-debug"}"; pname = "hyprland${optionalString debug "-debug"}";
inherit version; inherit version;
src = cleanSourceWith { src = cleanSourceWith {
filter = name: _type: let filter = name: type: let
baseName = baseNameOf (toString name); baseName = baseNameOf (toString name);
in in
! (hasSuffix ".nix" baseName); ! (hasSuffix ".nix" baseName);
@@ -91,7 +87,6 @@ in
DATE = date; DATE = date;
DIRTY = optionalString (commit == "") "dirty"; DIRTY = optionalString (commit == "") "dirty";
HASH = commit; HASH = commit;
TAG = "v${builtins.readFile "${finalAttrs.src}/VERSION"}";
depsBuildBuild = [ depsBuildBuild = [
pkg-config pkg-config
@@ -117,7 +112,6 @@ in
cairo cairo
git git
hyprcursor hyprcursor
hyprgraphics
hyprland-protocols hyprland-protocols
hyprlang hyprlang
hyprutils hyprutils
@@ -129,7 +123,6 @@ in
mesa mesa
pango pango
pciutils pciutils
re2
tomlplusplus tomlplusplus
udis86-hyprland udis86-hyprland
wayland wayland
@@ -154,11 +147,14 @@ in
then "debugoptimized" then "debugoptimized"
else "release"; else "release";
# we want as much debug info as possible
dontStrip = debug;
mesonFlags = flatten [ mesonFlags = flatten [
(mapAttrsToList mesonEnable { (mapAttrsToList mesonEnable {
"xwayland" = enableXWayland; "xwayland" = enableXWayland;
"legacy_renderer" = legacyRenderer; "legacy_renderer" = legacyRenderer;
"uwsm" = false; "systemd" = withSystemd;
}) })
(mapAttrsToList mesonBool { (mapAttrsToList mesonBool {
"b_pch" = false; "b_pch" = false;
@@ -171,7 +167,6 @@ in
wrapProgram $out/bin/Hyprland \ wrapProgram $out/bin/Hyprland \
--suffix PATH : ${makeBinPath [ --suffix PATH : ${makeBinPath [
binutils binutils
hyprland-qtutils
pciutils pciutils
pkgconf pkgconf
]} ]}
@@ -187,4 +182,4 @@ in
platforms = lib.platforms.linux; platforms = lib.platforms.linux;
mainProgram = "Hyprland"; mainProgram = "Hyprland";
}; };
}) }

View File

@@ -1,64 +0,0 @@
{
writeShellApplication,
deadnix,
statix,
alejandra,
llvmPackages_19,
fd,
}:
writeShellApplication {
name = "hyprland-treewide-formatter";
runtimeInputs = [
deadnix
statix
alejandra
llvmPackages_19.clang-tools
fd
];
text = ''
# shellcheck disable=SC2148
# common excludes
excludes="subprojects"
nix_format() {
if [ "$*" = 0 ]; then
fd '.*\.nix' . -E "$excludes" -x statix fix -- {} \;
fd '.*\.nix' . -E "$excludes" -X deadnix -e -- {} \; -X alejandra {} \;
elif [ -d "$1" ]; then
fd '.*\.nix' "$1" -E "$excludes" -i -x statix fix -- {} \;
fd '.*\.nix' "$1" -E "$excludes" -i -X deadnix -e -- {} \; -X alejandra {} \;
else
statix fix -- "$1"
deadnix -e "$1"
alejandra "$1"
fi
}
cpp_format() {
if [ "$*" = 0 ] || [ "$1" = "." ]; then
fd '.*\.cpp' . -E "$excludes" | xargs clang-format --verbose -i
elif [ -d "$1" ]; then
fd '.*\.cpp' "$1" -E "$excludes" | xargs clang-format --verbose -i
else
clang-format --verbose -i "$1"
fi
}
for i in "$@"; do
case ''${i##*.} in
"nix")
nix_format "$i"
;;
"cpp")
cpp_format "$i"
;;
*)
nix_format "$i"
cpp_format "$i"
;;
esac
done
'';
}

View File

@@ -22,16 +22,14 @@ in {
# Dependencies # Dependencies
inputs.aquamarine.overlays.default inputs.aquamarine.overlays.default
inputs.hyprcursor.overlays.default inputs.hyprcursor.overlays.default
inputs.hyprgraphics.overlays.default
inputs.hyprland-protocols.overlays.default inputs.hyprland-protocols.overlays.default
inputs.hyprland-qtutils.overlays.default
inputs.hyprlang.overlays.default inputs.hyprlang.overlays.default
inputs.hyprutils.overlays.default inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default inputs.hyprwayland-scanner.overlays.default
self.overlays.udis86 self.overlays.udis86
# Hyprland packages themselves # Hyprland packages themselves
(final: _prev: let (final: prev: let
date = mkDate (self.lastModifiedDate or "19700101"); date = mkDate (self.lastModifiedDate or "19700101");
in { in {
hyprland = final.callPackage ./default.nix { hyprland = final.callPackage ./default.nix {
@@ -42,13 +40,7 @@ in {
inherit date; inherit date;
}; };
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;}; hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
hyprland-debug = final.hyprland.override {debug = true;};
# Build major libs with debug to get as much info as possible in a stacktrace
hyprland-debug = final.hyprland.override {
aquamarine = final.aquamarine.override {debug = true;};
hyprutils = final.hyprutils.override {debug = true;};
debug = true;
};
hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;}; hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;};
# deprecated packages # deprecated packages
@@ -71,14 +63,14 @@ in {
# Packages for extra software recommended for usage with Hyprland, # Packages for extra software recommended for usage with Hyprland,
# including forked or patched packages for compatibility. # including forked or patched packages for compatibility.
hyprland-extras = lib.composeManyExtensions [ hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.default inputs.xdph.overlays.xdg-desktop-portal-hyprland
]; ];
# udis86 from nixpkgs is too old, and also does not provide a .pc file # udis86 from nixpkgs is too old, and also does not provide a .pc file
# this version is the one used in the git submodule, and allows us to # this version is the one used in the git submodule, and allows us to
# fetch the source without '?submodules=1' # fetch the source without '?submodules=1'
udis86 = final: prev: { udis86 = final: prev: {
udis86-hyprland = prev.udis86.overrideAttrs (_self: _super: { udis86-hyprland = prev.udis86.overrideAttrs (self: super: {
src = final.fetchFromGitHub { src = final.fetchFromGitHub {
owner = "canihavesomecoffee"; owner = "canihavesomecoffee";
repo = "udis86"; repo = "udis86";

View File

@@ -7,7 +7,7 @@ wayland_protos = dependency(
hyprland_protos = dependency( hyprland_protos = dependency(
'hyprland-protocols', 'hyprland-protocols',
version: '>=0.4', version: '>=0.2',
fallback: 'hyprland-protocols', fallback: 'hyprland-protocols',
) )
@@ -36,7 +36,6 @@ protocols = [
hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml',
wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml', wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml',
wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
@@ -65,7 +64,6 @@ protocols = [
wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml',
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
wayland_protocol_dir / 'staging/security-context/security-context-v1.xml',
] ]
wl_protocols = [] wl_protocols = []

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <deque>
#include <list> #include <list>
#include <sys/resource.h> #include <sys/resource.h>
@@ -34,7 +35,7 @@
class CWLSurfaceResource; class CWLSurfaceResource;
enum eManagersInitStage : uint8_t { enum eManagersInitStage {
STAGE_PRIORITY = 0, STAGE_PRIORITY = 0,
STAGE_BASICINIT, STAGE_BASICINIT,
STAGE_LATE STAGE_LATE
@@ -58,8 +59,8 @@ class CCompositor {
std::string m_szInstancePath = ""; std::string m_szInstancePath = "";
std::string m_szCurrentSplash = "error"; std::string m_szCurrentSplash = "error";
std::vector<PHLMONITOR> m_vMonitors; std::vector<SP<CMonitor>> m_vMonitors;
std::vector<PHLMONITOR> m_vRealMonitors; // for all monitors, even those turned off std::vector<SP<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
std::vector<PHLWINDOW> m_vWindows; std::vector<PHLWINDOW> m_vWindows;
std::vector<PHLLS> m_vLayers; std::vector<PHLLS> m_vLayers;
std::vector<PHLWORKSPACE> m_vWorkspaces; std::vector<PHLWORKSPACE> m_vWorkspaces;
@@ -79,7 +80,7 @@ class CCompositor {
WP<CWLSurfaceResource> m_pLastFocus; WP<CWLSurfaceResource> m_pLastFocus;
PHLWINDOWREF m_pLastWindow; PHLWINDOWREF m_pLastWindow;
PHLMONITORREF m_pLastMonitor; WP<CMonitor> m_pLastMonitor;
std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused. std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused.
@@ -88,7 +89,7 @@ class CCompositor {
bool m_bDPMSStateON = true; bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; bool m_bNextIsUnsafe = false;
PHLMONITORREF m_pUnsafeOutput; // fallback output for the unsafe state CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bIsShuttingDown = false; bool m_bIsShuttingDown = false;
bool m_bFinalRequests = false; bool m_bFinalRequests = false;
bool m_bDesktopEnvSet = false; bool m_bDesktopEnvSet = false;
@@ -96,29 +97,39 @@ class CCompositor {
// ------------------------------------------------- // // ------------------------------------------------- //
PHLMONITOR getMonitorFromID(const MONITORID&); CMonitor* getMonitorFromID(const MONITORID&);
PHLMONITOR getMonitorFromName(const std::string&); CMonitor* getMonitorFromName(const std::string&);
PHLMONITOR getMonitorFromDesc(const std::string&); CMonitor* getMonitorFromDesc(const std::string&);
PHLMONITOR getMonitorFromCursor(); CMonitor* getMonitorFromCursor();
PHLMONITOR getMonitorFromVector(const Vector2D&); CMonitor* getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(PHLWINDOW); void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr); void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr);
void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr); void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr);
bool monitorExists(PHLMONITOR); bool monitorExists(CMonitor*);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, PHLMONITOR monitor, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
PHLMONITOR getMonitorFromOutput(SP<Aquamarine::IOutput>); CMonitor* getMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLMONITOR getRealMonitorFromOutput(SP<Aquamarine::IOutput>); CMonitor* getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>); PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
PHLWINDOW getWindowFromHandle(uint32_t); PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE);
bool isWorkspaceVisibleNotCovered(PHLWORKSPACE);
PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&); PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&);
PHLWORKSPACE getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByName(const std::string&);
PHLWORKSPACE getWorkspaceByString(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces(); void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const WORKSPACEID&);
void updateWorkspaceWindowData(const WORKSPACEID&);
int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
PHLWINDOW getUrgentWindow(); PHLWINDOW getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&);
bool isWindowActive(PHLWINDOW); bool isWindowActive(PHLWINDOW);
void changeWindowZOrder(PHLWINDOW, bool); void changeWindowZOrder(PHLWINDOW, bool);
void cleanupFadingOut(const MONITORID& monid); void cleanupFadingOut(const MONITORID& monid);
@@ -127,24 +138,25 @@ class CCompositor {
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
WORKSPACEID getNextAvailableNamedWorkspace(); WORKSPACEID getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr); bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
PHLMONITOR getMonitorInDirection(const char&); CMonitor* getMonitorInDirection(const char&);
PHLMONITOR getMonitorInDirection(PHLMONITOR, const char&); CMonitor* getMonitorInDirection(CMonitor*, const char&);
void updateAllWindowsAnimatedDecorationValues(); void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const WORKSPACEID& id);
void updateWindowAnimatedDecorationValues(PHLWINDOW); void updateWindowAnimatedDecorationValues(PHLWINDOW);
MONITORID getNextAvailableMonitorID(std::string const& name); MONITORID getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false); void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(PHLMONITOR, PHLMONITOR); void swapActiveWorkspaces(CMonitor*, CMonitor*);
PHLMONITOR getMonitorFromString(const std::string&); CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const WORKSPACEID&); bool workspaceIDOutOfBounds(const WORKSPACEID&);
void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const SFullscreenState state); void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state);
void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON); void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON); void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW); PHLWINDOW getX11Parent(PHLWINDOW);
void scheduleFrameForMonitor(PHLMONITOR, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN); void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
void addToFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLLS);
void removeFromFadingOutSafe(PHLLS); void removeFromFadingOutSafe(PHLLS);
void addToFadingOutSafe(PHLWINDOW); void addToFadingOutSafe(PHLWINDOW);
@@ -153,9 +165,11 @@ class CCompositor {
PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>); PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>);
void closeWindow(PHLWINDOW); void closeWindow(PHLWINDOW);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&);
PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "",
bool isEmpty = true); // will be deleted next frame if left empty and unfocused! bool isEmpty = true); // will be deleted next frame if left empty and unfocused!
void setActiveMonitor(PHLMONITOR); void renameWorkspace(const WORKSPACEID&, const std::string& name = "");
void setActiveMonitor(CMonitor*);
bool isWorkspaceSpecial(const WORKSPACEID&); bool isWorkspaceSpecial(const WORKSPACEID&);
WORKSPACEID getNewSpecialID(); WORKSPACEID getNewSpecialID();
void performUserChecks(); void performUserChecks();

View File

@@ -5,7 +5,9 @@
#include <any> #include <any>
#include <hyprutils/math/Box.hpp> #include <hyprutils/math/Box.hpp>
enum eIcons : uint8_t { using namespace Hyprutils::Math;
enum eIcons {
ICON_WARNING = 0, ICON_WARNING = 0,
ICON_INFO, ICON_INFO,
ICON_HINT, ICON_HINT,
@@ -15,7 +17,7 @@ enum eIcons : uint8_t {
ICON_NONE ICON_NONE
}; };
enum eRenderStage : uint8_t { enum eRenderStage {
RENDER_PRE = 0, /* Before binding the gl context */ RENDER_PRE = 0, /* Before binding the gl context */
RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */ RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */
RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */ RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */
@@ -27,7 +29,7 @@ enum eRenderStage : uint8_t {
RENDER_POST_WINDOW, /* After rendering a window (any pass) */ RENDER_POST_WINDOW, /* After rendering a window (any pass) */
}; };
enum eInputType : uint8_t { enum eInputType {
INPUT_TYPE_AXIS = 0, INPUT_TYPE_AXIS = 0,
INPUT_TYPE_BUTTON, INPUT_TYPE_BUTTON,
INPUT_TYPE_DRAG_START, INPUT_TYPE_DRAG_START,
@@ -39,7 +41,7 @@ struct SCallbackInfo {
bool cancelled = false; /* on cancellable events, will cancel the event. */ bool cancelled = false; /* on cancellable events, will cancel the event. */
}; };
enum eHyprCtlOutputFormat : uint8_t { enum eHyprCtlOutputFormat {
FORMAT_NORMAL = 0, FORMAT_NORMAL = 0,
FORMAT_JSON FORMAT_JSON
}; };

View File

@@ -3,7 +3,7 @@
#include "../helpers/varlist/VarList.hpp" #include "../helpers/varlist/VarList.hpp"
#include <vector> #include <vector>
enum eConfigValueDataTypes : int8_t { enum eConfigValueDataTypes {
CVD_TYPE_INVALID = -1, CVD_TYPE_INVALID = -1,
CVD_TYPE_GRADIENT = 0, CVD_TYPE_GRADIENT = 0,
CVD_TYPE_CSS_VALUE = 1 CVD_TYPE_CSS_VALUE = 1
@@ -20,40 +20,24 @@ class ICustomConfigValueData {
class CGradientValueData : public ICustomConfigValueData { class CGradientValueData : public ICustomConfigValueData {
public: public:
CGradientValueData() = default; CGradientValueData() {};
CGradientValueData(CHyprColor col) { CGradientValueData(CColor col) {
m_vColors.push_back(col); m_vColors.push_back(col);
updateColorsOk();
}; };
virtual ~CGradientValueData() = default; virtual ~CGradientValueData() {};
virtual eConfigValueDataTypes getDataType() { virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_GRADIENT; return CVD_TYPE_GRADIENT;
} }
void reset(CHyprColor col) { void reset(CColor col) {
m_vColors.clear(); m_vColors.clear();
m_vColors.emplace_back(col); m_vColors.emplace_back(col);
m_fAngle = 0; m_fAngle = 0;
updateColorsOk();
}
void updateColorsOk() {
m_vColorsOkLabA.clear();
for (auto& c : m_vColors) {
const auto OKLAB = c.asOkLab();
m_vColorsOkLabA.emplace_back(OKLAB.l);
m_vColorsOkLabA.emplace_back(OKLAB.a);
m_vColorsOkLabA.emplace_back(OKLAB.b);
m_vColorsOkLabA.emplace_back(c.a);
}
} }
/* Vector containing the colors */ /* Vector containing the colors */
std::vector<CHyprColor> m_vColors; std::vector<CColor> m_vColors;
/* Vector containing pure colors for shoving into opengl */
std::vector<float> m_vColorsOkLabA;
/* Float corresponding to the angle (rad) */ /* Float corresponding to the angle (rad) */
float m_fAngle = 0; float m_fAngle = 0;

View File

@@ -104,30 +104,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{0, 0, 4}, .data = SConfigOptionDescription::SRangeData{0, 0, 4},
}, },
SConfigOptionDescription{
.value = "general:snap:enabled",
.description = "enable snapping for floating windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "general:snap:window_gap",
.description = "minimum gap in pixels between windows before snapping",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{10, 0, 100},
},
SConfigOptionDescription{
.value = "general:snap:monitor_gap",
.description = "minimum gap in pixels between window and monitor edges before snapping",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{10, 0, 100},
},
SConfigOptionDescription{
.value = "general:snap:border_overlap",
.description = "if true, windows snap such that only one border's worth of space is between them",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* decoration: * decoration:
@@ -158,55 +134,49 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SFloatData{1, 0, 1}, .data = SConfigOptionDescription::SFloatData{1, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:enabled", .value = "decoration:drop_shadow",
.description = "enable drop shadows on windows", .description = "enable drop shadows on windows",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:range", .value = "decoration:shadow_range",
.description = "Shadow range (size) in layout px", .description = "Shadow range (size) in layout px",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{4, 0, 100}, .data = SConfigOptionDescription::SRangeData{4, 0, 100},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:render_power", .value = "decoration:shadow_render_power",
.description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]", .description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{3, 1, 4}, .data = SConfigOptionDescription::SRangeData{3, 1, 4},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:sharp", .value = "decoration:shadow_ignore_window",
.description = "whether the shadow should be sharp or not. Akin to an infinitely high render power.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "decoration:shadow:ignore_window",
.description = "if true, the shadow will not be rendered behind the window itself, only around it.", .description = "if true, the shadow will not be rendered behind the window itself, only around it.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:color", .value = "decoration:col.shadow",
.description = "shadow's color. Alpha dictates shadow's opacity.", .description = "shadow's color. Alpha dictates shadow's opacity.",
.type = CONFIG_OPTION_COLOR, .type = CONFIG_OPTION_COLOR,
.data = SConfigOptionDescription::SColorData{0xee1a1a1a}, .data = SConfigOptionDescription::SColorData{0xee1a1a1a},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:color_inactive", .value = "decoration:col.shadow_inactive",
.description = "inactive shadow color. (if not set, will fall back to col.shadow)", .description = "inactive shadow color. (if not set, will fall back to col.shadow)",
.type = CONFIG_OPTION_COLOR, .type = CONFIG_OPTION_COLOR,
.data = SConfigOptionDescription::SColorData{}, //TODO: UNSET? .data = SConfigOptionDescription::SColorData{}, //##TODO UNSET?
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:offset", .value = "decoration:shadow_offset",
.description = "shadow's rendering offset.", .description = "shadow's rendering offset.",
.type = CONFIG_OPTION_VECTOR, .type = CONFIG_OPTION_VECTOR,
.data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}}, .data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:scale", .value = "decoration:shadow_scale",
.description = "shadow's scale. [0.0 - 1.0]", .description = "shadow's scale. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1}, .data = SConfigOptionDescription::SFloatData{1, 0, 1},
@@ -268,7 +238,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "blur:ignore_opacity", .value = "blur:ignore_opacity",
.description = "make the blur layer ignore the opacity of the window", .description = "make the blur layer ignore the opacity of the window",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "blur:new_optimizations", .value = "blur:new_optimizations",
@@ -331,18 +301,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
}, },
SConfigOptionDescription{
.value = "blur:input_methods",
.description = "whether to blur input methods (e.g. fcitx5)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "blur:input_methods_ignorealpha",
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
},
/* /*
* animations: * animations:
@@ -632,22 +590,16 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "input:tablet:output", .value = "input:tablet:output",
.description = "the monitor to bind tablets. Can be current or a monitor name. Leave empty to map across all monitors.", .description = "the monitor to bind tablets. Empty means unbound..",
.type = CONFIG_OPTION_STRING_SHORT, .type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "input:tablet:region_position", .value = "input:tablet:region_position",
.description = "position of the mapped region in monitor layout relative to the top left corner of the bound monitor or all monitors.", .description = "position of the mapped region in monitor layout.",
.type = CONFIG_OPTION_VECTOR, .type = CONFIG_OPTION_VECTOR,
.data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}}, .data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}},
}, },
SConfigOptionDescription{
.value = "input:tablet:absolute_region_position",
.description = "whether to treat the region_position as an absolute position in monitor layout. Only applies when output is empty.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "input:tablet:region_size", .value = "input:tablet:region_size",
.description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.", .description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.",
@@ -796,12 +748,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "group:merge_groups_on_groupbar",
.description = "whether one group will be merged with another when dragged into its groupbar",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "general:col.border_active", .value = "general:col.border_active",
.description = "border color for inactive windows", .description = "border color for inactive windows",
@@ -832,24 +778,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "group:drag_into_group",
.description = "whether dragging a window into a unlocked group will merge them. Options: 0 (disabled), 1 (enabled), 2 (only when dragging into the groupbar)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "disabled,enabled,only when dragging into the groupbar"},
},
SConfigOptionDescription{
.value = "group:merge_floated_into_tiled_on_groupbar",
.description = "whether dragging a floating window into a tiled window groupbar will merge them",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "group:group_on_movetoworkspace",
.description = "whether using movetoworkspace[silent] will merge the window into the workspace's solitary unlocked group",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* group:groupbar: * group:groupbar:
@@ -1133,18 +1061,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "misc:disable_hyprland_qtutils_check",
.description = "disable the warning if hyprland-qtutils is missing",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "misc:lockdead_screen_delay",
.description = "the delay in ms after the lockdead screen appears if the lock screen did not appear after a lock event occurred.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1000, 0, 5000},
},
/* /*
* binds: * binds:
@@ -1200,12 +1116,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "binds:movefocus_cycles_groupfirst",
.description = "If enabled, when in a grouped window, movefocus will cycle windows in the groups first, then at each ends of tabs, it'll move on to other windows/groups",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "binds:disable_keybind_grabbing", .value = "binds:disable_keybind_grabbing",
.description = "If enabled, apps that request keybinds to be disabled (e.g. VMs) will not be able to do so.", .description = "If enabled, apps that request keybinds to be disabled (e.g. VMs) will not be able to do so.",
@@ -1218,12 +1128,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "binds:allow_pin_fullscreen",
.description = "Allows fullscreen to pinned windows, and restore their pinned status afterwards",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* xwayland: * xwayland:
@@ -1304,8 +1208,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_hardware_cursors", .value = "cursor:no_hardware_cursors",
.description = "disables hardware cursors", .description = "disables hardware cursors",
.type = CONFIG_OPTION_CHOICE, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_break_fs_vrr", .value = "cursor:no_break_fs_vrr",
@@ -1345,9 +1249,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:warp_on_change_workspace", .value = "cursor:warp_on_change_workspace",
.description = "Move the cursor to the last focused window after changing the workspace. Options: 0 (Disabled), 1 (Enabled), 2 (Force - ignores cursor:no_warps option)", .description = "If true, move the cursor to the last focused window after changing the workspace.",
.type = CONFIG_OPTION_CHOICE, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:default_monitor", .value = "cursor:default_monitor",
@@ -1386,8 +1290,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:use_cpu_buffer", .value = "cursor:allow_dumb_copy",
.description = "Makes HW cursors use a CPU buffer. Required on Nvidia to have HW cursors. Experimental", .description = "Makes HW cursors work on Nvidia, at the cost of a possible hitch whenever the image changes",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
@@ -1530,6 +1434,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0.1, 3}, .data = SConfigOptionDescription::SFloatData{1, 0.1, 3},
}, },
SConfigOptionDescription{
.value = "dwindle:no_gaps_when_only",
.description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "dwindle:use_active_for_splits", .value = "dwindle:use_active_for_splits",
.description = "whether to prefer the active window or the mouse position for splits", .description = "whether to prefer the active window or the mouse position for splits",
@@ -1590,6 +1500,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_STRING_SHORT, .type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"none"}, .data = SConfigOptionDescription::SStringData{"none"},
}, },
SConfigOptionDescription{
.value = "master:no_gaps_when_only",
.description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "master:orientation", .value = "master:orientation",
.description = "default placement of the master area, can be left, right, top, bottom or center", .description = "default placement of the master area, can be left, right, top, bottom or center",
@@ -1608,12 +1524,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "master:center_ignores_reserved",
.description = "centers the master window on monitor ignoring reserved areas",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "master:smart_resizing", .value = "master:smart_resizing",
.description = .description =

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,9 @@
#include "../defines.hpp" #include "../defines.hpp"
#include <variant> #include <variant>
#include <vector> #include <vector>
#include <deque>
#include <algorithm> #include <algorithm>
#include <regex>
#include <optional> #include <optional>
#include <functional> #include <functional>
#include <xf86drmMode.h> #include <xf86drmMode.h>
@@ -67,13 +69,13 @@ struct SAnimationPropertyConfig {
}; };
struct SPluginKeyword { struct SPluginKeyword {
HANDLE handle = nullptr; HANDLE handle = 0;
std::string name = ""; std::string name = "";
Hyprlang::PCONFIGHANDLERFUNC fn = nullptr; Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
}; };
struct SPluginVariable { struct SPluginVariable {
HANDLE handle = nullptr; HANDLE handle = 0;
std::string name = ""; std::string name = "";
}; };
@@ -82,7 +84,7 @@ struct SExecRequestedRule {
uint64_t iPid = 0; uint64_t iPid = 0;
}; };
enum eConfigOptionType : uint8_t { enum eConfigOptionType : uint16_t {
CONFIG_OPTION_BOOL = 0, CONFIG_OPTION_BOOL = 0,
CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/ CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/
CONFIG_OPTION_FLOAT = 2, CONFIG_OPTION_FLOAT = 2,
@@ -94,7 +96,7 @@ enum eConfigOptionType : uint8_t {
CONFIG_OPTION_VECTOR = 8, CONFIG_OPTION_VECTOR = 8,
}; };
enum eConfigOptionFlags : uint8_t { enum eConfigOptionFlags : uint32_t {
CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0), CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0),
}; };
@@ -117,7 +119,7 @@ struct SConfigOptionDescription {
}; };
struct SColorData { struct SColorData {
CHyprColor color; CColor color;
}; };
struct SChoiceData { struct SChoiceData {
@@ -165,18 +167,18 @@ class CConfigManager {
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = ""); Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load); void onPluginLoadUnload(const std::string& name, bool load);
static std::string getMainConfigPath(); static std::string getMainConfigPath();
std::string getConfigString(); const std::string getConfigString();
SMonitorRule getMonitorRuleFor(const PHLMONITOR); SMonitorRule getMonitorRuleFor(const SP<CMonitor>);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
std::string getDefaultWorkspaceFor(const std::string&); std::string getDefaultWorkspaceFor(const std::string&);
PHLMONITOR getBoundMonitorForWS(const std::string&); CMonitor* getBoundMonitorForWS(const std::string&);
std::string getBoundMonitorStringForWS(const std::string&); std::string getBoundMonitorStringForWS(const std::string&);
const std::vector<SWorkspaceRule>& getAllWorkspaceRules(); const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
std::vector<SP<CWindowRule>> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false); std::vector<SWindowRule> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
std::vector<SP<CLayerRule>> getMatchingRules(PHLLS); std::vector<SLayerRule> getMatchingRules(PHLLS);
const std::vector<SConfigOptionDescription>& getAllDescriptions(); const std::vector<SConfigOptionDescription>& getAllDescriptions();
@@ -196,9 +198,7 @@ class CConfigManager {
void appendMonitorRule(const SMonitorRule&); void appendMonitorRule(const SMonitorRule&);
bool replaceMonitorRule(const SMonitorRule&); bool replaceMonitorRule(const SMonitorRule&);
void ensureMonitorStatus(); void ensureMonitorStatus();
void ensureVRR(PHLMONITOR pMonitor = nullptr); void ensureVRR(CMonitor* pMonitor = nullptr);
bool shouldUseSoftwareCursors();
std::string parseKeyword(const std::string&, const std::string&); std::string parseKeyword(const std::string&, const std::string&);
@@ -212,58 +212,52 @@ class CConfigManager {
std::string getErrors(); std::string getErrors();
// keywords // keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&); std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&); std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleExecShutdown(const std::string&, const std::string&); std::optional<std::string> handleExecShutdown(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&); std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&); std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&); std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&); std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&); std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&); std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&); std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&); std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&); std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&); std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&); std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&); std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&); std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&); std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&); std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::string configCurrentPath; std::string configCurrentPath;
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> mbWindowProperties = { std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(PHLWINDOW)>> mbWindowProperties = {
{"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.allowsInput; }}, {"allowsinput", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.dimAround; }}, {"dimaround", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.decorate; }}, {"decorate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }}, {"focusonactivate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }}, {"keepaspectratio", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }}, {"nearestneighbor", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noAnim; }}, {"noanim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBlur; }}, {"noblur", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBorder; }}, {"noborder", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noDim; }}, {"nodim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noFocus; }}, {"nofocus", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noMaxSize; }}, {"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noRounding; }}, {"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShadow; }}, {"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }}, {"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.opaque; }}, {"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.RGBX; }}, {"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }}, {"syncfullscreen", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.tearing; }}, {"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }}, {"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }},
}; };
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> miWindowProperties = { std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(PHLWINDOW)>> miWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> mfWindowProperties = {
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}};
bool m_bWantsMonitorReload = false; bool m_bWantsMonitorReload = false;
bool m_bForceReload = false; bool m_bForceReload = false;
@@ -273,7 +267,7 @@ class CConfigManager {
private: private:
std::unique_ptr<Hyprlang::CConfig> m_pConfig; std::unique_ptr<Hyprlang::CConfig> m_pConfig;
std::vector<std::string> configPaths; // stores all the config paths std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
@@ -288,16 +282,16 @@ class CConfigManager {
bool isFirstLaunch = true; // For exec-once bool isFirstLaunch = true; // For exec-once
std::vector<SMonitorRule> m_vMonitorRules; std::deque<SMonitorRule> m_dMonitorRules;
std::vector<SWorkspaceRule> m_vWorkspaceRules; std::deque<SWorkspaceRule> m_dWorkspaceRules;
std::vector<SP<CWindowRule>> m_vWindowRules; std::deque<SWindowRule> m_dWindowRules;
std::vector<SP<CLayerRule>> m_vLayerRules; std::deque<SLayerRule> m_dLayerRules;
std::vector<std::string> m_dBlurLSNamespaces; std::deque<std::string> m_dBlurLSNamespaces;
bool firstExecDispatched = false; bool firstExecDispatched = false;
bool m_bManualCrashInitiated = false; bool m_bManualCrashInitiated = false;
std::vector<std::string> firstExecRequests; std::deque<std::string> firstExecRequests;
std::vector<std::string> finalExecRequests; std::deque<std::string> finalExecRequests;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_szConfigErrors = ""; std::string m_szConfigErrors = "";

View File

@@ -13,7 +13,6 @@ class CConfigValue {
CConfigValue(const std::string& val) { CConfigValue(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val); const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
// NOLINTNEXTLINE
p_ = PVHYPRLANG->getDataStaticPtr(); p_ = PVHYPRLANG->getDataStaticPtr();
#ifdef HYPRLAND_DEBUG #ifdef HYPRLAND_DEBUG

View File

@@ -4,8 +4,8 @@
inline const std::string AUTOCONFIG = R"#( inline const std::string AUTOCONFIG = R"#(
# ####################################################################################### # #######################################################################################
# AUTOGENERATED HYPRLAND CONFIG. # AUTOGENERATED HYPR CONFIG.
# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hyprland.conf AND EDIT IT, # PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS. # OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
# ####################################################################################### # #######################################################################################
@@ -13,7 +13,7 @@ autogenerated = 1 # remove this line to remove the warning
# This is an example Hyprland config file. # This is an example Hyprland config file.
# Refer to the wiki for more information. # Refer to the wiki for more information.
# https://wiki.hyprland.org/Configuring/ # https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
# Please note not all available settings / options are set here. # Please note not all available settings / options are set here.
# For a full list, see the wiki # For a full list, see the wiki
@@ -99,12 +99,10 @@ decoration {
active_opacity = 1.0 active_opacity = 1.0
inactive_opacity = 1.0 inactive_opacity = 1.0
shadow { drop_shadow = true
enabled = true shadow_range = 4
range = 4 shadow_render_power = 3
render_power = 3 col.shadow = rgba(1a1a1aee)
color = rgba(1a1a1aee)
}
# https://wiki.hyprland.org/Configuring/Variables/#blur # https://wiki.hyprland.org/Configuring/Variables/#blur
blur { blur {
@@ -118,44 +116,20 @@ decoration {
# https://wiki.hyprland.org/Configuring/Variables/#animations # https://wiki.hyprland.org/Configuring/Variables/#animations
animations { animations {
enabled = yes, please :) enabled = true
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = easeOutQuint,0.23,1,0.32,1 bezier = myBezier, 0.05, 0.9, 0.1, 1.05
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = global, 1, 10, default animation = windows, 1, 7, myBezier
animation = border, 1, 5.39, easeOutQuint animation = windowsOut, 1, 7, default, popin 80%
animation = windows, 1, 4.79, easeOutQuint animation = border, 1, 10, default
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% animation = borderangle, 1, 8, default
animation = windowsOut, 1, 1.49, linear, popin 87% animation = fade, 1, 7, default
animation = fadeIn, 1, 1.73, almostLinear animation = workspaces, 1, 6, default
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, fade
animation = workspacesIn, 1, 1.21, almostLinear, fade
animation = workspacesOut, 1, 1.94, almostLinear, fade
} }
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below

View File

@@ -2,8 +2,8 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <link.h> #include <link.h>
#include <ctime> #include <time.h>
#include <cerrno> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <filesystem> #include <filesystem>
@@ -31,10 +31,10 @@ static char const* const MESSAGES[] = {"Sorry, didn't mean to...",
// <random> is not async-signal-safe, fake it with time(NULL) instead // <random> is not async-signal-safe, fake it with time(NULL) instead
char const* getRandomMessage() { char const* getRandomMessage() {
return MESSAGES[time(nullptr) % (sizeof(MESSAGES) / sizeof(MESSAGES[0]))]; return MESSAGES[time(NULL) % (sizeof(MESSAGES) / sizeof(MESSAGES[0]))];
} }
[[noreturn]] inline void exitWithError(char const* err) { [[noreturn]] inline void exit_with_error(char const* err) {
write(STDERR_FILENO, err, strlen(err)); write(STDERR_FILENO, err, strlen(err));
// perror() is not signal-safe, but we use it here // perror() is not signal-safe, but we use it here
// because if the crash-handler already crashed, it can't get any worse. // because if the crash-handler already crashed, it can't get any worse.
@@ -42,17 +42,17 @@ char const* getRandomMessage() {
abort(); abort();
} }
void NCrashReporter::createAndSaveCrash(int sig) { void CrashReporter::createAndSaveCrash(int sig) {
int reportFd = -1; int reportFd;
// We're in the signal handler, so we *only* have stack memory. // We're in the signal handler, so we *only* have stack memory.
// To save as much stack memory as possible, // To save as much stack memory as possible,
// destroy things as soon as possible. // destroy things as soon as possible.
{ {
CMaxLengthCString<255> reportPath; MaxLengthCString<255> reportPath;
const auto HOME = sigGetenv("HOME"); const auto HOME = sig_getenv("HOME");
const auto CACHE_HOME = sigGetenv("XDG_CACHE_HOME"); const auto CACHE_HOME = sig_getenv("XDG_CACHE_HOME");
if (CACHE_HOME && CACHE_HOME[0] != '\0') { if (CACHE_HOME && CACHE_HOME[0] != '\0') {
reportPath += CACHE_HOME; reportPath += CACHE_HOME;
@@ -61,24 +61,24 @@ void NCrashReporter::createAndSaveCrash(int sig) {
reportPath += HOME; reportPath += HOME;
reportPath += "/.cache/hyprland"; reportPath += "/.cache/hyprland";
} else { } else {
exitWithError("$CACHE_HOME and $HOME not set, nowhere to report crash\n"); exit_with_error("$CACHE_HOME and $HOME not set, nowhere to report crash\n");
return; return;
} }
int ret = mkdir(reportPath.getStr(), S_IRWXU); int ret = mkdir(reportPath.get_str(), S_IRWXU);
//__asm__("int $3"); //__asm__("int $3");
if (ret < 0 && errno != EEXIST) { if (ret < 0 && errno != EEXIST) {
exitWithError("failed to mkdir() crash report directory\n"); exit_with_error("failed to mkdir() crash report directory\n");
} }
reportPath += "/hyprlandCrashReport"; reportPath += "/hyprlandCrashReport";
reportPath.writeNum(getpid()); reportPath.write_num(getpid());
reportPath += ".txt"; reportPath += ".txt";
{ {
CBufFileWriter<64> stderr(2); BufFileWriter<64> stderr(2);
stderr += "Hyprland has crashed :( Consult the crash report at "; stderr += "Hyprland has crashed :( Consult the crash report at ";
if (!reportPath.boundsExceeded()) { if (!reportPath.boundsExceeded()) {
stderr += reportPath.getStr(); stderr += reportPath.get_str();
} else { } else {
stderr += "[ERROR: Crash report path does not fit into memory! Check if your $CACHE_HOME/$HOME is too deeply nested. Max 255 characters.]"; stderr += "[ERROR: Crash report path does not fit into memory! Check if your $CACHE_HOME/$HOME is too deeply nested. Max 255 characters.]";
} }
@@ -86,12 +86,12 @@ void NCrashReporter::createAndSaveCrash(int sig) {
stderr.flush(); stderr.flush();
} }
reportFd = open(reportPath.getStr(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (reportFd < 0) { if (reportFd < 0) {
exitWithError("Failed to open crash report path for writing"); exit_with_error("Failed to open crash report path for writing");
} }
} }
CBufFileWriter<512> finalCrashReport(reportFd); BufFileWriter<512> finalCrashReport(reportFd);
finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n"; finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n";
finalCrashReport += getRandomMessage(); finalCrashReport += getRandomMessage();
@@ -100,7 +100,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "Hyprland received signal "; finalCrashReport += "Hyprland received signal ";
finalCrashReport.writeNum(sig); finalCrashReport.writeNum(sig);
finalCrashReport += '('; finalCrashReport += '(';
finalCrashReport += sigStrsignal(sig); finalCrashReport += sig_strsignal(sig);
finalCrashReport += ")\nVersion: "; finalCrashReport += ")\nVersion: ";
finalCrashReport += GIT_COMMIT_HASH; finalCrashReport += GIT_COMMIT_HASH;
finalCrashReport += "\nTag: "; finalCrashReport += "\nTag: ";
@@ -122,9 +122,9 @@ void NCrashReporter::createAndSaveCrash(int sig) {
if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) { if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) {
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n"; finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
const size_t count = g_pPluginSystem->pluginCount(); size_t count = g_pPluginSystem->pluginCount();
std::vector<CPlugin*> plugins(count); CPlugin* plugins[count];
g_pPluginSystem->sigGetPlugins(plugins.data(), count); g_pPluginSystem->sig_getPlugins(plugins, count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
auto p = plugins[i]; auto p = plugins[i];
@@ -159,7 +159,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "GPU:\n\t"; finalCrashReport += "GPU:\n\t";
#if defined(__DragonFly__) || defined(__FreeBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__)
finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga"); finalCrashReport.writeCmdOutput("pciconf -lv | fgrep -A4 vga");
#else #else
finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA"); finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA");
#endif #endif
@@ -241,5 +241,5 @@ void NCrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "\n\nLog tail:\n"; finalCrashReport += "\n\nLog tail:\n";
finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find('\n') + 1); finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find("\n") + 1);
} }

View File

@@ -2,6 +2,6 @@
#include "../defines.hpp" #include "../defines.hpp"
namespace NCrashReporter { namespace CrashReporter {
void createAndSaveCrash(int sig); void createAndSaveCrash(int sig);
}; };

View File

@@ -1,13 +1,10 @@
#include "HyprCtl.hpp" #include "HyprCtl.hpp"
#include <algorithm>
#include <format> #include <format>
#include <fstream>
#include <iterator>
#include <netinet/in.h> #include <netinet/in.h>
#include <cstdio> #include <stdio.h>
#include <cstdlib> #include <stdlib.h>
#include <cstring> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@@ -39,7 +36,6 @@ using namespace Hyprutils::String;
#include "debug/RollingLogFollow.hpp" #include "debug/RollingLogFollow.hpp"
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "helpers/MiscFunctions.hpp" #include "helpers/MiscFunctions.hpp"
#include "../version.h"
static void trimTrailingComma(std::string& str) { static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',') if (!str.empty() && str.back() == ',')
@@ -58,7 +54,7 @@ static std::string formatToString(uint32_t drmFormat) {
return "Invalid"; return "Invalid";
} }
static std::string availableModesForOutput(PHLMONITOR pMonitor, eHyprCtlOutputFormat format) { static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) {
std::string result; std::string result;
for (auto const& m : pMonitor->output->modes) { for (auto const& m : pMonitor->output->modes) {
@@ -109,10 +105,8 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"vrr": {}, "vrr": {},
"solitary": "{:x}", "solitary": "{:x}",
"activelyTearing": {}, "activelyTearing": {},
"directScanoutTo": "{:x}",
"disabled": {}, "disabled": {},
"currentFormat": "{}", "currentFormat": "{}",
"mirrorOf": "{}",
"availableModes": [{}] "availableModes": [{}]
}},)#", }},)#",
@@ -122,21 +116,19 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(), (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(),
(m->tearingState.activelyTearing ? "true" : "false"), (uint64_t)m->lastScanout.get(), (m->m_bEnabled ? "false" : "true"), (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat),
formatToString(m->output->state->state().drmFormat), m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format)); availableModesForOutput(m.get(), format));
} else { } else {
result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdirectScanoutTo: {:x}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tmirrorOf: " "dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
"{}\n\tavailableModes: {}\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->szShortDescription, 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->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(), (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(),
m->tearingState.activelyTearing, (uint64_t)m->lastScanout.get(), !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format));
} }
return result; return result;
@@ -245,27 +237,26 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"grouped": [{}], "grouped": [{}],
"tags": [{}], "tags": [{}],
"swallowing": "0x{:x}", "swallowing": "0x{:x}",
"focusHistoryID": {}, "focusHistoryID": {}
"inhibitingIdle": {}
}},)#", }},)#",
(uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"),
(int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), (int64_t)w->m_iMonitorID, escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass),
escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
(uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false")); (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
} else { } else {
return std::format( return std::format(
"Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: " "Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\txwayland: {}\n\tpinned: " "{}\n\txwayland: {}\n\tpinned: "
"{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\tinhibitingIdle: {}\n\n", "{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName),
(int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(),
(int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (int)g_pInputManager->isWindowInhibiting(w, false)); (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
} }
} }
@@ -297,7 +288,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) { std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) {
const auto PLASTW = w->getLastFocusedWindow(); const auto PLASTW = w->getLastFocusedWindow();
const auto PMONITOR = w->m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID);
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
return std::format(R"#({{ return std::format(R"#({{
"id": {}, "id": {},
@@ -310,12 +301,12 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form
"lastwindowtitle": "{}" "lastwindowtitle": "{}"
}})#", }})#",
w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"), w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"),
escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), g_pCompositor->getWindowsOnWorkspace(w->m_iID),
(uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : ""); ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
} else { } else {
return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID, return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID,
w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow, w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", g_pCompositor->getWindowsOnWorkspace(w->m_iID),
(uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : ""); (int)w->m_bHasFullscreenWindow, (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "");
} }
} }
@@ -538,7 +529,7 @@ std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request
CVarList errLines(currErrors, 0, '\n'); CVarList errLines(currErrors, 0, '\n');
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (const auto& line : errLines) { for (auto line : errLines) {
result += std::format( result += std::format(
R"#( R"#(
"{}",)#", "{}",)#",
@@ -548,7 +539,7 @@ std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request
trimTrailingComma(result); trimTrailingComma(result);
result += "\n]\n"; result += "\n]\n";
} else { } else {
for (const auto& line : errLines) { for (auto line : errLines) {
result += std::format("{}\n", line); result += std::format("{}\n", line);
} }
} }
@@ -558,15 +549,6 @@ std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request
std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
auto getModState = [](SP<IKeyboard> keyboard, const char* xkbModName) -> bool {
auto IDX = xkb_keymap_mod_get_index(keyboard->xkbKeymap, xkbModName);
if (IDX == XKB_MOD_INVALID)
return false;
return (keyboard->modifiersState.locked & (1 << IDX)) > 0;
};
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n"; result += "{\n";
result += "\"mice\": [\n"; result += "\"mice\": [\n";
@@ -598,13 +580,11 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
"variant": "{}", "variant": "{}",
"options": "{}", "options": "{}",
"active_keymap": "{}", "active_keymap": "{}",
"capsLock": {},
"numLock": {},
"main": {} "main": {}
}},)#", }},)#",
(uintptr_t)k.get(), escapeJSONStrings(k->hlName), escapeJSONStrings(k->currentRules.rules), escapeJSONStrings(k->currentRules.model), (uintptr_t)k.get(), escapeJSONStrings(k->hlName), escapeJSONStrings(k->currentRules.rules), escapeJSONStrings(k->currentRules.model),
escapeJSONStrings(k->currentRules.layout), escapeJSONStrings(k->currentRules.variant), escapeJSONStrings(k->currentRules.options), escapeJSONStrings(KM), escapeJSONStrings(k->currentRules.layout), escapeJSONStrings(k->currentRules.variant), escapeJSONStrings(k->currentRules.options), escapeJSONStrings(KM),
(getModState(k, XKB_MOD_NAME_CAPS) ? "true" : "false"), (getModState(k, XKB_MOD_NAME_NUM) ? "true" : "false"), (k->active ? "true" : "false")); (k->active ? "true" : "false"));
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -688,11 +668,9 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
for (auto const& k : g_pInputManager->m_vKeyboards) { for (auto const& k : g_pInputManager->m_vKeyboards) {
const auto KM = k->getActiveLayout(); const auto KM = k->getActiveLayout();
result += result += std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tmain: {}\n",
std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tcapsLock: " (uintptr_t)k.get(), k->hlName, k->currentRules.rules, k->currentRules.model, k->currentRules.layout, k->currentRules.variant,
"{}\n\t\t\tnumLock: {}\n\t\t\tmain: {}\n", k->currentRules.options, KM, (k->active ? "yes" : "no"));
(uintptr_t)k.get(), k->hlName, k->currentRules.rules, k->currentRules.model, k->currentRules.layout, k->currentRules.variant, k->currentRules.options,
KM, (getModState(k, XKB_MOD_NAME_CAPS) ? "yes" : "no"), (getModState(k, XKB_MOD_NAME_NUM) ? "yes" : "no"), (k->active ? "yes" : "no"));
} }
result += "\n\nTablets:\n"; result += "\n\nTablets:\n";
@@ -818,28 +796,28 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ
std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = ""; std::string ret = "";
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto const& kb : g_pKeybindManager->m_vKeybinds) { for (auto const& kb : g_pKeybindManager->m_lKeybinds) {
ret += "bind"; ret += "bind";
if (kb->locked) if (kb.locked)
ret += "l"; ret += "l";
if (kb->mouse) if (kb.mouse)
ret += "m"; ret += "m";
if (kb->release) if (kb.release)
ret += "r"; ret += "r";
if (kb->repeat) if (kb.repeat)
ret += "e"; ret += "e";
if (kb->nonConsuming) if (kb.nonConsuming)
ret += "n"; ret += "n";
if (kb->hasDescription) if (kb.hasDescription)
ret += "d"; ret += "d";
ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb->modmask, ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap,
kb->submap, kb->key, kb->keycode, kb->catchAll, kb->description, kb->handler, kb->arg); kb.key, kb.keycode, kb.catchAll, kb.description, kb.handler, kb.arg);
} }
} else { } else {
// json // json
ret += "["; ret += "[";
for (auto const& kb : g_pKeybindManager->m_vKeybinds) { for (auto const& kb : g_pKeybindManager->m_lKeybinds) {
ret += std::format( ret += std::format(
R"#( R"#(
{{ {{
@@ -847,7 +825,6 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
"mouse": {}, "mouse": {},
"release": {}, "release": {},
"repeat": {}, "repeat": {},
"longPress": {},
"non_consuming": {}, "non_consuming": {},
"has_description": {}, "has_description": {},
"modmask": {}, "modmask": {},
@@ -859,9 +836,9 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
"dispatcher": "{}", "dispatcher": "{}",
"arg": "{}" "arg": "{}"
}},)#", }},)#",
kb->locked ? "true" : "false", kb->mouse ? "true" : "false", kb->release ? "true" : "false", kb->repeat ? "true" : "false", kb->longPress ? "true" : "false", kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false",
kb->nonConsuming ? "true" : "false", kb->hasDescription ? "true" : "false", kb->modmask, escapeJSONStrings(kb->submap), escapeJSONStrings(kb->key), kb->keycode, kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false",
kb->catchAll ? "true" : "false", escapeJSONStrings(kb->description), escapeJSONStrings(kb->handler), escapeJSONStrings(kb->arg)); escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg));
} }
trimTrailingComma(ret); trimTrailingComma(ret);
ret += "]"; ret += "]";
@@ -876,52 +853,40 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' ');
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n" std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg +
"Date: {}\n" ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" +
"Tag: {}, commits: {}\n" "\n\nflags: (if any)\n";
"built against:\n aquamarine {}\n hyprlang {}\n hyprutils {}\n hyprcursor {}\n hyprgraphics {}\n\n\n",
HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION,
HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION);
#if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND))
result += "no flags were set\n";
#else
result += "flags set:\n";
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "legacyrenderer\n"; result += "legacyrenderer\n";
#endif #endif
#ifdef ISDEBUG #ifndef ISDEBUG
result += "debug\n"; result += "debug\n";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
result += "no xwayland\n"; result += "no xwayland\n";
#endif #endif
#endif
return result; return result;
} else { } else {
std::string result = std::format( std::string result = std::format(
R"#({{ R"#({{
"branch": "{}", "branch": "{}",
"commit": "{}", "commit": "{}",
"version": "{}",
"dirty": {}, "dirty": {},
"commit_message": "{}", "commit_message": "{}",
"commit_date": "{}", "commit_date": "{}",
"tag": "{}", "tag": "{}",
"commits": "{}", "commits": "{}",
"buildAquamarine": "{}", "buildAquamarine": "{}",
"buildHyprlang": "{}",
"buildHyprutils": "{}",
"buildHyprcursor": "{}",
"buildHyprgraphics": "{}",
"flags": [)#", "flags": [)#",
GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS,
GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION); AQUAMARINE_VERSION);
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "\"legacyrenderer\","; result += "\"legacyrenderer\",";
#endif #endif
#ifdef ISDEBUG #ifndef ISDEBUG
result += "\"debug\","; result += "\"debug\",";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
@@ -955,51 +920,18 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
result += "\n\n"; result += "\n\n";
#if defined(__DragonFly__) || defined(__FreeBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga"); const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
#elif defined(__arm__) || defined(__aarch64__) #elif defined(__arm__) || defined(__aarch64__)
std::string GPUINFO; const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible");
const std::filesystem::path dev_tree = "/proc/device-tree";
try {
if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) {
std::for_each(std::filesystem::directory_iterator(dev_tree), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& entry) {
if (std::filesystem::is_directory(entry) && entry.path().filename().string().starts_with("soc")) {
std::for_each(std::filesystem::directory_iterator(entry.path()), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& sub_entry) {
if (std::filesystem::is_directory(sub_entry) && sub_entry.path().filename().string().starts_with("gpu")) {
std::filesystem::path file_path = sub_entry.path() / "compatible";
std::ifstream file(file_path);
if (file)
GPUINFO.append(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
}
});
}
});
}
} catch (...) { GPUINFO = "error"; }
#else #else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif #endif
result += "GPU information: \n" + GPUINFO; result += "GPU information: \n" + GPUINFO;
if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version")) { if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version"))
std::ifstream file("/proc/driver/nvidia/version"); result += execAndGet("cat /proc/driver/nvidia/version | grep NVRM");
std::string line;
if (file.is_open()) {
while (std::getline(file, line)) {
if (!line.contains("NVRM"))
continue;
result += line;
result += "\n";
}
} else
result += "error";
}
result += "\n\n"; result += "\n\n";
if (std::ifstream file("/etc/os-release"); file.is_open()) { result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
std::stringstream buffer;
buffer << file.rdbuf();
result += "os-release: " + buffer.str() + "\n\n";
} else
result += "os-release: error\n\n";
result += "plugins:\n"; result += "plugins:\n";
if (g_pPluginSystem) { if (g_pPluginSystem) {
@@ -1089,10 +1021,9 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
} }
// decorations will probably need a repaint // decorations will probably need a repaint
if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source" || if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source") {
COMMAND.starts_with("windowrule")) {
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
g_pHyprRenderer->damageMonitor(m); g_pHyprRenderer->damageMonitor(m.get());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
} }
} }
@@ -1295,7 +1226,7 @@ std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
return "ok"; return "ok";
} }
const CHyprColor COLOR = configStringToInt(vars[1]).value_or(0); const CColor COLOR = configStringToInt(vars[1]);
for (size_t i = 2; i < vars.size(); ++i) for (size_t i = 2; i < vars.size(); ++i)
errorMessage += vars[i] + ' '; errorMessage += vars[i] + ' ';
@@ -1311,8 +1242,101 @@ std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
} }
std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) { std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
auto result = g_pKeybindManager->m_mDispatchers["setprop"](request.substr(request.find_first_of(' ') + 1, -1)); CVarList vars(request, 0, ' ');
return "DEPRECATED: use hyprctl dispatch setprop instead" + (result.success ? "" : "\n" + result.error);
if (vars.size() < 4)
return "not enough args";
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
if (!PWINDOW)
return "window not found";
const auto PROP = vars[2];
const auto VAL = vars[3];
bool noFocus = PWINDOW->m_sWindowData.noFocus.valueOrDefault();
try {
if (PROP == "animationstyle") {
PWINDOW->m_sWindowData.animationStyle = CWindowOverridableVar(VAL, PRIORITY_SET_PROP);
} else if (PROP == "maxsize") {
PWINDOW->m_sWindowData.maxSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sWindowData.maxSize.value().x, PWINDOW->m_vRealSize.goal().x),
std::min((double)PWINDOW->m_sWindowData.maxSize.value().y, PWINDOW->m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
PWINDOW->setHidden(false);
} else if (PROP == "minsize") {
PWINDOW->m_sWindowData.minSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sWindowData.minSize.value().x, PWINDOW->m_vRealSize.goal().x),
std::max((double)PWINDOW->m_sWindowData.minSize.value().y, PWINDOW->m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
PWINDOW->setHidden(false);
} else if (PROP == "alpha") {
PWINDOW->m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alpha.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactive") {
PWINDOW->m_sWindowData.alphaInactive =
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphafullscreen") {
PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphaoverride") {
PWINDOW->m_sWindowData.alpha =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactiveoverride") {
PWINDOW->m_sWindowData.alphaInactive =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphafullscreenoverride") {
PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") {
CGradientValueData colorData = {};
if (vars.size() > 4) {
for (int i = 3; i < static_cast<int>(vars.size()); ++i) {
const auto TOKEN = vars[i];
if (TOKEN.ends_with("deg"))
colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0);
else
colorData.m_vColors.push_back(configStringToInt(TOKEN));
}
} else if (VAL != "-1")
colorData.m_vColors.push_back(configStringToInt(VAL));
if (PROP == "activebordercolor")
PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
else
PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
} else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) {
auto pWindowDataElement = search->second(PWINDOW);
if (VAL == "toggle")
*pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP);
else if (VAL == "unset")
pWindowDataElement->unset(PRIORITY_SET_PROP);
else
*pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP);
} else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) {
if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else
*(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP);
} else {
return "prop not found";
}
} catch (std::exception& e) { return "error in parsing prop value: " + std::string(e.what()); }
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!(PWINDOW->m_sWindowData.noFocus.valueOrDefault() == noFocus)) {
g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->focusWindow(PLASTWINDOW);
}
for (auto const& m : g_pCompositor->m_vMonitors)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
return "ok";
} }
std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) { std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
@@ -1356,16 +1380,17 @@ std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request)
return std::format("custom type: {}\nset: {}", ((ICustomConfigValueData*)std::any_cast<void*>(VAL))->toString(), VAR->m_bSetByUser); return std::format("custom type: {}\nset: {}", ((ICustomConfigValueData*)std::any_cast<void*>(VAL))->toString(), VAR->m_bSetByUser);
} else { } else {
if (TYPE == typeid(Hyprlang::INT)) if (TYPE == typeid(Hyprlang::INT))
return std::format(R"({{"option": "{}", "int": {}, "set": {} }})", curitem, std::any_cast<Hyprlang::INT>(VAL), VAR->m_bSetByUser); return std::format("{{\"option\": \"{}\", \"int\": {}, \"set\": {} }}", curitem, std::any_cast<Hyprlang::INT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::FLOAT)) else if (TYPE == typeid(Hyprlang::FLOAT))
return std::format(R"({{"option": "{}", "float": {:2f}, "set": {} }})", curitem, std::any_cast<Hyprlang::FLOAT>(VAL), VAR->m_bSetByUser); return std::format("{{\"option\": \"{}\", \"float\": {:2f}, \"set\": {} }}", curitem, std::any_cast<Hyprlang::FLOAT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::VEC2)) else if (TYPE == typeid(Hyprlang::VEC2))
return std::format(R"({{"option": "{}", "vec2": [{},{}], "set": {} }})", curitem, std::any_cast<Hyprlang::VEC2>(VAL).x, std::any_cast<Hyprlang::VEC2>(VAL).y, return std::format("{{\"option\": \"{}\", \"vec2\": [{},{}], \"set\": {} }}", curitem, std::any_cast<Hyprlang::VEC2>(VAL).x, std::any_cast<Hyprlang::VEC2>(VAL).y,
VAR->m_bSetByUser); VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::STRING)) else if (TYPE == typeid(Hyprlang::STRING))
return std::format(R"({{"option": "{}", "str": "{}", "set": {} }})", curitem, escapeJSONStrings(std::any_cast<Hyprlang::STRING>(VAL)), VAR->m_bSetByUser); return std::format("{{\"option\": \"{}\", \"str\": \"{}\", \"set\": {} }}", curitem, escapeJSONStrings(std::any_cast<Hyprlang::STRING>(VAL)), VAR->m_bSetByUser);
else if (TYPE == typeid(void*)) else if (TYPE == typeid(void*))
return std::format(R"({{"option": "{}", "custom": "{}", "set": {} }})", curitem, ((ICustomConfigValueData*)std::any_cast<void*>(VAL))->toString(), VAR->m_bSetByUser); return std::format("{{\"option\": \"{}\", \"custom\": \"{}\", \"set\": {} }}", curitem, ((ICustomConfigValueData*)std::any_cast<void*>(VAL))->toString(),
VAR->m_bSetByUser);
} }
return "invalid type (internal error)"; return "invalid type (internal error)";
@@ -1480,40 +1505,17 @@ std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
g_pPluginSystem->unloadPlugin(PLUGIN); g_pPluginSystem->unloadPlugin(PLUGIN);
} else if (OPERATION == "list") { } else if (OPERATION == "list") {
const auto PLUGINS = g_pPluginSystem->getAllPlugins(); const auto PLUGINS = g_pPluginSystem->getAllPlugins();
std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (PLUGINS.size() == 0)
result += "["; return "no plugins loaded";
if (PLUGINS.size() == 0) std::string list = "";
return "[]"; for (auto const& p : PLUGINS) {
list += std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description);
for (auto const& p : PLUGINS) {
result += std::format(
R"#(
{{
"name": "{}",
"author": "{}",
"handle": "{:x}",
"version": "{}",
"description": "{}"
}},)#",
escapeJSONStrings(p->name), escapeJSONStrings(p->author), (uintptr_t)p->m_pHandle, escapeJSONStrings(p->version), escapeJSONStrings(p->description));
}
trimTrailingComma(result);
result += "]";
} else {
if (PLUGINS.size() == 0)
return "no plugins loaded";
for (auto const& p : PLUGINS) {
result +=
std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description);
}
} }
return result; return list;
} else { } else {
return "unknown opt"; return "unknown opt";
} }
@@ -1537,8 +1539,9 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
icon = std::stoi(ICON); icon = std::stoi(ICON);
} catch (std::exception& e) { return "invalid arg 1"; } } catch (std::exception& e) { return "invalid arg 1"; }
if (icon > ICON_NONE || icon < 0) if (icon > ICON_NONE || icon < 0) {
icon = ICON_NONE; icon = ICON_NONE;
}
const auto TIME = vars[2]; const auto TIME = vars[2];
int time = 0; int time = 0;
@@ -1546,13 +1549,10 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
time = std::stoi(TIME); time = std::stoi(TIME);
} catch (std::exception& e) { return "invalid arg 2"; } } catch (std::exception& e) { return "invalid arg 2"; }
const auto COLOR_RESULT = configStringToInt(vars[3]); CColor color = configStringToInt(vars[3]);
if (!COLOR_RESULT)
return "invalid arg 3";
CHyprColor color = *COLOR_RESULT;
size_t msgidx = 4; size_t msgidx = 4;
float fontsize = 13.f; float fontsize = 13.f;
if (vars[msgidx].length() > 9 && vars[msgidx].compare(0, 9, "fontsize:") == 0) { if (vars[msgidx].length() > 9 && vars[msgidx].compare(0, 9, "fontsize:") == 0) {
const auto FONTSIZE = vars[msgidx].substr(9); const auto FONTSIZE = vars[msgidx].substr(9);
@@ -1771,16 +1771,8 @@ std::string CHyprCtl::getReply(std::string request) {
rd.blurFBDirty = true; rd.blurFBDirty = true;
} }
for (auto const& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || !w->m_pWorkspace || !w->m_pWorkspace->isVisible())
continue;
w->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(w);
}
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
g_pHyprRenderer->damageMonitor(m); g_pHyprRenderer->damageMonitor(m.get());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
} }
} }
@@ -1810,13 +1802,13 @@ void runWritingDebugLogThread(const int conn) {
Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn); Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn);
//will be finished, when reading side close connection //will be finished, when reading side close connection
std::thread([conn]() { std::thread([conn]() {
while (Debug::SRollingLogFollow::get().isRunning()) { while (Debug::RollingLogFollow::Get().IsRunning()) {
if (Debug::SRollingLogFollow::get().isEmpty(conn)) { if (Debug::RollingLogFollow::Get().isEmpty(conn)) {
std::this_thread::sleep_for(1000ms); std::this_thread::sleep_for(1000ms);
continue; continue;
} }
auto line = Debug::SRollingLogFollow::get().getLog(conn); auto line = Debug::RollingLogFollow::Get().GetLog(conn);
if (!successWrite(conn, line)) if (!successWrite(conn, line))
// We cannot write, when connection is closed. So thread will successfully exit by itself // We cannot write, when connection is closed. So thread will successfully exit by itself
break; break;
@@ -1824,7 +1816,7 @@ void runWritingDebugLogThread(const int conn) {
std::this_thread::sleep_for(100ms); std::this_thread::sleep_for(100ms);
} }
close(conn); close(conn);
Debug::SRollingLogFollow::get().stopFor(conn); Debug::RollingLogFollow::Get().StopFor(conn);
}).detach(); }).detach();
} }
@@ -1883,9 +1875,9 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
if (isFollowUpRollingLogRequest(request)) { if (isFollowUpRollingLogRequest(request)) {
Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket."); Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket.");
Debug::SRollingLogFollow::get().startFor(ACCEPTEDCONNECTION); Debug::RollingLogFollow::Get().StartFor(ACCEPTEDCONNECTION);
runWritingDebugLogThread(ACCEPTEDCONNECTION); runWritingDebugLogThread(ACCEPTEDCONNECTION);
Debug::log(LOG, Debug::SRollingLogFollow::get().debugInfo()); Debug::log(LOG, Debug::RollingLogFollow::Get().DebugInfo());
} else } else
close(ACCEPTEDCONNECTION); close(ACCEPTEDCONNECTION);

View File

@@ -7,7 +7,6 @@
// exposed for main.cpp // exposed for main.cpp
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request);
std::string versionRequest(eHyprCtlOutputFormat format, std::string request);
class CHyprCtl { class CHyprCtl {
public: public:

View File

@@ -7,13 +7,8 @@ CHyprDebugOverlay::CHyprDebugOverlay() {
m_pTexture = makeShared<CTexture>(); m_pTexture = makeShared<CTexture>();
} }
void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay"); m_dLastRenderTimes.push_back(durationUs / 1000.f);
if (!*PDEBUGOVERLAY)
return;
m_dLastRenderTimes.emplace_back(durationUs / 1000.f);
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimes.pop_front(); m_dLastRenderTimes.pop_front();
@@ -22,13 +17,8 @@ void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs)
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay"); m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f);
if (!*PDEBUGOVERLAY)
return;
m_dLastRenderTimesNoOverlay.emplace_back(durationUs / 1000.f);
if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimesNoOverlay.pop_front(); m_dLastRenderTimesNoOverlay.pop_front();
@@ -37,13 +27,8 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float du
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) { void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay"); m_dLastFrametimes.push_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
if (!*PDEBUGOVERLAY)
return;
m_dLastFrametimes.emplace_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastFrametimes.pop_front(); m_dLastFrametimes.pop_front();
@@ -54,7 +39,7 @@ void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
// anim data too // anim data too
const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor.lock() : g_pCompositor->m_pLastMonitor.lock(); const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor.get();
if (PMONITORFORTICKS) { if (PMONITORFORTICKS) {
if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate) if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate)
m_dLastAnimationTicks.pop_front(); m_dLastAnimationTicks.pop_front();
@@ -203,36 +188,21 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
return posY - offset; return posY - offset;
} }
void CHyprDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs); m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs);
} }
void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs); m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
} }
void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) { void CHyprDebugOverlay::frameData(CMonitor* pMonitor) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].frameData(pMonitor); m_mMonitorOverlays[pMonitor].frameData(pMonitor);
} }
void CHyprDebugOverlay::draw() { void CHyprDebugOverlay::draw() {
const auto PMONITOR = g_pCompositor->m_vMonitors.front(); const auto PMONITOR = g_pCompositor->m_vMonitors.front().get();
if (!m_pCairoSurface || !m_pCairo) { if (!m_pCairoSurface || !m_pCairo) {
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
@@ -248,7 +218,7 @@ void CHyprDebugOverlay::draw() {
// draw the things // draw the things
int offsetY = 0; int offsetY = 0;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
offsetY += m_mMonitorOverlays[m].draw(offsetY); offsetY += m_mMonitorOverlays[m.get()].draw(offsetY);
offsetY += 5; // for padding between mons offsetY += 5; // for padding between mons
} }

View File

@@ -3,9 +3,9 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/Monitor.hpp" #include "../helpers/Monitor.hpp"
#include "../render/Texture.hpp" #include "../render/Texture.hpp"
#include <cairo/cairo.h>
#include <map>
#include <deque> #include <deque>
#include <cairo/cairo.h>
#include <unordered_map>
class CHyprRenderer; class CHyprRenderer;
@@ -13,9 +13,9 @@ class CHyprMonitorDebugOverlay {
public: public:
int draw(int offset); int draw(int offset);
void renderData(PHLMONITOR pMonitor, float durationUs); void renderData(CMonitor* pMonitor, float durationUs);
void renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs); void renderDataNoOverlay(CMonitor* pMonitor, float durationUs);
void frameData(PHLMONITOR pMonitor); void frameData(CMonitor* pMonitor);
private: private:
std::deque<float> m_dLastFrametimes; std::deque<float> m_dLastFrametimes;
@@ -23,7 +23,7 @@ class CHyprMonitorDebugOverlay {
std::deque<float> m_dLastRenderTimesNoOverlay; std::deque<float> m_dLastRenderTimesNoOverlay;
std::deque<float> m_dLastAnimationTicks; std::deque<float> m_dLastAnimationTicks;
std::chrono::high_resolution_clock::time_point m_tpLastFrame; std::chrono::high_resolution_clock::time_point m_tpLastFrame;
PHLMONITORREF m_pMonitor; CMonitor* m_pMonitor = nullptr;
CBox m_wbLastDrawnBox; CBox m_wbLastDrawnBox;
friend class CHyprRenderer; friend class CHyprRenderer;
@@ -33,17 +33,17 @@ class CHyprDebugOverlay {
public: public:
CHyprDebugOverlay(); CHyprDebugOverlay();
void draw(); void draw();
void renderData(PHLMONITOR, float durationUs); void renderData(CMonitor*, float durationUs);
void renderDataNoOverlay(PHLMONITOR, float durationUs); void renderDataNoOverlay(CMonitor*, float durationUs);
void frameData(PHLMONITOR); void frameData(CMonitor*);
private: private:
std::map<PHLMONITORREF, CHyprMonitorDebugOverlay> m_mMonitorOverlays; std::unordered_map<CMonitor*, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
cairo_surface_t* m_pCairoSurface = nullptr; cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr; cairo_t* m_pCairo = nullptr;
SP<CTexture> m_pTexture; SP<CTexture> m_pTexture;
friend class CHyprMonitorDebugOverlay; friend class CHyprMonitorDebugOverlay;
friend class CHyprRenderer; friend class CHyprRenderer;

View File

@@ -18,7 +18,7 @@ inline auto iconBackendFromLayout(PangoLayout* layout) {
CHyprNotificationOverlay::CHyprNotificationOverlay() { CHyprNotificationOverlay::CHyprNotificationOverlay() {
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (m_vNotifications.size() == 0) if (m_dNotifications.size() == 0)
return; return;
g_pHyprRenderer->damageBox(&m_bLastDamage); g_pHyprRenderer->damageBox(&m_bLastDamage);
@@ -34,34 +34,34 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() {
cairo_surface_destroy(m_pCairoSurface); cairo_surface_destroy(m_pCairoSurface);
} }
void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) { void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) {
const auto PNOTIF = m_vNotifications.emplace_back(std::make_unique<SNotification>()).get(); const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text; PNOTIF->text = text;
PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color; PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color;
PNOTIF->started.reset(); PNOTIF->started.reset();
PNOTIF->timeMs = timeMs; PNOTIF->timeMs = timeMs;
PNOTIF->icon = icon; PNOTIF->icon = icon;
PNOTIF->fontSize = fontSize; PNOTIF->fontSize = fontSize;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m); g_pCompositor->scheduleFrameForMonitor(m.get());
} }
} }
void CHyprNotificationOverlay::dismissNotifications(const int amount) { void CHyprNotificationOverlay::dismissNotifications(const int amount) {
if (amount == -1) if (amount == -1)
m_vNotifications.clear(); m_dNotifications.clear();
else { else {
const int AMT = std::min(amount, static_cast<int>(m_vNotifications.size())); const int AMT = std::min(amount, static_cast<int>(m_dNotifications.size()));
for (int i = 0; i < AMT; ++i) { for (int i = 0; i < AMT; ++i) {
m_vNotifications.erase(m_vNotifications.begin()); m_dNotifications.pop_front();
} }
} }
} }
CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) { CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
static constexpr auto ANIM_DURATION_MS = 600.0; static constexpr auto ANIM_DURATION_MS = 600.0;
static constexpr auto ANIM_LAG_MS = 100.0; static constexpr auto ANIM_LAG_MS = 100.0;
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0; static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
@@ -87,7 +87,7 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
const auto iconBackendID = iconBackendFromLayout(layout); const auto iconBackendID = iconBackendFromLayout(layout);
const auto PBEZIER = g_pAnimationManager->getBezier("default"); const auto PBEZIER = g_pAnimationManager->getBezier("default");
for (auto const& notif : m_vNotifications) { for (auto const& notif : m_dNotifications) {
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40); const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
@@ -182,12 +182,12 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
g_object_unref(layout); g_object_unref(layout);
// cleanup notifs // cleanup notifs
std::erase_if(m_vNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; }); std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10}; return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
} }
void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) { void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
const auto MONSIZE = pMonitor->vecTransformedSize; const auto MONSIZE = pMonitor->vecTransformedSize;
@@ -205,7 +205,7 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
} }
// Draw the notifications // Draw the notifications
if (m_vNotifications.size() == 0) if (m_dNotifications.size() == 0)
return; return;
// Render to the monitor // Render to the monitor
@@ -246,5 +246,5 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
} }
bool CHyprNotificationOverlay::hasAny() { bool CHyprNotificationOverlay::hasAny() {
return !m_vNotifications.empty(); return !m_dNotifications.empty();
} }

View File

@@ -6,11 +6,11 @@
#include "../render/Texture.hpp" #include "../render/Texture.hpp"
#include "../SharedDefs.hpp" #include "../SharedDefs.hpp"
#include <vector> #include <deque>
#include <cairo/cairo.h> #include <cairo/cairo.h>
enum eIconBackend : uint8_t { enum eIconBackend {
ICONS_BACKEND_NONE = 0, ICONS_BACKEND_NONE = 0,
ICONS_BACKEND_NF, ICONS_BACKEND_NF,
ICONS_BACKEND_FA ICONS_BACKEND_FA
@@ -19,17 +19,17 @@ enum eIconBackend : uint8_t {
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = { static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""},
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "󰸞", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}}; std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "󰸞", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
static const std::array<CHyprColor, ICON_NONE + 1> ICONS_COLORS = {CHyprColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0}, static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
CHyprColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0}, CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
CHyprColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0}, CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
CHyprColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0}, CColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
CHyprColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0}, CColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
CHyprColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0}, CColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
CHyprColor{0, 0, 0, 1.0}}; CColor{0, 0, 0, 1.0}};
struct SNotification { struct SNotification {
std::string text = ""; std::string text = "";
CHyprColor color; CColor color;
CTimer started; CTimer started;
float timeMs = 0; float timeMs = 0;
eIcons icon = ICON_NONE; eIcons icon = ICON_NONE;
@@ -41,24 +41,24 @@ class CHyprNotificationOverlay {
CHyprNotificationOverlay(); CHyprNotificationOverlay();
~CHyprNotificationOverlay(); ~CHyprNotificationOverlay();
void draw(PHLMONITOR pMonitor); void draw(CMonitor* pMonitor);
void addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f); void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
void dismissNotifications(const int amount); void dismissNotifications(const int amount);
bool hasAny(); bool hasAny();
private: private:
CBox drawNotifications(PHLMONITOR pMonitor); CBox drawNotifications(CMonitor* pMonitor);
CBox m_bLastDamage; CBox m_bLastDamage;
std::vector<std::unique_ptr<SNotification>> m_vNotifications; std::deque<std::unique_ptr<SNotification>> m_dNotifications;
cairo_surface_t* m_pCairoSurface = nullptr; cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr; cairo_t* m_pCairo = nullptr;
PHLMONITORREF m_pLastMonitor; CMonitor* m_pLastMonitor = nullptr;
Vector2D m_vecLastSize = Vector2D(-1, -1); Vector2D m_vecLastSize = Vector2D(-1, -1);
SP<CTexture> m_pTexture; SP<CTexture> m_pTexture;
}; };
inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay; inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay;

View File

@@ -4,7 +4,7 @@
#include "RollingLogFollow.hpp" #include "RollingLogFollow.hpp"
#include <fstream> #include <fstream>
#include <print> #include <iostream>
#include <fcntl.h> #include <fcntl.h>
void Debug::init(const std::string& IS) { void Debug::init(const std::string& IS) {
@@ -18,7 +18,7 @@ void Debug::close() {
logOfs.close(); logOfs.close();
} }
void Debug::log(eLogLevel level, std::string str) { void Debug::log(LogLevel level, std::string str) {
if (level == TRACE && !trace) if (level == TRACE && !trace)
return; return;
@@ -26,7 +26,6 @@ void Debug::log(eLogLevel level, std::string str) {
return; return;
std::string coloredStr = str; std::string coloredStr = str;
//NOLINTBEGIN
switch (level) { switch (level) {
case LOG: case LOG:
str = "[LOG] " + str; str = "[LOG] " + str;
@@ -54,14 +53,13 @@ void Debug::log(eLogLevel level, std::string str) {
break; break;
default: break; default: break;
} }
//NOLINTEND
rollingLog += str + "\n"; rollingLog += str + "\n";
if (rollingLog.size() > ROLLING_LOG_SIZE) if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE); rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
if (SRollingLogFollow::get().isRunning()) if (RollingLogFollow::Get().IsRunning())
SRollingLogFollow::get().addLog(str); RollingLogFollow::Get().AddLog(str);
if (!disableLogs || !**disableLogs) { if (!disableLogs || !**disableLogs) {
// log to a file // log to a file
@@ -71,5 +69,5 @@ void Debug::log(eLogLevel level, std::string str) {
// log it to the stdout too. // log it to the stdout too.
if (!disableStdout) if (!disableStdout)
std::println("{}", ((coloredLogs && !**coloredLogs) ? str : coloredStr)); std::cout << ((coloredLogs && !**coloredLogs) ? str : coloredStr) << "\n";
} }

View File

@@ -11,7 +11,7 @@
#define LOGMESSAGESIZE 1024 #define LOGMESSAGESIZE 1024
#define ROLLING_LOG_SIZE 4096 #define ROLLING_LOG_SIZE 4096
enum eLogLevel : int8_t { enum LogLevel {
NONE = -1, NONE = -1,
LOG = 0, LOG = 0,
WARN, WARN,
@@ -21,7 +21,6 @@ enum eLogLevel : int8_t {
TRACE TRACE
}; };
// NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug { namespace Debug {
inline std::string logFile; inline std::string logFile;
inline std::ofstream logOfs; inline std::ofstream logOfs;
@@ -39,11 +38,10 @@ namespace Debug {
void close(); void close();
// //
void log(eLogLevel level, std::string str); void log(LogLevel level, std::string str);
template <typename... Args> template <typename... Args>
//NOLINTNEXTLINE void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
void log(eLogLevel level, std::format_string<Args...> fmt, Args&&... args) {
std::lock_guard<std::mutex> guard(logMutex); std::lock_guard<std::mutex> guard(logMutex);
if (level == TRACE && !trace) if (level == TRACE && !trace)

View File

@@ -2,9 +2,8 @@
#include <shared_mutex> #include <shared_mutex>
// NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug { namespace Debug {
struct SRollingLogFollow { struct RollingLogFollow {
std::unordered_map<int, std::string> socketToRollingLogFollowQueue; std::unordered_map<int, std::string> socketToRollingLogFollowQueue;
std::shared_mutex m; std::shared_mutex m;
bool running = false; bool running = false;
@@ -16,12 +15,12 @@ namespace Debug {
return socketToRollingLogFollowQueue[socket].empty(); return socketToRollingLogFollowQueue[socket].empty();
} }
std::string debugInfo() { std::string DebugInfo() {
std::shared_lock<std::shared_mutex> r(m); std::shared_lock<std::shared_mutex> r(m);
return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size()); return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size());
} }
std::string getLog(int socket) { std::string GetLog(int socket) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m);
const std::string ret = socketToRollingLogFollowQueue[socket]; const std::string ret = socketToRollingLogFollowQueue[socket];
@@ -30,7 +29,7 @@ namespace Debug {
return ret; return ret;
}; };
void addLog(const std::string& log) { void AddLog(std::string log) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m);
running = true; running = true;
std::vector<int> to_erase; std::vector<int> to_erase;
@@ -38,26 +37,26 @@ namespace Debug {
socketToRollingLogFollowQueue[p.first] += log + "\n"; socketToRollingLogFollowQueue[p.first] += log + "\n";
} }
bool isRunning() { bool IsRunning() {
std::shared_lock<std::shared_mutex> r(m); std::shared_lock<std::shared_mutex> r(m);
return running; return running;
} }
void stopFor(int socket) { void StopFor(int socket) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m);
socketToRollingLogFollowQueue.erase(socket); socketToRollingLogFollowQueue.erase(socket);
if (socketToRollingLogFollowQueue.empty()) if (socketToRollingLogFollowQueue.empty())
running = false; running = false;
} }
void startFor(int socket) { void StartFor(int socket) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m);
socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket); socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket);
running = true; running = true;
} }
static SRollingLogFollow& get() { static RollingLogFollow& Get() {
static SRollingLogFollow instance; static RollingLogFollow instance;
static std::mutex gm; static std::mutex gm;
std::lock_guard<std::mutex> lock(gm); std::lock_guard<std::mutex> lock(gm);
return instance; return instance;

View File

@@ -3,7 +3,6 @@
class CWorkspace; class CWorkspace;
class CWindow; class CWindow;
class CLayerSurface; class CLayerSurface;
class CMonitor;
/* Shared pointer to a workspace */ /* Shared pointer to a workspace */
typedef SP<CWorkspace> PHLWORKSPACE; typedef SP<CWorkspace> PHLWORKSPACE;
@@ -19,8 +18,3 @@ typedef WP<CWindow> PHLWINDOWREF;
typedef SP<CLayerSurface> PHLLS; typedef SP<CLayerSurface> PHLLS;
/* Weak pointer to a layer surface */ /* Weak pointer to a layer surface */
typedef WP<CLayerSurface> PHLLSREF; typedef WP<CLayerSurface> PHLLSREF;
/* Shared pointer to a monitor */
typedef SP<CMonitor> PHLMONITOR;
/* Weak pointer to a monitor */
typedef WP<CMonitor> PHLMONITORREF;

View File

@@ -1,37 +0,0 @@
#include "LayerRule.hpp"
#include <unordered_set>
#include <algorithm>
#include "../debug/Log.hpp"
static const auto RULES = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
static const auto RULES_PREFIX = std::unordered_set<std::string>{"ignorealpha", "ignorezero", "xray", "animation", "order"};
CLayerRule::CLayerRule(const std::string& rule_, const std::string& ns_) : targetNamespace(ns_), rule(rule_) {
const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule_](const auto& prefix) { return rule_.starts_with(prefix); });
if (!VALID)
return;
if (rule == "noanim")
ruleType = RULE_NOANIM;
else if (rule == "blur")
ruleType = RULE_BLUR;
else if (rule == "blurpopups")
ruleType = RULE_BLURPOPUPS;
else if (rule == "dimaround")
ruleType = RULE_DIMAROUND;
else if (rule.starts_with("ignorealpha"))
ruleType = RULE_IGNOREALPHA;
else if (rule.starts_with("ignorezero"))
ruleType = RULE_IGNOREZERO;
else if (rule.starts_with("xray"))
ruleType = RULE_XRAY;
else if (rule.starts_with("animation"))
ruleType = RULE_ANIMATION;
else if (rule.starts_with("order"))
ruleType = RULE_ORDER;
else {
Debug::log(ERR, "CLayerRule: didn't match a rule that was found valid?!");
ruleType = RULE_INVALID;
}
}

View File

@@ -1,28 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
class CLayerRule {
public:
CLayerRule(const std::string& rule, const std::string& targetNS);
enum eRuleType : uint8_t {
RULE_INVALID = 0,
RULE_NOANIM,
RULE_BLUR,
RULE_BLURPOPUPS,
RULE_DIMAROUND,
RULE_IGNOREALPHA,
RULE_IGNOREZERO,
RULE_XRAY,
RULE_ANIMATION,
RULE_ORDER,
RULE_ZUMBA,
};
eRuleType ruleType = RULE_INVALID;
const std::string targetNamespace;
const std::string rule;
};

View File

@@ -6,9 +6,9 @@
#include "../managers/SeatManager.hpp" #include "../managers/SeatManager.hpp"
PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) { PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource)); PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource));
auto pMonitor = resource->monitor.empty() ? g_pCompositor->m_pLastMonitor.lock() : g_pCompositor->getMonitorFromName(resource->monitor); CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor);
pLS->surface->assign(resource->surface.lock(), pLS); pLS->surface->assign(resource->surface.lock(), pLS);
@@ -18,7 +18,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
} }
if (pMonitor->pMirrorOf) if (pMonitor->pMirrorOf)
pMonitor = g_pCompositor->m_vMonitors.front(); pMonitor = g_pCompositor->m_vMonitors.front().get();
pLS->self = pLS; pLS->self = pLS;
@@ -26,7 +26,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
pLS->layer = resource->current.layer; pLS->layer = resource->current.layer;
pLS->popupHead = std::make_unique<CPopup>(pLS); pLS->popupHead = std::make_unique<CPopup>(pLS);
pLS->monitor = pMonitor; pLS->monitorID = pMonitor->ID;
pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS);
pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace);
@@ -50,7 +50,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
void CLayerSurface::registerCallbacks() { void CLayerSurface::registerCallbacks() {
alpha.setUpdateCallback([this](void*) { alpha.setUpdateCallback([this](void*) {
if (dimAround) if (dimAround)
g_pHyprRenderer->damageMonitor(monitor.lock()); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(monitorID));
}); });
} }
@@ -82,9 +82,9 @@ CLayerSurface::~CLayerSurface() {
void CLayerSurface::onDestroy() { void CLayerSurface::onDestroy() {
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get()); Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get());
const auto PMONITOR = monitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) if (!g_pCompositor->getMonitorFromID(monitorID))
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)"); Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
if (!fadingOut) { if (!fadingOut) {
@@ -137,7 +137,7 @@ void CLayerSurface::onMap() {
g_pCompositor->removeFromFadingOutSafe(self.lock()); g_pCompositor->removeFromFadingOutSafe(self.lock());
// fix if it changed its mon // fix if it changed its mon
const auto PMONITOR = monitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -175,7 +175,8 @@ void CLayerSurface::onMap() {
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
const bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; const auto WORKSPACE = PMONITOR->activeWorkspace;
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN;
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
readyToDelete = false; readyToDelete = false;
@@ -196,7 +197,7 @@ void CLayerSurface::onUnmap() {
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
if (!monitor || g_pCompositor->m_bUnsafeState) { if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
@@ -220,9 +221,9 @@ void CLayerSurface::onUnmap() {
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
const auto PMONITOR = monitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == surface->resource() || g_pSeatManager->state.pointerFocus == surface->resource(); const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -231,7 +232,7 @@ void CLayerSurface::onUnmap() {
// vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable())) if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
g_pInputManager->refocusLastWindow(PMONITOR); g_pInputManager->refocusLastWindow(PMONITOR);
else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource()) else if (g_pCompositor->m_pLastFocus)
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock()); g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
@@ -255,13 +256,13 @@ void CLayerSurface::onCommit() {
if (layerSurface->surface && !layerSurface->surface->current.texture) { if (layerSurface->surface && !layerSurface->surface->current.texture) {
fadingOut = false; fadingOut = false;
geometry = {}; geometry = {};
g_pHyprRenderer->arrangeLayersForMonitor(monitorID()); g_pHyprRenderer->arrangeLayersForMonitor(monitorID);
} }
return; return;
} }
const auto PMONITOR = monitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -320,18 +321,8 @@ void CLayerSurface::onCommit() {
realSize.setValueAndWarp(geometry.size()); realSize.setValueAndWarp(geometry.size());
} }
if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) { if (mapped) {
bool WASLASTFOCUS = false; const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
layerSurface->surface->breadthfirst(
[&WASLASTFOCUS](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->state.keyboardFocus == surf; },
nullptr);
if (!WASLASTFOCUS && popupHead) {
popupHead->breadthfirst(
[&WASLASTFOCUS](CPopup* popup, void* data) {
WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource());
},
nullptr);
}
const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
@@ -341,13 +332,11 @@ void CLayerSurface::onCommit() {
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
// if the surface was focused and interactive but now isn't, refocus // if the surface was focused and interactive but now isn't, refocus
if (WASLASTFOCUS && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) { if (WASLASTFOCUS && !layerSurface->current.interactivity) {
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either, // moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
// so unfocus the surface here. // so unfocus the surface here.
g_pCompositor->focusSurface(nullptr); g_pCompositor->focusSurface(nullptr);
g_pInputManager->refocusLastWindow(monitor.lock()); g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID));
} else if (WASLASTFOCUS && WASEXCLUSIVE && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) {
g_pInputManager->simulateMouseMovement();
} else if (!WASEXCLUSIVE && ISEXCLUSIVE) { } else if (!WASEXCLUSIVE && ISEXCLUSIVE) {
// if now exclusive and not previously // if now exclusive and not previously
g_pSeatManager->setGrab(nullptr); g_pSeatManager->setGrab(nullptr);
@@ -378,57 +367,38 @@ void CLayerSurface::applyRules() {
animationStyle.reset(); animationStyle.reset();
for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) { for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) {
switch (rule->ruleType) { if (rule.rule == "noanim")
case CLayerRule::RULE_NOANIM: { noAnimations = true;
noAnimations = true; else if (rule.rule == "blur")
break; forceBlur = true;
} else if (rule.rule == "blurpopups")
case CLayerRule::RULE_BLUR: { forceBlurPopups = true;
forceBlur = true; else if (rule.rule.starts_with("ignorealpha") || rule.rule.starts_with("ignorezero")) {
break; const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
} std::string alphaValue = "";
case CLayerRule::RULE_BLURPOPUPS: { if (FIRST_SPACE_POS != std::string::npos)
forceBlurPopups = true; alphaValue = rule.rule.substr(FIRST_SPACE_POS + 1);
break;
}
case CLayerRule::RULE_IGNOREALPHA:
case CLayerRule::RULE_IGNOREZERO: {
const auto FIRST_SPACE_POS = rule->rule.find_first_of(' ');
std::string alphaValue = "";
if (FIRST_SPACE_POS != std::string::npos)
alphaValue = rule->rule.substr(FIRST_SPACE_POS + 1);
try { try {
ignoreAlpha = true; ignoreAlpha = true;
if (!alphaValue.empty()) if (!alphaValue.empty())
ignoreAlphaValue = std::stof(alphaValue); ignoreAlphaValue = std::stof(alphaValue);
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); } } catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
break; } else if (rule.rule == "dimaround") {
} dimAround = true;
case CLayerRule::RULE_DIMAROUND: { } else if (rule.rule.starts_with("xray")) {
dimAround = true; CVarList vars{rule.rule, 0, ' '};
break; try {
} xray = configStringToInt(vars[1]);
case CLayerRule::RULE_XRAY: { } catch (...) {}
CVarList vars{rule->rule, 0, ' '}; } else if (rule.rule.starts_with("animation")) {
try { CVarList vars{rule.rule, 2, 's'};
xray = configStringToInt(vars[1]).value_or(false); animationStyle = vars[1];
} catch (...) {} } else if (rule.rule.starts_with("order")) {
break; CVarList vars{rule.rule, 2, 's'};
} try {
case CLayerRule::RULE_ANIMATION: { order = std::stoi(vars[1]);
CVarList vars{rule->rule, 2, 's'}; } catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
animationStyle = vars[1];
break;
}
case CLayerRule::RULE_ORDER: {
CVarList vars{rule->rule, 2, 's'};
try {
order = std::stoi(vars[1]);
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
break;
}
default: break;
} }
} }
} }
@@ -575,7 +545,3 @@ int CLayerSurface::popupsCount() {
popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no);
return no; return no;
} }
MONITORID CLayerSurface::monitorID() {
return monitor ? monitor->ID : MONITOR_INVALID;
}

View File

@@ -4,7 +4,11 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include "LayerRule.hpp"
struct SLayerRule {
std::string targetNamespace = "";
std::string rule = "";
};
class CLayerShellResource; class CLayerShellResource;
@@ -38,7 +42,7 @@ class CLayerSurface {
bool mapped = false; bool mapped = false;
uint32_t layer = 0; uint32_t layer = 0;
PHLMONITORREF monitor; MONITORID monitorID = -1;
bool fadingOut = false; bool fadingOut = false;
bool readyToDelete = false; bool readyToDelete = false;
@@ -66,7 +70,6 @@ class CLayerSurface {
void onMap(); void onMap();
void onUnmap(); void onUnmap();
void onCommit(); void onCommit();
MONITORID monitorID();
private: private:
struct { struct {
@@ -80,6 +83,6 @@ class CLayerSurface {
// For the list lookup // For the list lookup
bool operator==(const CLayerSurface& rhs) const { bool operator==(const CLayerSurface& rhs) const {
return layerSurface == rhs.layerSurface && monitor == rhs.monitor; return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID;
} }
}; };

View File

@@ -4,8 +4,6 @@
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include <ranges> #include <ranges>
CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) {
@@ -16,10 +14,13 @@ CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) {
initAllSignals(); initAllSignals();
} }
CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) { CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner), m_pResource(popup) {
m_pWLSurface = CWLSurface::create(); m_pWLSurface = CWLSurface::create();
m_pWLSurface->assign(popup->surface->surface.lock(), this); m_pWLSurface->assign(popup->surface->surface.lock(), this);
m_pLayerOwner = pOwner->m_pLayerOwner;
m_pWindowOwner = pOwner->m_pWindowOwner;
m_vLastSize = popup->surface->current.geometry.size(); m_vLastSize = popup->surface->current.geometry.size();
reposition(); reposition();
@@ -105,8 +106,6 @@ void CPopup::onUnmap() {
return; return;
} }
m_bMapped = false;
m_vLastSize = m_pResource->surface->surface->current.size; m_vLastSize = m_pResource->surface->surface->current.size;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
@@ -117,6 +116,8 @@ void CPopup::onUnmap() {
m_pSubsurfaceHead.reset(); m_pSubsurfaceHead.reset();
g_pInputManager->simulateMouseMovement();
if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
@@ -130,11 +131,6 @@ void CPopup::onUnmap() {
g_pHyprRenderer->damageBox(&box); g_pHyprRenderer->damageBox(&box);
}, },
nullptr); nullptr);
const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource();
if (WASLASTFOCUS)
g_pInputManager->simulateMouseMovement();
} }
void CPopup::onCommit(bool ignoreSiblings) { void CPopup::onCommit(bool ignoreSiblings) {
@@ -292,13 +288,12 @@ bool CPopup::visible() {
return false; return false;
} }
void CPopup::bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPopup*, void*)> fn, void* data) { void CPopup::bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data) {
for (auto const& n : nodes) { for (auto const& n : nodes) {
fn(n, data); fn(n, data);
} }
std::vector<CPopup*> nodes2; std::vector<CPopup*> nodes2;
nodes2.reserve(nodes.size() * 2);
for (auto const& n : nodes) { for (auto const& n : nodes) {
for (auto const& c : n->m_vChildren) { for (auto const& c : n->m_vChildren) {
@@ -321,7 +316,7 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
breadthfirst([](CPopup* popup, void* data) { ((std::vector<CPopup*>*)data)->push_back(popup); }, &popups); breadthfirst([](CPopup* popup, void* data) { ((std::vector<CPopup*>*)data)->push_back(popup); }, &popups);
for (auto const& p : popups | std::views::reverse) { for (auto const& p : popups | std::views::reverse) {
if (!p->m_pResource || !p->m_bMapped) if (!p->m_pResource)
continue; continue;
if (!allowsInput) { if (!allowsInput) {

View File

@@ -41,7 +41,6 @@ class CPopup {
// //
SP<CWLSurface> m_pWLSurface; SP<CWLSurface> m_pWLSurface;
bool m_bMapped = false;
private: private:
// T1 owners, each popup has to have one of these // T1 owners, each popup has to have one of these
@@ -58,7 +57,8 @@ class CPopup {
bool m_bRequestedReposition = false; bool m_bRequestedReposition = false;
bool m_bInert = false; bool m_bInert = false;
bool m_bMapped = false;
// //
std::vector<SP<CPopup>> m_vChildren; std::vector<SP<CPopup>> m_vChildren;
@@ -81,5 +81,5 @@ class CPopup {
Vector2D localToGlobal(const Vector2D& rel); Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords(); Vector2D t1ParentCoords();
static void bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPopup*, void*)> fn, void* data); static void bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data);
}; };

View File

@@ -1,5 +1,3 @@
#include <re2/re2.h>
#include <any> #include <any>
#include <bit> #include <bit>
#include <string_view> #include <string_view>
@@ -115,7 +113,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
const int BORDERSIZE = getRealBorderSize(); const int BORDERSIZE = getRealBorderSize();
if (m_sWindowData.dimAround.valueOrDefault()) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
} }
@@ -175,7 +173,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
CBox CWindow::getFullWindowBoundingBox() { CBox CWindow::getFullWindowBoundingBox() {
if (m_sWindowData.dimAround.valueOrDefault()) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
} }
@@ -188,7 +186,7 @@ CBox CWindow::getFullWindowBoundingBox() {
} }
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (!PMONITOR) if (!PMONITOR)
return {m_vPosition, m_vSize}; return {m_vPosition, m_vSize};
@@ -223,7 +221,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
CBox CWindow::getWindowBoxUnified(uint64_t properties) { CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_sWindowData.dimAround.valueOrDefault()) { if (m_sWindowData.dimAround.valueOrDefault()) {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR) if (PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
} }
@@ -242,6 +240,10 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) {
return box; return box;
} }
CBox CWindow::getWindowMainSurfaceBox() {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
SBoxExtents CWindow::getFullWindowReservedArea() { SBoxExtents CWindow::getFullWindowReservedArea() {
return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock()); return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock());
} }
@@ -354,9 +356,9 @@ void CWindow::updateSurfaceScaleTransformDetails(bool force) {
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID); const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
m_iLastSurfaceMonitorID = monitorID(); m_iLastSurfaceMonitorID = m_iMonitorID;
const auto PNEWMONITOR = m_pMonitor.lock(); const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (!PNEWMONITOR) if (!PNEWMONITOR)
return; return;
@@ -368,10 +370,10 @@ void CWindow::updateSurfaceScaleTransformDetails(bool force) {
m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr); m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr);
} }
const auto PMONITOR = m_pMonitor.lock();
m_pWLSurface->resource()->breadthfirst( m_pWLSurface->resource()->breadthfirst(
[PMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { [this](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto PSURFACE = CWLSurface::fromResource(s); const auto PSURFACE = CWLSurface::fromResource(s);
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale) if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
return; return;
@@ -406,7 +408,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
const auto OLDWORKSPACE = m_pWorkspace; const auto OLDWORKSPACE = m_pWorkspace;
m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->m_iMonitorID : -1;
m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F); m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F);
m_fMovingToWorkspaceAlpha = 0.F; m_fMovingToWorkspaceAlpha = 0.F;
m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; }); m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; });
@@ -415,13 +417,13 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
setAnimationsToMove(); setAnimationsToMove();
OLDWORKSPACE->updateWindows(); g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID);
OLDWORKSPACE->updateWindowData(); g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->monitorID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->m_iMonitorID);
pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindows(workspaceID());
pWorkspace->updateWindowData(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -433,37 +435,31 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
if (const auto SWALLOWED = m_pSwallowed.lock()) { if (const auto SWALLOWED = m_pSwallowed.lock()) {
SWALLOWED->moveToWorkspace(pWorkspace); SWALLOWED->moveToWorkspace(pWorkspace);
SWALLOWED->m_pMonitor = m_pMonitor; SWALLOWED->m_iMonitorID = m_iMonitorID;
} }
// update xwayland coords // update xwayland coords
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value()); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value());
if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE->m_iID) == 0 && *PCLOSEONLASTSPECIAL) {
if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(OLDWORKSPACE->m_iMonitorID); PMONITOR)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
} }
PHLWINDOW CWindow::x11TransientFor() { PHLWINDOW CWindow::X11TransientFor() {
if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent) if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent)
return nullptr; return nullptr;
auto s = m_pXWaylandSurface->parent; auto s = m_pXWaylandSurface->parent;
std::vector<SP<CXWaylandSurface>> visited; auto oldParent = s;
while (s) { while (s) {
// break loops. Some X apps make them, and it seems like it's valid behavior?!?!?! // break cyclic loop of m_pXWaylandSurface being parent of itself, #TODO reject this from even being created?
// TODO: we should reject loops being created in the first place. if (!s->parent || s->parent == oldParent)
if (std::find(visited.begin(), visited.end(), s) != visited.end())
break; break;
visited.emplace_back(s.lock());
s = s->parent; s = s->parent;
} }
if (s == m_pXWaylandSurface)
return nullptr; // dead-ass circle
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pXWaylandSurface != s) if (w->m_pXWaylandSurface != s)
continue; continue;
@@ -518,22 +514,20 @@ void CWindow::onUnmap() {
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; }); std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; });
if (*PCLOSEONLASTSPECIAL && m_pWorkspace && m_pWorkspace->getWindows() == 0 && onSpecialWorkspace()) { if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace) if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this) if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this)
PMONITOR->solitaryClient.reset(); PMONITOR->solitaryClient.reset();
if (m_pWorkspace) { g_pCompositor->updateWorkspaceWindows(workspaceID());
m_pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
m_pWorkspace->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
m_pWorkspace.reset(); m_pWorkspace.reset();
@@ -616,179 +610,156 @@ bool CWindow::isHidden() {
return m_bHidden; return m_bHidden;
} }
void CWindow::applyDynamicRule(const SP<CWindowRule>& r) { void CWindow::applyDynamicRule(const SWindowRule& r) {
const eOverridePriority priority = r->execRule ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE; const eOverridePriority priority = r.szValue == "execRule" ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
const CVarList VARS(r.szRule, 0, ' ');
if (r.szRule.starts_with("tag")) {
CVarList vars{r.szRule, 0, 's', true};
switch (r->ruleType) { if (vars.size() == 2 && vars[0] == "tag")
case CWindowRule::RULE_TAG: { m_tags.applyTag(vars[1], true);
CVarList vars{r->szRule, 0, 's', true}; else
Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
} else if (r.szRule.starts_with("opacity")) {
try {
CVarList vars(r.szRule, 0, ' ');
if (vars.size() == 2 && vars[0] == "tag") int opacityIDX = 0;
m_tags.applyTag(vars[1], true);
else
Debug::log(ERR, "Tag rule invalid: {}", r->szRule);
break;
}
case CWindowRule::RULE_OPACITY: {
try {
CVarList vars(r->szRule, 0, ' ');
int opacityIDX = 0; for (auto const& r : vars) {
if (r == "opacity")
continue;
for (auto const& r : vars) { if (r == "override") {
if (r == "opacity") if (opacityIDX == 1)
continue; m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
else if (opacityIDX == 2)
if (r == "override") { m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority);
if (opacityIDX == 1) else if (opacityIDX == 3)
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority); m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
else if (opacityIDX == 2) } else {
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority); if (opacityIDX == 0) {
else if (opacityIDX == 3) m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority); } else if (opacityIDX == 1) {
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 2) {
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else { } else {
if (opacityIDX == 0) { throw std::runtime_error("more than 3 alpha values");
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 1) {
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 2) {
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else {
throw std::runtime_error("more than 3 alpha values");
}
opacityIDX++;
} }
opacityIDX++;
} }
if (opacityIDX == 1) {
m_sWindowData.alphaInactive = m_sWindowData.alpha;
m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_ANIMATION: {
auto STYLE = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
break;
}
case CWindowRule::RULE_BORDERCOLOR: {
try {
// Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {};
bool active = true;
CVarList colorsAndAngles = CVarList(trim(r->szRule.substr(r->szRule.find_first_of(' ') + 1)), 0, 's', true);
// Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority);
return;
}
for (auto const& token : colorsAndAngles) {
// The first angle, or an explicit "0deg", splits the two gradients
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false;
} else if (token.contains("deg"))
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
else if (active)
activeBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
}
activeBorderGradient.updateColorsOk();
// Includes sanity checks for the number of colors in each gradient
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r->szRule);
else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r->szRule);
else if (inactiveBorderGradient.m_vColors.empty())
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else {
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_IDLEINHIBIT: {
auto IDLERULE = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
if (IDLERULE == "none")
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
else if (IDLERULE == "always")
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
else if (IDLERULE == "focus")
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
else if (IDLERULE == "fullscreen")
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
break;
}
case CWindowRule::RULE_MAXSIZE: {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r->szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for maxsize");
return;
}
m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(std::nullopt, m_sWindowData.maxSize.value());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_MINSIZE: {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r->szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for minsize");
return;
}
m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(m_sWindowData.minSize.value(), std::nullopt);
if (m_sGroupData.pNextWindow.expired())
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_RENDERUNFOCUSED: {
m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority);
g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock());
break;
}
case CWindowRule::RULE_PROP: {
const CVarList VARS(r->szRule, 0, ' ');
if (auto search = g_pConfigManager->miWindowProperties.find(VARS[1]); search != g_pConfigManager->miWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = g_pConfigManager->mfWindowProperties.find(VARS[1]); search != g_pConfigManager->mfWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stof(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[1]); search != g_pConfigManager->mbWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(VARS[2].empty() ? true : (bool)std::stoi(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} }
break;
if (opacityIDX == 1) {
m_sWindowData.alphaInactive = m_sWindowData.alpha;
m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("animation")) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
} else if (r.szRule.starts_with("bordercolor")) {
try {
// Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {};
bool active = true;
CVarList colorsAndAngles = CVarList(trim(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
// Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))), priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))), priority);
return;
}
for (auto const& token : colorsAndAngles) {
// The first angle, or an explicit "0deg", splits the two gradients
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false;
} else if (token.contains("deg"))
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
else if (active)
activeBorderGradient.m_vColors.push_back(configStringToInt(token));
else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
}
// Includes sanity checks for the number of colors in each gradient
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
else if (inactiveBorderGradient.m_vColors.empty())
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else {
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[0]); search != g_pConfigManager->mbWindowProperties.end()) {
if (VARS[1].empty()) {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority);
} else {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]), priority);
} catch (...) {}
} }
default: break; } else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[1]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (IDLERULE == "none")
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
else if (IDLERULE == "always")
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
else if (IDLERULE == "focus")
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
else if (IDLERULE == "fullscreen")
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
} else if (r.szRule.starts_with("maxsize")) {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r.szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for maxsize");
return;
}
m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
m_vRealSize =
Vector2D(std::min((double)m_sWindowData.maxSize.value().x, m_vRealSize.goal().x), std::min((double)m_sWindowData.maxSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("minsize")) {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r.szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for minsize");
return;
}
m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
m_vRealSize =
Vector2D(std::max((double)m_sWindowData.minSize.value().x, m_vRealSize.goal().x), std::max((double)m_sWindowData.minSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
if (m_sGroupData.pNextWindow.expired())
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "renderunfocused") {
m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority);
g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock());
} }
} }
@@ -813,13 +784,13 @@ void CWindow::updateDynamicRules() {
m_tags.removeDynamicTags(); m_tags.removeDynamicTags();
m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock()); m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock());
for (const auto& r : m_vMatchedRules) { for (auto const& r : m_vMatchedRules) {
applyDynamicRule(r); applyDynamicRule(r);
} }
EMIT_HOOK_EVENT("windowUpdateRules", m_pSelf.lock()); EMIT_HOOK_EVENT("windowUpdateRules", m_pSelf.lock());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
} }
// check if the point is "hidden" under a rounded corner of the window // check if the point is "hidden" under a rounded corner of the window
@@ -884,11 +855,9 @@ void CWindow::createGroup() {
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock())); addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock()));
if (m_pWorkspace) { g_pCompositor->updateWorkspaceWindows(workspaceID());
m_pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
m_pWorkspace->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("1,{:x}", (uintptr_t)this)}); g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("1,{:x}", (uintptr_t)this)});
@@ -904,11 +873,9 @@ void CWindow::destroyGroup() {
m_sGroupData.pNextWindow.reset(); m_sGroupData.pNextWindow.reset();
m_sGroupData.head = false; m_sGroupData.head = false;
updateWindowDecos(); updateWindowDecos();
if (m_pWorkspace) { g_pCompositor->updateWorkspaceWindows(workspaceID());
m_pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
m_pWorkspace->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("0,{:x}", (uintptr_t)this)}); g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("0,{:x}", (uintptr_t)this)});
@@ -942,11 +909,9 @@ void CWindow::destroyGroup() {
} }
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
if (m_pWorkspace) { g_pCompositor->updateWorkspaceWindows(workspaceID());
m_pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
m_pWorkspace->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!addresses.empty()) if (!addresses.empty())
@@ -1122,7 +1087,7 @@ void CWindow::updateGroupOutputs() {
const auto WS = m_pWorkspace; const auto WS = m_pWorkspace;
while (curr.get() != this) { while (curr.get() != this) {
curr->m_pMonitor = m_pMonitor; curr->m_iMonitorID = m_iMonitorID;
curr->moveToWorkspace(WS); curr->moveToWorkspace(WS);
curr->m_vRealPosition = m_vRealPosition.goal(); curr->m_vRealPosition = m_vRealPosition.goal();
@@ -1203,16 +1168,6 @@ int CWindow::getRealBorderSize() {
return m_sWindowData.borderSize.valueOr(*PBORDERSIZE); return m_sWindowData.borderSize.valueOr(*PBORDERSIZE);
} }
float CWindow::getScrollMouse() {
static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor");
return m_sWindowData.scrollMouse.valueOr(*PINPUTSCROLLFACTOR);
}
float CWindow::getScrollTouchpad() {
static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor");
return m_sWindowData.scrollTouchpad.valueOr(*PTOUCHPADSCROLLFACTOR);
}
bool CWindow::canBeTorn() { bool CWindow::canBeTorn() {
static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing"); static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING; return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING;
@@ -1229,7 +1184,7 @@ void CWindow::setSuspended(bool suspend) {
m_bSuspended = suspend; m_bSuspended = suspend;
} }
bool CWindow::visibleOnMonitor(PHLMONITOR pMonitor) { bool CWindow::visibleOnMonitor(CMonitor* pMonitor) {
CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()}; CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()};
return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty(); return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty();
@@ -1254,7 +1209,7 @@ void CWindow::onWorkspaceAnimUpdate() {
if (!PWORKSPACE) if (!PWORKSPACE)
return; return;
const auto PWSMON = m_pMonitor.lock(); const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
if (!PWSMON) if (!PWSMON)
return; return;
@@ -1298,16 +1253,6 @@ int CWindow::surfacesCount() {
return no; return no;
} }
void CWindow::clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize) {
const Vector2D REALSIZE = m_vRealSize.goal();
const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), maxSize.value_or(Vector2D{INFINITY, INFINITY}));
const Vector2D DELTA = REALSIZE - NEWSIZE;
m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0;
m_vRealSize = NEWSIZE;
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE);
}
bool CWindow::isFullscreen() { bool CWindow::isFullscreen() {
return m_sFullscreenState.internal != FSMODE_NONE; return m_sFullscreenState.internal != FSMODE_NONE;
} }
@@ -1320,10 +1265,6 @@ WORKSPACEID CWindow::workspaceID() {
return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace; return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace;
} }
MONITORID CWindow::monitorID() {
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID;
}
bool CWindow::onSpecialWorkspace() { bool CWindow::onSpecialWorkspace() {
return m_pWorkspace ? m_pWorkspace->m_bIsSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_iLastWorkspace); return m_pWorkspace ? m_pWorkspace->m_bIsSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_iLastWorkspace);
} }
@@ -1510,7 +1451,7 @@ void CWindow::onX11Configure(CBox box) {
m_pXWaylandSurface->configure(box); m_pXWaylandSurface->configure(box);
m_vPendingReportedSize = box.size(); m_vPendingReportedSize = box.size();
m_vReportedSize = box.size(); m_vReportedSize = box.size();
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
m_fX11SurfaceScaledBy = PMONITOR->scale; m_fX11SurfaceScaledBy = PMONITOR->scale;
return; return;
} }
@@ -1536,7 +1477,7 @@ void CWindow::onX11Configure(CBox box) {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling"); static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (*PXWLFORCESCALEZERO) { if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) { if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) {
m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale); m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale);
m_fX11SurfaceScaledBy = PMONITOR->scale; m_fX11SurfaceScaledBy = PMONITOR->scale;
} }
@@ -1552,7 +1493,7 @@ void CWindow::onX11Configure(CBox box) {
updateWindowDecos(); updateWindowDecos();
if (!m_pWorkspace || !m_pWorkspace->isVisible()) if (!g_pCompositor->isWorkspaceVisible(m_pWorkspace))
return; // further things are only for visible windows return; // further things are only for visible windows
m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace; m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace;
@@ -1564,15 +1505,15 @@ void CWindow::onX11Configure(CBox box) {
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());
} }
void CWindow::warpCursor(bool force) { void CWindow::warpCursor() {
static auto PERSISTENTWARPS = CConfigValue<Hyprlang::INT>("cursor:persistent_warps"); static auto PERSISTENTWARPS = CConfigValue<Hyprlang::INT>("cursor:persistent_warps");
const auto coords = m_vRelativeCursorCoordsOnLastWarp; const auto coords = m_vRelativeCursorCoordsOnLastWarp;
m_vRelativeCursorCoordsOnLastWarp.x = -1; // reset m_vRelativeCursorCoordsOnLastWarp m_vRelativeCursorCoordsOnLastWarp.x = -1; // reset m_vRelativeCursorCoordsOnLastWarp
if (*PERSISTENTWARPS && coords.x > 0 && coords.y > 0 && coords < m_vSize) // don't warp cursor outside the window if (*PERSISTENTWARPS && coords.x > 0 && coords.y > 0 && coords < m_vSize) // don't warp cursor outside the window
g_pCompositor->warpCursorTo(m_vPosition + coords, force); g_pCompositor->warpCursorTo(m_vPosition + coords);
else else
g_pCompositor->warpCursorTo(middle(), force); g_pCompositor->warpCursorTo(middle());
} }
PHLWINDOW CWindow::getSwallower() { PHLWINDOW CWindow::getSwallower() {
@@ -1580,7 +1521,7 @@ PHLWINDOW CWindow::getSwallower() {
static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex"); static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex");
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow"); static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
if (!*PSWALLOW || std::string{*PSWALLOWREGEX} == STRVAL_EMPTY || (*PSWALLOWREGEX).empty()) if (!*PSWALLOW || (*PSWALLOWREGEX).empty())
return nullptr; return nullptr;
// check parent // check parent
@@ -1603,13 +1544,13 @@ PHLWINDOW CWindow::getSwallower() {
} }
if (!(*PSWALLOWREGEX).empty()) if (!(*PSWALLOWREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return !RE2::FullMatch(other->m_szClass, *PSWALLOWREGEX); }); std::erase_if(candidates, [&](const auto& other) { return !std::regex_match(other->m_szClass, std::regex(*PSWALLOWREGEX)); });
if (candidates.size() <= 0) if (candidates.size() <= 0)
return nullptr; return nullptr;
if (!(*PSWALLOWEXREGEX).empty()) if (!(*PSWALLOWEXREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return RE2::FullMatch(other->m_szTitle, *PSWALLOWEXREGEX); }); std::erase_if(candidates, [&](const auto& other) { return std::regex_match(other->m_szTitle, std::regex(*PSWALLOWEXREGEX)); });
if (candidates.size() <= 0) if (candidates.size() <= 0)
return nullptr; return nullptr;
@@ -1637,9 +1578,6 @@ void CWindow::unsetWindowData(eOverridePriority priority) {
for (auto const& element : g_pConfigManager->miWindowProperties) { for (auto const& element : g_pConfigManager->miWindowProperties) {
element.second(m_pSelf.lock())->unset(priority); element.second(m_pSelf.lock())->unset(priority);
} }
for (auto const& element : g_pConfigManager->mfWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
} }
bool CWindow::isX11OverrideRedirect() { bool CWindow::isX11OverrideRedirect() {
@@ -1649,29 +1587,3 @@ bool CWindow::isX11OverrideRedirect() {
bool CWindow::isModal() { bool CWindow::isModal() {
return (m_pXWaylandSurface && m_pXWaylandSurface->modal); return (m_pXWaylandSurface && m_pXWaylandSurface->modal);
} }
Vector2D CWindow::requestedMinSize() {
if ((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel))
return Vector2D(1, 1);
Vector2D minSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->min_width, m_pXWaylandSurface->sizeHints->min_height) : m_pXDGSurface->toplevel->layoutMinSize();
minSize = minSize.clamp({1, 1});
return minSize;
}
Vector2D CWindow::requestedMaxSize() {
constexpr int NO_MAX_SIZE_LIMIT = 99999;
if (((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel) || m_sWindowData.noMaxSize.valueOrDefault()))
return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT);
Vector2D maxSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->max_width, m_pXWaylandSurface->sizeHints->max_height) : m_pXDGSurface->toplevel->layoutMaxSize();
if (maxSize.x < 5)
maxSize.x = NO_MAX_SIZE_LIMIT;
if (maxSize.y < 5)
maxSize.y = NO_MAX_SIZE_LIMIT;
return maxSize;
}

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include <vector> #include <deque>
#include <string> #include <string>
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
@@ -17,19 +17,18 @@
#include "Subsurface.hpp" #include "Subsurface.hpp"
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "Workspace.hpp" #include "Workspace.hpp"
#include "WindowRule.hpp"
class CXDGSurfaceResource; class CXDGSurfaceResource;
class CXWaylandSurface; class CXWaylandSurface;
enum eIdleInhibitMode : uint8_t { enum eIdleInhibitMode {
IDLEINHIBIT_NONE = 0, IDLEINHIBIT_NONE = 0,
IDLEINHIBIT_ALWAYS, IDLEINHIBIT_ALWAYS,
IDLEINHIBIT_FULLSCREEN, IDLEINHIBIT_FULLSCREEN,
IDLEINHIBIT_FOCUS IDLEINHIBIT_FOCUS
}; };
enum eGroupRules : uint8_t { enum eGroupRules {
// effective only during first map, except for _ALWAYS variant // effective only during first map, except for _ALWAYS variant
GROUP_NONE = 0, GROUP_NONE = 0,
GROUP_SET = 1 << 0, // Open as new group or add to focused group GROUP_SET = 1 << 0, // Open as new group or add to focused group
@@ -41,7 +40,7 @@ enum eGroupRules : uint8_t {
GROUP_OVERRIDE = 1 << 6, // Override other rules GROUP_OVERRIDE = 1 << 6, // Override other rules
}; };
enum eGetWindowProperties : uint8_t { enum eGetWindowProperties {
WINDOW_ONLY = 0, WINDOW_ONLY = 0,
RESERVED_EXTENTS = 1 << 0, RESERVED_EXTENTS = 1 << 0,
INPUT_EXTENTS = 1 << 1, INPUT_EXTENTS = 1 << 1,
@@ -51,7 +50,7 @@ enum eGetWindowProperties : uint8_t {
USE_PROP_TILED = 1 << 5, USE_PROP_TILED = 1 << 5,
}; };
enum eSuppressEvents : uint8_t { enum eSuppressEvents {
SUPPRESS_NONE = 0, SUPPRESS_NONE = 0,
SUPPRESS_FULLSCREEN = 1 << 0, SUPPRESS_FULLSCREEN = 1 << 0,
SUPPRESS_MAXIMIZE = 1 << 1, SUPPRESS_MAXIMIZE = 1 << 1,
@@ -65,7 +64,7 @@ struct SAlphaValue {
float m_fAlpha; float m_fAlpha;
bool m_bOverride; bool m_bOverride;
float applyAlpha(float alpha) const { float applyAlpha(float alpha) {
if (m_bOverride) if (m_bOverride)
return m_fAlpha; return m_fAlpha;
else else
@@ -73,8 +72,8 @@ struct SAlphaValue {
}; };
}; };
enum eOverridePriority : uint8_t { enum eOverridePriority {
PRIORITY_LAYOUT = 0, PRIORITY_LAYOUT,
PRIORITY_WORKSPACE_RULE, PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE, PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP, PRIORITY_SET_PROP,
@@ -86,7 +85,9 @@ class CWindowOverridableVar {
CWindowOverridableVar(T const& value, eOverridePriority priority) { CWindowOverridableVar(T const& value, eOverridePriority priority) {
values[priority] = value; values[priority] = value;
} }
CWindowOverridableVar(T const& value) : defaultValue{value} {} CWindowOverridableVar(T const& value) {
defaultValue = value;
}
CWindowOverridableVar() = default; CWindowOverridableVar() = default;
~CWindowOverridableVar() = default; ~CWindowOverridableVar() = default;
@@ -143,13 +144,6 @@ class CWindowOverridableVar {
unset(priority); unset(priority);
} }
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private: private:
std::map<eOverridePriority, T> values; std::map<eOverridePriority, T> values;
T defaultValue; // used for toggling, so required for bool T defaultValue; // used for toggling, so required for bool
@@ -185,9 +179,6 @@ struct SWindowData {
CWindowOverridableVar<int> rounding; CWindowOverridableVar<int> rounding;
CWindowOverridableVar<int> borderSize; CWindowOverridableVar<int> borderSize;
CWindowOverridableVar<float> scrollMouse;
CWindowOverridableVar<float> scrollTouchpad;
CWindowOverridableVar<std::string> animationStyle; CWindowOverridableVar<std::string> animationStyle;
CWindowOverridableVar<Vector2D> maxSize; CWindowOverridableVar<Vector2D> maxSize;
CWindowOverridableVar<Vector2D> minSize; CWindowOverridableVar<Vector2D> minSize;
@@ -196,12 +187,32 @@ struct SWindowData {
CWindowOverridableVar<CGradientValueData> inactiveBorderColor; CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
}; };
struct SWindowRule {
std::string szRule;
std::string szValue;
bool v2 = false;
std::string szTitle;
std::string szClass;
std::string szInitialTitle;
std::string szInitialClass;
std::string szTag;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
int bFullscreen = -1;
int bPinned = -1;
int bFocus = -1;
std::string szFullscreenState = ""; // empty means any
std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any
};
struct SInitialWorkspaceToken { struct SInitialWorkspaceToken {
PHLWINDOWREF primaryOwner; PHLWINDOWREF primaryOwner;
std::string workspace; std::string workspace;
}; };
struct SFullscreenState { struct sFullscreenState {
eFullscreenMode internal = FSMODE_NONE; eFullscreenMode internal = FSMODE_NONE;
eFullscreenMode client = FSMODE_NONE; eFullscreenMode client = FSMODE_NONE;
}; };
@@ -260,13 +271,13 @@ class CWindow {
bool m_bIsFloating = false; bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bWasMaximized = false; bool m_bWasMaximized = false;
SFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE}; sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
MONITORID m_iMonitorID = -1;
std::string m_szTitle = ""; std::string m_szTitle = "";
std::string m_szClass = ""; std::string m_szClass = "";
std::string m_szInitialTitle = ""; std::string m_szInitialTitle = "";
std::string m_szInitialClass = ""; std::string m_szInitialClass = "";
PHLWORKSPACE m_pWorkspace; PHLWORKSPACE m_pWorkspace;
PHLMONITORREF m_pMonitor;
bool m_bIsMapped = false; bool m_bIsMapped = false;
@@ -314,9 +325,6 @@ class CWindow {
// For pinned (sticky) windows // For pinned (sticky) windows
bool m_bPinned = false; bool m_bPinned = false;
// For preserving pinned state when fullscreening a pinned window
bool m_bPinFullscreened = false;
// urgency hint // urgency hint
bool m_bIsUrgent = false; bool m_bIsUrgent = false;
@@ -325,8 +333,8 @@ class CWindow {
// Window decorations // Window decorations
// TODO: make this a SP. // TODO: make this a SP.
std::vector<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations; std::deque<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations;
std::vector<IHyprWindowDecoration*> m_vDecosToRemove; std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
// Special render data, rules, etc // Special render data, rules, etc
SWindowData m_sWindowData; SWindowData m_sWindowData;
@@ -338,7 +346,7 @@ class CWindow {
CAnimatedVariable<float> m_fActiveInactiveAlpha; CAnimatedVariable<float> m_fActiveInactiveAlpha;
// animated shadow color // animated shadow color
CAnimatedVariable<CHyprColor> m_cRealShadowColor; CAnimatedVariable<CColor> m_cRealShadowColor;
// animated tint // animated tint
CAnimatedVariable<float> m_fDimPercent; CAnimatedVariable<float> m_fDimPercent;
@@ -349,7 +357,6 @@ class CWindow {
// swallowing // swallowing
PHLWINDOWREF m_pSwallowed; PHLWINDOWREF m_pSwallowed;
bool m_bGroupSwallowed = false;
// focus stuff // focus stuff
bool m_bStayFocused = false; bool m_bStayFocused = false;
@@ -376,13 +383,13 @@ class CWindow {
bool m_bTearingHint = false; bool m_bTearingHint = false;
// stores the currently matched window rules // stores the currently matched window rules
std::vector<SP<CWindowRule>> m_vMatchedRules; std::vector<SWindowRule> m_vMatchedRules;
// window tags // window tags
CTagKeeper m_tags; CTagKeeper m_tags;
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) const { bool operator==(const CWindow& rhs) {
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
m_bFadingOut == rhs.m_bFadingOut; m_bFadingOut == rhs.m_bFadingOut;
} }
@@ -391,6 +398,7 @@ class CWindow {
CBox getFullWindowBoundingBox(); CBox getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents(); SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props); CBox getWindowBoxUnified(uint64_t props);
CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved(); CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco); void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos(); void updateWindowDecos();
@@ -403,12 +411,12 @@ class CWindow {
void updateToplevel(); void updateToplevel();
void updateSurfaceScaleTransformDetails(bool force = false); void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE); void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW x11TransientFor(); PHLWINDOW X11TransientFor();
void onUnmap(); void onUnmap();
void onMap(); void onMap();
void setHidden(bool hidden); void setHidden(bool hidden);
bool isHidden(); bool isHidden();
void applyDynamicRule(const SP<CWindowRule>& r); void applyDynamicRule(const SWindowRule& r);
void updateDynamicRules(); void updateDynamicRules();
SBoxExtents getFullWindowReservedArea(); SBoxExtents getFullWindowReservedArea();
Vector2D middle(); Vector2D middle();
@@ -416,24 +424,24 @@ class CWindow {
float rounding(); float rounding();
bool canBeTorn(); bool canBeTorn();
void setSuspended(bool suspend); void setSuspended(bool suspend);
bool visibleOnMonitor(PHLMONITOR pMonitor); bool visibleOnMonitor(CMonitor* pMonitor);
WORKSPACEID workspaceID(); WORKSPACEID workspaceID();
MONITORID monitorID();
bool onSpecialWorkspace(); bool onSpecialWorkspace();
void activate(bool force = false); void activate(bool force = false);
int surfacesCount(); int surfacesCount();
void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
bool isFullscreen(); bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode); bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize(); int getRealBorderSize();
float getScrollMouse();
float getScrollTouchpad();
void updateWindowData(); void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&); void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(void* ptr); void onBorderAngleAnimEnd(void* ptr);
bool isInCurvedCorner(double x, double y); bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos); bool hasPopupAt(const Vector2D& pos);
int popupsCount(); int popupsCount();
void applyGroupRules(); void applyGroupRules();
void createGroup(); void createGroup();
void destroyGroup(); void destroyGroup();
@@ -456,17 +464,11 @@ class CWindow {
void onResourceChangeX11(); void onResourceChangeX11();
std::string fetchTitle(); std::string fetchTitle();
std::string fetchClass(); std::string fetchClass();
void warpCursor(bool force = false); void warpCursor();
PHLWINDOW getSwallower(); PHLWINDOW getSwallower();
void unsetWindowData(eOverridePriority priority); void unsetWindowData(eOverridePriority priority);
bool isX11OverrideRedirect(); bool isX11OverrideRedirect();
bool isModal(); bool isModal();
Vector2D requestedMinSize();
Vector2D requestedMaxSize();
CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
// listeners // listeners
void onAck(uint32_t serial); void onAck(uint32_t serial);
@@ -553,7 +555,7 @@ struct std::formatter<PHLWINDOW, CharT> : std::formatter<CharT> {
if (formatWorkspace) if (formatWorkspace)
std::format_to(out, ", workspace: {}", w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID); std::format_to(out, ", workspace: {}", w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID);
if (formatMonitor) if (formatMonitor)
std::format_to(out, ", monitor: {}", w->monitorID()); std::format_to(out, ", monitor: {}", w->m_iMonitorID);
if (formatClass) if (formatClass)
std::format_to(out, ", class: {}", w->m_szClass); std::format_to(out, ", class: {}", w->m_szClass);
return std::format_to(out, "]"); return std::format_to(out, "]");

View File

@@ -1,90 +0,0 @@
#include "WindowRule.hpp"
#include <unordered_set>
#include <algorithm>
#include "../config/ConfigManager.hpp"
static const auto RULES = std::unordered_set<std::string>{
"float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused",
};
static const auto RULES_PREFIX = std::unordered_set<std::string>{
"animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity",
"plugin:", "prop", "pseudo", "rounding", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray",
};
CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) {
const auto VALS = CVarList(rule, 2, ' ');
const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule](auto prefix) { return rule.starts_with(prefix); }) ||
(g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) ||
(g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end()) ||
(g_pConfigManager->mfWindowProperties.find(VALS[0]) != g_pConfigManager->mfWindowProperties.end());
if (!VALID)
return;
if (rule == "float")
ruleType = RULE_FLOAT;
else if (rule == "fullscreen")
ruleType = RULE_FULLSCREEN;
else if (rule == "maximize")
ruleType = RULE_MAXIMIZE;
else if (rule == "noinitialfocus")
ruleType = RULE_NOINITIALFOCUS;
else if (rule == "pin")
ruleType = RULE_PIN;
else if (rule == "stayfocused")
ruleType = RULE_STAYFOCUSED;
else if (rule == "tile")
ruleType = RULE_TILE;
else if (rule == "renderunfocused")
ruleType = RULE_RENDERUNFOCUSED;
else if (rule.starts_with("animation"))
ruleType = RULE_ANIMATION;
else if (rule.starts_with("bordercolor"))
ruleType = RULE_BORDERCOLOR;
else if (rule.starts_with("center"))
ruleType = RULE_CENTER;
else if (rule.starts_with("fullscreenstate"))
ruleType = RULE_FULLSCREENSTATE;
else if (rule.starts_with("group"))
ruleType = RULE_GROUP;
else if (rule.starts_with("idleinhibit"))
ruleType = RULE_IDLEINHIBIT;
else if (rule.starts_with("maxsize"))
ruleType = RULE_MAXSIZE;
else if (rule.starts_with("minsize"))
ruleType = RULE_MINSIZE;
else if (rule.starts_with("monitor"))
ruleType = RULE_MONITOR;
else if (rule.starts_with("move"))
ruleType = RULE_MOVE;
else if (rule.starts_with("opacity"))
ruleType = RULE_OPACITY;
else if (rule.starts_with("plugin:"))
ruleType = RULE_PLUGIN;
else if (rule.starts_with("pseudo"))
ruleType = RULE_PSEUDO;
else if (rule.starts_with("size"))
ruleType = RULE_SIZE;
else if (rule.starts_with("suppressevent"))
ruleType = RULE_SUPPRESSEVENT;
else if (rule.starts_with("tag"))
ruleType = RULE_TAG;
else if (rule.starts_with("workspace"))
ruleType = RULE_WORKSPACE;
else if (rule.starts_with("prop"))
ruleType = RULE_PROP;
else {
// check if this is a prop.
const CVarList VARS(rule, 0, 's', true);
if (g_pConfigManager->miWindowProperties.find(VARS[0]) != g_pConfigManager->miWindowProperties.end() ||
g_pConfigManager->mbWindowProperties.find(VARS[0]) != g_pConfigManager->mbWindowProperties.end() ||
g_pConfigManager->mfWindowProperties.find(VARS[0]) != g_pConfigManager->mfWindowProperties.end()) {
*const_cast<std::string*>(&szRule) = "prop " + rule;
ruleType = RULE_PROP;
Debug::log(LOG, "CWindowRule: direct prop rule found, rewritten {} -> {}", rule, szRule);
} else {
Debug::log(ERR, "CWindowRule: didn't match a rule that was found valid?!");
ruleType = RULE_INVALID;
}
}
}

View File

@@ -1,60 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
class CWindowRule {
public:
CWindowRule(const std::string& rule, const std::string& value, bool isV2 = false, bool isExecRule = false);
enum eRuleType : uint8_t {
RULE_INVALID = 0,
RULE_FLOAT,
RULE_FULLSCREEN,
RULE_MAXIMIZE,
RULE_NOINITIALFOCUS,
RULE_PIN,
RULE_STAYFOCUSED,
RULE_TILE,
RULE_RENDERUNFOCUSED,
RULE_ANIMATION,
RULE_BORDERCOLOR,
RULE_CENTER,
RULE_FULLSCREENSTATE,
RULE_GROUP,
RULE_IDLEINHIBIT,
RULE_MAXSIZE,
RULE_MINSIZE,
RULE_MONITOR,
RULE_MOVE,
RULE_OPACITY,
RULE_PLUGIN,
RULE_PSEUDO,
RULE_SIZE,
RULE_SUPPRESSEVENT,
RULE_TAG,
RULE_WORKSPACE,
RULE_PROP,
};
eRuleType ruleType = RULE_INVALID;
const std::string szValue;
const std::string szRule;
const bool v2 = false;
const bool execRule = false;
std::string szTitle;
std::string szClass;
std::string szInitialTitle;
std::string szInitialClass;
std::string szTag;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
int bFullscreen = -1;
int bPinned = -1;
int bFocus = -1;
std::string szFullscreenState = ""; // empty means any
std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any
};

View File

@@ -5,15 +5,18 @@
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) { PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) {
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitor, name, special, isEmpty); PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmpty);
workspace->init(workspace); workspace->init(workspace);
return workspace; return workspace;
} }
CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) : CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) {
m_iID(id), m_szName(name), m_pMonitor(monitor), m_bIsSpecialWorkspace(special), m_bWasCreatedEmpty(isEmpty) { m_iMonitorID = monitorID;
; m_iID = id;
m_szName = name;
m_bIsSpecialWorkspace = special;
m_bWasCreatedEmpty = isEmpty;
} }
void CWorkspace::init(PHLWORKSPACE self) { void CWorkspace::init(PHLWORKSPACE self) {
@@ -100,10 +103,10 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
}); });
if (ANIMSTYLE.starts_with("slidefade")) { if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
float movePerc = 100.f; float movePerc = 100.f;
if (ANIMSTYLE.find('%') != std::string::npos) { if (ANIMSTYLE.find("%") != std::string::npos) {
try { try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1); auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1);
movePerc = std::stoi(percstr.substr(0, percstr.length() - 1)); movePerc = std::stoi(percstr.substr(0, percstr.length() - 1));
@@ -148,7 +151,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} }
} else if (ANIMSTYLE == "slidevert") { } else if (ANIMSTYLE == "slidevert") {
// fallback is slide // fallback is slide
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP; const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
@@ -161,7 +164,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} }
} else { } else {
// fallback is slide // fallback is slide
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP; const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
@@ -221,7 +224,7 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
m_sPrevWorkspace.id = prev->m_iID; m_sPrevWorkspace.id = prev->m_iID;
m_sPrevWorkspace.name = prev->m_szName; m_sPrevWorkspace.name = prev->m_szName;
if (prev->m_pMonitor == m_pMonitor) { if (prev->m_iMonitorID == m_iMonitorID) {
m_sPrevWorkspacePerMonitor.id = prev->m_iID; m_sPrevWorkspacePerMonitor.id = prev->m_iID;
m_sPrevWorkspacePerMonitor.name = prev->m_szName; m_sPrevWorkspacePerMonitor.name = prev->m_szName;
} }
@@ -275,9 +278,9 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
// f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states // f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states
// -1: no fullscreen, 0: fullscreen, 1: maximized, 2: fullscreen without sending fs state to window // -1: no fullscreen, 0: fullscreen, 1: maximized, 2: fullscreen without sending fs state to window
const auto CLOSING_BRACKET = selector.find_first_of(']', i); const auto NEXTSPACE = selector.find_first_of(' ', i);
std::string prop = selector.substr(i, CLOSING_BRACKET == std::string::npos ? std::string::npos : CLOSING_BRACKET + 1 - i); std::string prop = selector.substr(i, NEXTSPACE == std::string::npos ? std::string::npos : NEXTSPACE - i);
i = std::min(CLOSING_BRACKET, std::string::npos - 1); i = std::min(NEXTSPACE, std::string::npos - 1);
if (cur == 'r') { if (cur == 'r') {
WORKSPACEID from = 0, to = 0; WORKSPACEID from = 0, to = 0;
@@ -293,7 +296,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false; return false;
} }
const auto DASHPOS = prop.find('-'); const auto DASHPOS = prop.find("-");
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1); const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) { if (!isNumber(LHS) || !isNumber(RHS)) {
@@ -329,7 +332,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto SHOULDBESPECIAL = configStringToInt(prop); const auto SHOULDBESPECIAL = configStringToInt(prop);
if (SHOULDBESPECIAL && (bool)*SHOULDBESPECIAL != m_bIsSpecialWorkspace) if ((bool)SHOULDBESPECIAL != m_bIsSpecialWorkspace)
return false; return false;
continue; continue;
} }
@@ -344,7 +347,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto PMONITOR = g_pCompositor->getMonitorFromString(prop); const auto PMONITOR = g_pCompositor->getMonitorFromString(prop);
if (!(PMONITOR ? PMONITOR == m_pMonitor : false)) if (!(PMONITOR ? PMONITOR->ID == m_iMonitorID : false))
return false; return false;
continue; continue;
} }
@@ -364,7 +367,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto WANTSNAMED = configStringToInt(prop); const auto WANTSNAMED = configStringToInt(prop);
if (WANTSNAMED && *WANTSNAMED != (m_iID <= -1337)) if (WANTSNAMED != (m_iID <= -1337))
return false; return false;
continue; continue;
} }
@@ -419,18 +422,18 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
int count; int count;
if (wantsCountGroup) if (wantsCountGroup)
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (count != from) if (count != from)
return false; return false;
continue; continue;
} }
const auto DASHPOS = prop.find('-'); const auto DASHPOS = prop.find("-");
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1); const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) { if (!isNumber(LHS) || !isNumber(RHS)) {
@@ -453,11 +456,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
WORKSPACEID count; WORKSPACEID count;
if (wantsCountGroup) if (wantsCountGroup)
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (std::clamp(count, from, to) != count) if (std::clamp(count, from, to) != count)
return false; return false;
@@ -509,151 +512,12 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
} }
void CWorkspace::markInert() { void CWorkspace::markInert() {
m_bInert = true; m_bInert = true;
m_iID = WORKSPACE_INVALID; m_iID = WORKSPACE_INVALID;
m_bVisible = false; m_iMonitorID = MONITOR_INVALID;
m_pMonitor.reset(); m_bVisible = false;
} }
bool CWorkspace::inert() { bool CWorkspace::inert() {
return m_bInert; return m_bInert;
} }
MONITORID CWorkspace::monitorID() {
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID;
}
PHLWINDOW CWorkspace::getFullscreenWindow() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->isFullscreen())
return w;
}
return nullptr;
}
bool CWorkspace::isVisible() {
return m_bVisible;
}
bool CWorkspace::isVisibleNotCovered() {
const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR->activeSpecialWorkspace)
return PMONITOR->activeSpecialWorkspace->m_iID == m_iID;
return PMONITOR->activeWorkspace->m_iID == m_iID;
}
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
}
return no;
}
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue;
if (!w->m_sGroupData.head)
continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
}
return no;
}
PHLWINDOW CWorkspace::getFirstWindow() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && !w->isHidden())
return w;
}
return nullptr;
}
PHLWINDOW CWorkspace::getTopLeftWindow() {
const auto PMONITOR = m_pMonitor.lock();
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue;
const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
if (WINDOWIDEALBB.x <= PMONITOR->vecPosition.x + 1 && WINDOWIDEALBB.y <= PMONITOR->vecPosition.y + 1)
return w;
}
return nullptr;
}
bool CWorkspace::hasUrgentWindow() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && w->m_bIsUrgent)
return true;
}
return false;
}
void CWorkspace::updateWindowDecos() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf)
continue;
w->updateWindowDecos();
}
}
void CWorkspace::updateWindowData() {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock());
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf)
continue;
w->updateWindowData(WORKSPACERULE);
}
}
void CWorkspace::forceReportSizesToWindows() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue;
g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true);
}
}
void CWorkspace::rename(const std::string& name) {
if (g_pCompositor->isWorkspaceSpecial(m_iID))
return;
Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name);
m_szName = name;
g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName});
}
void CWorkspace::updateWindows() {
m_bHasFullscreenWindow = std::ranges::any_of(g_pCompositor->m_vWindows, [this](const auto& w) { return w->m_bIsMapped && w->m_pWorkspace == m_pSelf && w->isFullscreen(); });
for (auto const& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_pWorkspace != m_pSelf)
continue;
w->updateDynamicRules();
}
}

View File

@@ -17,16 +17,16 @@ class CWindow;
class CWorkspace { class CWorkspace {
public: public:
static PHLWORKSPACE create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true); static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true);
// use create() don't use this // use create() don't use this
CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true); CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true);
~CWorkspace(); ~CWorkspace();
// Workspaces ID-based have IDs > 0 // Workspaces ID-based have IDs > 0
// and workspaces name-based have IDs starting with -1337 // and workspaces name-based have IDs starting with -1337
WORKSPACEID m_iID = WORKSPACE_INVALID; WORKSPACEID m_iID = WORKSPACE_INVALID;
std::string m_szName = ""; std::string m_szName = "";
PHLMONITORREF m_pMonitor; MONITORID m_iMonitorID = MONITOR_INVALID;
// Previous workspace ID and name is stored during a workspace change, allowing travel // Previous workspace ID and name is stored during a workspace change, allowing travel
// to the previous workspace. // to the previous workspace.
SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor; SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor;
@@ -63,29 +63,22 @@ class CWorkspace {
// Inert: destroyed and invalid. If this is true, release the ptr you have. // Inert: destroyed and invalid. If this is true, release the ptr you have.
bool inert(); bool inert();
void startAnim(bool in, bool left, bool instant = false); void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on); void setActive(bool on);
void moveToMonitor(const MONITORID&); void moveToMonitor(const MONITORID&);
MONITORID monitorID();
PHLWINDOW getLastFocusedWindow(); PHLWINDOW getLastFocusedWindow();
void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);
std::string getConfigName(); std::string getConfigName();
bool matchesStaticSelector(const std::string& selector); bool matchesStaticSelector(const std::string& selector);
void markInert(); void markInert();
SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const; SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const;
void updateWindowDecos();
void updateWindowData();
int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
bool hasUrgentWindow();
PHLWINDOW getFirstWindow();
PHLWINDOW getTopLeftWindow();
PHLWINDOW getFullscreenWindow();
bool isVisible();
bool isVisibleNotCovered();
void rename(const std::string& name = "");
void forceReportSizesToWindows();
void updateWindows();
private: private:
void init(PHLWORKSPACE self); void init(PHLWORKSPACE self);

View File

@@ -4,14 +4,14 @@
#include <string> #include <string>
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
enum eHIDCapabilityType : uint8_t { enum eHIDCapabilityType : uint32_t {
HID_INPUT_CAPABILITY_KEYBOARD = (1 << 0), HID_INPUT_CAPABILITY_KEYBOARD = (1 << 0),
HID_INPUT_CAPABILITY_POINTER = (1 << 1), HID_INPUT_CAPABILITY_POINTER = (1 << 1),
HID_INPUT_CAPABILITY_TOUCH = (1 << 2), HID_INPUT_CAPABILITY_TOUCH = (1 << 2),
HID_INPUT_CAPABILITY_TABLET = (1 << 3), HID_INPUT_CAPABILITY_TABLET = (1 << 3),
}; };
enum eHIDType : uint8_t { enum eHIDType {
HID_TYPE_UNKNOWN = 0, HID_TYPE_UNKNOWN = 0,
HID_TYPE_POINTER, HID_TYPE_POINTER,
HID_TYPE_KEYBOARD, HID_TYPE_KEYBOARD,
@@ -27,7 +27,7 @@ enum eHIDType : uint8_t {
*/ */
class IHID { class IHID {
public: public:
virtual ~IHID() = default; virtual ~IHID() {}
virtual uint32_t getCapabilities() = 0; virtual uint32_t getCapabilities() = 0;
virtual eHIDType getType(); virtual eHIDType getType();
@@ -36,5 +36,5 @@ class IHID {
CSignal destroy; CSignal destroy;
} events; } events;
std::string deviceName, hlName; std::string deviceName;
}; };

View File

@@ -94,6 +94,7 @@ class IKeyboard : public IHID {
std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID}; std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID};
uint32_t leds = 0; uint32_t leds = 0;
std::string hlName = "";
std::string xkbFilePath = ""; std::string xkbFilePath = "";
std::string xkbKeymapString = ""; std::string xkbKeymapString = "";
int xkbKeymapFD = -1; int xkbKeymapFD = -1;

View File

@@ -19,7 +19,6 @@ class IPointer : public IHID {
struct SMotionEvent { struct SMotionEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;
Vector2D delta, unaccel; Vector2D delta, unaccel;
bool mouse = false;
}; };
struct SMotionAbsoluteEvent { struct SMotionAbsoluteEvent {
@@ -32,7 +31,6 @@ class IPointer : public IHID {
uint32_t timeMs = 0; uint32_t timeMs = 0;
uint32_t button = 0; uint32_t button = 0;
wl_pointer_button_state state = WL_POINTER_BUTTON_STATE_PRESSED; wl_pointer_button_state state = WL_POINTER_BUTTON_STATE_PRESSED;
bool mouse = false;
}; };
struct SAxisEvent { struct SAxisEvent {
@@ -42,7 +40,6 @@ class IPointer : public IHID {
wl_pointer_axis_relative_direction relativeDirection = WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL; wl_pointer_axis_relative_direction relativeDirection = WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL;
double delta = 0.0; double delta = 0.0;
int32_t deltaDiscrete = 0; int32_t deltaDiscrete = 0;
bool mouse = false;
}; };
struct SSwipeBeginEvent { struct SSwipeBeginEvent {
@@ -107,6 +104,7 @@ class IPointer : public IHID {
CSignal holdEnd; CSignal holdEnd;
} pointerEvents; } pointerEvents;
std::string hlName;
bool connected = false; // means connected to the cursor bool connected = false; // means connected to the cursor
std::string boundOutput = ""; std::string boundOutput = "";

View File

@@ -44,6 +44,7 @@ class ITouch : public IHID {
CSignal frame; CSignal frame;
} touchEvents; } touchEvents;
std::string hlName = "";
std::string boundOutput = ""; std::string boundOutput = "";
WP<ITouch> self; WP<ITouch> self;

View File

@@ -26,7 +26,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.timeMs = E.timeMs, .timeMs = E.timeMs,
.delta = E.delta, .delta = E.delta,
.unaccel = E.unaccel, .unaccel = E.unaccel,
.mouse = true,
}); });
}); });
@@ -47,7 +46,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.timeMs = E.timeMs, .timeMs = E.timeMs,
.button = E.button, .button = E.button,
.state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED, .state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
.mouse = true,
}); });
}); });
@@ -61,7 +59,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.relativeDirection = (wl_pointer_axis_relative_direction)E.direction, .relativeDirection = (wl_pointer_axis_relative_direction)E.direction,
.delta = E.delta, .delta = E.delta,
.deltaDiscrete = E.discrete, .deltaDiscrete = E.discrete,
.mouse = true,
}); });
}); });

View File

@@ -197,7 +197,7 @@ CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
}); });
}); });
listeners.attach = pad->events.attach.registerListener([](std::any d) { listeners.attach = pad->events.attach.registerListener([this](std::any d) {
; // TODO: this doesn't do anything in aq atm ; // TODO: this doesn't do anything in aq atm
}); });

View File

@@ -3,6 +3,7 @@
#include "IHID.hpp" #include "IHID.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/math/Math.hpp"
AQUAMARINE_FORWARD(ITablet); AQUAMARINE_FORWARD(ITablet);
AQUAMARINE_FORWARD(ITabletTool); AQUAMARINE_FORWARD(ITabletTool);
@@ -26,7 +27,7 @@ class CTablet : public IHID {
virtual eHIDType getType(); virtual eHIDType getType();
SP<Aquamarine::ITablet> aq(); SP<Aquamarine::ITablet> aq();
enum eTabletToolAxes : uint16_t { enum eTabletToolAxes {
HID_TABLET_TOOL_AXIS_X = (1 << 0), HID_TABLET_TOOL_AXIS_X = (1 << 0),
HID_TABLET_TOOL_AXIS_Y = (1 << 1), HID_TABLET_TOOL_AXIS_Y = (1 << 1),
HID_TABLET_TOOL_AXIS_TILT_X = (1 << 2), HID_TABLET_TOOL_AXIS_TILT_X = (1 << 2),
@@ -91,10 +92,10 @@ class CTablet : public IHID {
WP<CTablet> self; WP<CTablet> self;
bool relativeInput = false; bool relativeInput = false;
bool absolutePos = false; std::string hlName = "";
std::string boundOutput = ""; std::string boundOutput = "";
CBox activeArea; CBox activeArea;
CBox boundBox; CBox boundBox; // output-local
private: private:
CTablet(SP<Aquamarine::ITablet> tablet); CTablet(SP<Aquamarine::ITablet> tablet);
@@ -153,6 +154,8 @@ class CTabletPad : public IHID {
WP<CTabletPad> self; WP<CTabletPad> self;
WP<CTabletTool> parent; WP<CTabletTool> parent;
std::string hlName;
private: private:
CTabletPad(SP<Aquamarine::ITabletPad> pad); CTabletPad(SP<Aquamarine::ITabletPad> pad);
@@ -172,7 +175,7 @@ class CTabletTool : public IHID {
static SP<CTabletTool> create(SP<Aquamarine::ITabletTool> tool); static SP<CTabletTool> create(SP<Aquamarine::ITabletTool> tool);
~CTabletTool(); ~CTabletTool();
enum eTabletToolType : uint8_t { enum eTabletToolType {
HID_TABLET_TOOL_TYPE_PEN = 1, HID_TABLET_TOOL_TYPE_PEN = 1,
HID_TABLET_TOOL_TYPE_ERASER, HID_TABLET_TOOL_TYPE_ERASER,
HID_TABLET_TOOL_TYPE_BRUSH, HID_TABLET_TOOL_TYPE_BRUSH,
@@ -183,7 +186,7 @@ class CTabletTool : public IHID {
HID_TABLET_TOOL_TYPE_TOTEM, HID_TABLET_TOOL_TYPE_TOTEM,
}; };
enum eTabletToolCapabilities : uint8_t { enum eTabletToolCapabilities {
HID_TABLET_TOOL_CAPABILITY_TILT = (1 << 0), HID_TABLET_TOOL_CAPABILITY_TILT = (1 << 0),
HID_TABLET_TOOL_CAPABILITY_PRESSURE = (1 << 1), HID_TABLET_TOOL_CAPABILITY_PRESSURE = (1 << 1),
HID_TABLET_TOOL_CAPABILITY_DISTANCE = (1 << 2), HID_TABLET_TOOL_CAPABILITY_DISTANCE = (1 << 2),
@@ -207,6 +210,8 @@ class CTabletTool : public IHID {
std::vector<uint32_t> buttonsDown; std::vector<uint32_t> buttonsDown;
Vector2D absolutePos; // last known absolute position. Vector2D absolutePos; // last known absolute position.
std::string hlName;
private: private:
CTabletTool(SP<Aquamarine::ITabletTool> tool); CTabletTool(SP<Aquamarine::ITabletTool> tool);

View File

@@ -38,7 +38,7 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); }); listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); });
listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); }); listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); });
boundOutput = resource->boundOutput ? resource->boundOutput->szName : ""; boundOutput = resource->boundOutput ? resource->boundOutput->szName : "entire";
deviceName = pointer->name; deviceName = pointer->name;
} }

View File

@@ -1,7 +1,12 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
// NOLINTNEXTLINE(readability-identifier-naming) //
// LISTEN_NAME -> the wl_listener
//
// LISTENER_NAME -> the wl_listener.notify function
//
namespace Events { namespace Events {
// Window events // Window events
DYNLISTENFUNC(commitWindow); DYNLISTENFUNC(commitWindow);
@@ -19,4 +24,12 @@ namespace Events {
DYNLISTENFUNC(requestMaximize); DYNLISTENFUNC(requestMaximize);
DYNLISTENFUNC(setOverrideRedirect); DYNLISTENFUNC(setOverrideRedirect);
DYNLISTENFUNC(ackConfigure); DYNLISTENFUNC(ackConfigure);
// Monitor part 2 the sequel
DYNLISTENFUNC(monitorFrame);
DYNLISTENFUNC(monitorStateRequest);
DYNLISTENFUNC(monitorDamage);
DYNLISTENFUNC(monitorNeedsFrame);
DYNLISTENFUNC(monitorCommit);
DYNLISTENFUNC(monitorBind);
}; };

105
src/events/Monitors.cpp Normal file
View File

@@ -0,0 +1,105 @@
#include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "Events.hpp"
#include "../debug/HyprCtl.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/Screencopy.hpp"
#include "../protocols/ToplevelExport.hpp"
#include <aquamarine/output/Output.hpp>
// --------------------------------------------------------- //
// __ __ ____ _ _ _____ _______ ____ _____ _____ //
// | \/ |/ __ \| \ | |_ _|__ __/ __ \| __ \ / ____| //
// | \ / | | | | \| | | | | | | | | | |__) | (___ //
// | |\/| | | | | . ` | | | | | | | | | _ / \___ \ //
// | | | | |__| | |\ |_| |_ | | | |__| | | \ \ ____) | //
// |_| |_|\____/|_| \_|_____| |_| \____/|_| \_\_____/ //
// //
// --------------------------------------------------------- //
void Events::listener_monitorFrame(void* owner, void* data) {
CMonitor* const PMONITOR = (CMonitor*)owner;
if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!");
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
return m->output != g_pCompositor->m_pUnsafeOutput->output;
})) {
// restore from unsafe state
g_pCompositor->leaveUnsafeState();
}
return; // cannot draw on session inactive (different tty)
}
if (!PMONITOR->m_bEnabled)
return;
g_pHyprRenderer->recheckSolitaryForMonitor(PMONITOR);
PMONITOR->tearingState.busy = false;
if (PMONITOR->tearingState.activelyTearing && PMONITOR->solitaryClient.lock() /* can be invalidated by a recheck */) {
if (!PMONITOR->tearingState.frameScheduledWhileBusy)
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
PMONITOR->tearingState.nextRenderTorn = true;
PMONITOR->tearingState.frameScheduledWhileBusy = false;
}
static auto PENABLERAT = CConfigValue<Hyprlang::INT>("misc:render_ahead_of_time");
static auto PRATSAFE = CConfigValue<Hyprlang::INT>("misc:render_ahead_safezone");
PMONITOR->lastPresentationTimer.reset();
if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
if (!PMONITOR->RATScheduled) {
// render
g_pHyprRenderer->renderMonitor(PMONITOR);
}
PMONITOR->RATScheduled = false;
const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR);
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 TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1)
g_pHyprRenderer->renderMonitor(PMONITOR);
else
wl_event_source_timer_update(PMONITOR->renderTimer, TIMETOSLEEP);
} else {
g_pHyprRenderer->renderMonitor(PMONITOR);
}
}
void Events::listener_monitorNeedsFrame(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME);
}
void Events::listener_monitorCommit(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
PROTO::screencopy->onOutputCommit(PMONITOR);
PROTO::toplevelExport->onOutputCommit(PMONITOR);
}
}
void Events::listener_monitorBind(void* owner, void* data) {
;
}

View File

@@ -12,7 +12,6 @@
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/ToplevelExport.hpp" #include "../protocols/ToplevelExport.hpp"
#include "../xwayland/XSurface.hpp" #include "../xwayland/XSurface.hpp"
#include "managers/PointerManager.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
@@ -44,16 +43,18 @@ void Events::listener_mapWindow(void* owner, void* data) {
static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity"); static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity");
static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity"); static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity");
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength"); static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
static auto PSWALLOWREGEX = CConfigValue<std::string>("misc:swallow_regex");
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen"); static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen");
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking"); static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
auto PMONITOR = g_pCompositor->m_pLastMonitor.lock(); auto PMONITOR = g_pCompositor->m_pLastMonitor.get();
if (!g_pCompositor->m_pLastMonitor) { if (!g_pCompositor->m_pLastMonitor) {
g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({})); g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({}));
PMONITOR = g_pCompositor->m_pLastMonitor.lock(); PMONITOR = g_pCompositor->m_pLastMonitor.get();
} }
auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
PWINDOW->m_pMonitor = PMONITOR; PWINDOW->m_iMonitorID = PMONITOR->ID;
PWINDOW->m_pWorkspace = PWORKSPACE; PWINDOW->m_pWorkspace = PWORKSPACE;
PWINDOW->m_bIsMapped = true; PWINDOW->m_bIsMapped = true;
PWINDOW->m_bReadyToDelete = false; PWINDOW->m_bReadyToDelete = false;
@@ -134,178 +135,149 @@ void Events::listener_mapWindow(void* owner, void* data) {
// window rules // window rules
PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false); PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
std::optional<eFullscreenMode> requestedInternalFSMode, requestedClientFSMode; std::optional<eFullscreenMode> requestedInternalFSMode, requestedClientFSMode;
std::optional<SFullscreenState> requestedFSState; std::optional<sFullscreenState> requestedFSState;
if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen)) if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen))
requestedClientFSMode = FSMODE_FULLSCREEN; requestedClientFSMode = FSMODE_FULLSCREEN;
for (auto const& r : PWINDOW->m_vMatchedRules) { for (auto const& r : PWINDOW->m_vMatchedRules) {
switch (r->ruleType) { if (r.szRule.starts_with("monitor")) {
case CWindowRule::RULE_MONITOR: { try {
try { const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' ')));
const auto MONITORSTR = trim(r->szRule.substr(r->szRule.find(' ')));
if (MONITORSTR == "unset") { if (MONITORSTR == "unset") {
PWINDOW->m_pMonitor = PMONITOR; PWINDOW->m_iMonitorID = PMONITOR->ID;
} else {
if (isNumber(MONITORSTR)) {
const MONITORID MONITOR = std::stoi(MONITORSTR);
if (!g_pCompositor->getMonitorFromID(MONITOR))
PWINDOW->m_iMonitorID = 0;
else
PWINDOW->m_iMonitorID = MONITOR;
} else { } else {
if (isNumber(MONITORSTR)) { const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR);
const MONITORID MONITOR = std::stoi(MONITORSTR); if (PMONITOR)
if (const auto PM = g_pCompositor->getMonitorFromID(MONITOR); PM) PWINDOW->m_iMonitorID = PMONITOR->ID;
PWINDOW->m_pMonitor = PM; else {
else Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
PWINDOW->m_pMonitor = g_pCompositor->m_vMonitors.at(0); continue;
} else {
const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR);
if (PMONITOR)
PWINDOW->m_pMonitor = PMONITOR;
else {
Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
continue;
}
} }
} }
const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock();
if (PWINDOW->m_pMonitor != PMONITOR) {
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID()));
PMONITOR = PMONITORFROMID;
}
PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r->szRule, r->szValue, e.what()); }
break;
}
case CWindowRule::RULE_WORKSPACE: {
// check if it isnt unset
const auto WORKSPACERQ = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
if (WORKSPACERQ == "unset") {
requestedWorkspace = "";
} else {
requestedWorkspace = WORKSPACERQ;
} }
const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ; const auto PMONITORFROMID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (JUSTWORKSPACE == PWORKSPACE->m_szName || JUSTWORKSPACE == "name:" + PWORKSPACE->m_szName) if (PWINDOW->m_iMonitorID != PMONITOR->ID) {
requestedWorkspace = ""; g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
PMONITOR = PMONITORFROMID;
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r->szValue);
break;
}
case CWindowRule::RULE_FLOAT: {
PWINDOW->m_bIsFloating = true;
break;
}
case CWindowRule::RULE_TILE: {
PWINDOW->m_bIsFloating = false;
break;
}
case CWindowRule::RULE_PSEUDO: {
PWINDOW->m_bIsPseudotiled = true;
break;
}
case CWindowRule::RULE_NOINITIALFOCUS: {
PWINDOW->m_bNoInitialFocus = true;
break;
}
case CWindowRule::RULE_FULLSCREENSTATE: {
const auto ARGS = CVarList(r->szRule.substr(r->szRule.find_first_of(' ') + 1), 2, ' ');
int internalMode, clientMode;
try {
internalMode = std::stoi(ARGS[0]);
} catch (std::exception& e) { internalMode = 0; }
try {
clientMode = std::stoi(ARGS[1]);
} catch (std::exception& e) { clientMode = 0; }
requestedFSState = SFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode};
break;
}
case CWindowRule::RULE_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]);
} }
break; PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
} else if (r.szRule.starts_with("workspace")) {
// check if it isnt unset
const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (WORKSPACERQ == "unset") {
requestedWorkspace = "";
} else {
requestedWorkspace = WORKSPACERQ;
} }
case CWindowRule::RULE_PIN: {
PWINDOW->m_bPinned = true; const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ;
break;
if (JUSTWORKSPACE == PWORKSPACE->m_szName || JUSTWORKSPACE == "name:" + PWORKSPACE->m_szName)
requestedWorkspace = "";
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r.szValue);
} else if (r.szRule.starts_with("float")) {
PWINDOW->m_bIsFloating = true;
} else if (r.szRule.starts_with("tile")) {
PWINDOW->m_bIsFloating = false;
} else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.starts_with("fullscreenstate")) {
const auto ARGS = CVarList(r.szRule.substr(r.szRule.find_first_of(' ') + 1), 2, ' ');
int internalMode, clientMode;
try {
internalMode = std::stoi(ARGS[0]);
} catch (std::exception& e) { internalMode = 0; }
try {
clientMode = std::stoi(ARGS[1]);
} catch (std::exception& e) { clientMode = 0; }
requestedFSState = sFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode};
} 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]);
} }
case CWindowRule::RULE_FULLSCREEN: { } else if (r.szRule == "pin") {
requestedInternalFSMode = FSMODE_FULLSCREEN; PWINDOW->m_bPinned = true;
break; } else if (r.szRule == "fullscreen") {
requestedInternalFSMode = FSMODE_FULLSCREEN;
} else if (r.szRule == "maximize") {
requestedInternalFSMode = FSMODE_MAXIMIZED;
} else if (r.szRule == "stayfocused") {
PWINDOW->m_bStayFocused = true;
} else if (r.szRule.starts_with("group")) {
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
continue;
// `group` is a shorthand of `group set`
if (trim(r.szRule) == "group") {
PWINDOW->m_eGroupRules |= GROUP_SET;
continue;
} }
case CWindowRule::RULE_MAXIMIZE: {
requestedInternalFSMode = FSMODE_MAXIMIZED; CVarList vars(r.szRule, 0, 's');
break; std::string vPrev = "";
}
case CWindowRule::RULE_STAYFOCUSED: { for (auto const& v : vars) {
PWINDOW->m_bStayFocused = true; if (v == "group")
break;
}
case CWindowRule::RULE_GROUP: {
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
continue; continue;
// `group` is a shorthand of `group set` if (v == "set") {
if (trim(r->szRule) == "group") {
PWINDOW->m_eGroupRules |= GROUP_SET; PWINDOW->m_eGroupRules |= GROUP_SET;
continue; } else if (v == "new") {
// shorthand for `group barred set`
PWINDOW->m_eGroupRules |= (GROUP_SET | GROUP_BARRED);
} else if (v == "lock") {
PWINDOW->m_eGroupRules |= GROUP_LOCK;
} else if (v == "invade") {
PWINDOW->m_eGroupRules |= GROUP_INVADE;
} else if (v == "barred") {
PWINDOW->m_eGroupRules |= GROUP_BARRED;
} else if (v == "deny") {
PWINDOW->m_sGroupData.deny = true;
} else if (v == "override") {
// Clear existing rules
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
} else if (v == "unset") {
// Clear existing rules and stop processing
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
break;
} else if (v == "always") {
if (vPrev == "set" || vPrev == "group")
PWINDOW->m_eGroupRules |= GROUP_SET_ALWAYS;
else if (vPrev == "lock")
PWINDOW->m_eGroupRules |= GROUP_LOCK_ALWAYS;
else
Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev);
} }
vPrev = v;
CVarList vars(r->szRule, 0, 's');
std::string vPrev = "";
for (auto const& v : vars) {
if (v == "group")
continue;
if (v == "set") {
PWINDOW->m_eGroupRules |= GROUP_SET;
} else if (v == "new") {
// shorthand for `group barred set`
PWINDOW->m_eGroupRules |= (GROUP_SET | GROUP_BARRED);
} else if (v == "lock") {
PWINDOW->m_eGroupRules |= GROUP_LOCK;
} else if (v == "invade") {
PWINDOW->m_eGroupRules |= GROUP_INVADE;
} else if (v == "barred") {
PWINDOW->m_eGroupRules |= GROUP_BARRED;
} else if (v == "deny") {
PWINDOW->m_sGroupData.deny = true;
} else if (v == "override") {
// Clear existing rules
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
} else if (v == "unset") {
// Clear existing rules and stop processing
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
break;
} else if (v == "always") {
if (vPrev == "set" || vPrev == "group")
PWINDOW->m_eGroupRules |= GROUP_SET_ALWAYS;
else if (vPrev == "lock")
PWINDOW->m_eGroupRules |= GROUP_LOCK_ALWAYS;
else
Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev);
}
vPrev = v;
}
break;
} }
default: break;
} }
PWINDOW->applyDynamicRule(r); PWINDOW->applyDynamicRule(r);
} }
@@ -325,23 +297,23 @@ void Events::listener_mapWindow(void* owner, void* data) {
auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID); auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID);
if (!pWorkspace) if (!pWorkspace)
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->monitorID(), requestedWorkspaceName, false); pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName);
PWORKSPACE = pWorkspace; PWORKSPACE = pWorkspace;
PWINDOW->m_pWorkspace = pWorkspace; PWINDOW->m_pWorkspace = pWorkspace;
PWINDOW->m_pMonitor = pWorkspace->m_pMonitor; PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID;
if (PWINDOW->m_pMonitor.lock()->activeSpecialWorkspace && !pWorkspace->m_bIsSpecialWorkspace) if (g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeSpecialWorkspace && !pWorkspace->m_bIsSpecialWorkspace)
workspaceSilent = true; workspaceSilent = true;
if (!workspaceSilent) { if (!workspaceSilent) {
if (pWorkspace->m_bIsSpecialWorkspace) if (pWorkspace->m_bIsSpecialWorkspace)
pWorkspace->m_pMonitor->setSpecialWorkspace(pWorkspace); g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID)->setSpecialWorkspace(pWorkspace);
else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID) else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID)
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName); g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
PMONITOR = g_pCompositor->m_pLastMonitor.lock(); PMONITOR = g_pCompositor->m_pLastMonitor.get();
} }
} else } else
workspaceSilent = false; workspaceSilent = false;
@@ -349,143 +321,124 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->updateWindowData(); PWINDOW->updateWindowData();
// Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped.
const auto SWALLOWER = PWINDOW->getSwallower();
PWINDOW->m_pSwallowed = SWALLOWER;
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
PWINDOW->m_bCreatedOverFullscreen = true; PWINDOW->m_bCreatedOverFullscreen = true;
// size and move rules // size and move rules
for (auto const& r : PWINDOW->m_vMatchedRules) { for (auto const& r : PWINDOW->m_vMatchedRules) {
switch (r->ruleType) { if (r.szRule.starts_with("size")) {
case CWindowRule::RULE_SIZE: { try {
try { const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) { const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
if (VALUE.starts_with('<')) const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
return std::min(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
else if (VALUE.starts_with('>'))
return std::max(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
return stringToPercentage(VALUE, REL); const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW);
};
const auto VALUE = r->szRule.substr(r->szRule.find(' ') + 1); const auto SIZEX = SIZEXSTR == "max" ?
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) :
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); (!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
const auto SIZEY = SIZEYSTR == "max" ?
std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) :
(!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
const auto MAXSIZE = PWINDOW->requestedMaxSize(); Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY);
stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x); PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal();
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : PWINDOW->setHidden(false);
stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y); } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("move")) {
try {
auto value = r.szRule.substr(r.szRule.find(' ') + 1);
Debug::log(LOG, "Rule size, applying to {}", PWINDOW); const bool ONSCREEN = value.starts_with("onscreen");
PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY}); if (ONSCREEN)
value = value.substr(value.find_first_of(' ') + 1);
PWINDOW->setHidden(false); const bool CURSOR = value.starts_with("cursor");
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->szRule, r->szValue); }
break;
}
case CWindowRule::RULE_MOVE: {
try {
auto value = r->szRule.substr(r->szRule.find(' ') + 1);
const bool ONSCREEN = value.starts_with("onscreen"); if (CURSOR)
value = value.substr(value.find_first_of(' ') + 1);
if (ONSCREEN) const auto POSXSTR = value.substr(0, value.find(' '));
value = value.substr(value.find_first_of(' ') + 1); const auto POSYSTR = value.substr(value.find(' ') + 1);
const bool CURSOR = value.starts_with("cursor"); int posX = 0;
int posY = 0;
if (POSXSTR.starts_with("100%-")) {
const bool subtractWindow = POSXSTR.starts_with("100%-w-");
const auto POSXRAW = (subtractWindow) ? POSXSTR.substr(7) : POSXSTR.substr(5);
posX =
PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
if (subtractWindow)
posX -= PWINDOW->m_vRealSize.goal().x;
if (CURSOR) if (CURSOR)
value = value.substr(value.find_first_of(' ') + 1); Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
const auto POSXSTR = value.substr(0, value.find(' ')); posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
const auto POSYSTR = value.substr(value.find(' ') + 1); } else {
// cursor
int posX = 0; if (POSXSTR == "cursor") {
int posY = 0; posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
if (POSXSTR.starts_with("100%-")) {
const bool subtractWindow = POSXSTR.starts_with("100%-w-");
const auto POSXRAW = (subtractWindow) ? POSXSTR.substr(7) : POSXSTR.substr(5);
posX = PMONITOR->vecSize.x -
(!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
if (subtractWindow)
posX -= PWINDOW->m_vRealSize.goal().x;
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
} else { } else {
// cursor posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
if (POSXSTR == "cursor") { (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
} else {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
}
} }
}
if (POSYSTR.starts_with("100%-")) { if (POSYSTR.starts_with("100%-")) {
const bool subtractWindow = POSYSTR.starts_with("100%-w-"); const bool subtractWindow = POSYSTR.starts_with("100%-w-");
const auto POSYRAW = (subtractWindow) ? POSYSTR.substr(7) : POSYSTR.substr(5); const auto POSYRAW = (subtractWindow) ? POSYSTR.substr(7) : POSYSTR.substr(5);
posY = PMONITOR->vecSize.y - posY =
(!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y); PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
if (subtractWindow) if (subtractWindow)
posY -= PWINDOW->m_vRealSize.goal().y; posY -= PWINDOW->m_vRealSize.goal().y;
if (CURSOR) if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!"); Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) { } else if (!CURSOR) {
posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y; posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
} else {
// cursor
if (POSYSTR == "cursor") {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
} else { } else {
// cursor posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
if (POSYSTR == "cursor") { (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
} else {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
}
} }
}
if (ONSCREEN) { if (ONSCREEN) {
int borderSize = PWINDOW->getRealBorderSize(); int borderSize = PWINDOW->getRealBorderSize();
posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize), posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize)); (int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize));
posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize), posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize)); (int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize));
} }
Debug::log(LOG, "Rule move, applying to {}", PWINDOW); Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition; PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
PWINDOW->setHidden(false); PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r->szRule, r->szValue); } } catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r.szRule, r.szValue); }
break; } else if (r.szRule.starts_with("center")) {
} auto RESERVEDOFFSET = Vector2D();
case CWindowRule::RULE_CENTER: { const auto ARGS = CVarList(r.szRule, 2, ' ');
auto RESERVEDOFFSET = Vector2D(); if (ARGS[1] == "1")
const auto ARGS = CVarList(r->szRule, 2, ' '); RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
if (ARGS[1] == "1")
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET; PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET;
break;
}
default: break;
} }
} }
@@ -500,27 +453,29 @@ void Events::listener_mapWindow(void* owner, void* data) {
bool setPseudo = false; bool setPseudo = false;
for (auto const& r : PWINDOW->m_vMatchedRules) { for (auto const& r : PWINDOW->m_vMatchedRules) {
if (r->ruleType != CWindowRule::RULE_SIZE) if (r.szRule.starts_with("size")) {
continue; try {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
try { const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW);
const auto VALUE = r->szRule.substr(r->szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto MAXSIZE = PWINDOW->requestedMaxSize(); const auto SIZEX = SIZEXSTR == "max" ?
std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) :
(!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
const auto SIZEY = SIZEYSTR == "max" ?
std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) :
(!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x); Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW);
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : stringToPercentage(SIZEYSTR, PMONITOR->vecSize.y); setPseudo = true;
PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY);
Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW); PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
setPseudo = true; }
PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY);
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->szRule, r->szValue); }
} }
if (!setPseudo) if (!setPseudo)
@@ -547,7 +502,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
else if (*PNEWTAKESOVERFS == 1) else if (*PNEWTAKESOVERFS == 1)
requestedInternalFSMode = PWINDOW->m_pWorkspace->m_efFullscreenMode; requestedInternalFSMode = PWINDOW->m_pWorkspace->m_efFullscreenMode;
else if (*PNEWTAKESOVERFS == 2) else if (*PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE); g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE);
} }
if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus && if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus &&
@@ -569,7 +524,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!PWINDOW->m_bNoInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) { if (!PWINDOW->m_bNoInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) {
// fix fullscreen on requested (basically do a switcheroo) // fix fullscreen on requested (basically do a switcheroo)
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow)
g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE); g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE);
PWINDOW->m_vRealPosition.warp(); PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealSize.warp(); PWINDOW->m_vRealSize.warp();
@@ -577,7 +532,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE); PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE);
g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value()); g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value());
} else if (requestedInternalFSMode.has_value() && requestedClientFSMode.has_value() && !PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault()) } else if (requestedInternalFSMode.has_value() && requestedClientFSMode.has_value() && !PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
g_pCompositor->setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = requestedInternalFSMode.value(), .client = requestedClientFSMode.value()}); g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = requestedInternalFSMode.value(), .client = requestedClientFSMode.value()});
else if (requestedInternalFSMode.has_value()) else if (requestedInternalFSMode.has_value())
g_pCompositor->setWindowFullscreenInternal(PWINDOW, requestedInternalFSMode.value()); g_pCompositor->setWindowFullscreenInternal(PWINDOW, requestedInternalFSMode.value());
else if (requestedClientFSMode.has_value()) else if (requestedClientFSMode.has_value())
@@ -597,12 +552,20 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(nullptr);
} }
// swallow // verify swallowing
if (SWALLOWER) { if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER); const auto SWALLOWER = PWINDOW->getSwallower();
g_pHyprRenderer->damageWindow(SWALLOWER);
SWALLOWER->setHidden(true); if (SWALLOWER) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID()); // swallow
PWINDOW->m_pSwallowed = SWALLOWER;
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER);
SWALLOWER->setHidden(true);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
}
} }
PWINDOW->m_bFirstMap = false; PWINDOW->m_bFirstMap = false;
@@ -641,8 +604,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// fix some xwayland apps that don't behave nicely // fix some xwayland apps that don't behave nicely
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
if (PWINDOW->m_pWorkspace) g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID());
PWINDOW->m_pWorkspace->updateWindows();
if (PMONITOR && PWINDOW->isX11OverrideRedirect()) if (PMONITOR && PWINDOW->isX11OverrideRedirect())
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
@@ -664,7 +626,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
return; return;
} }
const auto PMONITOR = PWINDOW->m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR) { if (PMONITOR) {
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition; PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value(); PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value();
@@ -685,13 +647,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
// swallowing // swallowing
if (valid(PWINDOW->m_pSwallowed)) { if (valid(PWINDOW->m_pSwallowed)) {
PWINDOW->m_pSwallowed->setHidden(false); PWINDOW->m_pSwallowed->setHidden(false);
if (PWINDOW->m_sGroupData.pNextWindow.lock())
PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false.
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock()); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock());
PWINDOW->m_pSwallowed->m_bGroupSwallowed = false;
PWINDOW->m_pSwallowed.reset(); PWINDOW->m_pSwallowed.reset();
} }
@@ -716,8 +672,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
g_pHyprRenderer->damageWindow(PWINDOW);
// do this after onWindowRemoved because otherwise it'll think the window is invalid // do this after onWindowRemoved because otherwise it'll think the window is invalid
PWINDOW->m_bIsMapped = false; PWINDOW->m_bIsMapped = false;
@@ -738,7 +692,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pCompositor->setWindowFullscreenInternal(PWINDOWCANDIDATE, CURRENTFSMODE); g_pCompositor->setWindowFullscreenInternal(PWINDOWCANDIDATE, CURRENTFSMODE);
} }
if (!PWINDOWCANDIDATE && PWINDOW->m_pWorkspace && PWINDOW->m_pWorkspace->getWindows() == 0) if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0)
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pInputManager->sendMotionEventsToFocused(); g_pInputManager->sendMotionEventsToFocused();
@@ -757,6 +711,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pCompositor->addToFadingOutSafe(PWINDOW); g_pCompositor->addToFadingOutSafe(PWINDOW);
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
@@ -768,8 +724,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
// force report all sizes (QT sometimes has an issue with this) // force report all sizes (QT sometimes has an issue with this)
if (PWINDOW->m_pWorkspace) g_pCompositor->forceReportSizesToWindowsOnWorkspace(PWINDOW->workspaceID());
PWINDOW->m_pWorkspace->forceReportSizesToWindows();
// update lastwindow after focus // update lastwindow after focus
PWINDOW->onUnmap(); PWINDOW->onUnmap();
@@ -793,33 +748,36 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
if (!PWINDOW->m_bIsX11 && !PWINDOW->isFullscreen() && PWINDOW->m_bIsFloating) { if (!PWINDOW->m_bIsX11 && !PWINDOW->isFullscreen() && PWINDOW->m_bIsFloating) {
const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->layoutMinSize(); const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize;
const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->layoutMaxSize(); const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize;
PWINDOW->clampWindowSize(MINSIZE, MAXSIZE > Vector2D{1, 1} ? std::optional<Vector2D>{MAXSIZE} : std::nullopt); if (MAXSIZE > Vector2D{1, 1}) {
g_pHyprRenderer->damageWindow(PWINDOW); const auto REALSIZE = PWINDOW->m_vRealSize.goal();
Vector2D newSize = REALSIZE;
if (MAXSIZE.x < newSize.x)
newSize.x = MAXSIZE.x;
if (MAXSIZE.y < newSize.y)
newSize.y = MAXSIZE.y;
if (MINSIZE.x > newSize.x)
newSize.x = MINSIZE.x;
if (MINSIZE.y > newSize.y)
newSize.y = MINSIZE.y;
const Vector2D DELTA = REALSIZE - newSize;
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0;
PWINDOW->m_vRealSize = newSize;
g_pXWaylandManager->setWindowSize(PWINDOW, newSize);
g_pHyprRenderer->damageWindow(PWINDOW);
}
} }
if (!PWINDOW->m_pWorkspace->m_bVisible) if (!PWINDOW->m_pWorkspace->m_bVisible)
return; return;
const auto PMONITOR = PWINDOW->m_pMonitor.lock(); g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
if (PMONITOR)
PMONITOR->debugLastPresentation(g_pSeatManager->isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow");
if (g_pSeatManager->isPointerFrameCommit) {
g_pSeatManager->isPointerFrameSkipped = false;
g_pSeatManager->isPointerFrameCommit = false;
} else
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
if (g_pSeatManager->isPointerFrameSkipped) {
g_pPointerManager->sendStoredMovement();
g_pSeatManager->sendPointerFrame();
g_pSeatManager->isPointerFrameCommit = true;
}
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces(); PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
@@ -827,6 +785,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
} }
// tearing: if solitary, redraw it. This still might be a single surface window // tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) { if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()}; CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
@@ -941,7 +900,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size()); PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size());
if (*PXWLFORCESCALEZERO) { if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = PWINDOW->m_pMonitor.lock(); PMONITOR) { if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale); PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
} }
} }

View File

@@ -2,11 +2,11 @@
#include "../managers/AnimationManager.hpp" #include "../managers/AnimationManager.hpp"
#include "../config/ConfigManager.hpp" #include "../config/ConfigManager.hpp"
CBaseAnimatedVariable::CBaseAnimatedVariable(eAnimatedVarType type) : m_Type(type) { CBaseAnimatedVariable::CBaseAnimatedVariable(ANIMATEDVARTYPE type) : m_Type(type) {
; // dummy var ; // dummy var
} }
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) { void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy; m_eDamagePolicy = policy;
m_pConfig = pAnimConfig; m_pConfig = pAnimConfig;
m_pWindow = pWindow; m_pWindow = pWindow;
@@ -14,7 +14,7 @@ void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWIN
m_bDummy = false; m_bDummy = false;
} }
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) { void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy; m_eDamagePolicy = policy;
m_pConfig = pAnimConfig; m_pConfig = pAnimConfig;
m_pLayer = pLayer; m_pLayer = pLayer;
@@ -22,7 +22,7 @@ void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS
m_bDummy = false; m_bDummy = false;
} }
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) { void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy; m_eDamagePolicy = policy;
m_pConfig = pAnimConfig; m_pConfig = pAnimConfig;
m_pWorkspace = pWorkspace; m_pWorkspace = pWorkspace;
@@ -30,7 +30,7 @@ void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWOR
m_bDummy = false; m_bDummy = false;
} }
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) { void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy; m_eDamagePolicy = policy;
m_pConfig = pAnimConfig; m_pConfig = pAnimConfig;

View File

@@ -10,39 +10,38 @@
#include "../debug/Log.hpp" #include "../debug/Log.hpp"
#include "../desktop/DesktopTypes.hpp" #include "../desktop/DesktopTypes.hpp"
enum eAnimatedVarType : int8_t { enum ANIMATEDVARTYPE {
AVARTYPE_INVALID = -1, AVARTYPE_INVALID = -1,
AVARTYPE_FLOAT, AVARTYPE_FLOAT,
AVARTYPE_VECTOR, AVARTYPE_VECTOR,
AVARTYPE_COLOR AVARTYPE_COLOR
}; };
// Utility to bind a type with its corresponding eAnimatedVarType // Utility to bind a type with its corresponding ANIMATEDVARTYPE
template <class T> template <class T>
// NOLINTNEXTLINE(readability-identifier-naming) struct typeToANIMATEDVARTYPE_t {
struct STypeToAnimatedVarType_t { static constexpr ANIMATEDVARTYPE value = AVARTYPE_INVALID;
static constexpr eAnimatedVarType value = AVARTYPE_INVALID;
}; };
template <> template <>
struct STypeToAnimatedVarType_t<float> { struct typeToANIMATEDVARTYPE_t<float> {
static constexpr eAnimatedVarType value = AVARTYPE_FLOAT; static constexpr ANIMATEDVARTYPE value = AVARTYPE_FLOAT;
}; };
template <> template <>
struct STypeToAnimatedVarType_t<Vector2D> { struct typeToANIMATEDVARTYPE_t<Vector2D> {
static constexpr eAnimatedVarType value = AVARTYPE_VECTOR; static constexpr ANIMATEDVARTYPE value = AVARTYPE_VECTOR;
}; };
template <> template <>
struct STypeToAnimatedVarType_t<CHyprColor> { struct typeToANIMATEDVARTYPE_t<CColor> {
static constexpr eAnimatedVarType value = AVARTYPE_COLOR; static constexpr ANIMATEDVARTYPE value = AVARTYPE_COLOR;
}; };
template <class T> template <class T>
inline constexpr eAnimatedVarType typeToeAnimatedVarType = STypeToAnimatedVarType_t<T>::value; inline constexpr ANIMATEDVARTYPE typeToANIMATEDVARTYPE = typeToANIMATEDVARTYPE_t<T>::value;
enum eAVarDamagePolicy : int8_t { enum AVARDAMAGEPOLICY {
AVARDAMAGE_NONE = -1, AVARDAMAGE_NONE = -1,
AVARDAMAGE_ENTIRE = 0, AVARDAMAGE_ENTIRE = 0,
AVARDAMAGE_BORDER, AVARDAMAGE_BORDER,
@@ -64,15 +63,15 @@ concept OneOf = (... or std::same_as<T, U>);
// This is mainly to get better errors if we put a type that's not supported // This is mainly to get better errors if we put a type that's not supported
// Otherwise template errors are ugly // Otherwise template errors are ugly
template <class T> template <class T>
concept Animable = OneOf<T, Vector2D, float, CHyprColor>; concept Animable = OneOf<T, Vector2D, float, CColor>;
class CBaseAnimatedVariable { class CBaseAnimatedVariable {
public: public:
CBaseAnimatedVariable(eAnimatedVarType type); CBaseAnimatedVariable(ANIMATEDVARTYPE type);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy); void create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy); void create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy); void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy); void create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy);
CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete; CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete; CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
@@ -104,7 +103,7 @@ class CBaseAnimatedVariable {
float getCurveValue(); float getCurveValue();
// checks if an animation is in progress // checks if an animation is in progress
bool isBeingAnimated() const { inline bool isBeingAnimated() {
return m_bIsBeingAnimated; return m_bIsBeingAnimated;
} }
@@ -112,7 +111,7 @@ class CBaseAnimatedVariable {
if an animation is not running, runs instantly. if an animation is not running, runs instantly.
if "remove" is set to true, will remove the callback when ran. */ if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnEnd(std::function<void(void* thisptr)> func, bool remove = true) { void setCallbackOnEnd(std::function<void(void* thisptr)> func, bool remove = true) {
m_fEndCallback = std::move(func); m_fEndCallback = func;
m_bRemoveEndAfterRan = remove; m_bRemoveEndAfterRan = remove;
if (!isBeingAnimated()) if (!isBeingAnimated())
@@ -122,14 +121,14 @@ class CBaseAnimatedVariable {
/* sets a function to be ran when an animation is started. /* sets a function to be ran when an animation is started.
if "remove" is set to true, will remove the callback when ran. */ if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnBegin(std::function<void(void* thisptr)> func, bool remove = true) { void setCallbackOnBegin(std::function<void(void* thisptr)> func, bool remove = true) {
m_fBeginCallback = std::move(func); m_fBeginCallback = func;
m_bRemoveBeginAfterRan = remove; m_bRemoveBeginAfterRan = remove;
} }
/* Sets the update callback, called every time the value is animated and a step is done /* Sets the update callback, called every time the value is animated and a step is done
Warning: calling unregisterVar/registerVar in this handler will cause UB */ Warning: calling unregisterVar/registerVar in this handler will cause UB */
void setUpdateCallback(std::function<void(void* thisptr)> func) { void setUpdateCallback(std::function<void(void* thisptr)> func) {
m_fUpdateCallback = std::move(func); m_fUpdateCallback = func;
} }
/* resets all callbacks. Does not call any. */ /* resets all callbacks. Does not call any. */
@@ -158,8 +157,8 @@ class CBaseAnimatedVariable {
std::chrono::steady_clock::time_point animationBegin; std::chrono::steady_clock::time_point animationBegin;
eAVarDamagePolicy m_eDamagePolicy = AVARDAMAGE_NONE; AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE;
eAnimatedVarType m_Type; ANIMATEDVARTYPE m_Type;
bool m_bRemoveEndAfterRan = true; bool m_bRemoveEndAfterRan = true;
bool m_bRemoveBeginAfterRan = true; bool m_bRemoveBeginAfterRan = true;
@@ -207,26 +206,24 @@ class CBaseAnimatedVariable {
template <Animable VarType> template <Animable VarType>
class CAnimatedVariable : public CBaseAnimatedVariable { class CAnimatedVariable : public CBaseAnimatedVariable {
public: public:
CAnimatedVariable() : CBaseAnimatedVariable(typeToeAnimatedVarType<VarType>) { CAnimatedVariable() : CBaseAnimatedVariable(typeToANIMATEDVARTYPE<VarType>) {} // dummy var
;
} // dummy var
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) { void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pWindow, policy); create(pAnimConfig, pWindow, policy);
m_Value = value; m_Value = value;
m_Goal = value; m_Goal = value;
} }
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) { void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pLayer, policy); create(pAnimConfig, pLayer, policy);
m_Value = value; m_Value = value;
m_Goal = value; m_Goal = value;
} }
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) { void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pWorkspace, policy); create(pAnimConfig, pWorkspace, policy);
m_Value = value; m_Value = value;
m_Goal = value; m_Goal = value;
} }
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) { void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, policy); create(pAnimConfig, policy);
m_Value = value; m_Value = value;
m_Goal = value; m_Goal = value;

View File

@@ -6,27 +6,24 @@
#include <algorithm> #include <algorithm>
void CBezierCurve::setup(std::vector<Vector2D>* pVec) { void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
m_dPoints.clear();
const auto BEGIN = std::chrono::high_resolution_clock::now(); const auto BEGIN = std::chrono::high_resolution_clock::now();
// Avoid reallocations by reserving enough memory upfront m_dPoints.emplace_back(Vector2D(0, 0));
m_vPoints.resize(pVec->size() + 2);
m_vPoints[0] = Vector2D(0, 0); // Start point
size_t index = 1; // Start after the first element
for (const auto& vec : *pVec) {
if (index < m_vPoints.size() - 1) { // Bounds check to ensure safety
m_vPoints[index] = vec;
++index;
}
}
m_vPoints.back() = Vector2D(1, 1); // End point
RASSERT(m_vPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_vPoints.size()); for (auto const& p : *pVec) {
m_dPoints.push_back(p);
}
m_dPoints.emplace_back(Vector2D(1, 1));
RASSERT(m_dPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_dPoints.size());
// bake BAKEDPOINTS points for faster lookups // bake BAKEDPOINTS points for faster lookups
// T -> X ( / BAKEDPOINTS ) // T -> X ( / BAKEDPOINTS )
for (int i = 0; i < BAKEDPOINTS; ++i) { for (int i = 0; i < BAKEDPOINTS; ++i) {
float const t = (i + 1) / (float)BAKEDPOINTS; m_aPointsBaked[i] = Vector2D(getXForT((i + 1) / (float)BAKEDPOINTS), getYForT((i + 1) / (float)BAKEDPOINTS));
m_aPointsBaked[i] = Vector2D(getXForT(t), getYForT(t));
} }
const auto ELAPSEDUS = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGIN).count() / 1000.f; const auto ELAPSEDUS = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGIN).count() / 1000.f;
@@ -43,26 +40,18 @@ void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
ELAPSEDUS, ELAPSEDCALCAVG); ELAPSEDUS, ELAPSEDCALCAVG);
} }
float CBezierCurve::getXForT(float const& t) const { float CBezierCurve::getYForT(float t) {
float t2 = t * t; return 3 * t * pow(1 - t, 2) * m_dPoints[1].y + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].y + pow(t, 3);
float t3 = t2 * t;
return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].x + 3 * t2 * (1 - t) * m_vPoints[2].x + t3 * m_vPoints[3].x;
} }
float CBezierCurve::getYForT(float const& t) const { float CBezierCurve::getXForT(float t) {
float t2 = t * t; return 3 * t * pow(1 - t, 2) * m_dPoints[1].x + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].x + pow(t, 3);
float t3 = t2 * t;
return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].y + 3 * t2 * (1 - t) * m_vPoints[2].y + t3 * m_vPoints[3].y;
} }
// Todo: this probably can be done better and faster // Todo: this probably can be done better and faster
float CBezierCurve::getYForPoint(float const& x) const { float CBezierCurve::getYForPoint(float x) {
if (x >= 1.f) if (x >= 1.f)
return 1.f; return 1.f;
if (x <= 0.f)
return 0.f;
int index = 0; int index = 0;
bool below = true; bool below = true;

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include <vector> #include <deque>
#include <array> #include <array>
#include <vector> #include <vector>
#include "math/Math.hpp" #include "math/Math.hpp"
@@ -16,13 +16,13 @@ class CBezierCurve {
// this EXCLUDES the 0,0 and 1,1 points, // this EXCLUDES the 0,0 and 1,1 points,
void setup(std::vector<Vector2D>* points); void setup(std::vector<Vector2D>* points);
float getYForT(float const& t) const; float getYForT(float t);
float getXForT(float const& t) const; float getXForT(float t);
float getYForPoint(float const& x) const; float getYForPoint(float x);
private: private:
// this INCLUDES the 0,0 and 1,1 points. // this INCLUDES the 0,0 and 1,1 points.
std::vector<Vector2D> m_vPoints; std::deque<Vector2D> m_dPoints;
std::array<Vector2D, BAKEDPOINTS> m_aPointsBaked; std::array<Vector2D, BAKEDPOINTS> m_aPointsBaked;
}; };

View File

@@ -30,27 +30,25 @@ constexpr LD operator""_TB(const LD BYTES) {
return BYTES * 1024 * 1024 * 1024 * 1024; return BYTES * 1024 * 1024 * 1024 * 1024;
} }
//NOLINTBEGIN
template <typename T> template <typename T>
using internal_hl_acceptable_byte_operation_type = typename std::enable_if<std::is_trivially_constructible<T, ULL>::value || std::is_trivially_constructible<T, LD>::value>::type; using __acceptable_byte_operation_type = typename std::enable_if<std::is_trivially_constructible<T, ULL>::value || std::is_trivially_constructible<T, LD>::value>::type;
template <typename X, typename = internal_hl_acceptable_byte_operation_type<X>> template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X kBtoBytes(const X kB) { constexpr X kBtoBytes(const X kB) {
return kB * 1024; return kB * 1024;
} }
template <typename X, typename = internal_hl_acceptable_byte_operation_type<X>> template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X MBtoBytes(const X MB) { constexpr X MBtoBytes(const X MB) {
return MB * 1024 * 1024; return MB * 1024 * 1024;
} }
template <typename X, typename = internal_hl_acceptable_byte_operation_type<X>> template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X GBtoBytes(const X GB) { constexpr X GBtoBytes(const X GB) {
return GB * 1024 * 1024 * 1024; return GB * 1024 * 1024 * 1024;
} }
template <typename X, typename = internal_hl_acceptable_byte_operation_type<X>> template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X TBtoBytes(const X TB) { constexpr X TBtoBytes(const X TB) {
return TB * 1024 * 1024 * 1024 * 1024; return TB * 1024 * 1024 * 1024 * 1024;
} }
//NOLINTEND
#undef ULL #undef ULL
#undef LD #undef LD

View File

@@ -5,41 +5,22 @@
#define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0) #define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0)
#define BLUE(c) ((double)(((c)) & 0xff) / 255.0) #define BLUE(c) ((double)(((c)) & 0xff) / 255.0)
CHyprColor::CHyprColor() = default; CColor::CColor() {}
CHyprColor::CHyprColor(float r_, float g_, float b_, float a_) : r(r_), g(g_), b(b_), a(a_) { CColor::CColor(float r, float g, float b, float a) {
okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab(); this->r = r;
this->g = g;
this->b = b;
this->a = a;
} }
CHyprColor::CHyprColor(uint64_t hex) : r(RED(hex)), g(GREEN(hex)), b(BLUE(hex)), a(ALPHA(hex)) { CColor::CColor(uint64_t hex) {
okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab(); this->r = RED(hex);
this->g = GREEN(hex);
this->b = BLUE(hex);
this->a = ALPHA(hex);
} }
CHyprColor::CHyprColor(const Hyprgraphics::CColor& color, float a_) : a(a_) { uint32_t CColor::getAsHex() const {
const auto SRGB = color.asRgb();
r = SRGB.r;
g = SRGB.g;
b = SRGB.b;
okLab = color.asOkLab();
}
uint32_t CHyprColor::getAsHex() const {
return (uint32_t)(a * 255.f) * 0x1000000 + (uint32_t)(r * 255.f) * 0x10000 + (uint32_t)(g * 255.f) * 0x100 + (uint32_t)(b * 255.f) * 0x1; return (uint32_t)(a * 255.f) * 0x1000000 + (uint32_t)(r * 255.f) * 0x10000 + (uint32_t)(g * 255.f) * 0x100 + (uint32_t)(b * 255.f) * 0x1;
} }
Hyprgraphics::CColor::SSRGB CHyprColor::asRGB() const {
return {r, g, b};
}
Hyprgraphics::CColor::SOkLab CHyprColor::asOkLab() const {
return okLab;
}
Hyprgraphics::CColor::SHSL CHyprColor::asHSL() const {
return Hyprgraphics::CColor(okLab).asHSL();
}
CHyprColor CHyprColor::stripA() const {
return {r, g, b, 1.F};
}

View File

@@ -1,47 +1,35 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <hyprgraphics/color/Color.hpp>
#include "../debug/Log.hpp"
#include "../macros.hpp"
class CHyprColor { class CColor {
public: public:
CHyprColor(); CColor();
CHyprColor(float r, float g, float b, float a); CColor(float r, float g, float b, float a);
CHyprColor(const Hyprgraphics::CColor& col, float a); CColor(uint64_t);
CHyprColor(uint64_t);
float r = 0, g = 0, b = 0, a = 1.f;
// AR32 // AR32
uint32_t getAsHex() const; uint32_t getAsHex() const;
Hyprgraphics::CColor::SSRGB asRGB() const;
Hyprgraphics::CColor::SOkLab asOkLab() const;
Hyprgraphics::CColor::SHSL asHSL() const;
CHyprColor stripA() const;
// CColor operator-(const CColor& c2) const {
bool operator==(const CHyprColor& c2) const { return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a);
return c2.r == r && c2.g == g && c2.b == b && c2.a == a;
} }
// stubs for the AnimationMgr CColor operator+(const CColor& c2) const {
CHyprColor operator-(const CHyprColor& c2) const { return CColor(r + c2.r, g + c2.g, b + c2.b, a + c2.a);
RASSERT(false, "CHyprColor: - is a STUB");
return {};
} }
CHyprColor operator+(const CHyprColor& c2) const { CColor operator*(const float& v) const {
RASSERT(false, "CHyprColor: + is a STUB"); return CColor(r * v, g * v, b * v, a * v);
return {};
} }
CHyprColor operator*(const float& c2) const { bool operator==(const CColor& c2) const {
RASSERT(false, "CHyprColor: * is a STUB"); return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
return {};
} }
double r = 0, g = 0, b = 0, a = 0; CColor stripA() const {
return {r, g, b, 1};
private: }
Hyprgraphics::CColor::SOkLab okLab; // cache for the OkLab representation
}; };

View File

@@ -231,7 +231,7 @@ inline const std::vector<SPixelFormat> GLES3_FORMATS = {
}, },
}; };
SHMFormat NFormatUtils::drmToShm(DRMFormat drm) { SHMFormat FormatUtils::drmToShm(DRMFormat drm) {
switch (drm) { switch (drm) {
case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888; case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888;
case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888; case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888;
@@ -241,7 +241,7 @@ SHMFormat NFormatUtils::drmToShm(DRMFormat drm) {
return drm; return drm;
} }
DRMFormat NFormatUtils::shmToDRM(SHMFormat shm) { DRMFormat FormatUtils::shmToDRM(SHMFormat shm) {
switch (shm) { switch (shm) {
case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888; case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888;
case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888; case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888;
@@ -251,7 +251,7 @@ DRMFormat NFormatUtils::shmToDRM(SHMFormat shm) {
return shm; return shm;
} }
const SPixelFormat* NFormatUtils::getPixelFormatFromDRM(DRMFormat drm) { const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) {
for (auto const& fmt : GLES3_FORMATS) { for (auto const& fmt : GLES3_FORMATS) {
if (fmt.drmFormat == drm) if (fmt.drmFormat == drm)
return &fmt; return &fmt;
@@ -260,7 +260,7 @@ const SPixelFormat* NFormatUtils::getPixelFormatFromDRM(DRMFormat drm) {
return nullptr; return nullptr;
} }
const SPixelFormat* NFormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha) { const SPixelFormat* FormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha) {
for (auto const& fmt : GLES3_FORMATS) { for (auto const& fmt : GLES3_FORMATS) {
if (fmt.glFormat == (int)glFormat && fmt.glType == (int)glType && fmt.withAlpha == alpha) if (fmt.glFormat == (int)glFormat && fmt.glType == (int)glType && fmt.withAlpha == alpha)
return &fmt; return &fmt;
@@ -269,23 +269,23 @@ const SPixelFormat* NFormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32
return nullptr; return nullptr;
} }
bool NFormatUtils::isFormatOpaque(DRMFormat drm) { bool FormatUtils::isFormatOpaque(DRMFormat drm) {
const auto FMT = NFormatUtils::getPixelFormatFromDRM(drm); const auto FMT = FormatUtils::getPixelFormatFromDRM(drm);
if (!FMT) if (!FMT)
return false; return false;
return !FMT->withAlpha; return !FMT->withAlpha;
} }
int NFormatUtils::pixelsPerBlock(const SPixelFormat* const fmt) { int FormatUtils::pixelsPerBlock(const SPixelFormat* const fmt) {
return fmt->blockSize.x * fmt->blockSize.y > 0 ? fmt->blockSize.x * fmt->blockSize.y : 1; return fmt->blockSize.x * fmt->blockSize.y > 0 ? fmt->blockSize.x * fmt->blockSize.y : 1;
} }
int NFormatUtils::minStride(const SPixelFormat* const fmt, int32_t width) { int FormatUtils::minStride(const SPixelFormat* const fmt, int32_t width) {
return std::ceil((width * fmt->bytesPerBlock) / pixelsPerBlock(fmt)); return std::ceil((width * fmt->bytesPerBlock) / pixelsPerBlock(fmt));
} }
uint32_t NFormatUtils::drmFormatToGL(DRMFormat drm) { uint32_t FormatUtils::drmFormatToGL(DRMFormat drm) {
switch (drm) { switch (drm) {
case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case. case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
@@ -302,7 +302,7 @@ uint32_t NFormatUtils::drmFormatToGL(DRMFormat drm) {
return GL_RGBA; return GL_RGBA;
} }
uint32_t NFormatUtils::glFormatToType(uint32_t gl) { uint32_t FormatUtils::glFormatToType(uint32_t gl) {
return gl != GL_RGBA ? return gl != GL_RGBA ?
#ifdef GLES2 #ifdef GLES2
GL_UNSIGNED_INT_2_10_10_10_REV_EXT : GL_UNSIGNED_INT_2_10_10_10_REV_EXT :
@@ -312,14 +312,14 @@ uint32_t NFormatUtils::glFormatToType(uint32_t gl) {
GL_UNSIGNED_BYTE; GL_UNSIGNED_BYTE;
} }
std::string NFormatUtils::drmFormatName(DRMFormat drm) { std::string FormatUtils::drmFormatName(DRMFormat drm) {
auto n = drmGetFormatName(drm); auto n = drmGetFormatName(drm);
std::string name = n; std::string name = n;
free(n); free(n);
return name; return name;
} }
std::string NFormatUtils::drmModifierName(uint64_t mod) { std::string FormatUtils::drmModifierName(uint64_t mod) {
auto n = drmGetFormatModifierName(mod); auto n = drmGetFormatModifierName(mod);
std::string name = n; std::string name = n;
free(n); free(n);

View File

@@ -22,7 +22,7 @@ struct SPixelFormat {
typedef Aquamarine::SDRMFormat SDRMFormat; typedef Aquamarine::SDRMFormat SDRMFormat;
namespace NFormatUtils { namespace FormatUtils {
SHMFormat drmToShm(DRMFormat drm); SHMFormat drmToShm(DRMFormat drm);
DRMFormat shmToDRM(SHMFormat shm); DRMFormat shmToDRM(SHMFormat shm);

View File

@@ -6,7 +6,6 @@
#include <optional> #include <optional>
#include <cstring> #include <cstring>
#include <cmath> #include <cmath>
#include <filesystem>
#include <set> #include <set>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/mman.h> #include <sys/mman.h>
@@ -18,9 +17,7 @@
#include <execinfo.h> #include <execinfo.h>
#endif #endif
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <hyprutils/os/Process.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::OS;
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sysctl.h> #include <sys/sysctl.h>
@@ -264,7 +261,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
WORKSPACEID id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; WORKSPACEID id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0;
while (++id < LONG_MAX) { while (++id < LONG_MAX) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!invalidWSes.contains(id) && (!PWORKSPACE || PWORKSPACE->getWindows() == 0)) { if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) {
result.id = id; result.id = id;
return result; return result;
} }
@@ -305,7 +302,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
// Collect all the workspaces we can't jump to. // Collect all the workspaces we can't jump to.
for (auto const& ws : g_pCompositor->m_vWorkspaces) { for (auto const& ws : g_pCompositor->m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor)) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)) {
// Can't jump to this workspace // Can't jump to this workspace
invalidWSes.insert(ws->m_iID); invalidWSes.insert(ws->m_iID);
} }
@@ -323,7 +320,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
// Prepare all named workspaces in case when we need them // Prepare all named workspaces in case when we need them
std::vector<WORKSPACEID> namedWSes; std::vector<WORKSPACEID> namedWSes;
for (auto const& ws : g_pCompositor->m_vWorkspaces) { for (auto const& ws : g_pCompositor->m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor) || ws->m_iID >= 0) if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0)
continue; continue;
namedWSes.push_back(ws->m_iID); namedWSes.push_back(ws->m_iID);
@@ -467,7 +464,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
std::vector<WORKSPACEID> validWSes; std::vector<WORKSPACEID> validWSes;
for (auto const& ws : g_pCompositor->m_vWorkspaces) { for (auto const& ws : g_pCompositor->m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor && !onAllMonitors)) if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors))
continue; continue;
validWSes.push_back(ws->m_iID); validWSes.push_back(ws->m_iID);
@@ -586,12 +583,18 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve
// Execute a shell command and get the output // Execute a shell command and get the output
std::string execAndGet(const char* cmd) { std::string execAndGet(const char* cmd) {
CProcess proc("/bin/sh", {"-c", cmd}); std::array<char, 128> buffer;
std::string result;
if (!proc.runSync()) using PcloseType = int (*)(FILE*);
return "error"; const std::unique_ptr<FILE, PcloseType> pipe(popen(cmd, "r"), static_cast<PcloseType>(pclose));
if (!pipe) {
return proc.stdOut(); Debug::log(ERR, "execAndGet: failed in pipe");
return "";
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
} }
void logSystemInfo() { void logSystemInfo() {
@@ -607,26 +610,9 @@ void logSystemInfo() {
Debug::log(NONE, "\n"); Debug::log(NONE, "\n");
#if defined(__DragonFly__) || defined(__FreeBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga"); const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
#elif defined(__arm__) || defined(__aarch64__) #elif defined(__arm__) || defined(__aarch64__)
std::string GPUINFO; const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible");
const std::filesystem::path dev_tree = "/proc/device-tree";
try {
if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) {
std::for_each(std::filesystem::directory_iterator(dev_tree), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& entry) {
if (std::filesystem::is_directory(entry) && entry.path().filename().string().starts_with("soc")) {
std::for_each(std::filesystem::directory_iterator(entry.path()), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& sub_entry) {
if (std::filesystem::is_directory(sub_entry) && sub_entry.path().filename().string().starts_with("gpu")) {
std::filesystem::path file_path = sub_entry.path() / "compatible";
std::ifstream file(file_path);
if (file)
GPUINFO.append(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
}
});
}
});
}
} catch (...) { GPUINFO = "error"; }
#else #else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif #endif
@@ -691,91 +677,44 @@ int64_t getPPIDof(int64_t pid) {
#endif #endif
} }
std::expected<int64_t, std::string> configStringToInt(const std::string& VALUE) { int64_t configStringToInt(const std::string& VALUE) {
auto parseHex = [](const std::string& value) -> std::expected<int64_t, std::string> {
try {
size_t position;
auto result = stoll(value, &position, 16);
if (position == value.size())
return result;
} catch (const std::exception&) {}
return std::unexpected("invalid hex " + value);
};
if (VALUE.starts_with("0x")) { if (VALUE.starts_with("0x")) {
// Values with 0x are hex // Values with 0x are hex
return parseHex(VALUE); const auto VALUEWITHOUTHEX = VALUE.substr(2);
return stol(VALUEWITHOUTHEX, nullptr, 16);
} else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) { } else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) {
const auto VALUEWITHOUTFUNC = trim(VALUE.substr(5, VALUE.length() - 6)); const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
// try doing it the comma way first if (trim(VALUEWITHOUTFUNC).length() != 8) {
if (std::count(VALUEWITHOUTFUNC.begin(), VALUEWITHOUTFUNC.end(), ',') == 3) { Debug::log(WARN, "invalid length {} for rgba", VALUEWITHOUTFUNC.length());
// cool throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)");
std::string rolling = VALUEWITHOUTFUNC;
auto r = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
auto g = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
auto b = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
uint8_t a = 0;
if (!r || !g || !b)
return std::unexpected("failed parsing " + VALUEWITHOUTFUNC);
try {
a = std::round(std::stof(trim(rolling.substr(0, rolling.find(',')))) * 255.f);
} catch (std::exception& e) { return std::unexpected("failed parsing " + VALUEWITHOUTFUNC); }
return a * (Hyprlang::INT)0x1000000 + *r * (Hyprlang::INT)0x10000 + *g * (Hyprlang::INT)0x100 + *b;
} else if (VALUEWITHOUTFUNC.length() == 8) {
const auto RGBA = parseHex(VALUEWITHOUTFUNC);
if (!RGBA)
return RGBA;
// now we need to RGBA -> ARGB. The config holds ARGB only.
return (*RGBA >> 8) + 0x1000000 * (*RGBA & 0xFF);
} }
return std::unexpected("rgba() expects length of 8 characters (4 bytes) or 4 comma separated values"); const auto RGBA = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
// now we need to RGBA -> ARGB. The config holds ARGB only.
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
} else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) { } else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) {
const auto VALUEWITHOUTFUNC = trim(VALUE.substr(4, VALUE.length() - 5)); const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
// try doing it the comma way first if (trim(VALUEWITHOUTFUNC).length() != 6) {
if (std::count(VALUEWITHOUTFUNC.begin(), VALUEWITHOUTFUNC.end(), ',') == 2) { Debug::log(WARN, "invalid length {} for rgb", VALUEWITHOUTFUNC.length());
// cool throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)");
std::string rolling = VALUEWITHOUTFUNC;
auto r = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
auto g = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
auto b = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
if (!r || !g || !b)
return std::unexpected("failed parsing " + VALUEWITHOUTFUNC);
return (Hyprlang::INT)0xFF000000 + *r * (Hyprlang::INT)0x10000 + *g * (Hyprlang::INT)0x100 + *b;
} else if (VALUEWITHOUTFUNC.length() == 6) {
auto r = parseHex(VALUEWITHOUTFUNC);
return r ? *r + 0xFF000000 : r;
} }
return std::unexpected("rgb() expects length of 6 characters (3 bytes) or 3 comma separated values"); const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
return RGB + 0xFF000000; // 0xFF for opaque
} else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) { } else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) {
return 1; return 1;
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) { } else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
return 0; return 0;
} }
if (VALUE.empty() || !isNumber(VALUE, false)) if (VALUE.empty() || !isNumber(VALUE))
return std::unexpected("cannot parse \"" + VALUE + "\" as an int."); return 0;
try { return std::stoll(VALUE);
const auto RES = std::stoll(VALUE);
return RES;
} catch (std::exception& e) { return std::unexpected(std::string{"stoll threw: "} + e.what()); }
return std::unexpected("parse error");
} }
Vector2D configStringToVector2D(const std::string& VALUE) { Vector2D configStringToVector2D(const std::string& VALUE) {
@@ -924,37 +863,3 @@ bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) {
*ro_fd_ptr = ro_fd; *ro_fd_ptr = ro_fd;
return true; return true;
} }
float stringToPercentage(const std::string& VALUE, const float REL) {
if (VALUE.ends_with('%'))
return (std::stof(VALUE.substr(0, VALUE.length() - 1)) * REL) / 100.f;
else
return std::stof(VALUE);
}
bool executableExistsInPath(const std::string& exe) {
if (!getenv("PATH"))
return false;
static CVarList paths(getenv("PATH"), 0, ':', true);
for (auto& p : paths) {
std::string path = p + std::string{"/"} + exe;
std::error_code ec;
if (!std::filesystem::exists(path, ec) || ec)
continue;
if (!std::filesystem::is_regular_file(path, ec) || ec)
continue;
auto stat = std::filesystem::status(path, ec);
if (ec)
continue;
auto perms = stat.permissions();
return std::filesystem::perms::none != (perms & std::filesystem::perms::others_exec);
}
return false;
}

View File

@@ -6,7 +6,6 @@
#include "math/Math.hpp" #include "math/Math.hpp"
#include <vector> #include <vector>
#include <format> #include <format>
#include <expected>
#include "../SharedDefs.hpp" #include "../SharedDefs.hpp"
#include "../macros.hpp" #include "../macros.hpp"
@@ -20,29 +19,27 @@ struct SWorkspaceIDName {
std::string name; std::string name;
}; };
std::string absolutePath(const std::string&, const std::string&); std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString); void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
void removeWLSignal(wl_listener*); void removeWLSignal(wl_listener*);
std::string escapeJSONStrings(const std::string& str); std::string escapeJSONStrings(const std::string& str);
bool isDirection(const std::string&); bool isDirection(const std::string&);
bool isDirection(const char&); bool isDirection(const char&);
SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&); SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&);
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string); std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
void logSystemInfo(); void logSystemInfo();
std::string execAndGet(const char*); std::string execAndGet(const char*);
int64_t getPPIDof(int64_t pid); int64_t getPPIDof(int64_t pid);
std::expected<int64_t, std::string> configStringToInt(const std::string&); int64_t configStringToInt(const std::string&);
Vector2D configStringToVector2D(const std::string&); Vector2D configStringToVector2D(const std::string&);
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative); std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
double normalizeAngleRad(double ang); double normalizeAngleRad(double ang);
std::vector<SCallstackFrameInfo> getBacktrace(); std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err); void throwError(const std::string& err);
bool envEnabled(const std::string& env); bool envEnabled(const std::string& env);
int allocateSHMFile(size_t len); int allocateSHMFile(size_t len);
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr);
float stringToPercentage(const std::string& VALUE, const float REL);
bool executableExistsInPath(const std::string& exe);
template <typename... Args> template <typename... Args>
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) { [[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {

View File

@@ -11,21 +11,18 @@
#include "../protocols/DRMLease.hpp" #include "../protocols/DRMLease.hpp"
#include "../protocols/DRMSyncobj.hpp" #include "../protocols/DRMSyncobj.hpp"
#include "../protocols/core/Output.hpp" #include "../protocols/core/Output.hpp"
#include "../protocols/Screencopy.hpp"
#include "../protocols/ToplevelExport.hpp"
#include "../managers/PointerManager.hpp" #include "../managers/PointerManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp" #include "../managers/eventLoop/EventLoopManager.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "sync/SyncTimeline.hpp" #include "sync/SyncTimeline.hpp"
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
#include "debug/Log.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <hyprutils/utils/ScopeGuard.hpp> #include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::Utils; using namespace Hyprutils::Utils;
int ratHandler(void* data) { int ratHandler(void* data) {
g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock()); g_pHyprRenderer->renderMonitor((CMonitor*)data);
return 1; return 1;
} }
@@ -39,7 +36,6 @@ CMonitor::~CMonitor() {
} }
void CMonitor::onConnect(bool noRule) { void CMonitor::onConnect(bool noRule) {
EMIT_HOOK_EVENT("preMonitorAdded", self.lock());
CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }}; CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }};
if (output->supportsExplicit) { if (output->supportsExplicit) {
@@ -47,15 +43,10 @@ void CMonitor::onConnect(bool noRule) {
outTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); outTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
} }
listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); }); listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); });
listeners.commit = output->events.commit.registerListener([this](std::any d) { listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); });
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
PROTO::screencopy->onOutputCommit(self.lock());
PROTO::toplevelExport->onOutputCommit(self.lock());
}
});
listeners.needsFrame = listeners.needsFrame =
output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); }); output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); });
listeners.presented = output->events.present.registerListener([this](std::any d) { listeners.presented = output->events.present.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IOutput::SPresentEvent>(d); auto E = std::any_cast<Aquamarine::IOutput::SPresentEvent>(d);
@@ -72,7 +63,7 @@ void CMonitor::onConnect(bool noRule) {
Debug::log(LOG, "Removing monitor {} from realMonitors", szName); Debug::log(LOG, "Removing monitor {} from realMonitors", szName);
std::erase_if(g_pCompositor->m_vRealMonitors, [&](PHLMONITOR& el) { return el.get() == this; }); std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP<CMonitor>& el) { return el.get() == this; });
}); });
listeners.state = output->events.state.registerListener([this](std::any d) { listeners.state = output->events.state.registerListener([this](std::any d) {
@@ -85,7 +76,7 @@ void CMonitor::onConnect(bool noRule) {
return; return;
Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName); Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName);
g_pHyprRenderer->applyMonitorRule(self.lock(), &activeMonitorRule, true); g_pHyprRenderer->applyMonitorRule(this, &activeMonitorRule, true);
return; return;
} }
@@ -99,7 +90,7 @@ void CMonitor::onConnect(bool noRule) {
SMonitorRule rule = activeMonitorRule; SMonitorRule rule = activeMonitorRule;
rule.resolution = SIZE; rule.resolution = SIZE;
g_pHyprRenderer->applyMonitorRule(self.lock(), &rule); g_pHyprRenderer->applyMonitorRule(this, &rule);
}); });
tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
@@ -150,7 +141,7 @@ void CMonitor::onConnect(bool noRule) {
return; return;
} }
PHLMONITOR* thisWrapper = nullptr; SP<CMonitor>* thisWrapper = nullptr;
// find the wrap // find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
@@ -172,7 +163,7 @@ void CMonitor::onConnect(bool noRule) {
// set mode, also applies // set mode, also applies
if (!noRule) if (!noRule)
g_pHyprRenderer->applyMonitorRule(self.lock(), &monitorRule, true); g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
if (!state.commit()) if (!state.commit())
Debug::log(WARN, "state.commit() failed in CMonitor::onCommit"); Debug::log(WARN, "state.commit() failed in CMonitor::onCommit");
@@ -188,7 +179,7 @@ void CMonitor::onConnect(bool noRule) {
continue; continue;
if (ws->m_szLastMonitor == szName || g_pCompositor->m_vMonitors.size() == 1 /* avoid lost workspaces on recover */) { if (ws->m_szLastMonitor == szName || g_pCompositor->m_vMonitors.size() == 1 /* avoid lost workspaces on recover */) {
g_pCompositor->moveWorkspaceToMonitor(ws, self.lock()); g_pCompositor->moveWorkspaceToMonitor(ws, this);
ws->startAnim(true, true, true); ws->startAnim(true, true, true);
ws->m_szLastMonitor = ""; ws->m_szLastMonitor = "";
} }
@@ -205,13 +196,13 @@ void CMonitor::onConnect(bool noRule) {
setMirror(activeMonitorRule.mirrorOf); setMirror(activeMonitorRule.mirrorOf);
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->setActiveMonitor(self.lock()); g_pCompositor->setActiveMonitor(this);
g_pHyprRenderer->arrangeLayersForMonitor(ID); g_pHyprRenderer->arrangeLayersForMonitor(ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
// ensure VRR (will enable if necessary) // ensure VRR (will enable if necessary)
g_pConfigManager->ensureVRR(self.lock()); g_pConfigManager->ensureVRR(this);
// verify last mon valid // verify last mon valid
bool found = false; bool found = false;
@@ -223,28 +214,27 @@ void CMonitor::onConnect(bool noRule) {
} }
if (!found) if (!found)
g_pCompositor->setActiveMonitor(self.lock()); g_pCompositor->setActiveMonitor(this);
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this); renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR);
PROTO::gamma->applyGammaToState(self.lock()); PROTO::gamma->applyGammaToState(this);
events.connect.emit(); events.connect.emit();
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)}); g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)});
EMIT_HOOK_EVENT("monitorAdded", self.lock()); EMIT_HOOK_EVENT("monitorAdded", this);
} }
void CMonitor::onDisconnect(bool destroy) { void CMonitor::onDisconnect(bool destroy) {
EMIT_HOOK_EVENT("preMonitorRemoved", self.lock());
CScopeGuard x = {[this]() { CScopeGuard x = {[this]() {
if (g_pCompositor->m_bIsShuttingDown) if (g_pCompositor->m_bIsShuttingDown)
return; return;
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", self.lock()); EMIT_HOOK_EVENT("monitorRemoved", this);
g_pCompositor->arrangeMonitors(); g_pCompositor->arrangeMonitors();
}}; }};
@@ -261,21 +251,21 @@ void CMonitor::onDisconnect(bool destroy) {
events.disconnect.emit(); events.disconnect.emit();
// Cleanup everything. Move windows back, snap cursor, shit. // Cleanup everything. Move windows back, snap cursor, shit.
PHLMONITOR BACKUPMON = nullptr; CMonitor* BACKUPMON = nullptr;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
if (m.get() != this) { if (m.get() != this) {
BACKUPMON = m; BACKUPMON = m.get();
break; break;
} }
} }
// remove mirror // remove mirror
if (pMirrorOf) { if (pMirrorOf) {
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == self; })); pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; }));
// unlock software for mirrored monitor // unlock software for mirrored monitor
g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf.lock()); g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf);
pMirrorOf.reset(); pMirrorOf = nullptr;
} }
if (!mirrors.empty()) { if (!mirrors.empty()) {
@@ -314,10 +304,11 @@ void CMonitor::onDisconnect(bool destroy) {
g_pCompositor->warpCursorTo(BACKUPMON->vecPosition + BACKUPMON->vecTransformedSize / 2.F, true); g_pCompositor->warpCursorTo(BACKUPMON->vecPosition + BACKUPMON->vecTransformedSize / 2.F, true);
// move workspaces // move workspaces
std::vector<PHLWORKSPACE> wspToMove; std::deque<PHLWORKSPACE> wspToMove;
for (auto const& w : g_pCompositor->m_vWorkspaces) { for (auto const& w : g_pCompositor->m_vWorkspaces) {
if (w->m_pMonitor == self || !w->m_pMonitor) if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) {
wspToMove.push_back(w); wspToMove.push_back(w);
}
} }
for (auto const& w : wspToMove) { for (auto const& w : wspToMove) {
@@ -336,38 +327,37 @@ void CMonitor::onDisconnect(bool destroy) {
activeWorkspace.reset(); activeWorkspace.reset();
output->state->resetExplicitFences(); output->state->resetExplicitFences();
output->state->setAdaptiveSync(false);
output->state->setEnabled(false); output->state->setEnabled(false);
if (!state.commit()) if (!state.commit())
Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect"); Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor == self) if (g_pCompositor->m_pLastMonitor.get() == this)
g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput.lock()); g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput);
if (g_pHyprRenderer->m_pMostHzMonitor == self) { if (g_pHyprRenderer->m_pMostHzMonitor == this) {
int mostHz = 0; int mostHz = 0;
PHLMONITOR pMonitorMostHz = nullptr; CMonitor* pMonitorMostHz = nullptr;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
if (m->refreshRate > mostHz && m != self) { if (m->refreshRate > mostHz && m.get() != this) {
pMonitorMostHz = m; pMonitorMostHz = m.get();
mostHz = m->refreshRate; mostHz = m->refreshRate;
} }
} }
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
} }
std::erase_if(g_pCompositor->m_vMonitors, [&](PHLMONITOR& el) { return el.get() == this; }); std::erase_if(g_pCompositor->m_vMonitors, [&](SP<CMonitor>& el) { return el.get() == this; });
} }
void CMonitor::addDamage(const pixman_region32_t* rg) { void CMonitor::addDamage(const pixman_region32_t* rg) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor"); static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) { if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
damage.damageEntire(); damage.damageEntire();
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} else if (damage.damage(rg)) } else if (damage.damage(rg))
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} }
void CMonitor::addDamage(const CRegion* rg) { void CMonitor::addDamage(const CRegion* rg) {
@@ -376,13 +366,13 @@ void CMonitor::addDamage(const CRegion* rg) {
void CMonitor::addDamage(const CBox* box) { void CMonitor::addDamage(const CBox* box) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor"); static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) { if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
damage.damageEntire(); damage.damageEntire();
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} }
if (damage.damage(*box)) if (damage.damage(*box))
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} }
bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
@@ -394,7 +384,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
// keep requested minimum refresh rate // keep requested minimum refresh rate
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) { if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
// damage whole screen because some previous cursor box damages were skipped // damage whole screen because some previous cursor box damages were skipped
damage.damageEntire(); damage.damageEntire();
return false; return false;
@@ -458,7 +448,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
if (PNEWWORKSPACE) { if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor // workspace exists, move it to the newly connected monitor
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, self.lock()); g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this);
activeWorkspace = PNEWWORKSPACE; activeWorkspace = PNEWWORKSPACE;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
PNEWWORKSPACE->startAnim(true, true, true); PNEWWORKSPACE->startAnim(true, true, true);
@@ -466,7 +456,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
if (newDefaultWorkspaceName == "") if (newDefaultWorkspaceName == "")
newDefaultWorkspaceName = std::to_string(wsID); newDefaultWorkspaceName = std::to_string(wsID);
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(CWorkspace::create(wsID, self.lock(), newDefaultWorkspaceName)); PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(CWorkspace::create(wsID, ID, newDefaultWorkspaceName));
} }
activeWorkspace = PNEWWORKSPACE; activeWorkspace = PNEWWORKSPACE;
@@ -487,7 +477,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
return; return;
} }
if (PMIRRORMON == self) { if (PMIRRORMON == this) {
Debug::log(ERR, "Cannot mirror self!"); Debug::log(ERR, "Cannot mirror self!");
return; return;
} }
@@ -496,13 +486,13 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
// disable mirroring // disable mirroring
if (pMirrorOf) { if (pMirrorOf) {
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == self; })); pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; }));
// unlock software for mirrored monitor // unlock software for mirrored monitor
g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf.lock()); g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf);
} }
pMirrorOf.reset(); pMirrorOf = nullptr;
// set rule // set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(self.lock()); const auto RULE = g_pConfigManager->getMonitorRuleFor(self.lock());
@@ -511,7 +501,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
// push to mvmonitors // push to mvmonitors
PHLMONITOR* thisWrapper = nullptr; SP<CMonitor>* thisWrapper = nullptr;
// find the wrap // find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
@@ -530,21 +520,22 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
setupDefaultWS(RULE); setupDefaultWS(RULE);
g_pHyprRenderer->applyMonitorRule(self.lock(), (SMonitorRule*)&RULE, true); // will apply the offset and stuff g_pHyprRenderer->applyMonitorRule(this, (SMonitorRule*)&RULE, true); // will apply the offset and stuff
} else { } else {
PHLMONITOR BACKUPMON = nullptr; CMonitor* BACKUPMON = nullptr;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
if (m.get() != this) { if (m.get() != this) {
BACKUPMON = m; BACKUPMON = m.get();
break; break;
} }
} }
// move all the WS // move all the WS
std::vector<PHLWORKSPACE> wspToMove; std::deque<PHLWORKSPACE> wspToMove;
for (auto const& w : g_pCompositor->m_vWorkspaces) { for (auto const& w : g_pCompositor->m_vWorkspaces) {
if (w->m_pMonitor == self || !w->m_pMonitor) if (w->m_iMonitorID == ID) {
wspToMove.push_back(w); wspToMove.push_back(w);
}
} }
for (auto const& w : wspToMove) { for (auto const& w : wspToMove) {
@@ -558,14 +549,14 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = PMIRRORMON; pMirrorOf = PMIRRORMON;
pMirrorOf->mirrors.push_back(self); pMirrorOf->mirrors.push_back(this);
// remove from mvmonitors // remove from mvmonitors
std::erase_if(g_pCompositor->m_vMonitors, [&](const auto& other) { return other == self; }); std::erase_if(g_pCompositor->m_vMonitors, [&](const auto& other) { return other.get() == this; });
g_pCompositor->arrangeMonitors(); g_pCompositor->arrangeMonitors();
g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front()); g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front().get());
g_pCompositor->sanityCheckWorkspaces(); g_pCompositor->sanityCheckWorkspaces();
@@ -627,19 +618,19 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
} }
if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace && if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace &&
!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) { !(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse"); static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
auto pWindow = pWorkspace->m_bHasFullscreenWindow ? pWorkspace->getFullscreenWindow() : pWorkspace->getLastFocusedWindow(); auto pWindow = pWorkspace->getLastFocusedWindow();
if (!pWindow) { if (!pWindow) {
if (*PFOLLOWMOUSE == 1) if (*PFOLLOWMOUSE == 1)
pWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); pWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!pWindow) if (!pWindow)
pWindow = pWorkspace->getTopLeftWindow(); pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
if (!pWindow) if (!pWindow)
pWindow = pWorkspace->getFirstWindow(); pWindow = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
} }
g_pCompositor->focusWindow(pWindow); g_pCompositor->focusWindow(pWindow);
@@ -655,11 +646,11 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
EMIT_HOOK_EVENT("workspace", pWorkspace); EMIT_HOOK_EVENT("workspace", pWorkspace);
} }
g_pHyprRenderer->damageMonitor(self.lock()); g_pHyprRenderer->damageMonitor(this);
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace); g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
g_pConfigManager->ensureVRR(self.lock()); g_pConfigManager->ensureVRR(this);
g_pCompositor->updateSuspendedStates(); g_pCompositor->updateSuspendedStates();
@@ -675,7 +666,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
if (activeSpecialWorkspace == pWorkspace) if (activeSpecialWorkspace == pWorkspace)
return; return;
g_pHyprRenderer->damageMonitor(self.lock()); g_pHyprRenderer->damageMonitor(this);
if (!pWorkspace) { if (!pWorkspace) {
// remove special if exists // remove special if exists
@@ -688,7 +679,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) { if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) {
if (const auto PLAST = activeWorkspace->getLastFocusedWindow(); PLAST) if (const auto PLAST = activeWorkspace->getLastFocusedWindow(); PLAST)
g_pCompositor->focusWindow(PLAST); g_pCompositor->focusWindow(PLAST);
else else
@@ -697,7 +688,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pCompositor->updateFullscreenFadeOnWorkspace(activeWorkspace); g_pCompositor->updateFullscreenFadeOnWorkspace(activeWorkspace);
g_pConfigManager->ensureVRR(self.lock()); g_pConfigManager->ensureVRR(this);
g_pCompositor->updateSuspendedStates(); g_pCompositor->updateSuspendedStates();
@@ -711,7 +702,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
bool animate = true; bool animate = true;
//close if open elsewhere //close if open elsewhere
const auto PMONITORWORKSPACEOWNER = pWorkspace->m_pMonitor.lock(); const auto PMONITORWORKSPACEOWNER = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
if (PMONITORWORKSPACEOWNER->activeSpecialWorkspace == pWorkspace) { if (PMONITORWORKSPACEOWNER->activeSpecialWorkspace == pWorkspace) {
PMONITORWORKSPACEOWNER->activeSpecialWorkspace.reset(); PMONITORWORKSPACEOWNER->activeSpecialWorkspace.reset();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
@@ -724,7 +715,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
} }
// open special // open special
pWorkspace->m_pMonitor = self; pWorkspace->m_iMonitorID = ID;
activeSpecialWorkspace = pWorkspace; activeSpecialWorkspace = pWorkspace;
activeSpecialWorkspace->m_bVisible = true; activeSpecialWorkspace->m_bVisible = true;
if (animate) if (animate)
@@ -732,7 +723,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == pWorkspace) { if (w->m_pWorkspace == pWorkspace) {
w->m_pMonitor = self; w->m_iMonitorID = ID;
w->updateSurfaceScaleTransformDetails(); w->updateSurfaceScaleTransformDetails();
w->setAnimationsToMove(); w->setAnimationsToMove();
@@ -756,7 +747,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) { if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) {
if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST) if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST)
g_pCompositor->focusWindow(PLAST); g_pCompositor->focusWindow(PLAST);
else else
@@ -765,11 +756,11 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
g_pHyprRenderer->damageMonitor(self.lock()); g_pHyprRenderer->damageMonitor(this);
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace); g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
g_pConfigManager->ensureVRR(self.lock()); g_pConfigManager->ensureVRR(this);
g_pCompositor->updateSuspendedStates(); g_pCompositor->updateSuspendedStates();
} }
@@ -822,12 +813,6 @@ void CMonitor::scheduleDone() {
}); });
} }
void CMonitor::setCTM(const Mat3x3& ctm_) {
ctm = ctm_;
ctmUpdated = true;
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::scheduleFrameReason::AQ_SCHEDULE_NEEDS_FRAME);
}
bool CMonitor::attemptDirectScanout() { bool CMonitor::attemptDirectScanout() {
if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked) if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked)
return false; // do not DS if this monitor is being mirrored. Will break the functionality. return false; // do not DS if this monitor is being mirrored. Will break the functionality.
@@ -846,7 +831,7 @@ bool CMonitor::attemptDirectScanout() {
return false; return false;
// we can't scanout shm buffers. // we can't scanout shm buffers.
if (!PSURFACE->current.buffer || !PSURFACE->current.buffer->buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */) if (!PSURFACE->current.buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
return false; return false;
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get()); Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get());
@@ -942,76 +927,8 @@ bool CMonitor::attemptDirectScanout() {
return true; return true;
} }
void CMonitor::debugLastPresentation(const std::string& message) { CMonitorState::CMonitorState(CMonitor* owner) {
Debug::log(TRACE, "{} (last presentation {} - {} fps)", message, lastPresentationTimer.getMillis(), m_pOwner = owner;
lastPresentationTimer.getMillis() > 0 ? 1000.0f / lastPresentationTimer.getMillis() : 0.0f);
}
void CMonitor::onMonitorFrame() {
if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!");
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
return m->output != g_pCompositor->m_pUnsafeOutput->output;
})) {
// restore from unsafe state
g_pCompositor->leaveUnsafeState();
}
return; // cannot draw on session inactive (different tty)
}
if (!m_bEnabled)
return;
g_pHyprRenderer->recheckSolitaryForMonitor(self.lock());
tearingState.busy = false;
if (tearingState.activelyTearing && solitaryClient.lock() /* can be invalidated by a recheck */) {
if (!tearingState.frameScheduledWhileBusy)
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
tearingState.nextRenderTorn = true;
tearingState.frameScheduledWhileBusy = false;
}
static auto PENABLERAT = CConfigValue<Hyprlang::INT>("misc:render_ahead_of_time");
static auto PRATSAFE = CConfigValue<Hyprlang::INT>("misc:render_ahead_safezone");
lastPresentationTimer.reset();
if (*PENABLERAT && !tearingState.nextRenderTorn) {
if (!RATScheduled) {
// render
g_pHyprRenderer->renderMonitor(self.lock());
}
RATScheduled = false;
const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(self.lock());
if (max + *PRATSAFE > 1000.0 / refreshRate)
return;
const auto MSLEFT = 1000.0 / refreshRate - lastPresentationTimer.getMillis();
RATScheduled = true;
const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE);
const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1)
g_pHyprRenderer->renderMonitor(self.lock());
else
wl_event_source_timer_update(renderTimer, TIMETOSLEEP);
} else
g_pHyprRenderer->renderMonitor(self.lock());
}
CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) {
;
} }
CMonitorState::~CMonitorState() { CMonitorState::~CMonitorState() {
@@ -1041,7 +958,7 @@ bool CMonitorState::commit() {
if (!updateSwapchain()) if (!updateSwapchain())
return false; return false;
EMIT_HOOK_EVENT("preMonitorCommit", m_pOwner->self.lock()); EMIT_HOOK_EVENT("preMonitorCommit", m_pOwner);
ensureBufferPresent(); ensureBufferPresent();

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include <vector> #include <deque>
#include "WLClasses.hpp" #include "WLClasses.hpp"
#include <vector> #include <vector>
#include <array> #include <array>
@@ -16,7 +16,7 @@
#include <aquamarine/allocator/Swapchain.hpp> #include <aquamarine/allocator/Swapchain.hpp>
// Enum for the different types of auto directions, e.g. auto-left, auto-up. // Enum for the different types of auto directions, e.g. auto-left, auto-up.
enum eAutoDirs : uint8_t { enum eAutoDirs {
DIR_AUTO_NONE = 0, /* None will be treated as right. */ DIR_AUTO_NONE = 0, /* None will be treated as right. */
DIR_AUTO_UP, DIR_AUTO_UP,
DIR_AUTO_DOWN, DIR_AUTO_DOWN,
@@ -54,7 +54,7 @@ class CMonitorState {
private: private:
void ensureBufferPresent(); void ensureBufferPresent();
CMonitor* m_pOwner = nullptr; CMonitor* m_pOwner;
}; };
class CMonitor { class CMonitor {
@@ -125,15 +125,11 @@ class CMonitor {
SP<CSyncTimeline> outTimeline; SP<CSyncTimeline> outTimeline;
uint64_t commitSeq = 0; uint64_t commitSeq = 0;
PHLMONITORREF self; WP<CMonitor> self;
// mirroring // mirroring
PHLMONITORREF pMirrorOf; CMonitor* pMirrorOf = nullptr;
std::vector<PHLMONITORREF> mirrors; std::vector<CMonitor*> mirrors;
// ctm
Mat3x3 ctm = Mat3x3::identity();
bool ctmUpdated = false;
// for tearing // for tearing
PHLWINDOWREF solitaryClient; PHLWINDOWREF solitaryClient;
@@ -183,10 +179,6 @@ class CMonitor {
CBox logicalBox(); CBox logicalBox();
void scheduleDone(); void scheduleDone();
bool attemptDirectScanout(); bool attemptDirectScanout();
void setCTM(const Mat3x3& ctm);
void debugLastPresentation(const std::string& message);
void onMonitorFrame();
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false; bool m_bRenderingInitPassed = false;

View File

@@ -4,56 +4,59 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <cerrno> #include <errno.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <cstdlib> #include <string.h>
#include <stdlib.h>
#include <cstring> #include <cstring>
int NSystemd::sdBooted() { namespace Systemd {
if (!faccessat(AT_FDCWD, "/run/systemd/system/", F_OK, AT_SYMLINK_NOFOLLOW)) int SdBooted(void) {
return true; if (!faccessat(AT_FDCWD, "/run/systemd/system/", F_OK, AT_SYMLINK_NOFOLLOW))
return true;
if (errno == ENOENT) if (errno == ENOENT)
return false; return false;
return -errno;
}
int NSystemd::sdNotify(int unsetEnvironment, const char* state) {
int fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno; return -errno;
}
constexpr char envVar[] = "NOTIFY_SOCKET"; int SdNotify(int unsetEnvironment, const char* state) {
int fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
auto cleanup = [unsetEnvironment, envVar](const int* fd) { constexpr char envVar[] = "NOTIFY_SOCKET";
if (unsetEnvironment)
unsetenv(envVar);
close(*fd);
};
std::unique_ptr<int, decltype(cleanup)> fdCleaup(&fd, cleanup);
const char* addr = getenv(envVar); auto cleanup = [unsetEnvironment, envVar](int* fd) {
if (!addr) if (unsetEnvironment)
return 0; unsetenv(envVar);
close(*fd);
};
std::unique_ptr<int, decltype(cleanup)> fdCleaup(&fd, cleanup);
// address length must be at most this; see man 7 unix const char* addr = getenv(envVar);
size_t addrLen = strnlen(addr, 107); if (!addr)
return 0;
struct sockaddr_un unixAddr; // address length must be at most this; see man 7 unix
unixAddr.sun_family = AF_UNIX; size_t addrLen = strnlen(addr, 107);
strncpy(unixAddr.sun_path, addr, addrLen);
if (unixAddr.sun_path[0] == '@') struct sockaddr_un unixAddr;
unixAddr.sun_path[0] = '\0'; unixAddr.sun_family = AF_UNIX;
strncpy(unixAddr.sun_path, addr, addrLen);
if (unixAddr.sun_path[0] == '@')
unixAddr.sun_path[0] = '\0';
if (connect(fd, (const sockaddr*)&unixAddr, sizeof(struct sockaddr_un)) < 0)
return -errno;
// arbitrary value which seems to be enough for s-d messages
ssize_t stateLen = strnlen(state, 128);
if (write(fd, state, stateLen) == stateLen)
return 1;
if (connect(fd, (const sockaddr*)&unixAddr, sizeof(struct sockaddr_un)) < 0)
return -errno; return -errno;
}
// arbitrary value which seems to be enough for s-d messages
ssize_t stateLen = strnlen(state, 128);
if (write(fd, state, stateLen) == stateLen)
return 1;
return -errno;
} }

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
namespace NSystemd { namespace Systemd {
int sdBooted(void); int SdBooted(void);
int sdNotify(int unset_environment, const char* state); int SdNotify(int unset_environment, const char* state);
} }

View File

@@ -3,135 +3,80 @@
#include <vector> #include <vector>
#include <string> #include <string>
namespace NSplashes { inline const std::vector<std::string> SPLASHES = {
inline const std::vector<std::string> SPLASHES = { // clang-format off
// clang-format off "Woo, animations!",
"Woo, animations!", "It's like Hypr, but better.",
"It's like Hypr, but better.", "Release 1.0 when?",
"Release 1.0 when?", "It's not awesome, it's Hyprland!",
"It's not awesome, it's Hyprland!", "\"I commit too often, people can't catch up lmao\" - Vaxry",
"\"I commit too often, people can't catch up lmao\" - Vaxry", "This text is random.",
"This text is random.", "\"There are reasons to not use rust.\" - Boga",
"\"There are reasons to not use rust.\" - Boga", "Read the wiki.",
"Read the wiki.", "\"Hello everyone this is YOUR daily dose of read the wiki\" - Vaxry",
"\"Hello everyone this is YOUR daily dose of read the wiki\" - Vaxry", "h",
"h", "\"why no work, bro I haven't hacked your pc to get live feeds yet\" - Vaxry",
"\"why no work, bro I haven't hacked your pc to get live feeds yet\" - Vaxry", "Compile, wait for 20 minutes, notice a new commit, compile again.",
"Compile, wait for 20 minutes, notice a new commit, compile again.", "To rice, or not to rice, that is the question.",
"To rice, or not to rice, that is the question.", "Now available on Fedora!",
"Now available on Fedora!", "\"Hyprland is so good it starts with a capital letter\" - Hazel",
"\"Hyprland is so good it starts with a capital letter\" - Hazel", "\"please make this message a splash\" - eriedaberrie",
"\"please make this message a splash\" - eriedaberrie", "\"the only wayland compositor powered by fried chicken\" - raf",
"\"the only wayland compositor powered by fried chicken\" - raf", "\"This will never get into Hyprland\" - Flafy",
"\"This will never get into Hyprland\" - Flafy", "\"Hyprland only gives you up on -git\" - fazzi",
"\"Hyprland only gives you up on -git\" - fazzi", "Segmentation fault (core dumped)",
"Segmentation fault (core dumped)", "\"disabling hyprland logo is a war crime\" - vaxry",
"\"disabling hyprland logo is a war crime\" - vaxry", "some basic startup code",
"some basic startup code", "\"I think I am addicted to hyprland\" - mathisbuilder",
"\"I think I am addicted to hyprland\" - mathisbuilder", "\"hyprland is the most important package in the arch repos\" - jacekpoz",
"\"hyprland is the most important package in the arch repos\" - jacekpoz", "Thanks Brodie!",
"Thanks Brodie!", "Thanks fufexan!",
"Thanks fufexan!", "Thanks raf!",
"Thanks raf!", "You can't use --splash to change this message :)",
"You can't use --splash to change this message :)", "Hyprland will overtake Gnome in popularity by [insert year]",
"Hyprland will overtake Gnome in popularity by [insert year]", // music reference / quote section
"Designed in California - Assembled in China", "J'remue le ciel, le jour, la nuit.",
"\"something <time here> and still no new splash\" - snowman", "aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
"My name is Land. Hypr Land. One red bull, shaken not stirred.", "Wir sind schon sehr lang zusammen...",
"\"Glory To The Emperor\" - raf", "I see a red door and I want it painted black.",
"Help I forgot to install kitty", "Take on me, take me on...",
"Go to settings to activate Hyprland", "You spin me right round baby right round",
"Why is there code??? Make a damn .exe file and give it to me.", "Stayin' alive, stayin' alive",
"Hyprland is not a window manager!", "Say no way, say no way ya, no way!",
"Can we get a version without anime girls?", "Ground control to Major Tom...",
"Check out quickshell!", "Alors on danse",
"A day without Hyprland is a day wasted", "And all that I can see, is just a yellow lemon tree.",
"By dt, do you mean damage tracking or distrotube?", "Got a one-way ticket to the blues",
"Made in Poland", "Is this the real life, is this just fantasy",
"\"I use Arch, btw\" - John Cena", "What's in your head, in your head?",
"\"Hyper\".replace(\"e\", \"\")", "We're all living in America, America, America.",
"\"my win11 install runs hyprland that is true\" - raf", "I'm still standing, better than I ever did",
"\"stop playing league loser\" - hyprBot", "Here comes the sun, bringing you love and shining on everyone",
"\"If it ain't broke, don't fix it\" - Lucascito_03", "Two trailer park girls go round the outside",
"\"@vaxry how do i learn c++\" - flicko", "With the lights out, it's less dangerous",
"Join the discord server!", "Here we go back, this is the moment, tonight is the night",
"Thanks ThatOneCalculator!", "Now you're just somebody that I used to know...",
"The AUR packages always work, except for the times they don't.", "Black bird, black moon, black sky",
"Funny animation compositor woo", "Some legends are told, some turn to dust or to gold",
"2 years!", "Your brain gets smart, but your head gets dumb.",
// music reference / quote section "Save your mercy for someone who needs it more",
"J'remue le ciel, le jour, la nuit.", "You're gonna hear my voice when I shout it out loud",
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!", "Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm",
"Wir sind schon sehr lang zusammen...", "Súbeme la radio que esta es mi canción",
"I see a red door and I want it painted black.", "I'm beggin', beggin' you",
"Take on me, take me on...", "Never gonna let you down (I am trying!)",
"You spin me right round baby right round", "\"I use Arch, btw\" - John Cena",
"Stayin' alive, stayin' alive", "\"Hyper\".replace(\"e\", \"\")",
"Say no way, say no way ya, no way!", "\"my win11 install runs hyprland that is true\" - raf",
"Ground control to Major Tom...", "\"stop playing league loser\" - hyprBot",
"Alors on danse", "\"If it ain't broke, don't fix it\" - Lucascito_03",
"And all that I can see, is just a yellow lemon tree.", "\"@vaxry how do i learn c++\" - flicko",
"Got a one-way ticket to the blues", //
"Is this the real life, is this just fantasy", "Join the discord server!",
"What's in your head, in your head?", "Thanks ThatOneCalculator!",
"We're all living in America, America, America.", "The AUR packages always work, except for the times they don't.",
"I'm still standing, better than I ever did", "Funny animation compositor woo",
"Here comes the sun, bringing you love and shining on everyone", //
"Two trailer park girls go round the outside", "2 years!"
"With the lights out, it's less dangerous", // clang-format on
"Here we go back, this is the moment, tonight is the night",
"Now you're just somebody that I used to know...",
"Black bird, black moon, black sky",
"Some legends are told, some turn to dust or to gold",
"Your brain gets smart, but your head gets dumb.",
"Save your mercy for someone who needs it more",
"You're gonna hear my voice when I shout it out loud",
"Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm",
"Súbeme la radio que esta es mi canción",
"I'm beggin', beggin' you",
"Never gonna let you down (I am trying!)",
"Hier kommt die Sonne",
"Kickstart my heart, give it a start",
"Fear of the dark, I have a constant fear that something's always near",
"Komm mit, reih dich ein.",
"I wish I had an angel for one moment of love",
"We're the children of the dark",
"You float like a feather, in a beautiful world",
"Demons come at night and they bring the end",
"All I wanna say is that they don't really care about us",
"Has he lost his mind? Can he see or is he blind?",
// clang-format on
};
inline const std::vector<std::string> SPLASHES_CHRISTMAS = {
// clang-format off
"Merry Christmas!",
"Merry Xmas!",
"Ho ho ho",
"Santa was here",
"Make sure to spend some jolly time with those near and dear to you!",
"Have you checked for christmas presents yet?",
// clang-format on
};
// ONLY valid near new years.
inline static int newYear = []() -> int {
auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto local = *localtime(&tt);
if (local.tm_mon < 8 /* decided with a fair die I promise. */)
return local.tm_year + 1900;
return local.tm_year + 1901;
}();
inline const std::vector<std::string> SPLASHES_NEWYEAR = {
// clang-format off
"Happy new Year!",
"[New year] will be the year of the Linux desktop!",
"[New year] will be the year of the Hyprland desktop!",
std::format("{} will be the year of the Linux desktop!", newYear),
std::format("{} will be the year of the Hyprland desktop!", newYear),
std::format("Let's make {} even better than {}!", newYear, newYear - 1),
// clang-format on
};
}; };

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