Compare commits

..

18 Commits

Author SHA1 Message Date
vaxerski
12f9a0d0b9 [gha] Nix: update inputs 2024-11-19 21:47:18 +00:00
Vaxry
fab0f426b5 version: bump to 0.45.2 2024-11-19 21:45:40 +00:00
Vaxry
e735eae4ad xdg-shell: don't report invalid min/max sizes on unset
fixes #8522
2024-11-19 21:45:20 +00:00
Aqa-Ib
57cf6d81a9 internal: fix changeWindowZOrder reordering incorrectly (#8494) 2024-11-19 21:45:20 +00:00
Vaxry
77b9d03c3f version: bump to 0.45.1 2024-11-18 14:27:21 +00:00
johannes hanika
53e8513000 constraints: don't warp pointer position on release (#8491)
this was annoying for nuklear properties/ui slider elements that grab
the pointer via GLFW_CURSOR_DISABLE to allow more range and finer control.
upon mouse release, the pointer is reset to the middle of the window
without this patch, making long mouse movements necessary to go back
to the original position for readjustments. fwiw the new behaviour
is consistent with x11 and weston.
2024-11-18 14:26:44 +00:00
Vaxry
7976bfa2df shell: don't use fgrep, prefer grep -F 2024-11-18 14:26:44 +00:00
Vaxry
a77ffa8cb8 windows/xdg: minor cleanup of min/max size calculations
fixes #8495
2024-11-18 14:26:44 +00:00
Vaxry
a4a1ad1f9b hyprpm: fix format crash
ref #8487
2024-11-18 14:26:44 +00:00
Vaxry
737b51d032 renderer: don't render unmapped popups
fixes #8485
2024-11-18 14:26:44 +00:00
staz
b3251f2961 workspacerules: Do not check 'on-created-empty' if using a workspace windowrule (#8486) 2024-11-18 14:26:44 +00:00
Vaxry
c4a77b8da7 core: guard pmonitor in focuswindow
may be null

fixes #8483
2024-11-18 14:26:44 +00:00
sslater11
38b6f3babb workspace: fix missing name via focusworkspaceoncurrentmonitor (#8484) 2024-11-18 14:26:44 +00:00
Vaxry
ace7ece4f2 protocols: mark primarySelection as not privileged
fixes #8479
2024-11-18 14:26:44 +00:00
Tom Englund
0557b2ed8c xcursors: store themes in a std:set to order it (#8474)
using a unordered_set means its store based on a hash_value meaning
currently it can end up loading inherited themes before the actual theme
itself depending on the hash of the theme name used, reason for using
set at all over vector is to keep unique members and not foreverever
looping broken inherit themeing.
2024-11-18 14:26:44 +00:00
Vaxry
9728a39b2e makefile: add stub to discourage direct make 2024-11-18 14:26:44 +00:00
dawsers
7120dde3d1 renderer: scaled surfaces could have zero area (#8423) 2024-11-18 14:26:44 +00:00
Vaxry
e7ab2d8533 defaultConfig: fixup smart gaps rules 2024-11-18 14:26:44 +00:00
415 changed files with 10913 additions and 23135 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

@@ -1,15 +1,75 @@
name: Do not open issues, go to discussions please! name: Bug Report
description: Do not open an issue description: Something is not working right
labels: ["bug"]
body: body:
- type: checkboxes - type: checkboxes
attributes: attributes:
label: Please close this issue. label: Already reported ? *
description: Users cannot open issues. I want my issue to be closed. description: Before opening a new bug report, please take a moment to search through the current open and closed issues to check if it already exists.
options: options:
- label: Yes, I want this issue to be closed. - label: I have searched the existing open and closed issues.
required: true required: true
- type: dropdown
id: type
attributes:
label: Regression?
description: |
Regression means that something used to work but no longer does.
**BEFORE CONTINUING**, please check if this bug is a regression or not, and if it is, we need you to bisect with the help of the wiki: https://wiki.hyprland.org/Crashes-and-Bugs/#bisecting-an-issue
multiple: true
options:
- "Yes"
- "No"
validations:
required: true
- type: textarea - type: textarea
id: body id: ver
attributes: attributes:
label: Issue body label: System Info and Version
description: |
Paste the output of `hyprctl systeminfo -c` here. If you can't
launch Hyprland, paste the output of `Hyprland --systeminfo`.
If `Hyprland --systeminfo` errors out (added in 0.44.0), find
and paste the Hyprland version manually.
value: "<details>
<summary>System/Version info</summary>
```sh
<Paste the output of the command here>
```
</details>"
validations:
required: true
- type: textarea
id: desc
attributes:
label: Description
description: "What went wrong?"
validations:
required: true
- type: textarea
id: repro
attributes:
label: How to reproduce
description: "How can someone else reproduce the issue?"
validations:
required: true
- type: textarea
id: logs
attributes:
label: Crash reports, logs, images, videos
description: |
Anything that can help. Please always ATTACH and not paste them.
Logs can be found in $XDG_RUNTIME_DIR/hypr
Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland

19
.github/ISSUE_TEMPLATE/feature.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Feature Request
description: I'd like to request additional functionality
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Before opening a new issue, take a moment to search through the current open ones.
---
- type: textarea
id: desc
attributes:
label: Description
description: "Describe your idea"
validations:
required: true

View File

@@ -33,10 +33,7 @@ runs:
libfontenc \ libfontenc \
libglvnd \ libglvnd \
libinput \ libinput \
libjxl \
libliftoff \ libliftoff \
libspng \
libwebp \
libxcursor \ libxcursor \
libxcvt \ libxcvt \
libxfont2 \ libxfont2 \
@@ -61,17 +58,7 @@ runs:
xcb-util \ xcb-util \
xcb-util-image \ xcb-util-image \
libzip \ libzip \
librsvg \ librsvg
re2
- name: Get glaze
shell: bash
run: |
git clone https://github.com/stephenberry/glaze.git
cd glaze
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
cmake --install build
- name: Get hyprwayland-scanner-git - name: Get hyprwayland-scanner-git
shell: bash shell: bash
@@ -82,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

@@ -21,7 +21,7 @@ jobs:
- name: Build Hyprland - name: Build Hyprland
run: | run: |
CFLAGS=-Werror CXXFLAGS=-Werror make all make all
- name: Compress and package artifacts - name: Compress and package artifacts
run: | run: |
@@ -107,7 +107,6 @@ jobs:
run: make release run: make release
clang-format: clang-format:
permissions: read-all
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Code Style (Arch)" name: "Code Style (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -1,48 +0,0 @@
name: clang-format
on: pull_request_target
jobs:
clang-format:
permissions: write-all
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Code Style (Arch)"
runs-on: ubuntu-latest
container:
image: archlinux
steps:
- name: Checkout repository actions
uses: actions/checkout@v4
with:
sparse-checkout: .github/actions
- name: Setup base
uses: ./.github/actions/setup_base
- name: Configure
run: meson setup build -Ddefault_library=static
- name: clang-format check
run: ninja -C build clang-format-check
- name: clang-format apply
if: ${{ failure() && github.event_name == 'pull_request' }}
run: ninja -C build clang-format
- name: Create patch
if: ${{ failure() && github.event_name == 'pull_request' }}
run: |
echo 'Please fix the formatting issues by running [`clang-format`](https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/#code-style), or directly apply this patch:' > clang-format.patch
echo '<details>' >> clang-format.patch
echo '<summary>clang-format.patch</summary>' >> clang-format.patch
echo >> clang-format.patch
echo '```diff' >> clang-format.patch
git diff >> clang-format.patch
echo '```' >> clang-format.patch
echo >> clang-format.patch
echo '</details>' >> clang-format.patch
- name: Comment patch
if: ${{ failure() && github.event_name == 'pull_request' }}
uses: mshick/add-pr-comment@v2
with:
message-path: |
clang-format.patch

View File

@@ -12,13 +12,13 @@ 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
steps: steps:
- uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v15 - uses: cachix/cachix-action@v15
with: with:

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

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

2
.gitignore vendored
View File

@@ -28,8 +28,6 @@ protocols/*.c*
protocols/*.h* protocols/*.h*
.ccls-cache .ccls-cache
*.so *.so
src/render/shaders/*.inc
src/render/shaders/Shaders.hpp
hyprctl/hyprctl hyprctl/hyprctl

View File

@@ -25,9 +25,6 @@ message(STATUS "Gathering git info")
# Get git info hash and branch # Get git info hash and branch
execute_process(COMMAND ./scripts/generateVersion.sh execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# Make shader files includable
execute_process(COMMAND ./scripts/generateShaderIncludes.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
@@ -80,7 +77,6 @@ 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)
set(CXX_STANDARD_REQUIRED ON)
add_compile_options( add_compile_options(
-Wall -Wall
-Wextra -Wextra
@@ -105,25 +101,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.8.0) 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(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.6.0)
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION}) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.2)
list(GET AQ_VERSION_LIST 0 AQ_VERSION_MAJOR)
list(GET AQ_VERSION_LIST 1 AQ_VERSION_MINOR)
list(GET AQ_VERSION_LIST 2 AQ_VERSION_PATCH)
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
add_compile_definitions(AQUAMARINE_VERSION_MAJOR=${AQ_VERSION_MAJOR})
add_compile_definitions(AQUAMARINE_VERSION_MINOR=${AQ_VERSION_MINOR})
add_compile_definitions(AQUAMARINE_VERSION_PATCH=${AQ_VERSION_PATCH})
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
@@ -132,7 +114,7 @@ pkg_check_modules(
xkbcommon xkbcommon
uuid uuid
wayland-server>=1.22.90 wayland-server>=1.22.90
wayland-protocols>=1.41 wayland-protocols
cairo cairo
pango pango
pangocairo pangocairo
@@ -142,7 +124,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)
@@ -209,12 +193,6 @@ if(NOT HAS_TIMERFD AND epoll_FOUND)
target_link_libraries(Hyprland PkgConfig::epoll) target_link_libraries(Hyprland PkgConfig::epoll)
endif() endif()
check_include_file("sys/inotify.h" HAS_INOTIFY)
pkg_check_modules(inotify IMPORTED_TARGET libinotify)
if(NOT HAS_INOTIFY AND inotify_FOUND)
target_link_libraries(Hyprland PkgConfig::inotify)
endif()
if(LEGACY_RENDERER) if(LEGACY_RENDERER)
message(STATUS "Using the legacy GLES2 renderer!") message(STATUS "Using the legacy GLES2 renderer!")
add_compile_definitions(LEGACY_RENDERER) add_compile_definitions(LEGACY_RENDERER)
@@ -244,15 +222,16 @@ 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)
configure_file(systemd/hyprland-session.service.in
systemd/hyprland-session.service @ONLY)
# session file -uwsm # session file -systemd
if(NO_UWSM) install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-systemd.desktop
message(STATUS "UWSM support is disabled...") DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
else()
message(STATUS "UWSM support is enabled (NO_UWSM not defined)...") # install systemd service
install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop install(FILES ${CMAKE_BINARY_DIR}/systemd/hyprland-session.service
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/user)
endif()
endif() endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})
@@ -266,15 +245,7 @@ target_precompile_headers(Hyprland PRIVATE
message(STATUS "Setting link libraries") message(STATUS "Setting link libraries")
target_link_libraries( target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps)
Hyprland
rt
PkgConfig::aquamarine_dep
PkgConfig::hyprlang_dep
PkgConfig::hyprutils_dep
PkgConfig::hyprcursor_dep
PkgConfig::hyprgraphics_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()
@@ -316,7 +287,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.6.2) pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.4.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}")
@@ -342,12 +313,8 @@ protocolnew("protocols" "kde-server-decoration" true)
protocolnew("protocols" "wlr-data-control-unstable-v1" true) 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" "xx-color-management-v4" true)
protocolnew("protocols" "frog-color-management-v1" true)
protocolnew("protocols" "wayland-drm" true) protocolnew("protocols" "wayland-drm" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-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)
@@ -380,20 +347,12 @@ 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) protocolnew("staging/security-context" "security-context-v1" false)
protocolnew("staging/content-type" "content-type-v1" false)
protocolnew("staging/color-management" "color-management-v1" false)
protocolwayland() protocolwayland()
# tools # tools
add_subdirectory(hyprctl) add_subdirectory(hyprctl)
add_subdirectory(hyprpm)
if(NO_HYPRPM)
message(STATUS "hyprpm is disabled")
else()
add_subdirectory(hyprpm)
message(STATUS "hyprpm is enabled (NO_HYPRPM not defined)")
endif()
# binary and symlink # binary and symlink
install(TARGETS Hyprland) install(TARGETS Hyprland)
@@ -404,6 +363,7 @@ install(
${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
\"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \ \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \
)") )")
# session file # session file
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
@@ -447,7 +407,4 @@ install(
DIRECTORY ${HEADERS_SRC} DIRECTORY ${HEADERS_SRC}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING FILES_MATCHING
PATTERN "*.h" PATTERN "*.h*")
PATTERN "*.hpp"
PATTERN "*.inc"
)

View File

@@ -52,7 +52,7 @@ installheaders:
cmake --build ./build --config Release --target generate-protocol-headers cmake --build ./build --config Release --target generate-protocol-headers
find src -type f \( -name '*.hpp' -o -name '*.h' -o -name '*.inc' \) -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi

View File

@@ -1 +1 @@
0.48.0 0.45.2

View File

@@ -52,20 +52,6 @@ env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24 env = HYPRCURSOR_SIZE,24
###################
### PERMISSIONS ###
###################
# See https://wiki.hyprland.org/Configuring/Permissions/
# ecosystem {
# enforce_permissions = 1
# }
# permission = /usr/(bin|local/bin)/grim, screencopy, allow
# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
##################### #####################
### LOOK AND FEEL ### ### LOOK AND FEEL ###
##################### #####################
@@ -95,7 +81,6 @@ general {
# https://wiki.hyprland.org/Configuring/Variables/#decoration # https://wiki.hyprland.org/Configuring/Variables/#decoration
decoration { decoration {
rounding = 10 rounding = 10
rounding_power = 2
# Change transparency of focused and unfocused windows # Change transparency of focused and unfocused windows
active_opacity = 1.0 active_opacity = 1.0
@@ -153,10 +138,10 @@ animations {
# uncomment all if you wish to use that. # uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] # windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrule = rounding 0, floating:0, onworkspace:w[tv1] # windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrule = bordersize 0, floating:0, onworkspace:f[1] # windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrule = rounding 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 {
@@ -290,11 +275,14 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules # See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule # Example windowrule v1
# windowrule = float,class:^(kitty)$,title:^(kitty)$ # windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.* windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland # Fix some dragging issues with XWayland
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0

View File

@@ -22,6 +22,5 @@
} }
] ]
}, },
] ]
} }

162
flake.lock generated
View File

@@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1743265529, "lastModified": 1731959031,
"narHash": "sha256-QbjP15/2N+VJl0b5jxrrTc+VOt39aU4XrDvtP0Lz5ik=", "narHash": "sha256-TGcvIjftziC1CjuiHCzrYDwmOoSFYIhdiKmLetzB5L0=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "1d2dbd72c2bbaceab031c592d4810f744741d203", "rev": "4468981c1c50999f315baa1508f0e53c4ee70c52",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -79,11 +79,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1742215578, "lastModified": 1728669738,
"narHash": "sha256-zfs71PXVVPEe56WEyNi2TJQPs0wabU4WAlq0XV7GcdE=", "narHash": "sha256-EDNAU9AYcx8OupUzbTbWE1d3HYdeG0wO6Msg3iL1muk=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "2fd36421c21aa87e2fe3bee11067540ae612f719", "rev": "0264e698149fcb857a66a53018157b41f8d97bb0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -92,32 +92,6 @@
"type": "github" "type": "github"
} }
}, },
"hyprgraphics": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1739049071,
"narHash": "sha256-3+7TpXMrbsUXSwgr5VAKAnmkzMb6JO+Rvc9XRb5NMg4=",
"owner": "hyprwm",
"repo": "hyprgraphics",
"rev": "175c6b29b6ff82100539e7c4363a35a02c74dd73",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprgraphics",
"type": "github"
}
},
"hyprland-protocols": { "hyprland-protocols": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -128,11 +102,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1743714874, "lastModified": 1728345020,
"narHash": "sha256-yt8F7NhMFCFHUHy/lNjH/pjZyIDFNk52Q4tivQ31WFo=", "narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "3a5c2bda1c1a4e55cc1330c782547695a93f05b2", "rev": "a7c183800e74f337753de186522b9017a07a8cee",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -141,67 +115,6 @@
"type": "github" "type": "github"
} }
}, },
"hyprland-qt-support": {
"inputs": {
"hyprlang": [
"hyprland-qtutils",
"hyprlang"
],
"nixpkgs": [
"hyprland-qtutils",
"nixpkgs"
],
"systems": [
"hyprland-qtutils",
"systems"
]
},
"locked": {
"lastModified": 1737634706,
"narHash": "sha256-nGCibkfsXz7ARx5R+SnisRtMq21IQIhazp6viBU8I/A=",
"owner": "hyprwm",
"repo": "hyprland-qt-support",
"rev": "8810df502cdee755993cb803eba7b23f189db795",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-qt-support",
"type": "github"
}
},
"hyprland-qtutils": {
"inputs": {
"hyprland-qt-support": "hyprland-qt-support",
"hyprlang": [
"hyprlang"
],
"hyprutils": [
"hyprland-qtutils",
"hyprlang",
"hyprutils"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1739048983,
"narHash": "sha256-REhTcXq4qs3B3cCDtLlYDz0GZvmsBSh947Ub6pQWGTQ=",
"owner": "hyprwm",
"repo": "hyprland-qtutils",
"rev": "3504a293c8f8db4127cb0f7cfc1a318ffb4316f8",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-qtutils",
"type": "github"
}
},
"hyprlang": { "hyprlang": {
"inputs": { "inputs": {
"hyprutils": [ "hyprutils": [
@@ -215,11 +128,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741191527, "lastModified": 1728168612,
"narHash": "sha256-kM+11Nch47Xwfgtw2EpRitJuORy4miwoMuRi5tyMBDY=", "narHash": "sha256-AnB1KfiXINmuiW7BALYrKqcjCnsLZPifhb/7BsfPbns=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "72df3861f1197e41b078faa3e38eedd60e00018d", "rev": "f054f2e44d6a0b74607a6bc0f52dba337a3db38e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -238,11 +151,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1743950287, "lastModified": 1731702627,
"narHash": "sha256-/6IAEWyb8gC/NKZElxiHChkouiUOrVYNq9YqG0Pzm4Y=", "narHash": "sha256-+JeO9gevnXannQxMfR5xzZtF4sYmSlWkX/BPmPx0mWk=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "f2dc70e448b994cef627a157ee340135bd68fbc6", "rev": "e911361a687753bbbdfe3b6a9eab755ecaf1d9e1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -261,11 +174,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1739870480, "lastModified": 1726874836,
"narHash": "sha256-SiDN5BGxa/1hAsqhgJsS03C3t2QrLgBT8u+ENJ0Qzwc=", "narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "206367a08dc5ac4ba7ad31bdca391d098082e64b", "rev": "500c81a9e1a76760371049a8d99e008ea77aa59e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -276,11 +189,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1743827369, "lastModified": 1731676054,
"narHash": "sha256-rpqepOZ8Eo1zg+KJeWoq1HAOgoMCDloqv5r2EAa9TSA=", "narHash": "sha256-OZiZ3m8SCMfh3B6bfGC/Bm4x3qc1m2SVEAlkV6iY7Yg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "42a1c966be226125b48c384171c44c651c236c22", "rev": "5e4fbfb6b3de1aa2872b76d49fafc942626e2add",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -290,20 +203,37 @@
"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": { "pre-commit-hooks": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"gitignore": "gitignore", "gitignore": "gitignore",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
] ],
"nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1742649964, "lastModified": 1732021966,
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=", "narHash": "sha256-mnTbjpdqF0luOkou8ZFi2asa1N3AA2CchR/RqCNmsGE=",
"owner": "cachix", "owner": "cachix",
"repo": "git-hooks.nix", "repo": "git-hooks.nix",
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82", "rev": "3308484d1a443fc5bc92012435d79e80458fe43c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -316,9 +246,7 @@
"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",
@@ -365,11 +293,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741934139, "lastModified": 1731703417,
"narHash": "sha256-ZhTcTH9FoeAtbPfWGrhkH7RjLJZ7GeF18nygLAMR+WE=", "narHash": "sha256-rheDc/7C+yI+QspYr9J2z9kQ5P9F4ATapI7qyFAe1XA=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "150b0b6f52bb422a1b232a53698606fe0320dde0", "rev": "8070f36deec723de71e7557441acb17e478204d3",
"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.hyprlang.follows = "hyprlang";
};
hyprlang = { hyprlang = {
url = "github:hyprwm/hyprlang"; url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@@ -130,11 +116,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;
@@ -157,11 +145,5 @@
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;
# Hydra build jobs
# Recent versions of Hydra can aggregate jobsets from 'hydraJobs' intead of a release.nix
# or similar. Remember to filter large or incompatible attributes here. More eval jobs can
# be added by merging, e.g., self.packages // self.devShells.
hydraJobs = self.packages;
}; };
} }

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

@@ -22,7 +22,6 @@ commands:
getoption <option> Gets the config option status (values) getoption <option> Gets the config option status (values)
globalshortcuts Lists all global shortcuts globalshortcuts Lists all global shortcuts
hyprpaper ... Issue a hyprpaper request hyprpaper ... Issue a hyprpaper request
hyprsunset ... Issue a hyprsunset request
instances Lists all running instances of Hyprland with instances Lists all running instances of Hyprland with
their info their info
keyword <name> <value> Issue a keyword to call a config keyword keyword <name> <value> Issue a keyword to call a config keyword
@@ -82,16 +81,6 @@ requests:
flags: flags:
See 'hyprctl --help')#"; See 'hyprctl --help')#";
const std::string_view HYPRSUNSET_HELP = R"#(usage: hyprctl [flags] hyprsunset <request>
requests:
temperature <temp> Enable blue-light filter
identity Disable blue-light filter
gamma <gamma> Enable gamma filter
flags:
See 'hyprctl --help')#";
const std::string_view NOTIFY_HELP = R"#(usage: hyprctl [flags] notify <icon> <time_ms> <color> <message...> const std::string_view NOTIFY_HELP = R"#(usage: hyprctl [flags] notify <icon> <time_ms> <color> <message...>
icon: icon:

View File

@@ -23,7 +23,7 @@ _hyprctl () {
local words cword local words cword
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword _get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
declare -a literals=(resizeactive 2 changegroupactive -r moveintogroup forceallowsinput 4 ::= systeminfo all layouts setprop animationstyle switchxkblayout create denywindowfromgroup headless activebordercolor exec setcursor wayland focusurgentorlast workspacerules movecurrentworkspacetomonitor movetoworkspacesilent hyprpaper alpha inactivebordercolor movegroupwindow movecursortocorner movewindowpixel prev movewindow globalshortcuts clients dimaround setignoregrouplock splash execr monitors 0 forcenoborder -q animations 1 nomaxsize splitratio moveactive pass swapnext devices layers rounding lockactivegroup 5 moveworkspacetomonitor -f -i --quiet forcenodim pin 0 1 forceopaque forcenoshadow setfloating minsize alphaoverride sendshortcut workspaces cyclenext alterzorder togglegroup lockgroups bordersize dpms focuscurrentorlast -1 --batch notify remove instances 1 3 moveoutofgroup killactive 2 movetoworkspace movecursor configerrors closewindow swapwindow tagwindow forcerendererreload centerwindow auto focuswindow seterror nofocus alphafullscreen binds version -h togglespecialworkspace fullscreen windowdancecompat 0 keyword toggleopaque 3 --instance togglefloating renameworkspace alphafullscreenoverride activeworkspace x11 kill forceopaqueoverriden output global dispatch reload forcenoblur -j event --help disable -1 activewindow keepaspectratio dismissnotify focusmonitor movefocus plugin exit workspace fullscreenstate getoption alphainactiveoverride alphainactive decorations settiled config-only descriptions resizewindowpixel fakefullscreen rollinglog swapactiveworkspaces submap next movewindoworgroup cursorpos forcenoanims focusworkspaceoncurrentmonitor maxsize sendkeystate) declare -a literals=(resizeactive 2 changegroupactive -r moveintogroup forceallowsinput 4 ::= systeminfo all layouts setprop animationstyle switchxkblayout create denywindowfromgroup headless activebordercolor exec setcursor wayland focusurgentorlast workspacerules movecurrentworkspacetomonitor movetoworkspacesilent hyprpaper alpha inactivebordercolor movegroupwindow movecursortocorner movewindowpixel prev movewindow globalshortcuts clients dimaround setignoregrouplock splash execr monitors 0 forcenoborder -q animations 1 nomaxsize splitratio moveactive pass swapnext devices layers rounding lockactivegroup 5 moveworkspacetomonitor -f -i --quiet forcenodim pin 0 1 forceopaque forcenoshadow setfloating minsize alphaoverride sendshortcut workspaces cyclenext alterzorder togglegroup lockgroups bordersize dpms focuscurrentorlast -1 --batch notify remove instances 1 3 moveoutofgroup killactive 2 movetoworkspace movecursor configerrors closewindow swapwindow tagwindow forcerendererreload centerwindow auto focuswindow seterror nofocus alphafullscreen binds version -h togglespecialworkspace fullscreen windowdancecompat 0 keyword toggleopaque 3 --instance togglefloating renameworkspace alphafullscreenoverride activeworkspace x11 kill forceopaqueoverriden output global dispatch reload forcenoblur -j event --help disable -1 activewindow keepaspectratio dismissnotify focusmonitor movefocus plugin exit workspace fullscreenstate getoption alphainactiveoverride alphainactive decorations settiled config-only descriptions resizewindowpixel fakefullscreen rollinglog swapactiveworkspaces submap next movewindoworgroup cursorpos forcenoanims focusworkspaceoncurrentmonitor maxsize)
declare -A literal_transitions declare -A literal_transitions
literal_transitions[0]="([120]=14 [43]=2 [125]=21 [81]=2 [3]=21 [51]=2 [50]=2 [128]=2 [89]=2 [58]=21 [8]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [102]=21 [133]=7 [100]=2 [137]=2 [22]=2 [19]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [78]=21 [114]=2 [37]=2 [151]=2 [116]=2 [121]=13 [123]=21 [39]=11 [42]=21 [79]=15 [118]=12)" literal_transitions[0]="([120]=14 [43]=2 [125]=21 [81]=2 [3]=21 [51]=2 [50]=2 [128]=2 [89]=2 [58]=21 [8]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [102]=21 [133]=7 [100]=2 [137]=2 [22]=2 [19]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [78]=21 [114]=2 [37]=2 [151]=2 [116]=2 [121]=13 [123]=21 [39]=11 [42]=21 [79]=15 [118]=12)"
literal_transitions[1]="([81]=2 [51]=2 [50]=2 [128]=2 [8]=2 [89]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [133]=7 [100]=2 [22]=2 [19]=2 [137]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [114]=2 [37]=2 [151]=2 [116]=2 [39]=11 [118]=12 [121]=13 [120]=14 [79]=15 [43]=2)" literal_transitions[1]="([81]=2 [51]=2 [50]=2 [128]=2 [8]=2 [89]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [133]=7 [100]=2 [22]=2 [19]=2 [137]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [114]=2 [37]=2 [151]=2 [116]=2 [39]=11 [118]=12 [121]=13 [120]=14 [79]=15 [43]=2)"

View File

@@ -29,7 +29,7 @@ function _hyprctl
set COMP_CWORD (count $COMP_WORDS) set COMP_CWORD (count $COMP_WORDS)
end end
set literals "resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" "sendkeystate" set literals "resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize"
set descriptions set descriptions
set descriptions[1] "Resize the active window" set descriptions[1] "Resize the active window"

View File

@@ -106,7 +106,6 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (execr) "Execute a raw shell command" | (execr) "Execute a raw shell command"
| (pass) "Pass the key to a specified window" | (pass) "Pass the key to a specified window"
| (sendshortcut) "On shortcut X sends shortcut Y to a specified window" | (sendshortcut) "On shortcut X sends shortcut Y to a specified window"
| (sendkeystate) "Send a key with specific state (down/repeat/up) to a specified window (window must keep focus for events to continue)"
| (killactive) "Close the active window" | (killactive) "Close the active window"
| (closewindow) "Close a specified window" | (closewindow) "Close a specified window"
| (workspace) "Change the workspace" | (workspace) "Change the workspace"

View File

@@ -17,7 +17,7 @@ _hyprctl_cmd_0 () {
} }
_hyprctl () { _hyprctl () {
local -a literals=("resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" "sendkeystate") local -a literals=("resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize")
local -A descriptions local -A descriptions
descriptions[1]="Resize the active window" descriptions[1]="Resize the active window"

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>
@@ -12,17 +10,24 @@
#include <sys/un.h> #include <sys/un.h>
#include <pwd.h> #include <pwd.h>
#include <unistd.h> #include <unistd.h>
#include <ranges>
#include <algorithm> #include <algorithm>
#include <csignal> #include <csignal>
#include <format>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <print> #include <print>
#include <fstream> #include <fstream>
#include <string>
#include <vector> #include <vector>
#include <deque>
#include <filesystem> #include <filesystem>
#include <cstdarg> #include <cstdarg>
#include <regex>
#include <sys/socket.h>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <cstring>
using namespace Hyprutils::String; using namespace Hyprutils::String;
#include "Strings.hpp" #include "Strings.hpp"
@@ -47,17 +52,11 @@ void log(const std::string& str) {
std::println("{}", str); std::println("{}", str);
} }
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";
} }
@@ -67,11 +66,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;
@@ -149,16 +143,8 @@ int rollingRead(const int socket) {
int request(std::string arg, int minArgs = 0, bool needRoll = false) { int request(std::string arg, int minArgs = 0, bool needRoll = false) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
if (SERVERSOCKET < 0) { auto t = timeval{.tv_sec = 5, .tv_usec = 0};
log("Couldn't open a socket (1)"); setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));
return 1;
}
auto t = timeval{.tv_sec = 5, .tv_usec = 0};
if (setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)) < 0) {
log("Couldn't set socket timeout (2)");
return 2;
}
const auto ARGS = std::count(arg.begin(), arg.end(), ' '); const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
@@ -167,12 +153,17 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
return -1; return -1;
} }
if (instanceSignature.empty()) { if (SERVERSOCKET < 0) {
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?) (3)"); log("Couldn't open a socket (1)");
return 3; return 1;
} }
const std::string USERID = std::to_string(getUID()); if (instanceSignature.empty()) {
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
return 2;
}
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;
@@ -182,40 +173,39 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1); strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) { if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
log("Couldn't connect to " + socketPath + ". (4)"); log("Couldn't connect to " + socketPath + ". (3)");
return 4; return 3;
} }
auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length()); auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
if (sizeWritten < 0) { if (sizeWritten < 0) {
log("Couldn't write (5)"); log("Couldn't write (4)");
return 5; return 4;
} }
if (needRoll) if (needRoll)
return rollingRead(SERVERSOCKET); return rollingRead(SERVERSOCKET);
std::string reply = ""; std::string reply = "";
constexpr size_t BUFFER_SIZE = 8192; char buffer[8192] = {0};
char buffer[BUFFER_SIZE] = {0};
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); sizeWritten = read(SERVERSOCKET, buffer, 8192);
if (sizeWritten < 0) { if (sizeWritten < 0) {
if (errno == EWOULDBLOCK) if (errno == EWOULDBLOCK)
log("Hyprland IPC didn't respond in time\n"); log("Hyprland IPC didn't respond in time\n");
log("Couldn't read (6)"); log("Couldn't read (5)");
return 6; return 5;
} }
reply += std::string(buffer, sizeWritten); reply += std::string(buffer, sizeWritten);
while (sizeWritten == BUFFER_SIZE) { while (sizeWritten == 8192) {
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); sizeWritten = read(SERVERSOCKET, buffer, 8192);
if (sizeWritten < 0) { if (sizeWritten < 0) {
log("Couldn't read (6)"); log("Couldn't read (5)");
return 6; return 5;
} }
reply += std::string(buffer, sizeWritten); reply += std::string(buffer, sizeWritten);
} }
@@ -227,7 +217,7 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
return 0; return 0;
} }
int requestIPC(std::string filename, std::string arg) { int requestHyprpaper(std::string arg) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
if (SERVERSOCKET < 0) { if (SERVERSOCKET < 0) {
@@ -243,9 +233,9 @@ int requestIPC(std::string filename, 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 + "/" + filename; std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock";
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1); strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
@@ -263,10 +253,10 @@ int requestIPC(std::string filename, std::string arg) {
log("Couldn't write (4)"); log("Couldn't write (4)");
return 4; return 4;
} }
constexpr size_t BUFFER_SIZE = 8192;
char buffer[BUFFER_SIZE] = {0};
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); char buffer[8192] = {0};
sizeWritten = read(SERVERSOCKET, buffer, 8192);
if (sizeWritten < 0) { if (sizeWritten < 0) {
log("Couldn't read (5)"); log("Couldn't read (5)");
@@ -280,20 +270,11 @@ int requestIPC(std::string filename, std::string arg) {
return 0; return 0;
} }
int requestHyprpaper(std::string arg) {
return requestIPC(".hyprpaper.sock", arg);
}
int requestHyprsunset(std::string arg) {
return requestIPC(".hyprsunset.sock", 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/");
commands.insert(0, "j/");
} }
std::string rq = "[[BATCH]]" + commands; std::string rq = "[[BATCH]]" + commands;
@@ -330,11 +311,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;
} }
@@ -392,8 +373,6 @@ int main(int argc, char** argv) {
if (cmd == "hyprpaper") { if (cmd == "hyprpaper") {
std::println("{}", HYPRPAPER_HELP); std::println("{}", HYPRPAPER_HELP);
} else if (cmd == "hyprsunset") {
std::println("{}", HYPRSUNSET_HELP);
} else if (cmd == "notify") { } else if (cmd == "notify") {
std::println("{}", NOTIFY_HELP); std::println("{}", NOTIFY_HELP);
} else if (cmd == "output") { } else if (cmd == "output") {
@@ -475,8 +454,6 @@ int main(int argc, char** argv) {
batchRequest(fullRequest, json); batchRequest(fullRequest, json);
else if (fullRequest.contains("/hyprpaper")) else if (fullRequest.contains("/hyprpaper"))
exitStatus = requestHyprpaper(fullRequest); exitStatus = requestHyprpaper(fullRequest);
else if (fullRequest.contains("/hyprsunset"))
exitStatus = requestHyprsunset(fullRequest);
else if (fullRequest.contains("/switchxkblayout")) else if (fullRequest.contains("/switchxkblayout"))
exitStatus = request(fullRequest, 2); exitStatus = request(fullRequest, 2);
else if (fullRequest.contains("/seterror")) else if (fullRequest.contains("/seterror"))

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,25 +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)
find_package(glaze QUIET)
if (NOT glaze_FOUND)
set(GLAZE_VERSION v4.2.3)
message(STATUS "glaze dependency not found, retrieving ${GLAZE_VERSION} with FetchContent")
include(FetchContent)
FetchContent_Declare(
glaze
GIT_REPOSITORY https://github.com/stephenberry/glaze.git
GIT_TAG ${GLAZE_VERSION}
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(glaze)
endif()
add_executable(hyprpm ${SRCFILES}) add_executable(hyprpm ${SRCFILES})
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps glaze::glaze) target_link_libraries(hyprpm PUBLIC PkgConfig::deps)
# binary # binary
install(TARGETS hyprpm) install(TARGETS hyprpm)

View File

@@ -14,7 +14,7 @@ hyprpm [<FLAGS>]... <ARGUMENT>
| (list) "List all installed plugins" | (list) "List all installed plugins"
| (enable <PLUGINS>) "Load a plugin" | (enable <PLUGINS>) "Load a plugin"
| (disable <PLUGINS>) "Unload a plugin" | (disable <PLUGINS>) "Unload a plugin"
| (reload) "Reload plugins to match the enabled/disabled state. Use -f to force reload." | (reload) "Reload all plugins"
; ;
<PLUGINS> ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}}; <PLUGINS> ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}};

View File

@@ -1,10 +1,11 @@
#include "DataState.hpp" #include "DataState.hpp"
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <print> #include <print>
#include <filesystem>
#include <fstream> #include <fstream>
#include "PluginManager.hpp" #include "PluginManager.hpp"
std::filesystem::path 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::println(stderr, "DataState: no $HOME");
@@ -15,29 +16,12 @@ std::filesystem::path DataState::getDataStatePath() {
const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME"); const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME");
if (XDG_DATA_HOME) if (XDG_DATA_HOME)
return std::filesystem::path{XDG_DATA_HOME} / "hyprpm"; return std::string{XDG_DATA_HOME} + "/hyprpm";
return std::filesystem::path{HOME} / ".local/share/hyprpm"; return std::string{HOME} + "/.local/share/hyprpm";
} }
std::string DataState::getHeadersPath() { std::string DataState::getHeadersPath() {
return getDataStatePath() / "headersRoot"; return getDataStatePath() + "/headersRoot";
}
std::vector<std::filesystem::path> DataState::getPluginStates() {
ensureStateStoreExists();
std::vector<std::filesystem::path> states;
for (const auto& entry : std::filesystem::directory_iterator(getDataStatePath())) {
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
const auto stateFile = entry.path() / "state.toml";
if (!std::filesystem::exists(stateFile))
continue;
states.emplace_back(stateFile);
}
return states;
} }
void DataState::ensureStateStoreExists() { void DataState::ensureStateStoreExists() {
@@ -53,7 +37,7 @@ void DataState::ensureStateStoreExists() {
void DataState::addNewPluginRepo(const SPluginRepository& repo) { void DataState::addNewPluginRepo(const SPluginRepository& repo) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath() / repo.name; const auto PATH = getDataStatePath() + "/" + repo.name;
std::filesystem::create_directories(PATH); std::filesystem::create_directories(PATH);
// clang-format off // clang-format off
@@ -66,21 +50,19 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
}} }}
}; };
for (auto const& p : repo.plugins) { for (auto const& p : repo.plugins) {
const auto filename = p.name + ".so";
// copy .so to the good place // copy .so to the good place
if (std::filesystem::exists(p.filename)) if (std::filesystem::exists(p.filename))
std::filesystem::copy_file(p.filename, PATH / filename); std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so");
DATA.emplace(p.name, toml::table{ DATA.emplace(p.name, toml::table{
{"filename", filename}, {"filename", p.name + ".so"},
{"enabled", p.enabled}, {"enabled", p.enabled},
{"failed", p.failed} {"failed", p.failed}
}); });
} }
// clang-format on // clang-format on
std::ofstream ofs(PATH / "state.toml", std::ios::trunc); std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
ofs << DATA; ofs << DATA;
ofs.close(); ofs.close();
} }
@@ -90,10 +72,17 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
const auto STATE = toml::parse_file(stateFile.c_str()); if (!entry.is_directory() || entry.path().stem() == "headersRoot")
const auto NAME = STATE["repository"]["name"].value_or(""); continue;
const auto URL = STATE["repository"]["url"].value_or("");
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
const auto NAME = STATE["repository"]["name"].value_or("");
const auto URL = STATE["repository"]["url"].value_or("");
if (URL == urlOrName || NAME == urlOrName) if (URL == urlOrName || NAME == urlOrName)
return true; return true;
@@ -107,22 +96,29 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
const auto STATE = toml::parse_file(stateFile.c_str()); if (!entry.is_directory() || entry.path().stem() == "headersRoot")
const auto NAME = STATE["repository"]["name"].value_or(""); continue;
const auto URL = STATE["repository"]["url"].value_or("");
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
const auto NAME = STATE["repository"]["name"].value_or("");
const auto URL = STATE["repository"]["url"].value_or("");
if (URL == urlOrName || NAME == urlOrName) { if (URL == urlOrName || NAME == urlOrName) {
// unload the plugins!! // unload the plugins!!
for (const auto& file : std::filesystem::directory_iterator(stateFile.parent_path())) { for (const auto& file : std::filesystem::directory_iterator(entry.path())) {
if (!file.path().string().ends_with(".so")) if (!file.path().string().ends_with(".so"))
continue; continue;
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false); g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
} }
std::filesystem::remove_all(stateFile.parent_path()); std::filesystem::remove_all(entry.path());
return; return;
} }
} }
@@ -143,7 +139,7 @@ void DataState::updateGlobalState(const SGlobalState& state) {
}; };
// clang-format on // clang-format on
std::ofstream ofs(PATH / "state.toml", std::ios::trunc); std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
ofs << DATA; ofs << DATA;
ofs.close(); ofs.close();
} }
@@ -151,12 +147,12 @@ void DataState::updateGlobalState(const SGlobalState& state) {
SGlobalState DataState::getGlobalState() { SGlobalState DataState::getGlobalState() {
ensureStateStoreExists(); ensureStateStoreExists();
const auto stateFile = getDataStatePath() / "state.toml"; const auto PATH = getDataStatePath();
if (!std::filesystem::exists(stateFile)) if (!std::filesystem::exists(PATH + "/state.toml"))
return SGlobalState{}; return SGlobalState{};
auto DATA = toml::parse_file(stateFile.c_str()); auto DATA = toml::parse_file(PATH + "/state.toml");
SGlobalState state; SGlobalState state;
state.headersHashCompiled = DATA["state"]["hash"].value_or(""); state.headersHashCompiled = DATA["state"]["hash"].value_or("");
@@ -171,8 +167,15 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
std::vector<SPluginRepository> repos; std::vector<SPluginRepository> repos;
for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
const auto NAME = STATE["repository"]["name"].value_or(""); const auto NAME = STATE["repository"]["name"].value_or("");
const auto URL = STATE["repository"]["url"].value_or(""); const auto URL = STATE["repository"]["url"].value_or("");
@@ -207,8 +210,15 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
const auto STATE = toml::parse_file(stateFile.c_str()); if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
for (const auto& [key, val] : STATE) { for (const auto& [key, val] : STATE) {
if (key == "repository") if (key == "repository")
continue; continue;
@@ -221,11 +231,10 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
if (FAILED) if (FAILED)
return false; return false;
auto modifiedState = STATE; (*STATE[key].as_table()).insert_or_assign("enabled", enabled);
(*modifiedState[key].as_table()).insert_or_assign("enabled", enabled);
std::ofstream state(stateFile, std::ios::trunc); std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
state << modifiedState; state << STATE;
state.close(); state.close();
return true; return true;

View File

@@ -1,5 +1,4 @@
#pragma once #pragma once
#include <filesystem>
#include <string> #include <string>
#include <vector> #include <vector>
#include "Plugin.hpp" #include "Plugin.hpp"
@@ -10,15 +9,14 @@ struct SGlobalState {
}; };
namespace DataState { namespace DataState {
std::filesystem::path getDataStatePath(); std::string getDataStatePath();
std::string getHeadersPath(); std::string getHeadersPath();
std::vector<std::filesystem::path> getPluginStates(); void ensureStateStoreExists();
void ensureStateStoreExists(); void addNewPluginRepo(const SPluginRepository& repo);
void addNewPluginRepo(const SPluginRepository& repo); void removePluginRepo(const std::string& urlOrName);
void removePluginRepo(const std::string& urlOrName); bool pluginRepoExists(const std::string& urlOrName);
bool pluginRepoExists(const std::string& urlOrName); void updateGlobalState(const SGlobalState& state);
void updateGlobalState(const SGlobalState& state); SGlobalState getGlobalState();
SGlobalState getGlobalState(); bool setPluginEnabled(const std::string& name, bool enabled);
bool setPluginEnabled(const std::string& name, bool enabled); std::vector<SPluginRepository> getAllRepositories();
std::vector<SPluginRepository> getAllRepositories();
}; };

View File

@@ -7,8 +7,10 @@
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
#include <array>
#include <filesystem> #include <filesystem>
#include <print> #include <print>
#include <thread>
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
#include <format> #include <format>
@@ -19,56 +21,37 @@
#include <unistd.h> #include <unistd.h>
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <glaze/glaze.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}); result.reserve(buffer.size());
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
if (!proc.runSync()) result += buffer.data();
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::println("{}", verboseString("version returned: {}", HLVERCALL));
if (!HLVERCALL.contains("Tag:")) { if (!HLVERCALL.contains("Tag:")) {
std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland.")); std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland."));
@@ -82,13 +65,13 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
hlbranch = hlbranch.substr(0, hlbranch.find(" at commit ")); hlbranch = hlbranch.substr(0, hlbranch.find(" at commit "));
std::string hldate = HLVERCALL.substr(HLVERCALL.find("Date: ") + 6); std::string hldate = HLVERCALL.substr(HLVERCALL.find("Date: ") + 6);
hldate = hldate.substr(0, hldate.find('\n')); hldate = hldate.substr(0, hldate.find("\n"));
std::string hlcommits; std::string hlcommits;
if (HLVERCALL.contains("commits:")) { if (HLVERCALL.contains("commits:")) {
hlcommits = HLVERCALL.substr(HLVERCALL.find("commits:") + 9); hlcommits = HLVERCALL.substr(HLVERCALL.find("commits:") + 9);
hlcommits = hlcommits.substr(0, hlcommits.find(' ')); hlcommits = hlcommits.substr(0, hlcommits.find(" "));
} }
int commits = 0; int commits = 0;
@@ -99,18 +82,12 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits)); std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits));
auto ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits}; ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
if (running)
verRunning = ver;
else
verInstalled = ver;
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))
@@ -129,7 +106,7 @@ 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::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio"));
return false; return false;
} }
@@ -168,17 +145,17 @@ 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::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm"));
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::println(stderr, "\n{}", failureString("Could not prepare working dir for repo"));
@@ -187,7 +164,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.printMessageAbove(infoString("Cloning {}", url)); progress.printMessageAbove(infoString("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::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret));
@@ -370,14 +347,14 @@ 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()); const std::string& cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
auto headers = execAndGet(cmd); auto headers = execAndGet(cmd.c_str());
if (!headers.contains("-I/")) if (!headers.contains("-I/"))
return HEADERS_MISSING; return HEADERS_MISSING;
@@ -432,16 +409,16 @@ 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::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio"));
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) {
@@ -456,16 +433,14 @@ 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::println("\n{}", failureString("Could not prepare working dir for hl"));
return false; return false;
} }
const auto& HL_URL = m_szCustomHlUrl.empty() ? "https://github.com/hyprwm/Hyprland" : m_szCustomHlUrl; progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment."));
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning {}, this might take a moment.", HL_URL));
const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow; const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow;
@@ -477,11 +452,11 @@ bool CPluginManager::updateHeaders(bool force) {
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE)); progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE));
std::string ret = std::string ret =
execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}{}", getTempRoot(), HL_URL, USERNAME, (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(failureString("Clone failed. Retrying without shallow."));
ret = execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}", getTempRoot(), HL_URL, 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")) {
@@ -596,7 +571,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
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;
@@ -605,7 +580,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;
@@ -620,7 +595,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(infoString("Cloning {}", repo.url)); progress.printMessageAbove(infoString("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::println("{}", failureString("could not clone repo: shell returned: {}", ret));
@@ -782,7 +757,7 @@ bool CPluginManager::disablePlugin(const std::string& name) {
return ret; return ret;
} }
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload) { 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::println(stderr, "\n{}", failureString("headers are not up-to-date, please run hyprpm update."));
return LOADSTATE_HEADERS_OUTDATED; return LOADSTATE_HEADERS_OUTDATED;
@@ -791,28 +766,35 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload)
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 $HYPRLAND_INSTANCE_SIGNATURE"); std::println(stderr, "PluginManager: no $HOME or HIS");
return LOADSTATE_FAIL; return LOADSTATE_FAIL;
} }
const auto HYPRPMPATH = DataState::getDataStatePath(); const auto HYPRPMPATH = DataState::getDataStatePath() + "/";
const auto json = glz::read_json<glz::json_t::array_t>(execAndGet("hyprctl plugins list -j")); auto pluginLines = execAndGet("hyprctl plugins list | grep Plugin");
if (!json) {
std::println(stderr, "PluginManager: couldn't parse hyprctl output");
return LOADSTATE_FAIL;
}
std::vector<std::string> loadedPlugins; std::vector<std::string> loadedPlugins;
for (const auto& plugin : json.value()) {
if (!plugin.is_object() || !plugin.contains("name")) {
std::println(stderr, "PluginManager: couldn't parse plugin object");
return LOADSTATE_FAIL;
}
loadedPlugins.emplace_back(plugin["name"].get<std::string>());
}
std::println("{}", successString("Ensuring plugin load state")); std::println("{}", successString("Ensuring plugin load state"));
// iterate line by line
while (!pluginLines.empty()) {
auto plLine = pluginLines.substr(0, pluginLines.find('\n'));
if (pluginLines.find('\n') != std::string::npos)
pluginLines = pluginLines.substr(pluginLines.find('\n') + 1);
else
pluginLines = "";
if (plLine.back() != ':')
continue;
plLine = plLine.substr(7);
plLine = plLine.substr(0, plLine.find(" by "));
loadedPlugins.push_back(plLine);
}
// get state // get state
const auto REPOS = DataState::getAllRepositories(); const auto REPOS = DataState::getAllRepositories();
@@ -838,20 +820,12 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload)
return ""; return "";
}; };
// if any of the loadUnloadPlugin calls return false, this is true // unload disabled plugins
// bcs that means the header version doesn't match the running version
// (and Hyprland needs to restart)
bool hyprlandVersionMismatch = false;
// unload disabled plugins (or all if forceReload is true)
for (auto const& p : loadedPlugins) { for (auto const& p : loadedPlugins) {
if (forceReload || !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::println("{}", successString("Unloaded {}", p));
hyprlandVersionMismatch = true;
} else
std::println("{}", successString("Unloaded {}", p));
} }
} }
@@ -861,31 +835,20 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload)
if (!p.enabled) if (!p.enabled)
continue; continue;
if (!forceReload && 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::println("{}", successString("Loaded {}", p.name));
hyprlandVersionMismatch = true;
} else
std::println("{}", successString("Loaded {}", p.name));
} }
} }
std::println("{}", successString("Plugin load state ensured")); std::println("{}", successString("Plugin load state ensured"));
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

View File

@@ -27,8 +27,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 {
@@ -51,10 +50,10 @@ class CPluginManager {
bool enablePlugin(const std::string& name); bool enablePlugin(const std::string& name);
bool disablePlugin(const std::string& name); bool disablePlugin(const std::string& name);
ePluginLoadStateReturn ensurePluginsLoadState(bool forceReload = false); 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);
@@ -62,7 +61,6 @@ class CPluginManager {
bool m_bVerbose = false; bool m_bVerbose = false;
bool m_bNoShallow = false; bool m_bNoShallow = false;
std::string m_szCustomHlUrl;
// will delete recursively if exists!! // will delete recursively if exists!!
bool createSafeDirectory(const std::string& path); bool createSafeDirectory(const std::string& path);

View File

@@ -29,7 +29,6 @@ constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
--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)
--no-shallow | -s Disable shallow cloning of Hyprland sources --no-shallow | -s Disable shallow cloning of Hyprland sources
--hl-url | Pass a custom hyprland source url
)#"; )#";
@@ -46,7 +45,6 @@ int main(int argc, char** argv, char** envp) {
std::vector<std::string> command; std::vector<std::string> command;
bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false; bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false;
std::string customHlUrl;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) { if (ARGS[i].starts_with("-")) {
@@ -61,13 +59,6 @@ int main(int argc, char** argv, char** envp) {
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] == "--hl-url") {
if (i + 1 >= argc) {
std::println(stderr, "Missing argument for --hl-url");
return 1;
}
customHlUrl = ARGS[i + 1];
i++;
} 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::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing."));
@@ -75,19 +66,19 @@ int main(int argc, char** argv, char** envp) {
std::println(stderr, "Unrecognized option {}", ARGS[i]); std::println(stderr, "Unrecognized option {}", ARGS[i]);
return 1; return 1;
} }
} else } else {
command.push_back(ARGS[i]); command.push_back(ARGS[i]);
}
} }
if (command.empty()) { if (command.empty()) {
std::println(stderr, "{}", HELP); std::println(stderr, "{}", HELP);
return 1; return 0;
} }
g_pPluginManager = std::make_unique<CPluginManager>(); g_pPluginManager = std::make_unique<CPluginManager>();
g_pPluginManager->m_bVerbose = verbose; g_pPluginManager->m_bVerbose = verbose;
g_pPluginManager->m_bNoShallow = noShallow; g_pPluginManager->m_bNoShallow = noShallow;
g_pPluginManager->m_szCustomHlUrl = customHlUrl;
if (command[0] == "add") { if (command[0] == "add") {
if (command.size() < 2) { if (command.size() < 2) {
@@ -112,7 +103,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;
@@ -123,9 +114,6 @@ 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)
@@ -142,10 +130,6 @@ int main(int argc, char** argv, char** envp) {
} }
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") {
@@ -163,21 +147,17 @@ int main(int argc, char** argv, char** envp) {
if (ret != LOADSTATE_OK) if (ret != LOADSTATE_OK)
return 1; return 1;
} else if (command[0] == "reload") { } else if (command[0] == "reload") {
auto ret = g_pPluginManager->ensurePluginsLoadState(force); auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret != LOADSTATE_OK) { if (ret != LOADSTATE_OK && notify) {
if (notify) { switch (ret) {
switch (ret) { case LOADSTATE_FAIL:
case LOADSTATE_FAIL: case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break; case LOADSTATE_HEADERS_OUTDATED:
case LOADSTATE_HEADERS_OUTDATED: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually.");
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually."); break;
break; default: break;
default: break;
}
} }
return 1;
} else if (notify && !notifyFail) { } else if (notify && !notifyFail) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins"); g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
} }

View File

@@ -8,7 +8,6 @@ executable(
dependency('hyprutils', version: '>= 0.1.1'), dependency('hyprutils', version: '>= 0.1.1'),
dependency('threads'), dependency('threads'),
dependency('tomlplusplus'), dependency('tomlplusplus'),
dependency('glaze', method: 'cmake'),
], ],
install: true, install: true,
) )

View File

@@ -31,20 +31,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.8.0') aquamarine = dependency('aquamarine', version: '>=0.4.2')
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.6.0')
aquamarine_version_list = aquamarine.version().split('.')
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(['-DAQUAMARINE_VERSION_MAJOR=@0@'.format(aquamarine_version_list.get(0))], language: 'cpp')
add_project_arguments(['-DAQUAMARINE_VERSION_MINOR=@0@'.format(aquamarine_version_list.get(1))], language: 'cpp')
add_project_arguments(['-DAQUAMARINE_VERSION_PATCH=@0@'.format(aquamarine_version_list.get(2))], 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'))
@@ -62,17 +50,10 @@ 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
inotify_dep = dependency('libinotify', required: false) # inotify 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 = dependency('systemd')
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') subdir('systemd')
endif endif
@@ -87,11 +68,9 @@ endif
# Generate hyprland version and populate version.h # Generate hyprland version and populate version.h
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
# Make shader files includable
run_command('sh', '-c', 'scripts/generateShaderIncludes.sh', check: true)
# Install headers # Install headers
globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.inc', check: true) globber = run_command('find', 'src', '-name', '*.h*', check: true)
headers = globber.stdout().strip().split('\n') headers = globber.stdout().strip().split('\n')
foreach file : headers foreach file : headers
install_headers(file, subdir: 'hyprland', preserve_path: true) install_headers(file, subdir: 'hyprland', preserve_path: true)
@@ -108,14 +87,11 @@ endif
subdir('protocols') subdir('protocols')
subdir('src') subdir('src')
subdir('hyprctl') subdir('hyprctl')
subdir('hyprpm/src')
subdir('assets') subdir('assets')
subdir('example') subdir('example')
subdir('docs') subdir('docs')
if get_option('hyprpm').enabled()
subdir('hyprpm/src')
endif
# Generate hyprland.pc # Generate hyprland.pc
pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig') pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')

View File

@@ -1,6 +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('hyprpm', type: 'feature', value: 'enabled', description: 'Enable hyprpm')
option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling') option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling')

View File

@@ -5,19 +5,14 @@
pkg-config, pkg-config,
pkgconf, pkgconf,
makeWrapper, makeWrapper,
cmake,
meson, meson,
ninja, ninja,
aquamarine, aquamarine,
binutils, binutils,
cairo, cairo,
epoll-shim,
git, git,
glaze,
hyprcursor, hyprcursor,
hyprgraphics,
hyprland-protocols, hyprland-protocols,
hyprland-qtutils,
hyprlang, hyprlang,
hyprutils, hyprutils,
hyprwayland-scanner, hyprwayland-scanner,
@@ -27,10 +22,9 @@
libinput, libinput,
libxkbcommon, libxkbcommon,
libuuid, libuuid,
libgbm, mesa,
pango, pango,
pciutils, pciutils,
re2,
systemd, systemd,
tomlplusplus, tomlplusplus,
udis86-hyprland, udis86-hyprland,
@@ -53,12 +47,12 @@
nvidiaPatches ? false, nvidiaPatches ? false,
hidpiXWayland ? false, hidpiXWayland ? false,
}: let }: let
inherit (builtins) baseNameOf foldl' readFile; inherit (builtins) baseNameOf foldl';
inherit (lib.asserts) assertMsg; inherit (lib.asserts) assertMsg;
inherit (lib.attrsets) mapAttrsToList; inherit (lib.attrsets) mapAttrsToList;
inherit (lib.lists) flatten concatLists optional optionals; inherit (lib.lists) flatten concatLists optional optionals;
inherit (lib.sources) cleanSourceWith cleanSource; inherit (lib.sources) cleanSourceWith cleanSource;
inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable trim; inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable;
adapters = flatten [ adapters = flatten [
stdenvAdapters.useMoldLinker stdenvAdapters.useMoldLinker
@@ -70,7 +64,7 @@ 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;
@@ -94,7 +88,6 @@ in
DATE = date; DATE = date;
DIRTY = optionalString (commit == "") "dirty"; DIRTY = optionalString (commit == "") "dirty";
HASH = commit; HASH = commit;
TAG = "v${trim (readFile "${finalAttrs.src}/VERSION")}";
depsBuildBuild = [ depsBuildBuild = [
pkg-config pkg-config
@@ -105,7 +98,6 @@ in
makeWrapper makeWrapper
meson meson
ninja ninja
cmake # needed for glaze
pkg-config pkg-config
]; ];
@@ -120,9 +112,7 @@ in
aquamarine aquamarine
cairo cairo
git git
glaze
hyprcursor hyprcursor
hyprgraphics
hyprland-protocols hyprland-protocols
hyprlang hyprlang
hyprutils hyprutils
@@ -131,10 +121,9 @@ in
libinput libinput
libuuid libuuid
libxkbcommon libxkbcommon
libgbm mesa
pango pango
pciutils pciutils
re2
tomlplusplus tomlplusplus
udis86-hyprland udis86-hyprland
wayland wayland
@@ -142,7 +131,6 @@ in
wayland-scanner wayland-scanner
xorg.libXcursor xorg.libXcursor
] ]
(optionals customStdenv.hostPlatform.isBSD [ epoll-shim ])
(optionals customStdenv.hostPlatform.isMusl [libexecinfo]) (optionals customStdenv.hostPlatform.isMusl [libexecinfo])
(optionals enableXWayland [ (optionals enableXWayland [
xorg.libxcb xorg.libxcb
@@ -155,11 +143,9 @@ in
(optional withSystemd systemd) (optional withSystemd systemd)
]; ];
strictDeps = true;
mesonBuildType = mesonBuildType =
if debug if debug
then "debug" then "debugoptimized"
else "release"; else "release";
mesonFlags = flatten [ mesonFlags = flatten [
@@ -167,8 +153,6 @@ in
"xwayland" = enableXWayland; "xwayland" = enableXWayland;
"legacy_renderer" = legacyRenderer; "legacy_renderer" = legacyRenderer;
"systemd" = withSystemd; "systemd" = withSystemd;
"uwsm" = false;
"hyprpm" = false;
}) })
(mapAttrsToList mesonBool { (mapAttrsToList mesonBool {
"b_pch" = false; "b_pch" = false;
@@ -181,7 +165,6 @@ in
wrapProgram $out/bin/Hyprland \ wrapProgram $out/bin/Hyprland \
--suffix PATH : ${makeBinPath [ --suffix PATH : ${makeBinPath [
binutils binutils
hyprland-qtutils
pciutils pciutils
pkgconf pkgconf
]} ]}
@@ -197,4 +180,4 @@ in
platforms = lib.platforms.linux; platforms = lib.platforms.linux;
mainProgram = "Hyprland"; mainProgram = "Hyprland";
}; };
}) }

View File

@@ -1,201 +0,0 @@
lib: let
inherit (lib)
attrNames
filterAttrs
foldl
generators
partition
;
inherit (lib.strings)
concatMapStrings
hasPrefix
;
/**
Convert a structured Nix attribute set into Hyprland's configuration format.
This function takes a nested attribute set and converts it into Hyprland-compatible
configuration syntax, supporting top, bottom, and regular command sections.
Commands are flattened using the `flattenAttrs` function, and attributes are formatted as
`key = value` pairs. Lists are expanded as duplicate keys to match Hyprland's expected format.
Configuration:
* `topCommandsPrefixes` - A list of prefixes to define **top** commands (default: `["$"]`).
* `bottomCommandsPrefixes` - A list of prefixes to define **bottom** commands (default: `[]`).
Attention:
- The function ensures top commands appear **first** and bottom commands **last**.
- The generated configuration is a **single string**, suitable for writing to a config file.
- Lists are converted into multiple entries, ensuring compatibility with Hyprland.
# Inputs
Structured function argument:
: topCommandsPrefixes (optional, default: `["$"]`)
: A list of prefixes that define **top** commands. Any key starting with one of these
prefixes will be placed at the beginning of the configuration.
: bottomCommandsPrefixes (optional, default: `[]`)
: A list of prefixes that define **bottom** commands. Any key starting with one of these
prefixes will be placed at the end of the configuration.
Value:
: The attribute set to be converted to Hyprland configuration format.
# Type
```
toHyprlang :: AttrSet -> AttrSet -> String
```
# Examples
:::{.example}
```nix
let
config = {
"$mod" = "SUPER";
monitor = {
"HDMI-A-1" = "1920x1080@60,0x0,1";
};
exec = [
"waybar"
"dunst"
];
};
in lib.toHyprlang {} config
```
**Output:**
```nix
"$mod = SUPER"
"monitor:HDMI-A-1 = 1920x1080@60,0x0,1"
"exec = waybar"
"exec = dunst"
```
:::
*/
toHyprlang = {
topCommandsPrefixes ? ["$"],
bottomCommandsPrefixes ? [],
}: attrs: let
toHyprlang' = attrs: let
# Specially configured `toKeyValue` generator with support for duplicate keys
# and a legible key-value separator.
mkCommands = generators.toKeyValue {
mkKeyValue = generators.mkKeyValueDefault {} " = ";
listsAsDuplicateKeys = true;
indent = ""; # No indent, since we don't have nesting
};
# Flatten the attrset, combining keys in a "path" like `"a:b:c" = "x"`.
# Uses `flattenAttrs` with a colon separator.
commands = flattenAttrs (p: k: "${p}:${k}") attrs;
# General filtering function to check if a key starts with any prefix in a given list.
filterCommands = list: n:
foldl (acc: prefix: acc || hasPrefix prefix n) false list;
# Partition keys into top commands and the rest
result = partition (filterCommands topCommandsPrefixes) (attrNames commands);
topCommands = filterAttrs (n: _: builtins.elem n result.right) commands;
remainingCommands = removeAttrs commands result.right;
# Partition remaining commands into bottom commands and regular commands
result2 = partition (filterCommands bottomCommandsPrefixes) result.wrong;
bottomCommands = filterAttrs (n: _: builtins.elem n result2.right) remainingCommands;
regularCommands = removeAttrs remainingCommands result2.right;
in
# Concatenate strings from mapping `mkCommands` over top, regular, and bottom commands.
concatMapStrings mkCommands [
topCommands
regularCommands
bottomCommands
];
in
toHyprlang' attrs;
/**
Flatten a nested attribute set into a flat attribute set, using a custom key separator function.
This function recursively traverses a nested attribute set and produces a flat attribute set
where keys are joined using a user-defined function (`pred`). It allows transforming deeply
nested structures into a single-level attribute set while preserving key-value relationships.
Configuration:
* `pred` - A function `(string -> string -> string)` defining how keys should be concatenated.
# Inputs
Structured function argument:
: pred (required)
: A function that determines how parent and child keys should be combined into a single key.
It takes a `prefix` (parent key) and `key` (current key) and returns the joined key.
Value:
: The nested attribute set to be flattened.
# Type
```
flattenAttrs :: (String -> String -> String) -> AttrSet -> AttrSet
```
# Examples
:::{.example}
```nix
let
nested = {
a = "3";
b = { c = "4"; d = "5"; };
};
separator = (prefix: key: "${prefix}.${key}"); # Use dot notation
in lib.flattenAttrs separator nested
```
**Output:**
```nix
{
"a" = "3";
"b.c" = "4";
"b.d" = "5";
}
```
:::
*/
flattenAttrs = pred: attrs: let
flattenAttrs' = prefix: attrs:
builtins.foldl' (
acc: key: let
value = attrs.${key};
newKey =
if prefix == ""
then key
else pred prefix key;
in
acc
// (
if builtins.isAttrs value
then flattenAttrs' newKey value
else {"${newKey}" = value;}
)
) {} (builtins.attrNames attrs);
in
flattenAttrs' "" attrs;
in
{
inherit flattenAttrs toHyprlang;
}

View File

@@ -5,149 +5,17 @@ inputs: {
... ...
}: let }: let
inherit (pkgs.stdenv.hostPlatform) system; inherit (pkgs.stdenv.hostPlatform) system;
selflib = import ./lib.nix lib;
cfg = config.programs.hyprland; cfg = config.programs.hyprland;
package = inputs.self.packages.${system}.hyprland;
portalPackage = inputs.self.packages.${system}.xdg-desktop-portal-hyprland.override {
hyprland = cfg.finalPackage;
};
in { in {
options = { config = {
programs.hyprland = { programs.hyprland = {
plugins = lib.mkOption { package = lib.mkDefault package;
type = with lib.types; listOf (either package path); portalPackage = lib.mkDefault portalPackage;
default = [];
description = ''
List of Hyprland plugins to use. Can either be packages or
absolute plugin paths.
'';
};
settings = lib.mkOption {
type = with lib.types; let
valueType =
nullOr (oneOf [
bool
int
float
str
path
(attrsOf valueType)
(listOf valueType)
])
// {
description = "Hyprland configuration value";
};
in
valueType;
default = {};
description = ''
Hyprland configuration written in Nix. Entries with the same key
should be written as lists. Variables' and colors' names should be
quoted. See <https://wiki.hyprland.org> for more examples.
Special categories (e.g `devices`) should be written as
`"devices[device-name]"`.
::: {.note}
Use the [](#programs.hyprland.plugins) option to
declare plugins.
:::
'';
example = lib.literalExpression ''
{
decoration = {
shadow_offset = "0 5";
"col.shadow" = "rgba(00000099)";
};
"$mod" = "SUPER";
bindm = [
# mouse movements
"$mod, mouse:272, movewindow"
"$mod, mouse:273, resizewindow"
"$mod ALT, mouse:272, resizewindow"
];
}
'';
};
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
example = ''
# window resize
bind = $mod, S, submap, resize
submap = resize
binde = , right, resizeactive, 10 0
binde = , left, resizeactive, -10 0
binde = , up, resizeactive, 0 -10
binde = , down, resizeactive, 0 10
bind = , escape, submap, reset
submap = reset
'';
description = ''
Extra configuration lines to add to `/etc/xdg/hypr/hyprland.conf`.
'';
};
topPrefixes = lib.mkOption {
type = with lib.types; listOf str;
default = ["$" "bezier"];
example = ["$" "bezier" "source"];
description = ''
List of prefix of attributes to put at the top of the config.
'';
};
bottomPrefixes = lib.mkOption {
type = with lib.types; listOf str;
default = [];
example = ["source"];
description = ''
List of prefix of attributes to put at the bottom of the config.
'';
};
}; };
}; };
config = lib.mkMerge [
{
programs.hyprland = {
package = lib.mkDefault inputs.self.packages.${system}.hyprland;
portalPackage = lib.mkDefault inputs.self.packages.${system}.xdg-desktop-portal-hyprland;
};
}
(lib.mkIf cfg.enable {
environment.etc."xdg/hypr/hyprland.conf" = let
shouldGenerate = cfg.extraConfig != "" || cfg.settings != {} || cfg.plugins != [];
pluginsToHyprlang = plugins:
selflib.toHyprlang {
topCommandsPrefixes = cfg.topPrefixes;
bottomCommandsPrefixes = cfg.bottomPrefixes;
}
{
"exec-once" = let
mkEntry = entry:
if lib.types.package.check entry
then "${entry}/lib/lib${entry.pname}.so"
else entry;
hyprctl = lib.getExe' config.programs.hyprland.package "hyprctl";
in
map (p: "${hyprctl} plugin load ${mkEntry p}") cfg.plugins;
};
in
lib.mkIf shouldGenerate {
text =
lib.optionalString (cfg.plugins != [])
(pluginsToHyprlang cfg.plugins)
+ lib.optionalString (cfg.settings != {})
(selflib.toHyprlang {
topCommandsPrefixes = cfg.topPrefixes;
bottomCommandsPrefixes = cfg.bottomPrefixes;
}
cfg.settings)
+ lib.optionalString (cfg.extraConfig != "") cfg.extraConfig;
};
})
];
} }

View File

@@ -22,9 +22,7 @@ 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

View File

@@ -1,366 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="frog_color_management_v1">
<copyright>
Copyright © 2023 Joshua Ashton for Valve Software
Copyright © 2023 Xaver Hugl
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>
<description summary="experimental color management protocol">
The aim of this color management extension is to get HDR games working quickly,
and have an easy way to test implementations in the wild before the upstream
protocol is ready to be merged.
For that purpose it's intentionally limited and cut down and does not serve
all uses cases.
</description>
<interface name="frog_color_management_factory_v1" version="1">
<description summary="color management factory">
The color management factory singleton creates color managed surface objects.
</description>
<request name="destroy" type="destructor"></request>
<request name="get_color_managed_surface">
<description summary="create color management interface for surface">
</description>
<arg name="surface" type="object" interface="wl_surface"
summary="target surface" />
<arg name="callback" type="new_id" interface="frog_color_managed_surface"
summary="new color managed surface object" />
</request>
</interface>
<interface name="frog_color_managed_surface" version="1">
<description summary="color managed surface">
Interface for changing surface color management and HDR state.
An implementation must: support every part of the version
of the frog_color_managed_surface interface it exposes.
Including all known enums associated with a given version.
</description>
<request name="destroy" type="destructor">
<description summary="destroy color managed surface">
Destroying the color managed surface resets all known color
state for the surface back to 'undefined' implementation-specific
values.
</description>
</request>
<enum name="transfer_function">
<description summary="known transfer functions">
Extended information on the transfer functions described
here can be found in the Khronos Data Format specification:
https://registry.khronos.org/DataFormat/specs/1.3/dataformat.1.3.html
</description>
<entry name="undefined" value="0"
summary="specifies undefined, implementation-specific handling of the surface's transfer function." />
<entry name="srgb" value="1"
summary="specifies the sRGB non-linear EOTF. An implementation may: display this as Gamma 2.2 for the purposes of being consistent with content rendering across displays, rendering_intent and user expectations." />
<entry name="gamma_22" value="2" summary="specifies gamma 2.2 power curve as the EOTF" />
<entry name="st2084_pq" value="3"
summary="specifies the SMPTE ST2084 Perceptual Quantizer (PQ) EOTF" />
<entry name="scrgb_linear" value="4"
summary="specifies the scRGB (extended sRGB) linear EOTF. Note: Primaries outside the gamut triangle specified can be expressed with negative values for this transfer function." />
</enum>
<request name="set_known_transfer_function">
<description summary="sets a known transfer function for a surface" />
<arg name="transfer_function" type="uint" enum="transfer_function"
summary="transfer function for the surface" />
</request>
<enum name="primaries">
<description summary="known primaries" />
<entry name="undefined" value="0"
summary="specifies undefined, implementation-specific handling" />
<entry name="rec709" value="1" summary="specifies Rec.709/sRGB primaries with D65 white point" />
<entry name="rec2020" value="2"
summary="specifies Rec.2020/HDR10 primaries with D65 white point" />
</enum>
<request name="set_known_container_color_volume">
<description summary="sets the container color volume (primaries) for a surface" />
<arg name="primaries" type="uint" enum="primaries" summary="primaries for the surface" />
</request>
<enum name="render_intent">
<description summary="known render intents">
Extended information on render intents described
here can be found in ICC.1:2022:
https://www.color.org/specification/ICC.1-2022-05.pdf
</description>
<entry name="perceptual" value="0" summary="perceptual" />
</enum>
<request name="set_render_intent">
<description summary="sets the render intent for a surface">
NOTE: On a surface with "perceptual" (default) render intent, handling of the container's
color volume
is implementation-specific, and may differ between different transfer functions it is paired
with:
ie. sRGB + 709 rendering may have it's primaries widened to more of the available display's
gamut
to be be more pleasing for the viewer.
Compared to scRGB Linear + 709 being treated faithfully as 709
(including utilizing negatives out of the 709 gamut triangle)
</description>
<arg name="render_intent" type="uint" enum="render_intent"
summary="render intent for the surface" />
</request>
<request name="set_hdr_metadata">
<description summary="set HDR metadata for a surface">
Forwards HDR metadata from the client to the compositor.
HDR Metadata Infoframe as per CTA 861.G spec.
Usage of this HDR metadata is implementation specific and
outside of the scope of this protocol.
</description>
<arg name="mastering_display_primary_red_x" type="uint">
<description summary="red primary x coordinate">
Mastering Red Color Primary X Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="mastering_display_primary_red_y" type="uint">
<description summary="red primary y coordinate">
Mastering Red Color Primary Y Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="mastering_display_primary_green_x" type="uint">
<description summary="green primary x coordinate">
Mastering Green Color Primary X Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="mastering_display_primary_green_y" type="uint">
<description summary="green primary y coordinate">
Mastering Green Color Primary Y Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="mastering_display_primary_blue_x" type="uint">
<description summary="blue primary x coordinate">
Mastering Blue Color Primary X Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="mastering_display_primary_blue_y" type="uint">
<description summary="blue primary y coordinate">
Mastering Blue Color Primary Y Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="mastering_white_point_x" type="uint">
<description summary="white point x coordinate">
Mastering White Point X Coordinate of the Data.
These are coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="mastering_white_point_y" type="uint">
<description summary="white point y coordinate">
Mastering White Point Y Coordinate of the Data.
These are coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="max_display_mastering_luminance" type="uint">
<description summary="max display mastering luminance">
Max Mastering Display Luminance.
This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
</description>
</arg>
<arg name="min_display_mastering_luminance" type="uint">
<description summary="min display mastering luminance">
Min Mastering Display Luminance.
This value is coded as an unsigned 16-bit value in units of
0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF
represents 6.5535 cd/m2.
</description>
</arg>
<arg name="max_cll" type="uint">
<description summary="max content light level">
Max Content Light Level.
This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
</description>
</arg>
<arg name="max_fall" type="uint">
<description summary="max frame average light level">
Max Frame Average Light Level.
This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
</description>
</arg>
</request>
<event name="preferred_metadata">
<description summary="preferred metadata for a surface">
Current preferred metadata for a surface.
The application should use this information to tone-map its buffers
to this target before committing.
This metadata does not necessarily correspond to any physical output, but
rather what the compositor thinks would be best for a given surface.
</description>
<arg name="transfer_function" type="uint" enum="transfer_function">
<description summary="output's current transfer function">
Specifies a known transfer function that corresponds to the
output the surface is targeting.
</description>
</arg>
<arg name="output_display_primary_red_x" type="uint">
<description summary="red primary x coordinate">
Output Red Color Primary X Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="output_display_primary_red_y" type="uint">
<description summary="red primary y coordinate">
Output Red Color Primary Y Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="output_display_primary_green_x" type="uint">
<description summary="green primary x coordinate">
Output Green Color Primary X Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="output_display_primary_green_y" type="uint">
<description summary="green primary y coordinate">
Output Green Color Primary Y Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="output_display_primary_blue_x" type="uint">
<description summary="blue primary x coordinate">
Output Blue Color Primary X Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="output_display_primary_blue_y" type="uint">
<description summary="blue primary y coordinate">
Output Blue Color Primary Y Coordinate of the Data.
Coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="output_white_point_x" type="uint">
<description summary="white point x coordinate">
Output White Point X Coordinate of the Data.
These are coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="output_white_point_y" type="uint">
<description summary="white point y coordinate">
Output White Point Y Coordinate of the Data.
These are coded as unsigned 16-bit values in units of
0.00002, where 0x0000 represents zero and 0xC350
represents 1.0000.
</description>
</arg>
<arg name="max_luminance" type="uint">
<description summary="maximum luminance">
Max Output Luminance
The max luminance in nits that the output is capable of rendering in small areas.
Content should: not exceed this value to avoid clipping.
This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
</description>
</arg>
<arg name="min_luminance" type="uint">
<description summary="minimum luminance">
Min Output Luminance
The min luminance that the output is capable of rendering.
Content should: not exceed this value to avoid clipping.
This value is coded as an unsigned 16-bit value in units of
0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF
represents 6.5535 cd/m2.
</description>
</arg>
<arg name="max_full_frame_luminance" type="uint">
<description summary="maximum full frame luminance">
Max Full Frame Luminance
The max luminance in nits that the output is capable of rendering for the
full frame sustained.
This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
</description>
</arg>
</event>
</interface>
</protocol>

View File

@@ -1,13 +1,13 @@
wayland_protos = dependency( wayland_protos = dependency(
'wayland-protocols', 'wayland-protocols',
version: '>=1.41', version: '>=1.32',
fallback: 'wayland-protocols', fallback: 'wayland-protocols',
default_options: ['tests=false'], default_options: ['tests=false'],
) )
hyprland_protos = dependency( hyprland_protos = dependency(
'hyprland-protocols', 'hyprland-protocols',
version: '>=0.6.2', version: '>=0.4',
fallback: 'hyprland-protocols', fallback: 'hyprland-protocols',
) )
@@ -33,14 +33,10 @@ protocols = [
'wayland-drm.xml', 'wayland-drm.xml',
'wlr-data-control-unstable-v1.xml', 'wlr-data-control-unstable-v1.xml',
'wlr-screencopy-unstable-v1.xml', 'wlr-screencopy-unstable-v1.xml',
'xx-color-management-v4.xml',
'frog-color-management-v1.xml',
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', hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-surface-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-lock-notify-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',
@@ -70,8 +66,6 @@ protocols = [
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', wayland_protocol_dir / 'staging/security-context/security-context-v1.xml',
wayland_protocol_dir / 'staging/content-type/content-type-v1.xml',
wayland_protocol_dir / 'staging/color-management/color-management-v1.xml',
] ]
wl_protocols = [] wl_protocols = []
@@ -87,7 +81,7 @@ foreach protocol : protocols
endforeach endforeach
# wayland.xml generation # wayland.xml generation
wayland_scanner = dependency('wayland-scanner', native: true) wayland_scanner = dependency('wayland-scanner')
wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir') wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir')
wayland_xml = wayland_scanner_datadir / 'wayland.xml' wayland_xml = wayland_scanner_datadir / 'wayland.xml'

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +0,0 @@
#!/bin/sh
SHADERS_SRC="./src/render/shaders/glsl"
echo "-- Generating shader includes"
if [ ! -d ./src/render/shaders ]; then
mkdir ./src/render/shaders
fi
echo '#pragma once' > ./src/render/shaders/Shaders.hpp
echo '#include <map>' >> ./src/render/shaders/Shaders.hpp
echo 'static const std::map<std::string, std::string> SHADERS = {' >> ./src/render/shaders/Shaders.hpp
for filename in `ls ${SHADERS_SRC}`; do
echo "-- ${filename}"
{ echo 'R"#('; cat ${SHADERS_SRC}/${filename}; echo ')#"'; } > ./src/render/shaders/${filename}.inc
echo "{\"${filename}\"," >> ./src/render/shaders/Shaders.hpp
echo "#include \"./${filename}.inc\"" >> ./src/render/shaders/Shaders.hpp
echo "}," >> ./src/render/shaders/Shaders.hpp
done
echo '};' >> ./src/render/shaders/Shaders.hpp

View File

@@ -1,13 +1,4 @@
#!/bin/sh #!/bin/sh
# if the git directory doesn't exist, don't gather data to avoid overwriting, unless
# the version file is missing altogether (otherwise compiling will fail)
if [ ! -d ./.git ]; then
if [ -f ./src/version.h ]; then
exit 0
fi
fi
cp -fr ./src/version.h.in ./src/version.h cp -fr ./src/version.h.in ./src/version.h
HASH=${HASH-$(git rev-parse HEAD)} HASH=${HASH-$(git rev-parse HEAD)}

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,41 @@
#pragma once #pragma once
#include <memory>
#include <deque>
#include <list>
#include <sys/resource.h> #include <sys/resource.h>
#include "defines.hpp"
#include "debug/Log.hpp"
#include "events/Events.hpp"
#include "config/ConfigManager.hpp"
#include "managers/ThreadManager.hpp"
#include "managers/XWaylandManager.hpp" #include "managers/XWaylandManager.hpp"
#include "managers/input/InputManager.hpp"
#include "managers/LayoutManager.hpp"
#include "managers/KeybindManager.hpp" #include "managers/KeybindManager.hpp"
#include "managers/AnimationManager.hpp"
#include "managers/EventManager.hpp"
#include "managers/ProtocolManager.hpp"
#include "managers/SessionLockManager.hpp" #include "managers/SessionLockManager.hpp"
#include "managers/HookSystemManager.hpp"
#include "debug/HyprDebugOverlay.hpp"
#include "debug/HyprNotificationOverlay.hpp"
#include "helpers/Monitor.hpp"
#include "desktop/Workspace.hpp"
#include "desktop/Window.hpp" #include "desktop/Window.hpp"
#include "protocols/types/ColorManagement.hpp" #include "render/Renderer.hpp"
#include "render/OpenGL.hpp"
#include "hyprerror/HyprError.hpp"
#include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp"
#include <aquamarine/backend/Backend.hpp> #include <aquamarine/backend/Backend.hpp>
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
class CWLSurfaceResource; class CWLSurfaceResource;
struct SWorkspaceRule;
enum eManagersInitStage : uint8_t { enum eManagersInitStage {
STAGE_PRIORITY = 0, STAGE_PRIORITY = 0,
STAGE_BASICINIT, STAGE_BASICINIT,
STAGE_LATE STAGE_LATE
@@ -22,11 +43,11 @@ enum eManagersInitStage : uint8_t {
class CCompositor { class CCompositor {
public: public:
CCompositor(bool onlyConfig = false); CCompositor();
~CCompositor(); ~CCompositor();
wl_display* m_sWLDisplay = nullptr; wl_display* m_sWLDisplay;
wl_event_loop* m_sWLEventLoop = nullptr; wl_event_loop* m_sWLEventLoop;
int m_iDRMFD = -1; int m_iDRMFD = -1;
bool m_bInitialized = false; bool m_bInitialized = false;
SP<Aquamarine::CBackend> m_pAqBackend; SP<Aquamarine::CBackend> m_pAqBackend;
@@ -52,6 +73,8 @@ class CCompositor {
void startCompositor(); void startCompositor();
void stopCompositor(); void stopCompositor();
void cleanup(); void cleanup();
void createLockFile();
void removeLockFile();
void bumpNofile(); void bumpNofile();
void restoreNofile(); void restoreNofile();
@@ -67,11 +90,10 @@ class CCompositor {
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 PHLMONITORREF m_pUnsafeOutput; // 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;
bool m_bWantsXwayland = true; bool m_bEnableXwayland = true;
bool m_bOnlyConfigVerification = false;
// ------------------------------------------------- // // ------------------------------------------------- //
@@ -81,7 +103,7 @@ class CCompositor {
PHLMONITOR getMonitorFromCursor(); PHLMONITOR getMonitorFromCursor();
PHLMONITOR getMonitorFromVector(const Vector2D&); PHLMONITOR getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(PHLWINDOW); void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr, bool preserveFocusHistory = false); 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(PHLMONITOR);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
@@ -93,24 +115,34 @@ class CCompositor {
PHLMONITOR getRealMonitorFromOutput(SP<Aquamarine::IOutput>); PHLMONITOR 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);
PHLWINDOW getWindowInDirection(PHLWINDOW, char); PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false); PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getWindowCycle(PHLWINDOW cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool prev = false); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool next = false);
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 PHLMONITOR monitor = nullptr);
PHLMONITOR getMonitorInDirection(const char&); PHLMONITOR getMonitorInDirection(const char&);
PHLMONITOR getMonitorInDirection(PHLMONITOR, const char&); PHLMONITOR getMonitorInDirection(PHLMONITOR, 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, PHLMONITOR, bool noWarpCursor = false);
@@ -119,7 +151,8 @@ class CCompositor {
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 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);
@@ -132,8 +165,10 @@ 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 renameWorkspace(const WORKSPACEID&, const std::string& name = "");
void setActiveMonitor(PHLMONITOR); void setActiveMonitor(PHLMONITOR);
bool isWorkspaceSpecial(const WORKSPACEID&); bool isWorkspaceSpecial(const WORKSPACEID&);
WORKSPACEID getNewSpecialID(); WORKSPACEID getNewSpecialID();
@@ -146,13 +181,10 @@ class CCompositor {
void setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, double scale); void setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, double scale);
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform); void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates(); void updateSuspendedStates();
PHLWINDOW windowForCPointer(CWindow*);
void onNewMonitor(SP<Aquamarine::IOutput> output); void onNewMonitor(SP<Aquamarine::IOutput> output);
void ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules, PHLWORKSPACE pWorkspace = nullptr);
NColorManagement::SImageDescription getPreferredImageDescription(); std::string explicitConfigPath;
bool shouldChangePreferredImageDescription();
std::string explicitConfigPath;
private: private:
void initAllSignals(); void initAllSignals();
@@ -161,13 +193,10 @@ class CCompositor {
void setRandomSplash(); void setRandomSplash();
void initManagers(eManagersInitStage stage); void initManagers(eManagersInitStage stage);
void prepareFallbackOutput(); void prepareFallbackOutput();
void createLockFile();
void removeLockFile();
void setMallocThreshold();
uint64_t m_iHyprlandPID = 0; uint64_t m_iHyprlandPID = 0;
wl_event_source* m_critSigSource = nullptr; wl_event_source* m_critSigSource = nullptr;
rlimit m_sOriginalNofile = {}; rlimit m_sOriginalNofile = {0};
}; };
inline UP<CCompositor> g_pCompositor; inline std::unique_ptr<CCompositor> g_pCompositor;

View File

@@ -3,11 +3,11 @@
#include "helpers/math/Math.hpp" #include "helpers/math/Math.hpp"
#include <functional> #include <functional>
#include <any> #include <any>
#include <string>
#include <algorithm>
#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,
@@ -17,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 */
@@ -29,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,
@@ -41,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
}; };
@@ -52,12 +52,6 @@ struct SHyprCtlCommand {
std::function<std::string(eHyprCtlOutputFormat, std::string)> fn; std::function<std::string(eHyprCtlOutputFormat, std::string)> fn;
}; };
struct SDispatchResult {
bool passEvent = false;
bool success = true;
std::string error;
};
typedef int64_t WINDOWID; typedef int64_t WINDOWID;
typedef int64_t MONITORID; typedef int64_t MONITORID;
typedef int64_t WORKSPACEID; typedef int64_t WORKSPACEID;

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
@@ -11,7 +11,7 @@ enum eConfigValueDataTypes : int8_t {
class ICustomConfigValueData { class ICustomConfigValueData {
public: public:
virtual ~ICustomConfigValueData() = default; virtual ~ICustomConfigValueData() = 0;
virtual eConfigValueDataTypes getDataType() = 0; virtual eConfigValueDataTypes getDataType() = 0;
@@ -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

@@ -139,12 +139,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{0, 0, 20}, .data = SConfigOptionDescription::SRangeData{0, 0, 20},
}, },
SConfigOptionDescription{
.value = "decoration:rounding_power",
.description = "rouding power of corners (2 is a circle)",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{2, 2, 10},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:active_opacity", .value = "decoration:active_opacity",
.description = "opacity of active windows. [0.0 - 1.0]", .description = "opacity of active windows. [0.0 - 1.0]",
@@ -247,110 +241,92 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_STRING_LONG, .type = CONFIG_OPTION_STRING_LONG,
.data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
}, },
SConfigOptionDescription{
.value = "decoration:border_part_of_window",
.description = "whether the border should be treated as a part of the window.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
/* /*
* blur: * blur:
*/ */
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:enabled", .value = "blur:enabled",
.description = "enable kawase window background blur", .description = "enable kawase window background blur",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:size", .value = "blur:size",
.description = "blur size (distance)", .description = "blur size (distance)",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{8, 0, 100}, .data = SConfigOptionDescription::SRangeData{8, 0, 100},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:passes", .value = "blur:passes",
.description = "the amount of passes to perform", .description = "the amount of passes to perform",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 10}, .data = SConfigOptionDescription::SRangeData{1, 0, 10},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration: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 = "decoration:blur:new_optimizations", .value = "blur:new_optimizations",
.description = "whether to enable further optimizations to the blur. Recommended to leave on, as it will massively improve performance.", .description = "whether to enable further optimizations to the blur. Recommended to leave on, as it will massively improve performance.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:xray", .value = "blur:xray",
.description = "if enabled, floating windows will ignore tiled windows in their blur. Only available if blur_new_optimizations is true. Will reduce overhead on floating " .description = "if enabled, floating windows will ignore tiled windows in their blur. Only available if blur_new_optimizations is true. Will reduce overhead on floating "
"blur significantly.", "blur significantly.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:noise", .value = "blur:noise",
.description = "how much noise to apply. [0.0 - 1.0]", .description = "how much noise to apply. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.0117, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.0117, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:contrast", .value = "blur:contrast",
.description = "contrast modulation for blur. [0.0 - 2.0]", .description = "contrast modulation for blur. [0.0 - 2.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.8916, 0, 2}, .data = SConfigOptionDescription::SFloatData{0.8916, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:brightness", .value = "blur:brightness",
.description = "brightness modulation for blur. [0.0 - 2.0]", .description = "brightness modulation for blur. [0.0 - 2.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.8172, 0, 2}, .data = SConfigOptionDescription::SFloatData{0.8172, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:vibrancy", .value = "blur:vibrancy",
.description = "Increase saturation of blurred colors. [0.0 - 1.0]", .description = "Increase saturation of blurred colors. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.1696, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.1696, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:vibrancy_darkness", .value = "blur:vibrancy_darkness",
.description = "How strong the effect of vibrancy is on dark areas . [0.0 - 1.0]", .description = "How strong the effect of vibrancy is on dark areas . [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0, 0, 1}, .data = SConfigOptionDescription::SFloatData{0, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:special", .value = "blur:special",
.description = "whether to blur behind the special workspace (note: expensive)", .description = "whether to blur behind the special workspace (note: expensive)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:popups", .value = "blur:popups",
.description = "whether to blur popups (e.g. right-click menus)", .description = "whether to blur popups (e.g. right-click menus)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:popups_ignorealpha", .value = "blur:popups_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},
},
SConfigOptionDescription{
.value = "decoration:blur:input_methods",
.description = "whether to blur input methods (e.g. fcitx5)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "decoration: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]", .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, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
@@ -507,12 +483,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 3}, .data = SConfigOptionDescription::SRangeData{1, 0, 3},
}, },
SConfigOptionDescription{
.value = "input:follow_mouse_threshold",
.description = "The smallest distance in logical pixels the mouse needs to travel for the window under it to get focused. Works only with follow_mouse = 1.",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "input:focus_on_close", .value = "input:focus_on_close",
.description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift " .description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift "
@@ -614,18 +584,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 = "input:touchpad:flip_x",
.description = "Inverts the horizontal movement of the touchpad",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "input:touchpad:flip_y",
.description = "Inverts the vertical movement of the touchpad",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* input:touchdevice: * input:touchdevice:
@@ -662,22 +620,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.",
@@ -833,25 +785,25 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_active", .value = "general:col.border_active",
.description = "border color for inactive windows", .description = "border color for inactive windows",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66ffff00"}, .data = SConfigOptionDescription::SGradientData{"0x66ffff00"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_inactive", .value = "general:col.border_inactive",
.description = "border color for the active window", .description = "border color for the active window",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66777700"}, .data = SConfigOptionDescription::SGradientData{"0x66777700"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_locked_inactive", .value = "general:col.border_locked_active",
.description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)", .description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66ff5500"}, .data = SConfigOptionDescription::SGradientData{"0x66ff5500"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_locked_active", .value = "general:col.border_locked_inactive",
.description = "active border color for window that cannot be added to a group", .description = "active border color for window that cannot be added to a group",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66775500"}, .data = SConfigOptionDescription::SGradientData{"0x66775500"},
@@ -907,7 +859,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "group:groupbar:gradients", .value = "group:groupbar:gradients",
.description = "enables gradients", .description = "enables gradients",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:height", .value = "group:groupbar:height",
@@ -915,12 +867,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{14, 1, 64}, .data = SConfigOptionDescription::SRangeData{14, 1, 64},
}, },
SConfigOptionDescription{
.value = "group:groupbar:indicator_height",
.description = "height of the groupbar indicator",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{3, 1, 64},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:stacked", .value = "group:groupbar:stacked",
.description = "render the groupbar as a vertical stack", .description = "render the groupbar as a vertical stack",
@@ -945,30 +891,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:groupbar:rounding",
.description = "how much to round the groupbar",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:gradient_rounding",
.description = "how much to round the groupbar gradient",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:round_only_edges",
.description = "if yes, will only round at the groupbar edges",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:groupbar:gradient_round_only_edges",
.description = "if yes, will only round at the groupbar gradient edges",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:text_color", .value = "group:groupbar:text_color",
.description = "controls the group bar text color", .description = "controls the group bar text color",
@@ -999,30 +921,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_COLOR, .type = CONFIG_OPTION_COLOR,
.data = SConfigOptionDescription::SColorData{0x66775500}, .data = SConfigOptionDescription::SColorData{0x66775500},
}, },
SConfigOptionDescription{
.value = "group:groupbar:gaps_out",
.description = "gap between gradients and window",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:gaps_in",
.description = "gap between gradients",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:keep_upper_gap",
.description = "keep an upper gap above gradient",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:groupbar:text_offset",
.description = "set an offset for a text",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SRangeData{0, -20, 20},
},
/* /*
* misc: * misc:
@@ -1072,9 +970,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "misc:vrr", .value = "misc:vrr",
.description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only, 3 - fullscreen with game or video content type [0/1/2/3]", .description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only [0/1/2]",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 3}, .data = SConfigOptionDescription::SRangeData{0, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "misc:mouse_move_enables_dpms", .value = "misc:mouse_move_enables_dpms",
@@ -1217,30 +1115,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},
},
SConfigOptionDescription{
.value = "misc:enable_anr_dialog",
.description = "whether to enable the ANR (app not responding) dialog when your apps hang",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "misc:anr_missed_pings",
.description = "number of missed pings before showing the ANR dialog",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 1, 10},
},
/* /*
* binds: * binds:
@@ -1264,12 +1138,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 = "binds:hide_special_on_workspace_change",
.description = "If enabled, changing the active workspace (including to itself) will hide the special workspace on the monitor where the newly active workspace resides.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "binds:allow_workspace_cycles", .value = "binds:allow_workspace_cycles",
.description = "If enabled, workspaces dont forget their previous workspace, so cycles can be created by switching to the first workspace in a sequence, then endlessly " .description = "If enabled, workspaces dont forget their previous workspace, so cycles can be created by switching to the first workspace in a sequence, then endlessly "
@@ -1300,13 +1168,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "binds:movefocus_cycles_fullscreen", .value = "binds:movefocus_cycles_fullscreen",
.description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.", .description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .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",
@@ -1320,12 +1182,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:
@@ -1349,12 +1205,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 = "xwayland:create_abstract_socket",
.description = "Create the abstract Unix domain socket for XWayland",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* opengl: * opengl:
@@ -1366,6 +1216,13 @@ 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 = "opengl:force_introspection",
.description = "forces introspection at all times. Introspection is aimed at reducing GPU usage in certain cases, but might cause graphical glitches on nvidia. 0 - "
"nothing, 1 - force always on, 2 - force always on if nvidia",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 2},
},
/* /*
* render: * render:
@@ -1386,57 +1243,33 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
SConfigOptionDescription{ SConfigOptionDescription{
.value = "render:direct_scanout", .value = "render:direct_scanout",
.description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also " .description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also "
"recommended to set this to false if the fullscreen application shows graphical glitches. 0 - off, 1 - on, 2 - auto (on with content type 'game')", "recommended to set this to false if the fullscreen application shows graphical glitches.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 2},
},
SConfigOptionDescription{
.value = "render:expand_undersized_textures",
.description = "Whether to expand textures that have not yet resized to be larger, or to just stretch them instead.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "render:xp_mode",
.description = "Disable back buffer and bottom layer rendering.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "render:ctm_animation",
.description = "Whether to enable a fade animation for CTM changes (hyprsunset). 2 means 'auto' (Yes on everything but Nvidia).",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 2},
},
SConfigOptionDescription{
.value = "render:cm_fs_passthrough",
.description = "Passthrough color settings for fullscreen apps when possible",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2},
},
SConfigOptionDescription{
.value = "render:cm_enabled",
.description = "Enable Color Management pipelines (requires restart to fully take effect)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
}, },
/* /*
* cursor: * cursor:
*/ */
SConfigOptionDescription{
.value = "cursor:use_nearest_neighbor",
.description = "sync xcursor theme with gsettings, it applies cursor-theme and cursor-size on theme load to gsettings making most CSD gtk based clients use same xcursor "
"theme and size.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_hardware_cursors", .value = "cursor:no_hardware_cursors",
.description = "disables hardware cursors. Auto = disable when tearing", .description = "disables hardware cursors",
.type = CONFIG_OPTION_CHOICE, .type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"}, .data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_break_fs_vrr", .value = "cursor:no_break_fs_vrr",
.description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (may require no_hardware_cursors = true) " .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)",
"0 - off, 1 - on, 2 - auto (on with content type 'game')", .type = CONFIG_OPTION_BOOL,
.type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SBoolData{false},
.data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:min_refresh_rate", .value = "cursor:min_refresh_rate",
@@ -1470,16 +1303,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{
.value = "cursor:warp_on_toggle_special",
.description = "Move the cursor to the last focused window when toggling a special workspace. Options: 0 (Disabled), 1 (Enabled), "
"2 (Force - ignores cursor:no_warps option)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:default_monitor", .value = "cursor:default_monitor",
@@ -1518,37 +1344,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,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "cursor:sync_gsettings_theme",
.description = "sync xcursor theme with gsettings, it applies cursor-theme and cursor-size on theme load to gsettings making most CSD gtk based clients use same xcursor "
"theme and size.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "cursor:warp_back_after_non_mouse_input",
.description = "warp the cursor back to where it was after using a non-mouse input to move it, and then returning back to mouse.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/*
* ecosystem:
*/
SConfigOptionDescription{
.value = "ecosystem:no_update_news",
.description = "disable the popup that shows up when you update hyprland to a new version.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "ecosystem:no_donation_nag",
.description = "disable the popup that shows up twice a year encouraging to donate.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
@@ -1605,6 +1402,12 @@ 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 = "debug:watchdog_timeout",
.description = "sets the timeout in seconds for watchdog to abort processing of a signal of the main thread. Set to 0 to disable.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{5, 0, 20},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "debug:disable_scale_checks", .value = "debug:disable_scale_checks",
.description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.", .description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.",
@@ -1629,24 +1432,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 = "debug:log_damage",
.description = "enables logging the damage.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "debug:pass",
.description = "enables render pass debugging.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "debug:full_cm_proto",
.description = "claims support for all cm proto features (requires restart)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* dwindle: * dwindle:
@@ -1776,20 +1561,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "master:slave_count_for_center_master", .value = "master:always_center_master",
.description = "when using orientation=center, make the master window centered only when at least this many slave windows are open. (Set 0 to always_center_master)", .description = "when using orientation=center, keep the master window centered, even when it is the only window in the workspace.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 10}, //##TODO RANGE?
},
SConfigOptionDescription{
.value = "master:center_master_slaves_on_right",
.description = "set if the slaves should appear on right of master when slave_count_for_center_master > 2",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:center_ignores_reserved",
.description = "centers the master window on monitor ignoring reserved areas",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
@@ -1807,16 +1580,4 @@ 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 = "experimental:xx_color_management_v4",
.description = "enable color management protocol",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:always_keep_position",
.description = "whether to keep the master window in its configured position when there are no slave windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +1,33 @@
#pragma once #pragma once
#include <hyprutils/animation/AnimationConfig.hpp>
#define CONFIG_MANAGER_H #define CONFIG_MANAGER_H
#include <map> #include <map>
#include "../debug/Log.hpp"
#include <unordered_map> #include <unordered_map>
#include "../defines.hpp" #include "../defines.hpp"
#include <variant> #include <variant>
#include <vector> #include <vector>
#include <deque>
#include <algorithm>
#include <regex>
#include <optional> #include <optional>
#include <functional> #include <functional>
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include "../helpers/WLClasses.hpp"
#include "../helpers/Monitor.hpp" #include "../helpers/Monitor.hpp"
#include "../helpers/varlist/VarList.hpp"
#include "../desktop/Window.hpp" #include "../desktop/Window.hpp"
#include "../desktop/LayerRule.hpp" #include "../desktop/LayerSurface.hpp"
#include "defaultConfig.hpp"
#include "ConfigDataValues.hpp" #include "ConfigDataValues.hpp"
#include "../SharedDefs.hpp"
#include "../helpers/Color.hpp"
#include "../desktop/DesktopTypes.hpp"
#include "../helpers/memory/Memory.hpp"
#include "../desktop/WindowRule.hpp"
#include "../managers/XWaylandManager.hpp"
#include <hyprlang.hpp> #include <hyprlang.hpp>
#define INITANIMCFG(name) animationConfig[name] = {}
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
#define HANDLE void* #define HANDLE void*
struct SWorkspaceRule { struct SWorkspaceRule {
@@ -53,14 +56,26 @@ struct SMonitorAdditionalReservedArea {
int right = 0; int right = 0;
}; };
struct SAnimationPropertyConfig {
bool overridden = true;
std::string internalBezier = "";
std::string internalStyle = "";
float internalSpeed = 0.f;
int internalEnabled = -1;
SAnimationPropertyConfig* pValues = nullptr;
SAnimationPropertyConfig* pParentAnimation = nullptr;
};
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 = "";
}; };
@@ -69,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,
@@ -81,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),
}; };
@@ -104,7 +119,7 @@ struct SConfigOptionDescription {
}; };
struct SColorData { struct SColorData {
CHyprColor color; CColor color;
}; };
struct SChoiceData { struct SChoiceData {
@@ -133,39 +148,12 @@ struct SConfigOptionDescription {
std::variant<SBoolData, SRangeData, SFloatData, SStringData, SColorData, SChoiceData, SGradientData, SVectorData> data; std::variant<SBoolData, SRangeData, SFloatData, SStringData, SColorData, SChoiceData, SGradientData, SVectorData> data;
}; };
struct SFirstExecRequest {
std::string exec = "";
bool withRules = false;
};
struct SFloatCache {
size_t hash;
SFloatCache(PHLWINDOW window) {
hash = std::hash<std::string>{}(window->m_szClass) ^ (std::hash<std::string>{}(window->m_szTitle) << 1);
}
bool operator==(const SFloatCache& other) const {
return hash == other.hash;
}
};
namespace std {
template <>
struct hash<SFloatCache> {
size_t operator()(const SFloatCache& id) const {
return id.hash;
}
};
}
class CConfigManager { class CConfigManager {
public: public:
CConfigManager(); CConfigManager();
void tick();
void init(); void init();
void reload();
std::string verify();
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = ""); int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = ""); float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
@@ -177,8 +165,9 @@ class CConfigManager {
void* const* getConfigValuePtr(const std::string&); void* const* getConfigValuePtr(const std::string&);
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = ""); Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
std::string getMainConfigPath(); void onPluginLoadUnload(const std::string& name, bool load);
std::string getConfigString(); static std::string getMainConfigPath();
const std::string getConfigString();
SMonitorRule getMonitorRuleFor(const PHLMONITOR); SMonitorRule getMonitorRuleFor(const PHLMONITOR);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
@@ -186,128 +175,139 @@ class CConfigManager {
PHLMONITOR getBoundMonitorForWS(const std::string&); PHLMONITOR 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);
void ensurePersistentWorkspacesPresent();
const std::vector<SConfigOptionDescription>& getAllDescriptions(); const std::vector<SConfigOptionDescription>& getAllDescriptions();
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas; std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
const std::unordered_map<std::string, SP<Hyprutils::Animation::SAnimationPropertyConfig>>& getAnimationConfig(); std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value); void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value);
void addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fun, Hyprlang::SHandlerOptions opts = {}); void addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fun, Hyprlang::SHandlerOptions opts = {});
void removePluginConfig(HANDLE handle); void removePluginConfig(HANDLE handle);
// no-op when done. // no-op when done.
void dispatchExecOnce(); void dispatchExecOnce();
void dispatchExecShutdown(); void dispatchExecShutdown();
void performMonitorReload(); void performMonitorReload();
void ensureMonitorStatus(); void appendMonitorRule(const SMonitorRule&);
void ensureVRR(PHLMONITOR pMonitor = nullptr); bool replaceMonitorRule(const SMonitorRule&);
void ensureMonitorStatus();
void ensureVRR(PHLMONITOR pMonitor = nullptr);
bool shouldUseSoftwareCursors(PHLMONITOR pMonitor); bool shouldUseSoftwareCursors();
void updateWatcher();
std::string parseKeyword(const std::string&, const std::string&); std::string parseKeyword(const std::string&, const std::string&);
void addParseError(const std::string&); void addParseError(const std::string&);
SP<Hyprutils::Animation::SAnimationPropertyConfig> getAnimationPropertyConfig(const std::string&); SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
void addExecRule(const SExecRequestedRule&); void addExecRule(const SExecRequestedRule&);
void handlePluginLoads(); void handlePluginLoads();
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> handleExec(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> handleExecRawOnce(const std::string&, const std::string&); std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleExecShutdown(const std::string&, const std::string&); std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&); std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&); std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&); std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&); std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(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::optional<std::string> handlePermission(const std::string&, const std::string&);
std::string configCurrentPath; std::string configCurrentPath;
bool m_bWantsMonitorReload = false; std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(PHLWINDOW)>> mbWindowProperties = {
bool m_bNoMonitorReload = false; {"allowsinput", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking {"dimaround", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.dimAround; }},
bool m_bLastConfigVerificationWasSuccessful = true; {"decorate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }},
};
void storeFloatingSize(PHLWINDOW window, const Vector2D& size); std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(PHLWINDOW)>> miWindowProperties = {
std::optional<Vector2D> getStoredFloatingSize(PHLWINDOW window); {"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
private: private:
UP<Hyprlang::CConfig> m_pConfig; std::unique_ptr<Hyprlang::CConfig> m_pConfig;
std::vector<std::string> m_configPaths; std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
Hyprutils::Animation::CAnimationConfigTree m_AnimationTree; std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
std::vector<std::string> m_vDeclaredPlugins; std::vector<std::string> m_vDeclaredPlugins;
std::vector<SPluginKeyword> pluginKeywords; std::vector<SPluginKeyword> pluginKeywords;
std::vector<SPluginVariable> pluginVariables; std::vector<SPluginVariable> pluginVariables;
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::deque<std::string> firstExecRequests;
std::deque<std::string> finalExecRequests;
std::vector<SFirstExecRequest> firstExecRequests; // bool is for if with rules std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::vector<std::string> finalExecRequests; std::string m_szConfigErrors = "";
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_szConfigErrors = "";
uint32_t m_configValueNumber = 0;
// internal methods // internal methods
void updateBlurredLS(const std::string&, const bool); void setAnimForChildren(SAnimationPropertyConfig* const);
void setDefaultAnimationVars(); void updateBlurredLS(const std::string&, const bool);
std::optional<std::string> resetHLConfig(); void setDefaultAnimationVars();
std::optional<std::string> generateConfig(std::string configPath); std::optional<std::string> resetHLConfig();
std::optional<std::string> verifyConfigExists(); static std::optional<std::string> generateConfig(std::string configPath);
void postConfigReload(const Hyprlang::CParseResult& result); static std::optional<std::string> verifyConfigExists();
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); void postConfigReload(const Hyprlang::CParseResult& result);
void reload();
void registerConfigVar(const char* name, const Hyprlang::INT& val); SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);
void registerConfigVar(const char* name, const Hyprlang::FLOAT& val);
void registerConfigVar(const char* name, const Hyprlang::VEC2& val);
void registerConfigVar(const char* name, const Hyprlang::STRING& val);
void registerConfigVar(const char* name, Hyprlang::CUSTOMTYPE&& val);
std::unordered_map<SFloatCache, Vector2D> m_mStoredFloatingSizes;
friend struct SConfigOptionDescription;
}; };
inline UP<CConfigManager> g_pConfigManager; inline std::unique_ptr<CConfigManager> g_pConfigManager;

