Compare commits

..

11 Commits

Author SHA1 Message Date
Vaxry
0bd541f2fd version: bump to 0.46.2 2024-12-19 19:26:47 +00:00
Aqa-Ib
23d00cdd0d layout: apply group rules after window creation (#8779)
* apply group rules after window creation

* clang-format
2024-12-19 19:26:40 +00:00
Vaxry
061241d3a2 core: fix possible crash on null active workspace
fixes #7822
2024-12-19 19:26:40 +00:00
Aaron Blasko
b9df70be22 hyprpm: fix hyrpm sometimes returning 0 despite errors occuring (#8761)
* hyprpm: fix hyrpm sometimes returning 0 despite errors occuring

* there u go
2024-12-19 19:26:40 +00:00
Jan Beich
9583429eae core: Unbreak build on FreeBSD (#8762)
* CrashReporter: restore explicit environ(7) after 8bbeee1173

BSD systems don't declare environ(7) in any header like POSIX suggests.

src/signal-safe.cpp:12:23: error: use of undeclared identifier 'environ'
   12 |     for (char** var = environ; *var != nullptr; var++) {
      |                       ^

* fix

---------

Co-authored-by: Vaxry <vaxry@vaxry.net>
2024-12-19 19:26:40 +00:00
Vaxry
747c38112b xwayland: fix compile with no xwayland 2024-12-19 19:26:40 +00:00
Vaxry
508e82341f xwm: fixup targets in selection requests
fixes #8719
2024-12-19 19:26:40 +00:00
Vaxry
ec0a38303b xwayland: fix dnd including xwayland
ref #8759
2024-12-19 19:26:40 +00:00
Vaxry
d0bffc4fa9 core: avoid activating toplevel-less surfaces
ref #8609
2024-12-19 19:26:40 +00:00
Khalid
07a19e2c95 hyprctl: Fix hyprctl batch JSON command (#8749) 2024-12-19 19:26:40 +00:00
Vaxry
46d5b363fa windowrules: fixup duplicate rule enum tags
fixes #8746
2024-12-19 19:26:40 +00:00
385 changed files with 9005 additions and 19066 deletions

View File

@@ -1,15 +1,75 @@
name: Do not open issues, go to discussions please!
description: Do not open an issue
name: Bug Report
description: Something is not working right
labels: ["bug"]
body:
- type: checkboxes
attributes:
label: Please close this issue.
description: Users cannot open issues. I want my issue to be closed.
label: Already reported ? *
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:
- label: Yes, I want this issue to be closed.
required: true
- label: I have searched the existing open and closed issues.
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
id: body
id: ver
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

@@ -35,7 +35,6 @@ runs:
libinput \
libjxl \
libliftoff \
libspng \
libwebp \
libxcursor \
libxcvt \
@@ -64,15 +63,6 @@ runs:
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
shell: bash
run: |

View File

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

@@ -19,6 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v15
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*
.ccls-cache
*.so
src/render/shaders/*.inc
src/render/shaders/Shaders.hpp
hyprctl/hyprctl

View File

@@ -25,9 +25,6 @@ message(STATUS "Gathering git info")
# Get git info hash and branch
execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# Make shader files includable
execute_process(COMMAND ./scripts/generateShaderIncludes.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
find_package(PkgConfig REQUIRED)
@@ -80,7 +77,6 @@ add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}")
include_directories(. "src/" "protocols/")
set(CMAKE_CXX_STANDARD 26)
set(CXX_STANDARD_REQUIRED ON)
add_compile_options(
-Wall
-Wextra
@@ -105,21 +101,13 @@ else()
endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.8.0)
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5)
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(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.2.3)
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION})
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_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}")
@@ -132,7 +120,7 @@ pkg_check_modules(
xkbcommon
uuid
wayland-server>=1.22.90
wayland-protocols>=1.41
wayland-protocols
cairo
pango
pangocairo
@@ -209,12 +197,6 @@ if(NOT HAS_TIMERFD AND epoll_FOUND)
target_link_libraries(Hyprland PkgConfig::epoll)
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)
message(STATUS "Using the legacy GLES2 renderer!")
add_compile_definitions(LEGACY_RENDERER)
@@ -266,15 +248,7 @@ target_precompile_headers(Hyprland PRIVATE
message(STATUS "Setting link libraries")
target_link_libraries(
Hyprland
rt
PkgConfig::aquamarine_dep
PkgConfig::hyprlang_dep
PkgConfig::hyprutils_dep
PkgConfig::hyprcursor_dep
PkgConfig::hyprgraphics_dep
PkgConfig::deps)
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::hyprgraphics_dep PkgConfig::deps)
if(udis_dep_FOUND)
target_link_libraries(Hyprland PkgConfig::udis_dep)
else()
@@ -316,7 +290,7 @@ endfunction()
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)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
@@ -342,12 +316,8 @@ protocolnew("protocols" "kde-server-decoration" true)
protocolnew("protocols" "wlr-data-control-unstable-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-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("${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/fractional-scale" "fractional-scale-v1" false)
@@ -380,20 +350,12 @@ protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-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()
# tools
add_subdirectory(hyprctl)
if(NO_HYPRPM)
message(STATUS "hyprpm is disabled")
else()
add_subdirectory(hyprpm)
message(STATUS "hyprpm is enabled (NO_HYPRPM not defined)")
endif()
add_subdirectory(hyprpm)
# binary and symlink
install(TARGETS Hyprland)
@@ -404,6 +366,7 @@ install(
${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
\"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \
)")
# session file
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
@@ -447,7 +410,4 @@ install(
DIRECTORY ${HEADERS_SRC}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING
PATTERN "*.h"
PATTERN "*.hpp"
PATTERN "*.inc"
)
PATTERN "*.h*")

View File

@@ -52,7 +52,7 @@ installheaders:
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 ./build/hyprland.pc ${PREFIX}/share/pkgconfig
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.46.2

View File

@@ -52,20 +52,6 @@ env = XCURSOR_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 ###
#####################
@@ -95,7 +81,6 @@ general {
# https://wiki.hyprland.org/Configuring/Variables/#decoration
decoration {
rounding = 10
rounding_power = 2
# Change transparency of focused and unfocused windows
active_opacity = 1.0
@@ -153,10 +138,10 @@ animations {
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrule = rounding 0, floating:0, onworkspace:w[tv1]
# windowrule = bordersize 0, floating:0, onworkspace:f[1]
# windowrule = rounding 0, floating:0, onworkspace:f[1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
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/Workspace-Rules/ for workspace rules
# Example windowrule
# windowrule = float,class:^(kitty)$,title:^(kitty)$
# Example windowrule v1
# windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.*
windowrulev2 = suppressevent maximize, class:.*
# 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 @@
}
]
},
]
}

120
flake.lock generated
View File

@@ -16,11 +16,11 @@
]
},
"locked": {
"lastModified": 1743265529,
"narHash": "sha256-QbjP15/2N+VJl0b5jxrrTc+VOt39aU4XrDvtP0Lz5ik=",
"lastModified": 1734364797,
"narHash": "sha256-2h1c+P0v3l0Z/ypUSsAPhU/yiSRgFwjVFODWp0S3d/w=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "1d2dbd72c2bbaceab031c592d4810f744741d203",
"rev": "8e77618b403a82fde2105a8e3cd7cabe7ef00952",
"type": "github"
},
"original": {
@@ -79,11 +79,11 @@
]
},
"locked": {
"lastModified": 1742215578,
"narHash": "sha256-zfs71PXVVPEe56WEyNi2TJQPs0wabU4WAlq0XV7GcdE=",
"lastModified": 1734364709,
"narHash": "sha256-+2bZJL2u5hva7rSp65OfKJBK+k03T6GB/NCvpoS1OOo=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "2fd36421c21aa87e2fe3bee11067540ae612f719",
"rev": "f388aacd22be4a6e4d634fbaf6f75eb0713d239a",
"type": "github"
},
"original": {
@@ -105,11 +105,11 @@
]
},
"locked": {
"lastModified": 1739049071,
"narHash": "sha256-3+7TpXMrbsUXSwgr5VAKAnmkzMb6JO+Rvc9XRb5NMg4=",
"lastModified": 1733684019,
"narHash": "sha256-2kYREgmSmbLsmDpLEq96hxVAU3qz8aCvVhF65yCFZHY=",
"owner": "hyprwm",
"repo": "hyprgraphics",
"rev": "175c6b29b6ff82100539e7c4363a35a02c74dd73",
"rev": "fb2c0268645a77403af3b8a4ce8fa7ba5917f15d",
"type": "github"
},
"original": {
@@ -128,11 +128,11 @@
]
},
"locked": {
"lastModified": 1743714874,
"narHash": "sha256-yt8F7NhMFCFHUHy/lNjH/pjZyIDFNk52Q4tivQ31WFo=",
"lastModified": 1728345020,
"narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "3a5c2bda1c1a4e55cc1330c782547695a93f05b2",
"rev": "a7c183800e74f337753de186522b9017a07a8cee",
"type": "github"
},
"original": {
@@ -141,44 +141,9 @@
"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": [
@@ -189,11 +154,11 @@
]
},
"locked": {
"lastModified": 1739048983,
"narHash": "sha256-REhTcXq4qs3B3cCDtLlYDz0GZvmsBSh947Ub6pQWGTQ=",
"lastModified": 1733940128,
"narHash": "sha256-hmfXWj2GA9cj1QUkPFYtAAeohhs615zL4E3APy3FnvQ=",
"owner": "hyprwm",
"repo": "hyprland-qtutils",
"rev": "3504a293c8f8db4127cb0f7cfc1a318ffb4316f8",
"rev": "3833097e50473a152dd614d4b468886840b4ea78",
"type": "github"
},
"original": {
@@ -215,11 +180,11 @@
]
},
"locked": {
"lastModified": 1741191527,
"narHash": "sha256-kM+11Nch47Xwfgtw2EpRitJuORy4miwoMuRi5tyMBDY=",
"lastModified": 1734364628,
"narHash": "sha256-ii8fzJfI953n/EmIxVvq64ZAwhvwuuPHWfGd61/mJG8=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "72df3861f1197e41b078faa3e38eedd60e00018d",
"rev": "16e59c1eb13d9fb6de066f54e7555eb5e8a4aba5",
"type": "github"
},
"original": {
@@ -238,11 +203,11 @@
]
},
"locked": {
"lastModified": 1743950287,
"narHash": "sha256-/6IAEWyb8gC/NKZElxiHChkouiUOrVYNq9YqG0Pzm4Y=",
"lastModified": 1733502241,
"narHash": "sha256-KAUNC4Dgq8WQjYov5auBw/usaHixhacvb7cRDd0AG/k=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "f2dc70e448b994cef627a157ee340135bd68fbc6",
"rev": "104117aed6dd68561be38b50f218190aa47f2cd8",
"type": "github"
},
"original": {
@@ -261,11 +226,11 @@
]
},
"locked": {
"lastModified": 1739870480,
"narHash": "sha256-SiDN5BGxa/1hAsqhgJsS03C3t2QrLgBT8u+ENJ0Qzwc=",
"lastModified": 1726874836,
"narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "206367a08dc5ac4ba7ad31bdca391d098082e64b",
"rev": "500c81a9e1a76760371049a8d99e008ea77aa59e",
"type": "github"
},
"original": {
@@ -276,11 +241,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1743827369,
"narHash": "sha256-rpqepOZ8Eo1zg+KJeWoq1HAOgoMCDloqv5r2EAa9TSA=",
"lastModified": 1734119587,
"narHash": "sha256-AKU6qqskl0yf2+JdRdD0cfxX4b9x3KKV5RqA6wijmPM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "42a1c966be226125b48c384171c44c651c236c22",
"rev": "3566ab7246670a43abd2ffa913cc62dad9cdf7d5",
"type": "github"
},
"original": {
@@ -290,20 +255,37 @@
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1730741070,
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1742649964,
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
"lastModified": 1734279981,
"narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
"rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785",
"type": "github"
},
"original": {
@@ -365,11 +347,11 @@
]
},
"locked": {
"lastModified": 1741934139,
"narHash": "sha256-ZhTcTH9FoeAtbPfWGrhkH7RjLJZ7GeF18nygLAMR+WE=",
"lastModified": 1734124279,
"narHash": "sha256-YNpFfiQjYt2o6LGcMN9NkjVvprC8ELrIpLHlbZbclRM=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "150b0b6f52bb422a1b232a53698606fe0320dde0",
"rev": "0c6861f819f6d31f6195c9864709b2556f00b5cf",
"type": "github"
},
"original": {

View File

@@ -39,7 +39,7 @@
url = "github:hyprwm/hyprland-qtutils";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprlang.follows = "hyprlang";
inputs.hyprutils.follows = "hyprutils";
};
hyprlang = {
@@ -157,11 +157,5 @@
nixosModules.default = import ./nix/module.nix inputs;
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

@@ -22,7 +22,6 @@ commands:
getoption <option> Gets the config option status (values)
globalshortcuts Lists all global shortcuts
hyprpaper ... Issue a hyprpaper request
hyprsunset ... Issue a hyprsunset request
instances Lists all running instances of Hyprland with
their info
keyword <name> <value> Issue a keyword to call a config keyword
@@ -82,16 +81,6 @@ requests:
flags:
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...>
icon:

View File

@@ -23,7 +23,7 @@ _hyprctl () {
local 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
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)"

View File

@@ -29,7 +29,7 @@ function _hyprctl
set COMP_CWORD (count $COMP_WORDS)
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[1] "Resize the active window"

View File

@@ -106,7 +106,6 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (execr) "Execute a raw shell command"
| (pass) "Pass the key 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"
| (closewindow) "Close a specified window"
| (workspace) "Change the workspace"

View File

@@ -17,7 +17,7 @@ _hyprctl_cmd_0 () {
}
_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
descriptions[1]="Resize the active window"

View File

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

View File

@@ -11,23 +11,9 @@ set(CMAKE_CXX_STANDARD 23)
pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4)
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})
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps glaze::glaze)
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps)
# binary
install(TARGETS hyprpm)

View File

@@ -14,7 +14,7 @@ hyprpm [<FLAGS>]... <ARGUMENT>
| (list) "List all installed plugins"
| (enable <PLUGINS>) "Load 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}' }}};

View File

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

View File

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

View File

@@ -7,8 +7,10 @@
#include <cstdio>
#include <iostream>
#include <array>
#include <filesystem>
#include <print>
#include <thread>
#include <fstream>
#include <algorithm>
#include <format>
@@ -19,7 +21,6 @@
#include <unistd.h>
#include <toml++/toml.hpp>
#include <glaze/glaze.hpp>
#include <hyprutils/string/String.hpp>
#include <hyprutils/os/Process.hpp>
@@ -82,13 +83,13 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
hlbranch = hlbranch.substr(0, hlbranch.find(" at commit "));
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;
if (HLVERCALL.contains("commits:")) {
hlcommits = HLVERCALL.substr(HLVERCALL.find("commits:") + 9);
hlcommits = hlcommits.substr(0, hlcommits.find(' '));
hlcommits = hlcommits.substr(0, hlcommits.find(" "));
}
int commits = 0;
@@ -377,7 +378,7 @@ eHeadersErrors CPluginManager::headersValid() {
// find headers commit
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/"))
return HEADERS_MISSING;
@@ -463,9 +464,7 @@ bool CPluginManager::updateHeaders(bool force) {
return false;
}
const auto& HL_URL = m_szCustomHlUrl.empty() ? "https://github.com/hyprwm/Hyprland" : m_szCustomHlUrl;
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning {}, this might take a moment.", HL_URL));
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment."));
const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow;
@@ -476,12 +475,12 @@ bool CPluginManager::updateHeaders(bool force) {
if (m_bVerbose && bShallow)
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE));
std::string ret =
execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}{}", getTempRoot(), HL_URL, USERNAME, (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")));
std::string ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-{}{}", getTempRoot(), USERNAME,
(bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")));
if (!std::filesystem::exists(WORKINGDIR)) {
progress.printMessageAbove(failureString("Clone failed. Retrying without shallow."));
ret = execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}", getTempRoot(), HL_URL, USERNAME));
ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/hyprland hyprland-{}", getTempRoot(), USERNAME));
}
if (!std::filesystem::exists(WORKINGDIR + "/.git")) {
@@ -782,7 +781,7 @@ bool CPluginManager::disablePlugin(const std::string& name) {
return ret;
}
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload) {
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (headersValid() != HEADERS_OK) {
std::println(stderr, "\n{}", failureString("headers are not up-to-date, please run hyprpm update."));
return LOADSTATE_HEADERS_OUTDATED;
@@ -791,28 +790,35 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload)
const auto HOME = getenv("HOME");
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!HOME || !HIS) {
std::println(stderr, "PluginManager: no $HOME or $HYPRLAND_INSTANCE_SIGNATURE");
std::println(stderr, "PluginManager: no $HOME or HIS");
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"));
if (!json) {
std::println(stderr, "PluginManager: couldn't parse hyprctl output");
return LOADSTATE_FAIL;
}
auto pluginLines = execAndGet("hyprctl plugins list | grep Plugin");
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"));
// iterate line by line
while (!pluginLines.empty()) {
auto plLine = pluginLines.substr(0, pluginLines.find('\n'));
if (pluginLines.find('\n') != std::string::npos)
pluginLines = pluginLines.substr(pluginLines.find('\n') + 1);
else
pluginLines = "";
if (plLine.back() != ':')
continue;
plLine = plLine.substr(7);
plLine = plLine.substr(0, plLine.find(" by "));
loadedPlugins.push_back(plLine);
}
// get state
const auto REPOS = DataState::getAllRepositories();
@@ -843,11 +849,11 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload)
// (and Hyprland needs to restart)
bool hyprlandVersionMismatch = false;
// unload disabled plugins (or all if forceReload is true)
// unload disabled plugins
for (auto const& p : loadedPlugins) {
if (forceReload || !enabled(p)) {
if (!enabled(p)) {
// unload
if (!loadUnloadPlugin(HYPRPMPATH / repoForName(p) / (p + ".so"), false)) {
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false)) {
std::println("{}", infoString("{} will be unloaded after restarting Hyprland", p));
hyprlandVersionMismatch = true;
} else
@@ -861,10 +867,10 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload)
if (!p.enabled)
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;
if (!loadUnloadPlugin(HYPRPMPATH / repoForName(p.name) / p.filename, true)) {
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true)) {
std::println("{}", infoString("{} will be loaded after restarting Hyprland", p.name));
hyprlandVersionMismatch = true;
} else

View File

@@ -51,7 +51,7 @@ class CPluginManager {
bool enablePlugin(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);
SHyprlandVersion getHyprlandVersion(bool running = true);
@@ -62,7 +62,6 @@ class CPluginManager {
bool m_bVerbose = false;
bool m_bNoShallow = false;
std::string m_szCustomHlUrl;
// will delete recursively if exists!!
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
--force | -f Force an operation ignoring checks (e.g. update -f)
--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;
bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false;
std::string customHlUrl;
for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) {
@@ -61,13 +59,6 @@ int main(int argc, char** argv, char** envp) {
verbose = true;
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
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") {
force = true;
std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing."));
@@ -75,8 +66,9 @@ int main(int argc, char** argv, char** envp) {
std::println(stderr, "Unrecognized option {}", ARGS[i]);
return 1;
}
} else
} else {
command.push_back(ARGS[i]);
}
}
if (command.empty()) {
@@ -84,10 +76,9 @@ int main(int argc, char** argv, char** envp) {
return 1;
}
g_pPluginManager = std::make_unique<CPluginManager>();
g_pPluginManager->m_bVerbose = verbose;
g_pPluginManager->m_bNoShallow = noShallow;
g_pPluginManager->m_szCustomHlUrl = customHlUrl;
g_pPluginManager = std::make_unique<CPluginManager>();
g_pPluginManager->m_bVerbose = verbose;
g_pPluginManager->m_bNoShallow = noShallow;
if (command[0] == "add") {
if (command.size() < 2) {
@@ -163,20 +154,17 @@ int main(int argc, char** argv, char** envp) {
if (ret != LOADSTATE_OK)
return 1;
} else if (command[0] == "reload") {
auto ret = g_pPluginManager->ensurePluginsLoadState(force);
auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret != LOADSTATE_OK) {
if (notify) {
switch (ret) {
case LOADSTATE_FAIL:
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
case LOADSTATE_HEADERS_OUTDATED:
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually.");
break;
default: break;
}
if (ret != LOADSTATE_OK && notify) {
switch (ret) {
case LOADSTATE_FAIL:
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
case LOADSTATE_HEADERS_OUTDATED:
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually.");
break;
default: break;
}
return 1;
} else if (notify && !notifyFail) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");

View File

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

View File

@@ -31,16 +31,12 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif
aquamarine = dependency('aquamarine', version: '>=0.8.0')
aquamarine = dependency('aquamarine', version: '>=0.4.5')
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('.')
hyprutils = dependency('hyprutils', version: '>= 0.2.3')
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')
@@ -62,7 +58,6 @@ endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs
inotify_dep = dependency('libinotify', required: false) # inotify on BSDs
re2 = dependency('re2', required: true)
@@ -87,11 +82,9 @@ endif
# Generate hyprland version and populate version.h
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
# Make shader files includable
run_command('sh', '-c', 'scripts/generateShaderIncludes.sh', check: true)
# 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')
foreach file : headers
install_headers(file, subdir: 'hyprland', preserve_path: true)
@@ -108,14 +101,11 @@ endif
subdir('protocols')
subdir('src')
subdir('hyprctl')
subdir('hyprpm/src')
subdir('assets')
subdir('example')
subdir('docs')
if get_option('hyprpm').enabled()
subdir('hyprpm/src')
endif
# Generate hyprland.pc
pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')

View File

@@ -2,5 +2,4 @@ option('xwayland', type: 'feature', value: 'auto', description: 'Enable support
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('hyprpm', type: 'feature', value: 'enabled', description: 'Enable hyprpm')
option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling')

View File

@@ -5,15 +5,12 @@
pkg-config,
pkgconf,
makeWrapper,
cmake,
meson,
ninja,
aquamarine,
binutils,
cairo,
epoll-shim,
git,
glaze,
hyprcursor,
hyprgraphics,
hyprland-protocols,
@@ -27,7 +24,7 @@
libinput,
libxkbcommon,
libuuid,
libgbm,
mesa,
pango,
pciutils,
re2,
@@ -53,12 +50,12 @@
nvidiaPatches ? false,
hidpiXWayland ? false,
}: let
inherit (builtins) baseNameOf foldl' readFile;
inherit (builtins) baseNameOf foldl';
inherit (lib.asserts) assertMsg;
inherit (lib.attrsets) mapAttrsToList;
inherit (lib.lists) flatten concatLists optional optionals;
inherit (lib.sources) cleanSourceWith cleanSource;
inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable trim;
inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable;
adapters = flatten [
stdenvAdapters.useMoldLinker
@@ -94,7 +91,7 @@ in
DATE = date;
DIRTY = optionalString (commit == "") "dirty";
HASH = commit;
TAG = "v${trim (readFile "${finalAttrs.src}/VERSION")}";
TAG = "v${builtins.readFile "${finalAttrs.src}/VERSION"}";
depsBuildBuild = [
pkg-config
@@ -105,7 +102,6 @@ in
makeWrapper
meson
ninja
cmake # needed for glaze
pkg-config
];
@@ -120,7 +116,6 @@ in
aquamarine
cairo
git
glaze
hyprcursor
hyprgraphics
hyprland-protocols
@@ -131,7 +126,7 @@ in
libinput
libuuid
libxkbcommon
libgbm
mesa
pango
pciutils
re2
@@ -142,7 +137,6 @@ in
wayland-scanner
xorg.libXcursor
]
(optionals customStdenv.hostPlatform.isBSD [ epoll-shim ])
(optionals customStdenv.hostPlatform.isMusl [libexecinfo])
(optionals enableXWayland [
xorg.libxcb
@@ -155,20 +149,16 @@ in
(optional withSystemd systemd)
];
strictDeps = true;
mesonBuildType =
if debug
then "debug"
then "debugoptimized"
else "release";
mesonFlags = flatten [
(mapAttrsToList mesonEnable {
"xwayland" = enableXWayland;
"legacy_renderer" = legacyRenderer;
"systemd" = withSystemd;
"uwsm" = false;
"hyprpm" = false;
})
(mapAttrsToList mesonBool {
"b_pch" = false;

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
inherit (pkgs.stdenv.hostPlatform) system;
selflib = import ./lib.nix lib;
cfg = config.programs.hyprland;
package = inputs.self.packages.${system}.hyprland;
portalPackage = inputs.self.packages.${system}.xdg-desktop-portal-hyprland.override {
hyprland = cfg.finalPackage;
};
in {
options = {
config = {
programs.hyprland = {
plugins = lib.mkOption {
type = with lib.types; listOf (either package path);
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.
'';
};
package = lib.mkDefault package;
portalPackage = lib.mkDefault portalPackage;
};
};
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

@@ -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-protocols',
version: '>=1.41',
version: '>=1.32',
fallback: 'wayland-protocols',
default_options: ['tests=false'],
)
hyprland_protos = dependency(
'hyprland-protocols',
version: '>=0.6.2',
version: '>=0.4',
fallback: 'hyprland-protocols',
)
@@ -33,14 +33,10 @@ protocols = [
'wayland-drm.xml',
'wlr-data-control-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-toplevel-export-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-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/fractional-scale/fractional-scale-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/single-pixel-buffer/single-pixel-buffer-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 = []
@@ -87,7 +81,7 @@ foreach protocol : protocols
endforeach
# wayland.xml generation
wayland_scanner = dependency('wayland-scanner', native: true)
wayland_scanner = dependency('wayland-scanner')
wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir')
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
# 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
HASH=${HASH-$(git rev-parse HEAD)}

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,38 @@
#pragma once
#include <memory>
#include <list>
#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/input/InputManager.hpp"
#include "managers/LayoutManager.hpp"
#include "managers/KeybindManager.hpp"
#include "managers/AnimationManager.hpp"
#include "managers/EventManager.hpp"
#include "managers/ProtocolManager.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 "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/output/Output.hpp>
class CWLSurfaceResource;
struct SWorkspaceRule;
enum eManagersInitStage : uint8_t {
STAGE_PRIORITY = 0,
@@ -22,11 +42,11 @@ enum eManagersInitStage : uint8_t {
class CCompositor {
public:
CCompositor(bool onlyConfig = false);
CCompositor();
~CCompositor();
wl_display* m_sWLDisplay = nullptr;
wl_event_loop* m_sWLEventLoop = nullptr;
wl_display* m_sWLDisplay;
wl_event_loop* m_sWLEventLoop;
int m_iDRMFD = -1;
bool m_bInitialized = false;
SP<Aquamarine::CBackend> m_pAqBackend;
@@ -52,6 +72,8 @@ class CCompositor {
void startCompositor();
void stopCompositor();
void cleanup();
void createLockFile();
void removeLockFile();
void bumpNofile();
void restoreNofile();
@@ -67,11 +89,10 @@ class CCompositor {
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false;
PHLMONITORREF m_pUnsafeOutput; // fallback output for the unsafe state
bool m_bIsShuttingDown = false;
bool m_bFinalRequests = false;
bool m_bDesktopEnvSet = false;
bool m_bWantsXwayland = true;
bool m_bOnlyConfigVerification = false;
bool m_bIsShuttingDown = false;
bool m_bFinalRequests = false;
bool m_bDesktopEnvSet = false;
bool m_bEnableXwayland = true;
// ------------------------------------------------- //
@@ -81,7 +102,7 @@ class CCompositor {
PHLMONITOR getMonitorFromCursor();
PHLMONITOR getMonitorFromVector(const Vector2D&);
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);
bool monitorExists(PHLMONITOR);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
@@ -102,9 +123,8 @@ class CCompositor {
void changeWindowZOrder(PHLWINDOW, bool);
void cleanupFadingOut(const MONITORID& monid);
PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false);
PHLWINDOW getWindowCycle(PHLWINDOW cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool prev = false);
PHLWINDOW getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool next = false);
PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
WORKSPACEID getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr);
@@ -120,6 +140,7 @@ class CCompositor {
void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
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 updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW);
@@ -146,13 +167,10 @@ class CCompositor {
void setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, double scale);
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates();
PHLWINDOW windowForCPointer(CWindow*);
void onNewMonitor(SP<Aquamarine::IOutput> output);
void ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules, PHLWORKSPACE pWorkspace = nullptr);
NColorManagement::SImageDescription getPreferredImageDescription();
bool shouldChangePreferredImageDescription();
std::string explicitConfigPath;
std::string explicitConfigPath;
private:
void initAllSignals();
@@ -161,13 +179,10 @@ class CCompositor {
void setRandomSplash();
void initManagers(eManagersInitStage stage);
void prepareFallbackOutput();
void createLockFile();
void removeLockFile();
void setMallocThreshold();
uint64_t m_iHyprlandPID = 0;
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,8 +3,6 @@
#include "helpers/math/Math.hpp"
#include <functional>
#include <any>
#include <string>
#include <algorithm>
#include <hyprutils/math/Box.hpp>
enum eIcons : uint8_t {
@@ -52,12 +50,6 @@ struct SHyprCtlCommand {
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 MONITORID;
typedef int64_t WORKSPACEID;

View File

@@ -11,7 +11,7 @@ enum eConfigValueDataTypes : int8_t {
class ICustomConfigValueData {
public:
virtual ~ICustomConfigValueData() = default;
virtual ~ICustomConfigValueData() = 0;
virtual eConfigValueDataTypes getDataType() = 0;

View File

@@ -139,12 +139,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT,
.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{
.value = "decoration:active_opacity",
.description = "opacity of active windows. [0.0 - 1.0]",
@@ -247,110 +241,104 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_STRING_LONG,
.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:
*/
SConfigOptionDescription{
.value = "decoration:blur:enabled",
.value = "blur:enabled",
.description = "enable kawase window background blur",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "decoration:blur:size",
.value = "blur:size",
.description = "blur size (distance)",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{8, 0, 100},
},
SConfigOptionDescription{
.value = "decoration:blur:passes",
.value = "blur:passes",
.description = "the amount of passes to perform",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 10},
},
SConfigOptionDescription{
.value = "decoration:blur:ignore_opacity",
.value = "blur:ignore_opacity",
.description = "make the blur layer ignore the opacity of the window",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
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.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
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 "
"blur significantly.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "decoration:blur:noise",
.value = "blur:noise",
.description = "how much noise to apply. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.0117, 0, 1},
},
SConfigOptionDescription{
.value = "decoration:blur:contrast",
.value = "blur:contrast",
.description = "contrast modulation for blur. [0.0 - 2.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.8916, 0, 2},
},
SConfigOptionDescription{
.value = "decoration:blur:brightness",
.value = "blur:brightness",
.description = "brightness modulation for blur. [0.0 - 2.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.8172, 0, 2},
},
SConfigOptionDescription{
.value = "decoration:blur:vibrancy",
.value = "blur:vibrancy",
.description = "Increase saturation of blurred colors. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.1696, 0, 1},
},
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]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0, 0, 1},
},
SConfigOptionDescription{
.value = "decoration:blur:special",
.value = "blur:special",
.description = "whether to blur behind the special workspace (note: expensive)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "decoration:blur:popups",
.value = "blur:popups",
.description = "whether to blur popups (e.g. right-click menus)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
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",
.value = "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",
.value = "blur:input_methods_ignorealpha",
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
@@ -507,12 +495,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT,
.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{
.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 "
@@ -614,18 +596,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.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:
@@ -833,25 +803,25 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:col.border_active",
.value = "general:col.border_active",
.description = "border color for inactive windows",
.type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66ffff00"},
},
SConfigOptionDescription{
.value = "group:col.border_inactive",
.value = "general:col.border_inactive",
.description = "border color for the active window",
.type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66777700"},
},
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)",
.type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66ff5500"},
},
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",
.type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66775500"},
@@ -907,7 +877,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "group:groupbar:gradients",
.description = "enables gradients",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:groupbar:height",
@@ -915,12 +885,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT,
.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{
.value = "group:groupbar:stacked",
.description = "render the groupbar as a vertical stack",
@@ -945,30 +909,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.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{
.value = "group:groupbar:text_color",
.description = "controls the group bar text color",
@@ -999,30 +939,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_COLOR,
.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:
@@ -1072,9 +988,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
},
SConfigOptionDescription{
.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,
.data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 3},
.data = SConfigOptionDescription::SRangeData{0, 0, 2},
},
SConfigOptionDescription{
.value = "misc:mouse_move_enables_dpms",
@@ -1229,18 +1145,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.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:
@@ -1264,12 +1168,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.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{
.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 "
@@ -1300,7 +1198,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.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.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "binds:movefocus_cycles_groupfirst",
@@ -1349,12 +1247,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.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:
@@ -1366,6 +1258,13 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.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:
@@ -1386,57 +1285,33 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
SConfigOptionDescription{
.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 "
"recommended to set this to false if the fullscreen application shows graphical glitches. 0 - off, 1 - on, 2 - auto (on with content type 'game')",
.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.",
"recommended to set this to false if the fullscreen application shows graphical glitches.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
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},
.data = SConfigOptionDescription::SBoolData{false},
},
/*
* 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{
.value = "cursor:no_hardware_cursors",
.description = "disables hardware cursors. Auto = disable when tearing",
.description = "disables hardware cursors",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"},
},
SConfigOptionDescription{
.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) "
"0 - off, 1 - on, 2 - auto (on with content type 'game')",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2},
.description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "cursor:min_refresh_rate",
@@ -1474,13 +1349,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"},
},
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{
.value = "cursor:default_monitor",
.description = "the name of a default monitor for the cursor to be set to on startup (see hyprctl monitors for names)",
@@ -1523,35 +1391,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.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,
.data = SConfigOptionDescription::SBoolData{false},
},
/*
* debug:
@@ -1605,6 +1444,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.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{
.value = "debug:disable_scale_checks",
.description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.",
@@ -1629,24 +1474,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.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:
@@ -1776,16 +1603,10 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:slave_count_for_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)",
.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",
.value = "master: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_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:center_ignores_reserved",
@@ -1807,16 +1628,4 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.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,31 @@
#pragma once
#include <hyprutils/animation/AnimationConfig.hpp>
#define CONFIG_MANAGER_H
#include <map>
#include "../debug/Log.hpp"
#include <unordered_map>
#include "../defines.hpp"
#include <variant>
#include <vector>
#include <algorithm>
#include <optional>
#include <functional>
#include <xf86drmMode.h>
#include "../helpers/WLClasses.hpp"
#include "../helpers/Monitor.hpp"
#include "../helpers/varlist/VarList.hpp"
#include "../desktop/Window.hpp"
#include "../desktop/LayerRule.hpp"
#include "../desktop/LayerSurface.hpp"
#include "defaultConfig.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>
#define INITANIMCFG(name) animationConfig[name] = {}
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
#define HANDLE void*
struct SWorkspaceRule {
@@ -53,6 +54,18 @@ struct SMonitorAdditionalReservedArea {
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 {
HANDLE handle = nullptr;
std::string name = "";
@@ -133,39 +146,12 @@ struct SConfigOptionDescription {
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 {
public:
CConfigManager();
void tick();
void init();
void reload();
std::string verify();
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
@@ -177,7 +163,8 @@ class CConfigManager {
void* const* getConfigValuePtr(const std::string&);
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
std::string getMainConfigPath();
void onPluginLoadUnload(const std::string& name, bool load);
static std::string getMainConfigPath();
std::string getConfigString();
SMonitorRule getMonitorRuleFor(const PHLMONITOR);
@@ -190,124 +177,141 @@ class CConfigManager {
std::vector<SP<CWindowRule>> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
std::vector<SP<CLayerRule>> getMatchingRules(PHLLS);
void ensurePersistentWorkspacesPresent();
const std::vector<SConfigOptionDescription>& getAllDescriptions();
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 removePluginConfig(HANDLE handle);
// no-op when done.
void dispatchExecOnce();
void dispatchExecShutdown();
void dispatchExecOnce();
void dispatchExecShutdown();
void performMonitorReload();
void ensureMonitorStatus();
void ensureVRR(PHLMONITOR pMonitor = nullptr);
void performMonitorReload();
void appendMonitorRule(const SMonitorRule&);
bool replaceMonitorRule(const SMonitorRule&);
void ensureMonitorStatus();
void ensureVRR(PHLMONITOR pMonitor = nullptr);
bool shouldUseSoftwareCursors(PHLMONITOR pMonitor);
void updateWatcher();
bool shouldUseSoftwareCursors();
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();
std::string getErrors();
void handlePluginLoads();
std::string getErrors();
// keywords
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> handleExecRawOnce(const std::string&, const std::string&);
std::optional<std::string> handleExecShutdown(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::optional<std::string> handlePermission(const std::string&, const std::string&);
std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleExecShutdown(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::string configCurrentPath;
std::string configCurrentPath;
bool m_bWantsMonitorReload = false;
bool m_bNoMonitorReload = false;
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
bool m_bLastConfigVerificationWasSuccessful = true;
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> mbWindowProperties = {
{"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; }},
};
void storeFloatingSize(PHLWINDOW window, const Vector2D& size);
std::optional<Vector2D> getStoredFloatingSize(PHLWINDOW window);
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> miWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }},
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> mfWindowProperties = {
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}};
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
private:
UP<Hyprlang::CConfig> m_pConfig;
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
std::vector<std::string> m_configPaths;
std::vector<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<SPluginKeyword> pluginKeywords;
std::vector<SPluginVariable> pluginVariables;
std::vector<std::string> m_vDeclaredPlugins;
std::vector<SPluginKeyword> pluginKeywords;
std::vector<SPluginVariable> pluginVariables;
bool isFirstLaunch = true; // For exec-once
bool isFirstLaunch = true; // For exec-once
std::vector<SMonitorRule> m_vMonitorRules;
std::vector<SWorkspaceRule> m_vWorkspaceRules;
std::vector<SP<CWindowRule>> m_vWindowRules;
std::vector<SP<CLayerRule>> m_vLayerRules;
std::vector<std::string> m_dBlurLSNamespaces;
std::vector<SMonitorRule> m_vMonitorRules;
std::vector<SWorkspaceRule> m_vWorkspaceRules;
std::vector<SP<CWindowRule>> m_vWindowRules;
std::vector<SP<CLayerRule>> m_vLayerRules;
std::vector<std::string> m_dBlurLSNamespaces;
bool firstExecDispatched = false;
bool m_bManualCrashInitiated = false;
bool firstExecDispatched = false;
bool m_bManualCrashInitiated = false;
std::vector<std::string> firstExecRequests;
std::vector<std::string> finalExecRequests;
std::vector<SFirstExecRequest> firstExecRequests; // bool is for if with rules
std::vector<std::string> finalExecRequests;
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;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_szConfigErrors = "";
// internal methods
void updateBlurredLS(const std::string&, const bool);
void setDefaultAnimationVars();
std::optional<std::string> resetHLConfig();
std::optional<std::string> generateConfig(std::string configPath);
std::optional<std::string> verifyConfigExists();
void postConfigReload(const Hyprlang::CParseResult& result);
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);
void registerConfigVar(const char* name, const Hyprlang::INT& val);
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;
void setAnimForChildren(SAnimationPropertyConfig* const);
void updateBlurredLS(const std::string&, const bool);
void setDefaultAnimationVars();
std::optional<std::string> resetHLConfig();
static std::optional<std::string> generateConfig(std::string configPath);
static std::optional<std::string> verifyConfigExists();
void postConfigReload(const Hyprlang::CParseResult& result);
void reload();
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);
};
inline UP<CConfigManager> g_pConfigManager;
inline std::unique_ptr<CConfigManager> g_pConfigManager;

View File

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

@@ -65,20 +65,6 @@ env = XCURSOR_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 ###
#####################
@@ -108,7 +94,6 @@ general {
# https://wiki.hyprland.org/Configuring/Variables/#decoration
decoration {
rounding = 10
rounding_power = 2
# Change transparency of focused and unfocused windows
active_opacity = 1.0
@@ -166,10 +151,10 @@ animations {
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrule = rounding 0, floating:0, onworkspace:w[tv1]
# windowrule = bordersize 0, floating:0, onworkspace:f[1]
# windowrule = rounding 0, floating:0, onworkspace:f[1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle {
@@ -283,7 +268,7 @@ bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
# 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 = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ 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/Workspace-Rules/ for workspace rules
# Example windowrule
# windowrule = float,class:^(kitty)$,title:^(kitty)$
# Example windowrule v1
# windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.*
windowrulev2 = suppressevent maximize, class:.*
# 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

@@ -6,7 +6,6 @@
#include <cerrno>
#include <sys/stat.h>
#include <filesystem>
#include "../helpers/MiscFunctions.hpp"
#include "../plugins/PluginSystem.hpp"
#include "../signal-safe.hpp"
@@ -112,7 +111,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
#ifdef LEGACY_RENDERER
finalCrashReport += "legacyrenderer\n";
#endif
#if ISDEBUG
#ifndef ISDEBUG
finalCrashReport += "debug\n";
#endif
#ifdef NO_XWAYLAND
@@ -162,7 +161,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
#if defined(__DragonFly__) || defined(__FreeBSD__)
finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga");
#else
finalCrashReport.writeCmdOutput("lspci -vnn | grep -E '(VGA|Display|3D)'");
finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA");
#endif
finalCrashReport += "\n\nos-release:\n";
@@ -192,7 +191,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
#endif
};
u_int miblen = sizeof(mib) / sizeof(mib[0]);
char exe[PATH_MAX] = "/nonexistent";
char exe[PATH_MAX] = "";
size_t sz = sizeof(exe);
sysctl(mib, miblen, &exe, &sz, NULL, 0);
const auto FPATH = std::filesystem::canonical(exe);

View File

@@ -25,7 +25,6 @@
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
using namespace Hyprutils::OS;
#include <aquamarine/input/Input.hpp>
#include "../config/ConfigDataValues.hpp"
@@ -40,19 +39,8 @@ using namespace Hyprutils::OS;
#include "debug/RollingLogFollow.hpp"
#include "config/ConfigManager.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) {
if (!str.empty() && str.back() == ',')
str.pop_back();
@@ -154,7 +142,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
return result;
}
static std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
auto allMonitors = false;
@@ -260,29 +248,28 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"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,
(int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
(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,
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),
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(),
getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "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.lock().get(), getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false"));
} else {
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: "
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\txwayland: {}\n\tpinned: "
"{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\tinhibitingIdle: {}\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,
(int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle,
w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal,
(uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.get(), getFocusHistoryID(w),
(int)g_pInputManager->isWindowInhibiting(w, false));
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName),
(int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(),
(int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (int)g_pInputManager->isWindowInhibiting(w, false));
}
}
static std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
@@ -320,17 +307,15 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form
"windows": {},
"hasfullscreen": {},
"lastwindow": "0x{:x}",
"lastwindowtitle": "{}",
"ispersistent": {}
"lastwindowtitle": "{}"
}})#",
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",
(uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "", w->m_bPersistent ? "true" : "false");
escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"),
(uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
} else {
return std::format(
"workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\tispersistent: {}\n\n",
w->m_iID, w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow,
(uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "", (int)w->m_bPersistent);
return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID,
w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow,
(uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "");
}
}
@@ -383,8 +368,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
return result;
}
}
static std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
if (!g_pCompositor->m_pLastMonitor)
return "unsafe state";
@@ -397,7 +381,7 @@ static std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::stri
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 = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@@ -418,7 +402,7 @@ static std::string workspacesRequest(eHyprCtlOutputFormat format, std::string re
return result;
}
static std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
@@ -438,7 +422,7 @@ static std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::strin
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();
if (!validMapped(PWINDOW))
@@ -452,7 +436,7 @@ static std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string
return result;
}
static std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@@ -480,11 +464,9 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
"y": {},
"w": {},
"h": {},
"namespace": "{}",
"pid": {}
"namespace": "{}"
}},)#",
(uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, escapeJSONStrings(layer->szNamespace),
layer->getPID());
(uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, escapeJSONStrings(layer->szNamespace));
}
trimTrailingComma(result);
@@ -515,8 +497,8 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]);
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,
layer->geometry.width, layer->geometry.height, layer->szNamespace, layer->getPID());
result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width,
layer->geometry.height, layer->szNamespace);
}
layerLevel++;
@@ -528,7 +510,7 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
return result;
}
static std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
@@ -550,7 +532,7 @@ static std::string layoutsRequest(eHyprCtlOutputFormat format, std::string reque
return result;
}
static std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
std::string currErrors = g_pConfigManager->getErrors();
CVarList errLines(currErrors, 0, '\n');
@@ -573,7 +555,7 @@ static std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string
return result;
}
static std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
auto getModState = [](SP<IKeyboard> keyboard, const char* xkbModName) -> bool {
@@ -743,14 +725,14 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
return result;
}
static std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
ret += "animations:\n";
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,
ac.second->internalBezier, ac.second->internalEnabled, ac.second->internalSpeed, ac.second->internalStyle);
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);
}
ret += "beziers:\n";
@@ -772,8 +754,8 @@ static std::string animationsRequest(eHyprCtlOutputFormat format, std::string re
"speed": {:.2f},
"style": "{}"
}},)#",
ac.first, ac.second->overridden ? "true" : "false", escapeJSONStrings(ac.second->internalBezier), ac.second->internalEnabled ? "true" : "false",
ac.second->internalSpeed, escapeJSONStrings(ac.second->internalStyle));
ac.first, ac.second.overridden ? "true" : "false", escapeJSONStrings(ac.second.internalBezier), ac.second.internalEnabled ? "true" : "false",
ac.second.internalSpeed, escapeJSONStrings(ac.second.internalStyle));
}
ret[ret.length() - 1] = ']';
@@ -796,7 +778,7 @@ static std::string animationsRequest(eHyprCtlOutputFormat format, std::string re
return ret;
}
static std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) {
std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@@ -810,15 +792,12 @@ static std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string re
return result;
}
static std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts();
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);
}
if (ret.empty())
ret = "none";
} else {
ret += "[";
for (auto const& sh : SHORTCUTS) {
@@ -836,7 +815,7 @@ static std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::stri
return ret;
}
static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto const& kb : g_pKeybindManager->m_vKeybinds) {
@@ -904,14 +883,14 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
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";
#else
result += "flags set:\n";
#ifdef LEGACY_RENDERER
result += "legacyrenderer\n";
#endif
#if ISDEBUG
#ifdef ISDEBUG
result += "debug\n";
#endif
#ifdef NO_XWAYLAND
@@ -942,7 +921,7 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
#ifdef LEGACY_RENDERER
result += "\"legacyrenderer\",";
#endif
#if ISDEBUG
#ifdef ISDEBUG
result += "\"debug\",";
#endif
#ifdef NO_XWAYLAND
@@ -997,7 +976,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
}
} catch (...) { GPUINFO = "error"; }
#else
const std::string GPUINFO = execAndGet("lspci -vnn | grep -E '(VGA|Display|3D)'");
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif
result += "GPU information: \n" + GPUINFO;
if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version")) {
@@ -1039,7 +1018,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
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
in = in.substr(in.find_first_of(' ') + 1);
@@ -1060,7 +1039,7 @@ static std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in)
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
auto const firstSpacePos = in.find_first_of(' ');
if (firstSpacePos == std::string::npos) // Handle the case where there's no space found (invalid input)
@@ -1109,9 +1088,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
if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source" ||
COMMAND.starts_with("windowrule")) {
@@ -1129,29 +1105,32 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in)
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);
if (REQMODE == "config-only")
g_pConfigManager->m_bNoMonitorReload = true;
g_pConfigManager->m_bForceReload = true;
g_pConfigManager->reload();
if (REQMODE == "config-only") {
g_pConfigManager->m_bNoMonitorReload = true;
}
g_pConfigManager->tick();
return "ok";
}
static std::string killRequest(eHyprCtlOutputFormat format, std::string request) {
std::string killRequest(eHyprCtlOutputFormat format, std::string request) {
g_pInputManager->setClickMode(CLICKMODE_KILL);
return "ok";
}
static std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
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();
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
@@ -1169,33 +1148,41 @@ static std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string req
return "error";
}
static std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
// split by ; ignores ; inside [] and adds ; on last command
std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
// split by ;
request = request.substr(9);
std::string reply = "";
const std::string DELIMITER = "\n\n\n";
int bracket = 0;
size_t idx = 0;
request = request.substr(9);
std::string curitem = "";
std::string reply = "";
for (size_t i = 0; i <= request.size(); ++i) {
char ch = (i < request.size()) ? request[i] : ';';
if (ch == '[')
++bracket;
else if (ch == ']')
--bracket;
else if (ch == ';' && bracket == 0) {
if (idx < i)
reply += g_pHyprCtl->getReply(trim(request.substr(idx, i - idx))).append(DELIMITER);
idx = i + 1;
continue;
auto nextItem = [&]() {
auto idx = request.find_first_of(';');
if (idx != std::string::npos) {
curitem = request.substr(0, idx);
request = request.substr(idx + 1);
} else {
curitem = request;
request = "";
}
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));
}
static std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
const auto SIZESTR = vars[vars.size() - 1];
@@ -1219,7 +1206,7 @@ static std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string re
return "ok";
}
static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) {
std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
const auto KB = vars[1];
@@ -1294,7 +1281,7 @@ static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::stri
return "ok";
}
static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
std::string errorMessage = "";
@@ -1323,12 +1310,12 @@ static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string req
return "ok";
}
static std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
auto result = g_pKeybindManager->m_mDispatchers["setprop"](request.substr(request.find_first_of(' ') + 1));
std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
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);
}
static std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
std::string curitem = "";
auto nextItem = [&]() {
@@ -1384,7 +1371,7 @@ static std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string re
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, ' ');
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
@@ -1410,7 +1397,7 @@ static std::string decorationRequest(eHyprCtlOutputFormat format, std::string re
return result;
}
static std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
if (vars.size() < 2)
@@ -1465,7 +1452,7 @@ static std::string dispatchOutput(eHyprCtlOutputFormat format, std::string reque
return "ok";
}
static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
if (vars.size() < 2)
@@ -1534,7 +1521,7 @@ static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string reque
return "ok";
}
static std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
if (vars.size() < 5)
@@ -1589,7 +1576,7 @@ static std::string dispatchNotify(eHyprCtlOutputFormat format, std::string reque
return "ok";
}
static std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::string request) {
std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
int amount = -1;
@@ -1609,7 +1596,7 @@ static std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::strin
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";
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
lockedStr = std::format(R"#(
@@ -1621,7 +1608,7 @@ static std::string getIsLocked(eHyprCtlOutputFormat format, std::string request)
return lockedStr;
}
static std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
std::string json = "{";
const auto& DESCS = g_pConfigManager->getAllDescriptions();
@@ -1636,7 +1623,7 @@ static std::string getDescriptions(eHyprCtlOutputFormat format, std::string requ
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();
if (submap.empty())
submap = "default";
@@ -1644,13 +1631,6 @@ static std::string submapRequest(eHyprCtlOutputFormat format, std::string reques
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() {
registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
@@ -1673,7 +1653,6 @@ CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
registerCommand(SHyprCtlCommand{"submap", true, submapRequest});
registerCommand(SHyprCtlCommand{.name = "reloadshaders", .exact = true, .fn = reloadShaders});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
@@ -1697,6 +1676,8 @@ CHyprCtl::CHyprCtl() {
CHyprCtl::~CHyprCtl() {
if (m_eventSource)
wl_event_source_remove(m_eventSource);
if (m_iSocketFD >= 0)
close(m_iSocketFD);
if (!m_socketPath.empty())
unlink(m_socketPath.c_str());
}
@@ -1811,7 +1792,7 @@ std::string CHyprCtl::makeDynamicCall(const std::string& 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)
return true;
@@ -1824,7 +1805,7 @@ static bool successWrite(int fd, const std::string& data, bool needLog = true) {
return false;
}
static void runWritingDebugLogThread(const int conn) {
void runWritingDebugLogThread(const int conn) {
using namespace std::chrono_literals;
Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn);
//will be finished, when reading side close connection
@@ -1847,21 +1828,18 @@ static void runWritingDebugLogThread(const int conn) {
}).detach();
}
static bool isFollowUpRollingLogRequest(const std::string& request) {
bool isFollowUpRollingLogRequest(const std::string& request) {
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)
return 0;
if (!g_pHyprCtl->m_iSocketFD.isValid())
return 0;
sockaddr_in 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;
@@ -1918,9 +1896,9 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
}
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.");
return;
}
@@ -1931,15 +1909,15 @@ void CHyprCtl::startHyprCtlSocket() {
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.");
return;
}
// 10 max queued.
listen(m_iSocketFD.get(), 10);
listen(m_iSocketFD, 10);
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
#include "../Compositor.hpp"
#include <fstream>
#include "../helpers/MiscFunctions.hpp"
#include "../desktop/Window.hpp"
#include <functional>
#include <hyprutils/os/FileDescriptor.hpp>
// exposed for main.cpp
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request);
@@ -15,12 +14,12 @@ class CHyprCtl {
CHyprCtl();
~CHyprCtl();
std::string makeDynamicCall(const std::string& input);
SP<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd);
void unregisterCommand(const SP<SHyprCtlCommand>& cmd);
std::string getReply(std::string);
std::string makeDynamicCall(const std::string& input);
SP<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd);
void unregisterCommand(const SP<SHyprCtlCommand>& cmd);
std::string getReply(std::string);
Hyprutils::OS::CFileDescriptor m_iSocketFD;
int m_iSocketFD = -1;
struct {
bool all = false;
@@ -39,4 +38,4 @@ class CHyprCtl {
std::string m_socketPath;
};
inline UP<CHyprCtl> g_pHyprCtl;
inline std::unique_ptr<CHyprCtl> g_pHyprCtl;

View File

@@ -2,9 +2,6 @@
#include "HyprDebugOverlay.hpp"
#include "config/ConfigValue.hpp"
#include "../Compositor.hpp"
#include "../render/pass/TexPassElement.hpp"
#include "../render/Renderer.hpp"
#include "../managers/AnimationManager.hpp"
CHyprDebugOverlay::CHyprDebugOverlay() {
m_pTexture = makeShared<CTexture>();
@@ -198,10 +195,10 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
double posX = 0, posY = 0;
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,
(int)maxTextW + 2, posY - offset - MARGIN_TOP + 2};
g_pHyprRenderer->damageBox(m_wbLastDrawnBox);
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
return posY - offset;
}
@@ -271,8 +268,6 @@ void CHyprDebugOverlay::draw() {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CTexPassElement::SRenderData data;
data.tex = m_pTexture;
data.box = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f);
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "../defines.hpp"
#include "../helpers/Monitor.hpp"
#include "../render/Texture.hpp"
#include <cairo/cairo.h>
#include <map>
@@ -48,4 +49,4 @@ class CHyprDebugOverlay {
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 "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../render/pass/TexPassElement.hpp"
#include "../managers/AnimationManager.hpp"
#include "../managers/HookSystemManager.hpp"
#include "../render/Renderer.hpp"
static inline auto iconBackendFromLayout(PangoLayout* layout) {
inline auto iconBackendFromLayout(PangoLayout* layout) {
// preference: Nerd > FontAwesome > text
auto eIconBackendChecks = std::array<eIconBackend, 2>{ICONS_BACKEND_NF, ICONS_BACKEND_FA};
for (auto iconID : eIconBackendChecks) {
@@ -26,7 +21,7 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() {
if (m_vNotifications.size() == 0)
return;
g_pHyprRenderer->damageBox(m_bLastDamage);
g_pHyprRenderer->damageBox(&m_bLastDamage);
});
m_pTexture = makeShared<CTexture>();
@@ -40,7 +35,7 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() {
}
void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) {
const auto PNOTIF = m_vNotifications.emplace_back(makeUnique<SNotification>()).get();
const auto PNOTIF = m_vNotifications.emplace_back(std::make_unique<SNotification>()).get();
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;
@@ -225,8 +220,8 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
CBox damage = drawNotifications(pMonitor);
g_pHyprRenderer->damageBox(damage);
g_pHyprRenderer->damageBox(m_bLastDamage);
g_pHyprRenderer->damageBox(&damage);
g_pHyprRenderer->damageBox(&m_bLastDamage);
g_pCompositor->scheduleFrameForMonitor(pMonitor);
@@ -246,12 +241,8 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CTexPassElement::SRenderData data;
data.tex = m_pTexture;
data.box = {0, 0, MONSIZE.x, MONSIZE.y};
data.a = 1.F;
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
CBox pMonBox = {0, 0, MONSIZE.x, MONSIZE.y};
g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f);
}
bool CHyprNotificationOverlay::hasAny() {

View File

@@ -2,6 +2,7 @@
#include "../defines.hpp"
#include "../helpers/Timer.hpp"
#include "../helpers/Monitor.hpp"
#include "../render/Texture.hpp"
#include "../SharedDefs.hpp"
@@ -46,18 +47,18 @@ class CHyprNotificationOverlay {
bool hasAny();
private:
CBox drawNotifications(PHLMONITOR pMonitor);
CBox m_bLastDamage;
CBox drawNotifications(PHLMONITOR pMonitor);
CBox m_bLastDamage;
std::vector<UP<SNotification>> m_vNotifications;
std::vector<std::unique_ptr<SNotification>> m_vNotifications;
cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr;
cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr;
PHLMONITORREF m_pLastMonitor;
Vector2D m_vecLastSize = Vector2D(-1, -1);
PHLMONITORREF m_pLastMonitor;
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 "../defines.hpp"
#include "../Compositor.hpp"
#include "RollingLogFollow.hpp"
#include <fstream>

View File

@@ -5,6 +5,8 @@
#include <fstream>
#include <chrono>
#include <mutex>
#include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp"
#define LOGMESSAGESIZE 1024
#define ROLLING_LOG_SIZE 4096

View File

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

View File

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

View File

@@ -1,4 +1,3 @@
#include <re2/re2.h>
#include "LayerRule.hpp"
#include <unordered_set>
#include <algorithm>

View File

@@ -2,7 +2,6 @@
#include <string>
#include <cstdint>
#include "Rule.hpp"
class CLayerRule {
public:
@@ -22,10 +21,8 @@ class CLayerRule {
RULE_ZUMBA,
};
eRuleType ruleType = RULE_INVALID;
eRuleType ruleType = RULE_INVALID;
const std::string targetNamespace;
const std::string rule;
CRuleRegexContainer targetNamespaceRegex;
const std::string targetNamespace;
const std::string rule;
};

View File

@@ -4,13 +4,6 @@
#include "../protocols/LayerShell.hpp"
#include "../protocols/core/Compositor.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 pLS = SP<CLayerSurface>(new CLayerSurface(resource));
@@ -32,19 +25,22 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
pLS->szNamespace = resource->layerNamespace;
pLS->layer = resource->current.layer;
pLS->popupHead = CPopup::create(pLS);
pLS->popupHead = std::make_unique<CPopup>(pLS);
pLS->monitor = pMonitor;
pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS);
pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace);
g_pAnimationManager->createAnimation(0.f, pLS->alpha, g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realPosition, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realSize, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE);
pLS->alpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE);
pLS->realPosition.create(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->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);
@@ -52,7 +48,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
}
void CLayerSurface::registerCallbacks() {
alpha->setUpdateCallback([this](auto) {
alpha.setUpdateCallback([this](void*) {
if (dimAround)
g_pHyprRenderer->damageMonitor(monitor.lock());
});
@@ -97,8 +93,7 @@ void CLayerSurface::onDestroy() {
onUnmap();
} else {
Debug::log(LOG, "Removing LayerSurface that wasn't mapped.");
if (alpha)
alpha->setValueAndWarp(0.f);
alpha.setValueAndWarp(0.f);
fadingOut = true;
g_pCompositor->addToFadingOutSafe(self.lock());
}
@@ -115,7 +110,7 @@ void CLayerSurface::onDestroy() {
// and damage
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;
@@ -179,7 +174,7 @@ void CLayerSurface::onMap() {
position = Vector2D(geometry.x, geometry.y);
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;
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
@@ -215,7 +210,7 @@ void CLayerSurface::onUnmap() {
}
// make a snapshot and start fade
g_pHyprRenderer->makeLayerSnapshot(self.lock());
g_pHyprOpenGL->makeLayerSnapshot(self.lock());
startAnimation(false);
@@ -234,20 +229,19 @@ void CLayerSurface::onUnmap() {
// refocus if needed
// 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 (!g_pInputManager->refocusLastWindow(PMONITOR))
g_pInputManager->refocus();
} else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource())
if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
g_pInputManager->refocusLastWindow(PMONITOR);
else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource())
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
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,
(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);
}
@@ -276,7 +270,7 @@ void CLayerSurface::onCommit() {
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
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 & CLayerShellResource::eCommittedState::STATE_LAYER) {
@@ -313,17 +307,17 @@ void CLayerSurface::onCommit() {
}
}
if (realPosition->goal() != geometry.pos()) {
if (realPosition->isBeingAnimated())
*realPosition = geometry.pos();
if (realPosition.goal() != geometry.pos()) {
if (realPosition.isBeingAnimated())
realPosition = geometry.pos();
else
realPosition->setValueAndWarp(geometry.pos());
realPosition.setValueAndWarp(geometry.pos());
}
if (realSize->goal() != geometry.size()) {
if (realSize->isBeingAnimated())
*realSize = geometry.size();
if (realSize.goal() != geometry.size()) {
if (realSize.isBeingAnimated())
realSize = geometry.size();
else
realSize->setValueAndWarp(geometry.size());
realSize.setValueAndWarp(geometry.size());
}
if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) {
@@ -333,7 +327,7 @@ void CLayerSurface::onCommit() {
nullptr);
if (!WASLASTFOCUS && popupHead) {
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());
},
nullptr);
@@ -440,17 +434,17 @@ void CLayerSurface::applyRules() {
}
void CLayerSurface::startAnimation(bool in, bool instant) {
const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle);
if (in) {
realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn"));
realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn"));
alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"));
realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn");
realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn");
alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn");
} else {
realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut"));
realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut"));
alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut"));
realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut");
realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut");
alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut");
}
const auto ANIMSTYLE = animationStyle.value_or(realPosition->getStyle());
if (ANIMSTYLE.starts_with("slide")) {
// get closest edge
const auto MIDDLE = geometry.middle();
@@ -491,9 +485,9 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
}
}
realSize->setValueAndWarp(geometry.size());
alpha->setValueAndWarp(in ? 0.f : 1.f);
*alpha = in ? 1.f : 0.f;
realSize.setValueAndWarp(geometry.size());
alpha.setValueAndWarp(in ? 0.f : 1.f);
alpha = in ? 1.f : 0.f;
Vector2D prePos;
@@ -518,11 +512,11 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
}
if (in) {
realPosition->setValueAndWarp(prePos);
*realPosition = geometry.pos();
realPosition.setValueAndWarp(prePos);
realPosition = geometry.pos();
} else {
realPosition->setValueAndWarp(geometry.pos());
*realPosition = prePos;
realPosition.setValueAndWarp(geometry.pos());
realPosition = prePos;
}
} else if (ANIMSTYLE.starts_with("popin")) {
@@ -541,25 +535,25 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5});
const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f;
alpha->setValueAndWarp(in ? 0.f : 1.f);
*alpha = in ? 1.f : 0.f;
alpha.setValueAndWarp(in ? 0.f : 1.f);
alpha = in ? 1.f : 0.f;
if (in) {
realSize->setValueAndWarp(GOALSIZE);
realPosition->setValueAndWarp(GOALPOS);
*realSize = geometry.size();
*realPosition = geometry.pos();
realSize.setValueAndWarp(GOALSIZE);
realPosition.setValueAndWarp(GOALPOS);
realSize = geometry.size();
realPosition = geometry.pos();
} else {
realSize->setValueAndWarp(geometry.size());
realPosition->setValueAndWarp(geometry.pos());
*realSize = GOALSIZE;
*realPosition = GOALPOS;
realSize.setValueAndWarp(geometry.size());
realPosition.setValueAndWarp(geometry.pos());
realSize = GOALSIZE;
realPosition = GOALPOS;
}
} else {
// fade
realPosition->setValueAndWarp(geometry.pos());
realSize->setValueAndWarp(geometry.size());
*alpha = in ? 1.f : 0.f;
realPosition.setValueAndWarp(geometry.pos());
realSize.setValueAndWarp(geometry.size());
alpha = in ? 1.f : 0.f;
}
if (!in)
@@ -570,7 +564,7 @@ bool CLayerSurface::isFadedOut() {
if (!fadingOut)
return false;
return !realPosition->isBeingAnimated() && !realSize->isBeingAnimated() && !alpha->isBeingAnimated();
return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated();
}
int CLayerSurface::popupsCount() {
@@ -578,22 +572,10 @@ int CLayerSurface::popupsCount() {
return 0;
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;
}
MONITORID CLayerSurface::monitorID() {
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

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

View File

@@ -6,43 +6,24 @@
#include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.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>
UP<CPopup> CPopup::create(PHLWINDOW pOwner) {
auto popup = UP<CPopup>(new CPopup());
popup->m_pWindowOwner = pOwner;
popup->m_pSelf = popup;
popup->initAllSignals();
return popup;
CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) {
initAllSignals();
}
UP<CPopup> CPopup::create(PHLLS pOwner) {
auto popup = UP<CPopup>(new CPopup());
popup->m_pLayerOwner = pOwner;
popup->m_pSelf = popup;
popup->initAllSignals();
return popup;
CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) {
initAllSignals();
}
UP<CPopup> CPopup::create(SP<CXDGPopupResource> resource, WP<CPopup> pOwner) {
auto popup = UP<CPopup>(new CPopup());
popup->m_pResource = resource;
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());
CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) {
m_pWLSurface = CWLSurface::create();
m_pWLSurface->assign(popup->surface->surface.lock(), this);
popup->m_vLastSize = resource->surface->current.geometry.size();
popup->reposition();
m_vLastSize = popup->surface->current.geometry.size();
reposition();
popup->initAllSignals();
return popup;
initAllSignals();
}
CPopup::~CPopup() {
@@ -73,8 +54,7 @@ void CPopup::initAllSignals() {
}
void CPopup::onNewPopup(SP<CXDGPopupResource> popup) {
const auto& POPUP = m_vChildren.emplace_back(CPopup::create(popup, m_pSelf));
POPUP->m_pSelf = POPUP;
const auto POPUP = m_vChildren.emplace_back(makeShared<CPopup>(popup, this)).get();
Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP);
}
@@ -99,13 +79,13 @@ void CPopup::onMap() {
CBox box = m_pWLSurface->resource()->extends();
box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(box);
g_pHyprRenderer->damageBox(&box);
m_vLastPos = coordsRelativeToParent();
g_pInputManager->simulateMouseMovement();
m_pSubsurfaceHead = CSubsurface::create(m_pSelf);
m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
//unconstrain();
sendScale();
@@ -133,7 +113,7 @@ void CPopup::onUnmap() {
CBox box = m_pWLSurface->resource()->extends();
box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(box);
g_pHyprRenderer->damageBox(&box);
m_pSubsurfaceHead.reset();
@@ -142,20 +122,19 @@ void CPopup::onUnmap() {
// damage all children
breadthfirst(
[](WP<CPopup> p, void* data) {
[](CPopup* p, void* data) {
if (!p->m_pResource)
return;
auto box = CBox{p->coordsGlobal(), p->size()};
g_pHyprRenderer->damageBox(box);
g_pHyprRenderer->damageBox(&box);
},
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)
// g_pInputManager->simulateMouseMovement();
if (WASLASTFOCUS)
g_pInputManager->simulateMouseMovement();
}
void CPopup::onCommit(bool ignoreSiblings) {
@@ -187,10 +166,10 @@ void CPopup::onCommit(bool ignoreSiblings) {
if (m_vLastSize != m_pResource->surface->surface->current.size || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) {
CBox box = {localToGlobal(m_vLastPos), m_vLastSize};
g_pHyprRenderer->damageBox(box);
g_pHyprRenderer->damageBox(&box);
m_vLastSize = m_pResource->surface->surface->current.size;
box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(box);
g_pHyprRenderer->damageBox(&box);
m_vLastPos = COORDSLOCAL;
}
@@ -240,7 +219,7 @@ Vector2D CPopup::coordsRelativeToParent() {
if (!m_pResource)
return {};
WP<CPopup> current = m_pSelf;
CPopup* current = this;
offset -= current->m_pResource->surface->current.geometry.pos();
while (current->m_pParent && current->m_pResource) {
@@ -264,16 +243,16 @@ Vector2D CPopup::localToGlobal(const Vector2D& rel) {
Vector2D CPopup::t1ParentCoords() {
if (!m_pWindowOwner.expired())
return m_pWindowOwner->m_vRealPosition->value();
return m_pWindowOwner->m_vRealPosition.value();
if (!m_pLayerOwner.expired())
return m_pLayerOwner->realPosition->value();
return m_pLayerOwner->realPosition.value();
ASSERT(false);
return {};
}
void CPopup::recheckTree() {
WP<CPopup> curr = m_pSelf;
CPopup* curr = this;
while (curr->m_pParent) {
curr = curr->m_pParent;
}
@@ -282,11 +261,7 @@ void CPopup::recheckTree() {
}
void CPopup::recheckChildrenRecursive() {
if (m_bInert || !m_pWLSurface)
return;
std::vector<WP<CPopup>> cpy;
std::ranges::for_each(m_vChildren, [&cpy](const auto& el) { cpy.emplace_back(el); });
auto cpy = m_vChildren;
for (auto const& c : cpy) {
c->onCommit(true);
c->recheckChildrenRecursive();
@@ -317,17 +292,17 @@ bool CPopup::visible() {
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) {
fn(n, data);
}
std::vector<WP<CPopup>> nodes2;
std::vector<CPopup*> nodes2;
nodes2.reserve(nodes.size() * 2);
for (auto const& n : nodes) {
for (auto const& c : n->m_vChildren) {
nodes2.push_back(c->m_pSelf);
nodes2.push_back(c.get());
}
}
@@ -335,42 +310,35 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
bfHelper(nodes2, fn, data);
}
void CPopup::breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data) {
std::vector<WP<CPopup>> popups;
popups.push_back(m_pSelf);
void CPopup::breadthfirst(std::function<void(CPopup*, void*)> fn, void* data) {
std::vector<CPopup*> popups;
popups.push_back(this);
bfHelper(popups, fn, data);
}
WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
std::vector<WP<CPopup>> popups;
breadthfirst([&popups](WP<CPopup> popup, void* data) { popups.push_back(popup); }, &popups);
CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
std::vector<CPopup*> popups;
breadthfirst([](CPopup* popup, void* data) { ((std::vector<CPopup*>*)data)->push_back(popup); }, &popups);
for (auto const& p : popups | std::views::reverse) {
if (!p->m_pResource || !p->m_bMapped)
continue;
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{};
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};
const auto BOX = CBox{p->coordsGlobal() + offset, size};
if (BOX.containsPoint(globalCoords))
return p;
} 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))
return p;
}
}
return {};
}
bool CPopup::inert() const {
return m_bInert;
return nullptr;
}

View File

@@ -1,20 +1,20 @@
#pragma once
#include <vector>
#include <memory>
#include "Subsurface.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/memory/Memory.hpp"
class CXDGPopupResource;
class CPopup {
public:
// dummy head nodes
static UP<CPopup> create(PHLWINDOW pOwner);
static UP<CPopup> create(PHLLS pOwner);
CPopup(PHLWINDOW pOwner);
CPopup(PHLLS pOwner);
// real nodes
static UP<CPopup> create(SP<CXDGPopupResource> popup, WP<CPopup> pOwner);
CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner);
~CPopup();
@@ -34,26 +34,22 @@ class CPopup {
void recheckTree();
bool visible();
bool inert() const;
// will also loop over this node
void breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data);
WP<CPopup> at(const Vector2D& globalCoords, bool allowsInput = false);
void breadthfirst(std::function<void(CPopup*, void*)> fn, void* data);
CPopup* at(const Vector2D& globalCoords, bool allowsInput = false);
//
SP<CWLSurface> m_pWLSurface;
WP<CPopup> m_pSelf;
bool m_bMapped = false;
private:
CPopup() = default;
// T1 owners, each popup has to have one of these
PHLWINDOWREF m_pWindowOwner;
PHLLSREF m_pLayerOwner;
// T2 owners
WP<CPopup> m_pParent;
CPopup* m_pParent = nullptr;
WP<CXDGPopupResource> m_pResource;
@@ -65,8 +61,8 @@ class CPopup {
bool m_bInert = false;
//
std::vector<UP<CPopup>> m_vChildren;
UP<CSubsurface> m_pSubsurfaceHead;
std::vector<SP<CPopup>> m_vChildren;
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
struct {
CHyprSignalListener newPopup;
@@ -85,5 +81,5 @@ class CPopup {
Vector2D localToGlobal(const Vector2D& rel);
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 "../protocols/core/Compositor.hpp"
#include "../protocols/core/Subcompositor.hpp"
#include "../render/Renderer.hpp"
#include "../managers/input/InputManager.hpp"
UP<CSubsurface> CSubsurface::create(PHLWINDOW pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface());
subsurface->m_pWindowParent = pOwner;
subsurface->m_pSelf = subsurface;
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
return subsurface;
CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) {
initSignals();
initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
}
UP<CSubsurface> CSubsurface::create(WP<CPopup> pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface());
subsurface->m_pPopupParent = pOwner;
subsurface->m_pSelf = subsurface;
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
return subsurface;
CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) {
initSignals();
initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
}
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface());
subsurface->m_pWindowParent = pOwner;
subsurface->m_pSubsurface = pSubsurface;
subsurface->m_pSelf = subsurface;
subsurface->m_pWLSurface = CWLSurface::create();
subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get());
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pSubsurface->surface.lock());
return subsurface;
CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) {
m_pWLSurface = CWLSurface::create();
m_pWLSurface->assign(pSubsurface->surface.lock(), this);
initSignals();
initExistingSubsurfaces(pSubsurface->surface.lock());
}
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface());
subsurface->m_pPopupParent = pOwner;
subsurface->m_pSubsurface = pSubsurface;
subsurface->m_pSelf = subsurface;
subsurface->m_pWLSurface = CWLSurface::create();
subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get());
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pSubsurface->surface.lock());
return subsurface;
CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
m_pWLSurface = CWLSurface::create();
m_pWLSurface->assign(pSubsurface->surface.lock(), this);
initSignals();
initExistingSubsurfaces(pSubsurface->surface.lock());
}
CSubsurface::~CSubsurface() {
;
}
void CSubsurface::initSignals() {
@@ -107,7 +90,7 @@ void CSubsurface::onCommit() {
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();
if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this
m_pWindowParent->m_pPopupHead->recheckTree();
@@ -116,20 +99,11 @@ void CSubsurface::onCommit() {
checkSiblingDamage();
if (m_vLastSize != m_pWLSurface->resource()->current.size) {
// TODO: fix this
// CBox box{COORDS, m_vLastSize};
// g_pHyprRenderer->damageBox(box);
// m_vLastSize = m_pWLSurface->resource()->current.size;
// box = {COORDS, m_vLastSize};
// 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);
CBox box{COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
m_vLastSize = m_pWLSurface->resource()->current.size;
box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
}
}
@@ -147,18 +121,16 @@ void CSubsurface::onDestroy() {
}
void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) {
WP<CSubsurface> PSUBSURFACE;
CSubsurface* PSUBSURFACE = nullptr;
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)
PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pPopupParent));
PSUBSURFACE->m_pSelf = PSUBSURFACE;
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pPopupParent)).get();
ASSERT(PSUBSURFACE);
PSUBSURFACE->m_pParent = m_pSelf;
PSUBSURFACE->m_pParent = this;
}
void CSubsurface::onMap() {
@@ -167,7 +139,7 @@ void CSubsurface::onMap() {
const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize};
box.expand(4);
g_pHyprRenderer->damageBox(box);
g_pHyprRenderer->damageBox(&box);
if (!m_pWindowParent.expired())
m_pWindowParent->updateSurfaceScaleTransformDetails();
@@ -177,7 +149,7 @@ void CSubsurface::onUnmap() {
const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize};
box.expand(4);
g_pHyprRenderer->damageBox(box);
g_pHyprRenderer->damageBox(&box);
if (m_pWLSurface->resource() == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons();
@@ -197,7 +169,7 @@ Vector2D CSubsurface::coordsGlobal() {
Vector2D coords = coordsRelativeToParent();
if (!m_pWindowParent.expired())
coords += m_pWindowParent->m_vRealPosition->value();
coords += m_pWindowParent->m_vRealPosition.value();
else if (m_pPopupParent)
coords += m_pPopupParent->coordsGlobal();

View File

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

View File

@@ -1,9 +1,7 @@
#include "WLSurface.hpp"
#include "LayerSurface.hpp"
#include "../desktop/Window.hpp"
#include "../Compositor.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../protocols/LayerShell.hpp"
#include "../render/Renderer.hpp"
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_pResource = pSurface;
@@ -74,7 +72,7 @@ Vector2D CWLSurface::correctSmallVec() const {
const auto SIZE = getViewporterCorrectedSize();
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 {
@@ -98,7 +96,7 @@ CRegion CWLSurface::computeDamage() const {
if (!m_pResource->current.texture)
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);
const auto BUFSIZE = m_pResource->current.bufferSize;

View File

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

View File

@@ -1,4 +1,3 @@
#include <hyprutils/animation/AnimatedVariable.hpp>
#include <re2/re2.h>
#include <any>
@@ -12,27 +11,12 @@
#include "../render/decorations/CHyprBorderDecoration.hpp"
#include "../config/ConfigValue.hpp"
#include "../managers/TokenManager.hpp"
#include "../managers/AnimationManager.hpp"
#include "../managers/ANRManager.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../protocols/ContentType.hpp"
#include "../protocols/FractionalScale.hpp"
#include "../xwayland/XWayland.hpp"
#include "../helpers/Color.hpp"
#include "../events/Events.hpp"
#include "../managers/XWaylandManager.hpp"
#include "../render/Renderer.hpp"
#include "../managers/LayoutManager.hpp"
#include "../managers/HookSystemManager.hpp"
#include "../managers/EventManager.hpp"
#include "../managers/input/InputManager.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
using namespace Hyprutils::Animation;
using enum NContentType::eContentType;
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
@@ -40,20 +24,18 @@ PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
pWindow->m_pSelf = pWindow;
pWindow->m_bIsX11 = true;
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderFadeAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderAngleAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER);
g_pAnimationManager->createAnimation(1.f, pWindow->m_fAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(1.f, pWindow->m_fActiveInactiveAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(CHyprColor(), pWindow->m_cRealShadowColor, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER);
pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER);
pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
return pWindow;
}
@@ -64,20 +46,18 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
pWindow->m_pSelf = pWindow;
resource->toplevel->window = pWindow;
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderFadeAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderAngleAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER);
g_pAnimationManager->createAnimation(1.f, pWindow->m_fAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(1.f, pWindow->m_fActiveInactiveAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(CHyprColor(), pWindow->m_cRealShadowColor, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER);
pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER);
pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
pWindow->m_pWLSurface->assign(pWindow->m_pXDGSurface->surface.lock(), pWindow);
@@ -99,22 +79,22 @@ CWindow::CWindow(SP<CXDGSurfaceResource> resource) : m_pXDGSurface(resource) {
CWindow::CWindow(SP<CXWaylandSurface> surface) : m_pXWaylandSurface(surface) {
m_pWLSurface = CWLSurface::create();
listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); });
listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); });
listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); });
listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); });
listeners.configureRequest = m_pXWaylandSurface->events.configureRequest.registerListener([this](std::any d) { onX11ConfigureRequest(std::any_cast<CBox>(d)); });
listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); });
listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); });
listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); });
listeners.activate = m_pXWaylandSurface->events.activate.registerListener([this](std::any d) { Events::listener_activateX11(this, nullptr); });
listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); });
listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); });
listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); });
listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); });
listeners.configure = m_pXWaylandSurface->events.configure.registerListener([this](std::any d) { onX11Configure(std::any_cast<CBox>(d)); });
listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); });
listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); });
listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); });
listeners.activate = m_pXWaylandSurface->events.activate.registerListener([this](std::any d) { Events::listener_activateX11(this, nullptr); });
if (m_pXWaylandSurface->overrideRedirect)
listeners.setGeometry = m_pXWaylandSurface->events.setGeometry.registerListener([this](std::any d) { Events::listener_unmanagedSetGeometry(this, nullptr); });
}
CWindow::~CWindow() {
if (g_pCompositor->m_pLastWindow == m_pSelf) {
if (g_pCompositor->m_pLastWindow.lock().get() == this) {
g_pCompositor->m_pLastFocus.reset();
g_pCompositor->m_pLastWindow.reset();
}
@@ -125,7 +105,7 @@ CWindow::~CWindow() {
return;
g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.get() == this; });
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return !other.first.lock() || other.first.lock().get() == this; });
}
SBoxExtents CWindow::getFullWindowExtents() {
@@ -136,8 +116,8 @@ SBoxExtents CWindow::getFullWindowExtents() {
if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
return {{m_vRealPosition->value().x - PMONITOR->vecPosition.x, m_vRealPosition->value().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition->value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition->value().y - PMONITOR->vecPosition.y)}};
return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
}
SBoxExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
@@ -160,7 +140,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
CBox surfaceExtents = {0, 0, 0, 0};
// TODO: this could be better, perhaps make a getFullWindowRegion?
m_pPopupHead->breadthfirst(
[](WP<CPopup> popup, void* data) {
[](CPopup* popup, void* data) {
if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource())
return;
@@ -201,8 +181,8 @@ CBox CWindow::getFullWindowBoundingBox() {
auto maxExtents = getFullWindowExtents();
CBox finalBox = {m_vRealPosition->value().x - maxExtents.topLeft.x, m_vRealPosition->value().y - maxExtents.topLeft.y,
m_vRealSize->value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize->value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
CBox finalBox = {m_vRealPosition.value().x - maxExtents.topLeft.x, m_vRealPosition.value().y - maxExtents.topLeft.y,
m_vRealSize.value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox;
}
@@ -256,7 +236,7 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (properties & FULL_EXTENTS)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(m_pSelf.lock(), false));
CBox box = {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y};
CBox box = {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
box.addExtents(EXTENTS);
return box;
@@ -288,8 +268,6 @@ void CWindow::updateWindowDecos() {
// make a copy because updateWindow can remove decos.
std::vector<IHyprWindowDecoration*> decos;
// reserve to avoid reallocations
decos.reserve(m_dWindowDecorations.size());
for (auto const& wd : m_dWindowDecorations) {
decos.push_back(wd.get());
@@ -302,7 +280,7 @@ void CWindow::updateWindowDecos() {
}
}
void CWindow::addWindowDeco(UP<IHyprWindowDecoration> deco) {
void CWindow::addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco) {
m_dWindowDecorations.emplace_back(std::move(deco));
g_pDecorationPositioner->forceRecalcFor(m_pSelf.lock());
updateWindowDecos();
@@ -398,7 +376,6 @@ void CWindow::updateSurfaceScaleTransformDetails(bool force) {
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
return;
PROTO::fractional->sendScale(s, PMONITOR->scale);
g_pCompositor->setPreferredScaleForSurface(s, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(s, PMONITOR->transform);
},
@@ -417,7 +394,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
if (*PINITIALWSTRACKING == 2) {
// persistent
SInitialWorkspaceToken token = std::any_cast<SInitialWorkspaceToken>(TOKEN->data);
if (token.primaryOwner == m_pSelf) {
if (token.primaryOwner.lock().get() == this) {
token.workspace = pWorkspace->getConfigName();
TOKEN->data = token;
}
@@ -429,12 +406,10 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
const auto OLDWORKSPACE = m_pWorkspace;
if (OLDWORKSPACE->isVisible()) {
m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F);
*m_fMovingToWorkspaceAlpha = 0.F;
m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; });
m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1;
}
m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1;
m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F);
m_fMovingToWorkspaceAlpha = 0.F;
m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; });
m_pWorkspace = pWorkspace;
@@ -457,12 +432,13 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
}
if (const auto SWALLOWED = m_pSwallowed.lock()) {
if (SWALLOWED->m_bCurrentlySwallowed) {
SWALLOWED->moveToWorkspace(pWorkspace);
SWALLOWED->m_pMonitor = m_pMonitor;
}
SWALLOWED->moveToWorkspace(pWorkspace);
SWALLOWED->m_pMonitor = m_pMonitor;
}
// update xwayland coords
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value());
if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) {
if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR)
PMONITOR->setSpecialWorkspace(nullptr);
@@ -497,6 +473,19 @@ PHLWINDOW CWindow::x11TransientFor() {
return nullptr;
}
void CWindow::removeDecorationByType(eDecorationType type) {
for (auto const& wd : m_dWindowDecorations) {
if (wd->getDecorationType() == type)
m_vDecosToRemove.push_back(wd.get());
}
updateWindowDecos();
}
void unregisterVar(void* ptr) {
((CBaseAnimatedVariable*)ptr)->unregister();
}
void CWindow::onUnmap() {
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
@@ -507,7 +496,7 @@ void CWindow::onUnmap() {
if (*PINITIALWSTRACKING == 2) {
// persistent token, but the first window got removed so the token is gone
SInitialWorkspaceToken token = std::any_cast<SInitialWorkspaceToken>(TOKEN->data);
if (token.primaryOwner == m_pSelf)
if (token.primaryOwner.lock().get() == this)
g_pTokenManager->removeToken(TOKEN);
}
}
@@ -515,7 +504,19 @@ void CWindow::onUnmap() {
m_iLastWorkspace = m_pWorkspace->m_iID;
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [this](const auto& other) { return other.expired() || other == m_pSelf; });
m_vRealPosition.setCallbackOnEnd(unregisterVar);
m_vRealSize.setCallbackOnEnd(unregisterVar);
m_fBorderFadeAnimationProgress.setCallbackOnEnd(unregisterVar);
m_fBorderAngleAnimationProgress.setCallbackOnEnd(unregisterVar);
m_fActiveInactiveAlpha.setCallbackOnEnd(unregisterVar);
m_fAlpha.setCallbackOnEnd(unregisterVar);
m_cRealShadowColor.setCallbackOnEnd(unregisterVar);
m_fDimPercent.setCallbackOnEnd(unregisterVar);
m_fMovingToWorkspaceAlpha.setCallbackOnEnd(unregisterVar);
m_vRealSize.setCallbackOnBegin(nullptr);
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; });
if (*PCLOSEONLASTSPECIAL && m_pWorkspace && m_pWorkspace->getWindows() == 0 && onSpecialWorkspace()) {
const auto PMONITOR = m_pMonitor.lock();
@@ -525,7 +526,7 @@ void CWindow::onUnmap() {
const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR && PMONITOR->solitaryClient == m_pSelf)
if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this)
PMONITOR->solitaryClient.reset();
if (m_pWorkspace) {
@@ -546,35 +547,30 @@ void CWindow::onUnmap() {
void CWindow::onMap() {
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
m_vRealPosition->resetAllCallbacks();
m_vRealSize->resetAllCallbacks();
m_fBorderFadeAnimationProgress->resetAllCallbacks();
m_fBorderAngleAnimationProgress->resetAllCallbacks();
m_fActiveInactiveAlpha->resetAllCallbacks();
m_fAlpha->resetAllCallbacks();
m_cRealShadowColor->resetAllCallbacks();
m_fDimPercent->resetAllCallbacks();
m_fMovingToWorkspaceAlpha->resetAllCallbacks();
m_fMovingFromWorkspaceAlpha->resetAllCallbacks();
m_vRealPosition.resetAllCallbacks();
m_vRealSize.resetAllCallbacks();
m_fBorderFadeAnimationProgress.resetAllCallbacks();
m_fBorderAngleAnimationProgress.resetAllCallbacks();
m_fActiveInactiveAlpha.resetAllCallbacks();
m_fAlpha.resetAllCallbacks();
m_cRealShadowColor.resetAllCallbacks();
m_fDimPercent.resetAllCallbacks();
m_fMovingToWorkspaceAlpha.resetAllCallbacks();
m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F);
m_vRealPosition.registerVar();
m_vRealSize.registerVar();
m_fBorderFadeAnimationProgress.registerVar();
m_fBorderAngleAnimationProgress.registerVar();
m_fActiveInactiveAlpha.registerVar();
m_fAlpha.registerVar();
m_cRealShadowColor.registerVar();
m_fDimPercent.registerVar();
m_fMovingToWorkspaceAlpha.registerVar();
if (m_fBorderAngleAnimationProgress->enabled()) {
m_fBorderAngleAnimationProgress->setValueAndWarp(0.f);
m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP<CBaseAnimatedVariable> p) { onBorderAngleAnimEnd(p); }, false);
*m_fBorderAngleAnimationProgress = 1.f;
}
m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false);
m_vRealSize->setCallbackOnBegin(
[this](auto) {
if (!m_bIsMapped || isX11OverrideRedirect())
return;
sendWindowSize();
},
false);
m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F);
m_fBorderAngleAnimationProgress.setValueAndWarp(0.f);
m_fBorderAngleAnimationProgress = 1.f;
g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf);
@@ -586,33 +582,32 @@ void CWindow::onMap() {
if (m_bIsX11)
return;
m_pSubsurfaceHead = CSubsurface::create(m_pSelf.lock());
m_pPopupHead = CPopup::create(m_pSelf.lock());
m_pSubsurfaceHead = std::make_unique<CSubsurface>(m_pSelf.lock());
m_pPopupHead = std::make_unique<CPopup>(m_pSelf.lock());
}
void CWindow::onBorderAngleAnimEnd(WP<CBaseAnimatedVariable> pav) {
const auto PAV = pav.lock();
if (!PAV)
return;
void CWindow::onBorderAngleAnimEnd(void* ptr) {
const auto PANIMVAR = (CAnimatedVariable<float>*)ptr;
if (PAV->getStyle() != "loop" || !PAV->enabled())
return;
const std::string STYLE = PANIMVAR->getConfig()->pValues->internalStyle;
const auto PANIMVAR = dynamic_cast<CAnimatedVariable<float>*>(PAV.get());
if (STYLE != "loop" || !PANIMVAR->getConfig()->pValues->internalEnabled)
return;
PANIMVAR->setCallbackOnEnd(nullptr); // we remove the callback here because otherwise setvalueandwarp will recurse this
PANIMVAR->setValueAndWarp(0);
*PANIMVAR = 1.f;
PANIMVAR->setCallbackOnEnd([&](WP<CBaseAnimatedVariable> pav) { onBorderAngleAnimEnd(pav); }, false);
PANIMVAR->setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false);
}
void CWindow::setHidden(bool hidden) {
m_bHidden = hidden;
if (hidden && g_pCompositor->m_pLastWindow == m_pSelf)
if (hidden && g_pCompositor->m_pLastWindow.lock().get() == this) {
g_pCompositor->m_pLastWindow.reset();
}
setSuspended(hidden);
}
@@ -778,25 +773,21 @@ void CWindow::applyDynamicRule(const SP<CWindowRule>& r) {
}
case CWindowRule::RULE_PROP: {
const CVarList VARS(r->szRule, 0, ' ');
if (auto search = NWindowProperties::intWindowProperties.find(VARS[1]); search != NWindowProperties::intWindowProperties.end()) {
if (auto search = g_pConfigManager->miWindowProperties.find(VARS[1]); search != g_pConfigManager->miWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = NWindowProperties::floatWindowProperties.find(VARS[1]); search != NWindowProperties::floatWindowProperties.end()) {
} else if (auto search = g_pConfigManager->mfWindowProperties.find(VARS[1]); search != g_pConfigManager->mfWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stof(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = NWindowProperties::boolWindowProperties.find(VARS[1]); search != NWindowProperties::boolWindowProperties.end()) {
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[1]); search != g_pConfigManager->mbWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(VARS[2].empty() ? true : (bool)std::stoi(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
}
break;
}
case CWindowRule::RULE_PERSISTENTSIZE: {
m_sWindowData.persistentSize = CWindowOverridableVar(true, PRIORITY_WINDOW_RULE);
break;
}
default: break;
}
}
@@ -835,28 +826,27 @@ void CWindow::updateDynamicRules() {
// it is assumed that the point is within the real window box (m_vRealPosition, m_vRealSize)
// otherwise behaviour is undefined
bool CWindow::isInCurvedCorner(double x, double y) {
const int ROUNDING = rounding();
const int ROUNDINGPOWER = roundingPower();
const int ROUNDING = rounding();
if (getRealBorderSize() >= ROUNDING)
return false;
// (x0, y0), (x0, y1), ... are the center point of rounding at each corner
double x0 = m_vRealPosition->value().x + ROUNDING;
double y0 = m_vRealPosition->value().y + ROUNDING;
double x1 = m_vRealPosition->value().x + m_vRealSize->value().x - ROUNDING;
double y1 = m_vRealPosition->value().y + m_vRealSize->value().y - ROUNDING;
double x0 = m_vRealPosition.value().x + ROUNDING;
double y0 = m_vRealPosition.value().y + ROUNDING;
double x1 = m_vRealPosition.value().x + m_vRealSize.value().x - ROUNDING;
double y1 = m_vRealPosition.value().y + m_vRealSize.value().y - ROUNDING;
if (x < x0 && y < y0) {
return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER);
return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING;
}
if (x > x1 && y < y0) {
return std::pow(x - x1, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER);
return Vector2D{x1, y0}.distance(Vector2D{x, y}) > (double)ROUNDING;
}
if (x < x0 && y > y1) {
return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y - y1, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER);
return Vector2D{x0, y1}.distance(Vector2D{x, y}) > (double)ROUNDING;
}
if (x > x1 && y > y1) {
return std::pow(x - x1, ROUNDINGPOWER) + std::pow(y - y1, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER);
return Vector2D{x1, y1}.distance(Vector2D{x, y}) > (double)ROUNDING;
}
return false;
@@ -867,7 +857,7 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
if (m_bIsX11)
return false;
auto popup = m_pPopupHead->at(pos);
CPopup* popup = m_pPopupHead->at(pos);
return popup && popup->m_pWLSurface->resource();
}
@@ -892,7 +882,7 @@ void CWindow::createGroup() {
m_sGroupData.locked = false;
m_sGroupData.deny = false;
addWindowDeco(makeUnique<CHyprGroupBarDecoration>(m_pSelf.lock()));
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock()));
if (m_pWorkspace) {
m_pWorkspace->updateWindows();
@@ -906,7 +896,7 @@ void CWindow::createGroup() {
}
void CWindow::destroyGroup() {
if (m_sGroupData.pNextWindow == m_pSelf) {
if (m_sGroupData.pNextWindow.lock().get() == this) {
if (m_eGroupRules & GROUP_SET_ALWAYS) {
Debug::log(LOG, "destoryGroup: window:{:x},title:{} has rule [group set always], ignored", (uintptr_t)this, this->m_szTitle);
return;
@@ -988,7 +978,7 @@ PHLWINDOW CWindow::getGroupCurrent() {
int CWindow::getGroupSize() {
int size = 1;
PHLWINDOW curr = m_pSelf.lock();
while (curr->m_sGroupData.pNextWindow != m_pSelf) {
while (curr->m_sGroupData.pNextWindow.lock().get() != this) {
curr = curr->m_sGroupData.pNextWindow.lock();
size++;
}
@@ -1038,22 +1028,22 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
const auto WORKSPACE = PCURRENT->m_pWorkspace;
const auto MODE = PCURRENT->m_sFullscreenState.internal;
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow.lock();
if (FULLSCREEN)
g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE);
const auto PWINDOWSIZE = PCURRENT->m_vRealSize->goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition->goal();
PCURRENT->setHidden(true);
pWindow->setHidden(false); // can remove m_pLastWindow
g_pLayoutManager->getCurrentLayout()->replaceWindowDataWith(PCURRENT, pWindow);
if (PCURRENT->m_bIsFloating) {
pWindow->m_vRealPosition->setValueAndWarp(PWINDOWPOS);
pWindow->m_vRealSize->setValueAndWarp(PWINDOWSIZE);
pWindow->m_vRealPosition.setValueAndWarp(PWINDOWPOS);
pWindow->m_vRealSize.setValueAndWarp(PWINDOWSIZE);
}
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -1074,7 +1064,7 @@ void CWindow::insertWindowToGroup(PHLWINDOW pWindow) {
const auto ENDAT = m_sGroupData.pNextWindow.lock();
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(makeUnique<CHyprGroupBarDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
if (!pWindow->m_sGroupData.pNextWindow.lock()) {
BEGINAT->m_sGroupData.pNextWindow = pWindow;
@@ -1094,7 +1084,7 @@ void CWindow::insertWindowToGroup(PHLWINDOW pWindow) {
PHLWINDOW CWindow::getGroupPrevious() {
PHLWINDOW curr = m_sGroupData.pNextWindow.lock();
while (curr != m_pSelf && curr->m_sGroupData.pNextWindow != m_pSelf)
while (curr != m_pSelf.lock() && curr->m_sGroupData.pNextWindow.lock().get() != this)
curr = curr->m_sGroupData.pNextWindow.lock();
return curr;
@@ -1109,7 +1099,7 @@ void CWindow::switchWithWindowInGroup(PHLWINDOW pWindow) {
m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow;
pWindow->m_sGroupData.pNextWindow = m_pSelf;
} else if (pWindow->m_sGroupData.pNextWindow == m_pSelf) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B
} else if (pWindow->m_sGroupData.pNextWindow.lock().get() == this) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B
pWindow->getGroupPrevious()->m_sGroupData.pNextWindow = m_pSelf;
pWindow->m_sGroupData.pNextWindow = m_sGroupData.pNextWindow;
m_sGroupData.pNextWindow = pWindow;
@@ -1135,19 +1125,22 @@ void CWindow::updateGroupOutputs() {
curr->m_pMonitor = m_pMonitor;
curr->moveToWorkspace(WS);
*curr->m_vRealPosition = m_vRealPosition->goal();
*curr->m_vRealSize = m_vRealSize->goal();
curr->m_vRealPosition = m_vRealPosition.goal();
curr->m_vRealSize = m_vRealSize.goal();
curr = curr->m_sGroupData.pNextWindow.lock();
}
}
Vector2D CWindow::middle() {
return m_vRealPosition->goal() + m_vRealSize->goal() / 2.f;
return m_vRealPosition.goal() + m_vRealSize.goal() / 2.f;
}
bool CWindow::opaque() {
if (m_fAlpha->value() != 1.f || m_fActiveInactiveAlpha->value() != 1.f)
if (m_fAlpha.value() != 1.f || m_fActiveInactiveAlpha.value() != 1.f)
return false;
if (m_vRealSize.goal().floor() != m_vReportedSize)
return false;
const auto PWORKSPACE = m_pWorkspace;
@@ -1155,7 +1148,7 @@ bool CWindow::opaque() {
if (m_pWLSurface->small() && !m_pWLSurface->m_bFillIgnoreSmall)
return false;
if (PWORKSPACE->m_fAlpha->value() != 1.f)
if (PWORKSPACE->m_fAlpha.value() != 1.f)
return false;
if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.texture)
@@ -1173,21 +1166,13 @@ bool CWindow::opaque() {
}
float CWindow::rounding() {
static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding");
static auto PROUNDINGPOWER = CConfigValue<Hyprlang::FLOAT>("decoration:rounding_power");
static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding");
float roundingPower = m_sWindowData.roundingPower.valueOr(*PROUNDINGPOWER);
float rounding = m_sWindowData.rounding.valueOr(*PROUNDING) * (roundingPower / 2.0); /* Make perceived roundness consistent. */
float rounding = m_sWindowData.rounding.valueOr(*PROUNDING);
return m_sWindowData.noRounding.valueOrDefault() ? 0 : rounding;
}
float CWindow::roundingPower() {
static auto PROUNDINGPOWER = CConfigValue<Hyprlang::FLOAT>("decoration:rounding_power");
return m_sWindowData.roundingPower.valueOr(*PROUNDINGPOWER);
}
void CWindow::updateWindowData() {
const auto PWORKSPACE = m_pWorkspace;
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
@@ -1237,7 +1222,7 @@ void CWindow::setSuspended(bool suspend) {
if (suspend == m_bSuspended)
return;
if (m_bIsX11 || !m_pXDGSurface || !m_pXDGSurface->toplevel)
if (m_bIsX11 || !m_pXDGSurface->toplevel)
return;
m_pXDGSurface->toplevel->setSuspeneded(suspend);
@@ -1245,19 +1230,21 @@ void CWindow::setSuspended(bool suspend) {
}
bool CWindow::visibleOnMonitor(PHLMONITOR pMonitor) {
CBox wbox = {m_vRealPosition->value(), m_vRealSize->value()};
CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()};
return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty();
}
void CWindow::setAnimationsToMove() {
m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
m_vRealPosition.setConfig(PANIMCFG);
m_vRealSize.setConfig(PANIMCFG);
m_bAnimatingIn = false;
}
void CWindow::onWorkspaceAnimUpdate() {
// clip box for animated offsets
if (!m_bIsFloating || m_bPinned || isFullscreen() || m_bDraggingTiled) {
if (!m_bIsFloating || m_bPinned || isFullscreen()) {
m_vFloatingOffset = Vector2D(0, 0);
return;
}
@@ -1272,16 +1259,16 @@ void CWindow::onWorkspaceAnimUpdate() {
return;
const auto WINBB = getFullWindowBoundingBox();
if (PWORKSPACE->m_vRenderOffset->value().x != 0) {
const auto PROGRESS = PWORKSPACE->m_vRenderOffset->value().x / PWSMON->vecSize.x;
if (PWORKSPACE->m_vRenderOffset.value().x != 0) {
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().x / PWSMON->vecSize.x;
if (WINBB.x < PWSMON->vecPosition.x)
offset.x += (PWSMON->vecPosition.x - WINBB.x) * PROGRESS;
if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x)
offset.x += (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS;
} else if (PWORKSPACE->m_vRenderOffset->value().y != 0) {
const auto PROGRESS = PWORKSPACE->m_vRenderOffset->value().y / PWSMON->vecSize.y;
} else if (PWORKSPACE->m_vRenderOffset.value().y != 0) {
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().y / PWSMON->vecSize.y;
if (WINBB.y < PWSMON->vecPosition.y)
offset.y += (PWSMON->vecPosition.y - WINBB.y) * PROGRESS;
@@ -1293,20 +1280,12 @@ void CWindow::onWorkspaceAnimUpdate() {
m_vFloatingOffset = offset;
}
void CWindow::onFocusAnimUpdate() {
// borderangle once
if (m_fBorderAngleAnimationProgress->enabled() && !m_fBorderAngleAnimationProgress->isBeingAnimated()) {
m_fBorderAngleAnimationProgress->setValueAndWarp(0.f);
*m_fBorderAngleAnimationProgress = 1.f;
}
}
int CWindow::popupsCount() {
if (m_bIsX11)
return 0;
int no = -1;
m_pPopupHead->breadthfirst([](WP<CPopup> p, void* d) { *((int*)d) += 1; }, &no);
m_pPopupHead->breadthfirst([](CPopup* p, void* d) { *((int*)d) += 1; }, &no);
return no;
}
@@ -1320,12 +1299,13 @@ int CWindow::surfacesCount() {
}
void CWindow::clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize) {
const Vector2D REALSIZE = m_vRealSize->goal();
const Vector2D REALSIZE = m_vRealSize.goal();
const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), maxSize.value_or(Vector2D{INFINITY, INFINITY}));
const Vector2D DELTA = REALSIZE - NEWSIZE;
*m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0;
*m_vRealSize = NEWSIZE;
m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0;
m_vRealSize = NEWSIZE;
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE);
}
bool CWindow::isFullscreen() {
@@ -1417,25 +1397,14 @@ void CWindow::activate(bool force) {
}
void CWindow::onUpdateState() {
std::optional<bool> requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen;
std::optional<MONITORID> requestsID = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreenMonitor : MONITOR_INVALID;
std::optional<bool> requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize;
std::optional<bool> requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen;
std::optional<bool> requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize;
if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
if (requestsID.has_value() && (requestsID.value() != MONITOR_INVALID) && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT)) {
if (m_bIsMapped) {
const auto monitor = g_pCompositor->getMonitorFromID(requestsID.value());
g_pCompositor->moveWindowToWorkspaceSafe(m_pSelf.lock(), monitor->activeWorkspace);
g_pCompositor->setActiveMonitor(monitor);
}
if (!m_bIsMapped)
m_iWantsInitialFullscreenMonitor = requestsID.value();
}
bool fs = requestsFS.value();
if (m_bIsMapped)
if (m_bIsMapped) {
g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value());
}
if (!m_bIsMapped)
m_bWantsInitialFullscreen = fs;
@@ -1535,21 +1504,21 @@ void CWindow::onResourceChangeX11() {
Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface->resource().get());
}
void CWindow::onX11ConfigureRequest(CBox box) {
void CWindow::onX11Configure(CBox box) {
if (!m_pXWaylandSurface->surface || !m_pXWaylandSurface->mapped || !m_bIsMapped) {
m_pXWaylandSurface->configure(box);
m_vPendingReportedSize = box.size();
m_vReportedSize = box.size();
m_vReportedPosition = box.pos();
updateX11SurfaceScale();
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
m_fX11SurfaceScaledBy = PMONITOR->scale;
return;
}
g_pHyprRenderer->damageWindow(m_pSelf.lock());
if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) {
sendWindowSize(true);
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true);
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock());
return;
@@ -1560,26 +1529,33 @@ void CWindow::onX11ConfigureRequest(CBox box) {
else
setHidden(true);
m_vRealPosition->setValueAndWarp(xwaylandPositionToReal(box.pos()));
m_vRealSize->setValueAndWarp(xwaylandSizeToReal(box.size()));
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos());
m_vPosition = m_vRealPosition->goal();
m_vSize = m_vRealSize->goal();
m_vRealPosition.setValueAndWarp(LOGICALPOS);
m_vRealSize.setValueAndWarp(box.size());
if (m_vPendingReportedSize != box.size() || m_vReportedPosition != box.pos()) {
m_pXWaylandSurface->configure(box);
m_vReportedSize = box.size();
m_vPendingReportedSize = box.size();
m_vReportedPosition = box.pos();
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) {
m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale);
m_fX11SurfaceScaledBy = PMONITOR->scale;
}
}
updateX11SurfaceScale();
m_vPosition = m_vRealPosition.value();
m_vSize = m_vRealSize.value();
m_pXWaylandSurface->configure(box);
m_vPendingReportedSize = box.size();
m_vReportedSize = box.size();
updateWindowDecos();
if (!m_pWorkspace || !m_pWorkspace->isVisible())
return; // further things are only for visible windows
m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition->goal() + m_vRealSize->goal() / 2.f)->activeWorkspace;
m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true);
@@ -1629,17 +1605,17 @@ PHLWINDOW CWindow::getSwallower() {
if (!(*PSWALLOWREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return !RE2::FullMatch(other->m_szClass, *PSWALLOWREGEX); });
if (candidates.size() == 0)
if (candidates.size() <= 0)
return nullptr;
if (!(*PSWALLOWEXREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return RE2::FullMatch(other->m_szTitle, *PSWALLOWEXREGEX); });
if (candidates.size() == 0)
if (candidates.size() <= 0)
return nullptr;
if (candidates.size() == 1)
return candidates[0];
return candidates.at(0);
// walk up the focus history and find the last focused
for (auto const& w : g_pCompositor->m_vWindowFocusHistory) {
@@ -1651,17 +1627,17 @@ PHLWINDOW CWindow::getSwallower() {
}
// if none are found (??) then just return the first one
return candidates[0];
return candidates.at(0);
}
void CWindow::unsetWindowData(eOverridePriority priority) {
for (auto const& element : NWindowProperties::boolWindowProperties) {
for (auto const& element : g_pConfigManager->mbWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
for (auto const& element : NWindowProperties::intWindowProperties) {
for (auto const& element : g_pConfigManager->miWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
for (auto const& element : NWindowProperties::floatWindowProperties) {
for (auto const& element : g_pConfigManager->mfWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
}
@@ -1687,7 +1663,7 @@ Vector2D CWindow::requestedMinSize() {
Vector2D CWindow::requestedMaxSize() {
constexpr int NO_MAX_SIZE_LIMIT = 99999;
if (((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && (!m_pXDGSurface || !m_pXDGSurface->toplevel)) || m_sWindowData.noMaxSize.valueOrDefault()))
if (((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel) || m_sWindowData.noMaxSize.valueOrDefault()))
return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT);
Vector2D maxSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->max_width, m_pXWaylandSurface->sizeHints->max_height) : m_pXDGSurface->toplevel->layoutMaxSize();
@@ -1699,111 +1675,3 @@ Vector2D CWindow::requestedMaxSize() {
return maxSize;
}
Vector2D CWindow::realToReportSize() {
if (!m_bIsX11)
return m_vRealSize->goal().clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
const auto REPORTSIZE = m_vRealSize->goal().clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
const auto PMONITOR = m_pMonitor.lock();
if (*PXWLFORCESCALEZERO && PMONITOR)
return REPORTSIZE * PMONITOR->scale;
return REPORTSIZE;
}
Vector2D CWindow::realToReportPosition() {
if (!m_bIsX11)
return m_vRealPosition->goal();
return g_pXWaylandManager->waylandToXWaylandCoords(m_vRealPosition->goal());
}
Vector2D CWindow::xwaylandSizeToReal(Vector2D size) {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
const auto PMONITOR = m_pMonitor.lock();
const auto SIZE = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
const auto SCALE = *PXWLFORCESCALEZERO ? PMONITOR->scale : 1.0f;
return SIZE / SCALE;
}
Vector2D CWindow::xwaylandPositionToReal(Vector2D pos) {
return g_pXWaylandManager->xwaylandToWaylandCoords(pos);
}
void CWindow::updateX11SurfaceScale() {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
m_fX11SurfaceScaledBy = 1.0f;
if (m_bIsX11 && *PXWLFORCESCALEZERO) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
m_fX11SurfaceScaledBy = PMONITOR->scale;
}
}
void CWindow::sendWindowSize(bool force) {
const auto PMONITOR = m_pMonitor.lock();
Debug::log(TRACE, "sendWindowSize: window:{:x},title:{} with real pos {}, real size {} (force: {})", (uintptr_t)this, this->m_szTitle, m_vRealPosition->goal(),
m_vRealSize->goal(), force);
// TODO: this should be decoupled from setWindowSize IMO
const auto REPORTPOS = realToReportPosition();
const auto REPORTSIZE = realToReportSize();
if (!force && m_vPendingReportedSize == REPORTSIZE && (m_vReportedPosition == REPORTPOS || !m_bIsX11))
return;
m_vReportedPosition = REPORTPOS;
m_vPendingReportedSize = REPORTSIZE;
updateX11SurfaceScale();
if (m_bIsX11 && m_pXWaylandSurface)
m_pXWaylandSurface->configure({REPORTPOS, REPORTSIZE});
else if (m_pXDGSurface && m_pXDGSurface->toplevel)
m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(REPORTSIZE), REPORTPOS.floor());
}
NContentType::eContentType CWindow::getContentType() {
if (!m_pWLSurface || !m_pWLSurface->resource() || !m_pWLSurface->resource()->contentType.valid())
return CONTENT_TYPE_NONE;
return m_pWLSurface->resource()->contentType->value;
}
void CWindow::setContentType(NContentType::eContentType contentType) {
if (!m_pWLSurface->resource()->contentType.valid())
m_pWLSurface->resource()->contentType = PROTO::contentType->getContentType(m_pWLSurface->resource());
// else disallow content type change if proto is used?
Debug::log(INFO, "ContentType for window {}", (int)contentType);
m_pWLSurface->resource()->contentType->value = contentType;
}
void CWindow::deactivateGroupMembers() {
auto curr = getGroupHead();
while (curr) {
if (curr != m_pSelf.lock()) {
// we dont want to deactivate unfocused xwayland windows
// because X is weird, keep the behavior for wayland windows
// also its not really needed for xwayland windows
// ref: #9760 #9294
if (!curr->m_bIsX11 && curr->m_pXDGSurface && curr->m_pXDGSurface->toplevel)
curr->m_pXDGSurface->toplevel->setActive(false);
}
curr = curr->m_sGroupData.pNextWindow.lock();
if (curr == getGroupHead())
break;
}
}
bool CWindow::isNotResponding() {
return g_pANRManager->isNotResponding(m_pSelf.lock());
}

View File

@@ -2,9 +2,9 @@
#include <vector>
#include <string>
#include <optional>
#include "../config/ConfigDataValues.hpp"
#include "../defines.hpp"
#include "../helpers/AnimatedVariable.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/signal/Signal.hpp"
@@ -12,14 +12,12 @@
#include "../macros.hpp"
#include "../managers/XWaylandManager.hpp"
#include "../render/decorations/IHyprWindowDecoration.hpp"
#include "../render/Transformer.hpp"
#include "DesktopTypes.hpp"
#include "Popup.hpp"
#include "Subsurface.hpp"
#include "WLSurface.hpp"
#include "Workspace.hpp"
#include "WindowRule.hpp"
#include "../protocols/types/ContentType.hpp"
class CXDGSurfaceResource;
class CXWaylandSurface;
@@ -59,7 +57,6 @@ enum eSuppressEvents : uint8_t {
SUPPRESS_MAXIMIZE = 1 << 1,
SUPPRESS_ACTIVATE = 1 << 2,
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
SUPPRESS_FULLSCREEN_OUTPUT = 1 << 4,
};
class IWindowTransformer;
@@ -186,7 +183,6 @@ struct SWindowData {
CWindowOverridableVar<bool> renderUnfocused = false;
CWindowOverridableVar<int> rounding;
CWindowOverridableVar<float> roundingPower;
CWindowOverridableVar<int> borderSize;
CWindowOverridableVar<float> scrollMouse;
@@ -198,8 +194,6 @@ struct SWindowData {
CWindowOverridableVar<CGradientValueData> activeBorderColor;
CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
CWindowOverridableVar<bool> persistentSize;
};
struct SInitialWorkspaceToken {
@@ -238,8 +232,8 @@ class CWindow {
Vector2D m_vSize = Vector2D(0, 0);
// this is the real position and size used to draw the thing
PHLANIMVAR<Vector2D> m_vRealPosition;
PHLANIMVAR<Vector2D> m_vRealSize;
CAnimatedVariable<Vector2D> m_vRealPosition;
CAnimatedVariable<Vector2D> m_vRealSize;
// for not spamming the protocols
Vector2D m_vReportedPosition;
@@ -293,30 +287,29 @@ class CWindow {
bool m_bNoInitialFocus = false;
// Fullscreen and Maximize
bool m_bWantsInitialFullscreen = false;
MONITORID m_iWantsInitialFullscreenMonitor = MONITOR_INVALID;
bool m_bWantsInitialFullscreen = false;
// bitfield eSuppressEvents
uint64_t m_eSuppressedEvents = SUPPRESS_NONE;
// desktop components
UP<CSubsurface> m_pSubsurfaceHead;
UP<CPopup> m_pPopupHead;
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
std::unique_ptr<CPopup> m_pPopupHead;
// Animated border
CGradientValueData m_cRealBorderColor = {0};
CGradientValueData m_cRealBorderColorPrevious = {0};
PHLANIMVAR<float> m_fBorderFadeAnimationProgress;
PHLANIMVAR<float> m_fBorderAngleAnimationProgress;
CGradientValueData m_cRealBorderColor = {0};
CGradientValueData m_cRealBorderColorPrevious = {0};
CAnimatedVariable<float> m_fBorderFadeAnimationProgress;
CAnimatedVariable<float> m_fBorderAngleAnimationProgress;
// Fade in-out
PHLANIMVAR<float> m_fAlpha;
bool m_bFadingOut = false;
bool m_bReadyToDelete = false;
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
Vector2D m_vOriginalClosedSize; // drawing the closing animations
SBoxExtents m_eOriginalClosedExtents;
bool m_bAnimatingIn = false;
CAnimatedVariable<float> m_fAlpha;
bool m_bFadingOut = false;
bool m_bReadyToDelete = false;
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
Vector2D m_vOriginalClosedSize; // drawing the closing animations
SBoxExtents m_eOriginalClosedExtents;
bool m_bAnimatingIn = false;
// For pinned (sticky) windows
bool m_bPinned = false;
@@ -332,33 +325,31 @@ class CWindow {
// Window decorations
// TODO: make this a SP.
std::vector<UP<IHyprWindowDecoration>> m_dWindowDecorations;
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
std::vector<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations;
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
// Special render data, rules, etc
SWindowData m_sWindowData;
// Transformers
std::vector<UP<IWindowTransformer>> m_vTransformers;
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
// for alpha
PHLANIMVAR<float> m_fActiveInactiveAlpha;
PHLANIMVAR<float> m_fMovingFromWorkspaceAlpha;
CAnimatedVariable<float> m_fActiveInactiveAlpha;
// animated shadow color
PHLANIMVAR<CHyprColor> m_cRealShadowColor;
CAnimatedVariable<CHyprColor> m_cRealShadowColor;
// animated tint
PHLANIMVAR<float> m_fDimPercent;
CAnimatedVariable<float> m_fDimPercent;
// animate moving to an invisible workspace
int m_iMonitorMovedFrom = -1; // -1 means not moving
PHLANIMVAR<float> m_fMovingToWorkspaceAlpha;
int m_iMonitorMovedFrom = -1; // -1 means not moving
CAnimatedVariable<float> m_fMovingToWorkspaceAlpha;
// swallowing
PHLWINDOWREF m_pSwallowed;
bool m_bCurrentlySwallowed = false;
bool m_bGroupSwallowed = false;
bool m_bGroupSwallowed = false;
// focus stuff
bool m_bStayFocused = false;
@@ -390,9 +381,6 @@ class CWindow {
// window tags
CTagKeeper m_tags;
// ANR
PHLANIMVAR<float> m_notRespondingTint;
// For the list lookup
bool operator==(const CWindow& rhs) const {
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
@@ -400,95 +388,84 @@ class CWindow {
}
// methods
CBox getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props);
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(UP<IHyprWindowDecoration> deco);
void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco);
void uncacheWindowDecos();
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType);
void updateToplevel();
void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW x11TransientFor();
void onUnmap();
void onMap();
void setHidden(bool hidden);
bool isHidden();
void applyDynamicRule(const SP<CWindowRule>& r);
void updateDynamicRules();
SBoxExtents getFullWindowReservedArea();
Vector2D middle();
bool opaque();
float rounding();
float roundingPower();
bool canBeTorn();
void setSuspended(bool suspend);
bool visibleOnMonitor(PHLMONITOR pMonitor);
WORKSPACEID workspaceID();
MONITORID monitorID();
bool onSpecialWorkspace();
void activate(bool force = false);
int surfacesCount();
void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize();
float getScrollMouse();
float getScrollTouchpad();
void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(WP<Hyprutils::Animation::CBaseAnimatedVariable> pav);
bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos);
int popupsCount();
void applyGroupRules();
void createGroup();
void destroyGroup();
PHLWINDOW getGroupHead();
PHLWINDOW getGroupTail();
PHLWINDOW getGroupCurrent();
PHLWINDOW getGroupPrevious();
PHLWINDOW getGroupWindowByIndex(int);
int getGroupSize();
bool canBeGroupedInto(PHLWINDOW pWindow);
void setGroupCurrent(PHLWINDOW pWindow);
void insertWindowToGroup(PHLWINDOW pWindow);
void updateGroupOutputs();
void switchWithWindowInGroup(PHLWINDOW pWindow);
void setAnimationsToMove();
void onWorkspaceAnimUpdate();
void onFocusAnimUpdate();
void onUpdateState();
void onUpdateMeta();
void onX11ConfigureRequest(CBox box);
void onResourceChangeX11();
std::string fetchTitle();
std::string fetchClass();
void warpCursor(bool force = false);
PHLWINDOW getSwallower();
void unsetWindowData(eOverridePriority priority);
bool isX11OverrideRedirect();
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 getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props);
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco);
void uncacheWindowDecos();
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType);
void removeDecorationByType(eDecorationType);
void updateToplevel();
void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW x11TransientFor();
void onUnmap();
void onMap();
void setHidden(bool hidden);
bool isHidden();
void applyDynamicRule(const SP<CWindowRule>& r);
void updateDynamicRules();
SBoxExtents getFullWindowReservedArea();
Vector2D middle();
bool opaque();
float rounding();
bool canBeTorn();
void setSuspended(bool suspend);
bool visibleOnMonitor(PHLMONITOR pMonitor);
WORKSPACEID workspaceID();
MONITORID monitorID();
bool onSpecialWorkspace();
void activate(bool force = false);
int surfacesCount();
void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize();
float getScrollMouse();
float getScrollTouchpad();
void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(void* ptr);
bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos);
int popupsCount();
void applyGroupRules();
void createGroup();
void destroyGroup();
PHLWINDOW getGroupHead();
PHLWINDOW getGroupTail();
PHLWINDOW getGroupCurrent();
PHLWINDOW getGroupPrevious();
PHLWINDOW getGroupWindowByIndex(int);
int getGroupSize();
bool canBeGroupedInto(PHLWINDOW pWindow);
void setGroupCurrent(PHLWINDOW pWindow);
void insertWindowToGroup(PHLWINDOW pWindow);
void updateGroupOutputs();
void switchWithWindowInGroup(PHLWINDOW pWindow);
void setAnimationsToMove();
void onWorkspaceAnimUpdate();
void onUpdateState();
void onUpdateMeta();
void onX11Configure(CBox box);
void onResourceChangeX11();
std::string fetchTitle();
std::string fetchClass();
void warpCursor(bool force = false);
PHLWINDOW getSwallower();
void unsetWindowData(eOverridePriority priority);
bool isX11OverrideRedirect();
bool isModal();
Vector2D requestedMinSize();
Vector2D requestedMaxSize();
CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y};
CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
// listeners
@@ -508,7 +485,7 @@ class CWindow {
CHyprSignalListener commit;
CHyprSignalListener destroy;
CHyprSignalListener activate;
CHyprSignalListener configureRequest;
CHyprSignalListener configure;
CHyprSignalListener setGeometry;
CHyprSignalListener updateState;
CHyprSignalListener updateMetadata;
@@ -542,42 +519,6 @@ inline bool validMapped(PHLWINDOWREF w) {
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
- 'x', only address, equivalent of (uintpr_t)CWindow*

View File

@@ -1,24 +1,22 @@
#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",
"float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused",
};
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",
"animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity",
"plugin:", "prop", "pseudo", "rounding", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray",
};
CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) {
const auto VALS = CVarList(rule, 2, ' ');
const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule](auto prefix) { return rule.starts_with(prefix); }) ||
(NWindowProperties::boolWindowProperties.find(VALS[0]) != NWindowProperties::boolWindowProperties.end()) ||
(NWindowProperties::intWindowProperties.find(VALS[0]) != NWindowProperties::intWindowProperties.end()) ||
(NWindowProperties::floatWindowProperties.find(VALS[0]) != NWindowProperties::floatWindowProperties.end());
(g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) ||
(g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end()) ||
(g_pConfigManager->mfWindowProperties.find(VALS[0]) != g_pConfigManager->mfWindowProperties.end());
if (!VALID)
return;
@@ -39,8 +37,6 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool
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"))
@@ -77,14 +73,12 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool
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()) {
if (g_pConfigManager->miWindowProperties.find(VARS[0]) != g_pConfigManager->miWindowProperties.end() ||
g_pConfigManager->mbWindowProperties.find(VARS[0]) != g_pConfigManager->mbWindowProperties.end() ||
g_pConfigManager->mfWindowProperties.find(VARS[0]) != g_pConfigManager->mfWindowProperties.end()) {
*const_cast<std::string*>(&szRule) = "prop " + rule;
ruleType = RULE_PROP;
Debug::log(LOG, "CWindowRule: direct prop rule found, rewritten {} -> {}", rule, szRule);
@@ -93,4 +87,4 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool
ruleType = RULE_INVALID;
}
}
}
}

