mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-15 20:13:49 -07:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4520b30d49 | ||
|
8405aa111d | ||
|
ad46257cce | ||
|
0cfbe618b5 | ||
|
7d0944acdf | ||
|
b9990468f3 | ||
|
736a8735b3 | ||
|
b54eecbd79 | ||
|
657aeb3946 | ||
|
6807430b18 |
101
.clang-tidy
101
.clang-tidy
@@ -1,101 +0,0 @@
|
||||
WarningsAsErrors: '*'
|
||||
HeaderFilterRegex: '.*\.hpp'
|
||||
FormatStyle: file
|
||||
Checks: >
|
||||
-*,
|
||||
bugprone-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-forward-declararion-namespace,
|
||||
-bugprone-forward-declararion-namespace,
|
||||
-bugprone-macro-parentheses,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-assignment-in-if-condition,
|
||||
concurrency-*,
|
||||
-concurrency-mt-unsafe,
|
||||
cppcoreguidelines-*,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||
-cppcoreguidelines-avoid-goto,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-cppcoreguidelines-avoid-do-while,
|
||||
-cppcoreguidelines-avoid-non-const-global-variables,
|
||||
-cppcoreguidelines-special-member-functions,
|
||||
-cppcoreguidelines-explicit-virtual-functions,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||
-cppcoreguidelines-narrowing-conversions,
|
||||
-cppcoreguidelines-pro-type-union-access,
|
||||
-cppcoreguidelines-pro-type-member-init,
|
||||
-cppcoreguidelines-macro-usage,
|
||||
-cppcoreguidelines-macro-to-enum,
|
||||
-cppcoreguidelines-init-variables,
|
||||
-cppcoreguidelines-pro-type-cstyle-cast,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
-cppcoreguidelines-pro-type-reinterpret-cast,
|
||||
google-global-names-in-headers,
|
||||
-google-readability-casting,
|
||||
google-runtime-operator,
|
||||
misc-*,
|
||||
-misc-unused-parameters,
|
||||
-misc-no-recursion,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-include-cleaner,
|
||||
-misc-use-anonymous-namespace,
|
||||
-misc-const-correctness,
|
||||
modernize-*,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-use-using,
|
||||
-modernize-use-override,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-macro-to-enum,
|
||||
-modernize-loop-convert,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-pass-by-value,
|
||||
-modernize-use-auto,
|
||||
performance-*,
|
||||
-performance-avoid-endl,
|
||||
-performance-unnecessary-value-param,
|
||||
portability-std-allocator-const,
|
||||
readability-*,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-function-size,
|
||||
-readability-identifier-length,
|
||||
-readability-magic-numbers,
|
||||
-readability-uppercase-literal-suffix,
|
||||
-readability-braces-around-statements,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-else-after-return,
|
||||
-readability-container-data-pointer,
|
||||
-readability-implicit-bool-conversion,
|
||||
-readability-avoid-nested-conditional-operator,
|
||||
-readability-redundant-member-init,
|
||||
-readability-redundant-string-init,
|
||||
-readability-avoid-const-params-in-decls,
|
||||
-readability-named-parameter,
|
||||
-readability-convert-member-functions-to-static,
|
||||
-readability-qualified-auto,
|
||||
-readability-make-member-function-const,
|
||||
-readability-isolate-declaration,
|
||||
-readability-inconsistent-declaration-parameter-name,
|
||||
-clang-diagnostic-error,
|
||||
|
||||
CheckOptions:
|
||||
performance-for-range-copy.WarnOnAllAutoCopies: true
|
||||
performance-inefficient-string-concatenation.StrictMode: true
|
||||
readability-braces-around-statements.ShortStatementLines: 0
|
||||
readability-identifier-naming.ClassCase: CamelCase
|
||||
readability-identifier-naming.ClassIgnoredRegexp: I.*
|
||||
readability-identifier-naming.ClassPrefix: C # We can't use regex here?!?!?!?
|
||||
readability-identifier-naming.EnumCase: CamelCase
|
||||
readability-identifier-naming.EnumPrefix: e
|
||||
readability-identifier-naming.EnumConstantCase: UPPER_CASE
|
||||
readability-identifier-naming.FunctionCase: camelBack
|
||||
readability-identifier-naming.NamespaceCase: CamelCase
|
||||
readability-identifier-naming.NamespacePrefix: N
|
||||
readability-identifier-naming.StructPrefix: S
|
||||
readability-identifier-naming.StructCase: CamelCase
|
76
.github/ISSUE_TEMPLATE/bug.yml
vendored
76
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -5,10 +5,10 @@ body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Already reported ? *
|
||||
description: Before opening a new bug report, please take a moment to search through the current open issues. If the same bug is already reported, don't open new issue - instead go upvote/comment on an existing one.
|
||||
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: I have searched the existing open and closed issues.
|
||||
required: true
|
||||
- label: I have searched the existing open and closed issues.
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: type
|
||||
@@ -19,28 +19,27 @@ body:
|
||||
**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:
|
||||
- "Definitely a regression - something broke after update (requires bisect)"
|
||||
- "Probably not a regression / I don't remember it happening before"
|
||||
- "Not a regression - it's bug regarding new feature"
|
||||
- "Not a regression - it's an old bug"
|
||||
- "I don't know, I started using Hyprland only recently"
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: ver
|
||||
attributes:
|
||||
label: System Info and Hyprland Version
|
||||
label: System Info and Version
|
||||
description: |
|
||||
Paste the output of `hyprctl systeminfo` here. If you can't
|
||||
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>
|
||||
|
||||
|
||||
```
|
||||
|
||||
<Paste the output of the command here, without removing any formatting around this>
|
||||
```sh
|
||||
|
||||
<Paste the output of the command here>
|
||||
|
||||
```
|
||||
|
||||
@@ -62,56 +61,15 @@ body:
|
||||
attributes:
|
||||
label: How to reproduce
|
||||
description: "How can someone else reproduce the issue?"
|
||||
placeholder: |
|
||||
1. ...
|
||||
2. ...
|
||||
3. ...
|
||||
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Additional info section
|
||||
|
||||
In the section below you will be asked to upload some files.
|
||||
|
||||
When including text files (such as logs or config), please **always ATTACH** them, and not paste them directly.
|
||||
|
||||
This is important to avoid clutter, spam, and make the issues more readable.
|
||||
Thanks for your understanding.
|
||||
|
||||
# The main reason to disallow pasting directly or in a dropdown, is to not clutter
|
||||
# the issue with unnecessary keywords, making the github issue search useless.
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Attach not paste
|
||||
options:
|
||||
- label: I understand that all text files must be *attached*, and not pasted directly. If not respected, this issue will likely get closed as spam
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >-
|
||||
Please be sure to upload the following files below if they are relevant to the issue:
|
||||
|
||||
- Logs can be found in $XDG_RUNTIME_DIR/hypr (sort by date to grab the latest)
|
||||
- Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland
|
||||
- Hyprland config files - `hyprctl systeminfo -c > /tmp/hyprland_config_dump.txt` use this command to dump full configuration to a single file.
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Checklist of files to include below
|
||||
options:
|
||||
- label: Hyprland config - `hyprctl systeminfo -c` (always include)
|
||||
- label: Crash report (always include in case of crash)
|
||||
- label: Video (always include in case of a visual bug)
|
||||
- label: Logs (might contain useful info such as errors)
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Additional info & File uploads
|
||||
label: Crash reports, logs, images, videos
|
||||
description: |
|
||||
Tip: You can attach files by clicking this area to highlight it and then dragging files in.
|
||||
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
|
||||
|
||||
|
20
.github/actions/setup_base/action.yml
vendored
20
.github/actions/setup_base/action.yml
vendored
@@ -33,10 +33,7 @@ runs:
|
||||
libfontenc \
|
||||
libglvnd \
|
||||
libinput \
|
||||
libjxl \
|
||||
libliftoff \
|
||||
libspng \
|
||||
libwebp \
|
||||
libxcursor \
|
||||
libxcvt \
|
||||
libxfont2 \
|
||||
@@ -61,17 +58,7 @@ runs:
|
||||
xcb-util \
|
||||
xcb-util-image \
|
||||
libzip \
|
||||
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
|
||||
librsvg
|
||||
|
||||
- name: Get hyprwayland-scanner-git
|
||||
shell: bash
|
||||
@@ -82,11 +69,6 @@ runs:
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
cmake --install build
|
||||
|
||||
- name: Get hyprgraphics-git
|
||||
shell: bash
|
||||
run: |
|
||||
git clone https://github.com/hyprwm/hyprgraphics && cd hyprgraphics && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprgraphics && cmake --install build
|
||||
|
||||
- name: Get hyprutils-git
|
||||
shell: bash
|
||||
run: |
|
||||
|
6
.github/pull_request_template.md
vendored
6
.github/pull_request_template.md
vendored
@@ -1,9 +1,3 @@
|
||||
<!--
|
||||
BEFORE you submit your PR, please check out the PR guidelines
|
||||
on our wiki: https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/
|
||||
-->
|
||||
|
||||
|
||||
#### Describe your PR, what does it fix/add?
|
||||
|
||||
|
||||
|
5
.github/workflows/ci.yaml
vendored
5
.github/workflows/ci.yaml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
- name: Build Hyprland
|
||||
run: |
|
||||
CFLAGS=-Werror CXXFLAGS=-Werror make all
|
||||
make all
|
||||
|
||||
- name: Compress and package artifacts
|
||||
run: |
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
tar -cvf Hyprland.tar.xz hyprland
|
||||
|
||||
- name: Release
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Build archive
|
||||
path: Hyprland.tar.xz
|
||||
@@ -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
|
||||
|
48
.github/workflows/clang-format.yml
vendored
48
.github/workflows/clang-format.yml
vendored
@@ -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
|
4
.github/workflows/man-update.yaml
vendored
4
.github/workflows/man-update.yaml
vendored
@@ -17,14 +17,14 @@ jobs:
|
||||
run: sudo apt install pandoc
|
||||
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
|
||||
- name: Build man pages
|
||||
run: make man
|
||||
|
||||
- uses: stefanzweifel/git-auto-commit-action@v5
|
||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||
name: Commit
|
||||
with:
|
||||
commit_message: "[gha] build man pages"
|
||||
|
4
.github/workflows/nix-build.yml
vendored
4
.github/workflows/nix-build.yml
vendored
@@ -12,13 +12,13 @@ jobs:
|
||||
matrix:
|
||||
package:
|
||||
- hyprland
|
||||
# - hyprland-cross # cross compiling fails due to qt
|
||||
# failure chain: hyprland-qtutils -> qt6.qtsvg -> qt6.qtbase -> psqlodbc & qt6.qttranslations
|
||||
- hyprland-cross
|
||||
- xdg-desktop-portal-hyprland
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
|
4
.github/workflows/nix-update-inputs.yml
vendored
4
.github/workflows/nix-update-inputs.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
|
||||
@@ -22,6 +22,6 @@ jobs:
|
||||
run: nix/update-inputs.sh
|
||||
|
||||
- name: Commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
uses: stefanzweifel/git-auto-commit-action@v4
|
||||
with:
|
||||
commit_message: "[gha] Nix: update inputs"
|
||||
|
3
.github/workflows/release.yaml
vendored
3
.github/workflows/release.yaml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Hyprland
|
||||
id: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -20,6 +20,7 @@ jobs:
|
||||
run: |
|
||||
git fetch --unshallow || echo "failed unshallowing"
|
||||
bash -c scripts/generateVersion.sh
|
||||
mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
|
||||
|
||||
- name: Create tarball with submodules
|
||||
id: tar
|
||||
|
2
.github/workflows/security-checks.yml
vendored
2
.github/workflows/security-checks.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Scan with Flawfinder
|
||||
uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c
|
||||
|
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.STALEBOT_PAT }}
|
||||
stale-issue-label: "stale"
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -14,7 +14,6 @@ _deps
|
||||
|
||||
build/
|
||||
result*
|
||||
/.pre-commit-config.yaml
|
||||
/.vscode/
|
||||
/.idea/
|
||||
.envrc
|
||||
@@ -40,6 +39,3 @@ PKGBUILD
|
||||
src/version.h
|
||||
hyprpm/Makefile
|
||||
hyprctl/Makefile
|
||||
|
||||
**/.#*.*
|
||||
**/#*.*#
|
||||
|
@@ -15,7 +15,6 @@ include(GNUInstallDirs)
|
||||
set(HYPRLAND_VERSION ${VER})
|
||||
set(PREFIX ${CMAKE_INSTALL_PREFIX})
|
||||
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
set(BINDIR ${CMAKE_INSTALL_BINDIR})
|
||||
configure_file(hyprland.pc.in hyprland.pc @ONLY)
|
||||
|
||||
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
|
||||
@@ -72,12 +71,9 @@ else()
|
||||
message(STATUS "Configuring Hyprland in Release with CMake")
|
||||
endif()
|
||||
|
||||
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
|
||||
@@ -102,25 +98,11 @@ else()
|
||||
endif()
|
||||
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
||||
|
||||
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.8.0)
|
||||
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.5.1)
|
||||
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
|
||||
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.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)
|
||||
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine)
|
||||
|
||||
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
|
||||
add_compile_definitions(AQUAMARINE_VERSION_MAJOR=${AQ_VERSION_MAJOR})
|
||||
add_compile_definitions(AQUAMARINE_VERSION_MINOR=${AQ_VERSION_MINOR})
|
||||
add_compile_definitions(AQUAMARINE_VERSION_PATCH=${AQ_VERSION_PATCH})
|
||||
add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}")
|
||||
add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}")
|
||||
add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}")
|
||||
add_compile_definitions(HYPRGRAPHICS_VERSION="${hyprgraphics_dep_VERSION}")
|
||||
|
||||
pkg_check_modules(
|
||||
deps
|
||||
@@ -129,7 +111,7 @@ pkg_check_modules(
|
||||
xkbcommon
|
||||
uuid
|
||||
wayland-server>=1.22.90
|
||||
wayland-protocols>=1.41
|
||||
wayland-protocols
|
||||
cairo
|
||||
pango
|
||||
pangocairo
|
||||
@@ -139,7 +121,9 @@ pkg_check_modules(
|
||||
libinput
|
||||
gbm
|
||||
gio-2.0
|
||||
re2)
|
||||
hyprlang>=0.3.2
|
||||
hyprcursor>=0.1.7
|
||||
hyprutils>=0.2.3)
|
||||
|
||||
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
|
||||
|
||||
@@ -206,12 +190,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)
|
||||
@@ -241,15 +219,6 @@ if(NO_SYSTEMD)
|
||||
else()
|
||||
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
|
||||
add_compile_definitions(USES_SYSTEMD)
|
||||
|
||||
# session file -uwsm
|
||||
if(NO_UWSM)
|
||||
message(STATUS "UWSM support is disabled...")
|
||||
else()
|
||||
message(STATUS "UWSM support is enabled (NO_UWSM not defined)...")
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||
@@ -263,15 +232,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::deps)
|
||||
if(udis_dep_FOUND)
|
||||
target_link_libraries(Hyprland PkgConfig::udis_dep)
|
||||
else()
|
||||
@@ -313,7 +274,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.2.0)
|
||||
if(hyprland_protocols_dep_FOUND)
|
||||
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
|
||||
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
|
||||
@@ -339,13 +300,7 @@ 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)
|
||||
protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false)
|
||||
@@ -376,21 +331,12 @@ protocolnew("staging/drm-lease" "drm-lease-v1" false)
|
||||
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)
|
||||
@@ -401,6 +347,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)
|
||||
@@ -444,5 +391,4 @@ install(
|
||||
DIRECTORY ${HEADERS_SRC}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h*"
|
||||
PATTERN "*.frag")
|
||||
PATTERN "*.h*")
|
||||
|
7
Makefile
7
Makefile
@@ -1,15 +1,12 @@
|
||||
PREFIX = /usr/local
|
||||
|
||||
stub:
|
||||
@echo "Do not run $(MAKE) directly without any arguments. Please refer to the wiki on how to compile Hyprland."
|
||||
|
||||
legacyrenderer:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./buildZ
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
|
||||
legacyrendererdebug:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build
|
||||
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
|
||||
release:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build
|
||||
|
@@ -100,7 +100,7 @@ easy IPC, much more QoL stuff than other compositors and more...
|
||||
|
||||
<!----------------------------------------------------------------------------->
|
||||
|
||||
[Configure]: https://wiki.hyprland.org/Configuring/
|
||||
[Configure]: https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
|
||||
[Stars]: https://starchart.cc/hyprwm/Hyprland
|
||||
[Hypr]: https://github.com/hyprwm/Hypr
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
First of all, please remember to:
|
||||
- Check that your issue is not a duplicate
|
||||
- Read the [FAQ](https://wiki.hyprland.org/FAQ/)
|
||||
- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/)
|
||||
- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/Configuring-Hyprland)
|
||||
|
||||
<br/>
|
||||
|
||||
|
14
example/hyprland-session.service
Normal file
14
example/hyprland-session.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Hyprland - Tiling compositor with the looks
|
||||
Documentation=man:Hyprland(1)
|
||||
BindsTo=graphical-session.target
|
||||
Before=graphical-session.target
|
||||
Wants=graphical-session-pre.target
|
||||
After=graphical-session-pre.target
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStart=/usr/bin/Hyprland
|
||||
ExecStop=/usr/bin/hyprctl dispatch exit
|
||||
Restart=on-failure
|
||||
Slice=session.slice
|
@@ -1,6 +1,5 @@
|
||||
[Desktop Entry]
|
||||
Name=Hyprland (uwsm-managed)
|
||||
Name=Hyprland
|
||||
Comment=An intelligent dynamic tiling Wayland compositor
|
||||
Exec=uwsm start -- hyprland.desktop
|
||||
DesktopNames=Hyprland
|
||||
Exec=systemctl --user start --wait hyprland-session
|
||||
Type=Application
|
@@ -1,6 +1,6 @@
|
||||
# This is an example Hyprland config file.
|
||||
# Refer to the wiki for more information.
|
||||
# https://wiki.hyprland.org/Configuring/
|
||||
# https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
|
||||
|
||||
# Please note not all available settings / options are set here.
|
||||
# For a full list, see the wiki
|
||||
@@ -81,18 +81,15 @@ 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
|
||||
inactive_opacity = 1.0
|
||||
|
||||
shadow {
|
||||
enabled = true
|
||||
range = 4
|
||||
render_power = 3
|
||||
color = rgba(1a1a1aee)
|
||||
}
|
||||
drop_shadow = true
|
||||
shadow_range = 4
|
||||
shadow_render_power = 3
|
||||
col.shadow = rgba(1a1a1aee)
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#blur
|
||||
blur {
|
||||
@@ -106,44 +103,20 @@ decoration {
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#animations
|
||||
animations {
|
||||
enabled = yes, please :)
|
||||
enabled = true
|
||||
|
||||
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
|
||||
|
||||
bezier = easeOutQuint,0.23,1,0.32,1
|
||||
bezier = easeInOutCubic,0.65,0.05,0.36,1
|
||||
bezier = linear,0,0,1,1
|
||||
bezier = almostLinear,0.5,0.5,0.75,1.0
|
||||
bezier = quick,0.15,0,0.1,1
|
||||
bezier = myBezier, 0.05, 0.9, 0.1, 1.05
|
||||
|
||||
animation = global, 1, 10, default
|
||||
animation = border, 1, 5.39, easeOutQuint
|
||||
animation = windows, 1, 4.79, easeOutQuint
|
||||
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
|
||||
animation = windowsOut, 1, 1.49, linear, popin 87%
|
||||
animation = fadeIn, 1, 1.73, almostLinear
|
||||
animation = fadeOut, 1, 1.46, almostLinear
|
||||
animation = fade, 1, 3.03, quick
|
||||
animation = layers, 1, 3.81, easeOutQuint
|
||||
animation = layersIn, 1, 4, easeOutQuint, fade
|
||||
animation = layersOut, 1, 1.5, linear, fade
|
||||
animation = fadeLayersIn, 1, 1.79, almostLinear
|
||||
animation = fadeLayersOut, 1, 1.39, almostLinear
|
||||
animation = workspaces, 1, 1.94, almostLinear, fade
|
||||
animation = workspacesIn, 1, 1.21, almostLinear, fade
|
||||
animation = workspacesOut, 1, 1.94, almostLinear, fade
|
||||
animation = windows, 1, 7, myBezier
|
||||
animation = windowsOut, 1, 7, default, popin 80%
|
||||
animation = border, 1, 10, default
|
||||
animation = borderangle, 1, 8, default
|
||||
animation = fade, 1, 7, default
|
||||
animation = workspaces, 1, 6, default
|
||||
}
|
||||
|
||||
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
|
||||
# "Smart gaps" / "No gaps when only"
|
||||
# uncomment all if you wish to use that.
|
||||
# workspace = w[tv1], gapsout:0, gapsin:0
|
||||
# workspace = f[1], gapsout:0, gapsin:0
|
||||
# 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]
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
||||
dwindle {
|
||||
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
|
||||
@@ -276,11 +249,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
|
||||
|
@@ -2,6 +2,4 @@
|
||||
Name=Hyprland
|
||||
Comment=An intelligent dynamic tiling Wayland compositor
|
||||
Exec=Hyprland
|
||||
Type=Application
|
||||
DesktopNames=Hyprland
|
||||
Keywords=tiling;wayland;compositor;
|
||||
Type=Application
|
@@ -22,6 +22,5 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
]
|
||||
}
|
192
flake.lock
generated
192
flake.lock
generated
@@ -16,11 +16,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742213273,
|
||||
"narHash": "sha256-0l0vDb4anfsBu1rOs94bC73Hub+xEivgBAo6QXl2MmU=",
|
||||
"lastModified": 1727261104,
|
||||
"narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "aquamarine",
|
||||
"rev": "484b732195cc53f4536ce4bd59a5c6402b1e7ccf",
|
||||
"rev": "b82fdaff917582a9d568969e15e61b398c71e990",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -29,43 +29,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprcursor": {
|
||||
"inputs": {
|
||||
"hyprlang": [
|
||||
@@ -79,11 +42,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742215578,
|
||||
"narHash": "sha256-zfs71PXVVPEe56WEyNi2TJQPs0wabU4WAlq0XV7GcdE=",
|
||||
"lastModified": 1727532803,
|
||||
"narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprcursor",
|
||||
"rev": "2fd36421c21aa87e2fe3bee11067540ae612f719",
|
||||
"rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -92,32 +55,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprgraphics": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
"hyprutils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1739049071,
|
||||
"narHash": "sha256-3+7TpXMrbsUXSwgr5VAKAnmkzMb6JO+Rvc9XRb5NMg4=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprgraphics",
|
||||
"rev": "175c6b29b6ff82100539e7c4363a35a02c74dd73",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprgraphics",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-protocols": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -128,11 +65,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1738422629,
|
||||
"narHash": "sha256-5v+bv75wJWvahyM2xcMTSNNxmV8a7hb01Eey5zYnBJw=",
|
||||
"lastModified": 1727451107,
|
||||
"narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "755aef8dab49d0fc4663c715fa4ad221b2aedaed",
|
||||
"rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -141,64 +78,28 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-qt-support": {
|
||||
"hyprland-protocols_2": {
|
||||
"inputs": {
|
||||
"hyprlang": [
|
||||
"hyprland-qtutils",
|
||||
"hyprlang"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"hyprland-qtutils",
|
||||
"xdph",
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"hyprland-qtutils",
|
||||
"xdph",
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737634706,
|
||||
"narHash": "sha256-nGCibkfsXz7ARx5R+SnisRtMq21IQIhazp6viBU8I/A=",
|
||||
"lastModified": 1721326555,
|
||||
"narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qt-support",
|
||||
"rev": "8810df502cdee755993cb803eba7b23f189db795",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qt-support",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-qtutils": {
|
||||
"inputs": {
|
||||
"hyprland-qt-support": "hyprland-qt-support",
|
||||
"hyprlang": [
|
||||
"hyprlang"
|
||||
],
|
||||
"hyprutils": [
|
||||
"hyprland-qtutils",
|
||||
"hyprlang",
|
||||
"hyprutils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1739048983,
|
||||
"narHash": "sha256-REhTcXq4qs3B3cCDtLlYDz0GZvmsBSh947Ub6pQWGTQ=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qtutils",
|
||||
"rev": "3504a293c8f8db4127cb0f7cfc1a318ffb4316f8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qtutils",
|
||||
"repo": "hyprland-protocols",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
@@ -215,11 +116,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741191527,
|
||||
"narHash": "sha256-kM+11Nch47Xwfgtw2EpRitJuORy4miwoMuRi5tyMBDY=",
|
||||
"lastModified": 1725997860,
|
||||
"narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "72df3861f1197e41b078faa3e38eedd60e00018d",
|
||||
"rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -238,11 +139,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741534688,
|
||||
"narHash": "sha256-EV3945SnjOCuRVbGRghsWx/9D89FyshnSO1Q6/TuQ14=",
|
||||
"lastModified": 1727300645,
|
||||
"narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "dd1f720cbc2dbb3c71167c9598045dd3261d27b3",
|
||||
"rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -261,11 +162,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 +177,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1742069588,
|
||||
"narHash": "sha256-C7jVfohcGzdZRF6DO+ybyG/sqpo1h6bZi9T56sxLy+k=",
|
||||
"lastModified": 1727348695,
|
||||
"narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c80f6a7e10b39afcc1894e02ef785b1ad0b0d7e5",
|
||||
"rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -290,40 +191,15 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742058297,
|
||||
"narHash": "sha256-b4SZc6TkKw8WQQssbN5O2DaCEzmFfvSTPYHlx/SFW9Y=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "59f17850021620cd348ad2e9c0c64f4e6325ce2a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"aquamarine": "aquamarine",
|
||||
"hyprcursor": "hyprcursor",
|
||||
"hyprgraphics": "hyprgraphics",
|
||||
"hyprland-protocols": "hyprland-protocols",
|
||||
"hyprland-qtutils": "hyprland-qtutils",
|
||||
"hyprlang": "hyprlang",
|
||||
"hyprutils": "hyprutils",
|
||||
"hyprwayland-scanner": "hyprwayland-scanner",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks",
|
||||
"systems": "systems",
|
||||
"xdph": "xdph"
|
||||
}
|
||||
@@ -345,9 +221,7 @@
|
||||
},
|
||||
"xdph": {
|
||||
"inputs": {
|
||||
"hyprland-protocols": [
|
||||
"hyprland-protocols"
|
||||
],
|
||||
"hyprland-protocols": "hyprland-protocols_2",
|
||||
"hyprlang": [
|
||||
"hyprlang"
|
||||
],
|
||||
@@ -365,11 +239,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741934139,
|
||||
"narHash": "sha256-ZhTcTH9FoeAtbPfWGrhkH7RjLJZ7GeF18nygLAMR+WE=",
|
||||
"lastModified": 1727524473,
|
||||
"narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "150b0b6f52bb422a1b232a53698606fe0320dde0",
|
||||
"rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
45
flake.nix
45
flake.nix
@@ -22,26 +22,12 @@
|
||||
inputs.hyprlang.follows = "hyprlang";
|
||||
};
|
||||
|
||||
hyprgraphics = {
|
||||
url = "github:hyprwm/hyprgraphics";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
inputs.hyprutils.follows = "hyprutils";
|
||||
};
|
||||
|
||||
hyprland-protocols = {
|
||||
url = "github:hyprwm/hyprland-protocols";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
|
||||
hyprland-qtutils = {
|
||||
url = "github:hyprwm/hyprland-qtutils";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
inputs.hyprlang.follows = "hyprlang";
|
||||
};
|
||||
|
||||
hyprlang = {
|
||||
url = "github:hyprwm/hyprlang";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
@@ -65,16 +51,10 @@
|
||||
url = "github:hyprwm/xdg-desktop-portal-hyprland";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
inputs.hyprland-protocols.follows = "hyprland-protocols";
|
||||
inputs.hyprlang.follows = "hyprlang";
|
||||
inputs.hyprutils.follows = "hyprutils";
|
||||
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
|
||||
};
|
||||
|
||||
pre-commit-hooks = {
|
||||
url = "github:cachix/git-hooks.nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = inputs @ {
|
||||
@@ -96,7 +76,7 @@
|
||||
pkgsCrossFor = eachSystem (system: crossSystem:
|
||||
import nixpkgs {
|
||||
localSystem = system;
|
||||
inherit crossSystem;
|
||||
crossSystem = crossSystem;
|
||||
overlays = with self.overlays; [
|
||||
hyprland-packages
|
||||
hyprland-extras
|
||||
@@ -111,18 +91,6 @@
|
||||
self.packages.${system})
|
||||
// {
|
||||
inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
|
||||
pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run {
|
||||
src = ./.;
|
||||
hooks = {
|
||||
hyprland-treewide-formatter = {
|
||||
enable = true;
|
||||
entry = "${self.formatter.${system}}/bin/hyprland-treewide-formatter";
|
||||
pass_filenames = false;
|
||||
excludes = ["subprojects"];
|
||||
always_run = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
packages = eachSystem (system: {
|
||||
@@ -130,11 +98,13 @@
|
||||
inherit
|
||||
(pkgsFor.${system})
|
||||
# hyprland-packages
|
||||
|
||||
hyprland
|
||||
hyprland-debug
|
||||
hyprland-legacy-renderer
|
||||
hyprland-unwrapped
|
||||
# hyprland-extras
|
||||
|
||||
xdg-desktop-portal-hyprland
|
||||
;
|
||||
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
|
||||
@@ -149,19 +119,12 @@
|
||||
hardeningDisable = ["fortify"];
|
||||
inputsFrom = [pkgsFor.${system}.hyprland];
|
||||
packages = [pkgsFor.${system}.clang-tools];
|
||||
inherit (self.checks.${system}.pre-commit-check) shellHook;
|
||||
};
|
||||
});
|
||||
|
||||
formatter = eachSystem (system: pkgsFor.${system}.callPackage ./nix/formatter.nix {});
|
||||
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
|
||||
|
||||
nixosModules.default = import ./nix/module.nix inputs;
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ project(
|
||||
DESCRIPTION "Control utility for Hyprland"
|
||||
)
|
||||
|
||||
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.4 re2)
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1)
|
||||
|
||||
add_executable(hyprctl "main.cpp")
|
||||
|
||||
|
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help]
|
||||
|
||||
commands:
|
||||
@@ -22,7 +20,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 +79,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:
|
||||
|
146
hyprctl/main.cpp
146
hyprctl/main.cpp
@@ -1,5 +1,3 @@
|
||||
#include <re2/re2.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -12,17 +10,23 @@
|
||||
#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 <deque>
|
||||
#include <filesystem>
|
||||
#include <cstdarg>
|
||||
#include <regex>
|
||||
#include <sys/socket.h>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <cstring>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#include "Strings.hpp"
|
||||
@@ -40,24 +44,18 @@ struct SInstanceData {
|
||||
bool valid = true;
|
||||
};
|
||||
|
||||
void log(const std::string& str) {
|
||||
void log(std::string str) {
|
||||
if (quiet)
|
||||
return;
|
||||
|
||||
std::println("{}", str);
|
||||
}
|
||||
|
||||
static int getUID() {
|
||||
const auto UID = getuid();
|
||||
const auto PWUID = getpwuid(UID);
|
||||
return PWUID ? PWUID->pw_uid : UID;
|
||||
std::cout << str << "\n";
|
||||
}
|
||||
|
||||
std::string getRuntimeDir() {
|
||||
const auto XDG = getenv("XDG_RUNTIME_DIR");
|
||||
|
||||
if (!XDG) {
|
||||
const std::string USERID = std::to_string(getUID());
|
||||
const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
|
||||
return "/run/user/" + USERID + "/hypr";
|
||||
}
|
||||
|
||||
@@ -67,11 +65,6 @@ std::string getRuntimeDir() {
|
||||
std::vector<SInstanceData> instances() {
|
||||
std::vector<SInstanceData> result;
|
||||
|
||||
try {
|
||||
if (!std::filesystem::exists(getRuntimeDir()))
|
||||
return {};
|
||||
} catch (std::exception& e) { return {}; }
|
||||
|
||||
for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) {
|
||||
if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock"))
|
||||
continue;
|
||||
@@ -112,7 +105,7 @@ std::vector<SInstanceData> instances() {
|
||||
static volatile bool sigintReceived = false;
|
||||
void intHandler(int sig) {
|
||||
sigintReceived = true;
|
||||
std::println("[hyprctl] SIGINT received, closing connection");
|
||||
std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl;
|
||||
}
|
||||
|
||||
int rollingRead(const int socket) {
|
||||
@@ -122,12 +115,12 @@ int rollingRead(const int socket) {
|
||||
constexpr size_t BUFFER_SIZE = 8192;
|
||||
std::array<char, BUFFER_SIZE> buffer = {0};
|
||||
long sizeWritten = 0;
|
||||
std::println("[hyprctl] reading from socket following up log:");
|
||||
std::cout << "[hyprctl] reading from socket following up log:" << std::endl;
|
||||
while (!sigintReceived) {
|
||||
sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
|
||||
if (sizeWritten < 0 && errno != EAGAIN) {
|
||||
if (errno != EINTR)
|
||||
std::println("Couldn't read (5): {}: {}", strerror(errno), errno);
|
||||
std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl;
|
||||
close(socket);
|
||||
return 5;
|
||||
}
|
||||
@@ -136,7 +129,7 @@ int rollingRead(const int socket) {
|
||||
break;
|
||||
|
||||
if (sizeWritten > 0) {
|
||||
std::println("{}", std::string(buffer.data(), sizeWritten));
|
||||
std::cout << std::string(buffer.data(), sizeWritten);
|
||||
buffer.fill('\0');
|
||||
}
|
||||
|
||||
@@ -149,16 +142,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,12 +152,17 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (instanceSignature.empty()) {
|
||||
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?) (3)");
|
||||
return 3;
|
||||
if (SERVERSOCKET < 0) {
|
||||
log("Couldn't open a socket (1)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const std::string USERID = std::to_string(getUID());
|
||||
if (instanceSignature.empty()) {
|
||||
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
|
||||
return 2;
|
||||
}
|
||||
|
||||
const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
|
||||
|
||||
sockaddr_un serverAddress = {0};
|
||||
serverAddress.sun_family = AF_UNIX;
|
||||
@@ -182,40 +172,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 +216,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) {
|
||||
@@ -243,9 +232,9 @@ int requestIPC(std::string filename, std::string arg) {
|
||||
sockaddr_un serverAddress = {0};
|
||||
serverAddress.sun_family = AF_UNIX;
|
||||
|
||||
const std::string USERID = std::to_string(getUID());
|
||||
const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
|
||||
|
||||
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/" + filename;
|
||||
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock";
|
||||
|
||||
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||
|
||||
@@ -263,10 +252,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,20 +269,11 @@ 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);
|
||||
std::string commands = arg.substr(arg.find_first_of(" ") + 1);
|
||||
|
||||
if (json) {
|
||||
RE2::GlobalReplace(&commands, ";\\s*", ";j/");
|
||||
commands.insert(0, "j/");
|
||||
commands = "j/" + std::regex_replace(commands, std::regex(";\\s*"), ";j/");
|
||||
}
|
||||
|
||||
std::string rq = "[[BATCH]]" + commands;
|
||||
@@ -330,11 +310,11 @@ void instancesRequest(bool json) {
|
||||
log(result + "\n");
|
||||
}
|
||||
|
||||
std::vector<std::string> splitArgs(int argc, char** argv) {
|
||||
std::vector<std::string> result;
|
||||
std::deque<std::string> splitArgs(int argc, char** argv) {
|
||||
std::deque<std::string> result;
|
||||
|
||||
for (auto i = 1 /* skip the executable */; i < argc; ++i)
|
||||
result.emplace_back(argv[i]);
|
||||
result.push_back(std::string(argv[i]));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -343,7 +323,7 @@ int main(int argc, char** argv) {
|
||||
bool parseArgs = true;
|
||||
|
||||
if (argc < 2) {
|
||||
std::println("{}", USAGE);
|
||||
std::cout << USAGE << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -380,7 +360,7 @@ int main(int argc, char** argv) {
|
||||
++i;
|
||||
|
||||
if (i >= ARGS.size()) {
|
||||
std::println("{}", USAGE);
|
||||
std::cout << USAGE << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -391,26 +371,24 @@ int main(int argc, char** argv) {
|
||||
const std::string& cmd = ARGS[0];
|
||||
|
||||
if (cmd == "hyprpaper") {
|
||||
std::println("{}", HYPRPAPER_HELP);
|
||||
} else if (cmd == "hyprsunset") {
|
||||
std::println("{}", HYPRSUNSET_HELP);
|
||||
std::cout << HYPRPAPER_HELP << std::endl;
|
||||
} else if (cmd == "notify") {
|
||||
std::println("{}", NOTIFY_HELP);
|
||||
std::cout << NOTIFY_HELP << std::endl;
|
||||
} else if (cmd == "output") {
|
||||
std::println("{}", OUTPUT_HELP);
|
||||
std::cout << OUTPUT_HELP << std::endl;
|
||||
} else if (cmd == "plugin") {
|
||||
std::println("{}", PLUGIN_HELP);
|
||||
std::cout << PLUGIN_HELP << std::endl;
|
||||
} else if (cmd == "setprop") {
|
||||
std::println("{}", SETPROP_HELP);
|
||||
std::cout << SETPROP_HELP << std::endl;
|
||||
} else if (cmd == "switchxkblayout") {
|
||||
std::println("{}", SWITCHXKBLAYOUT_HELP);
|
||||
std::cout << SWITCHXKBLAYOUT_HELP << std::endl;
|
||||
} else {
|
||||
std::println("{}", USAGE);
|
||||
std::cout << USAGE << std::endl;
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
std::println("{}", USAGE);
|
||||
std::cout << USAGE << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -421,7 +399,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (fullRequest.empty()) {
|
||||
std::println("{}", USAGE);
|
||||
std::cout << USAGE << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -475,8 +453,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"))
|
||||
@@ -500,7 +476,7 @@ int main(int argc, char** argv) {
|
||||
else if (fullRequest.contains("/decorations"))
|
||||
exitStatus = request(fullRequest, 1);
|
||||
else if (fullRequest.contains("/--help"))
|
||||
std::println("{}", USAGE);
|
||||
std::cout << USAGE << std::endl;
|
||||
else if (fullRequest.contains("/rollinglog") && needRoll)
|
||||
exitStatus = request(fullRequest, 0, true);
|
||||
else {
|
||||
|
@@ -3,7 +3,6 @@ executable(
|
||||
'main.cpp',
|
||||
dependencies: [
|
||||
dependency('hyprutils', version: '>= 0.1.1'),
|
||||
dependency('re2', required: true)
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
|
@@ -9,25 +9,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||
|
||||
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()
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1)
|
||||
|
||||
add_executable(hyprpm ${SRCFILES})
|
||||
|
||||
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps glaze::glaze)
|
||||
target_link_libraries(hyprpm PUBLIC PkgConfig::deps)
|
||||
|
||||
# binary
|
||||
install(TARGETS hyprpm)
|
||||
|
@@ -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}' }}};
|
||||
|
@@ -1,13 +1,14 @@
|
||||
#include "DataState.hpp"
|
||||
#include <toml++/toml.hpp>
|
||||
#include <print>
|
||||
#include <iostream>
|
||||
#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");
|
||||
std::cerr << "DataState: no $HOME\n";
|
||||
throw std::runtime_error("no $HOME");
|
||||
return "";
|
||||
}
|
||||
@@ -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;
|
||||
@@ -233,4 +242,4 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -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();
|
||||
};
|
@@ -1,14 +1,13 @@
|
||||
#include "PluginManager.hpp"
|
||||
#include "../helpers/Colors.hpp"
|
||||
#include "../helpers/StringUtils.hpp"
|
||||
#include "../progress/CProgressBar.hpp"
|
||||
#include "Manifest.hpp"
|
||||
#include "DataState.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <print>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
@@ -19,59 +18,39 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <toml++/toml.hpp>
|
||||
#include <glaze/glaze.hpp>
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
static std::string execAndGet(std::string cmd) {
|
||||
cmd += " 2>&1";
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
using PcloseType = int (*)(FILE*);
|
||||
const std::unique_ptr<FILE, PcloseType> pipe(popen(cmd.c_str(), "r"), static_cast<PcloseType>(pclose));
|
||||
if (!pipe)
|
||||
return "";
|
||||
|
||||
CProcess proc("/bin/sh", {"-c", cmd});
|
||||
|
||||
if (!proc.runSync())
|
||||
return "error";
|
||||
|
||||
return proc.stdOut();
|
||||
}
|
||||
|
||||
static std::string getTempRoot() {
|
||||
static auto ENV = getenv("XDG_RUNTIME_DIR");
|
||||
if (!ENV) {
|
||||
std::cerr << "\nERROR: XDG_RUNTIME_DIR not set!\n";
|
||||
exit(1);
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
result += buffer.data();
|
||||
}
|
||||
|
||||
const auto STR = ENV + std::string{"/hyprpm/"};
|
||||
|
||||
return STR;
|
||||
return result;
|
||||
}
|
||||
|
||||
SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
|
||||
static bool onceRunning = false;
|
||||
static bool onceInstalled = false;
|
||||
static SHyprlandVersion verRunning;
|
||||
static SHyprlandVersion verInstalled;
|
||||
SHyprlandVersion CPluginManager::getHyprlandVersion() {
|
||||
static SHyprlandVersion ver;
|
||||
static bool once = false;
|
||||
|
||||
if (onceRunning && running)
|
||||
return verRunning;
|
||||
if (once)
|
||||
return ver;
|
||||
|
||||
if (onceInstalled && !running)
|
||||
return verInstalled;
|
||||
|
||||
if (running)
|
||||
onceRunning = true;
|
||||
else
|
||||
onceInstalled = true;
|
||||
|
||||
const auto HLVERCALL = running ? execAndGet("hyprctl version") : execAndGet("Hyprland --version");
|
||||
once = true;
|
||||
const auto HLVERCALL = execAndGet("hyprctl version");
|
||||
if (m_bVerbose)
|
||||
std::println("{}", verboseString("{} version returned: {}", running ? "running" : "installed", HLVERCALL));
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "version returned: " << HLVERCALL << "\n";
|
||||
|
||||
if (!HLVERCALL.contains("Tag:")) {
|
||||
std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland."));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " You don't seem to be running Hyprland.";
|
||||
return SHyprlandVersion{};
|
||||
}
|
||||
|
||||
@@ -82,13 +61,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;
|
||||
@@ -97,20 +76,14 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
|
||||
} catch (...) { ; }
|
||||
|
||||
if (m_bVerbose)
|
||||
std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits));
|
||||
|
||||
auto ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
|
||||
|
||||
if (running)
|
||||
verRunning = ver;
|
||||
else
|
||||
verInstalled = ver;
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << " on " << hldate << ", commits " << commits << "\n";
|
||||
|
||||
ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
|
||||
return ver;
|
||||
}
|
||||
|
||||
bool CPluginManager::createSafeDirectory(const std::string& path) {
|
||||
if (path.empty() || !path.starts_with(getTempRoot()))
|
||||
if (path.empty() || !path.starts_with("/tmp"))
|
||||
return false;
|
||||
|
||||
if (std::filesystem::exists(path))
|
||||
@@ -129,21 +102,20 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
if (!hasDeps()) {
|
||||
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config"));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DataState::pluginRepoExists(url)) {
|
||||
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Repository already installed."));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
if (!GLOBALSTATE.dontWarnInstall) {
|
||||
std::println("{}!{} Disclaimer: {}", Colors::YELLOW, Colors::RED, Colors::RESET);
|
||||
std::println("plugins, especially not official, have no guarantee of stability, availablity or security.\n"
|
||||
"Run them at your own risk.\n"
|
||||
"This message will not appear again.");
|
||||
std::cout << Colors::YELLOW << "!" << Colors::RED << " Disclaimer:\n " << Colors::RESET
|
||||
<< "plugins, especially not official, have no guarantee of stability, availablity or security.\n Run them at your own risk.\n "
|
||||
<< "This message will not appear again.\n";
|
||||
GLOBALSTATE.dontWarnInstall = true;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
}
|
||||
@@ -157,7 +129,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
|
||||
std::println(stderr, "Aborting.");
|
||||
std::cout << "Aborting.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -168,72 +140,72 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
||||
|
||||
progress.print();
|
||||
|
||||
if (!std::filesystem::exists(getTempRoot())) {
|
||||
std::filesystem::create_directory(getTempRoot());
|
||||
std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace);
|
||||
} else if (!std::filesystem::is_directory(getTempRoot())) {
|
||||
std::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm"));
|
||||
if (!std::filesystem::exists("/tmp/hyprpm")) {
|
||||
std::filesystem::create_directory("/tmp/hyprpm");
|
||||
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
} else if (!std::filesystem::is_directory("/tmp/hyprpm")) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not prepare working dir for hyprpm\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string USERNAME = getpwuid(getuid())->pw_name;
|
||||
|
||||
m_szWorkingPluginDirectory = getTempRoot() + USERNAME;
|
||||
m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
|
||||
|
||||
if (!createSafeDirectory(m_szWorkingPluginDirectory)) {
|
||||
std::println(stderr, "\n{}", failureString("Could not prepare working dir for repo"));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not prepare working dir for repo\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(infoString("Cloning {}", url));
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + url);
|
||||
|
||||
std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), url, USERNAME));
|
||||
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME);
|
||||
|
||||
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
|
||||
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. shell returned:\n" << ret << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rev.empty()) {
|
||||
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev);
|
||||
if (ret.compare(0, 6, "fatal:") == 0) {
|
||||
std::println(stderr, "\n{}", failureString("Could not check out revision {}. shell returned:\n{}", rev, ret));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n";
|
||||
return false;
|
||||
}
|
||||
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
|
||||
if (m_bVerbose)
|
||||
std::println("{}", verboseString("git submodule update --init returned: {}", ret));
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
|
||||
}
|
||||
|
||||
progress.m_iSteps = 1;
|
||||
progress.printMessageAbove(successString("cloned"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned");
|
||||
progress.m_szCurrentMessage = "Reading the manifest";
|
||||
progress.print();
|
||||
|
||||
std::unique_ptr<CManifest> pManifest;
|
||||
|
||||
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
|
||||
progress.printMessageAbove(successString("found hyprpm manifest"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
|
||||
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
|
||||
progress.printMessageAbove(successString("found hyprload manifest"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
|
||||
}
|
||||
|
||||
if (!pManifest) {
|
||||
std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest"));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pManifest->m_bGood) {
|
||||
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest"));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.m_iSteps = 2;
|
||||
progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:");
|
||||
for (auto const& pl : pManifest->m_vPlugins) {
|
||||
std::string message = "→ " + pl.name + " by ";
|
||||
std::string message = std::string{Colors::RESET} + " → " + pl.name + " by ";
|
||||
for (auto const& a : pl.authors) {
|
||||
message += a + ", ";
|
||||
}
|
||||
@@ -248,19 +220,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
||||
if (!pManifest->m_sRepository.commitPins.empty()) {
|
||||
// check commit pins
|
||||
|
||||
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size()));
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
|
||||
|
||||
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
|
||||
if (hl != HLVER.hash)
|
||||
continue;
|
||||
|
||||
progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
|
||||
|
||||
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
|
||||
|
||||
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
|
||||
if (m_bVerbose)
|
||||
std::println("{}", verboseString("git submodule update --init returned: {}", ret));
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -272,12 +244,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
||||
const auto HEADERSSTATUS = headersValid();
|
||||
|
||||
if (HEADERSSTATUS != HEADERS_OK) {
|
||||
std::println("\n{}", headerError(HEADERSSTATUS));
|
||||
std::cerr << "\n" << headerError(HEADERSSTATUS);
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.m_iSteps = 3;
|
||||
progress.printMessageAbove(successString("Hyprland headers OK"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " Hyprland headers OK");
|
||||
progress.m_szCurrentMessage = "Building plugin(s)";
|
||||
progress.print();
|
||||
|
||||
@@ -285,36 +257,35 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
||||
std::string out;
|
||||
|
||||
if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) {
|
||||
progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name));
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
|
||||
p.failed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(infoString("Building {}", p.name));
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto const& bs : p.buildSteps) {
|
||||
const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
|
||||
std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
|
||||
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
|
||||
}
|
||||
|
||||
if (m_bVerbose)
|
||||
std::println("{}", verboseString("shell returned: {}", out));
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
|
||||
|
||||
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
|
||||
progress.printMessageAbove(failureString("Plugin {} failed to build.\n"
|
||||
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n"
|
||||
" If you are on -git, update first\n"
|
||||
" Try re-running with -v to see more verbose output.\n",
|
||||
p.name));
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Plugin " + p.name + " failed to build.\n" +
|
||||
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update "
|
||||
"first.\n Try re-running with -v to see "
|
||||
"more verbose output.\n");
|
||||
|
||||
p.failed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(successString("built {} into {}", p.name, p.output));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output);
|
||||
}
|
||||
|
||||
progress.printMessageAbove(successString("all plugins built"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " all plugins built");
|
||||
progress.m_iSteps = 4;
|
||||
progress.m_szCurrentMessage = "Installing repository";
|
||||
progress.print();
|
||||
@@ -333,13 +304,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
||||
}
|
||||
DataState::addNewPluginRepo(repo);
|
||||
|
||||
progress.printMessageAbove(successString("installed repository"));
|
||||
progress.printMessageAbove(successString("you can now enable the plugin(s) with hyprpm enable"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed repository");
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " you can now enable the plugin(s) with hyprpm enable");
|
||||
progress.m_iSteps = 5;
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
std::print("\n");
|
||||
std::cout << "\n";
|
||||
|
||||
// remove build files
|
||||
std::filesystem::remove_all(m_szWorkingPluginDirectory);
|
||||
@@ -349,7 +320,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
||||
|
||||
bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
|
||||
if (!DataState::pluginRepoExists(urlOrName)) {
|
||||
std::println(stderr, "\n{}", failureString("Could not remove the repository. Repository is not installed."));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not remove the repository. Repository is not installed.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -360,7 +331,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
|
||||
std::println("Aborting.");
|
||||
std::cout << "Aborting.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -370,21 +341,21 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
|
||||
}
|
||||
|
||||
eHeadersErrors CPluginManager::headersValid() {
|
||||
const auto HLVER = getHyprlandVersion(false);
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc"))
|
||||
return HEADERS_MISSING;
|
||||
|
||||
// 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);
|
||||
std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
|
||||
auto headers = execAndGet(cmd.c_str());
|
||||
|
||||
if (!headers.contains("-I/"))
|
||||
return HEADERS_MISSING;
|
||||
|
||||
headers.pop_back(); // pop newline
|
||||
|
||||
std::string verHeader;
|
||||
std::string verHeader = "";
|
||||
|
||||
while (!headers.empty()) {
|
||||
const auto PATH = headers.substr(0, headers.find(" -I/", 3));
|
||||
@@ -432,20 +403,20 @@ bool CPluginManager::updateHeaders(bool force) {
|
||||
|
||||
DataState::ensureStateStoreExists();
|
||||
|
||||
const auto HLVER = getHyprlandVersion(false);
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
if (!hasDeps()) {
|
||||
std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config"));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(getTempRoot())) {
|
||||
std::filesystem::create_directory(getTempRoot());
|
||||
std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace);
|
||||
if (!std::filesystem::exists("/tmp/hyprpm")) {
|
||||
std::filesystem::create_directory("/tmp/hyprpm");
|
||||
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
if (!force && headersValid() == HEADERS_OK) {
|
||||
std::println("\n{}", successString("Headers up to date."));
|
||||
std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Headers up to date.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -456,78 +427,77 @@ bool CPluginManager::updateHeaders(bool force) {
|
||||
progress.print();
|
||||
|
||||
const std::string USERNAME = getpwuid(getuid())->pw_name;
|
||||
const auto WORKINGDIR = getTempRoot() + "hyprland-" + USERNAME;
|
||||
const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME;
|
||||
|
||||
if (!createSafeDirectory(WORKINGDIR)) {
|
||||
std::println("\n{}", failureString("Could not prepare working dir for hl"));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not prepare working dir for hl\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& HL_URL = m_szCustomHlUrl.empty() ? "https://github.com/hyprwm/Hyprland" : m_szCustomHlUrl;
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment.");
|
||||
|
||||
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning {}, this might take a moment.", HL_URL));
|
||||
|
||||
const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow;
|
||||
const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow;
|
||||
|
||||
// let us give a bit of leg-room for shallowing
|
||||
// due to timezones, etc.
|
||||
const std::string SHALLOW_DATE = trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+%a %b %d %H:%M:%S %Y'");
|
||||
const std::string SHALLOW_DATE =
|
||||
trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'");
|
||||
|
||||
if (m_bVerbose && bShallow)
|
||||
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE));
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE);
|
||||
|
||||
std::string ret =
|
||||
execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}{}", getTempRoot(), HL_URL, USERNAME, (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")));
|
||||
execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""));
|
||||
|
||||
if (!std::filesystem::exists(WORKINGDIR)) {
|
||||
progress.printMessageAbove(failureString("Clone failed. Retrying without shallow."));
|
||||
ret = execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}", getTempRoot(), HL_URL, USERNAME));
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Clone failed. Retrying without shallow.");
|
||||
ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME);
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(WORKINGDIR + "/.git")) {
|
||||
std::println(stderr, "\n{}", failureString("Could not clone the Hyprland repository. shell returned:\n{}", ret));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(successString("Hyprland cloned"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned");
|
||||
progress.m_iSteps = 2;
|
||||
progress.m_szCurrentMessage = "Checking out sources";
|
||||
progress.print();
|
||||
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(verboseString("will run: cd {} && git checkout {} 2>&1", WORKINGDIR, HLVER.hash));
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
|
||||
|
||||
ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
|
||||
|
||||
if (ret.contains("fatal: unable to read tree")) {
|
||||
std::println(stderr, "\n{}",
|
||||
failureString("Could not checkout the running Hyprland commit. If you are on -git, try updating.\n"
|
||||
"You can also try re-running hyprpm update with --no-shallow."));
|
||||
std::cerr << "\n"
|
||||
<< Colors::RED << "✖" << Colors::RESET
|
||||
<< " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(verboseString("git returned (co): {}", ret));
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret);
|
||||
|
||||
ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash);
|
||||
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(verboseString("git returned (rs): {}", ret));
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret);
|
||||
|
||||
progress.printMessageAbove(successString("checked out to running ver"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " checked out to running ver");
|
||||
progress.m_iSteps = 3;
|
||||
progress.m_szCurrentMessage = "Building Hyprland";
|
||||
progress.print();
|
||||
|
||||
progress.printMessageAbove(statusString("!", Colors::YELLOW, "configuring Hyprland"));
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland");
|
||||
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(verboseString("setting PREFIX for cmake to {}", DataState::getHeadersPath()));
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath());
|
||||
|
||||
ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR,
|
||||
DataState::getHeadersPath()));
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(verboseString("cmake returned: {}", ret));
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
|
||||
|
||||
if (ret.contains("CMake Error at")) {
|
||||
// missing deps, let the user know.
|
||||
@@ -536,46 +506,48 @@ bool CPluginManager::updateHeaders(bool force) {
|
||||
missing = missing.substr(0, missing.find("-- Configuring incomplete"));
|
||||
missing = missing.substr(0, missing.find_last_of('\n'));
|
||||
|
||||
std::println(stderr, "\n{}",
|
||||
failureString("Could not configure the hyprland source, cmake complained:\n{}\n\n"
|
||||
"This likely means that you are missing the above dependencies or they are out of date.",
|
||||
missing));
|
||||
std::cerr << "\n"
|
||||
<< Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n"
|
||||
<< missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(successString("configured Hyprland"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " configured Hyprland");
|
||||
progress.m_iSteps = 4;
|
||||
progress.m_szCurrentMessage = "Installing sources";
|
||||
progress.print();
|
||||
|
||||
const std::string& cmd =
|
||||
std::string cmd =
|
||||
std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR);
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(verboseString("installation will run: {}", cmd));
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd);
|
||||
|
||||
ret = execAndGet(cmd);
|
||||
|
||||
if (m_bVerbose)
|
||||
std::println("{}", verboseString("installer returned: {}", ret));
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n";
|
||||
|
||||
// remove build files
|
||||
std::filesystem::remove_all(WORKINGDIR);
|
||||
|
||||
auto HEADERSVALID = headersValid();
|
||||
if (HEADERSVALID == HEADERS_OK) {
|
||||
progress.printMessageAbove(successString("installed headers"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed headers");
|
||||
progress.m_iSteps = 5;
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
std::print("\n");
|
||||
std::cout << "\n";
|
||||
} else {
|
||||
progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID)));
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" +
|
||||
headerErrorShort(HEADERSVALID) + ")");
|
||||
progress.m_iSteps = 5;
|
||||
progress.m_szCurrentMessage = "Failed";
|
||||
progress.print();
|
||||
|
||||
std::print(stderr, "\n\n{}", headerError(HEADERSVALID));
|
||||
std::cout << "\n";
|
||||
|
||||
std::cerr << "\n" << headerError(HEADERSVALID);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -585,18 +557,18 @@ bool CPluginManager::updateHeaders(bool force) {
|
||||
|
||||
bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
if (headersValid() != HEADERS_OK) {
|
||||
std::println("{}", failureString("headers are not up-to-date, please run hyprpm update."));
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
if (REPOS.size() < 1) {
|
||||
std::println("{}", failureString("No repos to update."));
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " No repos to update.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto HLVER = getHyprlandVersion(false);
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
CProgressBar progress;
|
||||
progress.m_iMaxSteps = REPOS.size() * 2 + 2;
|
||||
@@ -605,7 +577,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
progress.print();
|
||||
|
||||
const std::string USERNAME = getpwuid(getuid())->pw_name;
|
||||
m_szWorkingPluginDirectory = getTempRoot() + USERNAME;
|
||||
m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
|
||||
|
||||
for (auto const& repo : REPOS) {
|
||||
bool update = forceUpdateAll;
|
||||
@@ -614,26 +586,25 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
progress.m_szCurrentMessage = "Updating " + repo.name;
|
||||
progress.print();
|
||||
|
||||
progress.printMessageAbove(infoString("checking for updates for {}", repo.name));
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → checking for updates for " + repo.name);
|
||||
|
||||
createSafeDirectory(m_szWorkingPluginDirectory);
|
||||
|
||||
progress.printMessageAbove(infoString("Cloning {}", repo.url));
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + repo.url);
|
||||
|
||||
std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), repo.url, USERNAME));
|
||||
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME);
|
||||
|
||||
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
|
||||
std::println("{}", failureString("could not clone repo: shell returned: {}", ret));
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " could not clone repo: shell returned:\n" + ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!repo.rev.empty()) {
|
||||
progress.printMessageAbove(infoString("Plugin has revision set, resetting: {}", repo.rev));
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Plugin has revision set, resetting: " + repo.rev);
|
||||
|
||||
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev);
|
||||
if (ret.compare(0, 6, "fatal:") == 0) {
|
||||
std::println(stderr, "\n{}", failureString("could not check out revision {}: shell returned:\n{}", repo.rev, ret));
|
||||
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -649,7 +620,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
|
||||
if (!update) {
|
||||
std::filesystem::remove_all(m_szWorkingPluginDirectory);
|
||||
progress.printMessageAbove(successString("repository {} is up-to-date.", repo.name));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " is up-to-date.");
|
||||
progress.m_iSteps++;
|
||||
progress.print();
|
||||
continue;
|
||||
@@ -657,41 +628,41 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
|
||||
// we need to update
|
||||
|
||||
progress.printMessageAbove(successString("repository {} has updates.", repo.name));
|
||||
progress.printMessageAbove(infoString("Building {}", repo.name));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " has updates.");
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + repo.name);
|
||||
progress.m_iSteps++;
|
||||
progress.print();
|
||||
|
||||
std::unique_ptr<CManifest> pManifest;
|
||||
|
||||
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
|
||||
progress.printMessageAbove(successString("found hyprpm manifest"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
|
||||
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
|
||||
progress.printMessageAbove(successString("found hyprload manifest"));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
|
||||
}
|
||||
|
||||
if (!pManifest) {
|
||||
std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest"));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pManifest->m_bGood) {
|
||||
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest"));
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) {
|
||||
// check commit pins unless a revision is specified
|
||||
|
||||
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size()));
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
|
||||
|
||||
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
|
||||
if (hl != HLVER.hash)
|
||||
continue;
|
||||
|
||||
progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
|
||||
|
||||
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
|
||||
}
|
||||
@@ -701,33 +672,32 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
std::string out;
|
||||
|
||||
if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) {
|
||||
progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name));
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
|
||||
p.failed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(infoString("Building {}", p.name));
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto const& bs : p.buildSteps) {
|
||||
const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
|
||||
std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
|
||||
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
|
||||
}
|
||||
|
||||
if (m_bVerbose)
|
||||
std::println("{}", verboseString("shell returned: {}", out));
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
|
||||
|
||||
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
|
||||
std::println(stderr,
|
||||
"\n{}\n"
|
||||
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n"
|
||||
"If you are on -git, update first.\n"
|
||||
"Try re-running with -v to see more verbose output.",
|
||||
failureString("Plugin {} failed to build.", p.name));
|
||||
std::cerr << "\n"
|
||||
<< Colors::RED << "✖" << Colors::RESET << " Plugin " << p.name << " failed to build.\n"
|
||||
<< " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update first.\n Try "
|
||||
"re-running with -v to see more verbose "
|
||||
"output.\n";
|
||||
p.failed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(successString("built {} into {}", p.name, p.output));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output);
|
||||
}
|
||||
|
||||
// add repo toml to DataState
|
||||
@@ -748,7 +718,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
|
||||
std::filesystem::remove_all(m_szWorkingPluginDirectory);
|
||||
|
||||
progress.printMessageAbove(successString("updated {}", repo.name));
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " updated " + repo.name);
|
||||
}
|
||||
|
||||
progress.m_iSteps++;
|
||||
@@ -763,7 +733,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
std::print("\n");
|
||||
std::cout << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -771,47 +741,54 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
bool CPluginManager::enablePlugin(const std::string& name) {
|
||||
bool ret = DataState::setPluginEnabled(name, true);
|
||||
if (ret)
|
||||
std::println("{}", successString("Enabled {}", name));
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Enabled " << name << "\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::disablePlugin(const std::string& name) {
|
||||
bool ret = DataState::setPluginEnabled(name, false);
|
||||
if (ret)
|
||||
std::println("{}", successString("Disabled {}", name));
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Disabled " << name << "\n";
|
||||
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."));
|
||||
std::cerr << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
|
||||
return LOADSTATE_HEADERS_OUTDATED;
|
||||
}
|
||||
|
||||
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::cerr << "PluginManager: no $HOME or HIS\n";
|
||||
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"));
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Ensuring plugin load state\n";
|
||||
|
||||
// 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();
|
||||
@@ -838,20 +815,12 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload)
|
||||
return "";
|
||||
};
|
||||
|
||||
// if any of the loadUnloadPlugin calls return false, this is true
|
||||
// bcs that means the header version doesn't match the running version
|
||||
// (and Hyprland needs to restart)
|
||||
bool hyprlandVersionMismatch = false;
|
||||
|
||||
// unload disabled plugins (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)) {
|
||||
std::println("{}", infoString("{} will be unloaded after restarting Hyprland", p));
|
||||
hyprlandVersionMismatch = true;
|
||||
} else
|
||||
std::println("{}", successString("Unloaded {}", p));
|
||||
loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false);
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Unloaded " << p << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -861,31 +830,20 @@ 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)) {
|
||||
std::println("{}", infoString("{} will be loaded after restarting Hyprland", p.name));
|
||||
hyprlandVersionMismatch = true;
|
||||
} else
|
||||
std::println("{}", successString("Loaded {}", p.name));
|
||||
loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true);
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Loaded " << p.name << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::println("{}", successString("Plugin load state ensured"));
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Plugin load state ensured\n";
|
||||
|
||||
return hyprlandVersionMismatch ? LOADSTATE_HYPRLAND_UPDATED : LOADSTATE_OK;
|
||||
return LOADSTATE_OK;
|
||||
}
|
||||
|
||||
bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
|
||||
auto state = DataState::getGlobalState();
|
||||
auto HLVER = getHyprlandVersion(true);
|
||||
|
||||
if (state.headersHashCompiled != HLVER.hash) {
|
||||
std::println("{}", infoString("Running Hyprland version differs from plugin state, please restart Hyprland."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (load)
|
||||
execAndGet("hyprctl plugin load " + path);
|
||||
else
|
||||
@@ -898,17 +856,16 @@ void CPluginManager::listAllPlugins() {
|
||||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
for (auto const& r : REPOS) {
|
||||
std::println("{}", infoString("Repository {}:", r.name));
|
||||
std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n";
|
||||
|
||||
for (auto const& p : r.plugins) {
|
||||
std::println(" │ Plugin {}", p.name);
|
||||
|
||||
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
|
||||
|
||||
if (!p.failed)
|
||||
std::println(" └─ enabled: {}", (p.enabled ? std::string{Colors::GREEN} + "true" : std::string{Colors::RED} + "false"));
|
||||
std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n";
|
||||
else
|
||||
std::println(" └─ enabled: {}Plugin failed to build", Colors::RED);
|
||||
|
||||
std::println("{}", Colors::RESET);
|
||||
std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -919,19 +876,19 @@ void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int duratio
|
||||
|
||||
std::string CPluginManager::headerError(const eHeadersErrors err) {
|
||||
switch (err) {
|
||||
case HEADERS_CORRUPTED: return failureString("Headers corrupted. Please run hyprpm update to fix those.\n");
|
||||
case HEADERS_MISMATCHED: return failureString("Headers version mismatch. Please run hyprpm update to fix those.\n");
|
||||
case HEADERS_NOT_HYPRLAND: return failureString("It doesn't seem you are running on hyprland.\n");
|
||||
case HEADERS_MISSING: return failureString("Headers missing. Please run hyprpm update to fix those.\n");
|
||||
case HEADERS_CORRUPTED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers corrupted. Please run hyprpm update to fix those.\n";
|
||||
case HEADERS_MISMATCHED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers version mismatch. Please run hyprpm update to fix those.\n";
|
||||
case HEADERS_NOT_HYPRLAND: return std::string{Colors::RED} + "✖" + Colors::RESET + " It doesn't seem you are running on hyprland.\n";
|
||||
case HEADERS_MISSING: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers missing. Please run hyprpm update to fix those.\n";
|
||||
case HEADERS_DUPLICATED: {
|
||||
return failureString("Headers duplicated!!! This is a very bad sign.\n"
|
||||
"This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n"
|
||||
"If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n");
|
||||
return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers duplicated!!! This is a very bad sign.\n" +
|
||||
" This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" +
|
||||
" If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n";
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return failureString("Unknown header error. Please run hyprpm update to fix those.\n");
|
||||
return std::string{Colors::RED} + "✖" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n";
|
||||
}
|
||||
|
||||
std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
enum eHeadersErrors {
|
||||
HEADERS_OK = 0,
|
||||
@@ -27,8 +26,7 @@ enum ePluginLoadStateReturn {
|
||||
LOADSTATE_OK = 0,
|
||||
LOADSTATE_FAIL,
|
||||
LOADSTATE_PARTIAL_FAIL,
|
||||
LOADSTATE_HEADERS_OUTDATED,
|
||||
LOADSTATE_HYPRLAND_UPDATED
|
||||
LOADSTATE_HEADERS_OUTDATED
|
||||
};
|
||||
|
||||
struct SHyprlandVersion {
|
||||
@@ -51,10 +49,10 @@ 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);
|
||||
SHyprlandVersion getHyprlandVersion();
|
||||
|
||||
void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message);
|
||||
|
||||
@@ -62,7 +60,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);
|
||||
@@ -71,7 +68,7 @@ class CPluginManager {
|
||||
std::string headerError(const eHeadersErrors err);
|
||||
std::string headerErrorShort(const eHeadersErrors err);
|
||||
|
||||
std::string m_szWorkingPluginDirectory;
|
||||
std::string m_szWorkingPluginDirectory = "";
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CPluginManager> g_pPluginManager;
|
||||
|
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <string>
|
||||
#include "Colors.hpp"
|
||||
|
||||
template <typename... Args>
|
||||
std::string statusString(const std::string_view emoji, const std::string_view color, const std::string_view fmt, Args&&... args) {
|
||||
std::string ret = std::format("{}{}{} ", color, emoji, Colors::RESET);
|
||||
ret += std::vformat(fmt, std::make_format_args(args...));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string successString(const std::string_view fmt, Args&&... args) {
|
||||
return statusString("✔", Colors::GREEN, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string failureString(const std::string_view fmt, Args&&... args) {
|
||||
return statusString("✖", Colors::RED, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string verboseString(const std::string_view fmt, Args&&... args) {
|
||||
return statusString("[v]", Colors::BLUE, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string infoString(const std::string_view fmt, Args&&... args) {
|
||||
return statusString("→", Colors::RESET, fmt, args...);
|
||||
}
|
@@ -1,16 +1,15 @@
|
||||
#include "progress/CProgressBar.hpp"
|
||||
#include "helpers/Colors.hpp"
|
||||
#include "helpers/StringUtils.hpp"
|
||||
#include "core/PluginManager.hpp"
|
||||
#include "core/DataState.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <print>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
┃
|
||||
┣ add [url] [git rev] → Install a new plugin repository from git. Git revision
|
||||
┃ is optional, when set, commit locks are ignored.
|
||||
@@ -23,75 +22,63 @@ constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
┃
|
||||
┣ Flags:
|
||||
┃
|
||||
┣ --notify | -n → Send a hyprland notification for important events (including both successes and fail events)
|
||||
┣ --notify-fail | -nn → Send a hyprland notification for fail events only
|
||||
┣ --notify | -n → Send a hyprland notification for important events (e.g. load fail)
|
||||
┣ --help | -h → Show this menu
|
||||
┣ --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
|
||||
┗
|
||||
)#";
|
||||
|
||||
int main(int argc, char** argv, char** envp) {
|
||||
int main(int argc, char** argv, char** envp) {
|
||||
std::vector<std::string> ARGS{argc};
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
ARGS[i] = std::string{argv[i]};
|
||||
}
|
||||
|
||||
if (ARGS.size() < 2) {
|
||||
std::println(stderr, "{}", HELP);
|
||||
std::cout << HELP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<std::string> command;
|
||||
bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false;
|
||||
std::string customHlUrl;
|
||||
bool notify = false, verbose = false, force = false, noShallow = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (ARGS[i].starts_with("-")) {
|
||||
if (ARGS[i] == "--help" || ARGS[i] == "-h") {
|
||||
std::println("{}", HELP);
|
||||
std::cout << HELP;
|
||||
return 0;
|
||||
} else if (ARGS[i] == "--notify" || ARGS[i] == "-n") {
|
||||
notify = true;
|
||||
} else if (ARGS[i] == "--notify-fail" || ARGS[i] == "-nn") {
|
||||
notifyFail = notify = true;
|
||||
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
|
||||
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."));
|
||||
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
|
||||
} else {
|
||||
std::println(stderr, "Unrecognized option {}", ARGS[i]);
|
||||
std::cerr << "Unrecognized option " << ARGS[i] << "\n";
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
command.push_back(ARGS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (command.empty()) {
|
||||
std::println(stderr, "{}", HELP);
|
||||
return 1;
|
||||
std::cout << HELP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
std::println(stderr, "{}", failureString("Not enough args for add."));
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for add.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -103,7 +90,7 @@ int main(int argc, char** argv, char** envp) {
|
||||
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
|
||||
} else if (command[0] == "remove") {
|
||||
if (ARGS.size() < 2) {
|
||||
std::println(stderr, "{}", failureString("Not enough args for remove."));
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for remove.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -112,7 +99,7 @@ int main(int argc, char** argv, char** envp) {
|
||||
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
|
||||
bool headers = g_pPluginManager->updateHeaders(force);
|
||||
if (headers) {
|
||||
const auto HLVER = g_pPluginManager->getHyprlandVersion(false);
|
||||
const auto HLVER = g_pPluginManager->getHyprlandVersion();
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
|
||||
|
||||
@@ -123,39 +110,32 @@ int main(int argc, char** argv, char** envp) {
|
||||
|
||||
auto ret2 = g_pPluginManager->ensurePluginsLoadState();
|
||||
|
||||
if (ret2 == LOADSTATE_HYPRLAND_UPDATED)
|
||||
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Updated plugins, but Hyprland was updated. Please restart Hyprland.");
|
||||
|
||||
if (ret2 != LOADSTATE_OK)
|
||||
return 1;
|
||||
} else if (notify)
|
||||
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers");
|
||||
} else if (command[0] == "enable") {
|
||||
if (ARGS.size() < 2) {
|
||||
std::println(stderr, "{}", failureString("Not enough args for enable."));
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for enable.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!g_pPluginManager->enablePlugin(command[1])) {
|
||||
std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)"));
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't enable plugin (missing?)\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||
|
||||
if (ret == LOADSTATE_HYPRLAND_UPDATED)
|
||||
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland.");
|
||||
|
||||
if (ret != LOADSTATE_OK)
|
||||
return 1;
|
||||
} else if (command[0] == "disable") {
|
||||
if (command.size() < 2) {
|
||||
std::println(stderr, "{}", failureString("Not enough args for disable."));
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for disable.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!g_pPluginManager->disablePlugin(command[1])) {
|
||||
std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)"));
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't disable plugin (missing?)\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -163,30 +143,26 @@ 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) {
|
||||
} else if (notify) {
|
||||
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
|
||||
}
|
||||
} else if (command[0] == "list") {
|
||||
g_pPluginManager->listAllPlugins();
|
||||
} else {
|
||||
std::println(stderr, "{}", HELP);
|
||||
std::cout << HELP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -8,7 +8,6 @@ executable(
|
||||
dependency('hyprutils', version: '>= 0.1.1'),
|
||||
dependency('threads'),
|
||||
dependency('tomlplusplus'),
|
||||
dependency('glaze', method: 'cmake'),
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
|
@@ -1,11 +1,11 @@
|
||||
#include "CProgressBar.hpp"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
|
||||
#include <print>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -16,12 +16,11 @@ void CProgressBar::printMessageAbove(const std::string& msg) {
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
|
||||
std::string spaces;
|
||||
spaces.reserve(w.ws_col);
|
||||
for (size_t i = 0; i < w.ws_col; ++i) {
|
||||
spaces += ' ';
|
||||
}
|
||||
|
||||
std::println("\r{}\r{}", spaces, msg);
|
||||
std::cout << "\r" << spaces << "\r" << msg << "\n";
|
||||
print();
|
||||
}
|
||||
|
||||
@@ -30,16 +29,15 @@ void CProgressBar::print() {
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
|
||||
if (m_bFirstPrint)
|
||||
std::print("\n");
|
||||
std::cout << "\n";
|
||||
m_bFirstPrint = false;
|
||||
|
||||
std::string spaces;
|
||||
spaces.reserve(w.ws_col);
|
||||
for (size_t i = 0; i < w.ws_col; ++i) {
|
||||
spaces += ' ';
|
||||
}
|
||||
|
||||
std::print("\r{}\r", spaces);
|
||||
std::cout << "\r" << spaces << "\r";
|
||||
|
||||
std::string message = "";
|
||||
|
||||
@@ -76,7 +74,7 @@ void CProgressBar::print() {
|
||||
message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " ";
|
||||
|
||||
// draw message
|
||||
std::print("{} {}", message, m_szCurrentMessage);
|
||||
std::cout << message + " " + m_szCurrentMessage;
|
||||
|
||||
std::fflush(stdout);
|
||||
}
|
||||
}
|
@@ -14,4 +14,4 @@ class CProgressBar {
|
||||
|
||||
private:
|
||||
bool m_bFirstPrint = true;
|
||||
};
|
||||
};
|
35
meson.build
35
meson.build
@@ -21,7 +21,6 @@ add_project_arguments(
|
||||
'-Wno-missing-field-initializers',
|
||||
'-Wno-narrowing',
|
||||
'-Wno-pointer-arith', datarootdir,
|
||||
'-DHYPRLAND_VERSION="' + meson.project_version() + '"',
|
||||
],
|
||||
language: 'cpp',
|
||||
)
|
||||
@@ -31,20 +30,8 @@ if cpp_compiler.check_header('execinfo.h')
|
||||
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||
endif
|
||||
|
||||
aquamarine = dependency('aquamarine', version: '>=0.8.0')
|
||||
hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
|
||||
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
|
||||
hyprlang = dependency('hyprlang', version: '>= 0.3.2')
|
||||
hyprutils = dependency('hyprutils', version: '>= 0.2.3')
|
||||
aquamarine_version_list = aquamarine.version().split('.')
|
||||
aquamarine = dependency('aquamarine')
|
||||
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
|
||||
add_project_arguments(['-DAQUAMARINE_VERSION_MAJOR=@0@'.format(aquamarine_version_list.get(0))], language: 'cpp')
|
||||
add_project_arguments(['-DAQUAMARINE_VERSION_MINOR=@0@'.format(aquamarine_version_list.get(1))], language: 'cpp')
|
||||
add_project_arguments(['-DAQUAMARINE_VERSION_PATCH=@0@'.format(aquamarine_version_list.get(2))], language: 'cpp')
|
||||
add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp')
|
||||
add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp')
|
||||
add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp')
|
||||
add_project_arguments(['-DHYPRUTILS_VERSION="@0@"'.format(hyprutils.version())], language: 'cpp')
|
||||
|
||||
xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
||||
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
|
||||
@@ -62,19 +49,10 @@ 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)
|
||||
|
||||
# Handle options
|
||||
systemd_option = get_option('systemd')
|
||||
systemd = dependency('systemd', required: systemd_option)
|
||||
systemd_option.enable_auto_if(systemd.found())
|
||||
|
||||
if (systemd_option.enabled())
|
||||
message('Enabling systemd integration')
|
||||
if get_option('systemd').enabled()
|
||||
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
|
||||
subdir('systemd')
|
||||
endif
|
||||
|
||||
if get_option('legacy_renderer').enabled()
|
||||
@@ -89,7 +67,7 @@ endif
|
||||
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
|
||||
|
||||
# Install headers
|
||||
globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.frag', 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)
|
||||
@@ -101,19 +79,14 @@ if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized'
|
||||
warning('Profiling builds should set -- buildtype = debugoptimized')
|
||||
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')
|
||||
|
||||
|
@@ -1,6 +1,4 @@
|
||||
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
|
||||
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')
|
||||
|
@@ -5,18 +5,14 @@
|
||||
pkg-config,
|
||||
pkgconf,
|
||||
makeWrapper,
|
||||
cmake,
|
||||
meson,
|
||||
ninja,
|
||||
aquamarine,
|
||||
binutils,
|
||||
cairo,
|
||||
git,
|
||||
glaze,
|
||||
hyprcursor,
|
||||
hyprgraphics,
|
||||
hyprland-protocols,
|
||||
hyprland-qtutils,
|
||||
hyprlang,
|
||||
hyprutils,
|
||||
hyprwayland-scanner,
|
||||
@@ -26,10 +22,9 @@
|
||||
libinput,
|
||||
libxkbcommon,
|
||||
libuuid,
|
||||
libgbm,
|
||||
mesa,
|
||||
pango,
|
||||
pciutils,
|
||||
re2,
|
||||
systemd,
|
||||
tomlplusplus,
|
||||
udis86-hyprland,
|
||||
@@ -52,16 +47,15 @@
|
||||
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
|
||||
(lib.optional debug stdenvAdapters.keepDebugInfo)
|
||||
];
|
||||
|
||||
customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters;
|
||||
@@ -69,12 +63,12 @@ in
|
||||
assert assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
|
||||
assert assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
|
||||
assert assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
|
||||
customStdenv.mkDerivation (finalAttrs: {
|
||||
customStdenv.mkDerivation {
|
||||
pname = "hyprland${optionalString debug "-debug"}";
|
||||
inherit version;
|
||||
|
||||
src = cleanSourceWith {
|
||||
filter = name: _type: let
|
||||
filter = name: type: let
|
||||
baseName = baseNameOf (toString name);
|
||||
in
|
||||
! (hasSuffix ".nix" baseName);
|
||||
@@ -93,7 +87,6 @@ in
|
||||
DATE = date;
|
||||
DIRTY = optionalString (commit == "") "dirty";
|
||||
HASH = commit;
|
||||
TAG = "v${trim (readFile "${finalAttrs.src}/VERSION")}";
|
||||
|
||||
depsBuildBuild = [
|
||||
pkg-config
|
||||
@@ -104,7 +97,6 @@ in
|
||||
makeWrapper
|
||||
meson
|
||||
ninja
|
||||
cmake # needed for glaze
|
||||
pkg-config
|
||||
];
|
||||
|
||||
@@ -119,9 +111,7 @@ in
|
||||
aquamarine
|
||||
cairo
|
||||
git
|
||||
glaze
|
||||
hyprcursor
|
||||
hyprgraphics
|
||||
hyprland-protocols
|
||||
hyprlang
|
||||
hyprutils
|
||||
@@ -130,10 +120,9 @@ in
|
||||
libinput
|
||||
libuuid
|
||||
libxkbcommon
|
||||
libgbm
|
||||
mesa
|
||||
pango
|
||||
pciutils
|
||||
re2
|
||||
tomlplusplus
|
||||
udis86-hyprland
|
||||
wayland
|
||||
@@ -155,15 +144,17 @@ in
|
||||
|
||||
mesonBuildType =
|
||||
if debug
|
||||
then "debug"
|
||||
then "debugoptimized"
|
||||
else "release";
|
||||
|
||||
# we want as much debug info as possible
|
||||
dontStrip = debug;
|
||||
|
||||
mesonFlags = flatten [
|
||||
(mapAttrsToList mesonEnable {
|
||||
"xwayland" = enableXWayland;
|
||||
"legacy_renderer" = legacyRenderer;
|
||||
"uwsm" = false;
|
||||
"hyprpm" = false;
|
||||
"systemd" = withSystemd;
|
||||
})
|
||||
(mapAttrsToList mesonBool {
|
||||
"b_pch" = false;
|
||||
@@ -176,7 +167,6 @@ in
|
||||
wrapProgram $out/bin/Hyprland \
|
||||
--suffix PATH : ${makeBinPath [
|
||||
binutils
|
||||
hyprland-qtutils
|
||||
pciutils
|
||||
pkgconf
|
||||
]}
|
||||
@@ -192,4 +182,4 @@ in
|
||||
platforms = lib.platforms.linux;
|
||||
mainProgram = "Hyprland";
|
||||
};
|
||||
})
|
||||
}
|
||||
|
@@ -1,64 +0,0 @@
|
||||
{
|
||||
writeShellApplication,
|
||||
deadnix,
|
||||
statix,
|
||||
alejandra,
|
||||
llvmPackages_19,
|
||||
fd,
|
||||
}:
|
||||
writeShellApplication {
|
||||
name = "hyprland-treewide-formatter";
|
||||
runtimeInputs = [
|
||||
deadnix
|
||||
statix
|
||||
alejandra
|
||||
llvmPackages_19.clang-tools
|
||||
fd
|
||||
];
|
||||
text = ''
|
||||
# shellcheck disable=SC2148
|
||||
|
||||
# common excludes
|
||||
excludes="subprojects"
|
||||
|
||||
nix_format() {
|
||||
if [ "$*" = 0 ]; then
|
||||
fd '.*\.nix' . -E "$excludes" -x statix fix -- {} \;
|
||||
fd '.*\.nix' . -E "$excludes" -X deadnix -e -- {} \; -X alejandra {} \;
|
||||
elif [ -d "$1" ]; then
|
||||
fd '.*\.nix' "$1" -E "$excludes" -i -x statix fix -- {} \;
|
||||
fd '.*\.nix' "$1" -E "$excludes" -i -X deadnix -e -- {} \; -X alejandra {} \;
|
||||
else
|
||||
statix fix -- "$1"
|
||||
deadnix -e "$1"
|
||||
alejandra "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
cpp_format() {
|
||||
if [ "$*" = 0 ] || [ "$1" = "." ]; then
|
||||
fd '.*\.cpp' . -E "$excludes" | xargs clang-format --verbose -i
|
||||
elif [ -d "$1" ]; then
|
||||
fd '.*\.cpp' "$1" -E "$excludes" | xargs clang-format --verbose -i
|
||||
else
|
||||
clang-format --verbose -i "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
for i in "$@"; do
|
||||
case ''${i##*.} in
|
||||
"nix")
|
||||
nix_format "$i"
|
||||
;;
|
||||
"cpp")
|
||||
cpp_format "$i"
|
||||
;;
|
||||
*)
|
||||
nix_format "$i"
|
||||
cpp_format "$i"
|
||||
;;
|
||||
esac
|
||||
|
||||
done
|
||||
'';
|
||||
}
|
201
nix/lib.nix
201
nix/lib.nix
@@ -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;
|
||||
}
|
147
nix/module.nix
147
nix/module.nix
@@ -5,148 +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;
|
||||
}
|
||||
{
|
||||
plugin = let
|
||||
mkEntry = entry:
|
||||
if lib.types.package.check entry
|
||||
then "${entry}/lib/lib${entry.pname}.so"
|
||||
else entry;
|
||||
in
|
||||
map mkEntry 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;
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
@@ -22,16 +22,14 @@ in {
|
||||
# Dependencies
|
||||
inputs.aquamarine.overlays.default
|
||||
inputs.hyprcursor.overlays.default
|
||||
inputs.hyprgraphics.overlays.default
|
||||
inputs.hyprland-protocols.overlays.default
|
||||
inputs.hyprland-qtutils.overlays.default
|
||||
inputs.hyprlang.overlays.default
|
||||
inputs.hyprutils.overlays.default
|
||||
inputs.hyprwayland-scanner.overlays.default
|
||||
self.overlays.udis86
|
||||
|
||||
# Hyprland packages themselves
|
||||
(final: _prev: let
|
||||
(final: prev: let
|
||||
date = mkDate (self.lastModifiedDate or "19700101");
|
||||
in {
|
||||
hyprland = final.callPackage ./default.nix {
|
||||
@@ -42,13 +40,7 @@ in {
|
||||
inherit date;
|
||||
};
|
||||
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
|
||||
|
||||
# Build major libs with debug to get as much info as possible in a stacktrace
|
||||
hyprland-debug = final.hyprland.override {
|
||||
aquamarine = final.aquamarine.override {debug = true;};
|
||||
hyprutils = final.hyprutils.override {debug = true;};
|
||||
debug = true;
|
||||
};
|
||||
hyprland-debug = final.hyprland.override {debug = true;};
|
||||
hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;};
|
||||
|
||||
# deprecated packages
|
||||
@@ -71,14 +63,14 @@ in {
|
||||
# Packages for extra software recommended for usage with Hyprland,
|
||||
# including forked or patched packages for compatibility.
|
||||
hyprland-extras = lib.composeManyExtensions [
|
||||
inputs.xdph.overlays.default
|
||||
inputs.xdph.overlays.xdg-desktop-portal-hyprland
|
||||
];
|
||||
|
||||
# udis86 from nixpkgs is too old, and also does not provide a .pc file
|
||||
# this version is the one used in the git submodule, and allows us to
|
||||
# fetch the source without '?submodules=1'
|
||||
udis86 = final: prev: {
|
||||
udis86-hyprland = prev.udis86.overrideAttrs (_self: _super: {
|
||||
udis86-hyprland = prev.udis86.overrideAttrs (self: super: {
|
||||
src = final.fetchFromGitHub {
|
||||
owner = "canihavesomecoffee";
|
||||
repo = "udis86";
|
||||
|
@@ -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>
|
@@ -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.2',
|
||||
fallback: 'hyprland-protocols',
|
||||
)
|
||||
|
||||
@@ -33,14 +33,9 @@ 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',
|
||||
@@ -69,9 +64,6 @@ protocols = [
|
||||
wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml',
|
||||
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
|
||||
wayland_protocol_dir / 'staging/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 = []
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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)}
|
||||
|
1294
src/Compositor.cpp
1294
src/Compositor.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
#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 {
|
||||
enum eManagersInitStage {
|
||||
STAGE_PRIORITY = 0,
|
||||
STAGE_BASICINIT,
|
||||
STAGE_LATE
|
||||
@@ -22,11 +43,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;
|
||||
@@ -38,8 +59,8 @@ class CCompositor {
|
||||
std::string m_szInstancePath = "";
|
||||
std::string m_szCurrentSplash = "error";
|
||||
|
||||
std::vector<PHLMONITOR> m_vMonitors;
|
||||
std::vector<PHLMONITOR> m_vRealMonitors; // for all monitors, even those turned off
|
||||
std::vector<SP<CMonitor>> m_vMonitors;
|
||||
std::vector<SP<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
|
||||
std::vector<PHLWINDOW> m_vWindows;
|
||||
std::vector<PHLLS> m_vLayers;
|
||||
std::vector<PHLWORKSPACE> m_vWorkspaces;
|
||||
@@ -52,12 +73,14 @@ class CCompositor {
|
||||
void startCompositor();
|
||||
void stopCompositor();
|
||||
void cleanup();
|
||||
void createLockFile();
|
||||
void removeLockFile();
|
||||
void bumpNofile();
|
||||
void restoreNofile();
|
||||
|
||||
WP<CWLSurfaceResource> m_pLastFocus;
|
||||
PHLWINDOWREF m_pLastWindow;
|
||||
PHLMONITORREF m_pLastMonitor;
|
||||
WP<CMonitor> m_pLastMonitor;
|
||||
|
||||
std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused.
|
||||
|
||||
@@ -66,64 +89,74 @@ class CCompositor {
|
||||
bool m_bDPMSStateON = true;
|
||||
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;
|
||||
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
|
||||
bool m_bIsShuttingDown = false;
|
||||
bool m_bFinalRequests = false;
|
||||
bool m_bDesktopEnvSet = false;
|
||||
bool m_bEnableXwayland = true;
|
||||
|
||||
// ------------------------------------------------- //
|
||||
|
||||
PHLMONITOR getMonitorFromID(const MONITORID&);
|
||||
PHLMONITOR getMonitorFromName(const std::string&);
|
||||
PHLMONITOR getMonitorFromDesc(const std::string&);
|
||||
PHLMONITOR getMonitorFromCursor();
|
||||
PHLMONITOR getMonitorFromVector(const Vector2D&);
|
||||
CMonitor* getMonitorFromID(const MONITORID&);
|
||||
CMonitor* getMonitorFromName(const std::string&);
|
||||
CMonitor* getMonitorFromDesc(const std::string&);
|
||||
CMonitor* getMonitorFromCursor();
|
||||
CMonitor* 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);
|
||||
bool monitorExists(CMonitor*);
|
||||
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
|
||||
SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*);
|
||||
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, PHLMONITOR monitor, Vector2D*, PHLLS*);
|
||||
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*);
|
||||
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
|
||||
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
|
||||
PHLMONITOR getMonitorFromOutput(SP<Aquamarine::IOutput>);
|
||||
PHLMONITOR getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
|
||||
CMonitor* getMonitorFromOutput(SP<Aquamarine::IOutput>);
|
||||
CMonitor* getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
|
||||
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
|
||||
PHLWINDOW getWindowFromHandle(uint32_t);
|
||||
bool isWorkspaceVisible(PHLWORKSPACE);
|
||||
bool isWorkspaceVisibleNotCovered(PHLWORKSPACE);
|
||||
PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&);
|
||||
PHLWORKSPACE getWorkspaceByName(const std::string&);
|
||||
PHLWORKSPACE getWorkspaceByString(const std::string&);
|
||||
void sanityCheckWorkspaces();
|
||||
void updateWorkspaceWindowDecos(const WORKSPACEID&);
|
||||
void updateWorkspaceWindowData(const WORKSPACEID&);
|
||||
int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
|
||||
int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
|
||||
PHLWINDOW getUrgentWindow();
|
||||
bool hasUrgentWindowOnWorkspace(const WORKSPACEID&);
|
||||
PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&);
|
||||
PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&);
|
||||
PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&);
|
||||
bool isWindowActive(PHLWINDOW);
|
||||
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);
|
||||
PHLMONITOR getMonitorInDirection(const char&);
|
||||
PHLMONITOR getMonitorInDirection(PHLMONITOR, const char&);
|
||||
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
|
||||
CMonitor* getMonitorInDirection(const char&);
|
||||
CMonitor* getMonitorInDirection(CMonitor*, const char&);
|
||||
void updateAllWindowsAnimatedDecorationValues();
|
||||
void updateWorkspaceWindows(const WORKSPACEID& id);
|
||||
void updateWindowAnimatedDecorationValues(PHLWINDOW);
|
||||
MONITORID getNextAvailableMonitorID(std::string const& name);
|
||||
void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false);
|
||||
void swapActiveWorkspaces(PHLMONITOR, PHLMONITOR);
|
||||
PHLMONITOR getMonitorFromString(const std::string&);
|
||||
void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false);
|
||||
void swapActiveWorkspaces(CMonitor*, CMonitor*);
|
||||
CMonitor* getMonitorFromString(const std::string&);
|
||||
bool workspaceIDOutOfBounds(const WORKSPACEID&);
|
||||
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 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);
|
||||
void scheduleFrameForMonitor(PHLMONITOR, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
|
||||
void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
|
||||
void addToFadingOutSafe(PHLLS);
|
||||
void removeFromFadingOutSafe(PHLLS);
|
||||
void addToFadingOutSafe(PHLWINDOW);
|
||||
@@ -132,9 +165,11 @@ class CCompositor {
|
||||
PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>);
|
||||
void closeWindow(PHLWINDOW);
|
||||
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
|
||||
void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&);
|
||||
PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "",
|
||||
bool isEmpty = true); // will be deleted next frame if left empty and unfocused!
|
||||
void setActiveMonitor(PHLMONITOR);
|
||||
void renameWorkspace(const WORKSPACEID&, const std::string& name = "");
|
||||
void setActiveMonitor(CMonitor*);
|
||||
bool isWorkspaceSpecial(const WORKSPACEID&);
|
||||
WORKSPACEID getNewSpecialID();
|
||||
void performUserChecks();
|
||||
@@ -146,13 +181,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 +193,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;
|
||||
|
@@ -3,11 +3,11 @@
|
||||
#include "helpers/math/Math.hpp"
|
||||
#include <functional>
|
||||
#include <any>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <hyprutils/math/Box.hpp>
|
||||
|
||||
enum eIcons : uint8_t {
|
||||
using namespace Hyprutils::Math;
|
||||
|
||||
enum eIcons {
|
||||
ICON_WARNING = 0,
|
||||
ICON_INFO,
|
||||
ICON_HINT,
|
||||
@@ -17,7 +17,7 @@ enum eIcons : uint8_t {
|
||||
ICON_NONE
|
||||
};
|
||||
|
||||
enum eRenderStage : uint8_t {
|
||||
enum eRenderStage {
|
||||
RENDER_PRE = 0, /* Before binding the gl context */
|
||||
RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */
|
||||
RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */
|
||||
@@ -29,7 +29,7 @@ enum eRenderStage : uint8_t {
|
||||
RENDER_POST_WINDOW, /* After rendering a window (any pass) */
|
||||
};
|
||||
|
||||
enum eInputType : uint8_t {
|
||||
enum eInputType {
|
||||
INPUT_TYPE_AXIS = 0,
|
||||
INPUT_TYPE_BUTTON,
|
||||
INPUT_TYPE_DRAG_START,
|
||||
@@ -41,7 +41,7 @@ struct SCallbackInfo {
|
||||
bool cancelled = false; /* on cancellable events, will cancel the event. */
|
||||
};
|
||||
|
||||
enum eHyprCtlOutputFormat : uint8_t {
|
||||
enum eHyprCtlOutputFormat {
|
||||
FORMAT_NORMAL = 0,
|
||||
FORMAT_JSON
|
||||
};
|
||||
@@ -52,12 +52,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;
|
||||
|
@@ -3,7 +3,7 @@
|
||||
#include "../helpers/varlist/VarList.hpp"
|
||||
#include <vector>
|
||||
|
||||
enum eConfigValueDataTypes : int8_t {
|
||||
enum eConfigValueDataTypes {
|
||||
CVD_TYPE_INVALID = -1,
|
||||
CVD_TYPE_GRADIENT = 0,
|
||||
CVD_TYPE_CSS_VALUE = 1
|
||||
@@ -11,7 +11,7 @@ enum eConfigValueDataTypes : int8_t {
|
||||
|
||||
class ICustomConfigValueData {
|
||||
public:
|
||||
virtual ~ICustomConfigValueData() = default;
|
||||
virtual ~ICustomConfigValueData() = 0;
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() = 0;
|
||||
|
||||
@@ -20,40 +20,24 @@ class ICustomConfigValueData {
|
||||
|
||||
class CGradientValueData : public ICustomConfigValueData {
|
||||
public:
|
||||
CGradientValueData() = default;
|
||||
CGradientValueData(CHyprColor col) {
|
||||
CGradientValueData() {};
|
||||
CGradientValueData(CColor col) {
|
||||
m_vColors.push_back(col);
|
||||
updateColorsOk();
|
||||
};
|
||||
virtual ~CGradientValueData() = default;
|
||||
virtual ~CGradientValueData() {};
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() {
|
||||
return CVD_TYPE_GRADIENT;
|
||||
}
|
||||
|
||||
void reset(CHyprColor col) {
|
||||
void reset(CColor col) {
|
||||
m_vColors.clear();
|
||||
m_vColors.emplace_back(col);
|
||||
m_fAngle = 0;
|
||||
updateColorsOk();
|
||||
}
|
||||
|
||||
void updateColorsOk() {
|
||||
m_vColorsOkLabA.clear();
|
||||
for (auto& c : m_vColors) {
|
||||
const auto OKLAB = c.asOkLab();
|
||||
m_vColorsOkLabA.emplace_back(OKLAB.l);
|
||||
m_vColorsOkLabA.emplace_back(OKLAB.a);
|
||||
m_vColorsOkLabA.emplace_back(OKLAB.b);
|
||||
m_vColorsOkLabA.emplace_back(c.a);
|
||||
}
|
||||
}
|
||||
|
||||
/* Vector containing the colors */
|
||||
std::vector<CHyprColor> m_vColors;
|
||||
|
||||
/* Vector containing pure colors for shoving into opengl */
|
||||
std::vector<float> m_vColorsOkLabA;
|
||||
std::vector<CColor> m_vColors;
|
||||
|
||||
/* Float corresponding to the angle (rad) */
|
||||
float m_fAngle = 0;
|
||||
|
@@ -104,30 +104,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{0, 0, 4},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "general:snap:enabled",
|
||||
.description = "enable snapping for floating windows",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "general:snap:window_gap",
|
||||
.description = "minimum gap in pixels between windows before snapping",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{10, 0, 100},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "general:snap:monitor_gap",
|
||||
.description = "minimum gap in pixels between window and monitor edges before snapping",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{10, 0, 100},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "general:snap:border_overlap",
|
||||
.description = "if true, windows snap such that only one border's worth of space is between them",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
|
||||
/*
|
||||
* decoration:
|
||||
@@ -139,12 +115,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]",
|
||||
@@ -164,55 +134,49 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:enabled",
|
||||
.value = "decoration:drop_shadow",
|
||||
.description = "enable drop shadows on windows",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:range",
|
||||
.value = "decoration:shadow_range",
|
||||
.description = "Shadow range (size) in layout px",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{4, 0, 100},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:render_power",
|
||||
.value = "decoration:shadow_render_power",
|
||||
.description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{3, 1, 4},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:sharp",
|
||||
.description = "whether the shadow should be sharp or not. Akin to an infinitely high render power.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:ignore_window",
|
||||
.value = "decoration:shadow_ignore_window",
|
||||
.description = "if true, the shadow will not be rendered behind the window itself, only around it.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:color",
|
||||
.value = "decoration:col.shadow",
|
||||
.description = "shadow's color. Alpha dictates shadow's opacity.",
|
||||
.type = CONFIG_OPTION_COLOR,
|
||||
.data = SConfigOptionDescription::SColorData{0xee1a1a1a},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:color_inactive",
|
||||
.value = "decoration:col.shadow_inactive",
|
||||
.description = "inactive shadow color. (if not set, will fall back to col.shadow)",
|
||||
.type = CONFIG_OPTION_COLOR,
|
||||
.data = SConfigOptionDescription::SColorData{}, //TODO: UNSET?
|
||||
.data = SConfigOptionDescription::SColorData{}, //##TODO UNSET?
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:offset",
|
||||
.value = "decoration:shadow_offset",
|
||||
.description = "shadow's rendering offset.",
|
||||
.type = CONFIG_OPTION_VECTOR,
|
||||
.data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:scale",
|
||||
.value = "decoration:shadow_scale",
|
||||
.description = "shadow's scale. [0.0 - 1.0]",
|
||||
.type = CONFIG_OPTION_FLOAT,
|
||||
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
|
||||
@@ -253,98 +217,86 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
*/
|
||||
|
||||
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},
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
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",
|
||||
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
|
||||
.type = CONFIG_OPTION_FLOAT,
|
||||
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:blur:input_methods",
|
||||
.description = "whether to blur input methods (e.g. fcitx5)",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:blur:input_methods_ignorealpha",
|
||||
.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},
|
||||
@@ -501,12 +453,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 "
|
||||
@@ -608,18 +554,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:
|
||||
@@ -656,22 +590,16 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "input:tablet:output",
|
||||
.description = "the monitor to bind tablets. Can be current or a monitor name. Leave empty to map across all monitors.",
|
||||
.description = "the monitor to bind tablets. Empty means unbound..",
|
||||
.type = CONFIG_OPTION_STRING_SHORT,
|
||||
.data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "input:tablet:region_position",
|
||||
.description = "position of the mapped region in monitor layout relative to the top left corner of the bound monitor or all monitors.",
|
||||
.description = "position of the mapped region in monitor layout.",
|
||||
.type = CONFIG_OPTION_VECTOR,
|
||||
.data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "input:tablet:absolute_region_position",
|
||||
.description = "whether to treat the region_position as an absolute position in monitor layout. Only applies when output is empty.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "input:tablet:region_size",
|
||||
.description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.",
|
||||
@@ -821,31 +749,25 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "group:merge_groups_on_groupbar",
|
||||
.description = "whether one group will be merged with another when dragged into its groupbar",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.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"},
|
||||
@@ -856,24 +778,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "group:drag_into_group",
|
||||
.description = "whether dragging a window into a unlocked group will merge them. Options: 0 (disabled), 1 (enabled), 2 (only when dragging into the groupbar)",
|
||||
.type = CONFIG_OPTION_CHOICE,
|
||||
.data = SConfigOptionDescription::SChoiceData{0, "disabled,enabled,only when dragging into the groupbar"},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "group:merge_floated_into_tiled_on_groupbar",
|
||||
.description = "whether dragging a floating window into a tiled window groupbar will merge them",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "group:group_on_movetoworkspace",
|
||||
.description = "whether using movetoworkspace[silent] will merge the window into the workspace's solitary unlocked group",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
|
||||
/*
|
||||
* group:groupbar:
|
||||
@@ -901,7 +805,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",
|
||||
@@ -909,12 +813,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",
|
||||
@@ -939,30 +837,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",
|
||||
@@ -993,18 +867,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},
|
||||
},
|
||||
|
||||
/*
|
||||
* misc:
|
||||
@@ -1054,9 +916,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",
|
||||
@@ -1199,24 +1061,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "misc:disable_hyprland_qtutils_check",
|
||||
.description = "disable the warning if hyprland-qtutils is missing",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "misc:lockdead_screen_delay",
|
||||
.description = "the delay in ms after the lockdead screen appears if the lock screen did not appear after a lock event occurred.",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{1000, 0, 5000},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "misc:enable_anr_dialog",
|
||||
.description = "whether to enable the ANR (app not responding) dialog when your apps hang",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
|
||||
/*
|
||||
* binds:
|
||||
@@ -1270,13 +1114,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},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "binds:movefocus_cycles_groupfirst",
|
||||
.description = "If enabled, when in a grouped window, movefocus will cycle windows in the groups first, then at each ends of tabs, it'll move on to other windows/groups",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "binds:disable_keybind_grabbing",
|
||||
@@ -1290,12 +1128,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "binds:allow_pin_fullscreen",
|
||||
.description = "Allows fullscreen to pinned windows, and restore their pinned status afterwards",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
|
||||
/*
|
||||
* xwayland:
|
||||
@@ -1319,12 +1151,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:
|
||||
@@ -1336,6 +1162,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:
|
||||
@@ -1356,57 +1189,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",
|
||||
.type = CONFIG_OPTION_CHOICE,
|
||||
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"},
|
||||
.description = "disables hardware cursors",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
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",
|
||||
@@ -1440,9 +1249,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "cursor:warp_on_change_workspace",
|
||||
.description = "Move the cursor to the last focused window after changing the workspace. Options: 0 (Disabled), 1 (Enabled), 2 (Force - ignores cursor:no_warps option)",
|
||||
.type = CONFIG_OPTION_CHOICE,
|
||||
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"},
|
||||
.description = "If true, move the cursor to the last focused window after changing the workspace.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "cursor:default_monitor",
|
||||
@@ -1481,37 +1290,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "cursor:use_cpu_buffer",
|
||||
.description = "Makes HW cursors use a CPU buffer. Required on Nvidia to have HW cursors. Experimental",
|
||||
.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.",
|
||||
.value = "cursor:allow_dumb_copy",
|
||||
.description = "Makes HW cursors work on Nvidia, at the cost of a possible hitch whenever the image changes",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
@@ -1598,24 +1378,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:
|
||||
@@ -1672,6 +1434,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_FLOAT,
|
||||
.data = SConfigOptionDescription::SFloatData{1, 0.1, 3},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "dwindle:no_gaps_when_only",
|
||||
.description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]",
|
||||
.type = CONFIG_OPTION_CHOICE,
|
||||
.data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "dwindle:use_active_for_splits",
|
||||
.description = "whether to prefer the active window or the mouse position for splits",
|
||||
@@ -1732,6 +1500,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_STRING_SHORT,
|
||||
.data = SConfigOptionDescription::SStringData{"none"},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "master:no_gaps_when_only",
|
||||
.description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]",
|
||||
.type = CONFIG_OPTION_CHOICE,
|
||||
.data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "master:orientation",
|
||||
.description = "default placement of the master area, can be left, right, top, bottom or center",
|
||||
@@ -1745,20 +1519,8 @@ 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",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "master:center_ignores_reserved",
|
||||
.description = "centers the master window on monitor ignoring reserved areas",
|
||||
.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{false},
|
||||
},
|
||||
@@ -1776,16 +1538,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
@@ -1,30 +1,33 @@
|
||||
#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 <deque>
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#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,14 +56,26 @@ 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;
|
||||
HANDLE handle = 0;
|
||||
std::string name = "";
|
||||
Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
|
||||
};
|
||||
|
||||
struct SPluginVariable {
|
||||
HANDLE handle = nullptr;
|
||||
HANDLE handle = 0;
|
||||
std::string name = "";
|
||||
};
|
||||
|
||||
@@ -69,7 +84,7 @@ struct SExecRequestedRule {
|
||||
uint64_t iPid = 0;
|
||||
};
|
||||
|
||||
enum eConfigOptionType : uint8_t {
|
||||
enum eConfigOptionType : uint16_t {
|
||||
CONFIG_OPTION_BOOL = 0,
|
||||
CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/
|
||||
CONFIG_OPTION_FLOAT = 2,
|
||||
@@ -81,7 +96,7 @@ enum eConfigOptionType : uint8_t {
|
||||
CONFIG_OPTION_VECTOR = 8,
|
||||
};
|
||||
|
||||
enum eConfigOptionFlags : uint8_t {
|
||||
enum eConfigOptionFlags : uint32_t {
|
||||
CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0),
|
||||
};
|
||||
|
||||
@@ -104,7 +119,7 @@ struct SConfigOptionDescription {
|
||||
};
|
||||
|
||||
struct SColorData {
|
||||
CHyprColor color;
|
||||
CColor color;
|
||||
};
|
||||
|
||||
struct SChoiceData {
|
||||
@@ -133,39 +148,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,136 +165,147 @@ class CConfigManager {
|
||||
|
||||
void* const* getConfigValuePtr(const std::string&);
|
||||
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
|
||||
std::string getMainConfigPath();
|
||||
std::string getConfigString();
|
||||
void onPluginLoadUnload(const std::string& name, bool load);
|
||||
static std::string getMainConfigPath();
|
||||
const std::string getConfigString();
|
||||
|
||||
SMonitorRule getMonitorRuleFor(const PHLMONITOR);
|
||||
SMonitorRule getMonitorRuleFor(const SP<CMonitor>);
|
||||
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
|
||||
std::string getDefaultWorkspaceFor(const std::string&);
|
||||
|
||||
PHLMONITOR getBoundMonitorForWS(const std::string&);
|
||||
CMonitor* getBoundMonitorForWS(const std::string&);
|
||||
std::string getBoundMonitorStringForWS(const std::string&);
|
||||
const std::vector<SWorkspaceRule>& getAllWorkspaceRules();
|
||||
const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
|
||||
|
||||
std::vector<SP<CWindowRule>> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
|
||||
std::vector<SP<CLayerRule>> getMatchingRules(PHLLS);
|
||||
void ensurePersistentWorkspacesPresent();
|
||||
std::vector<SWindowRule> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
|
||||
std::vector<SLayerRule> getMatchingRules(PHLLS);
|
||||
|
||||
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(CMonitor* pMonitor = nullptr);
|
||||
|
||||
bool shouldUseSoftwareCursors(PHLMONITOR pMonitor);
|
||||
void updateWatcher();
|
||||
std::string parseKeyword(const std::string&, const std::string&);
|
||||
|
||||
std::string parseKeyword(const std::string&, const std::string&);
|
||||
void addParseError(const std::string&);
|
||||
|
||||
void addParseError(const std::string&);
|
||||
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
|
||||
|
||||
SP<Hyprutils::Animation::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> 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>*(PHLWINDOW)>> mbWindowProperties = {
|
||||
{"allowsinput", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
|
||||
{"dimaround", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.dimAround; }},
|
||||
{"decorate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.decorate; }},
|
||||
{"focusonactivate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
|
||||
{"keepaspectratio", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
|
||||
{"nearestneighbor", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
|
||||
{"noanim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noAnim; }},
|
||||
{"noblur", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBlur; }},
|
||||
{"noborder", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBorder; }},
|
||||
{"nodim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noDim; }},
|
||||
{"nofocus", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noFocus; }},
|
||||
{"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
|
||||
{"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
|
||||
{"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
|
||||
{"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
|
||||
{"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }},
|
||||
{"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }},
|
||||
{"syncfullscreen", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
|
||||
{"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }},
|
||||
{"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }},
|
||||
};
|
||||
|
||||
void storeFloatingSize(PHLWINDOW window, const Vector2D& size);
|
||||
std::optional<Vector2D> getStoredFloatingSize(PHLWINDOW window);
|
||||
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(PHLWINDOW)>> miWindowProperties = {
|
||||
{"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
|
||||
|
||||
bool m_bWantsMonitorReload = false;
|
||||
bool m_bForceReload = false;
|
||||
bool m_bNoMonitorReload = false;
|
||||
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
|
||||
|
||||
private:
|
||||
UP<Hyprlang::CConfig> m_pConfig;
|
||||
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
|
||||
|
||||
std::vector<std::string> m_configPaths;
|
||||
std::deque<std::string> configPaths; // stores all the config paths
|
||||
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
|
||||
|
||||
Hyprutils::Animation::CAnimationConfigTree m_AnimationTree;
|
||||
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
|
||||
|
||||
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
|
||||
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
|
||||
|
||||
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
|
||||
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
|
||||
|
||||
std::vector<std::string> m_vDeclaredPlugins;
|
||||
std::vector<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::deque<SMonitorRule> m_dMonitorRules;
|
||||
std::deque<SWorkspaceRule> m_dWorkspaceRules;
|
||||
std::deque<SWindowRule> m_dWindowRules;
|
||||
std::deque<SLayerRule> m_dLayerRules;
|
||||
std::deque<std::string> m_dBlurLSNamespaces;
|
||||
|
||||
bool firstExecDispatched = false;
|
||||
bool m_bManualCrashInitiated = false;
|
||||
bool firstExecDispatched = false;
|
||||
bool m_bManualCrashInitiated = false;
|
||||
std::deque<std::string> firstExecRequests;
|
||||
std::deque<std::string> finalExecRequests;
|
||||
|
||||
std::vector<SFirstExecRequest> firstExecRequests; // bool is for if with rules
|
||||
std::vector<std::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;
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <hyprlang.hpp>
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include "ConfigManager.hpp"
|
||||
|
||||
@@ -12,7 +13,6 @@ class CConfigValue {
|
||||
CConfigValue(const std::string& val) {
|
||||
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
p_ = PVHYPRLANG->getDataStaticPtr();
|
||||
|
||||
#ifdef HYPRLAND_DEBUG
|
||||
@@ -70,4 +70,4 @@ template <>
|
||||
inline Hyprlang::CUSTOMTYPE CConfigValue<Hyprlang::CUSTOMTYPE>::operator*() const {
|
||||
RASSERT(false, "Impossible to implement operator* of CConfigValue<Hyprlang::CUSTOMTYPE>, use ptr()");
|
||||
return *ptr();
|
||||
}
|
||||
}
|
@@ -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,
|
||||
});
|
||||
}
|
||||
}
|
@@ -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>();
|
@@ -4,8 +4,8 @@
|
||||
|
||||
inline const std::string AUTOCONFIG = R"#(
|
||||
# #######################################################################################
|
||||
# AUTOGENERATED HYPRLAND CONFIG.
|
||||
# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hyprland.conf AND EDIT IT,
|
||||
# AUTOGENERATED HYPR CONFIG.
|
||||
# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
|
||||
# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
|
||||
# #######################################################################################
|
||||
|
||||
@@ -13,7 +13,7 @@ autogenerated = 1 # remove this line to remove the warning
|
||||
|
||||
# This is an example Hyprland config file.
|
||||
# Refer to the wiki for more information.
|
||||
# https://wiki.hyprland.org/Configuring/
|
||||
# https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
|
||||
|
||||
# Please note not all available settings / options are set here.
|
||||
# For a full list, see the wiki
|
||||
@@ -94,18 +94,15 @@ 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
|
||||
inactive_opacity = 1.0
|
||||
|
||||
shadow {
|
||||
enabled = true
|
||||
range = 4
|
||||
render_power = 3
|
||||
color = rgba(1a1a1aee)
|
||||
}
|
||||
drop_shadow = true
|
||||
shadow_range = 4
|
||||
shadow_render_power = 3
|
||||
col.shadow = rgba(1a1a1aee)
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#blur
|
||||
blur {
|
||||
@@ -119,44 +116,20 @@ decoration {
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#animations
|
||||
animations {
|
||||
enabled = yes, please :)
|
||||
enabled = true
|
||||
|
||||
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
|
||||
|
||||
bezier = easeOutQuint,0.23,1,0.32,1
|
||||
bezier = easeInOutCubic,0.65,0.05,0.36,1
|
||||
bezier = linear,0,0,1,1
|
||||
bezier = almostLinear,0.5,0.5,0.75,1.0
|
||||
bezier = quick,0.15,0,0.1,1
|
||||
bezier = myBezier, 0.05, 0.9, 0.1, 1.05
|
||||
|
||||
animation = global, 1, 10, default
|
||||
animation = border, 1, 5.39, easeOutQuint
|
||||
animation = windows, 1, 4.79, easeOutQuint
|
||||
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
|
||||
animation = windowsOut, 1, 1.49, linear, popin 87%
|
||||
animation = fadeIn, 1, 1.73, almostLinear
|
||||
animation = fadeOut, 1, 1.46, almostLinear
|
||||
animation = fade, 1, 3.03, quick
|
||||
animation = layers, 1, 3.81, easeOutQuint
|
||||
animation = layersIn, 1, 4, easeOutQuint, fade
|
||||
animation = layersOut, 1, 1.5, linear, fade
|
||||
animation = fadeLayersIn, 1, 1.79, almostLinear
|
||||
animation = fadeLayersOut, 1, 1.39, almostLinear
|
||||
animation = workspaces, 1, 1.94, almostLinear, fade
|
||||
animation = workspacesIn, 1, 1.21, almostLinear, fade
|
||||
animation = workspacesOut, 1, 1.94, almostLinear, fade
|
||||
animation = windows, 1, 7, myBezier
|
||||
animation = windowsOut, 1, 7, default, popin 80%
|
||||
animation = border, 1, 10, default
|
||||
animation = borderangle, 1, 8, default
|
||||
animation = fade, 1, 7, default
|
||||
animation = workspaces, 1, 6, default
|
||||
}
|
||||
|
||||
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
|
||||
# "Smart gaps" / "No gaps when only"
|
||||
# uncomment all if you wish to use that.
|
||||
# workspace = w[tv1], gapsout:0, gapsin:0
|
||||
# workspace = f[1], gapsout:0, gapsin:0
|
||||
# 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]
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
||||
dwindle {
|
||||
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
|
||||
@@ -269,7 +242,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
|
||||
@@ -289,12 +262,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
|
||||
)#";
|
||||
|
@@ -2,11 +2,10 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <link.h>
|
||||
#include <ctime>
|
||||
#include <cerrno>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <filesystem>
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
|
||||
#include "../plugins/PluginSystem.hpp"
|
||||
#include "../signal-safe.hpp"
|
||||
@@ -32,10 +31,10 @@ static char const* const MESSAGES[] = {"Sorry, didn't mean to...",
|
||||
|
||||
// <random> is not async-signal-safe, fake it with time(NULL) instead
|
||||
char const* getRandomMessage() {
|
||||
return MESSAGES[time(nullptr) % (sizeof(MESSAGES) / sizeof(MESSAGES[0]))];
|
||||
return MESSAGES[time(NULL) % (sizeof(MESSAGES) / sizeof(MESSAGES[0]))];
|
||||
}
|
||||
|
||||
[[noreturn]] inline void exitWithError(char const* err) {
|
||||
[[noreturn]] inline void exit_with_error(char const* err) {
|
||||
write(STDERR_FILENO, err, strlen(err));
|
||||
// perror() is not signal-safe, but we use it here
|
||||
// because if the crash-handler already crashed, it can't get any worse.
|
||||
@@ -43,17 +42,17 @@ char const* getRandomMessage() {
|
||||
abort();
|
||||
}
|
||||
|
||||
void NCrashReporter::createAndSaveCrash(int sig) {
|
||||
int reportFd = -1;
|
||||
void CrashReporter::createAndSaveCrash(int sig) {
|
||||
int reportFd;
|
||||
|
||||
// We're in the signal handler, so we *only* have stack memory.
|
||||
// To save as much stack memory as possible,
|
||||
// destroy things as soon as possible.
|
||||
{
|
||||
CMaxLengthCString<255> reportPath;
|
||||
MaxLengthCString<255> reportPath;
|
||||
|
||||
const auto HOME = sigGetenv("HOME");
|
||||
const auto CACHE_HOME = sigGetenv("XDG_CACHE_HOME");
|
||||
const auto HOME = sig_getenv("HOME");
|
||||
const auto CACHE_HOME = sig_getenv("XDG_CACHE_HOME");
|
||||
|
||||
if (CACHE_HOME && CACHE_HOME[0] != '\0') {
|
||||
reportPath += CACHE_HOME;
|
||||
@@ -62,24 +61,24 @@ void NCrashReporter::createAndSaveCrash(int sig) {
|
||||
reportPath += HOME;
|
||||
reportPath += "/.cache/hyprland";
|
||||
} else {
|
||||
exitWithError("$CACHE_HOME and $HOME not set, nowhere to report crash\n");
|
||||
exit_with_error("$CACHE_HOME and $HOME not set, nowhere to report crash\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int ret = mkdir(reportPath.getStr(), S_IRWXU);
|
||||
int ret = mkdir(reportPath.get_str(), S_IRWXU);
|
||||
//__asm__("int $3");
|
||||
if (ret < 0 && errno != EEXIST) {
|
||||
exitWithError("failed to mkdir() crash report directory\n");
|
||||
exit_with_error("failed to mkdir() crash report directory\n");
|
||||
}
|
||||
reportPath += "/hyprlandCrashReport";
|
||||
reportPath.writeNum(getpid());
|
||||
reportPath.write_num(getpid());
|
||||
reportPath += ".txt";
|
||||
|
||||
{
|
||||
CBufFileWriter<64> stderr(2);
|
||||
BufFileWriter<64> stderr(2);
|
||||
stderr += "Hyprland has crashed :( Consult the crash report at ";
|
||||
if (!reportPath.boundsExceeded()) {
|
||||
stderr += reportPath.getStr();
|
||||
stderr += reportPath.get_str();
|
||||
} else {
|
||||
stderr += "[ERROR: Crash report path does not fit into memory! Check if your $CACHE_HOME/$HOME is too deeply nested. Max 255 characters.]";
|
||||
}
|
||||
@@ -87,12 +86,12 @@ void NCrashReporter::createAndSaveCrash(int sig) {
|
||||
stderr.flush();
|
||||
}
|
||||
|
||||
reportFd = open(reportPath.getStr(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (reportFd < 0) {
|
||||
exitWithError("Failed to open crash report path for writing");
|
||||
exit_with_error("Failed to open crash report path for writing");
|
||||
}
|
||||
}
|
||||
CBufFileWriter<512> finalCrashReport(reportFd);
|
||||
BufFileWriter<512> finalCrashReport(reportFd);
|
||||
|
||||
finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n";
|
||||
finalCrashReport += getRandomMessage();
|
||||
@@ -101,7 +100,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
|
||||
finalCrashReport += "Hyprland received signal ";
|
||||
finalCrashReport.writeNum(sig);
|
||||
finalCrashReport += '(';
|
||||
finalCrashReport += sigStrsignal(sig);
|
||||
finalCrashReport += sig_strsignal(sig);
|
||||
finalCrashReport += ")\nVersion: ";
|
||||
finalCrashReport += GIT_COMMIT_HASH;
|
||||
finalCrashReport += "\nTag: ";
|
||||
@@ -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
|
||||
@@ -123,9 +122,9 @@ void NCrashReporter::createAndSaveCrash(int sig) {
|
||||
if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) {
|
||||
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
|
||||
|
||||
const size_t count = g_pPluginSystem->pluginCount();
|
||||
std::vector<CPlugin*> plugins(count);
|
||||
g_pPluginSystem->sigGetPlugins(plugins.data(), count);
|
||||
size_t count = g_pPluginSystem->pluginCount();
|
||||
CPlugin* plugins[count];
|
||||
g_pPluginSystem->sig_getPlugins(plugins, count);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
auto p = plugins[i];
|
||||
@@ -160,9 +159,9 @@ void NCrashReporter::createAndSaveCrash(int sig) {
|
||||
|
||||
finalCrashReport += "GPU:\n\t";
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga");
|
||||
finalCrashReport.writeCmdOutput("pciconf -lv | fgrep -A4 vga");
|
||||
#else
|
||||
finalCrashReport.writeCmdOutput("lspci -vnn | grep -E '(VGA|Display|3D)'");
|
||||
finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA");
|
||||
#endif
|
||||
|
||||
finalCrashReport += "\n\nos-release:\n";
|
||||
@@ -242,5 +241,5 @@ void NCrashReporter::createAndSaveCrash(int sig) {
|
||||
|
||||
finalCrashReport += "\n\nLog tail:\n";
|
||||
|
||||
finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find('\n') + 1);
|
||||
finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find("\n") + 1);
|
||||
}
|
||||
|
@@ -2,6 +2,6 @@
|
||||
|
||||
#include "../defines.hpp"
|
||||
|
||||
namespace NCrashReporter {
|
||||
namespace CrashReporter {
|
||||
void createAndSaveCrash(int sig);
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@@ -1,26 +1,24 @@
|
||||
#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);
|
||||
std::string versionRequest(eHyprCtlOutputFormat format, std::string request);
|
||||
|
||||
class CHyprCtl {
|
||||
public:
|
||||
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 +37,4 @@ class CHyprCtl {
|
||||
std::string m_socketPath;
|
||||
};
|
||||
|
||||
inline UP<CHyprCtl> g_pHyprCtl;
|
||||
inline std::unique_ptr<CHyprCtl> g_pHyprCtl;
|
||||
|
@@ -2,21 +2,13 @@
|
||||
#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>();
|
||||
}
|
||||
|
||||
void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
|
||||
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
|
||||
|
||||
if (!*PDEBUGOVERLAY)
|
||||
return;
|
||||
|
||||
m_dLastRenderTimes.emplace_back(durationUs / 1000.f);
|
||||
void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
|
||||
m_dLastRenderTimes.push_back(durationUs / 1000.f);
|
||||
|
||||
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
|
||||
m_dLastRenderTimes.pop_front();
|
||||
@@ -25,13 +17,8 @@ void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs)
|
||||
m_pMonitor = pMonitor;
|
||||
}
|
||||
|
||||
void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
|
||||
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
|
||||
|
||||
if (!*PDEBUGOVERLAY)
|
||||
return;
|
||||
|
||||
m_dLastRenderTimesNoOverlay.emplace_back(durationUs / 1000.f);
|
||||
void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
|
||||
m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f);
|
||||
|
||||
if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
|
||||
m_dLastRenderTimesNoOverlay.pop_front();
|
||||
@@ -40,13 +27,8 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float du
|
||||
m_pMonitor = pMonitor;
|
||||
}
|
||||
|
||||
void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
|
||||
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
|
||||
|
||||
if (!*PDEBUGOVERLAY)
|
||||
return;
|
||||
|
||||
m_dLastFrametimes.emplace_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
|
||||
void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) {
|
||||
m_dLastFrametimes.push_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
|
||||
|
||||
if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate)
|
||||
m_dLastFrametimes.pop_front();
|
||||
@@ -57,7 +39,7 @@ void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
|
||||
m_pMonitor = pMonitor;
|
||||
|
||||
// anim data too
|
||||
const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor.lock() : g_pCompositor->m_pLastMonitor.lock();
|
||||
const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor.get();
|
||||
if (PMONITORFORTICKS) {
|
||||
if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate)
|
||||
m_dLastAnimationTicks.pop_front();
|
||||
@@ -198,44 +180,29 @@ 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;
|
||||
}
|
||||
|
||||
void CHyprDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
|
||||
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
|
||||
|
||||
if (!*PDEBUGOVERLAY)
|
||||
return;
|
||||
|
||||
void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
|
||||
m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs);
|
||||
}
|
||||
|
||||
void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
|
||||
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
|
||||
|
||||
if (!*PDEBUGOVERLAY)
|
||||
return;
|
||||
|
||||
void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
|
||||
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
|
||||
}
|
||||
|
||||
void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) {
|
||||
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
|
||||
|
||||
if (!*PDEBUGOVERLAY)
|
||||
return;
|
||||
|
||||
void CHyprDebugOverlay::frameData(CMonitor* pMonitor) {
|
||||
m_mMonitorOverlays[pMonitor].frameData(pMonitor);
|
||||
}
|
||||
|
||||
void CHyprDebugOverlay::draw() {
|
||||
|
||||
const auto PMONITOR = g_pCompositor->m_vMonitors.front();
|
||||
const auto PMONITOR = g_pCompositor->m_vMonitors.front().get();
|
||||
|
||||
if (!m_pCairoSurface || !m_pCairo) {
|
||||
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
||||
@@ -251,7 +218,7 @@ void CHyprDebugOverlay::draw() {
|
||||
// draw the things
|
||||
int offsetY = 0;
|
||||
for (auto const& m : g_pCompositor->m_vMonitors) {
|
||||
offsetY += m_mMonitorOverlays[m].draw(offsetY);
|
||||
offsetY += m_mMonitorOverlays[m.get()].draw(offsetY);
|
||||
offsetY += 5; // for padding between mons
|
||||
}
|
||||
|
||||
@@ -271,8 +238,6 @@ void CHyprDebugOverlay::draw() {
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../render/Texture.hpp"
|
||||
#include <cairo/cairo.h>
|
||||
#include <map>
|
||||
#include <deque>
|
||||
#include <cairo/cairo.h>
|
||||
#include <unordered_map>
|
||||
|
||||
class CHyprRenderer;
|
||||
|
||||
@@ -12,9 +13,9 @@ class CHyprMonitorDebugOverlay {
|
||||
public:
|
||||
int draw(int offset);
|
||||
|
||||
void renderData(PHLMONITOR pMonitor, float durationUs);
|
||||
void renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs);
|
||||
void frameData(PHLMONITOR pMonitor);
|
||||
void renderData(CMonitor* pMonitor, float durationUs);
|
||||
void renderDataNoOverlay(CMonitor* pMonitor, float durationUs);
|
||||
void frameData(CMonitor* pMonitor);
|
||||
|
||||
private:
|
||||
std::deque<float> m_dLastFrametimes;
|
||||
@@ -22,7 +23,7 @@ class CHyprMonitorDebugOverlay {
|
||||
std::deque<float> m_dLastRenderTimesNoOverlay;
|
||||
std::deque<float> m_dLastAnimationTicks;
|
||||
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
|
||||
PHLMONITORREF m_pMonitor;
|
||||
CMonitor* m_pMonitor = nullptr;
|
||||
CBox m_wbLastDrawnBox;
|
||||
|
||||
friend class CHyprRenderer;
|
||||
@@ -32,20 +33,20 @@ class CHyprDebugOverlay {
|
||||
public:
|
||||
CHyprDebugOverlay();
|
||||
void draw();
|
||||
void renderData(PHLMONITOR, float durationUs);
|
||||
void renderDataNoOverlay(PHLMONITOR, float durationUs);
|
||||
void frameData(PHLMONITOR);
|
||||
void renderData(CMonitor*, float durationUs);
|
||||
void renderDataNoOverlay(CMonitor*, float durationUs);
|
||||
void frameData(CMonitor*);
|
||||
|
||||
private:
|
||||
std::map<PHLMONITORREF, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
|
||||
std::unordered_map<CMonitor*, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
|
||||
|
||||
cairo_surface_t* m_pCairoSurface = nullptr;
|
||||
cairo_t* m_pCairo = nullptr;
|
||||
cairo_surface_t* m_pCairoSurface = nullptr;
|
||||
cairo_t* m_pCairo = nullptr;
|
||||
|
||||
SP<CTexture> m_pTexture;
|
||||
SP<CTexture> m_pTexture;
|
||||
|
||||
friend class CHyprMonitorDebugOverlay;
|
||||
friend class CHyprRenderer;
|
||||
};
|
||||
|
||||
inline UP<CHyprDebugOverlay> g_pDebugOverlay;
|
||||
inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay;
|
@@ -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) {
|
||||
@@ -23,10 +18,10 @@ static inline auto iconBackendFromLayout(PangoLayout* layout) {
|
||||
|
||||
CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
||||
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
|
||||
if (m_vNotifications.size() == 0)
|
||||
if (m_dNotifications.size() == 0)
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->damageBox(m_bLastDamage);
|
||||
g_pHyprRenderer->damageBox(&m_bLastDamage);
|
||||
});
|
||||
|
||||
m_pTexture = makeShared<CTexture>();
|
||||
@@ -39,34 +34,34 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() {
|
||||
cairo_surface_destroy(m_pCairoSurface);
|
||||
}
|
||||
|
||||
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();
|
||||
void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) {
|
||||
const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
|
||||
|
||||
PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text;
|
||||
PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color;
|
||||
PNOTIF->text = text;
|
||||
PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color;
|
||||
PNOTIF->started.reset();
|
||||
PNOTIF->timeMs = timeMs;
|
||||
PNOTIF->icon = icon;
|
||||
PNOTIF->fontSize = fontSize;
|
||||
|
||||
for (auto const& m : g_pCompositor->m_vMonitors) {
|
||||
g_pCompositor->scheduleFrameForMonitor(m);
|
||||
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprNotificationOverlay::dismissNotifications(const int amount) {
|
||||
if (amount == -1)
|
||||
m_vNotifications.clear();
|
||||
m_dNotifications.clear();
|
||||
else {
|
||||
const int AMT = std::min(amount, static_cast<int>(m_vNotifications.size()));
|
||||
const int AMT = std::min(amount, static_cast<int>(m_dNotifications.size()));
|
||||
|
||||
for (int i = 0; i < AMT; ++i) {
|
||||
m_vNotifications.erase(m_vNotifications.begin());
|
||||
m_dNotifications.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
|
||||
CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
||||
static constexpr auto ANIM_DURATION_MS = 600.0;
|
||||
static constexpr auto ANIM_LAG_MS = 100.0;
|
||||
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
|
||||
@@ -92,7 +87,7 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
|
||||
const auto iconBackendID = iconBackendFromLayout(layout);
|
||||
const auto PBEZIER = g_pAnimationManager->getBezier("default");
|
||||
|
||||
for (auto const& notif : m_vNotifications) {
|
||||
for (auto const& notif : m_dNotifications) {
|
||||
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
|
||||
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
|
||||
|
||||
@@ -187,12 +182,12 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
|
||||
g_object_unref(layout);
|
||||
|
||||
// cleanup notifs
|
||||
std::erase_if(m_vNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
|
||||
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
|
||||
|
||||
return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
|
||||
}
|
||||
|
||||
void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
|
||||
void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
|
||||
|
||||
const auto MONSIZE = pMonitor->vecTransformedSize;
|
||||
|
||||
@@ -210,7 +205,7 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
|
||||
}
|
||||
|
||||
// Draw the notifications
|
||||
if (m_vNotifications.size() == 0)
|
||||
if (m_dNotifications.size() == 0)
|
||||
return;
|
||||
|
||||
// Render to the monitor
|
||||
@@ -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,14 +241,10 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||
|
||||
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() {
|
||||
return !m_vNotifications.empty();
|
||||
return !m_dNotifications.empty();
|
||||
}
|
||||
|
@@ -2,14 +2,15 @@
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/Timer.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../render/Texture.hpp"
|
||||
#include "../SharedDefs.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
enum eIconBackend : uint8_t {
|
||||
enum eIconBackend {
|
||||
ICONS_BACKEND_NONE = 0,
|
||||
ICONS_BACKEND_NF,
|
||||
ICONS_BACKEND_FA
|
||||
@@ -18,17 +19,17 @@ enum eIconBackend : uint8_t {
|
||||
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
|
||||
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""},
|
||||
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
|
||||
static const std::array<CHyprColor, ICON_NONE + 1> ICONS_COLORS = {CHyprColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
|
||||
CHyprColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
|
||||
CHyprColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
|
||||
CHyprColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
|
||||
CHyprColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
|
||||
CHyprColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
|
||||
CHyprColor{0, 0, 0, 1.0}};
|
||||
static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
|
||||
CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
|
||||
CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
|
||||
CColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
|
||||
CColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
|
||||
CColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
|
||||
CColor{0, 0, 0, 1.0}};
|
||||
|
||||
struct SNotification {
|
||||
std::string text = "";
|
||||
CHyprColor color;
|
||||
CColor color;
|
||||
CTimer started;
|
||||
float timeMs = 0;
|
||||
eIcons icon = ICON_NONE;
|
||||
@@ -40,24 +41,24 @@ class CHyprNotificationOverlay {
|
||||
CHyprNotificationOverlay();
|
||||
~CHyprNotificationOverlay();
|
||||
|
||||
void draw(PHLMONITOR pMonitor);
|
||||
void addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
|
||||
void draw(CMonitor* pMonitor);
|
||||
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
|
||||
void dismissNotifications(const int amount);
|
||||
bool hasAny();
|
||||
|
||||
private:
|
||||
CBox drawNotifications(PHLMONITOR pMonitor);
|
||||
CBox m_bLastDamage;
|
||||
CBox drawNotifications(CMonitor* pMonitor);
|
||||
CBox m_bLastDamage;
|
||||
|
||||
std::vector<UP<SNotification>> m_vNotifications;
|
||||
std::deque<std::unique_ptr<SNotification>> m_dNotifications;
|
||||
|
||||
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);
|
||||
CMonitor* m_pLastMonitor = nullptr;
|
||||
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;
|
||||
|
@@ -1,9 +1,10 @@
|
||||
#include "Log.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "RollingLogFollow.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <print>
|
||||
#include <iostream>
|
||||
#include <fcntl.h>
|
||||
|
||||
void Debug::init(const std::string& IS) {
|
||||
@@ -17,7 +18,7 @@ void Debug::close() {
|
||||
logOfs.close();
|
||||
}
|
||||
|
||||
void Debug::log(eLogLevel level, std::string str) {
|
||||
void Debug::log(LogLevel level, std::string str) {
|
||||
if (level == TRACE && !trace)
|
||||
return;
|
||||
|
||||
@@ -25,7 +26,6 @@ void Debug::log(eLogLevel level, std::string str) {
|
||||
return;
|
||||
|
||||
std::string coloredStr = str;
|
||||
//NOLINTBEGIN
|
||||
switch (level) {
|
||||
case LOG:
|
||||
str = "[LOG] " + str;
|
||||
@@ -53,14 +53,13 @@ void Debug::log(eLogLevel level, std::string str) {
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
//NOLINTEND
|
||||
|
||||
rollingLog += str + "\n";
|
||||
if (rollingLog.size() > ROLLING_LOG_SIZE)
|
||||
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
|
||||
|
||||
if (SRollingLogFollow::get().isRunning())
|
||||
SRollingLogFollow::get().addLog(str);
|
||||
if (RollingLogFollow::Get().IsRunning())
|
||||
RollingLogFollow::Get().AddLog(str);
|
||||
|
||||
if (!disableLogs || !**disableLogs) {
|
||||
// log to a file
|
||||
@@ -70,5 +69,5 @@ void Debug::log(eLogLevel level, std::string str) {
|
||||
|
||||
// log it to the stdout too.
|
||||
if (!disableStdout)
|
||||
std::println("{}", ((coloredLogs && !**coloredLogs) ? str : coloredStr));
|
||||
std::cout << ((coloredLogs && !**coloredLogs) ? str : coloredStr) << "\n";
|
||||
}
|
||||
|
@@ -5,11 +5,13 @@
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include "../includes.hpp"
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
|
||||
#define LOGMESSAGESIZE 1024
|
||||
#define ROLLING_LOG_SIZE 4096
|
||||
|
||||
enum eLogLevel : int8_t {
|
||||
enum LogLevel {
|
||||
NONE = -1,
|
||||
LOG = 0,
|
||||
WARN,
|
||||
@@ -19,7 +21,6 @@ enum eLogLevel : int8_t {
|
||||
TRACE
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
namespace Debug {
|
||||
inline std::string logFile;
|
||||
inline std::ofstream logOfs;
|
||||
@@ -37,11 +38,10 @@ namespace Debug {
|
||||
void close();
|
||||
|
||||
//
|
||||
void log(eLogLevel level, std::string str);
|
||||
void log(LogLevel level, std::string str);
|
||||
|
||||
template <typename... Args>
|
||||
//NOLINTNEXTLINE
|
||||
void log(eLogLevel level, std::format_string<Args...> fmt, Args&&... args) {
|
||||
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
|
||||
std::lock_guard<std::mutex> guard(logMutex);
|
||||
|
||||
if (level == TRACE && !trace)
|
||||
|
@@ -2,9 +2,8 @@
|
||||
|
||||
#include <shared_mutex>
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
namespace Debug {
|
||||
struct SRollingLogFollow {
|
||||
struct RollingLogFollow {
|
||||
std::unordered_map<int, std::string> socketToRollingLogFollowQueue;
|
||||
std::shared_mutex m;
|
||||
bool running = false;
|
||||
@@ -16,12 +15,12 @@ namespace Debug {
|
||||
return socketToRollingLogFollowQueue[socket].empty();
|
||||
}
|
||||
|
||||
std::string debugInfo() {
|
||||
std::string DebugInfo() {
|
||||
std::shared_lock<std::shared_mutex> r(m);
|
||||
return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size());
|
||||
}
|
||||
|
||||
std::string getLog(int socket) {
|
||||
std::string GetLog(int socket) {
|
||||
std::unique_lock<std::shared_mutex> w(m);
|
||||
|
||||
const std::string ret = socketToRollingLogFollowQueue[socket];
|
||||
@@ -30,7 +29,7 @@ namespace Debug {
|
||||
return ret;
|
||||
};
|
||||
|
||||
void addLog(const std::string& log) {
|
||||
void AddLog(std::string log) {
|
||||
std::unique_lock<std::shared_mutex> w(m);
|
||||
running = true;
|
||||
std::vector<int> to_erase;
|
||||
@@ -38,26 +37,26 @@ namespace Debug {
|
||||
socketToRollingLogFollowQueue[p.first] += log + "\n";
|
||||
}
|
||||
|
||||
bool isRunning() {
|
||||
bool IsRunning() {
|
||||
std::shared_lock<std::shared_mutex> r(m);
|
||||
return running;
|
||||
}
|
||||
|
||||
void stopFor(int socket) {
|
||||
void StopFor(int socket) {
|
||||
std::unique_lock<std::shared_mutex> w(m);
|
||||
socketToRollingLogFollowQueue.erase(socket);
|
||||
if (socketToRollingLogFollowQueue.empty())
|
||||
running = false;
|
||||
}
|
||||
|
||||
void startFor(int socket) {
|
||||
void StartFor(int socket) {
|
||||
std::unique_lock<std::shared_mutex> w(m);
|
||||
socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket);
|
||||
running = true;
|
||||
}
|
||||
|
||||
static SRollingLogFollow& get() {
|
||||
static SRollingLogFollow instance;
|
||||
static RollingLogFollow& Get() {
|
||||
static RollingLogFollow instance;
|
||||
static std::mutex gm;
|
||||
std::lock_guard<std::mutex> lock(gm);
|
||||
return instance;
|
||||
|
@@ -1,5 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "includes.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "helpers/Color.hpp"
|
||||
|
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
#include "../macros.hpp"
|
||||
class CWorkspace;
|
||||
class CWindow;
|
||||
class CLayerSurface;
|
||||
class CMonitor;
|
||||
|
||||
/* Shared pointer to a workspace */
|
||||
typedef SP<CWorkspace> PHLWORKSPACE;
|
||||
@@ -19,8 +18,3 @@ typedef WP<CWindow> PHLWINDOWREF;
|
||||
typedef SP<CLayerSurface> PHLLS;
|
||||
/* Weak pointer to a layer surface */
|
||||
typedef WP<CLayerSurface> PHLLSREF;
|
||||
|
||||
/* Shared pointer to a monitor */
|
||||
typedef SP<CMonitor> PHLMONITOR;
|
||||
/* Weak pointer to a monitor */
|
||||
typedef WP<CMonitor> PHLMONITORREF;
|
||||
|
@@ -1,38 +0,0 @@
|
||||
#include <re2/re2.h>
|
||||
#include "LayerRule.hpp"
|
||||
#include <unordered_set>
|
||||
#include <algorithm>
|
||||
#include "../debug/Log.hpp"
|
||||
|
||||
static const auto RULES = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
|
||||
static const auto RULES_PREFIX = std::unordered_set<std::string>{"ignorealpha", "ignorezero", "xray", "animation", "order"};
|
||||
|
||||
CLayerRule::CLayerRule(const std::string& rule_, const std::string& ns_) : targetNamespace(ns_), rule(rule_) {
|
||||
const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule_](const auto& prefix) { return rule_.starts_with(prefix); });
|
||||
|
||||
if (!VALID)
|
||||
return;
|
||||
|
||||
if (rule == "noanim")
|
||||
ruleType = RULE_NOANIM;
|
||||
else if (rule == "blur")
|
||||
ruleType = RULE_BLUR;
|
||||
else if (rule == "blurpopups")
|
||||
ruleType = RULE_BLURPOPUPS;
|
||||
else if (rule == "dimaround")
|
||||
ruleType = RULE_DIMAROUND;
|
||||
else if (rule.starts_with("ignorealpha"))
|
||||
ruleType = RULE_IGNOREALPHA;
|
||||
else if (rule.starts_with("ignorezero"))
|
||||
ruleType = RULE_IGNOREZERO;
|
||||
else if (rule.starts_with("xray"))
|
||||
ruleType = RULE_XRAY;
|
||||
else if (rule.starts_with("animation"))
|
||||
ruleType = RULE_ANIMATION;
|
||||
else if (rule.starts_with("order"))
|
||||
ruleType = RULE_ORDER;
|
||||
else {
|
||||
Debug::log(ERR, "CLayerRule: didn't match a rule that was found valid?!");
|
||||
ruleType = RULE_INVALID;
|
||||
}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include "Rule.hpp"
|
||||
|
||||
class CLayerRule {
|
||||
public:
|
||||
CLayerRule(const std::string& rule, const std::string& targetNS);
|
||||
|
||||
enum eRuleType : uint8_t {
|
||||
RULE_INVALID = 0,
|
||||
RULE_NOANIM,
|
||||
RULE_BLUR,
|
||||
RULE_BLURPOPUPS,
|
||||
RULE_DIMAROUND,
|
||||
RULE_IGNOREALPHA,
|
||||
RULE_IGNOREZERO,
|
||||
RULE_XRAY,
|
||||
RULE_ANIMATION,
|
||||
RULE_ORDER,
|
||||
RULE_ZUMBA,
|
||||
};
|
||||
|
||||
eRuleType ruleType = RULE_INVALID;
|
||||
|
||||
const std::string targetNamespace;
|
||||
const std::string rule;
|
||||
|
||||
CRuleRegexContainer targetNamespaceRegex;
|
||||
};
|
@@ -4,18 +4,11 @@
|
||||
#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));
|
||||
PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource));
|
||||
|
||||
auto pMonitor = resource->monitor.empty() ? g_pCompositor->m_pLastMonitor.lock() : g_pCompositor->getMonitorFromName(resource->monitor);
|
||||
CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor);
|
||||
|
||||
pLS->surface->assign(resource->surface.lock(), pLS);
|
||||
|
||||
@@ -25,26 +18,29 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
|
||||
}
|
||||
|
||||
if (pMonitor->pMirrorOf)
|
||||
pMonitor = g_pCompositor->m_vMonitors.front();
|
||||
pMonitor = g_pCompositor->m_vMonitors.front().get();
|
||||
|
||||
pLS->self = pLS;
|
||||
|
||||
pLS->szNamespace = resource->layerNamespace;
|
||||
|
||||
pLS->layer = resource->current.layer;
|
||||
pLS->popupHead = CPopup::create(pLS);
|
||||
pLS->monitor = pMonitor;
|
||||
pLS->popupHead = std::make_unique<CPopup>(pLS);
|
||||
pLS->monitorID = pMonitor->ID;
|
||||
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,9 +48,9 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
|
||||
}
|
||||
|
||||
void CLayerSurface::registerCallbacks() {
|
||||
alpha->setUpdateCallback([this](auto) {
|
||||
alpha.setUpdateCallback([this](void*) {
|
||||
if (dimAround)
|
||||
g_pHyprRenderer->damageMonitor(monitor.lock());
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(monitorID));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -86,9 +82,9 @@ CLayerSurface::~CLayerSurface() {
|
||||
void CLayerSurface::onDestroy() {
|
||||
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get());
|
||||
|
||||
const auto PMONITOR = monitor.lock();
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
|
||||
|
||||
if (!PMONITOR)
|
||||
if (!g_pCompositor->getMonitorFromID(monitorID))
|
||||
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
|
||||
|
||||
if (!fadingOut) {
|
||||
@@ -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;
|
||||
@@ -142,7 +137,7 @@ void CLayerSurface::onMap() {
|
||||
g_pCompositor->removeFromFadingOutSafe(self.lock());
|
||||
|
||||
// fix if it changed its mon
|
||||
const auto PMONITOR = monitor.lock();
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
|
||||
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
@@ -179,8 +174,9 @@ 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);
|
||||
const bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
|
||||
g_pHyprRenderer->damageBox(&geomFixed);
|
||||
const auto WORKSPACE = PMONITOR->activeWorkspace;
|
||||
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN;
|
||||
|
||||
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
|
||||
readyToDelete = false;
|
||||
@@ -201,7 +197,7 @@ void CLayerSurface::onUnmap() {
|
||||
|
||||
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
|
||||
|
||||
if (!monitor || g_pCompositor->m_bUnsafeState) {
|
||||
if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
|
||||
|
||||
g_pCompositor->addToFadingOutSafe(self.lock());
|
||||
@@ -215,7 +211,7 @@ void CLayerSurface::onUnmap() {
|
||||
}
|
||||
|
||||
// make a snapshot and start fade
|
||||
g_pHyprRenderer->makeLayerSnapshot(self.lock());
|
||||
g_pHyprOpenGL->makeLayerSnapshot(self.lock());
|
||||
|
||||
startAnimation(false);
|
||||
|
||||
@@ -225,9 +221,9 @@ void CLayerSurface::onUnmap() {
|
||||
|
||||
g_pCompositor->addToFadingOutSafe(self.lock());
|
||||
|
||||
const auto PMONITOR = monitor.lock();
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
|
||||
|
||||
const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == surface->resource() || g_pSeatManager->state.pointerFocus == surface->resource();
|
||||
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
|
||||
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
@@ -236,17 +232,17 @@ void CLayerSurface::onUnmap() {
|
||||
// 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()))
|
||||
g_pInputManager->refocusLastWindow(PMONITOR);
|
||||
else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource())
|
||||
else if (g_pCompositor->m_pLastFocus)
|
||||
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -260,13 +256,13 @@ void CLayerSurface::onCommit() {
|
||||
if (layerSurface->surface && !layerSurface->surface->current.texture) {
|
||||
fadingOut = false;
|
||||
geometry = {};
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(monitorID());
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(monitorID);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PMONITOR = monitor.lock();
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
|
||||
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
@@ -275,7 +271,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) {
|
||||
@@ -312,31 +308,21 @@ 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)) {
|
||||
bool WASLASTFOCUS = false;
|
||||
layerSurface->surface->breadthfirst(
|
||||
[&WASLASTFOCUS](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->state.keyboardFocus == surf; },
|
||||
nullptr);
|
||||
if (!WASLASTFOCUS && popupHead) {
|
||||
popupHead->breadthfirst(
|
||||
[&WASLASTFOCUS](WP<CPopup> popup, void* data) {
|
||||
WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource());
|
||||
},
|
||||
nullptr);
|
||||
}
|
||||
if (mapped) {
|
||||
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
|
||||
const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
|
||||
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
|
||||
|
||||
@@ -346,13 +332,11 @@ void CLayerSurface::onCommit() {
|
||||
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
|
||||
|
||||
// if the surface was focused and interactive but now isn't, refocus
|
||||
if (WASLASTFOCUS && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) {
|
||||
if (WASLASTFOCUS && !layerSurface->current.interactivity) {
|
||||
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
|
||||
// so unfocus the surface here.
|
||||
g_pCompositor->focusSurface(nullptr);
|
||||
g_pInputManager->refocusLastWindow(monitor.lock());
|
||||
} else if (WASLASTFOCUS && WASEXCLUSIVE && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) {
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID));
|
||||
} else if (!WASEXCLUSIVE && ISEXCLUSIVE) {
|
||||
// if now exclusive and not previously
|
||||
g_pSeatManager->setGrab(nullptr);
|
||||
@@ -383,73 +367,54 @@ void CLayerSurface::applyRules() {
|
||||
animationStyle.reset();
|
||||
|
||||
for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) {
|
||||
switch (rule->ruleType) {
|
||||
case CLayerRule::RULE_NOANIM: {
|
||||
noAnimations = true;
|
||||
break;
|
||||
}
|
||||
case CLayerRule::RULE_BLUR: {
|
||||
forceBlur = true;
|
||||
break;
|
||||
}
|
||||
case CLayerRule::RULE_BLURPOPUPS: {
|
||||
forceBlurPopups = true;
|
||||
break;
|
||||
}
|
||||
case CLayerRule::RULE_IGNOREALPHA:
|
||||
case CLayerRule::RULE_IGNOREZERO: {
|
||||
const auto FIRST_SPACE_POS = rule->rule.find_first_of(' ');
|
||||
std::string alphaValue = "";
|
||||
if (FIRST_SPACE_POS != std::string::npos)
|
||||
alphaValue = rule->rule.substr(FIRST_SPACE_POS + 1);
|
||||
if (rule.rule == "noanim")
|
||||
noAnimations = true;
|
||||
else if (rule.rule == "blur")
|
||||
forceBlur = true;
|
||||
else if (rule.rule == "blurpopups")
|
||||
forceBlurPopups = true;
|
||||
else if (rule.rule.starts_with("ignorealpha") || rule.rule.starts_with("ignorezero")) {
|
||||
const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
|
||||
std::string alphaValue = "";
|
||||
if (FIRST_SPACE_POS != std::string::npos)
|
||||
alphaValue = rule.rule.substr(FIRST_SPACE_POS + 1);
|
||||
|
||||
try {
|
||||
ignoreAlpha = true;
|
||||
if (!alphaValue.empty())
|
||||
ignoreAlphaValue = std::stof(alphaValue);
|
||||
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
|
||||
break;
|
||||
}
|
||||
case CLayerRule::RULE_DIMAROUND: {
|
||||
dimAround = true;
|
||||
break;
|
||||
}
|
||||
case CLayerRule::RULE_XRAY: {
|
||||
CVarList vars{rule->rule, 0, ' '};
|
||||
try {
|
||||
xray = configStringToInt(vars[1]).value_or(false);
|
||||
} catch (...) {}
|
||||
break;
|
||||
}
|
||||
case CLayerRule::RULE_ANIMATION: {
|
||||
CVarList vars{rule->rule, 2, 's'};
|
||||
animationStyle = vars[1];
|
||||
break;
|
||||
}
|
||||
case CLayerRule::RULE_ORDER: {
|
||||
CVarList vars{rule->rule, 2, 's'};
|
||||
try {
|
||||
order = std::stoi(vars[1]);
|
||||
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
try {
|
||||
ignoreAlpha = true;
|
||||
if (!alphaValue.empty())
|
||||
ignoreAlphaValue = std::stof(alphaValue);
|
||||
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
|
||||
} else if (rule.rule == "dimaround") {
|
||||
dimAround = true;
|
||||
} else if (rule.rule.starts_with("xray")) {
|
||||
CVarList vars{rule.rule, 0, ' '};
|
||||
try {
|
||||
xray = configStringToInt(vars[1]);
|
||||
} catch (...) {}
|
||||
} else if (rule.rule.starts_with("animation")) {
|
||||
CVarList vars{rule.rule, 2, 's'};
|
||||
animationStyle = vars[1];
|
||||
} else if (rule.rule.starts_with("order")) {
|
||||
CVarList vars{rule.rule, 2, 's'};
|
||||
try {
|
||||
order = std::stoi(vars[1]);
|
||||
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -490,9 +455,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;
|
||||
|
||||
@@ -517,11 +482,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")) {
|
||||
@@ -540,25 +505,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)
|
||||
@@ -569,7 +534,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() {
|
||||
@@ -577,22 +542,6 @@ 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;
|
||||
}
|
||||
|
@@ -5,6 +5,11 @@
|
||||
#include "WLSurface.hpp"
|
||||
#include "../helpers/AnimatedVariable.hpp"
|
||||
|
||||
struct SLayerRule {
|
||||
std::string targetNamespace = "";
|
||||
std::string rule = "";
|
||||
};
|
||||
|
||||
class CLayerShellResource;
|
||||
|
||||
class CLayerSurface {
|
||||
@@ -17,17 +22,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;
|
||||
@@ -37,7 +42,7 @@ class CLayerSurface {
|
||||
bool mapped = false;
|
||||
uint32_t layer = 0;
|
||||
|
||||
PHLMONITORREF monitor;
|
||||
MONITORID monitorID = -1;
|
||||
|
||||
bool fadingOut = false;
|
||||
bool readyToDelete = false;
|
||||
@@ -59,15 +64,12 @@ 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();
|
||||
void onUnmap();
|
||||
void onCommit();
|
||||
MONITORID monitorID();
|
||||
|
||||
private:
|
||||
struct {
|
||||
@@ -81,6 +83,6 @@ class CLayerSurface {
|
||||
|
||||
// For the list lookup
|
||||
bool operator==(const CLayerSurface& rhs) const {
|
||||
return layerSurface == rhs.layerSurface && monitor == rhs.monitor;
|
||||
return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID;
|
||||
}
|
||||
};
|
||||
|
@@ -4,45 +4,27 @@
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#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_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_pLayerOwner = pOwner->m_pLayerOwner;
|
||||
m_pWindowOwner = pOwner->m_pWindowOwner;
|
||||
|
||||
popup->initAllSignals();
|
||||
return popup;
|
||||
m_vLastSize = popup->surface->current.geometry.size();
|
||||
reposition();
|
||||
|
||||
initAllSignals();
|
||||
}
|
||||
|
||||
CPopup::~CPopup() {
|
||||
@@ -73,8 +55,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 +80,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();
|
||||
@@ -125,37 +106,31 @@ void CPopup::onUnmap() {
|
||||
return;
|
||||
}
|
||||
|
||||
m_bMapped = false;
|
||||
|
||||
m_vLastSize = m_pResource->surface->surface->current.size;
|
||||
|
||||
const auto COORDS = coordsGlobal();
|
||||
|
||||
CBox box = m_pWLSurface->resource()->extends();
|
||||
box.translate(COORDS).expand(4);
|
||||
g_pHyprRenderer->damageBox(box);
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
|
||||
m_pSubsurfaceHead.reset();
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
|
||||
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
|
||||
|
||||
// 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();
|
||||
|
||||
// if (WASLASTFOCUS)
|
||||
// g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
|
||||
void CPopup::onCommit(bool ignoreSiblings) {
|
||||
@@ -187,10 +162,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 +215,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 +239,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 +257,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 +288,16 @@ 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*> nodes, std::function<void(CPopup*, void*)> fn, void* data) {
|
||||
for (auto const& n : nodes) {
|
||||
fn(n, data);
|
||||
}
|
||||
|
||||
std::vector<WP<CPopup>> nodes2;
|
||||
nodes2.reserve(nodes.size() * 2);
|
||||
std::vector<CPopup*> nodes2;
|
||||
|
||||
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 +305,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)
|
||||
if (!p->m_pResource)
|
||||
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;
|
||||
}
|
||||
|
@@ -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,21 @@ 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;
|
||||
|
||||
@@ -62,11 +57,12 @@ class CPopup {
|
||||
|
||||
bool m_bRequestedReposition = false;
|
||||
|
||||
bool m_bInert = false;
|
||||
bool m_bInert = false;
|
||||
bool m_bMapped = 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*> nodes, std::function<void(CPopup*, void*)> fn, void* data);
|
||||
};
|
||||
|
@@ -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;
|
||||
}
|
@@ -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;
|
||||
};
|
@@ -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();
|
||||
|
||||
|
@@ -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();
|
||||
};
|
@@ -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;
|
||||
|
@@ -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;
|
||||
};
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#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,26 +12,23 @@
|
||||
#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;
|
||||
|
||||
enum eIdleInhibitMode : uint8_t {
|
||||
enum eIdleInhibitMode {
|
||||
IDLEINHIBIT_NONE = 0,
|
||||
IDLEINHIBIT_ALWAYS,
|
||||
IDLEINHIBIT_FULLSCREEN,
|
||||
IDLEINHIBIT_FOCUS
|
||||
};
|
||||
|
||||
enum eGroupRules : uint8_t {
|
||||
enum eGroupRules {
|
||||
// effective only during first map, except for _ALWAYS variant
|
||||
GROUP_NONE = 0,
|
||||
GROUP_SET = 1 << 0, // Open as new group or add to focused group
|
||||
@@ -43,7 +40,7 @@ enum eGroupRules : uint8_t {
|
||||
GROUP_OVERRIDE = 1 << 6, // Override other rules
|
||||
};
|
||||
|
||||
enum eGetWindowProperties : uint8_t {
|
||||
enum eGetWindowProperties {
|
||||
WINDOW_ONLY = 0,
|
||||
RESERVED_EXTENTS = 1 << 0,
|
||||
INPUT_EXTENTS = 1 << 1,
|
||||
@@ -53,13 +50,12 @@ enum eGetWindowProperties : uint8_t {
|
||||
USE_PROP_TILED = 1 << 5,
|
||||
};
|
||||
|
||||
enum eSuppressEvents : uint8_t {
|
||||
enum eSuppressEvents {
|
||||
SUPPRESS_NONE = 0,
|
||||
SUPPRESS_FULLSCREEN = 1 << 0,
|
||||
SUPPRESS_MAXIMIZE = 1 << 1,
|
||||
SUPPRESS_ACTIVATE = 1 << 2,
|
||||
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
|
||||
SUPPRESS_FULLSCREEN_OUTPUT = 1 << 4,
|
||||
};
|
||||
|
||||
class IWindowTransformer;
|
||||
@@ -68,7 +64,7 @@ struct SAlphaValue {
|
||||
float m_fAlpha;
|
||||
bool m_bOverride;
|
||||
|
||||
float applyAlpha(float alpha) const {
|
||||
float applyAlpha(float alpha) {
|
||||
if (m_bOverride)
|
||||
return m_fAlpha;
|
||||
else
|
||||
@@ -76,8 +72,8 @@ struct SAlphaValue {
|
||||
};
|
||||
};
|
||||
|
||||
enum eOverridePriority : uint8_t {
|
||||
PRIORITY_LAYOUT = 0,
|
||||
enum eOverridePriority {
|
||||
PRIORITY_LAYOUT,
|
||||
PRIORITY_WORKSPACE_RULE,
|
||||
PRIORITY_WINDOW_RULE,
|
||||
PRIORITY_SET_PROP,
|
||||
@@ -89,7 +85,9 @@ class CWindowOverridableVar {
|
||||
CWindowOverridableVar(T const& value, eOverridePriority priority) {
|
||||
values[priority] = value;
|
||||
}
|
||||
CWindowOverridableVar(T const& value) : defaultValue{value} {}
|
||||
CWindowOverridableVar(T const& value) {
|
||||
defaultValue = value;
|
||||
}
|
||||
|
||||
CWindowOverridableVar() = default;
|
||||
~CWindowOverridableVar() = default;
|
||||
@@ -146,13 +144,6 @@ class CWindowOverridableVar {
|
||||
unset(priority);
|
||||
}
|
||||
|
||||
operator std::optional<T>() {
|
||||
if (hasValue())
|
||||
return value();
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<eOverridePriority, T> values;
|
||||
T defaultValue; // used for toggling, so required for bool
|
||||
@@ -186,20 +177,34 @@ struct SWindowData {
|
||||
CWindowOverridableVar<bool> renderUnfocused = false;
|
||||
|
||||
CWindowOverridableVar<int> rounding;
|
||||
CWindowOverridableVar<float> roundingPower;
|
||||
CWindowOverridableVar<int> borderSize;
|
||||
|
||||
CWindowOverridableVar<float> scrollMouse;
|
||||
CWindowOverridableVar<float> scrollTouchpad;
|
||||
|
||||
CWindowOverridableVar<std::string> animationStyle;
|
||||
CWindowOverridableVar<Vector2D> maxSize;
|
||||
CWindowOverridableVar<Vector2D> minSize;
|
||||
|
||||
CWindowOverridableVar<CGradientValueData> activeBorderColor;
|
||||
CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
|
||||
};
|
||||
|
||||
CWindowOverridableVar<bool> persistentSize;
|
||||
struct SWindowRule {
|
||||
std::string szRule;
|
||||
std::string szValue;
|
||||
|
||||
bool v2 = false;
|
||||
std::string szTitle;
|
||||
std::string szClass;
|
||||
std::string szInitialTitle;
|
||||
std::string szInitialClass;
|
||||
std::string szTag;
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
int bFullscreen = -1;
|
||||
int bPinned = -1;
|
||||
int bFocus = -1;
|
||||
std::string szFullscreenState = ""; // empty means any
|
||||
std::string szOnWorkspace = ""; // empty means any
|
||||
std::string szWorkspace = ""; // empty means any
|
||||
};
|
||||
|
||||
struct SInitialWorkspaceToken {
|
||||
@@ -207,7 +212,7 @@ struct SInitialWorkspaceToken {
|
||||
std::string workspace;
|
||||
};
|
||||
|
||||
struct SFullscreenState {
|
||||
struct sFullscreenState {
|
||||
eFullscreenMode internal = FSMODE_NONE;
|
||||
eFullscreenMode client = FSMODE_NONE;
|
||||
};
|
||||
@@ -238,8 +243,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;
|
||||
@@ -266,13 +271,13 @@ class CWindow {
|
||||
bool m_bIsFloating = false;
|
||||
bool m_bDraggingTiled = false; // for dragging around tiled windows
|
||||
bool m_bWasMaximized = false;
|
||||
SFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
|
||||
sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
|
||||
MONITORID m_iMonitorID = -1;
|
||||
std::string m_szTitle = "";
|
||||
std::string m_szClass = "";
|
||||
std::string m_szInitialTitle = "";
|
||||
std::string m_szInitialClass = "";
|
||||
PHLWORKSPACE m_pWorkspace;
|
||||
PHLMONITORREF m_pMonitor;
|
||||
|
||||
bool m_bIsMapped = false;
|
||||
|
||||
@@ -293,37 +298,33 @@ 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;
|
||||
|
||||
// For preserving pinned state when fullscreening a pinned window
|
||||
bool m_bPinFullscreened = false;
|
||||
|
||||
// urgency hint
|
||||
bool m_bIsUrgent = false;
|
||||
|
||||
@@ -332,33 +333,30 @@ class CWindow {
|
||||
|
||||
// Window decorations
|
||||
// TODO: make this a SP.
|
||||
std::vector<UP<IHyprWindowDecoration>> m_dWindowDecorations;
|
||||
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
|
||||
std::deque<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<CColor> 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;
|
||||
|
||||
// focus stuff
|
||||
bool m_bStayFocused = false;
|
||||
@@ -385,111 +383,92 @@ class CWindow {
|
||||
bool m_bTearingHint = false;
|
||||
|
||||
// stores the currently matched window rules
|
||||
std::vector<SP<CWindowRule>> m_vMatchedRules;
|
||||
std::vector<SWindowRule> m_vMatchedRules;
|
||||
|
||||
// window tags
|
||||
CTagKeeper m_tags;
|
||||
|
||||
// ANR
|
||||
PHLANIMVAR<float> m_notRespondingTint;
|
||||
|
||||
// For the list lookup
|
||||
bool operator==(const CWindow& rhs) const {
|
||||
bool operator==(const CWindow& rhs) {
|
||||
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
|
||||
m_bFadingOut == rhs.m_bFadingOut;
|
||||
}
|
||||
|
||||
// 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 getWindowMainSurfaceBox();
|
||||
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 SWindowRule& r);
|
||||
void updateDynamicRules();
|
||||
SBoxExtents getFullWindowReservedArea();
|
||||
Vector2D middle();
|
||||
bool opaque();
|
||||
float rounding();
|
||||
bool canBeTorn();
|
||||
void setSuspended(bool suspend);
|
||||
bool visibleOnMonitor(CMonitor* pMonitor);
|
||||
WORKSPACEID workspaceID();
|
||||
bool onSpecialWorkspace();
|
||||
void activate(bool force = false);
|
||||
int surfacesCount();
|
||||
|
||||
CBox getWindowMainSurfaceBox() const {
|
||||
return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y};
|
||||
}
|
||||
bool isFullscreen();
|
||||
bool isEffectiveInternalFSMode(const eFullscreenMode);
|
||||
|
||||
int getRealBorderSize();
|
||||
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();
|
||||
PHLWINDOW getSwallower();
|
||||
void unsetWindowData(eOverridePriority priority);
|
||||
bool isX11OverrideRedirect();
|
||||
bool isModal();
|
||||
|
||||
// listeners
|
||||
void onAck(uint32_t serial);
|
||||
@@ -508,7 +487,7 @@ class CWindow {
|
||||
CHyprSignalListener commit;
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener activate;
|
||||
CHyprSignalListener configureRequest;
|
||||
CHyprSignalListener configure;
|
||||
CHyprSignalListener setGeometry;
|
||||
CHyprSignalListener updateState;
|
||||
CHyprSignalListener updateMetadata;
|
||||
@@ -542,42 +521,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*
|
||||
@@ -612,7 +555,7 @@ struct std::formatter<PHLWINDOW, CharT> : std::formatter<CharT> {
|
||||
if (formatWorkspace)
|
||||
std::format_to(out, ", workspace: {}", w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID);
|
||||
if (formatMonitor)
|
||||
std::format_to(out, ", monitor: {}", w->monitorID());
|
||||
std::format_to(out, ", monitor: {}", w->m_iMonitorID);
|
||||
if (formatClass)
|
||||
std::format_to(out, ", class: {}", w->m_szClass);
|
||||
return std::format_to(out, "]");
|
||||
|
@@ -1,96 +0,0 @@
|
||||
#include "WindowRule.hpp"
|
||||
#include <unordered_set>
|
||||
#include <algorithm>
|
||||
#include <re2/re2.h>
|
||||
#include "../config/ConfigManager.hpp"
|
||||
|
||||
static const auto RULES = std::unordered_set<std::string>{
|
||||
"float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", "persistentsize",
|
||||
};
|
||||
static const auto RULES_PREFIX = std::unordered_set<std::string>{
|
||||
"animation", "bordercolor", "bordersize", "center", "content", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize",
|
||||
"monitor", "move", "opacity", "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad",
|
||||
"size", "suppressevent", "tag", "workspace", "xray",
|
||||
};
|
||||
|
||||
CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) {
|
||||
const auto VALS = CVarList(rule, 2, ' ');
|
||||
const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule](auto prefix) { return rule.starts_with(prefix); }) ||
|
||||
(NWindowProperties::boolWindowProperties.find(VALS[0]) != NWindowProperties::boolWindowProperties.end()) ||
|
||||
(NWindowProperties::intWindowProperties.find(VALS[0]) != NWindowProperties::intWindowProperties.end()) ||
|
||||
(NWindowProperties::floatWindowProperties.find(VALS[0]) != NWindowProperties::floatWindowProperties.end());
|
||||
|
||||
if (!VALID)
|
||||
return;
|
||||
|
||||
if (rule == "float")
|
||||
ruleType = RULE_FLOAT;
|
||||
else if (rule == "fullscreen")
|
||||
ruleType = RULE_FULLSCREEN;
|
||||
else if (rule == "maximize")
|
||||
ruleType = RULE_MAXIMIZE;
|
||||
else if (rule == "noinitialfocus")
|
||||
ruleType = RULE_NOINITIALFOCUS;
|
||||
else if (rule == "pin")
|
||||
ruleType = RULE_PIN;
|
||||
else if (rule == "stayfocused")
|
||||
ruleType = RULE_STAYFOCUSED;
|
||||
else if (rule == "tile")
|
||||
ruleType = RULE_TILE;
|
||||
else if (rule == "renderunfocused")
|
||||
ruleType = RULE_RENDERUNFOCUSED;
|
||||
else if (rule == "persistentsize")
|
||||
ruleType = RULE_PERSISTENTSIZE;
|
||||
else if (rule.starts_with("animation"))
|
||||
ruleType = RULE_ANIMATION;
|
||||
else if (rule.starts_with("bordercolor"))
|
||||
ruleType = RULE_BORDERCOLOR;
|
||||
else if (rule.starts_with("center"))
|
||||
ruleType = RULE_CENTER;
|
||||
else if (rule.starts_with("fullscreenstate"))
|
||||
ruleType = RULE_FULLSCREENSTATE;
|
||||
else if (rule.starts_with("group"))
|
||||
ruleType = RULE_GROUP;
|
||||
else if (rule.starts_with("idleinhibit"))
|
||||
ruleType = RULE_IDLEINHIBIT;
|
||||
else if (rule.starts_with("maxsize"))
|
||||
ruleType = RULE_MAXSIZE;
|
||||
else if (rule.starts_with("minsize"))
|
||||
ruleType = RULE_MINSIZE;
|
||||
else if (rule.starts_with("monitor"))
|
||||
ruleType = RULE_MONITOR;
|
||||
else if (rule.starts_with("move"))
|
||||
ruleType = RULE_MOVE;
|
||||
else if (rule.starts_with("opacity"))
|
||||
ruleType = RULE_OPACITY;
|
||||
else if (rule.starts_with("plugin:"))
|
||||
ruleType = RULE_PLUGIN;
|
||||
else if (rule.starts_with("pseudo"))
|
||||
ruleType = RULE_PSEUDO;
|
||||
else if (rule.starts_with("size"))
|
||||
ruleType = RULE_SIZE;
|
||||
else if (rule.starts_with("suppressevent"))
|
||||
ruleType = RULE_SUPPRESSEVENT;
|
||||
else if (rule.starts_with("tag"))
|
||||
ruleType = RULE_TAG;
|
||||
else if (rule.starts_with("workspace"))
|
||||
ruleType = RULE_WORKSPACE;
|
||||
else if (rule.starts_with("prop"))
|
||||
ruleType = RULE_PROP;
|
||||
else if (rule.starts_with("content"))
|
||||
ruleType = RULE_CONTENT;
|
||||
else {
|
||||
// check if this is a prop.
|
||||
const CVarList VARS(rule, 0, 's', true);
|
||||
if (NWindowProperties::intWindowProperties.find(VARS[0]) != NWindowProperties::intWindowProperties.end() ||
|
||||
NWindowProperties::boolWindowProperties.find(VARS[0]) != NWindowProperties::boolWindowProperties.end() ||
|
||||
NWindowProperties::floatWindowProperties.find(VARS[0]) != NWindowProperties::floatWindowProperties.end()) {
|
||||
*const_cast<std::string*>(&szRule) = "prop " + rule;
|
||||
ruleType = RULE_PROP;
|
||||
Debug::log(LOG, "CWindowRule: direct prop rule found, rewritten {} -> {}", rule, szRule);
|
||||
} else {
|
||||
Debug::log(ERR, "CWindowRule: didn't match a rule that was found valid?!");
|
||||
ruleType = RULE_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,71 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include "Rule.hpp"
|
||||
|
||||
class CWindowRule {
|
||||
public:
|
||||
CWindowRule(const std::string& rule, const std::string& value, bool isV2 = false, bool isExecRule = false);
|
||||
|
||||
enum eRuleType : uint8_t {
|
||||
RULE_INVALID = 0,
|
||||
RULE_FLOAT,
|
||||
RULE_FULLSCREEN,
|
||||
RULE_MAXIMIZE,
|
||||
RULE_NOINITIALFOCUS,
|
||||
RULE_PIN,
|
||||
RULE_STAYFOCUSED,
|
||||
RULE_TILE,
|
||||
RULE_RENDERUNFOCUSED,
|
||||
RULE_ANIMATION,
|
||||
RULE_BORDERCOLOR,
|
||||
RULE_CENTER,
|
||||
RULE_FULLSCREENSTATE,
|
||||
RULE_GROUP,
|
||||
RULE_IDLEINHIBIT,
|
||||
RULE_MAXSIZE,
|
||||
RULE_MINSIZE,
|
||||
RULE_MONITOR,
|
||||
RULE_MOVE,
|
||||
RULE_OPACITY,
|
||||
RULE_PLUGIN,
|
||||
RULE_PSEUDO,
|
||||
RULE_SIZE,
|
||||
RULE_SUPPRESSEVENT,
|
||||
RULE_TAG,
|
||||
RULE_WORKSPACE,
|
||||
RULE_PROP,
|
||||
RULE_CONTENT,
|
||||
RULE_PERSISTENTSIZE,
|
||||
};
|
||||
|
||||
eRuleType ruleType = RULE_INVALID;
|
||||
|
||||
const std::string szValue;
|
||||
const std::string szRule;
|
||||
const bool v2 = false;
|
||||
const bool execRule = false;
|
||||
|
||||
std::string szTitle;
|
||||
std::string szClass;
|
||||
std::string szInitialTitle;
|
||||
std::string szInitialClass;
|
||||
std::string szTag;
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
int bFullscreen = -1;
|
||||
int bPinned = -1;
|
||||
int bFocus = -1;
|
||||
std::string szFullscreenState = ""; // empty means any
|
||||
std::string szOnWorkspace = ""; // empty means any
|
||||
std::string szWorkspace = ""; // empty means any
|
||||
std::string szContentType = ""; // empty means any
|
||||
|
||||
// precompiled regexes
|
||||
CRuleRegexContainer rTitle;
|
||||
CRuleRegexContainer rClass;
|
||||
CRuleRegexContainer rInitialTitle;
|
||||
CRuleRegexContainer rInitialClass;
|
||||
CRuleRegexContainer rV1Regex;
|
||||
};
|
@@ -1,33 +1,37 @@
|
||||
#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;
|
||||
|
||||
PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) {
|
||||
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitor, name, special, isEmpty);
|
||||
PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) {
|
||||
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmpty);
|
||||
workspace->init(workspace);
|
||||
return workspace;
|
||||
}
|
||||
|
||||
CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) :
|
||||
m_iID(id), m_szName(name), m_pMonitor(monitor), m_bIsSpecialWorkspace(special), m_bWasCreatedEmpty(isEmpty) {
|
||||
;
|
||||
CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) {
|
||||
m_iMonitorID = monitorID;
|
||||
m_iID = id;
|
||||
m_szName = name;
|
||||
m_bIsSpecialWorkspace = special;
|
||||
m_bWasCreatedEmpty = isEmpty;
|
||||
}
|
||||
|
||||
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 +58,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 +85,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;
|
||||
@@ -94,94 +103,94 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||
});
|
||||
|
||||
if (ANIMSTYLE.starts_with("slidefade")) {
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
float movePerc = 100.f;
|
||||
|
||||
if (ANIMSTYLE.find('%') != std::string::npos) {
|
||||
if (ANIMSTYLE.find("%") != std::string::npos) {
|
||||
try {
|
||||
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1);
|
||||
movePerc = std::stoi(percstr.substr(0, percstr.length() - 1));
|
||||
} 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 PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
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 PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
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 +224,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_iMonitorID == m_iMonitorID) {
|
||||
m_sPrevWorkspacePerMonitor.id = prev->m_iID;
|
||||
m_sPrevWorkspacePerMonitor.name = prev->m_szName;
|
||||
}
|
||||
}
|
||||
|
||||
std::string CWorkspace::getConfigName() {
|
||||
@@ -261,15 +273,14 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
||||
// n - named: n[true] or n[s:string] or n[e:string]
|
||||
// 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
|
||||
// -1: no fullscreen, 0: fullscreen, 1: maximized, 2: fullscreen without sending fs state to window
|
||||
|
||||
const auto CLOSING_BRACKET = selector.find_first_of(']', i);
|
||||
std::string prop = selector.substr(i, CLOSING_BRACKET == std::string::npos ? std::string::npos : CLOSING_BRACKET + 1 - i);
|
||||
i = std::min(CLOSING_BRACKET, std::string::npos - 1);
|
||||
const auto NEXTSPACE = selector.find_first_of(' ', i);
|
||||
std::string prop = selector.substr(i, NEXTSPACE == std::string::npos ? std::string::npos : NEXTSPACE - i);
|
||||
i = std::min(NEXTSPACE, std::string::npos - 1);
|
||||
|
||||
if (cur == 'r') {
|
||||
WORKSPACEID from = 0, to = 0;
|
||||
@@ -285,7 +296,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto DASHPOS = prop.find('-');
|
||||
const auto DASHPOS = prop.find("-");
|
||||
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
|
||||
|
||||
if (!isNumber(LHS) || !isNumber(RHS)) {
|
||||
@@ -321,7 +332,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
||||
|
||||
const auto SHOULDBESPECIAL = configStringToInt(prop);
|
||||
|
||||
if (SHOULDBESPECIAL && (bool)*SHOULDBESPECIAL != m_bIsSpecialWorkspace)
|
||||
if ((bool)SHOULDBESPECIAL != m_bIsSpecialWorkspace)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
@@ -336,7 +347,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromString(prop);
|
||||
|
||||
if (!(PMONITOR ? PMONITOR == m_pMonitor : false))
|
||||
if (!(PMONITOR ? PMONITOR->ID == m_iMonitorID : false))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
@@ -356,7 +367,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
||||
|
||||
const auto WANTSNAMED = configStringToInt(prop);
|
||||
|
||||
if (WANTSNAMED && *WANTSNAMED != (m_iID <= -1337))
|
||||
if (WANTSNAMED != (m_iID <= -1337))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
@@ -371,7 +382,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 +393,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++;
|
||||
@@ -415,20 +422,18 @@ 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);
|
||||
count = g_pCompositor->getGroupsOnWorkspace(m_iID, 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);
|
||||
count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
|
||||
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
|
||||
|
||||
if (count != from)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto DASHPOS = prop.find('-');
|
||||
const auto DASHPOS = prop.find("-");
|
||||
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
|
||||
|
||||
if (!isNumber(LHS) || !isNumber(RHS)) {
|
||||
@@ -451,13 +456,11 @@ 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 = g_pCompositor->getGroupsOnWorkspace(m_iID, 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);
|
||||
count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
|
||||
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
|
||||
|
||||
if (std::clamp(count, from, to) != count)
|
||||
return false;
|
||||
@@ -509,161 +512,12 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
||||
}
|
||||
|
||||
void CWorkspace::markInert() {
|
||||
m_bInert = true;
|
||||
m_iID = WORKSPACE_INVALID;
|
||||
m_bVisible = false;
|
||||
m_pMonitor.reset();
|
||||
m_bInert = true;
|
||||
m_iID = WORKSPACE_INVALID;
|
||||
m_iMonitorID = MONITOR_INVALID;
|
||||
m_bVisible = false;
|
||||
}
|
||||
|
||||
bool CWorkspace::inert() {
|
||||
return m_bInert;
|
||||
}
|
||||
|
||||
MONITORID CWorkspace::monitorID() {
|
||||
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID;
|
||||
}
|
||||
|
||||
PHLWINDOW CWorkspace::getFullscreenWindow() {
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_pWorkspace == m_pSelf && w->isFullscreen())
|
||||
return w;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CWorkspace::isVisible() {
|
||||
return m_bVisible;
|
||||
}
|
||||
|
||||
bool CWorkspace::isVisibleNotCovered() {
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
if (PMONITOR->activeSpecialWorkspace)
|
||||
return PMONITOR->activeSpecialWorkspace->m_iID == m_iID;
|
||||
|
||||
return PMONITOR->activeWorkspace->m_iID == m_iID;
|
||||
}
|
||||
|
||||
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) {
|
||||
int no = 0;
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
|
||||
continue;
|
||||
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
|
||||
continue;
|
||||
if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value())
|
||||
continue;
|
||||
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
|
||||
continue;
|
||||
no++;
|
||||
}
|
||||
|
||||
return no;
|
||||
}
|
||||
|
||||
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) {
|
||||
int no = 0;
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
|
||||
continue;
|
||||
if (!w->m_sGroupData.head)
|
||||
continue;
|
||||
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
|
||||
continue;
|
||||
if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value())
|
||||
continue;
|
||||
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
|
||||
continue;
|
||||
no++;
|
||||
}
|
||||
return no;
|
||||
}
|
||||
|
||||
PHLWINDOW CWorkspace::getFirstWindow() {
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && !w->isHidden())
|
||||
return w;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PHLWINDOW CWorkspace::getTopLeftWindow() {
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
|
||||
continue;
|
||||
|
||||
const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
|
||||
|
||||
if (WINDOWIDEALBB.x <= PMONITOR->vecPosition.x + 1 && WINDOWIDEALBB.y <= PMONITOR->vecPosition.y + 1)
|
||||
return w;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CWorkspace::hasUrgentWindow() {
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && w->m_bIsUrgent)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CWorkspace::updateWindowDecos() {
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_pWorkspace != m_pSelf)
|
||||
continue;
|
||||
|
||||
w->updateWindowDecos();
|
||||
}
|
||||
}
|
||||
|
||||
void CWorkspace::updateWindowData() {
|
||||
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock());
|
||||
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_pWorkspace != m_pSelf)
|
||||
continue;
|
||||
|
||||
w->updateWindowData(WORKSPACERULE);
|
||||
}
|
||||
}
|
||||
|
||||
void CWorkspace::forceReportSizesToWindows() {
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
|
||||
continue;
|
||||
|
||||
w->sendWindowSize(true);
|
||||
}
|
||||
}
|
||||
|
||||
void CWorkspace::rename(const std::string& name) {
|
||||
if (g_pCompositor->isWorkspaceSpecial(m_iID))
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name);
|
||||
m_szName = name;
|
||||
|
||||
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock());
|
||||
m_bPersistent = WORKSPACERULE.isPersistent;
|
||||
|
||||
if (WORKSPACERULE.isPersistent)
|
||||
g_pCompositor->ensurePersistentWorkspacesPresent(std::vector<SWorkspaceRule>{WORKSPACERULE}, m_pSelf.lock());
|
||||
|
||||
g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName});
|
||||
}
|
||||
|
||||
void CWorkspace::updateWindows() {
|
||||
m_bHasFullscreenWindow = std::ranges::any_of(g_pCompositor->m_vWindows, [this](const auto& w) { return w->m_bIsMapped && w->m_pWorkspace == m_pSelf && w->isFullscreen(); });
|
||||
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->m_pWorkspace != m_pSelf)
|
||||
continue;
|
||||
|
||||
w->updateDynamicRules();
|
||||
}
|
||||
}
|
||||
|
@@ -17,26 +17,29 @@ class CWindow;
|
||||
|
||||
class CWorkspace {
|
||||
public:
|
||||
static PHLWORKSPACE create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true);
|
||||
static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true);
|
||||
// use create() don't use this
|
||||
CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true);
|
||||
CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true);
|
||||
~CWorkspace();
|
||||
|
||||
// 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 = "";
|
||||
MONITORID m_iMonitorID = MONITOR_INVALID;
|
||||
// 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;
|
||||
@@ -60,35 +63,25 @@ class CWorkspace {
|
||||
|
||||
// Inert: destroyed and invalid. If this is true, release the ptr you have.
|
||||
bool inert();
|
||||
|
||||
void startAnim(bool in, bool left, bool instant = false);
|
||||
void setActive(bool on);
|
||||
|
||||
void moveToMonitor(const MONITORID&);
|
||||
MONITORID monitorID();
|
||||
|
||||
PHLWINDOW getLastFocusedWindow();
|
||||
void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);
|
||||
|
||||
std::string getConfigName();
|
||||
|
||||
bool matchesStaticSelector(const std::string& selector);
|
||||
|
||||
void markInert();
|
||||
SWorkspaceIDName getPrevWorkspaceIDName() 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 = {});
|
||||
bool hasUrgentWindow();
|
||||
PHLWINDOW getFirstWindow();
|
||||
PHLWINDOW getTopLeftWindow();
|
||||
PHLWINDOW getFullscreenWindow();
|
||||
bool isVisible();
|
||||
bool isVisibleNotCovered();
|
||||
void rename(const std::string& name = "");
|
||||
void forceReportSizesToWindows();
|
||||
void updateWindows();
|
||||
|
||||
SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const;
|
||||
|
||||
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;
|
||||
|
@@ -4,14 +4,14 @@
|
||||
#include <string>
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
enum eHIDCapabilityType : uint8_t {
|
||||
enum eHIDCapabilityType : uint32_t {
|
||||
HID_INPUT_CAPABILITY_KEYBOARD = (1 << 0),
|
||||
HID_INPUT_CAPABILITY_POINTER = (1 << 1),
|
||||
HID_INPUT_CAPABILITY_TOUCH = (1 << 2),
|
||||
HID_INPUT_CAPABILITY_TABLET = (1 << 3),
|
||||
};
|
||||
|
||||
enum eHIDType : uint8_t {
|
||||
enum eHIDType {
|
||||
HID_TYPE_UNKNOWN = 0,
|
||||
HID_TYPE_POINTER,
|
||||
HID_TYPE_KEYBOARD,
|
||||
@@ -27,7 +27,7 @@ enum eHIDType : uint8_t {
|
||||
*/
|
||||
class IHID {
|
||||
public:
|
||||
virtual ~IHID() = default;
|
||||
virtual ~IHID() {}
|
||||
|
||||
virtual uint32_t getCapabilities() = 0;
|
||||
virtual eHIDType getType();
|
||||
@@ -36,5 +36,5 @@ class IHID {
|
||||
CSignal destroy;
|
||||
} events;
|
||||
|
||||
std::string deviceName, hlName;
|
||||
std::string deviceName;
|
||||
};
|
@@ -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);
|
||||
|
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <optional>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
|
||||
AQUAMARINE_FORWARD(IKeyboard);
|
||||
|
||||
@@ -95,9 +94,10 @@ class IKeyboard : public IHID {
|
||||
std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID};
|
||||
uint32_t leds = 0;
|
||||
|
||||
std::string hlName = "";
|
||||
std::string xkbFilePath = "";
|
||||
std::string xkbKeymapString = "";
|
||||
Hyprutils::OS::CFileDescriptor xkbKeymapFD;
|
||||
int xkbKeymapFD = -1;
|
||||
|
||||
SStringRuleNames currentRules;
|
||||
int repeatRate = 0;
|
||||
|
@@ -17,10 +17,8 @@ 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;
|
||||
};
|
||||
|
||||
struct SMotionAbsoluteEvent {
|
||||
@@ -33,7 +31,6 @@ class IPointer : public IHID {
|
||||
uint32_t timeMs = 0;
|
||||
uint32_t button = 0;
|
||||
wl_pointer_button_state state = WL_POINTER_BUTTON_STATE_PRESSED;
|
||||
bool mouse = false;
|
||||
};
|
||||
|
||||
struct SAxisEvent {
|
||||
@@ -43,7 +40,6 @@ class IPointer : public IHID {
|
||||
wl_pointer_axis_relative_direction relativeDirection = WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL;
|
||||
double delta = 0.0;
|
||||
int32_t deltaDiscrete = 0;
|
||||
bool mouse = false;
|
||||
};
|
||||
|
||||
struct SSwipeBeginEvent {
|
||||
@@ -108,11 +104,9 @@ class IPointer : public IHID {
|
||||
CSignal holdEnd;
|
||||
} pointerEvents;
|
||||
|
||||
std::string hlName;
|
||||
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;
|
||||
};
|
||||
|
@@ -44,6 +44,7 @@ class ITouch : public IHID {
|
||||
CSignal frame;
|
||||
} touchEvents;
|
||||
|
||||
std::string hlName = "";
|
||||
std::string boundOutput = "";
|
||||
|
||||
WP<ITouch> self;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include "Keyboard.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
|
||||
|
@@ -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();
|
||||
@@ -31,8 +26,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
|
||||
.timeMs = E.timeMs,
|
||||
.delta = E.delta,
|
||||
.unaccel = E.unaccel,
|
||||
.mouse = true,
|
||||
.device = self.lock(),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,7 +46,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
|
||||
.timeMs = E.timeMs,
|
||||
.button = E.button,
|
||||
.state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
|
||||
.mouse = true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -67,7 +59,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
|
||||
.relativeDirection = (wl_pointer_axis_relative_direction)E.direction,
|
||||
.delta = E.delta,
|
||||
.deltaDiscrete = E.discrete,
|
||||
.mouse = true,
|
||||
});
|
||||
});
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user