View File

@@ -3,6 +3,7 @@
#include <string> #include <string>
#include <typeindex> #include <typeindex>
#include <hyprlang.hpp> #include <hyprlang.hpp>
#include "../debug/Log.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "ConfigManager.hpp" #include "ConfigManager.hpp"
@@ -12,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
@@ -70,4 +70,4 @@ template <>
inline Hyprlang::CUSTOMTYPE CConfigValue<Hyprlang::CUSTOMTYPE>::operator*() const { inline Hyprlang::CUSTOMTYPE CConfigValue<Hyprlang::CUSTOMTYPE>::operator*() const {
RASSERT(false, "Impossible to implement operator* of CConfigValue<Hyprlang::CUSTOMTYPE>, use ptr()"); RASSERT(false, "Impossible to implement operator* of CConfigValue<Hyprlang::CUSTOMTYPE>, use ptr()");
return *ptr(); return *ptr();
} }

View File

@@ -1,81 +0,0 @@
#include "ConfigWatcher.hpp"
#include <sys/inotify.h>
#include "../debug/Log.hpp"
#include <ranges>
#include <fcntl.h>
#include <unistd.h>
#include <filesystem>
using namespace Hyprutils::OS;
CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) {
if (!m_inotifyFd.isValid()) {
Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded");
return;
}
// TODO: make CFileDescriptor take F_GETFL, F_SETFL
const int FLAGS = fcntl(m_inotifyFd.get(), F_GETFL, 0);
if (fcntl(m_inotifyFd.get(), F_SETFL, FLAGS | O_NONBLOCK) < 0) {
Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded");
m_inotifyFd.reset();
return;
}
}
CFileDescriptor& CConfigWatcher::getInotifyFD() {
return m_inotifyFd;
}
void CConfigWatcher::setWatchList(const std::vector<std::string>& paths) {
// we clear all watches first, because whichever fired is now invalid
// or that is at least what it seems to be.
// since we don't know which fired,
// plus it doesn't matter that much, these ops are done rarely and fast anyways.
// cleanup old paths
for (auto& watch : m_watches) {
inotify_rm_watch(m_inotifyFd.get(), watch.wd);
}
m_watches.clear();
// add new paths
for (const auto& path : paths) {
m_watches.emplace_back(SInotifyWatch{
.wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY | IN_DONT_FOLLOW),
.file = path,
});
std::error_code ec, ec2;
const auto CANONICAL = std::filesystem::canonical(path, ec);
const auto IS_SYMLINK = std::filesystem::is_symlink(path, ec2);
if (!ec && !ec2 && IS_SYMLINK) {
m_watches.emplace_back(SInotifyWatch{
.wd = inotify_add_watch(m_inotifyFd.get(), CANONICAL.c_str(), IN_MODIFY),
.file = path,
});
}
}
}
void CConfigWatcher::setOnChange(const std::function<void(const SConfigWatchEvent&)>& fn) {
m_watchCallback = fn;
}
void CConfigWatcher::onInotifyEvent() {
inotify_event ev;
while (read(m_inotifyFd.get(), &ev, sizeof(ev)) > 0) {
const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; });
if (WD == m_watches.end()) {
Debug::log(ERR, "CConfigWatcher: got an event for wd {} which we don't have?!", ev.wd);
return;
}
m_watchCallback(SConfigWatchEvent{
.file = WD->file,
});
}
}