View File

@@ -2,7 +2,6 @@
#include <string>
#include <cstdint>
#include "Rule.hpp"
class CWindowRule {
public:
@@ -36,8 +35,6 @@ class CWindowRule {
RULE_TAG,
RULE_WORKSPACE,
RULE_PROP,
RULE_CONTENT,
RULE_PERSISTENTSIZE,
};
eRuleType ruleType = RULE_INVALID;
@@ -60,12 +57,4 @@ class CWindowRule {
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 "../Compositor.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>
using namespace Hyprutils::String;
@@ -24,10 +19,16 @@ CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, boo
void CWorkspace::init(PHLWORKSPACE self) {
m_pSelf = self;
g_pAnimationManager->createAnimation(Vector2D(0, 0), m_vRenderOffset,
g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(1.f, m_fAlpha, g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self,
AVARDAMAGE_ENTIRE);
m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") :
g_pConfigManager->getAnimationPropertyConfig("workspacesIn"),
self, 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);
if (RULEFORTHIS.defaultName.has_value())
@@ -54,11 +55,16 @@ void CWorkspace::init(PHLWORKSPACE self) {
EMIT_HOOK_EVENT("createWorkspace", this);
}
SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName() const {
SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName(bool perMonitor) const {
if (perMonitor)
return m_sPrevWorkspacePerMonitor;
return m_sPrevWorkspace;
}
CWorkspace::~CWorkspace() {
m_vRenderOffset.unregister();
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.
@@ -76,15 +82,15 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
if (!instant) {
const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out");
m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME));
m_vRenderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME));
m_fAlpha.m_pConfig = 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");
// set floating windows offset callbacks
m_vRenderOffset->setUpdateCallback([&](auto) {
m_vRenderOffset.setUpdateCallback([&](void*) {
for (auto const& w : g_pCompositor->m_vWindows) {
if (!validMapped(w) || w->workspaceID() != m_iID)
continue;
@@ -104,84 +110,84 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); }
}
m_fAlpha->setValueAndWarp(1.f);
m_vRenderOffset->setValueAndWarp(Vector2D(0, 0));
m_fAlpha.setValueAndWarp(1.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) {
m_fAlpha->setValueAndWarp(0.f);
m_vRenderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
*m_fAlpha = 1.f;
*m_vRenderOffset = Vector2D(0, 0);
m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0);
} else {
m_fAlpha->setValueAndWarp(1.f);
*m_fAlpha = 0.f;
*m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
}
} else {
if (in) {
m_fAlpha->setValueAndWarp(0.f);
m_vRenderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0));
*m_fAlpha = 1.f;
*m_vRenderOffset = Vector2D(0, 0);
m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0));
m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0);
} else {
m_fAlpha->setValueAndWarp(1.f);
*m_fAlpha = 0.f;
*m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0);
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0);
}
}
} 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) {
m_fAlpha->setValueAndWarp(0.f);
*m_fAlpha = 1.f;
m_fAlpha.setValueAndWarp(0.f);
m_fAlpha = 1.f;
} else {
m_fAlpha->setValueAndWarp(1.f);
*m_fAlpha = 0.f;
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
}
} else if (ANIMSTYLE == "slidevert") {
// fallback is slide
const auto PMONITOR = m_pMonitor.lock();
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) {
m_vRenderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
*m_vRenderOffset = Vector2D(0, 0);
m_vRenderOffset.setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
m_vRenderOffset = Vector2D(0, 0);
} else {
*m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
}
} else {
// fallback is slide
const auto PMONITOR = m_pMonitor.lock();
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) {
m_vRenderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
*m_vRenderOffset = Vector2D(0, 0);
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
m_vRenderOffset = Vector2D(0, 0);
} else {
*m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
}
}
if (m_bIsSpecialWorkspace) {
// required for open/close animations
if (in) {
m_fAlpha->setValueAndWarp(0.f);
*m_fAlpha = 1.f;
m_fAlpha.setValueAndWarp(0.f);
m_fAlpha = 1.f;
} else {
m_fAlpha->setValueAndWarp(1.f);
*m_fAlpha = 0.f;
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
}
}
if (instant) {
m_vRenderOffset->warp();
m_fAlpha->warp();
m_vRenderOffset.warp();
m_fAlpha.warp();
}
}
@@ -215,7 +221,10 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
m_sPrevWorkspace.id = prev->m_iID;
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() {
@@ -261,7 +270,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
// n - named: n[true] or n[s:string] or n[e:string]
// m - monitor: m[monitor_selector]
// 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 v will count only visible windows
// f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states
@@ -371,7 +379,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
prop = prop.substr(2, prop.length() - 3);
int wantsOnlyTiled = -1;
int wantsOnlyPinned = false;
bool wantsCountGroup = false;
bool wantsCountVisible = false;
@@ -383,9 +390,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
} else if (flag == 'f' && wantsOnlyTiled == -1) {
wantsOnlyTiled = 0;
flagCount++;
} else if (flag == 'p' && !wantsOnlyPinned) {
wantsOnlyPinned = true;
flagCount++;
} else if (flag == 'g' && !wantsCountGroup) {
wantsCountGroup = true;
flagCount++;
@@ -416,11 +420,9 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
int count;
if (wantsCountGroup)
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (count != from)
@@ -451,12 +453,10 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
WORKSPACEID count;
if (wantsCountGroup)
count =
getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (std::clamp(count, from, to) != count)
@@ -544,15 +544,13 @@ bool CWorkspace::isVisibleNotCovered() {
return PMONITOR->activeWorkspace->m_iID == m_iID;
}
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) {
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
@@ -561,7 +559,7 @@ int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> on
return no;
}
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) {
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
@@ -570,8 +568,6 @@ int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onl
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++;
@@ -637,7 +633,7 @@ void CWorkspace::forceReportSizesToWindows() {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue;
w->sendWindowSize(true);
g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true);
}
}
@@ -648,12 +644,6 @@ void CWorkspace::rename(const std::string& name) {
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});
}