View File

@@ -1,33 +0,0 @@
#pragma once
#include "../helpers/memory/Memory.hpp"
#include <vector>
#include <string>
#include <functional>
#include <hyprutils/os/FileDescriptor.hpp>
class CConfigWatcher {
public:
CConfigWatcher();
~CConfigWatcher() = default;
struct SConfigWatchEvent {
std::string file;
};
Hyprutils::OS::CFileDescriptor& getInotifyFD();
void setWatchList(const std::vector<std::string>& paths);
void setOnChange(const std::function<void(const SConfigWatchEvent&)>& fn);
void onInotifyEvent();
private:
struct SInotifyWatch {
int wd = -1;
std::string file;
};
std::function<void(const SConfigWatchEvent&)> m_watchCallback;
std::vector<SInotifyWatch> m_watches;
Hyprutils::OS::CFileDescriptor m_inotifyFd;
};
inline UP<CConfigWatcher> g_pConfigWatcher = makeUnique<CConfigWatcher>();

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.
# ####################################################################################### # #######################################################################################
@@ -65,20 +65,6 @@ env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24 env = HYPRCURSOR_SIZE,24
###################
### PERMISSIONS ###
###################
# See https://wiki.hyprland.org/Configuring/Permissions/
# ecosystem {
# enforce_permissions = 1
# }
# permission = /usr/(bin|local/bin)/grim, screencopy, allow
# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
##################### #####################
### LOOK AND FEEL ### ### LOOK AND FEEL ###
##################### #####################
@@ -108,7 +94,6 @@ general {
# https://wiki.hyprland.org/Configuring/Variables/#decoration # https://wiki.hyprland.org/Configuring/Variables/#decoration
decoration { decoration {
rounding = 10 rounding = 10
rounding_power = 2
# Change transparency of focused and unfocused windows # Change transparency of focused and unfocused windows
active_opacity = 1.0 active_opacity = 1.0
@@ -166,10 +151,10 @@ animations {
# uncomment all if you wish to use that. # uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] # windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrule = rounding 0, floating:0, onworkspace:w[tv1] # windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrule = bordersize 0, floating:0, onworkspace:f[1] # windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrule = rounding 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 {
@@ -283,7 +268,7 @@ bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness # Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
@@ -303,12 +288,15 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules # See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule # Example windowrule v1
# windowrule = float,class:^(kitty)$,title:^(kitty)$ # windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.* windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland # Fix some dragging issues with XWayland
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
)#"; )#";

View File

@@ -2,11 +2,10 @@
#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>
#include "../helpers/MiscFunctions.hpp"
#include "../plugins/PluginSystem.hpp" #include "../plugins/PluginSystem.hpp"
#include "../signal-safe.hpp" #include "../signal-safe.hpp"
@@ -32,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.
@@ -43,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;
@@ -62,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.]";
} }
@@ -87,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();
@@ -101,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: ";
@@ -112,7 +111,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
finalCrashReport += "legacyrenderer\n"; finalCrashReport += "legacyrenderer\n";
#endif #endif
#if ISDEBUG #ifndef ISDEBUG
finalCrashReport += "debug\n"; finalCrashReport += "debug\n";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
@@ -123,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];
@@ -162,7 +161,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
#if defined(__DragonFly__) || defined(__FreeBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__)
finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga"); finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga");
#else #else
finalCrashReport.writeCmdOutput("lspci -vnn | grep -E '(VGA|Display|3D)'"); finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA");
#endif #endif
finalCrashReport += "\n\nos-release:\n"; finalCrashReport += "\n\nos-release:\n";
@@ -192,7 +191,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
#endif #endif
}; };
u_int miblen = sizeof(mib) / sizeof(mib[0]); u_int miblen = sizeof(mib) / sizeof(mib[0]);
char exe[PATH_MAX] = "/nonexistent"; char exe[PATH_MAX] = "";
size_t sz = sizeof(exe); size_t sz = sizeof(exe);
sysctl(mib, miblen, &exe, &sz, NULL, 0); sysctl(mib, miblen, &exe, &sz, NULL, 0);
const auto FPATH = std::filesystem::canonical(exe); const auto FPATH = std::filesystem::canonical(exe);
@@ -242,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>
@@ -25,7 +22,6 @@
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::OS;
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
@@ -40,18 +36,6 @@ using namespace Hyprutils::OS;
#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 "../desktop/LayerSurface.hpp"
#include "../version.h"
#include "../Compositor.hpp"
#include "../managers/input/InputManager.hpp"
#include "../managers/XWaylandManager.hpp"
#include "../managers/LayoutManager.hpp"
#include "../plugins/PluginSystem.hpp"
#include "../managers/AnimationManager.hpp"
#include "../debug/HyprNotificationOverlay.hpp"
#include "../render/Renderer.hpp"
#include "../render/OpenGL.hpp"
static void trimTrailingComma(std::string& str) { static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',') if (!str.empty() && str.back() == ',')
@@ -121,7 +105,6 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"vrr": {}, "vrr": {},
"solitary": "{:x}", "solitary": "{:x}",
"activelyTearing": {}, "activelyTearing": {},
"directScanoutTo": "{:x}",
"disabled": {}, "disabled": {},
"currentFormat": "{}", "currentFormat": "{}",
"mirrorOf": "{}", "mirrorOf": "{}",
@@ -134,27 +117,26 @@ 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)); m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, 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\tmirrorOf: {}\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),
m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format)); m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format));
} }
return result; return result;
} }
static std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
auto allMonitors = false; auto allMonitors = false;
@@ -257,32 +239,30 @@ 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->monitorID(), 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), (uintptr_t)w->m_pSwallowed.get(), (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
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, (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),
(!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, (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(),
w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (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),
(uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.get(), getFocusHistoryID(w), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
(int)g_pInputManager->isWindowInhibiting(w, false));
} }
} }
static std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) { std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
@@ -320,17 +300,15 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form
"windows": {}, "windows": {},
"hasfullscreen": {}, "hasfullscreen": {},
"lastwindow": "0x{:x}", "lastwindow": "0x{:x}",
"lastwindowtitle": "{}", "lastwindowtitle": "{}"
"ispersistent": {}
}})#", }})#",
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(), w->m_bHasFullscreenWindow ? "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) : "", w->m_bPersistent ? "true" : "false"); ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
} else { } else {
return std::format( return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID,
"workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\tispersistent: {}\n\n", w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", g_pCompositor->getWindowsOnWorkspace(w->m_iID),
w->m_iID, w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow, (int)w->m_bHasFullscreenWindow, (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "");
(uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "", (int)w->m_bPersistent);
} }
} }
@@ -383,8 +361,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
return result; return result;
} }
} }
std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
static std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_pLastMonitor)
return "unsafe state"; return "unsafe state";
@@ -397,7 +374,7 @@ static std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::stri
return CHyprCtl::getWorkspaceData(w, format); return CHyprCtl::getWorkspaceData(w, format);
} }
static std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) { std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@@ -418,7 +395,7 @@ static std::string workspacesRequest(eHyprCtlOutputFormat format, std::string re
return result; return result;
} }
static std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) { std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
@@ -438,7 +415,7 @@ static std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::strin
return result; return result;
} }
static std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) { std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) {
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!validMapped(PWINDOW)) if (!validMapped(PWINDOW))
@@ -452,7 +429,7 @@ static std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string
return result; return result;
} }
static std::string layersRequest(eHyprCtlOutputFormat format, std::string request) { std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@@ -480,11 +457,9 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
"y": {}, "y": {},
"w": {}, "w": {},
"h": {}, "h": {},
"namespace": "{}", "namespace": "{}"
"pid": {}
}},)#", }},)#",
(uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, escapeJSONStrings(layer->szNamespace), (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, escapeJSONStrings(layer->szNamespace));
layer->getPID());
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -515,8 +490,8 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]); result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]);
for (auto const& layer : level) { for (auto const& layer : level) {
result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}, pid: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width,
layer->geometry.width, layer->geometry.height, layer->szNamespace, layer->getPID()); layer->geometry.height, layer->szNamespace);
} }
layerLevel++; layerLevel++;
@@ -528,7 +503,7 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
return result; return result;
} }
static std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) { std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
@@ -550,13 +525,13 @@ static std::string layoutsRequest(eHyprCtlOutputFormat format, std::string reque
return result; return result;
} }
static std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request) { std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
std::string currErrors = g_pConfigManager->getErrors(); std::string currErrors = g_pConfigManager->getErrors();
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"#(
"{}",)#", "{}",)#",
@@ -566,14 +541,14 @@ static std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string
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);
} }
} }
return result; return result;
} }
static 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 getModState = [](SP<IKeyboard> keyboard, const char* xkbModName) -> bool {
@@ -743,14 +718,14 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
return result; return result;
} }
static std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) { std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = ""; std::string ret = "";
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
ret += "animations:\n"; ret += "animations:\n";
for (auto const& ac : g_pConfigManager->getAnimationConfig()) { for (auto const& ac : g_pConfigManager->getAnimationConfig()) {
ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second->overridden, ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second.overridden,
ac.second->internalBezier, ac.second->internalEnabled, ac.second->internalSpeed, ac.second->internalStyle); ac.second.internalBezier, ac.second.internalEnabled, ac.second.internalSpeed, ac.second.internalStyle);
} }
ret += "beziers:\n"; ret += "beziers:\n";
@@ -772,8 +747,8 @@ static std::string animationsRequest(eHyprCtlOutputFormat format, std::string re
"speed": {:.2f}, "speed": {:.2f},
"style": "{}" "style": "{}"
}},)#", }},)#",
ac.first, ac.second->overridden ? "true" : "false", escapeJSONStrings(ac.second->internalBezier), ac.second->internalEnabled ? "true" : "false", ac.first, ac.second.overridden ? "true" : "false", escapeJSONStrings(ac.second.internalBezier), ac.second.internalEnabled ? "true" : "false",
ac.second->internalSpeed, escapeJSONStrings(ac.second->internalStyle)); ac.second.internalSpeed, escapeJSONStrings(ac.second.internalStyle));
} }
ret[ret.length() - 1] = ']'; ret[ret.length() - 1] = ']';
@@ -796,7 +771,7 @@ static std::string animationsRequest(eHyprCtlOutputFormat format, std::string re
return ret; return ret;
} }
static std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) { std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@@ -810,15 +785,12 @@ static std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string re
return result; return result;
} }
static std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) { std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = ""; std::string ret = "";
const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts(); const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts();
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto const& sh : SHORTCUTS) { for (auto const& sh : SHORTCUTS)
ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description);
}
if (ret.empty())
ret = "none";
} else { } else {
ret += "["; ret += "[";
for (auto const& sh : SHORTCUTS) { for (auto const& sh : SHORTCUTS) {
@@ -836,31 +808,31 @@ static std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::stri
return ret; return ret;
} }
static 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"#(
{{ {{
@@ -868,7 +840,6 @@ static 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": {},
@@ -880,9 +851,9 @@ static 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 += "]";
@@ -900,18 +871,17 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n" std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n"
"Date: {}\n" "Date: {}\n"
"Tag: {}, commits: {}\n" "Tag: {}, commits: {}\n"
"built against:\n aquamarine {}\n hyprlang {}\n hyprutils {}\n hyprcursor {}\n hyprgraphics {}\n\n\n", "built against aquamarine {}\n\n\n",
HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION, 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) && !ISDEBUG && !defined(NO_XWAYLAND)) #if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND))
result += "no flags were set\n"; result += "no flags were set\n";
#else #else
result += "flags set:\n"; result += "flags set:\n";
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "legacyrenderer\n"; result += "legacyrenderer\n";
#endif #endif
#if ISDEBUG #ifdef ISDEBUG
result += "debug\n"; result += "debug\n";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
@@ -931,18 +901,14 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
"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, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG,
GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION); GIT_COMMITS, AQUAMARINE_VERSION);
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "\"legacyrenderer\","; result += "\"legacyrenderer\",";
#endif #endif
#if ISDEBUG #ifdef ISDEBUG
result += "\"debug\","; result += "\"debug\",";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
@@ -978,49 +944,16 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
#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 | grep -F -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 -E '(VGA|Display|3D)'"); 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) {
@@ -1039,7 +972,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
return result; return result;
} }
static std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) { std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) {
// get rid of the dispatch keyword // get rid of the dispatch keyword
in = in.substr(in.find_first_of(' ') + 1); in = in.substr(in.find_first_of(' ') + 1);
@@ -1060,7 +993,7 @@ static std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in)
return res.success ? "ok" : res.error; return res.success ? "ok" : res.error;
} }
static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
// Find the first space to strip the keyword keyword // Find the first space to strip the keyword keyword
auto const firstSpacePos = in.find_first_of(' '); auto const firstSpacePos = in.find_first_of(' ');
if (firstSpacePos == std::string::npos) // Handle the case where there's no space found (invalid input) if (firstSpacePos == std::string::npos) // Handle the case where there's no space found (invalid input)
@@ -1109,9 +1042,6 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in)
} }
} }
if (COMMAND.contains("misc:disable_autoreload"))
g_pConfigManager->updateWatcher();
// 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")) { COMMAND.starts_with("windowrule")) {
@@ -1129,29 +1059,32 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in)
return retval; return retval;
} }
static std::string reloadRequest(eHyprCtlOutputFormat format, std::string request) { std::string reloadRequest(eHyprCtlOutputFormat format, std::string request) {
const auto REQMODE = request.substr(request.find_last_of(' ') + 1); const auto REQMODE = request.substr(request.find_last_of(' ') + 1);
if (REQMODE == "config-only") g_pConfigManager->m_bForceReload = true;
g_pConfigManager->m_bNoMonitorReload = true;
g_pConfigManager->reload(); if (REQMODE == "config-only") {
g_pConfigManager->m_bNoMonitorReload = true;
}
g_pConfigManager->tick();
return "ok"; return "ok";
} }
static std::string killRequest(eHyprCtlOutputFormat format, std::string request) { std::string killRequest(eHyprCtlOutputFormat format, std::string request) {
g_pInputManager->setClickMode(CLICKMODE_KILL); g_pInputManager->setClickMode(CLICKMODE_KILL);
return "ok"; return "ok";
} }
static std::string splashRequest(eHyprCtlOutputFormat format, std::string request) { std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
return g_pCompositor->m_szCurrentSplash; return g_pCompositor->m_szCurrentSplash;
} }
static std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) { std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) {
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal().floor(); const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal().floor();
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
@@ -1169,33 +1102,41 @@ static std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string req
return "error"; return "error";
} }
static std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) { std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
// split by ; ignores ; inside [] and adds ; on last command // split by ;
request = request.substr(9); request = request.substr(9);
std::string reply = ""; std::string curitem = "";
const std::string DELIMITER = "\n\n\n"; std::string reply = "";
int bracket = 0;
size_t idx = 0;
for (size_t i = 0; i <= request.size(); ++i) { auto nextItem = [&]() {
char ch = (i < request.size()) ? request[i] : ';'; auto idx = request.find_first_of(';');
if (ch == '[')
++bracket; if (idx != std::string::npos) {
else if (ch == ']') curitem = request.substr(0, idx);
--bracket; request = request.substr(idx + 1);
else if (ch == ';' && bracket == 0) { } else {
if (idx < i) curitem = request;
reply += g_pHyprCtl->getReply(trim(request.substr(idx, i - idx))).append(DELIMITER); request = "";
idx = i + 1;
continue;
} }
curitem = trim(curitem);
};
nextItem();
const std::string DELIMITER = "\n\n\n";
while (curitem != "" || request != "") {
reply += g_pHyprCtl->getReply(curitem) + DELIMITER;
nextItem();
} }
return reply.substr(0, std::max(static_cast<int>(reply.size() - DELIMITER.size()), 0)); return reply.substr(0, std::max(static_cast<int>(reply.size() - DELIMITER.size()), 0));
} }
static std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) { std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
const auto SIZESTR = vars[vars.size() - 1]; const auto SIZESTR = vars[vars.size() - 1];
@@ -1219,7 +1160,7 @@ static std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string re
return "ok"; return "ok";
} }
static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) { std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
const auto KB = vars[1]; const auto KB = vars[1];
@@ -1294,7 +1235,7 @@ static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::stri
return "ok"; return "ok";
} }
static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) { std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
std::string errorMessage = ""; std::string errorMessage = "";
@@ -1308,7 +1249,7 @@ static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string req
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] + ' ';
@@ -1323,12 +1264,12 @@ static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string req
return "ok"; return "ok";
} }
static 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)); auto result = g_pKeybindManager->m_mDispatchers["setprop"](request.substr(request.find_first_of(' ') + 1, -1));
return "DEPRECATED: use hyprctl dispatch setprop instead" + (result.success ? "" : "\n" + result.error); return "DEPRECATED: use hyprctl dispatch setprop instead" + (result.success ? "" : "\n" + result.error);
} }
static std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) { std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
std::string curitem = ""; std::string curitem = "";
auto nextItem = [&]() { auto nextItem = [&]() {
@@ -1369,22 +1310,23 @@ static std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string re
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)";
} }
static std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) { std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
@@ -1410,7 +1352,7 @@ static std::string decorationRequest(eHyprCtlOutputFormat format, std::string re
return result; return result;
} }
static std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
if (vars.size() < 2) if (vars.size() < 2)
@@ -1465,7 +1407,7 @@ static std::string dispatchOutput(eHyprCtlOutputFormat format, std::string reque
return "ok"; return "ok";
} }
static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) { std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
if (vars.size() < 2) if (vars.size() < 2)
@@ -1493,40 +1435,17 @@ static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string reque
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";
} }
@@ -1534,7 +1453,7 @@ static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string reque
return "ok"; return "ok";
} }
static std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) { std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
if (vars.size() < 5) if (vars.size() < 5)
@@ -1550,8 +1469,9 @@ static std::string dispatchNotify(eHyprCtlOutputFormat format, std::string reque
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;
@@ -1559,13 +1479,10 @@ static std::string dispatchNotify(eHyprCtlOutputFormat format, std::string reque
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);
@@ -1589,7 +1506,7 @@ static std::string dispatchNotify(eHyprCtlOutputFormat format, std::string reque
return "ok"; return "ok";
} }
static std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::string request) { std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
int amount = -1; int amount = -1;
@@ -1609,7 +1526,7 @@ static std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::strin
return "ok"; return "ok";
} }
static std::string getIsLocked(eHyprCtlOutputFormat format, std::string request) { std::string getIsLocked(eHyprCtlOutputFormat format, std::string request) {
std::string lockedStr = g_pSessionLockManager->isSessionLocked() ? "true" : "false"; std::string lockedStr = g_pSessionLockManager->isSessionLocked() ? "true" : "false";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) if (format == eHyprCtlOutputFormat::FORMAT_JSON)
lockedStr = std::format(R"#( lockedStr = std::format(R"#(
@@ -1621,7 +1538,7 @@ static std::string getIsLocked(eHyprCtlOutputFormat format, std::string request)
return lockedStr; return lockedStr;
} }
static std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) { std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
std::string json = "{"; std::string json = "{";
const auto& DESCS = g_pConfigManager->getAllDescriptions(); const auto& DESCS = g_pConfigManager->getAllDescriptions();
@@ -1636,7 +1553,7 @@ static std::string getDescriptions(eHyprCtlOutputFormat format, std::string requ
return json; return json;
} }
static std::string submapRequest(eHyprCtlOutputFormat format, std::string request) { std::string submapRequest(eHyprCtlOutputFormat format, std::string request) {
std::string submap = g_pKeybindManager->getCurrentSubmap(); std::string submap = g_pKeybindManager->getCurrentSubmap();
if (submap.empty()) if (submap.empty())
submap = "default"; submap = "default";
@@ -1644,13 +1561,6 @@ static std::string submapRequest(eHyprCtlOutputFormat format, std::string reques
return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n"); return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n");
} }
static std::string reloadShaders(eHyprCtlOutputFormat format, std::string request) {
if (g_pHyprOpenGL->initShaders())
return format == FORMAT_JSON ? "{\"ok\": true}" : "ok";
else
return format == FORMAT_JSON ? "{\"ok\": false}" : "error";
}
CHyprCtl::CHyprCtl() { CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
@@ -1673,7 +1583,6 @@ CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions}); registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
registerCommand(SHyprCtlCommand{"submap", true, submapRequest}); registerCommand(SHyprCtlCommand{"submap", true, submapRequest});
registerCommand(SHyprCtlCommand{.name = "reloadshaders", .exact = true, .fn = reloadShaders});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
@@ -1697,6 +1606,8 @@ CHyprCtl::CHyprCtl() {
CHyprCtl::~CHyprCtl() { CHyprCtl::~CHyprCtl() {
if (m_eventSource) if (m_eventSource)
wl_event_source_remove(m_eventSource); wl_event_source_remove(m_eventSource);
if (m_iSocketFD >= 0)
close(m_iSocketFD);
if (!m_socketPath.empty()) if (!m_socketPath.empty())
unlink(m_socketPath.c_str()); unlink(m_socketPath.c_str());
} }
@@ -1791,7 +1702,7 @@ std::string CHyprCtl::getReply(std::string request) {
} }
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || !w->m_pWorkspace || !w->m_pWorkspace->isVisible()) if (!w->m_bIsMapped || !g_pCompositor->isWorkspaceVisible(w->m_pWorkspace))
continue; continue;
w->updateDynamicRules(); w->updateDynamicRules();
@@ -1811,7 +1722,7 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) {
return getReply(input); return getReply(input);
} }
static bool successWrite(int fd, const std::string& data, bool needLog = true) { bool successWrite(int fd, const std::string& data, bool needLog = true) {
if (write(fd, data.c_str(), data.length()) > 0) if (write(fd, data.c_str(), data.length()) > 0)
return true; return true;
@@ -1824,18 +1735,18 @@ static bool successWrite(int fd, const std::string& data, bool needLog = true) {
return false; return false;
} }
static void runWritingDebugLogThread(const int conn) { void runWritingDebugLogThread(const int conn) {
using namespace std::chrono_literals; using namespace std::chrono_literals;
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;
@@ -1843,25 +1754,22 @@ static 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();
} }
static bool isFollowUpRollingLogRequest(const std::string& request) { bool isFollowUpRollingLogRequest(const std::string& request) {
return request.contains("rollinglog") && request.contains("f"); return request.contains("rollinglog") && request.contains("f");
} }
static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
return 0; return 0;
if (!g_pHyprCtl->m_iSocketFD.isValid())
return 0;
sockaddr_in clientAddress; sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress); socklen_t clientSize = sizeof(clientAddress);
const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
std::array<char, 1024> readBuffer; std::array<char, 1024> readBuffer;
@@ -1905,9 +1813,9 @@ static 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);
@@ -1918,9 +1826,9 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
} }
void CHyprCtl::startHyprCtlSocket() { void CHyprCtl::startHyprCtlSocket() {
m_iSocketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)}; m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (!m_iSocketFD.isValid()) { if (m_iSocketFD < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
return; return;
} }
@@ -1931,15 +1839,15 @@ void CHyprCtl::startHyprCtlSocket() {
strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str()); strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str());
if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work.");
return; return;
} }
// 10 max queued. // 10 max queued.
listen(m_iSocketFD.get(), 10); listen(m_iSocketFD, 10);
Debug::log(LOG, "Hypr socket started at {}", m_socketPath); Debug::log(LOG, "Hypr socket started at {}", m_socketPath);
m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr); m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
} }