View File

@@ -24,19 +24,22 @@ class CWorkspace {
// Workspaces ID-based have IDs > 0
// and workspaces name-based have IDs starting with -1337
WORKSPACEID m_iID = WORKSPACE_INVALID;
std::string m_szName = "";
PHLMONITORREF m_pMonitor;
WORKSPACEID m_iID = WORKSPACE_INVALID;
std::string m_szName = "";
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;
eFullscreenMode m_efFullscreenMode = FSMODE_NONE;
bool m_bHasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FSMODE_NONE;
wl_array m_wlrCoordinateArr;
wl_array m_wlrCoordinateArr;
// for animations
PHLANIMVAR<Vector2D> m_vRenderOffset;
PHLANIMVAR<float> m_fAlpha;
bool m_bForceRendering = false;
CAnimatedVariable<Vector2D> m_vRenderOffset;
CAnimatedVariable<float> m_fAlpha;
bool m_bForceRendering = false;
// allows damage to propagate.
bool m_bVisible = false;
@@ -69,11 +72,11 @@ class CWorkspace {
std::string getConfigName();
bool matchesStaticSelector(const std::string& selector);
void markInert();
SWorkspaceIDName getPrevWorkspaceIDName() const;
SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const;
void updateWindowDecos();
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 = {});
int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
bool hasUrgentWindow();
PHLWINDOW getFirstWindow();
PHLWINDOW getTopLeftWindow();
@@ -85,10 +88,7 @@ class CWorkspace {
void updateWindows();
private:
void init(PHLWORKSPACE self);
// Previous workspace ID and name is stored during a workspace change, allowing travel
// to the previous workspace.
SWorkspaceIDName m_sPrevWorkspace;
void init(PHLWORKSPACE self);
SP<HOOK_CALLBACK_FN> m_pFocusedWindowHook;
bool m_bInert = true;

View File

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

View File

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

View File

@@ -17,10 +17,9 @@ class IPointer : public IHID {
virtual SP<Aquamarine::IPointer> aq() = 0;
struct SMotionEvent {
uint32_t timeMs = 0;
Vector2D delta, unaccel;
bool mouse = false;
SP<IPointer> device;
uint32_t timeMs = 0;
Vector2D delta, unaccel;
bool mouse = false;
};
struct SMotionAbsoluteEvent {
@@ -110,9 +109,6 @@ class IPointer : public IHID {
bool connected = false; // means connected to the cursor
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;
};

View File

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

View File

@@ -14,11 +14,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
if (!mouse)
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) {
mouse.reset();
events.destroy.emit();
@@ -32,7 +27,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.delta = E.delta,
.unaccel = E.unaccel,
.mouse = true,
.device = self.lock(),
});
});