View File

@@ -1,10 +1,9 @@
#pragma once #pragma once
#include "../Compositor.hpp"
#include <fstream> #include <fstream>
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#include "../desktop/Window.hpp"
#include <functional> #include <functional>
#include <hyprutils/os/FileDescriptor.hpp>
// exposed for main.cpp // exposed for main.cpp
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request);
@@ -15,12 +14,12 @@ class CHyprCtl {
CHyprCtl(); CHyprCtl();
~CHyprCtl(); ~CHyprCtl();
std::string makeDynamicCall(const std::string& input); std::string makeDynamicCall(const std::string& input);
SP<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd); SP<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd);
void unregisterCommand(const SP<SHyprCtlCommand>& cmd); void unregisterCommand(const SP<SHyprCtlCommand>& cmd);
std::string getReply(std::string); std::string getReply(std::string);
Hyprutils::OS::CFileDescriptor m_iSocketFD; int m_iSocketFD = -1;
struct { struct {
bool all = false; bool all = false;
@@ -39,4 +38,4 @@ class CHyprCtl {
std::string m_socketPath; std::string m_socketPath;
}; };
inline UP<CHyprCtl> g_pHyprCtl; inline std::unique_ptr<CHyprCtl> g_pHyprCtl;

View File

@@ -2,21 +2,13 @@
#include "HyprDebugOverlay.hpp" #include "HyprDebugOverlay.hpp"
#include "config/ConfigValue.hpp" #include "config/ConfigValue.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../render/pass/TexPassElement.hpp"
#include "../render/Renderer.hpp"
#include "../managers/AnimationManager.hpp"
CHyprDebugOverlay::CHyprDebugOverlay() { CHyprDebugOverlay::CHyprDebugOverlay() {
m_pTexture = makeShared<CTexture>(); m_pTexture = makeShared<CTexture>();
} }
void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderData(PHLMONITOR 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();
@@ -26,12 +18,7 @@ void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs)
} }
void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR 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();
@@ -41,12 +28,7 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float du
} }
void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) { void CHyprMonitorDebugOverlay::frameData(PHLMONITOR 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();
@@ -198,38 +180,23 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
double posX = 0, posY = 0; double posX = 0, posY = 0;
cairo_get_current_point(cr, &posX, &posY); cairo_get_current_point(cr, &posX, &posY);
g_pHyprRenderer->damageBox(m_wbLastDrawnBox); g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset + MARGIN_TOP - 1, m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset + MARGIN_TOP - 1,
(int)maxTextW + 2, posY - offset - MARGIN_TOP + 2}; (int)maxTextW + 2, posY - offset - MARGIN_TOP + 2};
g_pHyprRenderer->damageBox(m_wbLastDrawnBox); g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
return posY - offset; return posY - offset;
} }
void CHyprDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { void CHyprDebugOverlay::renderData(PHLMONITOR 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(PHLMONITOR 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(PHLMONITOR pMonitor) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].frameData(pMonitor); m_mMonitorOverlays[pMonitor].frameData(pMonitor);
} }
@@ -271,8 +238,6 @@ void CHyprDebugOverlay::draw() {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CTexPassElement::SRenderData data; CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
data.tex = m_pTexture; g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f);
data.box = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
} }