View File

@@ -11,7 +11,7 @@ SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resour
}
CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : pointer(resource) {
if UNLIKELY (!resource->good())
if (!resource->good())
return;
listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) {
@@ -19,11 +19,7 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
events.destroy.emit();
});
listeners.motion = pointer->events.move.registerListener([this](std::any d) {
auto E = std::any_cast<SMotionEvent>(d);
E.device = self.lock();
pointerEvents.motion.emit(E);
});
listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(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
auto E = std::any_cast<SMotionAbsoluteEvent>(d);

View File

@@ -11,18 +11,11 @@
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../protocols/ToplevelExport.hpp"
#include "../protocols/types/ContentType.hpp"
#include "../xwayland/XSurface.hpp"
#include "managers/AnimationManager.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>
using namespace Hyprutils::String;
using namespace Hyprutils::Animation;
// ------------------------------------------------------------ //
// __ _______ _ _ _____ ______ _______ //
@@ -34,17 +27,15 @@ using namespace Hyprutils::Animation;
// //
// ------------------------------------------------------------ //
static void setVector2DAnimToMove(WP<CBaseAnimatedVariable> pav) {
const auto PAV = pav.lock();
if (!PAV)
return;
void setAnimToMove(void* data) {
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
CAnimatedVariable<Vector2D>* animvar = dynamic_cast<CAnimatedVariable<Vector2D>*>(PAV.get());
animvar->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data;
const auto PHLWINDOW = animvar->m_Context.pWindow.lock();
if (PHLWINDOW)
PHLWINDOW->m_bAnimatingIn = false;
animvar->setConfig(PANIMCFG);
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) {
@@ -130,13 +121,22 @@ void Events::listener_mapWindow(void* owner, void* data) {
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
PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
std::optional<eFullscreenMode> requestedInternalFSMode, requestedClientFSMode;
std::optional<SFullscreenState> requestedFSState;
if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen))
requestedClientFSMode = FSMODE_FULLSCREEN;
MONITORID requestedFSMonitor = PWINDOW->m_iWantsInitialFullscreenMonitor;
for (auto const& r : PWINDOW->m_vMatchedRules) {
switch (r->ruleType) {
@@ -171,10 +171,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
PMONITOR = PMONITORFROMID;
}
PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
PWORKSPACE = PWINDOW->m_pWorkspace;
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()); }
break;
}
@@ -182,10 +180,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
// check if it isnt unset
const auto WORKSPACERQ = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
if (WORKSPACERQ == "unset")
if (WORKSPACERQ == "unset") {
requestedWorkspace = "";
else
} else {
requestedWorkspace = WORKSPACERQ;
}
const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ;
@@ -193,7 +192,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
requestedWorkspace = "";
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r->szValue);
requestedFSMonitor = MONITOR_INVALID;
break;
}
case CWindowRule::RULE_FLOAT: {
@@ -235,8 +233,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
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]);
}
@@ -307,13 +303,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
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;
}
@@ -349,51 +338,20 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!workspaceSilent) {
if (pWorkspace->m_bIsSpecialWorkspace)
pWorkspace->m_pMonitor->setSpecialWorkspace(pWorkspace);
else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID && !PWINDOW->m_bNoInitialFocus)
else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID)
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
PMONITOR = g_pCompositor->m_pLastMonitor.lock();
}
requestedFSMonitor = MONITOR_INVALID;
} else
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();
// Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped.
const auto SWALLOWER = PWINDOW->getSwallower();
PWINDOW->m_pSwallowed = SWALLOWER;
if (PWINDOW->m_pSwallowed)
PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = true;
if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
@@ -420,10 +378,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto MAXSIZE = PWINDOW->requestedMaxSize();
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) :
stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize->goal().x, PMONITOR->vecSize.x);
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) :
stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize->goal().y, PMONITOR->vecSize.y);
stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y);
Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
@@ -460,7 +418,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
(!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;
posX -= PWINDOW->m_vRealSize.goal().x;
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
@@ -472,7 +430,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
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);
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
}
}
@@ -483,7 +441,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
(!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
if (subtractWindow)
posY -= PWINDOW->m_vRealSize->goal().y;
posY -= PWINDOW->m_vRealSize.goal().y;
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
@@ -495,7 +453,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
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);
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
}
}
@@ -503,15 +461,15 @@ void Events::listener_mapWindow(void* owner, void* data) {
int borderSize = PWINDOW->getRealBorderSize();
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),
(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);
*PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r->szRule, r->szValue); }
@@ -523,7 +481,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
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;
}
@@ -533,7 +491,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// set the pseudo size to the GOAL of our current size
// 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);
} else {
@@ -566,7 +524,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
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();
@@ -596,11 +554,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
(!PWINDOW->isX11OverrideRedirect() || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) &&
!g_pInputManager->isConstrained()) {
g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PACTIVEALPHA);
PWINDOW->m_fDimPercent->setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH);
} else {
PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PINACTIVEALPHA);
PWINDOW->m_fDimPercent->setValueAndWarp(0);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(0);
}
if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
@@ -613,8 +571,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow)
g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE);
PWINDOW->m_vRealPosition->warp();
PWINDOW->m_vRealSize->warp();
PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealSize.warp();
if (requestedFSState.has_value()) {
PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE);
g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value());
@@ -649,7 +607,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
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;
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, PWINDOW->m_szClass, PWINDOW->m_szTitle)});
@@ -662,17 +620,17 @@ void Events::listener_mapWindow(void* owner, void* data) {
// do animations
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
PWINDOW->m_fAlpha->setValueAndWarp(0.f);
*PWINDOW->m_fAlpha = 1.f;
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
PWINDOW->m_fAlpha = 1.f;
PWINDOW->m_vRealPosition->setCallbackOnEnd(setVector2DAnimToMove);
PWINDOW->m_vRealSize->setCallbackOnEnd(setVector2DAnimToMove);
PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove);
PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove);
// recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
// avoid this window being visible
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->setPreferredTransformForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->transform);
@@ -708,40 +666,30 @@ void Events::listener_unmapWindow(void* owner, void* data) {
const auto PMONITOR = PWINDOW->m_pMonitor.lock();
if (PMONITOR) {
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition->value() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize->value();
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value();
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
}
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", 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);
if (PWINDOW->isFullscreen())
g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE);
// Allow the renderer to catch the last frame.
g_pHyprRenderer->makeWindowSnapshot(PWINDOW);
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
// swallowing
if (valid(PWINDOW->m_pSwallowed)) {
if (PWINDOW->m_pSwallowed->m_bCurrentlySwallowed) {
PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = false;
PWINDOW->m_pSwallowed->setHidden(false);
PWINDOW->m_pSwallowed->setHidden(false);
if (PWINDOW->m_sGroupData.pNextWindow.lock())
PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false.
if (PWINDOW->m_sGroupData.pNextWindow.lock())
PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false.
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock());
}
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock());
PWINDOW->m_pSwallowed->m_bGroupSwallowed = false;
PWINDOW->m_pSwallowed.reset();
@@ -809,12 +757,12 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pCompositor->addToFadingOutSafe(PWINDOW);
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
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
// anims
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true);
*PWINDOW->m_fAlpha = 0.f;
PWINDOW->m_fAlpha = 0.f;
// recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus();
@@ -864,7 +812,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
g_pSeatManager->isPointerFrameSkipped = false;
g_pSeatManager->isPointerFrameCommit = false;
} else
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition->goal().x, PWINDOW->m_vRealPosition->goal().y,
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
if (g_pSeatManager->isPointerFrameSkipped) {
@@ -880,7 +828,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
// 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) {
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.accumulateBufferDamage()};
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) {
@@ -924,6 +872,15 @@ void Events::listener_destroyWindow(void* owner, void* data) {
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) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
@@ -955,8 +912,8 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
if (!PWINDOW->m_bIsMapped || !PWINDOW->m_pXWaylandSurface || !PWINDOW->m_pXWaylandSurface->overrideRedirect)
return;
const auto POS = PWINDOW->m_vRealPosition->goal();
const auto SIZ = PWINDOW->m_vRealSize->goal();
const auto POS = PWINDOW->m_vRealPosition.goal();
const auto SIZ = PWINDOW->m_vRealSize.goal();
if (PWINDOW->m_pXWaylandSurface->geometry.size() > Vector2D{1, 1})
PWINDOW->setHidden(false);
@@ -964,7 +921,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->setHidden(true);
if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) {
PWINDOW->sendWindowSize(true);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
g_pHyprRenderer->damageWindow(PWINDOW);
return;
}
@@ -978,27 +935,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());
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)
PWINDOW->m_vRealSize->setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size());
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size());
if (*PXWLFORCESCALEZERO) {
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_vSize = PWINDOW->m_vRealSize->goal();
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.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);
PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition->goal();
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize->goal();
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.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(eAnimatedVarType type) : m_Type(type) {
; // dummy var
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pWindow = pWindow;
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pLayer = pLayer;
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pWorkspace = pWorkspace;
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy 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,18 +1,15 @@
#pragma once
#include <hyprutils/animation/AnimatedVariable.hpp>
#include <functional>
#include <any>
#include <chrono>
#include <type_traits>
#include "math/Math.hpp"
#include "Color.hpp"
#include "../defines.hpp"
#include "../debug/Log.hpp"
#include "../desktop/DesktopTypes.hpp"
enum eAVarDamagePolicy : int8_t {
AVARDAMAGE_NONE = -1,
AVARDAMAGE_ENTIRE = 0,
AVARDAMAGE_BORDER,
AVARDAMAGE_SHADOW
};
enum eAnimatedVarType : int8_t {
AVARTYPE_INVALID = -1,
AVARTYPE_FLOAT,
@@ -45,6 +42,20 @@ struct STypeToAnimatedVarType_t<CHyprColor> {
template <class T>
inline constexpr eAnimatedVarType typeToeAnimatedVarType = STypeToAnimatedVarType_t<T>::value;
enum eAVarDamagePolicy : int8_t {
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
template <class T, class... U>
concept OneOf = (... or std::same_as<T, U>);
@@ -55,19 +66,247 @@ concept OneOf = (... or std::same_as<T, U>);
template <class T>
concept Animable = OneOf<T, Vector2D, float, CHyprColor>;
struct SAnimationContext {
PHLWINDOWREF pWindow;
PHLWORKSPACEREF pWorkspace;
PHLLSREF pLayer;
class CBaseAnimatedVariable {
public:
CBaseAnimatedVariable(eAnimatedVarType type);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy);
void create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy 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
bool isBeingAnimated() const {
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 = std::move(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 = std::move(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 = std::move(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;
eAVarDamagePolicy m_eDamagePolicy = AVARDAMAGE_NONE;
eAnimatedVarType 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>
using CAnimatedVariable = Hyprutils::Animation::CGenericAnimatedVariable<VarType, SAnimationContext>;
class CAnimatedVariable : public CBaseAnimatedVariable {
public:
CAnimatedVariable() : CBaseAnimatedVariable(typeToeAnimatedVarType<VarType>) {
;
} // dummy var
template <Animable VarType>
using PHLANIMVAR = SP<CAnimatedVariable<VarType>>;
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) {
create(pAnimConfig, pWindow, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) {
create(pAnimConfig, pLayer, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) {
create(pAnimConfig, pWorkspace, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) {
create(pAnimConfig, policy);
m_Value = value;
m_Goal = value;
}
template <Animable VarType>
using PHLANIMVARREF = WP<CAnimatedVariable<VarType>>;
using CBaseAnimatedVariable::create;
CAnimatedVariable(const CAnimatedVariable&) = delete;
CAnimatedVariable(CAnimatedVariable&&) = delete;
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
~CAnimatedVariable() = default;
// gets the current vector value (real time)
const VarType& value() const {
return m_Value;
}
// gets the goal vector value
const VarType& goal() const {
return m_Goal;
}
CAnimatedVariable& operator=(const VarType& v) {
if (v == m_Goal)
return *this;
m_Goal = v;
animationBegin = std::chrono::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;
};

View File

@@ -0,0 +1,90 @@
#include "BezierCurve.hpp"
#include "../debug/Log.hpp"
#include "../macros.hpp"
#include <chrono>
#include <algorithm>
void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
const auto BEGIN = std::chrono::high_resolution_clock::now();
// Avoid reallocations by reserving enough memory upfront
m_vPoints.resize(pVec->size() + 2);
m_vPoints[0] = Vector2D(0, 0); // Start point
size_t index = 1; // Start after the first element
for (const auto& vec : *pVec) {
if (index < m_vPoints.size() - 1) { // Bounds check to ensure safety
m_vPoints[index] = vec;
++index;
}
}
m_vPoints.back() = Vector2D(1, 1); // End point
RASSERT(m_vPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_vPoints.size());
// bake BAKEDPOINTS points for faster lookups
// T -> X ( / BAKEDPOINTS )
for (int i = 0; i < BAKEDPOINTS; ++i) {
float const t = (i + 1) / (float)BAKEDPOINTS;
m_aPointsBaked[i] = Vector2D(getXForT(t), getYForT(t));
}
const auto ELAPSEDUS = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGIN).count() / 1000.f;
const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f;
const auto BEGINCALC = std::chrono::high_resolution_clock::now();
for (int j = 1; j < 10; ++j) {
float i = j / 10.0f;
getYForPoint(i);
}
const auto ELAPSEDCALCAVG = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f;
Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE,
ELAPSEDUS, ELAPSEDCALCAVG);
}
float CBezierCurve::getXForT(float const& t) const {
float t2 = t * t;
float t3 = t2 * t;
return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].x + 3 * t2 * (1 - t) * m_vPoints[2].x + t3 * m_vPoints[3].x;
}
float CBezierCurve::getYForT(float const& t) const {
float t2 = t * t;
float t3 = t2 * t;
return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].y + 3 * t2 * (1 - t) * m_vPoints[2].y + t3 * m_vPoints[3].y;
}
// Todo: this probably can be done better and faster
float CBezierCurve::getYForPoint(float const& x) const {
if (x >= 1.f)
return 1.f;
if (x <= 0.f)
return 0.f;
int index = 0;
bool below = true;
for (int step = (BAKEDPOINTS + 1) / 2; step > 0; step /= 2) {
if (below)
index += step;
else
index -= step;
below = m_aPointsBaked[index].x < x;
}
int lowerIndex = index - (!below || index == BAKEDPOINTS - 1);
// in the name of performance i shall make a hack
const auto LOWERPOINT = &m_aPointsBaked[lowerIndex];
const auto UPPERPOINT = &m_aPointsBaked[lowerIndex + 1];
const auto PERCINDELTA = (x - LOWERPOINT->x) / (UPPERPOINT->x - LOWERPOINT->x);
if (std::isnan(PERCINDELTA) || std::isinf(PERCINDELTA)) // can sometimes happen for VERY small x
return 0.f;
return LOWERPOINT->y + (UPPERPOINT->y - LOWERPOINT->y) * PERCINDELTA;
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <vector>
#include <array>
#include <vector>
#include "math/Math.hpp"
constexpr int BAKEDPOINTS = 255;
constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS;
// an implementation of a cubic bezier curve
// might do better later
class CBezierCurve {
public:
// sets up the bezier curve.
// this EXCLUDES the 0,0 and 1,1 points,
void setup(std::vector<Vector2D>* points);
float getYForT(float const& t) const;
float getXForT(float const& t) const;
float getYForPoint(float const& x) const;
private:
// this INCLUDES the 0,0 and 1,1 points.
std::vector<Vector2D> m_vPoints;
std::array<Vector2D, BAKEDPOINTS> m_aPointsBaked;
};

View File

@@ -43,7 +43,3 @@ Hyprgraphics::CColor::SHSL CHyprColor::asHSL() const {
CHyprColor CHyprColor::stripA() const {
return {r, g, b, 1.F};
}
CHyprColor CHyprColor::modifyA(float newa) const {
return {r, g, b, newa};
}

View File

@@ -2,6 +2,7 @@
#include <cstdint>
#include <hyprgraphics/color/Color.hpp>
#include "../debug/Log.hpp"
#include "../macros.hpp"
class CHyprColor {
@@ -17,7 +18,6 @@ class CHyprColor {
Hyprgraphics::CColor::SOkLab asOkLab() const;
Hyprgraphics::CColor::SHSL asHSL() const;
CHyprColor stripA() const;
CHyprColor modifyA(float newa) const;
//
bool operator==(const CHyprColor& c2) const {
@@ -45,18 +45,3 @@ class CHyprColor {
private:
Hyprgraphics::CColor::SOkLab okLab; // cache for the OkLab representation
};
//NOLINTNEXTLINE
namespace Colors {
static const CHyprColor WHITE = CHyprColor(1.F, 1.F, 1.F, 1.F);
static const CHyprColor GREEN = CHyprColor(0.F, 1.F, 0.F, 1.F);
static const CHyprColor BLUE = CHyprColor(0.F, 0.F, 1.F, 1.F);
static const CHyprColor RED = CHyprColor(1.F, 0.F, 0.F, 1.F);
static const CHyprColor ORANGE = CHyprColor(1.F, 0.5F, 0.F, 1.F);
static const CHyprColor YELLOW = CHyprColor(1.F, 1.F, 0.F, 1.F);
static const CHyprColor MAGENTA = CHyprColor(1.F, 0.F, 1.F, 1.F);
static const CHyprColor PURPLE = CHyprColor(0.5F, 0.F, 0.5F, 1.F);
static const CHyprColor LIME = CHyprColor(0.5F, 1.F, 0.1F, 1.F);
static const CHyprColor LIGHT_BLUE = CHyprColor(0.1F, 1.F, 1.F, 1.F);
static const CHyprColor BLACK = CHyprColor(0.F, 0.F, 0.F, 1.F);
};

View File

@@ -3,9 +3,6 @@
#include <algorithm>
#include "../Compositor.hpp"
#include "../managers/TokenManager.hpp"
#include "Monitor.hpp"
#include "../config/ConfigManager.hpp"
#include "fs/FsUtils.hpp"
#include <optional>
#include <cstring>
#include <cmath>
@@ -49,6 +46,97 @@ using namespace Hyprutils::OS;
#endif
#endif
static const float transforms[][9] = {
{
1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
0.0f,
1.0f,
0.0f,
-1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
-1.0f,
0.0f,
0.0f,
0.0f,
-1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
0.0f,
-1.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
-1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
0.0f,
1.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
1.0f,
0.0f,
0.0f,
0.0f,
-1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
0.0f,
-1.0f,
0.0f,
-1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
};
std::string absolutePath(const std::string& rawpath, const std::string& currentPath) {
auto value = rawpath;
@@ -73,6 +161,26 @@ std::string absolutePath(const std::string& rawpath, const std::string& currentP
return value;
}
void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, const std::string& ownerString) {
ASSERT(pSignal);
ASSERT(pListener);
wl_signal_add(pSignal, pListener);
Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString);
}
void removeWLSignal(wl_listener* pListener) {
wl_list_remove(&pListener->link);
wl_list_init(&pListener->link);
Debug::log(LOG, "Removed listener {:x}", (uintptr_t)pListener);
}
void handleNoop(struct wl_listener* listener, void* data) {
// Do nothing
}
std::string escapeJSONStrings(const std::string& str) {
std::ostringstream oss;
for (auto const& c : str) {
@@ -170,7 +278,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
if (!valid(PWORKSPACE))
return {WORKSPACE_INVALID};
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->getPrevWorkspaceIDName().id);
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.id);
if (!PLASTWORKSPACE)
return {WORKSPACE_INVALID};
@@ -520,7 +628,7 @@ void logSystemInfo() {
}
} catch (...) { GPUINFO = "error"; }
#else
const std::string GPUINFO = execAndGet("lspci -vnn | grep -E '(VGA|Display|3D)'");
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif
Debug::log(LOG, "GPU information:\n{}\n", GPUINFO);
@@ -531,7 +639,7 @@ void logSystemInfo() {
// log etc
Debug::log(LOG, "os-release:");
Debug::log(NONE, "{}", NFsUtils::readFileAsString("/etc/os-release").value_or("error"));
Debug::log(NONE, "{}", execAndGet("cat /etc/os-release"));
}
int64_t getPPIDof(int64_t pid) {
@@ -745,48 +853,50 @@ bool envEnabled(const std::string& env) {
return std::string(ENV) == "1";
}
std::pair<CFileDescriptor, std::string> openExclusiveShm() {
std::pair<int, std::string> openExclusiveShm() {
// Only absolute paths can be shared across different shm_open() calls
std::string name = "/" + g_pTokenManager->getRandomUUID();
for (size_t i = 0; i < 69; ++i) {
CFileDescriptor fd{shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)};
if (fd.isValid())
return {std::move(fd), name};
int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd >= 0)
return {fd, name};
}
return {{}, ""};
return {-1, ""};
}
CFileDescriptor allocateSHMFile(size_t len) {
int allocateSHMFile(size_t len) {
auto [fd, name] = openExclusiveShm();
if (!fd.isValid())
return {};
if (fd < 0)
return -1;
shm_unlink(name.c_str());
int ret;
do {
ret = ftruncate(fd.get(), len);
ret = ftruncate(fd, len);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
return {};
close(fd);
return -1;
}
return std::move(fd);
return fd;
}
bool allocateSHMFilePair(size_t size, CFileDescriptor& rw_fd_ptr, CFileDescriptor& ro_fd_ptr) {
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) {
auto [fd, name] = openExclusiveShm();
if (!fd.isValid()) {
if (fd < 0) {
return false;
}
// CLOEXEC is guaranteed to be set by shm_open
CFileDescriptor ro_fd{shm_open(name.c_str(), O_RDONLY, 0)};
if (!ro_fd.isValid()) {
int ro_fd = shm_open(name.c_str(), O_RDONLY, 0);
if (ro_fd < 0) {
shm_unlink(name.c_str());
close(fd);
return false;
}
@@ -794,20 +904,24 @@ bool allocateSHMFilePair(size_t size, CFileDescriptor& rw_fd_ptr, CFileDescripto
// Make sure the file cannot be re-opened in read-write mode (e.g. via
// "/proc/self/fd/" on Linux)
if (fchmod(fd.get(), 0) != 0) {
if (fchmod(fd, 0) != 0) {
close(fd);
close(ro_fd);
return false;
}
int ret;
do {
ret = ftruncate(fd.get(), size);
ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
close(fd);
close(ro_fd);
return false;
}
rw_fd_ptr = std::move(fd);
ro_fd_ptr = std::move(ro_fd);
*rw_fd_ptr = fd;
*ro_fd_ptr = ro_fd;
return true;
}
@@ -817,3 +931,30 @@ float stringToPercentage(const std::string& VALUE, const float REL) {
else
return std::stof(VALUE);
}
bool executableExistsInPath(const std::string& exe) {
if (!getenv("PATH"))
return false;
static CVarList paths(getenv("PATH"), 0, ':', true);
for (auto& p : paths) {
std::string path = p + std::string{"/"} + exe;
std::error_code ec;
if (!std::filesystem::exists(path, ec) || ec)
continue;
if (!std::filesystem::is_regular_file(path, ec) || ec)
continue;
auto stat = std::filesystem::status(path, ec);
if (ec)
continue;
auto perms = stat.permissions();
return std::filesystem::perms::none != (perms & std::filesystem::perms::others_exec);
}
return false;
}

View File

@@ -1,11 +1,12 @@
#pragma once
#include <optional>
#include <string>
#include <wayland-server.h>
#include "math/Math.hpp"
#include <vector>
#include <format>
#include <expected>
#include <hyprutils/os/FileDescriptor.hpp>
#include "../SharedDefs.hpp"
#include "../macros.hpp"
@@ -20,6 +21,8 @@ struct SWorkspaceIDName {
};
std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
void removeWLSignal(wl_listener*);
std::string escapeJSONStrings(const std::string& str);
bool isDirection(const std::string&);
bool isDirection(const char&);
@@ -36,9 +39,10 @@ double normalizeAngleRad(double ang);
std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err);
bool envEnabled(const std::string& env);
Hyprutils::OS::CFileDescriptor allocateSHMFile(size_t len);
bool allocateSHMFilePair(size_t size, Hyprutils::OS::CFileDescriptor& rw_fd_ptr, Hyprutils::OS::CFileDescriptor& ro_fd_ptr);
int allocateSHMFile(size_t len);
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr);
float stringToPercentage(const std::string& VALUE, const float REL);
bool executableExistsInPath(const std::string& exe);
template <typename... Args>
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {

View File

@@ -1,8 +1,6 @@
#include "Monitor.hpp"
#include "MiscFunctions.hpp"
#include "../macros.hpp"
#include "math/Math.hpp"
#include "../protocols/ColorManagement.hpp"
#include "sync/SyncReleaser.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
@@ -18,25 +16,15 @@
#include "../managers/PointerManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../render/Renderer.hpp"
#include "../managers/EventManager.hpp"
#include "../managers/LayoutManager.hpp"
#include "../managers/input/InputManager.hpp"
#include "sync/SyncTimeline.hpp"
#include "../desktop/LayerSurface.hpp"
#include <aquamarine/output/Output.hpp>
#include "debug/Log.hpp"
#include "debug/HyprNotificationOverlay.hpp"
#include <hyprutils/string/String.hpp>
#include <hyprutils/utils/ScopeGuard.hpp>
#include <cstring>
#include <ranges>
using namespace Hyprutils::String;
using namespace Hyprutils::Utils;
using namespace Hyprutils::OS;
using enum NContentType::eContentType;
static int ratHandler(void* data) {
int ratHandler(void* data) {
g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock());
return 1;
@@ -54,10 +42,9 @@ void CMonitor::onConnect(bool noRule) {
EMIT_HOOK_EVENT("preMonitorAdded", self.lock());
CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }};
g_pEventLoopManager->doLater([] { g_pConfigManager->ensurePersistentWorkspacesPresent(); });
if (output->supportsExplicit) {
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
outTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
}
listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); });
@@ -98,7 +85,7 @@ void CMonitor::onConnect(bool noRule) {
return;
Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName);
applyMonitorRule(&activeMonitorRule, true);
g_pHyprRenderer->applyMonitorRule(self.lock(), &activeMonitorRule, true);
return;
}
@@ -112,7 +99,7 @@ void CMonitor::onConnect(bool noRule) {
SMonitorRule rule = activeMonitorRule;
rule.resolution = SIZE;
applyMonitorRule(&rule);
g_pHyprRenderer->applyMonitorRule(self.lock(), &rule);
});
tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
@@ -185,7 +172,7 @@ void CMonitor::onConnect(bool noRule) {
// set mode, also applies
if (!noRule)
applyMonitorRule(&monitorRule, true);
g_pHyprRenderer->applyMonitorRule(self.lock(), &monitorRule, true);
if (!state.commit())
Debug::log(WARN, "state.commit() failed in CMonitor::onCommit");
@@ -374,464 +361,6 @@ void CMonitor::onDisconnect(bool destroy) {
std::erase_if(g_pCompositor->m_vMonitors, [&](PHLMONITOR& el) { return el.get() == this; });
}
bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
static auto PDISABLESCALECHECKS = CConfigValue<Hyprlang::INT>("debug:disable_scale_checks");
Debug::log(LOG, "Applying monitor rule for {}", szName);
activeMonitorRule = *pMonitorRule;
if (forceSize.has_value())
activeMonitorRule.resolution = forceSize.value();
const auto RULE = &activeMonitorRule;
// if it's disabled, disable and ignore
if (RULE->disabled) {
if (m_bEnabled)
onDisconnect();
events.modeChanged.emit();
return true;
}
// don't touch VR headsets
if (output->nonDesktop)
return true;
if (!m_bEnabled) {
onConnect(true); // enable it.
Debug::log(LOG, "Monitor {} is disabled but is requested to be enabled", szName);
force = true;
}
// Check if the rule isn't already applied
// TODO: clean this up lol
if (!force && DELTALESSTHAN(vecPixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(vecPixelSize.y, RULE->resolution.y, 1) &&
DELTALESSTHAN(refreshRate, RULE->refreshRate, 1) && setScale == RULE->scale &&
((DELTALESSTHAN(vecPosition.x, RULE->offset.x, 1) && DELTALESSTHAN(vecPosition.y, RULE->offset.y, 1)) || RULE->offset == Vector2D(-INT32_MAX, -INT32_MAX)) &&
transform == RULE->transform && RULE->enable10bit == enabled10bit && RULE->cmType == cmType && RULE->sdrSaturation == sdrSaturation &&
RULE->sdrBrightness == sdrBrightness && !std::memcmp(&customDrmMode, &RULE->drmMode, sizeof(customDrmMode))) {
Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", szName);
setMirror(RULE->mirrorOf);
return true;
}
bool autoScale = false;
if (RULE->scale > 0.1) {
scale = RULE->scale;
} else {
autoScale = true;
const auto DEFAULTSCALE = getDefaultScale();
scale = DEFAULTSCALE;
}
setScale = scale;
transform = RULE->transform;
// accumulate requested modes in reverse order (cause inesrting at front is inefficient)
std::vector<SP<Aquamarine::SOutputMode>> requestedModes;
std::string requestedStr = "unknown";
// use sortFunc, add best 3 to requestedModes in reverse, since we test in reverse
auto addBest3Modes = [&](auto const& sortFunc) {
auto sortedModes = output->modes;
std::ranges::sort(sortedModes, sortFunc);
if (sortedModes.size() > 3)
sortedModes.erase(sortedModes.begin() + 3, sortedModes.end());
requestedModes.insert(requestedModes.end(), sortedModes.rbegin(), sortedModes.rend());
};
// last fallback is always preferred mode
if (!output->preferredMode())
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", output->name);
else
requestedModes.push_back(output->preferredMode());
if (RULE->resolution == Vector2D()) {
requestedStr = "preferred";
// fallback to first 3 modes if preferred fails/doesn't exist
requestedModes = output->modes;
if (requestedModes.size() > 3)
requestedModes.erase(requestedModes.begin() + 3, requestedModes.end());
std::ranges::reverse(requestedModes.begin(), requestedModes.end());
if (output->preferredMode())
requestedModes.push_back(output->preferredMode());
} else if (RULE->resolution == Vector2D(-1, -1)) {
requestedStr = "highrr";
// sort prioritizing refresh rate 1st and resolution 2nd, then add best 3
addBest3Modes([](auto const& a, auto const& b) {
if (std::round(a->refreshRate) > std::round(b->refreshRate))
return true;
else if (DELTALESSTHAN((float)a->refreshRate, (float)b->refreshRate, 1.F) && a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y)
return true;
return false;
});
} else if (RULE->resolution == Vector2D(-1, -2)) {
requestedStr = "highres";
// sort prioritizing resultion 1st and refresh rate 2nd, then add best 3
addBest3Modes([](auto const& a, auto const& b) {
if (a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y)
return true;
else if (DELTALESSTHAN(a->pixelSize.x, b->pixelSize.x, 1) && DELTALESSTHAN(a->pixelSize.y, b->pixelSize.y, 1) &&
std::round(a->refreshRate) > std::round(b->refreshRate))
return true;
return false;
});
} else if (RULE->resolution != Vector2D()) {
// user requested mode
requestedStr = std::format("{:X0}@{:.2f}Hz", RULE->resolution, RULE->refreshRate);
// sort by closeness to requested, then add best 3
addBest3Modes([&](auto const& a, auto const& b) {
if (abs(a->pixelSize.x - RULE->resolution.x) < abs(b->pixelSize.x - RULE->resolution.x))
return true;
if (a->pixelSize.x == b->pixelSize.x && abs(a->pixelSize.y - RULE->resolution.y) < abs(b->pixelSize.y - RULE->resolution.y))
return true;
if (a->pixelSize == b->pixelSize && abs((a->refreshRate / 1000.f) - RULE->refreshRate) < abs((b->refreshRate / 1000.f) - RULE->refreshRate))
return true;
return false;
});
// if the best mode isnt close to requested, then try requested as custom mode first
if (!requestedModes.empty()) {
auto bestMode = requestedModes.back();
if (!DELTALESSTHAN(bestMode->pixelSize.x, RULE->resolution.x, 1) || !DELTALESSTHAN(bestMode->pixelSize.y, RULE->resolution.y, 1) ||
!DELTALESSTHAN(bestMode->refreshRate / 1000.f, RULE->refreshRate, 1))
requestedModes.push_back(makeShared<Aquamarine::SOutputMode>(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = RULE->refreshRate * 1000.f}));
}
// then if requested is custom, try custom mode first
if (RULE->drmMode.type == DRM_MODE_TYPE_USERDEF) {
if (output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM)
Debug::log(ERR, "Tried to set custom modeline on non-DRM output");
else
requestedModes.push_back(makeShared<Aquamarine::SOutputMode>(
Aquamarine::SOutputMode{.pixelSize = {RULE->drmMode.hdisplay, RULE->drmMode.vdisplay}, .refreshRate = RULE->drmMode.vrefresh, .modeInfo = RULE->drmMode}));
}
}
const auto WAS10B = enabled10bit;
const auto OLDRES = vecPixelSize;
bool success = false;
// Needed in case we are switching from a custom modeline to a standard mode
customDrmMode = {};
currentMode = nullptr;
output->state->setFormat(DRM_FORMAT_XRGB8888);
prevDrmFormat = drmFormat;
drmFormat = DRM_FORMAT_XRGB8888;
output->state->resetExplicitFences();
if (Debug::trace) {
Debug::log(TRACE, "Monitor {} requested modes:", szName);
if (requestedModes.empty())
Debug::log(TRACE, "| None");
else {
for (auto const& mode : requestedModes | std::views::reverse) {
Debug::log(TRACE, "| {:X0}@{:.2f}Hz", mode->pixelSize, mode->refreshRate / 1000.f);
}
}
}
for (auto const& mode : requestedModes | std::views::reverse) {
std::string modeStr = std::format("{:X0}@{:.2f}Hz", mode->pixelSize, mode->refreshRate / 1000.f);
if (mode->modeInfo.has_value() && mode->modeInfo->type == DRM_MODE_TYPE_USERDEF) {
output->state->setCustomMode(mode);
if (!state.test()) {
Debug::log(ERR, "Monitor {}: REJECTED custom mode {}!", szName, modeStr);
continue;
}
customDrmMode = mode->modeInfo.value();
} else {
output->state->setMode(mode);
if (!state.test()) {
Debug::log(ERR, "Monitor {}: REJECTED available mode {}!", szName, modeStr);
if (mode->preferred)
Debug::log(ERR, "Monitor {}: REJECTED preferred mode!!!", szName);
continue;
}
customDrmMode = {};
}
refreshRate = mode->refreshRate / 1000.f;
vecSize = mode->pixelSize;
currentMode = mode;
success = true;
if (mode->preferred)
Debug::log(LOG, "Monitor {}: requested {}, using preferred mode {}", szName, requestedStr, modeStr);
else if (mode->modeInfo.has_value() && mode->modeInfo->type == DRM_MODE_TYPE_USERDEF)
Debug::log(LOG, "Monitor {}: requested {}, using custom mode {}", szName, requestedStr, modeStr);
else
Debug::log(LOG, "Monitor {}: requested {}, using available mode {}", szName, requestedStr, modeStr);
break;
}
// try requested as custom mode jic it works
if (!success && RULE->resolution != Vector2D() && RULE->resolution != Vector2D(-1, -1) && RULE->resolution != Vector2D(-1, -2)) {
auto refreshRate = output->getBackend()->type() == Aquamarine::eBackendType::AQ_BACKEND_DRM ? RULE->refreshRate * 1000 : 0;
auto mode = makeShared<Aquamarine::SOutputMode>(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = refreshRate});
std::string modeStr = std::format("{:X0}@{:.2f}Hz", mode->pixelSize, mode->refreshRate / 1000.f);
output->state->setCustomMode(mode);
if (state.test()) {
Debug::log(LOG, "Monitor {}: requested {}, using custom mode {}", szName, requestedStr, modeStr);
refreshRate = mode->refreshRate / 1000.f;
vecSize = mode->pixelSize;
currentMode = mode;
customDrmMode = {};
success = true;
} else
Debug::log(ERR, "Monitor {}: REJECTED custom mode {}!", szName, modeStr);
}
// try any of the modes if none of the above work
if (!success) {
for (auto const& mode : output->modes) {
output->state->setMode(mode);
if (!state.test())
continue;
auto errorMessage =
std::format("Monitor {} failed to set any requested modes, falling back to mode {:X0}@{:.2f}Hz", szName, mode->pixelSize, mode->refreshRate / 1000.f);
Debug::log(WARN, errorMessage);
g_pHyprNotificationOverlay->addNotification(errorMessage, CHyprColor(0xff0000ff), 5000, ICON_WARNING);
refreshRate = mode->refreshRate / 1000.f;
vecSize = mode->pixelSize;
currentMode = mode;
customDrmMode = {};
success = true;
break;
}
}
if (!success) {
Debug::log(ERR, "Monitor {} has NO FALLBACK MODES, and an INVALID one was requested: {:X0}@{:.2f}Hz", szName, RULE->resolution, RULE->refreshRate);
return true;
}
vrrActive = output->state->state().adaptiveSync // disabled here, will be tested in CConfigManager::ensureVRR()
|| createdByUser; // wayland backend doesn't allow for disabling adaptive_sync
vecPixelSize = vecSize;
// clang-format off
static const std::array<std::vector<std::pair<std::string, uint32_t>>, 2> formats{
std::vector<std::pair<std::string, uint32_t>>{ /* 10-bit */
{"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}
},
std::vector<std::pair<std::string, uint32_t>>{ /* 8-bit */
{"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}
}
};
// clang-format on
bool set10bit = false;
for (auto const& fmt : formats[(int)!RULE->enable10bit]) {
output->state->setFormat(fmt.second);
prevDrmFormat = drmFormat;
drmFormat = fmt.second;
if (!state.test()) {
Debug::log(ERR, "output {} failed basic test on format {}", szName, fmt.first);
} else {
Debug::log(LOG, "output {} succeeded basic test on format {}", szName, fmt.first);
if (RULE->enable10bit && fmt.first.contains("101010"))
set10bit = true;
break;
}
}
enabled10bit = set10bit;
auto oldImageDescription = imageDescription;
cmType = RULE->cmType;
switch (cmType) {
case CM_AUTO: cmType = enabled10bit && output->parsedEDID.supportsBT2020 ? CM_WIDE : CM_SRGB; break;
case CM_EDID: cmType = output->parsedEDID.chromaticityCoords.has_value() ? CM_EDID : CM_SRGB; break;
case CM_HDR:
case CM_HDR_EDID:
cmType = output->parsedEDID.supportsBT2020 && output->parsedEDID.hdrMetadata.has_value() && output->parsedEDID.hdrMetadata->supportsPQ ? cmType : CM_SRGB;
break;
default: break;
}
switch (cmType) {
case CM_SRGB: imageDescription = {}; break; // assumes SImageDescirption defaults to sRGB
case CM_WIDE:
imageDescription = {.primariesNameSet = true,
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020)};
break;
case CM_EDID:
imageDescription = {.primariesNameSet = false,
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
.primaries = {
.red = {.x = output->parsedEDID.chromaticityCoords->red.x, .y = output->parsedEDID.chromaticityCoords->red.y},
.green = {.x = output->parsedEDID.chromaticityCoords->green.x, .y = output->parsedEDID.chromaticityCoords->green.y},
.blue = {.x = output->parsedEDID.chromaticityCoords->blue.x, .y = output->parsedEDID.chromaticityCoords->blue.y},
.white = {.x = output->parsedEDID.chromaticityCoords->white.x, .y = output->parsedEDID.chromaticityCoords->white.y},
}};
break;
case CM_HDR:
imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
.primariesNameSet = true,
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
.luminances = {.min = 0, .max = 10000, .reference = 203}};
break;
case CM_HDR_EDID:
imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
.primariesNameSet = false,
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
.primaries = output->parsedEDID.chromaticityCoords.has_value() ?
NColorManagement::SPCPRimaries{
.red = {.x = output->parsedEDID.chromaticityCoords->red.x, .y = output->parsedEDID.chromaticityCoords->red.y},
.green = {.x = output->parsedEDID.chromaticityCoords->green.x, .y = output->parsedEDID.chromaticityCoords->green.y},
.blue = {.x = output->parsedEDID.chromaticityCoords->blue.x, .y = output->parsedEDID.chromaticityCoords->blue.y},
.white = {.x = output->parsedEDID.chromaticityCoords->white.x, .y = output->parsedEDID.chromaticityCoords->white.y},
} :
NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
.luminances = {.min = output->parsedEDID.hdrMetadata->desiredContentMinLuminance,
.max = output->parsedEDID.hdrMetadata->desiredContentMaxLuminance,
.reference = output->parsedEDID.hdrMetadata->desiredMaxFrameAverageLuminance}};
break;
default: UNREACHABLE();
}
if (oldImageDescription != imageDescription)
PROTO::colorManagement->onMonitorImageDescriptionChanged(self);
sdrSaturation = RULE->sdrSaturation;
sdrBrightness = RULE->sdrBrightness;
Vector2D logicalSize = vecPixelSize / scale;
if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) {
// invalid scale, will produce fractional pixels.
// find the nearest valid.
float searchScale = std::round(scale * 120.0);
bool found = false;
double scaleZero = searchScale / 120.0;
Vector2D logicalZero = vecPixelSize / scaleZero;
if (logicalZero == logicalZero.round())
scale = scaleZero;
else {
for (size_t i = 1; i < 90; ++i) {
double scaleUp = (searchScale + i) / 120.0;
double scaleDown = (searchScale - i) / 120.0;
Vector2D logicalUp = vecPixelSize / scaleUp;
Vector2D logicalDown = vecPixelSize / scaleDown;
if (logicalUp == logicalUp.round()) {
found = true;
searchScale = scaleUp;
break;
}
if (logicalDown == logicalDown.round()) {
found = true;
searchScale = scaleDown;
break;
}
}
if (!found) {
if (autoScale)
scale = std::round(scaleZero);
else {
Debug::log(ERR, "Invalid scale passed to monitor, {} failed to find a clean divisor", scale);
g_pConfigManager->addParseError("Invalid scale passed to monitor " + szName + ", failed to find a clean divisor");
scale = getDefaultScale();
}
} else {
if (!autoScale) {
Debug::log(ERR, "Invalid scale passed to monitor, {} found suggestion {}", scale, searchScale);
g_pConfigManager->addParseError(
std::format("Invalid scale passed to monitor {}, failed to find a clean divisor. Suggested nearest scale: {:5f}", szName, searchScale));
scale = getDefaultScale();
} else
scale = searchScale;
}
}
}
output->scheduleFrame();
if (!state.commit())
Debug::log(ERR, "Couldn't commit output named {}", output->name);
Vector2D xfmd = transform % 2 == 1 ? Vector2D{vecPixelSize.y, vecPixelSize.x} : vecPixelSize;
vecSize = (xfmd / scale).round();
vecTransformedSize = xfmd;
if (createdByUser) {
CBox transformedBox = {0, 0, vecTransformedSize.x, vecTransformedSize.y};
transformedBox.transform(wlTransformToHyprutils(invertTransform(transform)), vecTransformedSize.x, vecTransformedSize.y);
vecPixelSize = Vector2D(transformedBox.width, transformedBox.height);
}
updateMatrix();
if (WAS10B != enabled10bit || OLDRES != vecPixelSize)
g_pHyprOpenGL->destroyMonitorResources(self.lock());
g_pCompositor->arrangeMonitors();
damage.setSize(vecTransformedSize);
// Set scale for all surfaces on this monitor, needed for some clients
// but not on unsafe state to avoid crashes
if (!g_pCompositor->m_bUnsafeState) {
for (auto const& w : g_pCompositor->m_vWindows) {
w->updateSurfaceScaleTransformDetails();
}
}
// updato us
g_pHyprRenderer->arrangeLayersForMonitor(ID);
// reload to fix mirrors
g_pConfigManager->m_bWantsMonitorReload = true;
Debug::log(LOG, "Monitor {} data dump: res {:X}@{:.2f}Hz, scale {:.2f}, transform {}, pos {:X}, 10b {}", szName, vecPixelSize, refreshRate, scale, (int)transform, vecPosition,
(int)enabled10bit);
EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr);
events.modeChanged.emit();
return true;
}
void CMonitor::addDamage(const pixman_region32_t* rg) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) {
@@ -841,18 +370,18 @@ void CMonitor::addDamage(const pixman_region32_t* rg) {
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
}
void CMonitor::addDamage(const CRegion& rg) {
addDamage(const_cast<CRegion*>(&rg)->pixman());
void CMonitor::addDamage(const CRegion* rg) {
addDamage(const_cast<CRegion*>(rg)->pixman());
}
void CMonitor::addDamage(const CBox& box) {
void CMonitor::addDamage(const CBox* box) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) {
damage.damageEntire();
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
}
if (damage.damage(box))
if (damage.damage(*box))
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
}
@@ -861,8 +390,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate");
// skip scheduling extra frames for fullsreen apps with vrr
const bool shouldSkip = activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN &&
(*PNOBREAK == 1 || (*PNOBREAK == 2 && activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && output->state->state().adaptiveSync;
bool shouldSkip =
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
// keep requested minimum refresh rate
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) {
@@ -881,9 +410,9 @@ bool CMonitor::isMirror() {
bool CMonitor::matchesStaticSelector(const std::string& selector) const {
if (selector.starts_with("desc:")) {
// match by description
const auto DESCRIPTIONSELECTOR = trim(selector.substr(5));
const auto DESCRIPTIONSELECTOR = selector.substr(5);
return szDescription.starts_with(DESCRIPTIONSELECTOR) || szShortDescription.starts_with(DESCRIPTIONSELECTOR);
return DESCRIPTIONSELECTOR == szShortDescription || DESCRIPTIONSELECTOR == szDescription;
} else {
// match by selector
return szName == selector;
@@ -1001,7 +530,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
setupDefaultWS(RULE);
applyMonitorRule((SMonitorRule*)&RULE, true); // will apply the offset and stuff
g_pHyprRenderer->applyMonitorRule(self.lock(), (SMonitorRule*)&RULE, true); // will apply the offset and stuff
} else {
PHLMONITOR BACKUPMON = nullptr;
for (auto const& m : g_pCompositor->m_vMonitors) {
@@ -1080,17 +609,15 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
if (pWorkspace == activeWorkspace)
return;
const auto POLDWORKSPACE = activeWorkspace;
if (POLDWORKSPACE)
POLDWORKSPACE->m_bVisible = false;
pWorkspace->m_bVisible = true;
const auto POLDWORKSPACE = activeWorkspace;
POLDWORKSPACE->m_bVisible = false;
pWorkspace->m_bVisible = true;
activeWorkspace = pWorkspace;
if (!internal) {
const auto ANIMTOLEFT = POLDWORKSPACE && pWorkspace->m_iID > POLDWORKSPACE->m_iID;
if (POLDWORKSPACE)
POLDWORKSPACE->startAnim(false, ANIMTOLEFT);
const auto ANIMTOLEFT = pWorkspace->m_iID > POLDWORKSPACE->m_iID;
POLDWORKSPACE->startAnim(false, ANIMTOLEFT);
pWorkspace->startAnim(true, ANIMTOLEFT);
// move pinned windows
@@ -1156,7 +683,6 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
activeSpecialWorkspace->m_bVisible = false;
activeSpecialWorkspace->startAnim(false, false);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + szName});
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", ",," + szName});
}
activeSpecialWorkspace.reset();
@@ -1186,13 +712,12 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
bool animate = true;
//close if open elsewhere
const auto PMONITORWORKSPACEOWNER = pWorkspace->m_pMonitor.lock();
if (const auto PMWSOWNER = pWorkspace->m_pMonitor.lock(); PMWSOWNER && PMWSOWNER->activeSpecialWorkspace == pWorkspace) {
PMWSOWNER->activeSpecialWorkspace.reset();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMWSOWNER->ID);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMWSOWNER->szName});
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", ",," + PMWSOWNER->szName});
if (PMONITORWORKSPACEOWNER->activeSpecialWorkspace == pWorkspace) {
PMONITORWORKSPACEOWNER->activeSpecialWorkspace.reset();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMONITORWORKSPACEOWNER->szName});
const auto PACTIVEWORKSPACE = PMWSOWNER->activeWorkspace;
const auto PACTIVEWORKSPACE = PMONITORWORKSPACEOWNER->activeWorkspace;
g_pCompositor->updateFullscreenFadeOnWorkspace(PACTIVEWORKSPACE);
animate = false;
@@ -1215,16 +740,16 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && !w->isX11OverrideRedirect()) {
// if it's floating and the middle isnt on the current mon, move it to the center
const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE);
Vector2D pos = w->m_vRealPosition->goal();
Vector2D pos = w->m_vRealPosition.goal();
if (!VECINRECT(MIDDLE, PMONFROMMIDDLE->vecPosition.x, PMONFROMMIDDLE->vecPosition.y, PMONFROMMIDDLE->vecPosition.x + PMONFROMMIDDLE->vecSize.x,
PMONFROMMIDDLE->vecPosition.y + PMONFROMMIDDLE->vecSize.y)) {
// not on any monitor, center
pos = middle() / 2.f - w->m_vRealSize->goal() / 2.f;
pos = middle() / 2.f - w->m_vRealSize.goal() / 2.f;
} else
pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition;
*w->m_vRealPosition = pos;
w->m_vPosition = pos;
w->m_vRealPosition = pos;
w->m_vPosition = pos;
}
}
}
@@ -1239,7 +764,6 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
}
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", std::to_string(pWorkspace->m_iID) + "," + pWorkspace->m_szName + "," + szName});
g_pHyprRenderer->damageMonitor(self.lock());
@@ -1258,29 +782,6 @@ void CMonitor::moveTo(const Vector2D& pos) {
vecPosition = pos;
}
SWorkspaceIDName CMonitor::getPrevWorkspaceIDName(const WORKSPACEID id) {
while (!prevWorkSpaces.empty()) {
const int PREVID = prevWorkSpaces.top();
prevWorkSpaces.pop();
if (PREVID == id) // skip same workspace
continue;
// recheck if previous workspace's was moved to another monitor
const auto ws = g_pCompositor->getWorkspaceByID(PREVID);
if (ws && ws->monitorID() == ID)
return {.id = PREVID, .name = ws->m_szName};
}
return {.id = WORKSPACE_INVALID};
}
void CMonitor::addPrevWorkspaceID(const WORKSPACEID id) {
if (!prevWorkSpaces.empty() && prevWorkSpaces.top() == id)
return;
prevWorkSpaces.emplace(id);
}
Vector2D CMonitor::middle() {
return vecPosition + vecSize / 2.f;
}
@@ -1341,43 +842,23 @@ bool CMonitor::attemptDirectScanout() {
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
if (!PSURFACE || !PSURFACE->current.texture || !PSURFACE->current.buffer)
return false;
if (PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform)
if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform)
return false;
// we can't scanout shm buffers.
const auto params = PSURFACE->current.buffer->dmabuf();
if (!params.success || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
if (!PSURFACE->current.buffer || !PSURFACE->current.buffer->buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
return false;
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt, buffer {}", (uintptr_t)PSURFACE.get(), (uintptr_t)PSURFACE->current.buffer.buffer.get());
auto PBUFFER = PSURFACE->current.buffer.buffer;
if (PBUFFER == output->state->state().buffer) {
if (scanoutNeedsCursorUpdate) {
if (!state.test()) {
Debug::log(TRACE, "attemptDirectScanout: failed basic test");
return false;
}
if (!output->commit()) {
Debug::log(TRACE, "attemptDirectScanout: failed to commit cursor update");
lastScanout.reset();
return false;
}
scanoutNeedsCursorUpdate = false;
}
return true;
}
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get());
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats
// and comes from the appropriate device. This may implode on multi-gpu!!
const auto params = PSURFACE->current.buffer->buffer->dmabuf();
// scanout buffer isn't dmabuf, so no scanout
if (!params.success)
return false;
// entering into scanout, so save monitor format
if (lastScanout.expired())
prevDrmFormat = drmFormat;
@@ -1387,7 +868,7 @@ bool CMonitor::attemptDirectScanout() {
drmFormat = params.format;
}
output->state->setBuffer(PBUFFER);
output->state->setBuffer(PSURFACE->current.buffer->buffer.lock());
output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
@@ -1396,28 +877,34 @@ bool CMonitor::attemptDirectScanout() {
return false;
}
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings();
// wait for the explicit fence if present, and if kms explicit is allowed
bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled;
int explicitWaitFD = -1;
if (DOEXPLICIT) {
explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint);
if (explicitWaitFD < 0)
Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd");
}
DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0;
auto cleanup = CScopeGuard([explicitWaitFD, this]() {
output->state->resetExplicitFences();
if (explicitWaitFD >= 0)
close(explicitWaitFD);
});
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
PSURFACE->presentFeedback(&now, self.lock());
output->state->addDamage(PSURFACE->current.accumulateBufferDamage());
output->state->addDamage(CBox{{}, vecPixelSize});
output->state->resetExplicitFences();
auto cleanup = CScopeGuard([this]() { output->state->resetExplicitFences(); });
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(output);
bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->current.buffer && PSURFACE->current.acquire && explicitOptions.explicitKMSEnabled;
if (DOEXPLICIT) {
// wait for surface's explicit fence if present
inFence = PSURFACE->current.acquire.exportAsFD();
if (inFence.isValid()) {
Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", inFence.get());
output->state->setExplicitInFence(inFence.get());
} else {
Debug::log(TRACE, "attemptDirectScanout: failed to acquire an sync file fd for aq IN_FENCE");
DOEXPLICIT = false;
}
Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD);
output->state->setExplicitInFence(explicitWaitFD);
}
bool ok = output->commit();
@@ -1429,27 +916,29 @@ bool CMonitor::attemptDirectScanout() {
ok = output->commit();
}
if (!ok) {
if (ok) {
if (lastScanout.expired()) {
lastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
}
// delay explicit sync feedback until kms release of the buffer
if (DOEXPLICIT) {
Debug::log(TRACE, "attemptDirectScanout: Delaying explicit sync release feedback until kms release");
PSURFACE->current.buffer->releaser->drop();
PSURFACE->current.buffer->buffer->hlEvents.backendRelease2 = PSURFACE->current.buffer->buffer->events.backendRelease.registerListener([PSURFACE](std::any d) {
const bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.releaseTimeline && PSURFACE->syncobj->current.releaseTimeline->timeline;
if (DOEXPLICIT)
PSURFACE->syncobj->current.releaseTimeline->timeline->signal(PSURFACE->syncobj->current.releasePoint);
});
}
} else {
Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface");
lastScanout.reset();
return false;
}
if (lastScanout.expired()) {
lastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
}
scanoutNeedsCursorUpdate = false;
if (!PBUFFER->lockedByBackend || PBUFFER->hlEvents.backendRelease)
return true;
// lock buffer while DRM/KMS is using it, then release it when page flip happens since DRM/KMS should be done by then
// btw buffer's syncReleaser will take care of signaling release point, so we don't do that here
PBUFFER->lock();
PBUFFER->onBackendRelease([PBUFFER]() { PBUFFER->unlock(); });
return true;
}
@@ -1521,25 +1010,11 @@ void CMonitor::onMonitorFrame() {
g_pHyprRenderer->renderMonitor(self.lock());
}
void CMonitor::onCursorMovedOnMonitor() {
if (!tearingState.activelyTearing || !solitaryClient || !g_pHyprRenderer->shouldRenderCursor())
return;
// submit a frame immediately. This will only update the cursor pos.
// output->state->setBuffer(output->state->state().buffer);
// output->state->addDamage(CRegion{});
// output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE);
// if (!output->commit())
// Debug::log(ERR, "onCursorMovedOnMonitor: tearing and wanted to update cursor, failed.");
// FIXME: try to do the above. We currently can't just render because drm is a fucking bitch
// and throws a "nO pRoP cAn Be ChAnGeD dUrInG AsYnC fLiP" on crtc_x
// this will throw too but fix it if we use sw cursors
tearingState.frameScheduledWhileBusy = true;
CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) {
;
}
CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) {
CMonitorState::~CMonitorState() {
;
}

View File

@@ -1,23 +1,19 @@
#pragma once
#include "../defines.hpp"
#include <stack>
#include <vector>
#include "../SharedDefs.hpp"
#include "MiscFunctions.hpp"
#include "WLClasses.hpp"
#include <vector>
#include <array>
#include <memory>
#include <xf86drmMode.h>
#include "Timer.hpp"
#include "math/Math.hpp"
#include <optional>
#include "../protocols/types/ColorManagement.hpp"
#include "signal/Signal.hpp"
#include "DamageRing.hpp"
#include <aquamarine/output/Output.hpp>
#include <aquamarine/allocator/Swapchain.hpp>
#include <hyprutils/os/FileDescriptor.hpp>
// Enum for the different types of auto directions, e.g. auto-left, auto-up.
enum eAutoDirs : uint8_t {
@@ -28,41 +24,28 @@ enum eAutoDirs : uint8_t {
DIR_AUTO_RIGHT
};
enum eCMType : uint8_t {
CM_AUTO = 0, // subject to change. srgb for 8bpc, wide for 10bpc if supported
CM_SRGB, // default, sRGB primaries
CM_WIDE, // wide color gamut, BT2020 primaries
CM_EDID, // primaries from edid (known to be inaccurate)
CM_HDR, // wide color gamut and HDR PQ transfer function
CM_HDR_EDID, // same as CM_HDR with edid primaries
};
struct SMonitorRule {
eAutoDirs autoDir = DIR_AUTO_NONE;
std::string name = "";
Vector2D resolution = Vector2D(1280, 720);
Vector2D offset = Vector2D(0, 0);
float scale = 1;
float refreshRate = 60; // Hz
bool disabled = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
std::string mirrorOf = "";
bool enable10bit = false;
eCMType cmType = CM_SRGB;
float sdrSaturation = 1.0f; // SDR -> HDR
float sdrBrightness = 1.0f; // SDR -> HDR
drmModeModeInfo drmMode = {};
eAutoDirs autoDir = DIR_AUTO_NONE;
std::string name = "";
Vector2D resolution = Vector2D(1280, 720);
Vector2D offset = Vector2D(0, 0);
float scale = 1;
float refreshRate = 60;
bool disabled = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
std::string mirrorOf = "";
bool enable10bit = false;
drmModeModeInfo drmMode = {};
std::optional<int> vrr;
};
class CMonitor;
class CSyncTimeline;
class CEGLSync;
class CMonitorState {
public:
CMonitorState(CMonitor* owner);
~CMonitorState() = default;
~CMonitorState();
bool commit();
bool test();
@@ -106,8 +89,10 @@ class CMonitor {
CDamageRing damage;
SP<Aquamarine::IOutput> output;
float refreshRate = 60; // Hz
float refreshRate = 60;
int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float xwaylandScale = 1.f;
@@ -121,9 +106,6 @@ class CMonitor {
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
eCMType cmType = CM_SRGB;
float sdrSaturation = 1.0f;
float sdrBrightness = 1.0f;
bool createdByUser = false;
bool isUnsafeFallback = false;
@@ -139,12 +121,11 @@ class CMonitor {
SMonitorRule activeMonitorRule;
// explicit sync
SP<CSyncTimeline> inTimeline;
Hyprutils::OS::CFileDescriptor inFence;
SP<CEGLSync> eglSync;
uint64_t inTimelinePoint = 0;
SP<CSyncTimeline> inTimeline;
SP<CSyncTimeline> outTimeline;
uint64_t commitSeq = 0;
PHLMONITORREF self;
PHLMONITORREF self;
// mirroring
PHLMONITORREF pMirrorOf;
@@ -159,7 +140,6 @@ class CMonitor {
// for direct scanout
PHLWINDOWREF lastScanout;
bool scanoutNeedsCursorUpdate = false;
struct {
bool canTear = false;
@@ -181,39 +161,35 @@ class CMonitor {
std::array<std::vector<PHLLSREF>, 4> m_aLayerSurfaceLayers;
// methods
void onConnect(bool noRule);
void onDisconnect(bool destroy = false);
bool applyMonitorRule(SMonitorRule* pMonitorRule, bool force = false);
void addDamage(const pixman_region32_t* rg);
void addDamage(const CRegion& rg);
void addDamage(const CBox& box);
bool shouldSkipScheduleFrameOnMouseEvent();
void setMirror(const std::string&);
bool isMirror();
bool matchesStaticSelector(const std::string& selector) const;
float getDefaultScale();
void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void changeWorkspace(const WORKSPACEID& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace);
void setSpecialWorkspace(const WORKSPACEID& id);
void moveTo(const Vector2D& pos);
Vector2D middle();
void updateMatrix();
WORKSPACEID activeWorkspaceID();
WORKSPACEID activeSpecialWorkspaceID();
CBox logicalBox();
void scheduleDone();
bool attemptDirectScanout();
void setCTM(const Mat3x3& ctm);
void onCursorMovedOnMonitor();
void onConnect(bool noRule);
void onDisconnect(bool destroy = false);
void addDamage(const pixman_region32_t* rg);
void addDamage(const CRegion* rg);
void addDamage(const CBox* box);
bool shouldSkipScheduleFrameOnMouseEvent();
void setMirror(const std::string&);
bool isMirror();
bool matchesStaticSelector(const std::string& selector) const;
float getDefaultScale();
void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void changeWorkspace(const WORKSPACEID& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace);
void setSpecialWorkspace(const WORKSPACEID& id);
void moveTo(const Vector2D& pos);
Vector2D middle();
void updateMatrix();
WORKSPACEID activeWorkspaceID();
WORKSPACEID activeSpecialWorkspaceID();
CBox logicalBox();
void scheduleDone();
bool attemptDirectScanout();
void setCTM(const Mat3x3& ctm);
void debugLastPresentation(const std::string& message);
void onMonitorFrame();
void debugLastPresentation(const std::string& message);
void onMonitorFrame();
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
WP<CWindow> m_previousFSWindow;
NColorManagement::SImageDescription imageDescription;
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
// For the list lookup
@@ -221,16 +197,11 @@ class CMonitor {
return vecPosition == rhs.vecPosition && vecSize == rhs.vecSize && szName == rhs.szName;
}
// workspace previous per monitor functionality
SWorkspaceIDName getPrevWorkspaceIDName(const WORKSPACEID id);
void addPrevWorkspaceID(const WORKSPACEID id);
private:
void setupDefaultWS(const SMonitorRule&);
WORKSPACEID findAvailableDefaultWS();
void setupDefaultWS(const SMonitorRule&);
WORKSPACEID findAvailableDefaultWS();
bool doneScheduled = false;
std::stack<WORKSPACEID> prevWorkSpaces;
bool doneScheduled = false;
struct {
CHyprSignalListener frame;

View File

@@ -1,7 +1,7 @@
#include "SdDaemon.hpp"
#include "memory/Memory.hpp"
#include <memory>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>

View File

@@ -58,7 +58,7 @@ namespace NSplashes {
"Thanks ThatOneCalculator!",
"The AUR packages always work, except for the times they don't.",
"Funny animation compositor woo",
"3 years!",
"2 years!",
// music reference / quote section
"J'remue le ciel, le jour, la nuit.",
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",

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