View File

@@ -1,10 +1,11 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/Monitor.hpp"
#include "../render/Texture.hpp" #include "../render/Texture.hpp"
#include <deque>
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <map> #include <map>
#include <deque>
class CHyprRenderer; class CHyprRenderer;
@@ -48,4 +49,4 @@ class CHyprDebugOverlay {
friend class CHyprRenderer; friend class CHyprRenderer;
}; };
inline UP<CHyprDebugOverlay> g_pDebugOverlay; inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay;

View File

@@ -3,13 +3,8 @@
#include "HyprNotificationOverlay.hpp" #include "HyprNotificationOverlay.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../render/pass/TexPassElement.hpp"
#include "../managers/AnimationManager.hpp" inline auto iconBackendFromLayout(PangoLayout* layout) {
#include "../managers/HookSystemManager.hpp"
#include "../render/Renderer.hpp"
static inline auto iconBackendFromLayout(PangoLayout* layout) {
// preference: Nerd > FontAwesome > text // preference: Nerd > FontAwesome > text
auto eIconBackendChecks = std::array<eIconBackend, 2>{ICONS_BACKEND_NF, ICONS_BACKEND_FA}; auto eIconBackendChecks = std::array<eIconBackend, 2>{ICONS_BACKEND_NF, ICONS_BACKEND_FA};
for (auto iconID : eIconBackendChecks) { for (auto iconID : eIconBackendChecks) {
@@ -23,10 +18,10 @@ static 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);
}); });
m_pTexture = makeShared<CTexture>(); m_pTexture = makeShared<CTexture>();
@@ -39,11 +34,11 @@ 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(makeUnique<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 = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches 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;
@@ -56,12 +51,12 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CH
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();
} }
} }
} }
@@ -92,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);
@@ -187,7 +182,7 @@ 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};
} }
@@ -210,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
@@ -225,8 +220,8 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
CBox damage = drawNotifications(pMonitor); CBox damage = drawNotifications(pMonitor);
g_pHyprRenderer->damageBox(damage); g_pHyprRenderer->damageBox(&damage);
g_pHyprRenderer->damageBox(m_bLastDamage); g_pHyprRenderer->damageBox(&m_bLastDamage);
g_pCompositor->scheduleFrameForMonitor(pMonitor); g_pCompositor->scheduleFrameForMonitor(pMonitor);
@@ -246,14 +241,10 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CTexPassElement::SRenderData data; CBox pMonBox = {0, 0, MONSIZE.x, MONSIZE.y};
data.tex = m_pTexture; g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f);
data.box = {0, 0, MONSIZE.x, MONSIZE.y};
data.a = 1.F;
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
} }
bool CHyprNotificationOverlay::hasAny() { bool CHyprNotificationOverlay::hasAny() {
return !m_vNotifications.empty(); return !m_dNotifications.empty();
} }

View File

@@ -2,14 +2,15 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/Timer.hpp" #include "../helpers/Timer.hpp"
#include "../helpers/Monitor.hpp"
#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
@@ -18,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,23 +42,23 @@ class CHyprNotificationOverlay {
~CHyprNotificationOverlay(); ~CHyprNotificationOverlay();
void draw(PHLMONITOR pMonitor); void draw(PHLMONITOR 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(PHLMONITOR pMonitor);
CBox m_bLastDamage; CBox m_bLastDamage;
std::vector<UP<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; PHLMONITORREF m_pLastMonitor;
Vector2D m_vecLastSize = Vector2D(-1, -1); Vector2D m_vecLastSize = Vector2D(-1, -1);
SP<CTexture> m_pTexture; SP<CTexture> m_pTexture;
}; };
inline UP<CHyprNotificationOverlay> g_pHyprNotificationOverlay; inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay;

View File

@@ -1,5 +1,6 @@
#include "Log.hpp" #include "Log.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../Compositor.hpp"
#include "RollingLogFollow.hpp" #include "RollingLogFollow.hpp"
#include <fstream> #include <fstream>
@@ -17,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;
@@ -25,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;
@@ -53,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

View File

@@ -5,11 +5,13 @@
#include <fstream> #include <fstream>
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>
#include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp"
#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,
@@ -19,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;
@@ -37,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

@@ -1,5 +1,3 @@
#pragma once
#include "includes.hpp" #include "includes.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
#include "helpers/Color.hpp" #include "helpers/Color.hpp"

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#include "../helpers/memory/Memory.hpp" #include "../macros.hpp"
class CWorkspace; class CWorkspace;
class CWindow; class CWindow;
class CLayerSurface; class CLayerSurface;

View File

@@ -1,38 +0,0 @@
#include <re2/re2.h>
#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,31 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
#include "Rule.hpp"
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;
CRuleRegexContainer targetNamespaceRegex;
};

View File

@@ -4,18 +4,11 @@
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp" #include "../managers/SeatManager.hpp"
#include "../managers/AnimationManager.hpp"
#include "../render/Renderer.hpp"
#include "../config/ConfigManager.hpp"
#include "../helpers/Monitor.hpp"
#include "../managers/input/InputManager.hpp"
#include "../managers/HookSystemManager.hpp"
#include "../managers/EventManager.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); auto 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);
@@ -32,19 +25,22 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
pLS->szNamespace = resource->layerNamespace; pLS->szNamespace = resource->layerNamespace;
pLS->layer = resource->current.layer; pLS->layer = resource->current.layer;
pLS->popupHead = CPopup::create(pLS); pLS->popupHead = std::make_unique<CPopup>(pLS);
pLS->monitor = pMonitor; pLS->monitor = pMonitor;
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);
g_pAnimationManager->createAnimation(0.f, pLS->alpha, g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE); pLS->alpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realPosition, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); pLS->realPosition.create(g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realSize, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); pLS->realSize.create(g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE);
pLS->alpha.registerVar();
pLS->realPosition.registerVar();
pLS->realSize.registerVar();
pLS->registerCallbacks(); pLS->registerCallbacks();
pLS->alpha->setValueAndWarp(0.f); pLS->alpha.setValueAndWarp(0.f);
Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName); Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName);
@@ -52,7 +48,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
} }
void CLayerSurface::registerCallbacks() { void CLayerSurface::registerCallbacks() {
alpha->setUpdateCallback([this](auto) { alpha.setUpdateCallback([this](void*) {
if (dimAround) if (dimAround)
g_pHyprRenderer->damageMonitor(monitor.lock()); g_pHyprRenderer->damageMonitor(monitor.lock());
}); });
@@ -97,8 +93,7 @@ void CLayerSurface::onDestroy() {
onUnmap(); onUnmap();
} else { } else {
Debug::log(LOG, "Removing LayerSurface that wasn't mapped."); Debug::log(LOG, "Removing LayerSurface that wasn't mapped.");
if (alpha) alpha.setValueAndWarp(0.f);
alpha->setValueAndWarp(0.f);
fadingOut = true; fadingOut = true;
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
} }
@@ -115,7 +110,7 @@ void CLayerSurface::onDestroy() {
// and damage // and damage
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);
} }
readyToDelete = true; readyToDelete = true;
@@ -179,7 +174,7 @@ void CLayerSurface::onMap() {
position = Vector2D(geometry.x, geometry.y); position = Vector2D(geometry.x, geometry.y);
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 bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
@@ -215,7 +210,7 @@ void CLayerSurface::onUnmap() {
} }
// make a snapshot and start fade // make a snapshot and start fade
g_pHyprRenderer->makeLayerSnapshot(self.lock()); g_pHyprOpenGL->makeLayerSnapshot(self.lock());
startAnimation(false); startAnimation(false);
@@ -234,20 +229,19 @@ void CLayerSurface::onUnmap() {
// refocus if needed // refocus if needed
// 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()))
if (!g_pInputManager->refocusLastWindow(PMONITOR)) g_pInputManager->refocusLastWindow(PMONITOR);
g_pInputManager->refocus(); else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource())
} else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource())
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};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.size.x, geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.size.x,
(int)layerSurface->surface->current.size.y}; (int)layerSurface->surface->current.size.y};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
g_pInputManager->simulateMouseMovement(); g_pInputManager->sendMotionEventsToFocused();
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
} }
@@ -276,7 +270,7 @@ void CLayerSurface::onCommit() {
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
CBox geomFixed = {geometry.x, geometry.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x, geometry.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
if (layerSurface->current.committed != 0) { if (layerSurface->current.committed != 0) {
if (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_LAYER) { if (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_LAYER) {
@@ -313,17 +307,17 @@ void CLayerSurface::onCommit() {
} }
} }
if (realPosition->goal() != geometry.pos()) { if (realPosition.goal() != geometry.pos()) {
if (realPosition->isBeingAnimated()) if (realPosition.isBeingAnimated())
*realPosition = geometry.pos(); realPosition = geometry.pos();
else else
realPosition->setValueAndWarp(geometry.pos()); realPosition.setValueAndWarp(geometry.pos());
} }
if (realSize->goal() != geometry.size()) { if (realSize.goal() != geometry.size()) {
if (realSize->isBeingAnimated()) if (realSize.isBeingAnimated())
*realSize = geometry.size(); realSize = geometry.size();
else else
realSize->setValueAndWarp(geometry.size()); realSize.setValueAndWarp(geometry.size());
} }
if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) { if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) {
@@ -333,7 +327,7 @@ void CLayerSurface::onCommit() {
nullptr); nullptr);
if (!WASLASTFOCUS && popupHead) { if (!WASLASTFOCUS && popupHead) {
popupHead->breadthfirst( popupHead->breadthfirst(
[&WASLASTFOCUS](WP<CPopup> popup, void* data) { [&WASLASTFOCUS](CPopup* popup, void* data) {
WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource()); WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource());
}, },
nullptr); nullptr);
@@ -384,73 +378,54 @@ 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;
} }
} }
} }
void CLayerSurface::startAnimation(bool in, bool instant) { void CLayerSurface::startAnimation(bool in, bool instant) {
const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle);
if (in) { if (in) {
realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn");
realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn");
alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn")); alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn");
} else { } else {
realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut");
realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut");
alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut")); alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut");
} }
const auto ANIMSTYLE = animationStyle.value_or(realPosition->getStyle());
if (ANIMSTYLE.starts_with("slide")) { if (ANIMSTYLE.starts_with("slide")) {
// get closest edge // get closest edge
const auto MIDDLE = geometry.middle(); const auto MIDDLE = geometry.middle();
@@ -491,9 +466,9 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
} }
} }
realSize->setValueAndWarp(geometry.size()); realSize.setValueAndWarp(geometry.size());
alpha->setValueAndWarp(in ? 0.f : 1.f); alpha.setValueAndWarp(in ? 0.f : 1.f);
*alpha = in ? 1.f : 0.f; alpha = in ? 1.f : 0.f;
Vector2D prePos; Vector2D prePos;
@@ -518,11 +493,11 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
} }
if (in) { if (in) {
realPosition->setValueAndWarp(prePos); realPosition.setValueAndWarp(prePos);
*realPosition = geometry.pos(); realPosition = geometry.pos();
} else { } else {
realPosition->setValueAndWarp(geometry.pos()); realPosition.setValueAndWarp(geometry.pos());
*realPosition = prePos; realPosition = prePos;
} }
} else if (ANIMSTYLE.starts_with("popin")) { } else if (ANIMSTYLE.starts_with("popin")) {
@@ -541,25 +516,25 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5}); const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5});
const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f; const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f;
alpha->setValueAndWarp(in ? 0.f : 1.f); alpha.setValueAndWarp(in ? 0.f : 1.f);
*alpha = in ? 1.f : 0.f; alpha = in ? 1.f : 0.f;
if (in) { if (in) {
realSize->setValueAndWarp(GOALSIZE); realSize.setValueAndWarp(GOALSIZE);
realPosition->setValueAndWarp(GOALPOS); realPosition.setValueAndWarp(GOALPOS);
*realSize = geometry.size(); realSize = geometry.size();
*realPosition = geometry.pos(); realPosition = geometry.pos();
} else { } else {
realSize->setValueAndWarp(geometry.size()); realSize.setValueAndWarp(geometry.size());
realPosition->setValueAndWarp(geometry.pos()); realPosition.setValueAndWarp(geometry.pos());
*realSize = GOALSIZE; realSize = GOALSIZE;
*realPosition = GOALPOS; realPosition = GOALPOS;
} }
} else { } else {
// fade // fade
realPosition->setValueAndWarp(geometry.pos()); realPosition.setValueAndWarp(geometry.pos());
realSize->setValueAndWarp(geometry.size()); realSize.setValueAndWarp(geometry.size());
*alpha = in ? 1.f : 0.f; alpha = in ? 1.f : 0.f;
} }
if (!in) if (!in)
@@ -570,7 +545,7 @@ bool CLayerSurface::isFadedOut() {
if (!fadingOut) if (!fadingOut)
return false; return false;
return !realPosition->isBeingAnimated() && !realSize->isBeingAnimated() && !alpha->isBeingAnimated(); return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated();
} }
int CLayerSurface::popupsCount() { int CLayerSurface::popupsCount() {
@@ -578,22 +553,10 @@ int CLayerSurface::popupsCount() {
return 0; return 0;
int no = -1; // we have one dummy int no = -1; // we have one dummy
popupHead->breadthfirst([](WP<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() { MONITORID CLayerSurface::monitorID() {
return monitor ? monitor->ID : MONITOR_INVALID; return monitor ? monitor->ID : MONITOR_INVALID;
} }
pid_t CLayerSurface::getPID() {
pid_t PID = -1;
if (!layerSurface || !layerSurface->surface || !layerSurface->surface->getResource() || !layerSurface->surface->getResource()->resource() ||
!layerSurface->surface->getResource()->resource()->client)
return -1;
wl_client_get_credentials(layerSurface->surface->getResource()->resource()->client, &PID, nullptr, nullptr);
return PID;
}

View File

@@ -5,6 +5,11 @@
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
struct SLayerRule {
std::string targetNamespace = "";
std::string rule = "";
};
class CLayerShellResource; class CLayerShellResource;
class CLayerSurface { class CLayerSurface {
@@ -17,17 +22,17 @@ class CLayerSurface {
public: public:
~CLayerSurface(); ~CLayerSurface();
void applyRules(); void applyRules();
void startAnimation(bool in, bool instant = false); void startAnimation(bool in, bool instant = false);
bool isFadedOut(); bool isFadedOut();
int popupsCount(); int popupsCount();
PHLANIMVAR<Vector2D> realPosition; CAnimatedVariable<Vector2D> realPosition;
PHLANIMVAR<Vector2D> realSize; CAnimatedVariable<Vector2D> realSize;
PHLANIMVAR<float> alpha; CAnimatedVariable<float> alpha;
WP<CLayerShellResource> layerSurface; WP<CLayerShellResource> layerSurface;
wl_list link; wl_list link;
// the header providing the enum type cannot be imported here // the header providing the enum type cannot be imported here
int interactivity = 0; int interactivity = 0;
@@ -59,9 +64,7 @@ class CLayerSurface {
CBox geometry = {0, 0, 0, 0}; CBox geometry = {0, 0, 0, 0};
Vector2D position; Vector2D position;
std::string szNamespace = ""; std::string szNamespace = "";
UP<CPopup> popupHead; std::unique_ptr<CPopup> popupHead;
pid_t getPID();
void onDestroy(); void onDestroy();
void onMap(); void onMap();

View File

@@ -6,43 +6,27 @@
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp" #include "../managers/SeatManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp" #include "../managers/eventLoop/EventLoopManager.hpp"
#include "../desktop/LayerSurface.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "../render/OpenGL.hpp"
#include <ranges> #include <ranges>
UP<CPopup> CPopup::create(PHLWINDOW pOwner) { CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) {
auto popup = UP<CPopup>(new CPopup()); initAllSignals();
popup->m_pWindowOwner = pOwner;
popup->m_pSelf = popup;
popup->initAllSignals();
return popup;
} }
UP<CPopup> CPopup::create(PHLLS pOwner) { CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) {
auto popup = UP<CPopup>(new CPopup()); initAllSignals();
popup->m_pLayerOwner = pOwner;
popup->m_pSelf = popup;
popup->initAllSignals();
return popup;
} }
UP<CPopup> CPopup::create(SP<CXDGPopupResource> resource, WP<CPopup> pOwner) { CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner), m_pResource(popup) {
auto popup = UP<CPopup>(new CPopup()); m_pWLSurface = CWLSurface::create();
popup->m_pResource = resource; m_pWLSurface->assign(popup->surface->surface.lock(), this);
popup->m_pWindowOwner = pOwner->m_pWindowOwner;
popup->m_pLayerOwner = pOwner->m_pLayerOwner;
popup->m_pParent = pOwner;
popup->m_pSelf = popup;
popup->m_pWLSurface = CWLSurface::create();
popup->m_pWLSurface->assign(resource->surface->surface.lock(), popup.get());
popup->m_vLastSize = resource->surface->current.geometry.size(); m_pLayerOwner = pOwner->m_pLayerOwner;
popup->reposition(); m_pWindowOwner = pOwner->m_pWindowOwner;
popup->initAllSignals(); m_vLastSize = popup->surface->current.geometry.size();
return popup; reposition();
initAllSignals();
} }
CPopup::~CPopup() { CPopup::~CPopup() {
@@ -73,8 +57,7 @@ void CPopup::initAllSignals() {
} }
void CPopup::onNewPopup(SP<CXDGPopupResource> popup) { void CPopup::onNewPopup(SP<CXDGPopupResource> popup) {
const auto& POPUP = m_vChildren.emplace_back(CPopup::create(popup, m_pSelf)); const auto POPUP = m_vChildren.emplace_back(makeShared<CPopup>(popup, this)).get();
POPUP->m_pSelf = POPUP;
Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP);
} }
@@ -99,13 +82,13 @@ void CPopup::onMap() {
CBox box = m_pWLSurface->resource()->extends(); CBox box = m_pWLSurface->resource()->extends();
box.translate(COORDS).expand(4); box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(&box);
m_vLastPos = coordsRelativeToParent(); m_vLastPos = coordsRelativeToParent();
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
m_pSubsurfaceHead = CSubsurface::create(m_pSelf); m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
//unconstrain(); //unconstrain();
sendScale(); sendScale();
@@ -133,7 +116,7 @@ void CPopup::onUnmap() {
CBox box = m_pWLSurface->resource()->extends(); CBox box = m_pWLSurface->resource()->extends();
box.translate(COORDS).expand(4); box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(&box);
m_pSubsurfaceHead.reset(); m_pSubsurfaceHead.reset();
@@ -142,20 +125,19 @@ void CPopup::onUnmap() {
// damage all children // damage all children
breadthfirst( breadthfirst(
[](WP<CPopup> p, void* data) { [](CPopup* p, void* data) {
if (!p->m_pResource) if (!p->m_pResource)
return; return;
auto box = CBox{p->coordsGlobal(), p->size()}; auto box = CBox{p->coordsGlobal(), p->size()};
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(&box);
}, },
nullptr); nullptr);
// TODO: probably refocus, but without a motion event? const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource();
// const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource();
// if (WASLASTFOCUS) if (WASLASTFOCUS)
// g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
} }
void CPopup::onCommit(bool ignoreSiblings) { void CPopup::onCommit(bool ignoreSiblings) {
@@ -187,10 +169,10 @@ void CPopup::onCommit(bool ignoreSiblings) {
if (m_vLastSize != m_pResource->surface->surface->current.size || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) { if (m_vLastSize != m_pResource->surface->surface->current.size || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) {
CBox box = {localToGlobal(m_vLastPos), m_vLastSize}; CBox box = {localToGlobal(m_vLastPos), m_vLastSize};
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(&box);
m_vLastSize = m_pResource->surface->surface->current.size; m_vLastSize = m_pResource->surface->surface->current.size;
box = {COORDS, m_vLastSize}; box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(&box);
m_vLastPos = COORDSLOCAL; m_vLastPos = COORDSLOCAL;
} }
@@ -240,7 +222,7 @@ Vector2D CPopup::coordsRelativeToParent() {
if (!m_pResource) if (!m_pResource)
return {}; return {};
WP<CPopup> current = m_pSelf; CPopup* current = this;
offset -= current->m_pResource->surface->current.geometry.pos(); offset -= current->m_pResource->surface->current.geometry.pos();
while (current->m_pParent && current->m_pResource) { while (current->m_pParent && current->m_pResource) {
@@ -264,16 +246,16 @@ Vector2D CPopup::localToGlobal(const Vector2D& rel) {
Vector2D CPopup::t1ParentCoords() { Vector2D CPopup::t1ParentCoords() {
if (!m_pWindowOwner.expired()) if (!m_pWindowOwner.expired())
return m_pWindowOwner->m_vRealPosition->value(); return m_pWindowOwner->m_vRealPosition.value();
if (!m_pLayerOwner.expired()) if (!m_pLayerOwner.expired())
return m_pLayerOwner->realPosition->value(); return m_pLayerOwner->realPosition.value();
ASSERT(false); ASSERT(false);
return {}; return {};
} }
void CPopup::recheckTree() { void CPopup::recheckTree() {
WP<CPopup> curr = m_pSelf; CPopup* curr = this;
while (curr->m_pParent) { while (curr->m_pParent) {
curr = curr->m_pParent; curr = curr->m_pParent;
} }
@@ -282,11 +264,7 @@ void CPopup::recheckTree() {
} }
void CPopup::recheckChildrenRecursive() { void CPopup::recheckChildrenRecursive() {
if (m_bInert || !m_pWLSurface) auto cpy = m_vChildren;
return;
std::vector<WP<CPopup>> cpy;
std::ranges::for_each(m_vChildren, [&cpy](const auto& el) { cpy.emplace_back(el); });
for (auto const& c : cpy) { for (auto const& c : cpy) {
c->onCommit(true); c->onCommit(true);
c->recheckChildrenRecursive(); c->recheckChildrenRecursive();
@@ -317,17 +295,17 @@ bool CPopup::visible() {
return false; return false;
} }
void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(WP<CPopup>, void*)> fn, void* data) { void CPopup::bfHelper(std::vector<CPopup*> const& 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<WP<CPopup>> nodes2; std::vector<CPopup*> nodes2;
nodes2.reserve(nodes.size() * 2); 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) {
nodes2.push_back(c->m_pSelf); nodes2.push_back(c.get());
} }
} }
@@ -335,42 +313,35 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
bfHelper(nodes2, fn, data); bfHelper(nodes2, fn, data);
} }
void CPopup::breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data) { void CPopup::breadthfirst(std::function<void(CPopup*, void*)> fn, void* data) {
std::vector<WP<CPopup>> popups; std::vector<CPopup*> popups;
popups.push_back(m_pSelf); popups.push_back(this);
bfHelper(popups, fn, data); bfHelper(popups, fn, data);
} }
WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) { CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
std::vector<WP<CPopup>> popups; std::vector<CPopup*> popups;
breadthfirst([&popups](WP<CPopup> popup, void* data) { popups.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 || !p->m_bMapped)
continue; continue;
if (!allowsInput) { if (!allowsInput) {
const bool HASSURFACE = p->m_pResource && p->m_pResource->surface; const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{};
const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size();
Vector2D offset = HASSURFACE ? p->m_pResource->surface->current.geometry.pos() : Vector2D{}; const auto BOX = CBox{p->coordsGlobal() + offset, size};
Vector2D size = HASSURFACE ? p->m_pResource->surface->current.geometry.size() : p->size();
if (size == Vector2D{})
size = p->size();
const auto BOX = CBox{p->coordsGlobal() + offset, size};
if (BOX.containsPoint(globalCoords)) if (BOX.containsPoint(globalCoords))
return p; return p;
} else { } else {
const auto REGION = CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal()); const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{};
const auto REGION =
CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset);
if (REGION.containsPoint(globalCoords)) if (REGION.containsPoint(globalCoords))
return p; return p;
} }
} }
return {}; return nullptr;
}
bool CPopup::inert() const {
return m_bInert;
} }

View File

@@ -1,20 +1,20 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <memory>
#include "Subsurface.hpp" #include "Subsurface.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
#include "../helpers/memory/Memory.hpp"
class CXDGPopupResource; class CXDGPopupResource;
class CPopup { class CPopup {
public: public:
// dummy head nodes // dummy head nodes
static UP<CPopup> create(PHLWINDOW pOwner); CPopup(PHLWINDOW pOwner);
static UP<CPopup> create(PHLLS pOwner); CPopup(PHLLS pOwner);
// real nodes // real nodes
static UP<CPopup> create(SP<CXDGPopupResource> popup, WP<CPopup> pOwner); CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner);
~CPopup(); ~CPopup();
@@ -34,26 +34,22 @@ class CPopup {
void recheckTree(); void recheckTree();
bool visible(); bool visible();
bool inert() const;
// will also loop over this node // will also loop over this node
void breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data); void breadthfirst(std::function<void(CPopup*, void*)> fn, void* data);
WP<CPopup> at(const Vector2D& globalCoords, bool allowsInput = false); CPopup* at(const Vector2D& globalCoords, bool allowsInput = false);
// //
SP<CWLSurface> m_pWLSurface; SP<CWLSurface> m_pWLSurface;
WP<CPopup> m_pSelf;
bool m_bMapped = false; bool m_bMapped = false;
private: private:
CPopup() = default;
// T1 owners, each popup has to have one of these // T1 owners, each popup has to have one of these
PHLWINDOWREF m_pWindowOwner; PHLWINDOWREF m_pWindowOwner;
PHLLSREF m_pLayerOwner; PHLLSREF m_pLayerOwner;
// T2 owners // T2 owners
WP<CPopup> m_pParent; CPopup* m_pParent = nullptr;
WP<CXDGPopupResource> m_pResource; WP<CXDGPopupResource> m_pResource;
@@ -65,8 +61,8 @@ class CPopup {
bool m_bInert = false; bool m_bInert = false;
// //
std::vector<UP<CPopup>> m_vChildren; std::vector<SP<CPopup>> m_vChildren;
UP<CSubsurface> m_pSubsurfaceHead; std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
struct { struct {
CHyprSignalListener newPopup; CHyprSignalListener newPopup;
@@ -85,5 +81,5 @@ class CPopup {
Vector2D localToGlobal(const Vector2D& rel); Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords(); Vector2D t1ParentCoords();
static void bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(WP<CPopup>, void*)> fn, void* data); static void bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPopup*, void*)> fn, void* data);
}; };

View File

@@ -1,22 +0,0 @@
#include <re2/re2.h>
#include "../helpers/memory/Memory.hpp"
#include "Rule.hpp"
#include "../debug/Log.hpp"
CRuleRegexContainer::CRuleRegexContainer(const std::string& regex_) {
const bool NEGATIVE = regex_.starts_with("negative:");
negative = NEGATIVE;
regex = makeUnique<RE2>(NEGATIVE ? regex_.substr(9) : regex_);
// TODO: maybe pop an error?
if (!regex->ok())
Debug::log(ERR, "RuleRegexContainer: regex {} failed to parse!", regex_);
}
bool CRuleRegexContainer::passes(const std::string& str) const {
if (!regex)
return false;
return RE2::FullMatch(str, *regex) != negative;
}

View File

@@ -1,21 +0,0 @@
#pragma once
#include <hyprutils/memory/UniquePtr.hpp>
//NOLINTNEXTLINE
namespace re2 {
class RE2;
};
class CRuleRegexContainer {
public:
CRuleRegexContainer() = default;
CRuleRegexContainer(const std::string& regex);
bool passes(const std::string& str) const;
private:
Hyprutils::Memory::CUniquePointer<re2::RE2> regex;
bool negative = false;
};

View File

@@ -4,50 +4,33 @@
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/core/Subcompositor.hpp" #include "../protocols/core/Subcompositor.hpp"
#include "../render/Renderer.hpp"
#include "../managers/input/InputManager.hpp"
UP<CSubsurface> CSubsurface::create(PHLWINDOW pOwner) { CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); initSignals();
subsurface->m_pWindowParent = pOwner; initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
subsurface->m_pSelf = subsurface;
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
return subsurface;
} }
UP<CSubsurface> CSubsurface::create(WP<CPopup> pOwner) { CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); initSignals();
subsurface->m_pPopupParent = pOwner; initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
subsurface->m_pSelf = subsurface;
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
return subsurface;
} }
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) { CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); m_pWLSurface = CWLSurface::create();
subsurface->m_pWindowParent = pOwner; m_pWLSurface->assign(pSubsurface->surface.lock(), this);
subsurface->m_pSubsurface = pSubsurface; initSignals();
subsurface->m_pSelf = subsurface; initExistingSubsurfaces(pSubsurface->surface.lock());
subsurface->m_pWLSurface = CWLSurface::create();
subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get());
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pSubsurface->surface.lock());
return subsurface;
} }
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner) { CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); m_pWLSurface = CWLSurface::create();
subsurface->m_pPopupParent = pOwner; m_pWLSurface->assign(pSubsurface->surface.lock(), this);
subsurface->m_pSubsurface = pSubsurface; initSignals();
subsurface->m_pSelf = subsurface; initExistingSubsurfaces(pSubsurface->surface.lock());
subsurface->m_pWLSurface = CWLSurface::create(); }
subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get());
subsurface->initSignals(); CSubsurface::~CSubsurface() {
subsurface->initExistingSubsurfaces(pSubsurface->surface.lock()); ;
return subsurface;
} }
void CSubsurface::initSignals() { void CSubsurface::initSignals() {
@@ -107,7 +90,7 @@ void CSubsurface::onCommit() {
g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y);
if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface) if (m_pPopupParent)
m_pPopupParent->recheckTree(); m_pPopupParent->recheckTree();
if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this
m_pWindowParent->m_pPopupHead->recheckTree(); m_pWindowParent->m_pPopupHead->recheckTree();
@@ -116,20 +99,11 @@ void CSubsurface::onCommit() {
checkSiblingDamage(); checkSiblingDamage();
if (m_vLastSize != m_pWLSurface->resource()->current.size) { if (m_vLastSize != m_pWLSurface->resource()->current.size) {
// TODO: fix this CBox box{COORDS, m_vLastSize};
// CBox box{COORDS, m_vLastSize}; g_pHyprRenderer->damageBox(&box);
// g_pHyprRenderer->damageBox(box); m_vLastSize = m_pWLSurface->resource()->current.size;
// m_vLastSize = m_pWLSurface->resource()->current.size; box = {COORDS, m_vLastSize};
// box = {COORDS, m_vLastSize}; g_pHyprRenderer->damageBox(&box);
// g_pHyprRenderer->damageBox(box);
CBox box;
if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface)
box = m_pPopupParent->m_pWLSurface->getSurfaceBoxGlobal().value_or(CBox{});
else if (m_pWindowParent)
box = m_pWindowParent->getWindowMainSurfaceBox();
g_pHyprRenderer->damageBox(box);
} }
} }
@@ -147,18 +121,16 @@ void CSubsurface::onDestroy() {
} }
void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) { void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) {
WP<CSubsurface> PSUBSURFACE; CSubsurface* PSUBSURFACE = nullptr;
if (!m_pWindowParent.expired()) if (!m_pWindowParent.expired())
PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pWindowParent.lock())); PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pWindowParent.lock())).get();
else if (m_pPopupParent) else if (m_pPopupParent)
PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pPopupParent)); PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pPopupParent)).get();
PSUBSURFACE->m_pSelf = PSUBSURFACE;
ASSERT(PSUBSURFACE); ASSERT(PSUBSURFACE);
PSUBSURFACE->m_pParent = m_pSelf; PSUBSURFACE->m_pParent = this;
} }
void CSubsurface::onMap() { void CSubsurface::onMap() {
@@ -167,7 +139,7 @@ void CSubsurface::onMap() {
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize}; CBox box{COORDS, m_vLastSize};
box.expand(4); box.expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(&box);
if (!m_pWindowParent.expired()) if (!m_pWindowParent.expired())
m_pWindowParent->updateSurfaceScaleTransformDetails(); m_pWindowParent->updateSurfaceScaleTransformDetails();
@@ -177,7 +149,7 @@ void CSubsurface::onUnmap() {
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize}; CBox box{COORDS, m_vLastSize};
box.expand(4); box.expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(&box);
if (m_pWLSurface->resource() == g_pCompositor->m_pLastFocus) if (m_pWLSurface->resource() == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
@@ -197,7 +169,7 @@ Vector2D CSubsurface::coordsGlobal() {
Vector2D coords = coordsRelativeToParent(); Vector2D coords = coordsRelativeToParent();
if (!m_pWindowParent.expired()) if (!m_pWindowParent.expired())
coords += m_pWindowParent->m_vRealPosition->value(); coords += m_pWindowParent->m_vRealPosition.value();
else if (m_pPopupParent) else if (m_pPopupParent)
coords += m_pPopupParent->coordsGlobal(); coords += m_pPopupParent->coordsGlobal();

View File

@@ -10,35 +10,31 @@ class CWLSubsurfaceResource;
class CSubsurface { class CSubsurface {
public: public:
// root dummy nodes // root dummy nodes
static UP<CSubsurface> create(PHLWINDOW pOwner); CSubsurface(PHLWINDOW pOwner);
static UP<CSubsurface> create(WP<CPopup> pOwner); CSubsurface(CPopup* pOwner);
// real nodes // real nodes
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner); CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner);
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner); CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner);
~CSubsurface() = default; ~CSubsurface();
Vector2D coordsRelativeToParent(); Vector2D coordsRelativeToParent();
Vector2D coordsGlobal(); Vector2D coordsGlobal();
Vector2D size(); Vector2D size();
void onCommit(); void onCommit();
void onDestroy(); void onDestroy();
void onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface); void onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface);
void onMap(); void onMap();
void onUnmap(); void onUnmap();
bool visible(); bool visible();
void recheckDamageForSubsurfaces(); void recheckDamageForSubsurfaces();
WP<CSubsurface> m_pSelf;
private: private:
CSubsurface() = default;
struct { struct {
CHyprSignalListener destroySubsurface; CHyprSignalListener destroySubsurface;
CHyprSignalListener commitSubsurface; CHyprSignalListener commitSubsurface;
@@ -52,16 +48,16 @@ class CSubsurface {
Vector2D m_vLastSize = {}; Vector2D m_vLastSize = {};
// if nullptr, means it's a dummy node // if nullptr, means it's a dummy node
WP<CSubsurface> m_pParent; CSubsurface* m_pParent = nullptr;
PHLWINDOWREF m_pWindowParent; PHLWINDOWREF m_pWindowParent;
WP<CPopup> m_pPopupParent; CPopup* m_pPopupParent = nullptr;
std::vector<UP<CSubsurface>> m_vChildren; std::vector<std::unique_ptr<CSubsurface>> m_vChildren;
bool m_bInert = false; bool m_bInert = false;
void initSignals(); void initSignals();
void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface); void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface);
void checkSiblingDamage(); void checkSiblingDamage();
}; };

View File

@@ -1,9 +1,7 @@
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "LayerSurface.hpp" #include "../Compositor.hpp"
#include "../desktop/Window.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../render/Renderer.hpp"
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_pResource = pSurface; m_pResource = pSurface;
@@ -74,7 +72,7 @@ Vector2D CWLSurface::correctSmallVec() const {
const auto SIZE = getViewporterCorrectedSize(); const auto SIZE = getViewporterCorrectedSize();
const auto O = m_pWindowOwner.lock(); const auto O = m_pWindowOwner.lock();
return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize->value() / O->m_vReportedSize); return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize.value() / O->m_vReportedSize);
} }
Vector2D CWLSurface::correctSmallVecBuf() const { Vector2D CWLSurface::correctSmallVecBuf() const {
@@ -98,7 +96,7 @@ CRegion CWLSurface::computeDamage() const {
if (!m_pResource->current.texture) if (!m_pResource->current.texture)
return {}; return {};
CRegion damage = m_pResource->current.accumulateBufferDamage(); CRegion damage = m_pResource->accumulateCurrentBufferDamage();
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y); damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y);
const auto BUFSIZE = m_pResource->current.bufferSize; const auto BUFSIZE = m_pResource->current.bufferSize;

View File

@@ -84,11 +84,7 @@ class CWLSurface {
static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface); static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface);
// used by the alpha-modifier protocol // used by the alpha-modifier protocol
float m_fAlphaModifier = 1.F; float m_pAlphaModifier = 1.F;
// used by the hyprland-surface protocol
float m_fOverallOpacity = 1.F;
CRegion m_visibleRegion;
struct { struct {
CSignal destroy; CSignal destroy;
@@ -120,5 +116,4 @@ class CWLSurface {
} listeners; } listeners;
friend class CPointerConstraint; friend class CPointerConstraint;
friend class CXxColorManagerV4; };
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,10 @@
#pragma once #pragma once
#include <vector> #include <deque>
#include <string> #include <string>
#include <optional>
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
#include "../defines.hpp"
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
@@ -12,26 +12,23 @@
#include "../macros.hpp" #include "../macros.hpp"
#include "../managers/XWaylandManager.hpp" #include "../managers/XWaylandManager.hpp"
#include "../render/decorations/IHyprWindowDecoration.hpp" #include "../render/decorations/IHyprWindowDecoration.hpp"
#include "../render/Transformer.hpp"
#include "DesktopTypes.hpp" #include "DesktopTypes.hpp"
#include "Popup.hpp" #include "Popup.hpp"
#include "Subsurface.hpp" #include "Subsurface.hpp"
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "Workspace.hpp" #include "Workspace.hpp"
#include "WindowRule.hpp"
#include "../protocols/types/ContentType.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
@@ -43,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,
@@ -53,13 +50,12 @@ 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,
SUPPRESS_ACTIVATE = 1 << 2, SUPPRESS_ACTIVATE = 1 << 2,
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3, SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
SUPPRESS_FULLSCREEN_OUTPUT = 1 << 4,
}; };
class IWindowTransformer; class IWindowTransformer;
@@ -68,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
@@ -76,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,
@@ -89,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;
@@ -186,20 +184,34 @@ struct SWindowData {
CWindowOverridableVar<bool> renderUnfocused = false; CWindowOverridableVar<bool> renderUnfocused = false;
CWindowOverridableVar<int> rounding; CWindowOverridableVar<int> rounding;
CWindowOverridableVar<float> roundingPower;
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;
CWindowOverridableVar<CGradientValueData> activeBorderColor; CWindowOverridableVar<CGradientValueData> activeBorderColor;
CWindowOverridableVar<CGradientValueData> inactiveBorderColor; CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
};
CWindowOverridableVar<bool> persistentSize; 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 {
@@ -207,7 +219,7 @@ struct SInitialWorkspaceToken {
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;
}; };
@@ -238,8 +250,8 @@ class CWindow {
Vector2D m_vSize = Vector2D(0, 0); Vector2D m_vSize = Vector2D(0, 0);
// this is the real position and size used to draw the thing // this is the real position and size used to draw the thing
PHLANIMVAR<Vector2D> m_vRealPosition; CAnimatedVariable<Vector2D> m_vRealPosition;
PHLANIMVAR<Vector2D> m_vRealSize; CAnimatedVariable<Vector2D> m_vRealSize;
// for not spamming the protocols // for not spamming the protocols
Vector2D m_vReportedPosition; Vector2D m_vReportedPosition;
@@ -266,7 +278,7 @@ 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};
std::string m_szTitle = ""; std::string m_szTitle = "";
std::string m_szClass = ""; std::string m_szClass = "";
std::string m_szInitialTitle = ""; std::string m_szInitialTitle = "";
@@ -293,37 +305,33 @@ class CWindow {
bool m_bNoInitialFocus = false; bool m_bNoInitialFocus = false;
// Fullscreen and Maximize // Fullscreen and Maximize
bool m_bWantsInitialFullscreen = false; bool m_bWantsInitialFullscreen = false;
MONITORID m_iWantsInitialFullscreenMonitor = MONITOR_INVALID;
// bitfield eSuppressEvents // bitfield eSuppressEvents
uint64_t m_eSuppressedEvents = SUPPRESS_NONE; uint64_t m_eSuppressedEvents = SUPPRESS_NONE;
// desktop components // desktop components
UP<CSubsurface> m_pSubsurfaceHead; std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
UP<CPopup> m_pPopupHead; std::unique_ptr<CPopup> m_pPopupHead;
// Animated border // Animated border
CGradientValueData m_cRealBorderColor = {0}; CGradientValueData m_cRealBorderColor = {0};
CGradientValueData m_cRealBorderColorPrevious = {0}; CGradientValueData m_cRealBorderColorPrevious = {0};
PHLANIMVAR<float> m_fBorderFadeAnimationProgress; CAnimatedVariable<float> m_fBorderFadeAnimationProgress;
PHLANIMVAR<float> m_fBorderAngleAnimationProgress; CAnimatedVariable<float> m_fBorderAngleAnimationProgress;
// Fade in-out // Fade in-out
PHLANIMVAR<float> m_fAlpha; CAnimatedVariable<float> m_fAlpha;
bool m_bFadingOut = false; bool m_bFadingOut = false;
bool m_bReadyToDelete = false; bool m_bReadyToDelete = false;
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
Vector2D m_vOriginalClosedSize; // drawing the closing animations Vector2D m_vOriginalClosedSize; // drawing the closing animations
SBoxExtents m_eOriginalClosedExtents; SBoxExtents m_eOriginalClosedExtents;
bool m_bAnimatingIn = false; bool m_bAnimatingIn = false;
// 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;
@@ -332,33 +340,31 @@ class CWindow {
// Window decorations // Window decorations
// TODO: make this a SP. // TODO: make this a SP.
std::vector<UP<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;
// Transformers // Transformers
std::vector<UP<IWindowTransformer>> m_vTransformers; std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
// for alpha // for alpha
PHLANIMVAR<float> m_fActiveInactiveAlpha; CAnimatedVariable<float> m_fActiveInactiveAlpha;
PHLANIMVAR<float> m_fMovingFromWorkspaceAlpha;
// animated shadow color // animated shadow color
PHLANIMVAR<CHyprColor> m_cRealShadowColor; CAnimatedVariable<CColor> m_cRealShadowColor;
// animated tint // animated tint
PHLANIMVAR<float> m_fDimPercent; CAnimatedVariable<float> m_fDimPercent;
// animate moving to an invisible workspace // animate moving to an invisible workspace
int m_iMonitorMovedFrom = -1; // -1 means not moving int m_iMonitorMovedFrom = -1; // -1 means not moving
PHLANIMVAR<float> m_fMovingToWorkspaceAlpha; CAnimatedVariable<float> m_fMovingToWorkspaceAlpha;
// swallowing // swallowing
PHLWINDOWREF m_pSwallowed; PHLWINDOWREF m_pSwallowed;
bool m_bCurrentlySwallowed = false; bool m_bGroupSwallowed = false;
bool m_bGroupSwallowed = false;
// focus stuff // focus stuff
bool m_bStayFocused = false; bool m_bStayFocused = false;
@@ -385,110 +391,94 @@ 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;
// ANR
PHLANIMVAR<float> m_notRespondingTint;
// 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;
} }
// methods // methods
CBox getFullWindowBoundingBox(); CBox getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents(); SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props); CBox getWindowBoxUnified(uint64_t props);
CBox getWindowIdealBoundingBoxIgnoreReserved(); CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(UP<IHyprWindowDecoration> deco); void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos(); void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco); void removeWindowDeco(IHyprWindowDecoration* deco);
void uncacheWindowDecos(); void uncacheWindowDecos();
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {}); bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
pid_t getPID(); pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType); IHyprWindowDecoration* getDecorationByType(eDecorationType);
void updateToplevel(); void removeDecorationByType(eDecorationType);
void updateSurfaceScaleTransformDetails(bool force = false); void updateToplevel();
void moveToWorkspace(PHLWORKSPACE); void updateSurfaceScaleTransformDetails(bool force = false);
PHLWINDOW x11TransientFor(); void moveToWorkspace(PHLWORKSPACE);
void onUnmap(); PHLWINDOW X11TransientFor();
void onMap(); void onUnmap();
void setHidden(bool hidden); void onMap();
bool isHidden(); void setHidden(bool hidden);
void applyDynamicRule(const SP<CWindowRule>& r); bool isHidden();
void updateDynamicRules(); void applyDynamicRule(const SWindowRule& r);
SBoxExtents getFullWindowReservedArea(); void updateDynamicRules();
Vector2D middle(); SBoxExtents getFullWindowReservedArea();
bool opaque(); Vector2D middle();
float rounding(); bool opaque();
float roundingPower(); float rounding();
bool canBeTorn(); bool canBeTorn();
void setSuspended(bool suspend); void setSuspended(bool suspend);
bool visibleOnMonitor(PHLMONITOR pMonitor); bool visibleOnMonitor(PHLMONITOR pMonitor);
WORKSPACEID workspaceID(); WORKSPACEID workspaceID();
MONITORID monitorID(); 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); 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(); void updateWindowData();
float getScrollTouchpad(); void updateWindowData(const struct SWorkspaceRule&);
void updateWindowData(); void onBorderAngleAnimEnd(void* ptr);
void updateWindowData(const struct SWorkspaceRule&); bool isInCurvedCorner(double x, double y);
void onBorderAngleAnimEnd(WP<Hyprutils::Animation::CBaseAnimatedVariable> pav); bool hasPopupAt(const Vector2D& pos);
bool isInCurvedCorner(double x, double y); int popupsCount();
bool hasPopupAt(const Vector2D& pos); void applyGroupRules();
int popupsCount(); void createGroup();
void applyGroupRules(); void destroyGroup();
void createGroup(); PHLWINDOW getGroupHead();
void destroyGroup(); PHLWINDOW getGroupTail();
PHLWINDOW getGroupHead(); PHLWINDOW getGroupCurrent();
PHLWINDOW getGroupTail(); PHLWINDOW getGroupPrevious();
PHLWINDOW getGroupCurrent(); PHLWINDOW getGroupWindowByIndex(int);
PHLWINDOW getGroupPrevious(); int getGroupSize();
PHLWINDOW getGroupWindowByIndex(int); bool canBeGroupedInto(PHLWINDOW pWindow);
int getGroupSize(); void setGroupCurrent(PHLWINDOW pWindow);
bool canBeGroupedInto(PHLWINDOW pWindow); void insertWindowToGroup(PHLWINDOW pWindow);
void setGroupCurrent(PHLWINDOW pWindow); void updateGroupOutputs();
void insertWindowToGroup(PHLWINDOW pWindow); void switchWithWindowInGroup(PHLWINDOW pWindow);
void updateGroupOutputs(); void setAnimationsToMove();
void switchWithWindowInGroup(PHLWINDOW pWindow); void onWorkspaceAnimUpdate();
void setAnimationsToMove(); void onUpdateState();
void onWorkspaceAnimUpdate(); void onUpdateMeta();
void onFocusAnimUpdate(); void onX11Configure(CBox box);
void onUpdateState(); void onResourceChangeX11();
void onUpdateMeta(); std::string fetchTitle();
void onX11ConfigureRequest(CBox box); std::string fetchClass();
void onResourceChangeX11(); void warpCursor();
std::string fetchTitle(); PHLWINDOW getSwallower();
std::string fetchClass(); void unsetWindowData(eOverridePriority priority);
void warpCursor(bool force = false); bool isX11OverrideRedirect();
PHLWINDOW getSwallower(); bool isModal();
void unsetWindowData(eOverridePriority priority); Vector2D requestedMinSize();
bool isX11OverrideRedirect(); Vector2D requestedMaxSize();
bool isModal();
Vector2D requestedMinSize();
Vector2D requestedMaxSize();
Vector2D realToReportSize();
Vector2D realToReportPosition();
Vector2D xwaylandSizeToReal(Vector2D size);
Vector2D xwaylandPositionToReal(Vector2D size);
void updateX11SurfaceScale();
void sendWindowSize(bool force = false);
NContentType::eContentType getContentType();
void setContentType(NContentType::eContentType contentType);
void deactivateGroupMembers();
bool isNotResponding();
CBox getWindowMainSurfaceBox() const { inline CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
} }
// listeners // listeners
@@ -508,7 +498,7 @@ class CWindow {
CHyprSignalListener commit; CHyprSignalListener commit;
CHyprSignalListener destroy; CHyprSignalListener destroy;
CHyprSignalListener activate; CHyprSignalListener activate;
CHyprSignalListener configureRequest; CHyprSignalListener configure;
CHyprSignalListener setGeometry; CHyprSignalListener setGeometry;
CHyprSignalListener updateState; CHyprSignalListener updateState;
CHyprSignalListener updateMetadata; CHyprSignalListener updateMetadata;
@@ -542,42 +532,6 @@ inline bool validMapped(PHLWINDOWREF w) {
return w->m_bIsMapped; return w->m_bIsMapped;
} }
namespace NWindowProperties {
static const std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> boolWindowProperties = {
{"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }},
};
const std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> intWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }},
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }},
};
const std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> floatWindowProperties = {
{"roundingpower", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.roundingPower; }},
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }},
};
};
/** /**
format specification format specification
- 'x', only address, equivalent of (uintpr_t)CWindow* - 'x', only address, equivalent of (uintpr_t)CWindow*

View File

@@ -1,96 +0,0 @@
#include "WindowRule.hpp"
#include <unordered_set>
#include <algorithm>
#include <re2/re2.h>
#include "../config/ConfigManager.hpp"
static const auto RULES = std::unordered_set<std::string>{
"float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", "persistentsize",
};
static const auto RULES_PREFIX = std::unordered_set<std::string>{
"animation", "bordercolor", "bordersize", "center", "content", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize",
"monitor", "move", "opacity", "plugin:", "prop", "pseudo", "rounding", "roundingpower", "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); }) ||
(NWindowProperties::boolWindowProperties.find(VALS[0]) != NWindowProperties::boolWindowProperties.end()) ||
(NWindowProperties::intWindowProperties.find(VALS[0]) != NWindowProperties::intWindowProperties.end()) ||
(NWindowProperties::floatWindowProperties.find(VALS[0]) != NWindowProperties::floatWindowProperties.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 == "persistentsize")
ruleType = RULE_PERSISTENTSIZE;
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 if (rule.starts_with("content"))
ruleType = RULE_CONTENT;
else {
// check if this is a prop.
const CVarList VARS(rule, 0, 's', true);
if (NWindowProperties::intWindowProperties.find(VARS[0]) != NWindowProperties::intWindowProperties.end() ||
NWindowProperties::boolWindowProperties.find(VARS[0]) != NWindowProperties::boolWindowProperties.end() ||
NWindowProperties::floatWindowProperties.find(VARS[0]) != NWindowProperties::floatWindowProperties.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,71 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
#include "Rule.hpp"
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,
RULE_CONTENT,
RULE_PERSISTENTSIZE,
};
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
std::string szContentType = ""; // empty means any
// precompiled regexes
CRuleRegexContainer rTitle;
CRuleRegexContainer rClass;
CRuleRegexContainer rInitialTitle;
CRuleRegexContainer rInitialClass;
CRuleRegexContainer rV1Regex;
};

View File

@@ -1,12 +1,7 @@
#include "Workspace.hpp" #include "Workspace.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "config/ConfigManager.hpp"
#include "managers/AnimationManager.hpp"
#include "../managers/EventManager.hpp"
#include "../managers/HookSystemManager.hpp"
#include <hyprutils/animation/AnimatedVariable.hpp>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
@@ -16,18 +11,27 @@ PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string
return workspace; return workspace;
} }
CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) : CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) {
m_iID(id), m_szName(name), m_pMonitor(monitor), m_bIsSpecialWorkspace(special), m_bWasCreatedEmpty(isEmpty) { m_pMonitor = monitor;
; m_iID = id;
m_szName = name;
m_bIsSpecialWorkspace = special;
m_bWasCreatedEmpty = isEmpty;
} }
void CWorkspace::init(PHLWORKSPACE self) { void CWorkspace::init(PHLWORKSPACE self) {
m_pSelf = self; m_pSelf = self;
g_pAnimationManager->createAnimation(Vector2D(0, 0), m_vRenderOffset, m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") :
g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, AVARDAMAGE_ENTIRE); g_pConfigManager->getAnimationPropertyConfig("workspacesIn"),
g_pAnimationManager->createAnimation(1.f, m_fAlpha, g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, self, AVARDAMAGE_ENTIRE);
AVARDAMAGE_ENTIRE); m_fAlpha.create(AVARTYPE_FLOAT,
m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), self,
AVARDAMAGE_ENTIRE);
m_fAlpha.setValueAndWarp(1.f);
m_vRenderOffset.registerVar();
m_fAlpha.registerVar();
const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self); const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self);
if (RULEFORTHIS.defaultName.has_value()) if (RULEFORTHIS.defaultName.has_value())
@@ -54,11 +58,16 @@ void CWorkspace::init(PHLWORKSPACE self) {
EMIT_HOOK_EVENT("createWorkspace", this); EMIT_HOOK_EVENT("createWorkspace", this);
} }
SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName() const { SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName(bool perMonitor) const {
if (perMonitor)
return m_sPrevWorkspacePerMonitor;
return m_sPrevWorkspace; return m_sPrevWorkspace;
} }
CWorkspace::~CWorkspace() { CWorkspace::~CWorkspace() {
m_vRenderOffset.unregister();
Debug::log(LOG, "Destroying workspace ID {}", m_iID); Debug::log(LOG, "Destroying workspace ID {}", m_iID);
// check if g_pHookSystem and g_pEventManager exist, they might be destroyed as in when the compositor is closing. // check if g_pHookSystem and g_pEventManager exist, they might be destroyed as in when the compositor is closing.
@@ -76,15 +85,15 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
if (!instant) { if (!instant) {
const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out"); const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out");
m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME);
m_vRenderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); m_vRenderOffset.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME);
} }
const auto ANIMSTYLE = m_fAlpha->getStyle(); const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
// set floating windows offset callbacks // set floating windows offset callbacks
m_vRenderOffset->setUpdateCallback([&](auto) { m_vRenderOffset.setUpdateCallback([&](void*) {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (!validMapped(w) || w->workspaceID() != m_iID) if (!validMapped(w) || w->workspaceID() != m_iID)
continue; continue;
@@ -97,91 +106,91 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_pMonitor.lock();
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));
} catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); } } catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); }
} }
m_fAlpha->setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
if (ANIMSTYLE.starts_with("slidefadevert")) { if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) { if (in) {
m_fAlpha->setValueAndWarp(0.f); m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
*m_fAlpha = 1.f; m_fAlpha = 1.f;
*m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_fAlpha->setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
*m_fAlpha = 0.f; m_fAlpha = 0.f;
*m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
} }
} else { } else {
if (in) { if (in) {
m_fAlpha->setValueAndWarp(0.f); m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0)); m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0));
*m_fAlpha = 1.f; m_fAlpha = 1.f;
*m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_fAlpha->setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
*m_fAlpha = 0.f; m_fAlpha = 0.f;
*m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0); m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0);
} }
} }
} else if (ANIMSTYLE == "fade") { } else if (ANIMSTYLE == "fade") {
m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade. m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade.
if (in) { if (in) {
m_fAlpha->setValueAndWarp(0.f); m_fAlpha.setValueAndWarp(0.f);
*m_fAlpha = 1.f; m_fAlpha = 1.f;
} else { } else {
m_fAlpha->setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
*m_fAlpha = 0.f; m_fAlpha = 0.f;
} }
} else if (ANIMSTYLE == "slidevert") { } else if (ANIMSTYLE == "slidevert") {
// fallback is slide // fallback is slide
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_pMonitor.lock();
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.
if (in) { if (in) {
m_vRenderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE)); m_vRenderOffset.setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
*m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
*m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE); m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
} }
} else { } else {
// fallback is slide // fallback is slide
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_pMonitor.lock();
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.
if (in) { if (in) {
m_vRenderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0)); m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
*m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
*m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0); m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
} }
} }
if (m_bIsSpecialWorkspace) { if (m_bIsSpecialWorkspace) {
// required for open/close animations // required for open/close animations
if (in) { if (in) {
m_fAlpha->setValueAndWarp(0.f); m_fAlpha.setValueAndWarp(0.f);
*m_fAlpha = 1.f; m_fAlpha = 1.f;
} else { } else {
m_fAlpha->setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
*m_fAlpha = 0.f; m_fAlpha = 0.f;
} }
} }
if (instant) { if (instant) {
m_vRenderOffset->warp(); m_vRenderOffset.warp();
m_fAlpha->warp(); m_fAlpha.warp();
} }
} }
@@ -215,7 +224,10 @@ 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;
prev->m_pMonitor->addPrevWorkspaceID(prev->m_iID); if (prev->m_pMonitor == m_pMonitor) {
m_sPrevWorkspacePerMonitor.id = prev->m_iID;
m_sPrevWorkspacePerMonitor.name = prev->m_szName;
}
} }
std::string CWorkspace::getConfigName() { std::string CWorkspace::getConfigName() {
@@ -261,15 +273,14 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
// n - named: n[true] or n[s:string] or n[e:string] // n - named: n[true] or n[s:string] or n[e:string]
// m - monitor: m[monitor_selector] // m - monitor: m[monitor_selector]
// w - windowCount: w[1-4] or w[1], optional flag t or f for tiled or floating and // w - windowCount: w[1-4] or w[1], optional flag t or f for tiled or floating and
// flag p to count only pinned windows, e.g. w[p1-2], w[pg4]
// flag g to count groups instead of windows, e.g. w[t1-2], w[fg4] // flag g to count groups instead of windows, e.g. w[t1-2], w[fg4]
// flag v will count only visible windows // flag v will count only visible windows
// 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;
@@ -285,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)) {
@@ -321,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;
} }
@@ -356,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;
} }
@@ -371,7 +382,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
prop = prop.substr(2, prop.length() - 3); prop = prop.substr(2, prop.length() - 3);
int wantsOnlyTiled = -1; int wantsOnlyTiled = -1;
int wantsOnlyPinned = false;
bool wantsCountGroup = false; bool wantsCountGroup = false;
bool wantsCountVisible = false; bool wantsCountVisible = false;
@@ -383,9 +393,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
} else if (flag == 'f' && wantsOnlyTiled == -1) { } else if (flag == 'f' && wantsOnlyTiled == -1) {
wantsOnlyTiled = 0; wantsOnlyTiled = 0;
flagCount++; flagCount++;
} else if (flag == 'p' && !wantsOnlyPinned) {
wantsOnlyPinned = true;
flagCount++;
} else if (flag == 'g' && !wantsCountGroup) { } else if (flag == 'g' && !wantsCountGroup) {
wantsCountGroup = true; wantsCountGroup = true;
flagCount++; flagCount++;
@@ -415,20 +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),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt, 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),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt, 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)) {
@@ -451,13 +456,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
WORKSPACEID count; WORKSPACEID count;
if (wantsCountGroup) if (wantsCountGroup)
count = count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : 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),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt, 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;
@@ -522,148 +525,3 @@ bool CWorkspace::inert() {
MONITORID CWorkspace::monitorID() { MONITORID CWorkspace::monitorID() {
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID; 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> onlyPinned, 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 (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
}
return no;
}
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, 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 (onlyPinned.has_value() && w->m_bPinned != onlyPinned.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;
w->sendWindowSize(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;
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock());
m_bPersistent = WORKSPACERULE.isPersistent;
if (WORKSPACERULE.isPersistent)
g_pCompositor->ensurePersistentWorkspacesPresent(std::vector<SWorkspaceRule>{WORKSPACERULE}, m_pSelf.lock());
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

@@ -24,19 +24,22 @@ class 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; PHLMONITORREF m_pMonitor;
// Previous workspace ID and name is stored during a workspace change, allowing travel
// to the previous workspace.
SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor;
bool m_bHasFullscreenWindow = false; bool m_bHasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FSMODE_NONE; eFullscreenMode m_efFullscreenMode = FSMODE_NONE;
wl_array m_wlrCoordinateArr; wl_array m_wlrCoordinateArr;
// for animations // for animations
PHLANIMVAR<Vector2D> m_vRenderOffset; CAnimatedVariable<Vector2D> m_vRenderOffset;
PHLANIMVAR<float> m_fAlpha; CAnimatedVariable<float> m_fAlpha;
bool m_bForceRendering = false; bool m_bForceRendering = false;
// allows damage to propagate. // allows damage to propagate.
bool m_bVisible = false; bool m_bVisible = false;
@@ -60,35 +63,26 @@ 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(); 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() const;
void updateWindowDecos(); SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const;
void updateWindowData();
int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyPinned = {}, std::optional<bool> onlyVisible = {});
int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyPinned = {}, 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);
// Previous workspace ID and name is stored during a workspace change, allowing travel
// to the previous workspace.
SWorkspaceIDName m_sPrevWorkspace;
SP<HOOK_CALLBACK_FN> m_pFocusedWindowHook; SP<HOOK_CALLBACK_FN> m_pFocusedWindowHook;
bool m_bInert = true; bool m_bInert = true;

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();

View File

@@ -8,8 +8,6 @@
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>
#include <cstring> #include <cstring>
using namespace Hyprutils::OS;
#define LED_COUNT 3 #define LED_COUNT 3
constexpr static std::array<const char*, 8> MODNAMES = { constexpr static std::array<const char*, 8> MODNAMES = {
@@ -43,14 +41,13 @@ void IKeyboard::clearManuallyAllocd() {
if (xkbKeymap) if (xkbKeymap)
xkb_keymap_unref(xkbKeymap); xkb_keymap_unref(xkbKeymap);
if (xkbSymState) if (xkbKeymapFD >= 0)
xkb_state_unref(xkbSymState); close(xkbKeymapFD);
xkbSymState = nullptr;
xkbKeymap = nullptr; xkbKeymap = nullptr;
xkbState = nullptr; xkbState = nullptr;
xkbStaticState = nullptr; xkbStaticState = nullptr;
xkbKeymapFD.reset(); xkbKeymapFD = -1;
} }
void IKeyboard::setKeymap(const SStringRuleNames& rules) { void IKeyboard::setKeymap(const SStringRuleNames& rules) {
@@ -126,14 +123,14 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
updateModifiers(0, 0, modifiersState.locked, modifiersState.group); updateModifiers(0, 0, modifiersState.locked, modifiersState.group);
} }
for (size_t i = 0; i < std::min(LEDNAMES.size(), ledIndexes.size()); ++i) { for (size_t i = 0; i < LEDNAMES.size(); ++i) {
ledIndexes[i] = xkb_map_led_get_index(xkbKeymap, LEDNAMES[i]); ledIndexes.at(i) = xkb_map_led_get_index(xkbKeymap, LEDNAMES.at(i));
Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES[i], ledIndexes[i]); Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES.at(i), ledIndexes.at(i));
} }
for (size_t i = 0; i < std::min(MODNAMES.size(), modIndexes.size()); ++i) { for (size_t i = 0; i < MODNAMES.size(); ++i) {
modIndexes[i] = xkb_map_mod_get_index(xkbKeymap, MODNAMES[i]); modIndexes.at(i) = xkb_map_mod_get_index(xkbKeymap, MODNAMES.at(i));
Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES[i], modIndexes[i]); Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i));
} }
updateKeymapFD(); updateKeymapFD();
@@ -146,30 +143,31 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
void IKeyboard::updateKeymapFD() { void IKeyboard::updateKeymapFD() {
Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName); Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName);
if (xkbKeymapFD.isValid()) if (xkbKeymapFD >= 0)
xkbKeymapFD.reset(); close(xkbKeymapFD);
xkbKeymapFD = -1;
auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
xkbKeymapString = cKeymapStr; xkbKeymapString = cKeymapStr;
free(cKeymapStr); free(cKeymapStr);
CFileDescriptor rw, ro; int rw, ro;
if (!allocateSHMFilePair(xkbKeymapString.length() + 1, rw, ro)) if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro))
Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap"); Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap");
else { else {
auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw.get(), 0); auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0);
rw.reset(); close(rw);
if (keymapFDDest == MAP_FAILED) { if (keymapFDDest == MAP_FAILED) {
Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap"); Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap");
ro.reset(); close(ro);
} else { } else {
memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length()); memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length());
munmap(keymapFDDest, xkbKeymapString.length() + 1); munmap(keymapFDDest, xkbKeymapString.length() + 1);
xkbKeymapFD = std::move(ro); xkbKeymapFD = ro;
} }
} }
Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD.get()); Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD);
} }
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
@@ -289,8 +287,8 @@ std::optional<uint32_t> IKeyboard::getLEDs() {
return {}; return {};
uint32_t leds = 0; uint32_t leds = 0;
for (uint32_t i = 0; i < std::min((size_t)LED_COUNT, ledIndexes.size()); ++i) { for (uint32_t i = 0; i < LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(xkbState, ledIndexes[i])) if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i)))
leds |= (1 << i); leds |= (1 << i);
} }
@@ -323,10 +321,10 @@ uint32_t IKeyboard::getModifiers() {
uint32_t modMask = modifiersState.depressed | modifiersState.latched; uint32_t modMask = modifiersState.depressed | modifiersState.latched;
uint32_t mods = 0; uint32_t mods = 0;
for (size_t i = 0; i < modIndexes.size(); ++i) { for (size_t i = 0; i < modIndexes.size(); ++i) {
if (modIndexes[i] == XKB_MOD_INVALID) if (modIndexes.at(i) == XKB_MOD_INVALID)
continue; continue;
if (!(modMask & (1 << modIndexes[i]))) if (!(modMask & (1 << modIndexes.at(i))))
continue; continue;
mods |= (1 << i); mods |= (1 << i);

View File

@@ -6,7 +6,6 @@
#include <optional> #include <optional>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <hyprutils/os/FileDescriptor.hpp>
AQUAMARINE_FORWARD(IKeyboard); AQUAMARINE_FORWARD(IKeyboard);
@@ -97,7 +96,7 @@ class IKeyboard : public IHID {
std::string xkbFilePath = ""; std::string xkbFilePath = "";
std::string xkbKeymapString = ""; std::string xkbKeymapString = "";
Hyprutils::OS::CFileDescriptor xkbKeymapFD; int xkbKeymapFD = -1;
SStringRuleNames currentRules; SStringRuleNames currentRules;
int repeatRate = 0; int repeatRate = 0;

View File

@@ -17,10 +17,8 @@ class IPointer : public IHID {
virtual SP<Aquamarine::IPointer> aq() = 0; virtual SP<Aquamarine::IPointer> aq() = 0;
struct SMotionEvent { struct SMotionEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;
Vector2D delta, unaccel; Vector2D delta, unaccel;
bool mouse = false;
SP<IPointer> device;
}; };
struct SMotionAbsoluteEvent { struct SMotionAbsoluteEvent {
@@ -33,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 {
@@ -43,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 {
@@ -110,9 +106,6 @@ class IPointer : public IHID {
bool connected = false; // means connected to the cursor bool connected = false; // means connected to the cursor
std::string boundOutput = ""; std::string boundOutput = "";
bool flipX = false; // decide to invert horizontal movement
bool flipY = false; // decide to invert vertical movement
bool isTouchpad = false;
WP<IPointer> self; WP<IPointer> self;
}; };

View File

@@ -1,5 +1,6 @@
#include "Keyboard.hpp" #include "Keyboard.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../Compositor.hpp"
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>

View File

@@ -14,11 +14,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
if (!mouse) if (!mouse)
return; return;
if (auto handle = mouse->getLibinputHandle()) {
double w = 0, h = 0;
isTouchpad = libinput_device_has_capability(handle, LIBINPUT_DEVICE_CAP_POINTER) && libinput_device_get_size(handle, &w, &h) == 0;
}
listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) { listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) {
mouse.reset(); mouse.reset();
events.destroy.emit(); events.destroy.emit();
@@ -31,8 +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,
.device = self.lock(),
}); });
}); });
@@ -53,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,
}); });
}); });
@@ -67,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

@@ -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,9 @@ class CTablet : public IHID {
WP<CTablet> self; WP<CTablet> self;
bool relativeInput = false; bool relativeInput = false;
bool absolutePos = false;
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);
@@ -172,7 +172,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 +183,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),

View File

@@ -11,7 +11,7 @@ SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resour
} }
CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : pointer(resource) { CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : pointer(resource) {
if UNLIKELY (!resource->good()) if (!resource->good())
return; return;
listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) { listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) {
@@ -19,11 +19,7 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
events.destroy.emit(); events.destroy.emit();
}); });
listeners.motion = pointer->events.move.registerListener([this](std::any d) { listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
auto E = std::any_cast<SMotionEvent>(d);
E.device = self.lock();
pointerEvents.motion.emit(E);
});
listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) { listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) {
// we need to unpack the event and add our device here because it's required to calculate the position correctly // we need to unpack the event and add our device here because it's required to calculate the position correctly
auto E = std::any_cast<SMotionAbsoluteEvent>(d); auto E = std::any_cast<SMotionAbsoluteEvent>(d);
@@ -42,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);

View File

@@ -11,18 +11,11 @@
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/ToplevelExport.hpp" #include "../protocols/ToplevelExport.hpp"
#include "../protocols/types/ContentType.hpp"
#include "../xwayland/XSurface.hpp" #include "../xwayland/XSurface.hpp"
#include "managers/AnimationManager.hpp"
#include "managers/PointerManager.hpp" #include "managers/PointerManager.hpp"
#include "../desktop/LayerSurface.hpp"
#include "../managers/LayoutManager.hpp"
#include "../managers/EventManager.hpp"
#include "../managers/AnimationManager.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::Animation;
// ------------------------------------------------------------ // // ------------------------------------------------------------ //
// __ _______ _ _ _____ ______ _______ // // __ _______ _ _ _____ ______ _______ //
@@ -34,17 +27,15 @@ using namespace Hyprutils::Animation;
// // // //
// ------------------------------------------------------------ // // ------------------------------------------------------------ //
static void setVector2DAnimToMove(WP<CBaseAnimatedVariable> pav) { void setAnimToMove(void* data) {
const auto PAV = pav.lock(); auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
if (!PAV)
return;
CAnimatedVariable<Vector2D>* animvar = dynamic_cast<CAnimatedVariable<Vector2D>*>(PAV.get()); CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data;
animvar->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
const auto PHLWINDOW = animvar->m_Context.pWindow.lock(); animvar->setConfig(PANIMCFG);
if (PHLWINDOW)
PHLWINDOW->m_bAnimatingIn = false; if (animvar->getWindow() && !animvar->getWindow()->m_vRealPosition.isBeingAnimated() && !animvar->getWindow()->m_vRealSize.isBeingAnimated())
animvar->getWindow()->m_bAnimatingIn = false;
} }
void Events::listener_mapWindow(void* owner, void* data) { void Events::listener_mapWindow(void* owner, void* data) {
@@ -130,193 +121,162 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->isX11OverrideRedirect() && !PWINDOW->m_pXWaylandSurface->wantsFocus()); PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->isX11OverrideRedirect() && !PWINDOW->m_pXWaylandSurface->wantsFocus());
if (PWORKSPACE->m_bDefaultFloating)
PWINDOW->m_bIsFloating = true;
if (PWORKSPACE->m_bDefaultPseudo) {
PWINDOW->m_bIsPseudotiled = true;
CBox desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry);
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
}
// 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;
MONITORID requestedFSMonitor = PWINDOW->m_iWantsInitialFullscreenMonitor;
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_pMonitor = PMONITOR;
} else {
if (isNumber(MONITORSTR)) {
const MONITORID MONITOR = std::stoi(MONITORSTR);
if (const auto PM = g_pCompositor->getMonitorFromID(MONITOR); PM)
PWINDOW->m_pMonitor = PM;
else
PWINDOW->m_pMonitor = g_pCompositor->m_vMonitors.at(0);
} 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_pMonitor = PMONITOR;
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(); const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock();
if (PWINDOW->m_pMonitor != PMONITOR) { if (PWINDOW->m_pMonitor != PMONITOR) {
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID())); g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID()));
PMONITOR = PMONITORFROMID; PMONITOR = PMONITORFROMID;
} }
PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
PWORKSPACE = PWINDOW->m_pWorkspace;
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW); Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
requestedFSMonitor = MONITOR_INVALID; } catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r->szRule, r->szValue, e.what()); } } else if (r.szRule.starts_with("workspace")) {
break; // 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_WORKSPACE: {
// check if it isnt unset
const auto WORKSPACERQ = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
if (WORKSPACERQ == "unset") const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ;
requestedWorkspace = "";
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 else
requestedWorkspace = WORKSPACERQ; Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
}
} else if (r.szRule == "pin") {
PWINDOW->m_bPinned = true;
} 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;
const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ; // `group` is a shorthand of `group set`
if (trim(r.szRule) == "group") {
PWINDOW->m_eGroupRules |= GROUP_SET;
continue;
}
if (JUSTWORKSPACE == PWORKSPACE->m_szName || JUSTWORKSPACE == "name:" + PWORKSPACE->m_szName) CVarList vars(r.szRule, 0, 's');
requestedWorkspace = ""; std::string vPrev = "";
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r->szValue); for (auto const& v : vars) {
requestedFSMonitor = MONITOR_INVALID; if (v == "group")
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 if (vars[i] == "fullscreenoutput")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN_OUTPUT;
else
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
}
break;
}
case CWindowRule::RULE_PIN: {
PWINDOW->m_bPinned = true;
break;
}
case CWindowRule::RULE_FULLSCREEN: {
requestedInternalFSMode = FSMODE_FULLSCREEN;
break;
}
case CWindowRule::RULE_MAXIMIZE: {
requestedInternalFSMode = FSMODE_MAXIMIZED;
break;
}
case CWindowRule::RULE_STAYFOCUSED: {
PWINDOW->m_bStayFocused = true;
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;
} }
case CWindowRule::RULE_CONTENT: {
const CVarList VARS(r->szRule, 0, ' ');
try {
PWINDOW->setContentType(NContentType::fromString(VARS[1]));
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
default: break;
} }
PWINDOW->applyDynamicRule(r); PWINDOW->applyDynamicRule(r);
} }
@@ -349,51 +309,20 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!workspaceSilent) { if (!workspaceSilent) {
if (pWorkspace->m_bIsSpecialWorkspace) if (pWorkspace->m_bIsSpecialWorkspace)
pWorkspace->m_pMonitor->setSpecialWorkspace(pWorkspace); pWorkspace->m_pMonitor->setSpecialWorkspace(pWorkspace);
else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID && !PWINDOW->m_bNoInitialFocus) 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.lock();
} }
requestedFSMonitor = MONITOR_INVALID;
} else } else
workspaceSilent = false; workspaceSilent = false;
} }
if (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT)
requestedFSMonitor = MONITOR_INVALID;
else if (requestedFSMonitor != MONITOR_INVALID) {
if (const auto PM = g_pCompositor->getMonitorFromID(requestedFSMonitor); PM)
PWINDOW->m_pMonitor = PM;
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;
PWORKSPACE = PWINDOW->m_pWorkspace;
Debug::log(LOG, "Requested monitor, applying to {:mw}", PWINDOW);
}
if (PWORKSPACE->m_bDefaultFloating)
PWINDOW->m_bIsFloating = true;
if (PWORKSPACE->m_bDefaultPseudo) {
PWINDOW->m_bIsPseudotiled = true;
CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(PWINDOW);
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
}
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. // 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(); const auto SWALLOWER = PWINDOW->getSwallower();
PWINDOW->m_pSwallowed = SWALLOWER; PWINDOW->m_pSwallowed = SWALLOWER;
if (PWINDOW->m_pSwallowed)
PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = true;
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
@@ -401,139 +330,131 @@ void Events::listener_mapWindow(void* owner, void* data) {
// 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 {
auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) {
if (VALUE.starts_with('<'))
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); auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) {
}; if (VALUE.starts_with('<'))
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));
const auto VALUE = r->szRule.substr(r->szRule.find(' ') + 1); return stringToPercentage(VALUE, REL);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); };
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto MAXSIZE = PWINDOW->requestedMaxSize(); 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 float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : const auto MAXSIZE = PWINDOW->requestedMaxSize();
stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize->goal().x, PMONITOR->vecSize.x);
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) :
stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize->goal().y, PMONITOR->vecSize.y); stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x);
Debug::log(LOG, "Rule size, applying to {}", PWINDOW); const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) :
stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y);
PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY}); Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
PWINDOW->setHidden(false); PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY});
} 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"); PWINDOW->setHidden(false);
} 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);
if (ONSCREEN) const bool ONSCREEN = value.starts_with("onscreen");
value = value.substr(value.find_first_of(' ') + 1);
const bool CURSOR = value.starts_with("cursor"); if (ONSCREEN)
value = value.substr(value.find_first_of(' ') + 1);
const bool CURSOR = value.starts_with("cursor");
if (CURSOR)
value = value.substr(value.find_first_of(' ') + 1);
const auto POSXSTR = value.substr(0, value.find(' '));
const auto POSYSTR = value.substr(value.find(' ') + 1);
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;
} }
} }
// set the pseudo size to the GOAL of our current size // set the pseudo size to the GOAL of our current size
// because the windows are animated on RealSize // because the windows are animated on RealSize
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize->goal(); PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal();
g_pCompositor->changeWindowZOrder(PWINDOW, true); g_pCompositor->changeWindowZOrder(PWINDOW, true);
} else { } else {
@@ -542,31 +463,30 @@ 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 = PWINDOW->requestedMaxSize();
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 float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x);
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x); const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : stringToPercentage(SIZEYSTR, PMONITOR->vecSize.y);
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : stringToPercentage(SIZEYSTR, PMONITOR->vecSize.y); Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW);
Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW); setPseudo = true;
PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY);
setPseudo = true; PWINDOW->setHidden(false);
PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY); } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
}
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->szRule, r->szValue); }
} }
if (!setPseudo) if (!setPseudo)
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize->goal() - Vector2D(10, 10); PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10);
} }
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock(); const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock();
@@ -589,18 +509,18 @@ 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 &&
(!PWINDOW->isX11OverrideRedirect() || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && (!PWINDOW->isX11OverrideRedirect() || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) &&
!g_pInputManager->isConstrained()) { !g_pInputManager->isConstrained()) {
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
PWINDOW->m_fDimPercent->setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH); PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH);
} else { } else {
PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PINACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
PWINDOW->m_fDimPercent->setValueAndWarp(0); PWINDOW->m_fDimPercent.setValueAndWarp(0);
} }
if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
@@ -611,15 +531,15 @@ 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();
if (requestedFSState.has_value()) { if (requestedFSState.has_value()) {
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())
@@ -649,7 +569,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bFirstMap = false; PWINDOW->m_bFirstMap = false;
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition->goal(), PWINDOW->m_vRealSize->goal()); Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goal(), PWINDOW->m_vRealSize.goal());
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName; auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, PWINDOW->m_szClass, PWINDOW->m_szTitle)}); g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, PWINDOW->m_szClass, PWINDOW->m_szTitle)});
@@ -662,17 +582,17 @@ void Events::listener_mapWindow(void* owner, void* data) {
// do animations // do animations
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false); g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
PWINDOW->m_fAlpha->setValueAndWarp(0.f); PWINDOW->m_fAlpha.setValueAndWarp(0.f);
*PWINDOW->m_fAlpha = 1.f; PWINDOW->m_fAlpha = 1.f;
PWINDOW->m_vRealPosition->setCallbackOnEnd(setVector2DAnimToMove); PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove);
PWINDOW->m_vRealSize->setCallbackOnEnd(setVector2DAnimToMove); PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove);
// recalc the values for this window // recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
// avoid this window being visible // avoid this window being visible
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen() && !PWINDOW->m_bIsFloating) if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen() && !PWINDOW->m_bIsFloating)
PWINDOW->m_fAlpha->setValueAndWarp(0.f); PWINDOW->m_fAlpha.setValueAndWarp(0.f);
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale); g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->transform); g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->transform);
@@ -683,8 +603,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;
@@ -708,40 +627,30 @@ void Events::listener_unmapWindow(void* owner, void* data) {
const auto PMONITOR = PWINDOW->m_pMonitor.lock(); const auto PMONITOR = PWINDOW->m_pMonitor.lock();
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();
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents(); PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
} }
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)}); g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
EMIT_HOOK_EVENT("closeWindow", PWINDOW); EMIT_HOOK_EVENT("closeWindow", PWINDOW);
if (PWINDOW->m_bIsFloating && !PWINDOW->m_bIsX11 &&
std::any_of(PWINDOW->m_vMatchedRules.begin(), PWINDOW->m_vMatchedRules.end(), [](const auto& r) { return r->ruleType == CWindowRule::RULE_PERSISTENTSIZE; })) {
Debug::log(LOG, "storing floating size {}x{} for window {}::{} on close", PWINDOW->m_vRealSize->value().x, PWINDOW->m_vRealSize->value().y, PWINDOW->m_szClass,
PWINDOW->m_szTitle);
g_pConfigManager->storeFloatingSize(PWINDOW, PWINDOW->m_vRealSize->value());
}
PROTO::toplevelExport->onWindowUnmap(PWINDOW); PROTO::toplevelExport->onWindowUnmap(PWINDOW);
if (PWINDOW->isFullscreen()) if (PWINDOW->isFullscreen())
g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE);
// Allow the renderer to catch the last frame. // Allow the renderer to catch the last frame.
g_pHyprRenderer->makeWindowSnapshot(PWINDOW); g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
// swallowing // swallowing
if (valid(PWINDOW->m_pSwallowed)) { if (valid(PWINDOW->m_pSwallowed)) {
if (PWINDOW->m_pSwallowed->m_bCurrentlySwallowed) { PWINDOW->m_pSwallowed->setHidden(false);
PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = false;
PWINDOW->m_pSwallowed->setHidden(false);
if (PWINDOW->m_sGroupData.pNextWindow.lock()) 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. 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->m_bGroupSwallowed = false;
PWINDOW->m_pSwallowed.reset(); PWINDOW->m_pSwallowed.reset();
@@ -790,7 +699,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();
@@ -809,19 +718,18 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pCompositor->addToFadingOutSafe(PWINDOW); g_pCompositor->addToFadingOutSafe(PWINDOW);
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
// anims // anims
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true); g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true);
*PWINDOW->m_fAlpha = 0.f; PWINDOW->m_fAlpha = 0.f;
// recheck idle inhibitors // recheck idle inhibitors
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();
@@ -864,7 +772,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
g_pSeatManager->isPointerFrameSkipped = false; g_pSeatManager->isPointerFrameSkipped = false;
g_pSeatManager->isPointerFrameCommit = false; g_pSeatManager->isPointerFrameCommit = false;
} else } else
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition->goal().x, PWINDOW->m_vRealPosition->goal().y, 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); PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
if (g_pSeatManager->isPointerFrameSkipped) { if (g_pSeatManager->isPointerFrameSkipped) {
@@ -880,7 +788,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
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()->current.accumulateBufferDamage()}; CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
if (!damageBox.empty()) { if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) { if (PMONITOR->tearingState.busy) {
@@ -924,6 +832,15 @@ void Events::listener_destroyWindow(void* owner, void* data) {
PWINDOW->listeners.commit.reset(); PWINDOW->listeners.commit.reset();
} }
void Events::listener_setTitleWindow(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
if (!validMapped(PWINDOW))
return;
PWINDOW->onUpdateMeta();
}
void Events::listener_activateX11(void* owner, void* data) { void Events::listener_activateX11(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
@@ -955,8 +872,8 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
if (!PWINDOW->m_bIsMapped || !PWINDOW->m_pXWaylandSurface || !PWINDOW->m_pXWaylandSurface->overrideRedirect) if (!PWINDOW->m_bIsMapped || !PWINDOW->m_pXWaylandSurface || !PWINDOW->m_pXWaylandSurface->overrideRedirect)
return; return;
const auto POS = PWINDOW->m_vRealPosition->goal(); const auto POS = PWINDOW->m_vRealPosition.goal();
const auto SIZ = PWINDOW->m_vRealSize->goal(); const auto SIZ = PWINDOW->m_vRealSize.goal();
if (PWINDOW->m_pXWaylandSurface->geometry.size() > Vector2D{1, 1}) if (PWINDOW->m_pXWaylandSurface->geometry.size() > Vector2D{1, 1})
PWINDOW->setHidden(false); PWINDOW->setHidden(false);
@@ -964,7 +881,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->setHidden(true); PWINDOW->setHidden(true);
if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) { if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) {
PWINDOW->sendWindowSize(true); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
return; return;
} }
@@ -978,27 +895,27 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {:j}", PWINDOW, LOGICALPOS, PWINDOW->m_pXWaylandSurface->geometry.size()); Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {:j}", PWINDOW, LOGICALPOS, PWINDOW->m_pXWaylandSurface->geometry.size());
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vRealPosition->setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y)); PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y));
if (abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.w) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.h) > 2) if (abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.w) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.h) > 2)
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 = PWINDOW->m_pMonitor.lock(); PMONITOR) {
PWINDOW->m_vRealSize->setValueAndWarp(PWINDOW->m_vRealSize->goal() / PMONITOR->scale); PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
} }
} }
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition->goal(); PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal();
PWINDOW->m_vSize = PWINDOW->m_vRealSize->goal(); PWINDOW->m_vSize = PWINDOW->m_vRealSize.goal();
PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition->value() + PWINDOW->m_vRealSize->value() / 2.f)->activeWorkspace; PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(PWINDOW, true); g_pCompositor->changeWindowZOrder(PWINDOW, true);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition->goal(); PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goal();
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize->goal(); PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal();
} }
} }

View File

@@ -0,0 +1,92 @@
#include "AnimatedVariable.hpp"
#include "../managers/AnimationManager.hpp"
#include "../config/ConfigManager.hpp"
CBaseAnimatedVariable::CBaseAnimatedVariable(ANIMATEDVARTYPE type) : m_Type(type) {
; // dummy var
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pWindow = pWindow;
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pLayer = pLayer;
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pWorkspace = pWorkspace;
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_bDummy = false;
}
CBaseAnimatedVariable::~CBaseAnimatedVariable() {
unregister();
}
void CBaseAnimatedVariable::unregister() {
if (!g_pAnimationManager)
return;
std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; });
m_bIsRegistered = false;
disconnectFromActive();
}
void CBaseAnimatedVariable::registerVar() {
if (!m_bIsRegistered)
g_pAnimationManager->m_vAnimatedVariables.push_back(this);
m_bIsRegistered = true;
}
int CBaseAnimatedVariable::getDurationLeftMs() {
return std::max(
(int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - animationBegin).count(), 0);
}
float CBaseAnimatedVariable::getPercent() {
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - animationBegin).count();
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
}
float CBaseAnimatedVariable::getCurveValue() {
if (!m_bIsBeingAnimated)
return 1.f;
const auto SPENT = getPercent();
if (SPENT >= 1.f)
return 1.f;
return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT);
}
void CBaseAnimatedVariable::connectToActive() {
g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up
if (!m_bIsConnectedToActive)
g_pAnimationManager->m_vActiveAnimatedVariables.push_back(this);
m_bIsConnectedToActive = true;
}
void CBaseAnimatedVariable::disconnectFromActive() {
std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; });
m_bIsConnectedToActive = false;
}

View File

@@ -1,49 +1,59 @@
#pragma once #pragma once
#include <hyprutils/animation/AnimatedVariable.hpp> #include <functional>
#include <any>
#include <chrono>
#include <type_traits>
#include "math/Math.hpp"
#include "Color.hpp" #include "Color.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../debug/Log.hpp"
#include "../desktop/DesktopTypes.hpp" #include "../desktop/DesktopTypes.hpp"
enum eAVarDamagePolicy : int8_t { enum ANIMATEDVARTYPE {
AVARDAMAGE_NONE = -1,
AVARDAMAGE_ENTIRE = 0,
AVARDAMAGE_BORDER,
AVARDAMAGE_SHADOW
};
enum eAnimatedVarType : int8_t {
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 AVARDAMAGEPOLICY {
AVARDAMAGE_NONE = -1,
AVARDAMAGE_ENTIRE = 0,
AVARDAMAGE_BORDER,
AVARDAMAGE_SHADOW
};
class CAnimationManager;
struct SAnimationPropertyConfig;
class CHyprRenderer;
class CWindow;
class CWorkspace;
class CLayerSurface;
// Utility to define a concept as a list of possible type // Utility to define a concept as a list of possible type
template <class T, class... U> template <class T, class... U>
@@ -53,21 +63,247 @@ 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>;
struct SAnimationContext { class CBaseAnimatedVariable {
PHLWINDOWREF pWindow; public:
PHLWORKSPACEREF pWorkspace; CBaseAnimatedVariable(ANIMATEDVARTYPE type);
PHLLSREF pLayer; void create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy);
eAVarDamagePolicy eDamagePolicy = AVARDAMAGE_NONE; CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
CBaseAnimatedVariable& operator=(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable& operator=(CBaseAnimatedVariable&&) = delete;
virtual ~CBaseAnimatedVariable();
void unregister();
void registerVar();
virtual void warp(bool endCallback = true) = 0;
//
void setConfig(SAnimationPropertyConfig* pConfig) {
m_pConfig = pConfig;
}
SAnimationPropertyConfig* getConfig() {
return m_pConfig;
}
int getDurationLeftMs();
/* returns the spent (completion) % */
float getPercent();
/* returns the current curve value */
float getCurveValue();
// checks if an animation is in progress
inline bool isBeingAnimated() {
return m_bIsBeingAnimated;
}
/* sets a function to be ran when the animation finishes.
if an animation is not running, runs instantly.
if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnEnd(std::function<void(void* thisptr)> func, bool remove = true) {
m_fEndCallback = func;
m_bRemoveEndAfterRan = remove;
if (!isBeingAnimated())
onAnimationEnd();
}
/* sets a function to be ran when an animation is started.
if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnBegin(std::function<void(void* thisptr)> func, bool remove = true) {
m_fBeginCallback = func;
m_bRemoveBeginAfterRan = remove;
}
/* 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 */
void setUpdateCallback(std::function<void(void* thisptr)> func) {
m_fUpdateCallback = func;
}
/* resets all callbacks. Does not call any. */
void resetAllCallbacks() {
m_fBeginCallback = nullptr;
m_fEndCallback = nullptr;
m_fUpdateCallback = nullptr;
m_bRemoveBeginAfterRan = false;
m_bRemoveEndAfterRan = false;
}
PHLWINDOW getWindow() {
return m_pWindow.lock();
}
protected:
PHLWINDOWREF m_pWindow;
PHLWORKSPACEREF m_pWorkspace;
PHLLSREF m_pLayer;
SAnimationPropertyConfig* m_pConfig = nullptr;
bool m_bDummy = true;
bool m_bIsRegistered = false;
bool m_bIsBeingAnimated = false;
std::chrono::steady_clock::time_point animationBegin;
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE;
ANIMATEDVARTYPE m_Type;
bool m_bRemoveEndAfterRan = true;
bool m_bRemoveBeginAfterRan = true;
std::function<void(void* thisptr)> m_fEndCallback;
std::function<void(void* thisptr)> m_fBeginCallback;
std::function<void(void* thisptr)> m_fUpdateCallback;
bool m_bIsConnectedToActive = false;
void connectToActive();
void disconnectFromActive();
// methods
void onAnimationEnd() {
m_bIsBeingAnimated = false;
disconnectFromActive();
if (m_fEndCallback) {
// loading m_bRemoveEndAfterRan before calling the callback allows the callback to delete this animation safely if it is false.
auto removeEndCallback = m_bRemoveEndAfterRan;
m_fEndCallback(this);
if (removeEndCallback)
m_fEndCallback = nullptr; // reset
}
}
void onAnimationBegin() {
m_bIsBeingAnimated = true;
connectToActive();
if (m_fBeginCallback) {
m_fBeginCallback(this);
if (m_bRemoveBeginAfterRan)
m_fBeginCallback = nullptr; // reset
}
}
friend class CAnimationManager;
friend class CWorkspace;
friend class CLayerSurface;
friend class CHyprRenderer;
}; };
template <Animable VarType> template <Animable VarType>
using CAnimatedVariable = Hyprutils::Animation::CGenericAnimatedVariable<VarType, SAnimationContext>; class CAnimatedVariable : public CBaseAnimatedVariable {
public:
CAnimatedVariable() : CBaseAnimatedVariable(typeToANIMATEDVARTYPE<VarType>) {} // dummy var
template <Animable VarType> void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, AVARDAMAGEPOLICY policy) {
using PHLANIMVAR = SP<CAnimatedVariable<VarType>>; create(pAnimConfig, pWindow, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pLayer, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pWorkspace, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, policy);
m_Value = value;
m_Goal = value;
}
template <Animable VarType> using CBaseAnimatedVariable::create;
using PHLANIMVARREF = WP<CAnimatedVariable<VarType>>;
CAnimatedVariable(const CAnimatedVariable&) = delete;
CAnimatedVariable(CAnimatedVariable&&) = delete;
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
~CAnimatedVariable() = default;
// gets the current vector value (real time)
const VarType& value() const {
return m_Value;
}
// gets the goal vector value
const VarType& goal() const {
return m_Goal;
}
CAnimatedVariable& operator=(const VarType& v) {
if (v == m_Goal)
return *this;
m_Goal = v;
animationBegin = std::chrono::steady_clock::now();
m_Begun = m_Value;
onAnimationBegin();
return *this;
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const VarType& v) {
if (v == m_Value)
return;
m_Value = v;
animationBegin = std::chrono::steady_clock::now();
m_Begun = m_Value;
onAnimationBegin();
}
// Sets the actual value and goal
void setValueAndWarp(const VarType& v) {
m_Goal = v;
m_bIsBeingAnimated = true;
warp();
}
void warp(bool endCallback = true) override {
if (!m_bIsBeingAnimated)
return;
m_Value = m_Goal;
m_bIsBeingAnimated = false;
if (m_fUpdateCallback)
m_fUpdateCallback(this);
if (endCallback)
onAnimationEnd();
}
private:
VarType m_Value{};
VarType m_Goal{};
VarType m_Begun{};
// owners
friend class CAnimationManager;
friend class CWorkspace;
friend class CLayerSurface;
friend class CHyprRenderer;
};

View File

@@ -1,123 +0,0 @@
#include "AsyncDialogBox.hpp"
#include "./fs/FsUtils.hpp"
#include <csignal>
#include <unistd.h>
#include "../managers/eventLoop/EventLoopManager.hpp"
using namespace Hyprutils::OS;
SP<CAsyncDialogBox> CAsyncDialogBox::create(const std::string& title, const std::string& description, std::vector<std::string> buttons) {
if (!NFsUtils::executableExistsInPath("hyprland-dialog")) {
Debug::log(ERR, "CAsyncDialogBox: cannot create, no hyprland-dialog");
return nullptr;
}
auto dialog = SP<CAsyncDialogBox>(new CAsyncDialogBox(title, description, buttons));
dialog->m_selfWeakReference = dialog;
return dialog;
}
CAsyncDialogBox::CAsyncDialogBox(const std::string& title, const std::string& description, std::vector<std::string> buttons) :
m_title(title), m_description(description), m_buttons(buttons) {
;
}
static int onFdWrite(int fd, uint32_t mask, void* data) {
auto box = (CAsyncDialogBox*)data;
box->onWrite(fd, mask);
return 0;
}
void CAsyncDialogBox::onWrite(int fd, uint32_t mask) {
if (mask & WL_EVENT_READABLE) {
std::array<char, 1024> buf;
int ret = 0;
// make the FD nonblock for a moment
// TODO: can we avoid this without risking a blocking read()?
int fdFlags = fcntl(fd, F_GETFL, 0);
if (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) {
Debug::log(ERR, "CAsyncDialogBox::onWrite: fcntl 1 failed!");
return;
}
while ((ret = read(m_pipeReadFd.get(), buf.data(), 1023)) > 0) {
m_stdout += std::string_view{(char*)buf.data(), (size_t)ret};
}
// restore the flags (otherwise libwayland wont give us a hangup)
if (fcntl(fd, F_SETFL, fdFlags) < 0) {
Debug::log(ERR, "CAsyncDialogBox::onWrite: fcntl 2 failed!");
return;
}
}
if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
Debug::log(LOG, "CAsyncDialogBox: dialog {:x} hung up, closed.");
if (m_onResolution)
m_onResolution(m_stdout);
wl_event_source_remove(m_readEventSource);
m_selfReference.reset();
return;
}
}
void CAsyncDialogBox::open(std::function<void(std::string)> onResolution) {
m_onResolution = onResolution;
std::string buttonsString = "";
for (auto& b : m_buttons) {
buttonsString += b + ";";
}
if (!buttonsString.empty())
buttonsString.pop_back();
CProcess proc("hyprland-dialog", std::vector<std::string>{"--title", m_title, "--text", m_description, "--buttons", buttonsString});
int outPipe[2];
if (pipe(outPipe)) {
Debug::log(ERR, "CAsyncDialogBox::open: failed to pipe()");
return;
}
m_pipeReadFd = CFileDescriptor(outPipe[0]);
proc.setStdoutFD(outPipe[1]);
m_readEventSource = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, m_pipeReadFd.get(), WL_EVENT_READABLE, ::onFdWrite, this);
if (!m_readEventSource) {
Debug::log(ERR, "CAsyncDialogBox::open: failed to add read fd to loop");
return;
}
m_selfReference = m_selfWeakReference.lock();
m_dialogPid = proc.pid();
if (!proc.runAsync()) {
Debug::log(ERR, "CAsyncDialogBox::open: failed to run async");
wl_event_source_remove(m_readEventSource);
return;
}
// close the write fd, only the dialog owns it now
close(outPipe[1]);
}
void CAsyncDialogBox::kill() {
if (m_dialogPid <= 0)
return;
::kill(m_dialogPid, SIGKILL);
}
bool CAsyncDialogBox::isRunning() const {
return m_readEventSource;
}

View File

@@ -1,45 +0,0 @@
#pragma once
#include "../macros.hpp"
#include "./memory/Memory.hpp"
#include <vector>
#include <functional>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/os/FileDescriptor.hpp>
struct wl_event_source;
class CAsyncDialogBox {
public:
static SP<CAsyncDialogBox> create(const std::string& title, const std::string& description, std::vector<std::string> buttons);
CAsyncDialogBox(const CAsyncDialogBox&) = delete;
CAsyncDialogBox(CAsyncDialogBox&&) = delete;
CAsyncDialogBox& operator=(const CAsyncDialogBox&) = delete;
CAsyncDialogBox& operator=(CAsyncDialogBox&&) = delete;
void open(std::function<void(std::string)> onResolution);
void kill();
bool isRunning() const;
void onWrite(int fd, uint32_t mask);
private:
CAsyncDialogBox(const std::string& title, const std::string& description, std::vector<std::string> buttons);
pid_t m_dialogPid = 0;
wl_event_source* m_readEventSource = nullptr;
std::function<void(std::string)> m_onResolution;
Hyprutils::OS::CFileDescriptor m_pipeReadFd;
std::string m_stdout = "";
const std::string m_title;
const std::string m_description;
const std::vector<std::string> m_buttons;
// WARNING: cyclic reference. This will be removed once the event source is removed to avoid dangling pointers
SP<CAsyncDialogBox> m_selfReference;
WP<CAsyncDialogBox> m_selfWeakReference;
};

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