mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-16 12:33:48 -07:00
Compare commits
367 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5ee35f914f | ||
|
aa1bd647b1 | ||
|
fdb7ca6c8f | ||
|
6ab5a0befb | ||
|
6384f4acf4 | ||
|
4600043a49 | ||
|
279b06044c | ||
|
ccbdba7ee2 | ||
|
c7f0519faf | ||
|
7ea4fbf0ba | ||
|
f6ca4bac51 | ||
|
155eba57d8 | ||
|
7b10530a0d | ||
|
a25a214523 | ||
|
c8d80a2920 | ||
|
03385fc07f | ||
|
cca0f48b74 | ||
|
60edb376f2 | ||
|
6f74d8d7e9 | ||
|
ec4bea7901 | ||
|
9171db1984 | ||
|
5f60fc7d00 | ||
|
c4f46473df | ||
|
011d7ccb91 | ||
|
efc51eb7d1 | ||
|
c2835b6b0f | ||
|
d5d7f69d1e | ||
|
5cef2f44fe | ||
|
22154fa272 | ||
|
2ddd16ef28 | ||
|
d7382aa8a1 | ||
|
90306bdae6 | ||
|
b1ab0f7539 | ||
|
bf5e4bf116 | ||
|
4c471218c9 | ||
|
e59680481d | ||
|
f4315db50f | ||
|
3cc8e8c6be | ||
|
b37944605f | ||
|
f4995c1837 | ||
|
6ffde36466 | ||
|
c754d7963f | ||
|
8c97cb7858 | ||
|
e86d3a14e4 | ||
|
4b25fbe5fd | ||
|
81e93acba4 | ||
|
b21edb1a97 | ||
|
e4af4b5e2e | ||
|
d30cc19d25 | ||
|
f15b49e0fd | ||
|
c544c5115c | ||
|
b80b64cd6c | ||
|
4082e876d5 | ||
|
8ce1665fdb | ||
|
7753e8ea68 | ||
|
cb4230e1c2 | ||
|
7055d0c138 | ||
|
4435f5c546 | ||
|
7a84317f33 | ||
|
2433760786 | ||
|
b51ab182ae | ||
|
d7e7a29261 | ||
|
f1ef724a87 | ||
|
474bfcbccd | ||
|
905ca39bc9 | ||
|
3a21dd84b3 | ||
|
e6be4af21f | ||
|
2c78867a98 | ||
|
2acbb59bf2 | ||
|
11943f761e | ||
|
f148b96bea | ||
|
445337d03d | ||
|
34f2a4713e | ||
|
d5920bc5da | ||
|
aee9b8ac19 | ||
|
32a3d84d74 | ||
|
002cd91fbf | ||
|
01f4074421 | ||
|
6787fe8933 | ||
|
f0850905f0 | ||
|
d1ea18b492 | ||
|
73ae9790f9 | ||
|
3458d7ac93 | ||
|
e59464629f | ||
|
2e81648980 | ||
|
8f50460bfe | ||
|
f4b148df1e | ||
|
0e24f9c0d5 | ||
|
2cfa5d2408 | ||
|
fa246cb6ed | ||
|
6d25ef09cd | ||
|
0137a5f6cd | ||
|
3c1a2e9fca | ||
|
fb8eaba83f | ||
|
3352317ca8 | ||
|
e59623d1d5 | ||
|
d01f9943e1 | ||
|
59c615c321 | ||
|
e2a9271150 | ||
|
897ee276dc | ||
|
94a30889a7 | ||
|
9228116c9a | ||
|
410da2e46f | ||
|
7a6fde8414 | ||
|
3eb6cb1875 | ||
|
2f967037aa | ||
|
1309b59f2c | ||
|
fb36815b01 | ||
|
df3fba1572 | ||
|
40adb3dfb4 | ||
|
5d2b008294 | ||
|
208f94fe12 | ||
|
1789405163 | ||
|
68bb3e7f0a | ||
|
f83fe9986b | ||
|
f2d43e5f21 | ||
|
e1179b665b | ||
|
f261fb6fe0 | ||
|
3a43e7bb9a | ||
|
1f97643e83 | ||
|
56f6f61596 | ||
|
8e10ddb592 | ||
|
feb8ad48f0 | ||
|
f7fcbe32c9 | ||
|
a724332eb8 | ||
|
54441e0c4e | ||
|
acbcf0cf11 | ||
|
30b49c75bf | ||
|
ff9e059de6 | ||
|
f1e32cd122 | ||
|
868b2b544a | ||
|
8a6778f0a0 | ||
|
64591c85aa | ||
|
873bff390e | ||
|
84c9baecc6 | ||
|
3b99e906df | ||
|
5e7292434a | ||
|
70cfc7cc9c | ||
|
1da0b2c02e | ||
|
708d166360 | ||
|
44004abc01 | ||
|
31431a9271 | ||
|
70d94fec13 | ||
|
373108102c | ||
|
97a24ec6f3 | ||
|
64fefa3749 | ||
|
e380b6ed66 | ||
|
88adae73ba | ||
|
c6f672257b | ||
|
5b43c106bd | ||
|
d11d069715 | ||
|
ddf180fa30 | ||
|
a4b7d1c2d7 | ||
|
12b5034c99 | ||
|
9c38287410 | ||
|
ac5668192e | ||
|
7d51dee103 | ||
|
ea16b64ec1 | ||
|
e6a9cfab91 | ||
|
ef03f69116 | ||
|
32c0fa2f2f | ||
|
7d1c78f4a3 | ||
|
d462cc7fa1 | ||
|
09ec1cca51 | ||
|
6fc9c8e479 | ||
|
6131919715 | ||
|
aaa5573c73 | ||
|
344e32d71b | ||
|
d41135d07c | ||
|
b884f1f7c8 | ||
|
3d1dd6b5c7 | ||
|
1d3904c3e7 | ||
|
529ad4eaf4 | ||
|
d3042e5358 | ||
|
d2773d7a4e | ||
|
5fd90548dc | ||
|
25d5ce4833 | ||
|
e7a72de9b5 | ||
|
cb7ed4f62b | ||
|
2a478c30ca | ||
|
04ac46c543 | ||
|
2f55806d6f | ||
|
3b207d29bd | ||
|
6bd6c5512e | ||
|
bb5b09def0 | ||
|
efe29a2461 | ||
|
e951011503 | ||
|
16aeb24bc1 | ||
|
74d0f34cf3 | ||
|
4abf9155ee | ||
|
0a28e13787 | ||
|
3cd6e3960f | ||
|
8b1d6e3009 | ||
|
445acec2a2 | ||
|
45c3787e75 | ||
|
9199a9746d | ||
|
bce58d9d65 | ||
|
f3fc8d599a | ||
|
107723bdf4 | ||
|
065e89648b | ||
|
354d4594de | ||
|
089fdd1ea0 | ||
|
1815f9a2e5 | ||
|
d8f79d7678 | ||
|
80b2fd135b | ||
|
fda9790cde | ||
|
9b3f71390c | ||
|
0e5d03a557 | ||
|
57a39984dd | ||
|
944e36ea2e | ||
|
4a1b960cbe | ||
|
5d8261aee2 | ||
|
d075d1cab9 | ||
|
bb099e5733 | ||
|
dadb2e0949 | ||
|
a8c2d5a616 | ||
|
465cf66df1 | ||
|
1a0a22ad03 | ||
|
0a1ae48a9f | ||
|
ae403e6a05 | ||
|
ae4e38d9d5 | ||
|
ecae3c5e4b | ||
|
f1bd62806e | ||
|
fda5626594 | ||
|
c90dbfab6f | ||
|
d335c8f101 | ||
|
c8a0443adc | ||
|
ce48bc5408 | ||
|
da6e966313 | ||
|
a661203bb6 | ||
|
9e8d9791c7 | ||
|
2d82a92324 | ||
|
407453166c | ||
|
8dd2cd41fb | ||
|
0a0e56d99c | ||
|
086fd7ece8 | ||
|
4da9b7cc5b | ||
|
f56153a9c1 | ||
|
a36fa5c229 | ||
|
fdfcfc824e | ||
|
d01756c1f4 | ||
|
078e13f463 | ||
|
47d645d84a | ||
|
b65f8a8723 | ||
|
401a3bae61 | ||
|
76a899627e | ||
|
b7a3c45269 | ||
|
2bad73354a | ||
|
0dc7367a70 | ||
|
52b9ae592b | ||
|
25add26881 | ||
|
f16f170433 | ||
|
a6b263713a | ||
|
4f0f512cab | ||
|
a3a7499317 | ||
|
b117fae3b4 | ||
|
2671656a75 | ||
|
2778aff08f | ||
|
9e4f90aedf | ||
|
15dc024a39 | ||
|
3b85690aa6 | ||
|
cef09fbfe6 | ||
|
a8b568c6c4 | ||
|
b5fb6110ab | ||
|
da9252a23e | ||
|
8475a8ef99 | ||
|
f9c37ca43b | ||
|
9dc9366fc6 | ||
|
85aba23cbe | ||
|
2d1ebadb9b | ||
|
e66eab7b6a | ||
|
c9822b08f9 | ||
|
983bc067da | ||
|
b320bc2dc6 | ||
|
ad64726f5d | ||
|
5fa2594659 | ||
|
75727e7c17 | ||
|
67e1e46f9b | ||
|
308b1f3afb | ||
|
c143907857 | ||
|
830350a1f7 | ||
|
95542e4488 | ||
|
5642ed331d | ||
|
c7086f936a | ||
|
b9f110ef87 | ||
|
1bf4937b02 | ||
|
6a90b50545 | ||
|
602d6b7356 | ||
|
780e3dd542 | ||
|
f1a7a7497e | ||
|
f390f48a07 | ||
|
1b06d222cf | ||
|
391ff29110 | ||
|
a5c14370c1 | ||
|
b0bae15499 | ||
|
e8317ae34d | ||
|
a25d228840 | ||
|
60f069d540 | ||
|
2e6e0e9278 | ||
|
f69e72eca1 | ||
|
b0cd9972e8 | ||
|
f3c49c1295 | ||
|
4971725b69 | ||
|
1697171fc0 | ||
|
81721b8aa8 | ||
|
365caa49ff | ||
|
94381e5999 | ||
|
42fd366046 | ||
|
cbd2451570 | ||
|
dde3e082c9 | ||
|
9f3c9ac01a | ||
|
7f177fa1cf | ||
|
d64ac47202 | ||
|
4e93b2def5 | ||
|
aff34089c4 | ||
|
1989b0049f | ||
|
9f933da1c5 | ||
|
af301312d5 | ||
|
8c14c2a5f4 | ||
|
cb211d83f6 | ||
|
fde569db65 | ||
|
5b37d53992 | ||
|
deb077c346 | ||
|
3f40d6d936 | ||
|
a364e80425 | ||
|
2b01a5bcf6 | ||
|
8d4c18d723 | ||
|
c600e1aaff | ||
|
cca0adf6a3 | ||
|
534adad6b1 | ||
|
775111b603 | ||
|
85632e7c33 | ||
|
43ca66779b | ||
|
e75e2cdac7 | ||
|
2eaa4d80a0 | ||
|
dddb64dc35 | ||
|
1a3d17da91 | ||
|
2a24a61126 | ||
|
2e2e2e2cad | ||
|
68a5842f06 | ||
|
5f7ad767db | ||
|
a4a4fffffb | ||
|
1830296df3 | ||
|
e536b02248 | ||
|
1cc1a46c2e | ||
|
31422ae25d | ||
|
57921d7dbd | ||
|
8e8073c421 | ||
|
52ee7a8748 | ||
|
71dc9f6128 | ||
|
fd67ee9ecd | ||
|
bec18dc6f9 | ||
|
5b714f05f8 | ||
|
7c43eed2c1 | ||
|
23e7d8f6a7 | ||
|
df06cb4d71 | ||
|
0fec38fe72 | ||
|
80a4852266 | ||
|
4c4471c66d | ||
|
6378c8ed65 | ||
|
49e5f9c428 | ||
|
5f1df55fcb | ||
|
e2c78c00e5 | ||
|
bd7092a9fe | ||
|
c7d9719910 | ||
|
7ae7920572 | ||
|
4b6163aef3 |
70
.github/ISSUE_TEMPLATE/bug.yml
vendored
70
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Already reported ? *
|
||||
description: Before opening a new bug report, please take a moment to search through the current open and closed issues to check if it already exists.
|
||||
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.
|
||||
options:
|
||||
- label: I have searched the existing open and closed issues.
|
||||
required: true
|
||||
@@ -19,27 +19,28 @@ 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:
|
||||
- "Yes"
|
||||
- "No"
|
||||
- "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"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: ver
|
||||
attributes:
|
||||
label: System Info and Version
|
||||
label: System Info and Hyprland Version
|
||||
description: |
|
||||
Paste the output of `hyprctl systeminfo -c` here. If you can't
|
||||
Paste the output of `hyprctl systeminfo` here. If you can't
|
||||
launch Hyprland, paste the output of `Hyprland --systeminfo`.
|
||||
If `Hyprland --systeminfo` errors out (added in 0.44.0), find
|
||||
and paste the Hyprland version manually.
|
||||
value: "<details>
|
||||
<summary>System/Version info</summary>
|
||||
|
||||
|
||||
```sh
|
||||
```
|
||||
|
||||
<Paste the output of the command here>
|
||||
<Paste the output of the command here, without removing any formatting around this>
|
||||
|
||||
```
|
||||
|
||||
@@ -61,15 +62,56 @@ 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: Crash reports, logs, images, videos
|
||||
label: Additional info & File uploads
|
||||
description: |
|
||||
Anything that can help. Please always ATTACH and not paste them.
|
||||
Logs can be found in $XDG_RUNTIME_DIR/hypr
|
||||
Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland
|
||||
|
||||
Tip: You can attach files by clicking this area to highlight it and then dragging files in.
|
||||
|
10
.github/actions/setup_base/action.yml
vendored
10
.github/actions/setup_base/action.yml
vendored
@@ -35,6 +35,7 @@ runs:
|
||||
libinput \
|
||||
libjxl \
|
||||
libliftoff \
|
||||
libspng \
|
||||
libwebp \
|
||||
libxcursor \
|
||||
libxcvt \
|
||||
@@ -63,6 +64,15 @@ runs:
|
||||
librsvg \
|
||||
re2
|
||||
|
||||
- name: Get glaze
|
||||
shell: bash
|
||||
run: |
|
||||
git clone https://github.com/stephenberry/glaze.git
|
||||
cd glaze
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
cmake --install build
|
||||
|
||||
- name: Get hyprwayland-scanner-git
|
||||
shell: bash
|
||||
run: |
|
||||
|
3
.github/workflows/ci.yaml
vendored
3
.github/workflows/ci.yaml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
- name: Build Hyprland
|
||||
run: |
|
||||
make all
|
||||
CFLAGS=-Werror CXXFLAGS=-Werror make all
|
||||
|
||||
- name: Compress and package artifacts
|
||||
run: |
|
||||
@@ -107,6 +107,7 @@ 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
Normal file
48
.github/workflows/clang-format.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
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
|
1
.github/workflows/nix-build.yml
vendored
1
.github/workflows/nix-build.yml
vendored
@@ -19,7 +19,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
|
@@ -77,6 +77,7 @@ 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
|
||||
@@ -101,13 +102,21 @@ else()
|
||||
endif()
|
||||
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
||||
|
||||
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5)
|
||||
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.2.3)
|
||||
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.1)
|
||||
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
|
||||
|
||||
string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION})
|
||||
list(GET AQ_VERSION_LIST 0 AQ_VERSION_MAJOR)
|
||||
list(GET AQ_VERSION_LIST 1 AQ_VERSION_MINOR)
|
||||
list(GET AQ_VERSION_LIST 2 AQ_VERSION_PATCH)
|
||||
|
||||
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
|
||||
add_compile_definitions(AQUAMARINE_VERSION_MAJOR=${AQ_VERSION_MAJOR})
|
||||
add_compile_definitions(AQUAMARINE_VERSION_MINOR=${AQ_VERSION_MINOR})
|
||||
add_compile_definitions(AQUAMARINE_VERSION_PATCH=${AQ_VERSION_PATCH})
|
||||
add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}")
|
||||
add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}")
|
||||
add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}")
|
||||
@@ -120,7 +129,7 @@ pkg_check_modules(
|
||||
xkbcommon
|
||||
uuid
|
||||
wayland-server>=1.22.90
|
||||
wayland-protocols
|
||||
wayland-protocols>=1.41
|
||||
cairo
|
||||
pango
|
||||
pangocairo
|
||||
@@ -197,6 +206,12 @@ 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)
|
||||
@@ -248,7 +263,15 @@ target_precompile_headers(Hyprland PRIVATE
|
||||
|
||||
message(STATUS "Setting link libraries")
|
||||
|
||||
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::hyprgraphics_dep PkgConfig::deps)
|
||||
target_link_libraries(
|
||||
Hyprland
|
||||
rt
|
||||
PkgConfig::aquamarine_dep
|
||||
PkgConfig::hyprlang_dep
|
||||
PkgConfig::hyprutils_dep
|
||||
PkgConfig::hyprcursor_dep
|
||||
PkgConfig::hyprgraphics_dep
|
||||
PkgConfig::deps)
|
||||
if(udis_dep_FOUND)
|
||||
target_link_libraries(Hyprland PkgConfig::udis_dep)
|
||||
else()
|
||||
@@ -290,7 +313,7 @@ endfunction()
|
||||
|
||||
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
|
||||
|
||||
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.4.0)
|
||||
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.2)
|
||||
if(hyprland_protocols_dep_FOUND)
|
||||
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
|
||||
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
|
||||
@@ -316,8 +339,12 @@ 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)
|
||||
@@ -350,12 +377,20 @@ 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)
|
||||
add_subdirectory(hyprpm)
|
||||
|
||||
if(NO_HYPRPM)
|
||||
message(STATUS "hyprpm is disabled")
|
||||
else()
|
||||
add_subdirectory(hyprpm)
|
||||
message(STATUS "hyprpm is enabled (NO_HYPRPM not defined)")
|
||||
endif()
|
||||
|
||||
# binary and symlink
|
||||
install(TARGETS Hyprland)
|
||||
@@ -366,7 +401,6 @@ 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)
|
||||
@@ -410,4 +444,5 @@ install(
|
||||
DIRECTORY ${HEADERS_SRC}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h*")
|
||||
PATTERN "*.h*"
|
||||
PATTERN "*.frag")
|
||||
|
@@ -81,6 +81,7 @@ 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
|
||||
@@ -138,10 +139,10 @@ animations {
|
||||
# uncomment all if you wish to use that.
|
||||
# workspace = w[tv1], gapsout:0, gapsin:0
|
||||
# workspace = f[1], gapsout:0, gapsin:0
|
||||
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
|
||||
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
|
||||
# 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 {
|
||||
@@ -275,14 +276,11 @@ 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 v1
|
||||
# windowrule = float, ^(kitty)$
|
||||
|
||||
# Example windowrule v2
|
||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||
# Example windowrule
|
||||
# windowrule = float,class:^(kitty)$,title:^(kitty)$
|
||||
|
||||
# Ignore maximize requests from apps. You'll probably like this.
|
||||
windowrulev2 = suppressevent maximize, class:.*
|
||||
windowrule = suppressevent maximize, class:.*
|
||||
|
||||
# Fix some dragging issues with XWayland
|
||||
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
|
||||
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
|
||||
|
@@ -22,5 +22,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
]
|
||||
}
|
120
flake.lock
generated
120
flake.lock
generated
@@ -16,11 +16,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734364797,
|
||||
"narHash": "sha256-2h1c+P0v3l0Z/ypUSsAPhU/yiSRgFwjVFODWp0S3d/w=",
|
||||
"lastModified": 1742213273,
|
||||
"narHash": "sha256-0l0vDb4anfsBu1rOs94bC73Hub+xEivgBAo6QXl2MmU=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "aquamarine",
|
||||
"rev": "8e77618b403a82fde2105a8e3cd7cabe7ef00952",
|
||||
"rev": "484b732195cc53f4536ce4bd59a5c6402b1e7ccf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -79,11 +79,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734364709,
|
||||
"narHash": "sha256-+2bZJL2u5hva7rSp65OfKJBK+k03T6GB/NCvpoS1OOo=",
|
||||
"lastModified": 1742215578,
|
||||
"narHash": "sha256-zfs71PXVVPEe56WEyNi2TJQPs0wabU4WAlq0XV7GcdE=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprcursor",
|
||||
"rev": "f388aacd22be4a6e4d634fbaf6f75eb0713d239a",
|
||||
"rev": "2fd36421c21aa87e2fe3bee11067540ae612f719",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -105,11 +105,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1733684019,
|
||||
"narHash": "sha256-2kYREgmSmbLsmDpLEq96hxVAU3qz8aCvVhF65yCFZHY=",
|
||||
"lastModified": 1739049071,
|
||||
"narHash": "sha256-3+7TpXMrbsUXSwgr5VAKAnmkzMb6JO+Rvc9XRb5NMg4=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprgraphics",
|
||||
"rev": "fb2c0268645a77403af3b8a4ce8fa7ba5917f15d",
|
||||
"rev": "175c6b29b6ff82100539e7c4363a35a02c74dd73",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -128,11 +128,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1728345020,
|
||||
"narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=",
|
||||
"lastModified": 1738422629,
|
||||
"narHash": "sha256-5v+bv75wJWvahyM2xcMTSNNxmV8a7hb01Eey5zYnBJw=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "a7c183800e74f337753de186522b9017a07a8cee",
|
||||
"rev": "755aef8dab49d0fc4663c715fa4ad221b2aedaed",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -141,9 +141,44 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-qt-support": {
|
||||
"inputs": {
|
||||
"hyprlang": [
|
||||
"hyprland-qtutils",
|
||||
"hyprlang"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"hyprland-qtutils",
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"hyprland-qtutils",
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737634706,
|
||||
"narHash": "sha256-nGCibkfsXz7ARx5R+SnisRtMq21IQIhazp6viBU8I/A=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qt-support",
|
||||
"rev": "8810df502cdee755993cb803eba7b23f189db795",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qt-support",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-qtutils": {
|
||||
"inputs": {
|
||||
"hyprland-qt-support": "hyprland-qt-support",
|
||||
"hyprlang": [
|
||||
"hyprlang"
|
||||
],
|
||||
"hyprutils": [
|
||||
"hyprland-qtutils",
|
||||
"hyprlang",
|
||||
"hyprutils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
@@ -154,11 +189,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1733940128,
|
||||
"narHash": "sha256-hmfXWj2GA9cj1QUkPFYtAAeohhs615zL4E3APy3FnvQ=",
|
||||
"lastModified": 1739048983,
|
||||
"narHash": "sha256-REhTcXq4qs3B3cCDtLlYDz0GZvmsBSh947Ub6pQWGTQ=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qtutils",
|
||||
"rev": "3833097e50473a152dd614d4b468886840b4ea78",
|
||||
"rev": "3504a293c8f8db4127cb0f7cfc1a318ffb4316f8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -180,11 +215,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734364628,
|
||||
"narHash": "sha256-ii8fzJfI953n/EmIxVvq64ZAwhvwuuPHWfGd61/mJG8=",
|
||||
"lastModified": 1741191527,
|
||||
"narHash": "sha256-kM+11Nch47Xwfgtw2EpRitJuORy4miwoMuRi5tyMBDY=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "16e59c1eb13d9fb6de066f54e7555eb5e8a4aba5",
|
||||
"rev": "72df3861f1197e41b078faa3e38eedd60e00018d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -203,11 +238,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1733502241,
|
||||
"narHash": "sha256-KAUNC4Dgq8WQjYov5auBw/usaHixhacvb7cRDd0AG/k=",
|
||||
"lastModified": 1741534688,
|
||||
"narHash": "sha256-EV3945SnjOCuRVbGRghsWx/9D89FyshnSO1Q6/TuQ14=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "104117aed6dd68561be38b50f218190aa47f2cd8",
|
||||
"rev": "dd1f720cbc2dbb3c71167c9598045dd3261d27b3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -226,11 +261,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726874836,
|
||||
"narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=",
|
||||
"lastModified": 1739870480,
|
||||
"narHash": "sha256-SiDN5BGxa/1hAsqhgJsS03C3t2QrLgBT8u+ENJ0Qzwc=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprwayland-scanner",
|
||||
"rev": "500c81a9e1a76760371049a8d99e008ea77aa59e",
|
||||
"rev": "206367a08dc5ac4ba7ad31bdca391d098082e64b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -241,11 +276,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1734119587,
|
||||
"narHash": "sha256-AKU6qqskl0yf2+JdRdD0cfxX4b9x3KKV5RqA6wijmPM=",
|
||||
"lastModified": 1742069588,
|
||||
"narHash": "sha256-C7jVfohcGzdZRF6DO+ybyG/sqpo1h6bZi9T56sxLy+k=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3566ab7246670a43abd2ffa913cc62dad9cdf7d5",
|
||||
"rev": "c80f6a7e10b39afcc1894e02ef785b1ad0b0d7e5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -255,37 +290,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1730741070,
|
||||
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734279981,
|
||||
"narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=",
|
||||
"lastModified": 1742058297,
|
||||
"narHash": "sha256-b4SZc6TkKw8WQQssbN5O2DaCEzmFfvSTPYHlx/SFW9Y=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785",
|
||||
"rev": "59f17850021620cd348ad2e9c0c64f4e6325ce2a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -347,11 +365,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734124279,
|
||||
"narHash": "sha256-YNpFfiQjYt2o6LGcMN9NkjVvprC8ELrIpLHlbZbclRM=",
|
||||
"lastModified": 1741934139,
|
||||
"narHash": "sha256-ZhTcTH9FoeAtbPfWGrhkH7RjLJZ7GeF18nygLAMR+WE=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "0c6861f819f6d31f6195c9864709b2556f00b5cf",
|
||||
"rev": "150b0b6f52bb422a1b232a53698606fe0320dde0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@@ -39,7 +39,7 @@
|
||||
url = "github:hyprwm/hyprland-qtutils";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
inputs.hyprutils.follows = "hyprutils";
|
||||
inputs.hyprlang.follows = "hyprlang";
|
||||
};
|
||||
|
||||
hyprlang = {
|
||||
@@ -157,5 +157,11 @@
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ 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
|
||||
@@ -81,6 +82,16 @@ 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:
|
||||
|
@@ -12,22 +12,17 @@
|
||||
#include <sys/un.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
#include <csignal>
|
||||
#include <format>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <print>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <cstdarg>
|
||||
#include <sys/socket.h>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <cstring>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#include "Strings.hpp"
|
||||
@@ -154,8 +149,16 @@ 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};
|
||||
setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));
|
||||
if (setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)) < 0) {
|
||||
log("Couldn't set socket timeout (2)");
|
||||
return 2;
|
||||
}
|
||||
|
||||
const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
|
||||
|
||||
@@ -164,14 +167,9 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SERVERSOCKET < 0) {
|
||||
log("Couldn't open a socket (1)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (instanceSignature.empty()) {
|
||||
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
|
||||
return 2;
|
||||
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?) (3)");
|
||||
return 3;
|
||||
}
|
||||
|
||||
const std::string USERID = std::to_string(getUID());
|
||||
@@ -184,39 +182,40 @@ 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 + ". (3)");
|
||||
return 3;
|
||||
log("Couldn't connect to " + socketPath + ". (4)");
|
||||
return 4;
|
||||
}
|
||||
|
||||
auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
|
||||
|
||||
if (sizeWritten < 0) {
|
||||
log("Couldn't write (4)");
|
||||
return 4;
|
||||
log("Couldn't write (5)");
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (needRoll)
|
||||
return rollingRead(SERVERSOCKET);
|
||||
|
||||
std::string reply = "";
|
||||
char buffer[8192] = {0};
|
||||
constexpr size_t BUFFER_SIZE = 8192;
|
||||
char buffer[BUFFER_SIZE] = {0};
|
||||
|
||||
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
||||
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
||||
|
||||
if (sizeWritten < 0) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
log("Hyprland IPC didn't respond in time\n");
|
||||
log("Couldn't read (5)");
|
||||
return 5;
|
||||
log("Couldn't read (6)");
|
||||
return 6;
|
||||
}
|
||||
|
||||
reply += std::string(buffer, sizeWritten);
|
||||
|
||||
while (sizeWritten == 8192) {
|
||||
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
||||
while (sizeWritten == BUFFER_SIZE) {
|
||||
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
||||
if (sizeWritten < 0) {
|
||||
log("Couldn't read (5)");
|
||||
return 5;
|
||||
log("Couldn't read (6)");
|
||||
return 6;
|
||||
}
|
||||
reply += std::string(buffer, sizeWritten);
|
||||
}
|
||||
@@ -228,7 +227,7 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int requestHyprpaper(std::string arg) {
|
||||
int requestIPC(std::string filename, std::string arg) {
|
||||
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (SERVERSOCKET < 0) {
|
||||
@@ -246,7 +245,7 @@ int requestHyprpaper(std::string arg) {
|
||||
|
||||
const std::string USERID = std::to_string(getUID());
|
||||
|
||||
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock";
|
||||
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/" + filename;
|
||||
|
||||
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||
|
||||
@@ -264,10 +263,10 @@ int requestHyprpaper(std::string arg) {
|
||||
log("Couldn't write (4)");
|
||||
return 4;
|
||||
}
|
||||
constexpr size_t BUFFER_SIZE = 8192;
|
||||
char buffer[BUFFER_SIZE] = {0};
|
||||
|
||||
char buffer[8192] = {0};
|
||||
|
||||
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
||||
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
||||
|
||||
if (sizeWritten < 0) {
|
||||
log("Couldn't read (5)");
|
||||
@@ -281,6 +280,14 @@ int requestHyprpaper(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);
|
||||
|
||||
@@ -385,6 +392,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
if (cmd == "hyprpaper") {
|
||||
std::println("{}", HYPRPAPER_HELP);
|
||||
} else if (cmd == "hyprsunset") {
|
||||
std::println("{}", HYPRSUNSET_HELP);
|
||||
} else if (cmd == "notify") {
|
||||
std::println("{}", NOTIFY_HELP);
|
||||
} else if (cmd == "output") {
|
||||
@@ -466,6 +475,8 @@ 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"))
|
||||
|
@@ -11,9 +11,23 @@ set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4)
|
||||
|
||||
find_package(glaze QUIET)
|
||||
if (NOT glaze_FOUND)
|
||||
set(GLAZE_VERSION v4.2.3)
|
||||
message(STATUS "glaze dependency not found, retrieving ${GLAZE_VERSION} with FetchContent")
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
glaze
|
||||
GIT_REPOSITORY https://github.com/stephenberry/glaze.git
|
||||
GIT_TAG ${GLAZE_VERSION}
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(glaze)
|
||||
endif()
|
||||
|
||||
add_executable(hyprpm ${SRCFILES})
|
||||
|
||||
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps)
|
||||
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps glaze::glaze)
|
||||
|
||||
# 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 all plugins"
|
||||
| (reload) "Reload plugins to match the enabled/disabled state. Use -f to force reload."
|
||||
;
|
||||
|
||||
<PLUGINS> ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}};
|
||||
|
@@ -1,11 +1,10 @@
|
||||
#include "DataState.hpp"
|
||||
#include <toml++/toml.hpp>
|
||||
#include <print>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include "PluginManager.hpp"
|
||||
|
||||
std::string DataState::getDataStatePath() {
|
||||
std::filesystem::path DataState::getDataStatePath() {
|
||||
const auto HOME = getenv("HOME");
|
||||
if (!HOME) {
|
||||
std::println(stderr, "DataState: no $HOME");
|
||||
@@ -16,12 +15,29 @@ std::string DataState::getDataStatePath() {
|
||||
const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME");
|
||||
|
||||
if (XDG_DATA_HOME)
|
||||
return std::string{XDG_DATA_HOME} + "/hyprpm";
|
||||
return std::string{HOME} + "/.local/share/hyprpm";
|
||||
return std::filesystem::path{XDG_DATA_HOME} / "hyprpm";
|
||||
return std::filesystem::path{HOME} / ".local/share/hyprpm";
|
||||
}
|
||||
|
||||
std::string DataState::getHeadersPath() {
|
||||
return getDataStatePath() + "/headersRoot";
|
||||
return getDataStatePath() / "headersRoot";
|
||||
}
|
||||
|
||||
std::vector<std::filesystem::path> DataState::getPluginStates() {
|
||||
ensureStateStoreExists();
|
||||
|
||||
std::vector<std::filesystem::path> states;
|
||||
for (const auto& entry : std::filesystem::directory_iterator(getDataStatePath())) {
|
||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||
continue;
|
||||
|
||||
const auto stateFile = entry.path() / "state.toml";
|
||||
if (!std::filesystem::exists(stateFile))
|
||||
continue;
|
||||
|
||||
states.emplace_back(stateFile);
|
||||
}
|
||||
return states;
|
||||
}
|
||||
|
||||
void DataState::ensureStateStoreExists() {
|
||||
@@ -37,7 +53,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
|
||||
@@ -50,19 +66,21 @@ 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 + "/" + p.name + ".so");
|
||||
std::filesystem::copy_file(p.filename, PATH / filename);
|
||||
|
||||
DATA.emplace(p.name, toml::table{
|
||||
{"filename", p.name + ".so"},
|
||||
{"filename", filename},
|
||||
{"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();
|
||||
}
|
||||
@@ -72,15 +90,8 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
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& 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("");
|
||||
|
||||
@@ -96,29 +107,22 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
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& 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("");
|
||||
|
||||
if (URL == urlOrName || NAME == urlOrName) {
|
||||
|
||||
// unload the plugins!!
|
||||
for (const auto& file : std::filesystem::directory_iterator(entry.path())) {
|
||||
for (const auto& file : std::filesystem::directory_iterator(stateFile.parent_path())) {
|
||||
if (!file.path().string().ends_with(".so"))
|
||||
continue;
|
||||
|
||||
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
|
||||
}
|
||||
|
||||
std::filesystem::remove_all(entry.path());
|
||||
std::filesystem::remove_all(stateFile.parent_path());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -139,7 +143,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();
|
||||
}
|
||||
@@ -147,12 +151,12 @@ void DataState::updateGlobalState(const SGlobalState& state) {
|
||||
SGlobalState DataState::getGlobalState() {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
const auto stateFile = getDataStatePath() / "state.toml";
|
||||
|
||||
if (!std::filesystem::exists(PATH + "/state.toml"))
|
||||
if (!std::filesystem::exists(stateFile))
|
||||
return SGlobalState{};
|
||||
|
||||
auto DATA = toml::parse_file(PATH + "/state.toml");
|
||||
auto DATA = toml::parse_file(stateFile.c_str());
|
||||
|
||||
SGlobalState state;
|
||||
state.headersHashCompiled = DATA["state"]["hash"].value_or("");
|
||||
@@ -167,15 +171,8 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
std::vector<SPluginRepository> repos;
|
||||
|
||||
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& 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("");
|
||||
@@ -210,15 +207,8 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory() || 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& stateFile : getPluginStates()) {
|
||||
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||
for (const auto& [key, val] : STATE) {
|
||||
if (key == "repository")
|
||||
continue;
|
||||
@@ -231,10 +221,11 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
if (FAILED)
|
||||
return false;
|
||||
|
||||
(*STATE[key].as_table()).insert_or_assign("enabled", enabled);
|
||||
auto modifiedState = STATE;
|
||||
(*modifiedState[key].as_table()).insert_or_assign("enabled", enabled);
|
||||
|
||||
std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
|
||||
state << STATE;
|
||||
std::ofstream state(stateFile, std::ios::trunc);
|
||||
state << modifiedState;
|
||||
state.close();
|
||||
|
||||
return true;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Plugin.hpp"
|
||||
@@ -9,8 +10,9 @@ struct SGlobalState {
|
||||
};
|
||||
|
||||
namespace DataState {
|
||||
std::string getDataStatePath();
|
||||
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);
|
||||
|
@@ -7,10 +7,8 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <print>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
@@ -21,6 +19,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <toml++/toml.hpp>
|
||||
#include <glaze/glaze.hpp>
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
@@ -83,13 +82,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;
|
||||
@@ -378,7 +377,7 @@ eHeadersErrors CPluginManager::headersValid() {
|
||||
|
||||
// find headers commit
|
||||
const std::string& cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
|
||||
auto headers = execAndGet(cmd.c_str());
|
||||
auto headers = execAndGet(cmd);
|
||||
|
||||
if (!headers.contains("-I/"))
|
||||
return HEADERS_MISSING;
|
||||
@@ -464,7 +463,9 @@ bool CPluginManager::updateHeaders(bool force) {
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment."));
|
||||
const auto& HL_URL = m_szCustomHlUrl.empty() ? "https://github.com/hyprwm/Hyprland" : m_szCustomHlUrl;
|
||||
|
||||
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning {}, this might take a moment.", HL_URL));
|
||||
|
||||
const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow;
|
||||
|
||||
@@ -475,12 +476,12 @@ bool CPluginManager::updateHeaders(bool force) {
|
||||
if (m_bVerbose && bShallow)
|
||||
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE));
|
||||
|
||||
std::string ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-{}{}", getTempRoot(), USERNAME,
|
||||
(bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")));
|
||||
std::string ret =
|
||||
execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}{}", getTempRoot(), HL_URL, 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 https://github.com/hyprwm/hyprland hyprland-{}", getTempRoot(), USERNAME));
|
||||
ret = execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}", getTempRoot(), HL_URL, USERNAME));
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(WORKINGDIR + "/.git")) {
|
||||
@@ -781,7 +782,7 @@ bool CPluginManager::disablePlugin(const std::string& name) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
|
||||
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload) {
|
||||
if (headersValid() != HEADERS_OK) {
|
||||
std::println(stderr, "\n{}", failureString("headers are not up-to-date, please run hyprpm update."));
|
||||
return LOADSTATE_HEADERS_OUTDATED;
|
||||
@@ -790,35 +791,28 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
|
||||
const auto HOME = getenv("HOME");
|
||||
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
if (!HOME || !HIS) {
|
||||
std::println(stderr, "PluginManager: no $HOME or HIS");
|
||||
std::println(stderr, "PluginManager: no $HOME or $HYPRLAND_INSTANCE_SIGNATURE");
|
||||
return LOADSTATE_FAIL;
|
||||
}
|
||||
const auto HYPRPMPATH = DataState::getDataStatePath() + "/";
|
||||
const auto HYPRPMPATH = DataState::getDataStatePath();
|
||||
|
||||
auto pluginLines = execAndGet("hyprctl plugins list | grep Plugin");
|
||||
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;
|
||||
}
|
||||
|
||||
std::vector<std::string> loadedPlugins;
|
||||
for (const auto& plugin : json.value()) {
|
||||
if (!plugin.is_object() || !plugin.contains("name")) {
|
||||
std::println(stderr, "PluginManager: couldn't parse plugin object");
|
||||
return LOADSTATE_FAIL;
|
||||
}
|
||||
loadedPlugins.emplace_back(plugin["name"].get<std::string>());
|
||||
}
|
||||
|
||||
std::println("{}", successString("Ensuring plugin load state"));
|
||||
|
||||
// iterate line by line
|
||||
while (!pluginLines.empty()) {
|
||||
auto plLine = pluginLines.substr(0, pluginLines.find('\n'));
|
||||
|
||||
if (pluginLines.find('\n') != std::string::npos)
|
||||
pluginLines = pluginLines.substr(pluginLines.find('\n') + 1);
|
||||
else
|
||||
pluginLines = "";
|
||||
|
||||
if (plLine.back() != ':')
|
||||
continue;
|
||||
|
||||
plLine = plLine.substr(7);
|
||||
plLine = plLine.substr(0, plLine.find(" by "));
|
||||
|
||||
loadedPlugins.push_back(plLine);
|
||||
}
|
||||
|
||||
// get state
|
||||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
@@ -849,11 +843,11 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
|
||||
// (and Hyprland needs to restart)
|
||||
bool hyprlandVersionMismatch = false;
|
||||
|
||||
// unload disabled plugins
|
||||
// unload disabled plugins (or all if forceReload is true)
|
||||
for (auto const& p : loadedPlugins) {
|
||||
if (!enabled(p)) {
|
||||
if (forceReload || !enabled(p)) {
|
||||
// unload
|
||||
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false)) {
|
||||
if (!loadUnloadPlugin(HYPRPMPATH / repoForName(p) / (p + ".so"), false)) {
|
||||
std::println("{}", infoString("{} will be unloaded after restarting Hyprland", p));
|
||||
hyprlandVersionMismatch = true;
|
||||
} else
|
||||
@@ -867,10 +861,10 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
|
||||
if (!p.enabled)
|
||||
continue;
|
||||
|
||||
if (std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end())
|
||||
if (!forceReload && std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end())
|
||||
continue;
|
||||
|
||||
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true)) {
|
||||
if (!loadUnloadPlugin(HYPRPMPATH / repoForName(p.name) / p.filename, true)) {
|
||||
std::println("{}", infoString("{} will be loaded after restarting Hyprland", p.name));
|
||||
hyprlandVersionMismatch = true;
|
||||
} else
|
||||
|
@@ -51,7 +51,7 @@ class CPluginManager {
|
||||
|
||||
bool enablePlugin(const std::string& name);
|
||||
bool disablePlugin(const std::string& name);
|
||||
ePluginLoadStateReturn ensurePluginsLoadState();
|
||||
ePluginLoadStateReturn ensurePluginsLoadState(bool forceReload = false);
|
||||
|
||||
bool loadUnloadPlugin(const std::string& path, bool load);
|
||||
SHyprlandVersion getHyprlandVersion(bool running = true);
|
||||
@@ -62,6 +62,7 @@ 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);
|
||||
|
@@ -29,6 +29,7 @@ constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
┣ --verbose | -v → Enable too much logging
|
||||
┣ --force | -f → Force an operation ignoring checks (e.g. update -f)
|
||||
┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources
|
||||
┣ --hl-url | → Pass a custom hyprland source url
|
||||
┗
|
||||
)#";
|
||||
|
||||
@@ -45,6 +46,7 @@ int main(int argc, char** argv, char** envp) {
|
||||
|
||||
std::vector<std::string> command;
|
||||
bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false;
|
||||
std::string customHlUrl;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (ARGS[i].starts_with("-")) {
|
||||
@@ -59,6 +61,13 @@ int main(int argc, char** argv, char** envp) {
|
||||
verbose = true;
|
||||
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
|
||||
noShallow = true;
|
||||
} else if (ARGS[i] == "--hl-url") {
|
||||
if (i + 1 >= argc) {
|
||||
std::println(stderr, "Missing argument for --hl-url");
|
||||
return 1;
|
||||
}
|
||||
customHlUrl = ARGS[i + 1];
|
||||
i++;
|
||||
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
|
||||
force = true;
|
||||
std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing."));
|
||||
@@ -66,10 +75,9 @@ int main(int argc, char** argv, char** envp) {
|
||||
std::println(stderr, "Unrecognized option {}", ARGS[i]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
command.push_back(ARGS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (command.empty()) {
|
||||
std::println(stderr, "{}", HELP);
|
||||
@@ -79,6 +87,7 @@ int main(int argc, char** argv, char** envp) {
|
||||
g_pPluginManager = std::make_unique<CPluginManager>();
|
||||
g_pPluginManager->m_bVerbose = verbose;
|
||||
g_pPluginManager->m_bNoShallow = noShallow;
|
||||
g_pPluginManager->m_szCustomHlUrl = customHlUrl;
|
||||
|
||||
if (command[0] == "add") {
|
||||
if (command.size() < 2) {
|
||||
@@ -154,9 +163,10 @@ int main(int argc, char** argv, char** envp) {
|
||||
if (ret != LOADSTATE_OK)
|
||||
return 1;
|
||||
} else if (command[0] == "reload") {
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState(force);
|
||||
|
||||
if (ret != LOADSTATE_OK && notify) {
|
||||
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;
|
||||
@@ -165,6 +175,8 @@ int main(int argc, char** argv, char** envp) {
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if (notify && !notifyFail) {
|
||||
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
|
||||
|
@@ -8,6 +8,7 @@ executable(
|
||||
dependency('hyprutils', version: '>= 0.1.1'),
|
||||
dependency('threads'),
|
||||
dependency('tomlplusplus'),
|
||||
dependency('glaze', method: 'cmake'),
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
|
14
meson.build
14
meson.build
@@ -31,12 +31,16 @@ if cpp_compiler.check_header('execinfo.h')
|
||||
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||
endif
|
||||
|
||||
aquamarine = dependency('aquamarine', version: '>=0.4.5')
|
||||
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('.')
|
||||
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')
|
||||
@@ -58,6 +62,7 @@ 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)
|
||||
|
||||
@@ -84,7 +89,7 @@ endif
|
||||
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
|
||||
|
||||
# Install headers
|
||||
globber = run_command('find', 'src', '-name', '*.h*', check: true)
|
||||
globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.frag', check: true)
|
||||
headers = globber.stdout().strip().split('\n')
|
||||
foreach file : headers
|
||||
install_headers(file, subdir: 'hyprland', preserve_path: true)
|
||||
@@ -101,11 +106,14 @@ 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')
|
||||
|
||||
|
@@ -2,4 +2,5 @@ option('xwayland', type: 'feature', value: 'auto', description: 'Enable support
|
||||
option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration')
|
||||
option('uwsm', type: 'feature', value: 'enabled', description: 'Enable uwsm integration (only if systemd is enabled)')
|
||||
option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer')
|
||||
option('hyprpm', type: 'feature', value: 'enabled', description: 'Enable hyprpm')
|
||||
option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling')
|
||||
|
@@ -5,12 +5,14 @@
|
||||
pkg-config,
|
||||
pkgconf,
|
||||
makeWrapper,
|
||||
cmake,
|
||||
meson,
|
||||
ninja,
|
||||
aquamarine,
|
||||
binutils,
|
||||
cairo,
|
||||
git,
|
||||
glaze,
|
||||
hyprcursor,
|
||||
hyprgraphics,
|
||||
hyprland-protocols,
|
||||
@@ -24,7 +26,7 @@
|
||||
libinput,
|
||||
libxkbcommon,
|
||||
libuuid,
|
||||
mesa,
|
||||
libgbm,
|
||||
pango,
|
||||
pciutils,
|
||||
re2,
|
||||
@@ -50,12 +52,12 @@
|
||||
nvidiaPatches ? false,
|
||||
hidpiXWayland ? false,
|
||||
}: let
|
||||
inherit (builtins) baseNameOf foldl';
|
||||
inherit (builtins) baseNameOf foldl' readFile;
|
||||
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;
|
||||
inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable trim;
|
||||
|
||||
adapters = flatten [
|
||||
stdenvAdapters.useMoldLinker
|
||||
@@ -91,7 +93,7 @@ in
|
||||
DATE = date;
|
||||
DIRTY = optionalString (commit == "") "dirty";
|
||||
HASH = commit;
|
||||
TAG = "v${builtins.readFile "${finalAttrs.src}/VERSION"}";
|
||||
TAG = "v${trim (readFile "${finalAttrs.src}/VERSION")}";
|
||||
|
||||
depsBuildBuild = [
|
||||
pkg-config
|
||||
@@ -102,6 +104,7 @@ in
|
||||
makeWrapper
|
||||
meson
|
||||
ninja
|
||||
cmake # needed for glaze
|
||||
pkg-config
|
||||
];
|
||||
|
||||
@@ -116,6 +119,7 @@ in
|
||||
aquamarine
|
||||
cairo
|
||||
git
|
||||
glaze
|
||||
hyprcursor
|
||||
hyprgraphics
|
||||
hyprland-protocols
|
||||
@@ -126,7 +130,7 @@ in
|
||||
libinput
|
||||
libuuid
|
||||
libxkbcommon
|
||||
mesa
|
||||
libgbm
|
||||
pango
|
||||
pciutils
|
||||
re2
|
||||
@@ -151,7 +155,7 @@ in
|
||||
|
||||
mesonBuildType =
|
||||
if debug
|
||||
then "debugoptimized"
|
||||
then "debug"
|
||||
else "release";
|
||||
|
||||
mesonFlags = flatten [
|
||||
@@ -159,6 +163,7 @@ in
|
||||
"xwayland" = enableXWayland;
|
||||
"legacy_renderer" = legacyRenderer;
|
||||
"uwsm" = false;
|
||||
"hyprpm" = false;
|
||||
})
|
||||
(mapAttrsToList mesonBool {
|
||||
"b_pch" = false;
|
||||
|
201
nix/lib.nix
Normal file
201
nix/lib.nix
Normal file
@@ -0,0 +1,201 @@
|
||||
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,17 +5,148 @@ 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 {
|
||||
config = {
|
||||
options = {
|
||||
programs.hyprland = {
|
||||
package = lib.mkDefault package;
|
||||
portalPackage = lib.mkDefault portalPackage;
|
||||
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.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
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;
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
366
protocols/frog-color-management-v1.xml
Normal file
366
protocols/frog-color-management-v1.xml
Normal file
@@ -0,0 +1,366 @@
|
||||
<?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.32',
|
||||
version: '>=1.41',
|
||||
fallback: 'wayland-protocols',
|
||||
default_options: ['tests=false'],
|
||||
)
|
||||
|
||||
hyprland_protos = dependency(
|
||||
'hyprland-protocols',
|
||||
version: '>=0.4',
|
||||
version: '>=0.6.2',
|
||||
fallback: 'hyprland-protocols',
|
||||
)
|
||||
|
||||
@@ -33,10 +33,14 @@ 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',
|
||||
@@ -66,6 +70,8 @@ protocols = [
|
||||
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
|
||||
wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
|
||||
wayland_protocol_dir / 'staging/security-context/security-context-v1.xml',
|
||||
wayland_protocol_dir / 'staging/content-type/content-type-v1.xml',
|
||||
wayland_protocol_dir / 'staging/color-management/color-management-v1.xml',
|
||||
]
|
||||
|
||||
wl_protocols = []
|
||||
|
1457
protocols/xx-color-management-v4.xml
Normal file
1457
protocols/xx-color-management-v4.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# if the git directory doesn't exist, don't gather data to avoid overwriting, unless
|
||||
# the version file is missing altogether (otherwise compiling will fail)
|
||||
if [ ! -d ./.git ]; then
|
||||
if [ -f ./src/version.h ]; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
cp -fr ./src/version.h.in ./src/version.h
|
||||
|
||||
HASH=${HASH-$(git rev-parse HEAD)}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,38 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "events/Events.hpp"
|
||||
#include "config/ConfigManager.hpp"
|
||||
#include "managers/ThreadManager.hpp"
|
||||
#include "managers/XWaylandManager.hpp"
|
||||
#include "managers/input/InputManager.hpp"
|
||||
#include "managers/LayoutManager.hpp"
|
||||
#include "managers/KeybindManager.hpp"
|
||||
#include "managers/AnimationManager.hpp"
|
||||
#include "managers/EventManager.hpp"
|
||||
#include "managers/ProtocolManager.hpp"
|
||||
#include "managers/SessionLockManager.hpp"
|
||||
#include "managers/HookSystemManager.hpp"
|
||||
#include "debug/HyprDebugOverlay.hpp"
|
||||
#include "debug/HyprNotificationOverlay.hpp"
|
||||
#include "helpers/Monitor.hpp"
|
||||
#include "desktop/Workspace.hpp"
|
||||
#include "desktop/Window.hpp"
|
||||
#include "render/Renderer.hpp"
|
||||
#include "render/OpenGL.hpp"
|
||||
#include "hyprerror/HyprError.hpp"
|
||||
#include "plugins/PluginSystem.hpp"
|
||||
#include "helpers/Watchdog.hpp"
|
||||
#include "protocols/types/ColorManagement.hpp"
|
||||
|
||||
#include <aquamarine/backend/Backend.hpp>
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
|
||||
class CWLSurfaceResource;
|
||||
struct SWorkspaceRule;
|
||||
|
||||
enum eManagersInitStage : uint8_t {
|
||||
STAGE_PRIORITY = 0,
|
||||
@@ -42,11 +22,11 @@ enum eManagersInitStage : uint8_t {
|
||||
|
||||
class CCompositor {
|
||||
public:
|
||||
CCompositor();
|
||||
CCompositor(bool onlyConfig = false);
|
||||
~CCompositor();
|
||||
|
||||
wl_display* m_sWLDisplay;
|
||||
wl_event_loop* m_sWLEventLoop;
|
||||
wl_display* m_sWLDisplay = nullptr;
|
||||
wl_event_loop* m_sWLEventLoop = nullptr;
|
||||
int m_iDRMFD = -1;
|
||||
bool m_bInitialized = false;
|
||||
SP<Aquamarine::CBackend> m_pAqBackend;
|
||||
@@ -72,8 +52,6 @@ class CCompositor {
|
||||
void startCompositor();
|
||||
void stopCompositor();
|
||||
void cleanup();
|
||||
void createLockFile();
|
||||
void removeLockFile();
|
||||
void bumpNofile();
|
||||
void restoreNofile();
|
||||
|
||||
@@ -92,7 +70,8 @@ class CCompositor {
|
||||
bool m_bIsShuttingDown = false;
|
||||
bool m_bFinalRequests = false;
|
||||
bool m_bDesktopEnvSet = false;
|
||||
bool m_bEnableXwayland = true;
|
||||
bool m_bWantsXwayland = true;
|
||||
bool m_bOnlyConfigVerification = false;
|
||||
|
||||
// ------------------------------------------------- //
|
||||
|
||||
@@ -102,7 +81,7 @@ class CCompositor {
|
||||
PHLMONITOR getMonitorFromCursor();
|
||||
PHLMONITOR getMonitorFromVector(const Vector2D&);
|
||||
void removeWindowFromVectorSafe(PHLWINDOW);
|
||||
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr);
|
||||
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr, bool preserveFocusHistory = false);
|
||||
void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr);
|
||||
bool monitorExists(PHLMONITOR);
|
||||
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
|
||||
@@ -123,8 +102,9 @@ class CCompositor {
|
||||
void changeWindowZOrder(PHLWINDOW, bool);
|
||||
void cleanupFadingOut(const MONITORID& monid);
|
||||
PHLWINDOW getWindowInDirection(PHLWINDOW, char);
|
||||
PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
|
||||
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
|
||||
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);
|
||||
WORKSPACEID getNextAvailableNamedWorkspace();
|
||||
bool isPointOnAnyMonitor(const Vector2D&);
|
||||
bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr);
|
||||
@@ -140,7 +120,6 @@ class CCompositor {
|
||||
void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
|
||||
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
|
||||
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const SFullscreenState state);
|
||||
void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
|
||||
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
|
||||
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
|
||||
PHLWINDOW getX11Parent(PHLWINDOW);
|
||||
@@ -167,8 +146,11 @@ 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;
|
||||
|
||||
@@ -179,10 +161,13 @@ 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 = {0};
|
||||
rlimit m_sOriginalNofile = {};
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CCompositor> g_pCompositor;
|
||||
inline UP<CCompositor> g_pCompositor;
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "helpers/math/Math.hpp"
|
||||
#include <functional>
|
||||
#include <any>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <hyprutils/math/Box.hpp>
|
||||
|
||||
enum eIcons : uint8_t {
|
||||
@@ -50,6 +52,12 @@ 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;
|
||||
|
@@ -11,7 +11,7 @@ enum eConfigValueDataTypes : int8_t {
|
||||
|
||||
class ICustomConfigValueData {
|
||||
public:
|
||||
virtual ~ICustomConfigValueData() = 0;
|
||||
virtual ~ICustomConfigValueData() = default;
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() = 0;
|
||||
|
||||
|
@@ -139,6 +139,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{0, 0, 20},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:rounding_power",
|
||||
.description = "rouding power of corners (2 is a circle)",
|
||||
.type = CONFIG_OPTION_FLOAT,
|
||||
.data = SConfigOptionDescription::SFloatData{2, 2, 10},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:active_opacity",
|
||||
.description = "opacity of active windows. [0.0 - 1.0]",
|
||||
@@ -247,98 +253,98 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
*/
|
||||
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:enabled",
|
||||
.value = "decoration:blur:enabled",
|
||||
.description = "enable kawase window background blur",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:size",
|
||||
.value = "decoration:blur:size",
|
||||
.description = "blur size (distance)",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{8, 0, 100},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:passes",
|
||||
.value = "decoration:blur:passes",
|
||||
.description = "the amount of passes to perform",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{1, 0, 10},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:ignore_opacity",
|
||||
.value = "decoration:blur:ignore_opacity",
|
||||
.description = "make the blur layer ignore the opacity of the window",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:new_optimizations",
|
||||
.value = "decoration: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 = "blur:xray",
|
||||
.value = "decoration: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 = "blur:noise",
|
||||
.value = "decoration: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 = "blur:contrast",
|
||||
.value = "decoration:blur:contrast",
|
||||
.description = "contrast modulation for blur. [0.0 - 2.0]",
|
||||
.type = CONFIG_OPTION_FLOAT,
|
||||
.data = SConfigOptionDescription::SFloatData{0.8916, 0, 2},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:brightness",
|
||||
.value = "decoration:blur:brightness",
|
||||
.description = "brightness modulation for blur. [0.0 - 2.0]",
|
||||
.type = CONFIG_OPTION_FLOAT,
|
||||
.data = SConfigOptionDescription::SFloatData{0.8172, 0, 2},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:vibrancy",
|
||||
.value = "decoration: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 = "blur:vibrancy_darkness",
|
||||
.value = "decoration: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 = "blur:special",
|
||||
.value = "decoration:blur:special",
|
||||
.description = "whether to blur behind the special workspace (note: expensive)",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:popups",
|
||||
.value = "decoration:blur:popups",
|
||||
.description = "whether to blur popups (e.g. right-click menus)",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:popups_ignorealpha",
|
||||
.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 = "blur:input_methods",
|
||||
.value = "decoration:blur:input_methods",
|
||||
.description = "whether to blur input methods (e.g. fcitx5)",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "blur:input_methods_ignorealpha",
|
||||
.value = "decoration:blur:input_methods_ignorealpha",
|
||||
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
|
||||
.type = CONFIG_OPTION_FLOAT,
|
||||
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
|
||||
@@ -495,6 +501,12 @@ 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 "
|
||||
@@ -596,6 +608,18 @@ 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:
|
||||
@@ -803,25 +827,25 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "general:col.border_active",
|
||||
.value = "group:col.border_active",
|
||||
.description = "border color for inactive windows",
|
||||
.type = CONFIG_OPTION_GRADIENT,
|
||||
.data = SConfigOptionDescription::SGradientData{"0x66ffff00"},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "general:col.border_inactive",
|
||||
.value = "group:col.border_inactive",
|
||||
.description = "border color for the active window",
|
||||
.type = CONFIG_OPTION_GRADIENT,
|
||||
.data = SConfigOptionDescription::SGradientData{"0x66777700"},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "general:col.border_locked_active",
|
||||
.value = "group:col.border_locked_inactive",
|
||||
.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 = "general:col.border_locked_inactive",
|
||||
.value = "group:col.border_locked_active",
|
||||
.description = "active border color for window that cannot be added to a group",
|
||||
.type = CONFIG_OPTION_GRADIENT,
|
||||
.data = SConfigOptionDescription::SGradientData{"0x66775500"},
|
||||
@@ -877,7 +901,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.value = "group:groupbar:gradients",
|
||||
.description = "enables gradients",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "group:groupbar:height",
|
||||
@@ -885,6 +909,12 @@ 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",
|
||||
@@ -909,6 +939,30 @@ 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",
|
||||
@@ -939,6 +993,18 @@ 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:
|
||||
@@ -988,9 +1054,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 [0/1/2]",
|
||||
.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]",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{0, 0, 2},
|
||||
.data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 3},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "misc:mouse_move_enables_dpms",
|
||||
@@ -1145,6 +1211,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{1000, 0, 5000},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "misc:enable_anr_dialog",
|
||||
.description = "whether to enable the ANR (app not responding) dialog when your apps hang",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
|
||||
/*
|
||||
* binds:
|
||||
@@ -1198,7 +1270,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{true},
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "binds:movefocus_cycles_groupfirst",
|
||||
@@ -1247,6 +1319,12 @@ 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:
|
||||
@@ -1258,13 +1336,6 @@ 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:
|
||||
@@ -1285,33 +1356,57 @@ 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.",
|
||||
"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.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
.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},
|
||||
},
|
||||
|
||||
/*
|
||||
* 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",
|
||||
.description = "disables hardware cursors. Auto = disable when tearing",
|
||||
.type = CONFIG_OPTION_CHOICE,
|
||||
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "cursor:no_break_fs_vrr",
|
||||
.description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
.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},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "cursor:min_refresh_rate",
|
||||
@@ -1391,6 +1486,35 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "cursor:sync_gsettings_theme",
|
||||
.description = "sync xcursor theme with gsettings, it applies cursor-theme and cursor-size on theme load to gsettings making most CSD gtk based clients use same xcursor "
|
||||
"theme and size.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "cursor:warp_back_after_non_mouse_input",
|
||||
.description = "warp the cursor back to where it was after using a non-mouse input to move it, and then returning back to mouse.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
|
||||
/*
|
||||
* ecosystem:
|
||||
*/
|
||||
SConfigOptionDescription{
|
||||
.value = "ecosystem:no_update_news",
|
||||
.description = "disable the popup that shows up when you update hyprland to a new version.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "ecosystem:no_donation_nag",
|
||||
.description = "disable the popup that shows up twice a year encouraging to donate.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
|
||||
/*
|
||||
* debug:
|
||||
@@ -1474,6 +1598,24 @@ 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:
|
||||
@@ -1603,10 +1745,16 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.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.",
|
||||
.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{false},
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "master:center_ignores_reserved",
|
||||
@@ -1628,4 +1776,16 @@ 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,31 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <hyprutils/animation/AnimationConfig.hpp>
|
||||
#define CONFIG_MANAGER_H
|
||||
|
||||
#include <map>
|
||||
#include "../debug/Log.hpp"
|
||||
#include <unordered_map>
|
||||
#include "../defines.hpp"
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <xf86drmMode.h>
|
||||
#include "../helpers/WLClasses.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../helpers/varlist/VarList.hpp"
|
||||
#include "../desktop/Window.hpp"
|
||||
#include "../desktop/LayerSurface.hpp"
|
||||
#include "../desktop/LayerRule.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 {
|
||||
@@ -54,18 +53,6 @@ struct SMonitorAdditionalReservedArea {
|
||||
int right = 0;
|
||||
};
|
||||
|
||||
struct SAnimationPropertyConfig {
|
||||
bool overridden = true;
|
||||
|
||||
std::string internalBezier = "";
|
||||
std::string internalStyle = "";
|
||||
float internalSpeed = 0.f;
|
||||
int internalEnabled = -1;
|
||||
|
||||
SAnimationPropertyConfig* pValues = nullptr;
|
||||
SAnimationPropertyConfig* pParentAnimation = nullptr;
|
||||
};
|
||||
|
||||
struct SPluginKeyword {
|
||||
HANDLE handle = nullptr;
|
||||
std::string name = "";
|
||||
@@ -146,12 +133,39 @@ 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 = "");
|
||||
@@ -163,8 +177,7 @@ class CConfigManager {
|
||||
|
||||
void* const* getConfigValuePtr(const std::string&);
|
||||
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
|
||||
void onPluginLoadUnload(const std::string& name, bool load);
|
||||
static std::string getMainConfigPath();
|
||||
std::string getMainConfigPath();
|
||||
std::string getConfigString();
|
||||
|
||||
SMonitorRule getMonitorRuleFor(const PHLMONITOR);
|
||||
@@ -177,12 +190,13 @@ class CConfigManager {
|
||||
|
||||
std::vector<SP<CWindowRule>> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
|
||||
std::vector<SP<CLayerRule>> getMatchingRules(PHLLS);
|
||||
void ensurePersistentWorkspacesPresent();
|
||||
|
||||
const std::vector<SConfigOptionDescription>& getAllDescriptions();
|
||||
|
||||
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
|
||||
|
||||
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
|
||||
const std::unordered_map<std::string, SP<Hyprutils::Animation::SAnimationPropertyConfig>>& getAnimationConfig();
|
||||
|
||||
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 = {});
|
||||
@@ -193,18 +207,17 @@ class CConfigManager {
|
||||
void dispatchExecShutdown();
|
||||
|
||||
void performMonitorReload();
|
||||
void appendMonitorRule(const SMonitorRule&);
|
||||
bool replaceMonitorRule(const SMonitorRule&);
|
||||
void ensureMonitorStatus();
|
||||
void ensureVRR(PHLMONITOR pMonitor = nullptr);
|
||||
|
||||
bool shouldUseSoftwareCursors();
|
||||
bool shouldUseSoftwareCursors(PHLMONITOR pMonitor);
|
||||
void updateWatcher();
|
||||
|
||||
std::string parseKeyword(const std::string&, 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&);
|
||||
|
||||
@@ -213,14 +226,15 @@ class CConfigManager {
|
||||
|
||||
// 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> 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&);
|
||||
@@ -233,50 +247,20 @@ class CConfigManager {
|
||||
|
||||
std::string configCurrentPath;
|
||||
|
||||
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> mbWindowProperties = {
|
||||
{"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
|
||||
{"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.dimAround; }},
|
||||
{"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.decorate; }},
|
||||
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
|
||||
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
|
||||
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
|
||||
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noAnim; }},
|
||||
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBlur; }},
|
||||
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBorder; }},
|
||||
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noDim; }},
|
||||
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noFocus; }},
|
||||
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
|
||||
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noRounding; }},
|
||||
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShadow; }},
|
||||
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
|
||||
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.opaque; }},
|
||||
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.RGBX; }},
|
||||
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
|
||||
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.tearing; }},
|
||||
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }},
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> miWindowProperties = {
|
||||
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }},
|
||||
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }},
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> mfWindowProperties = {
|
||||
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }},
|
||||
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}};
|
||||
|
||||
bool m_bWantsMonitorReload = false;
|
||||
bool m_bForceReload = false;
|
||||
bool m_bNoMonitorReload = false;
|
||||
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
|
||||
bool m_bLastConfigVerificationWasSuccessful = true;
|
||||
|
||||
void storeFloatingSize(PHLWINDOW window, const Vector2D& size);
|
||||
std::optional<Vector2D> getStoredFloatingSize(PHLWINDOW window);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
|
||||
UP<Hyprlang::CConfig> m_pConfig;
|
||||
|
||||
std::vector<std::string> configPaths; // stores all the config paths
|
||||
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
|
||||
std::vector<std::string> m_configPaths;
|
||||
|
||||
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
|
||||
Hyprutils::Animation::CAnimationConfigTree m_AnimationTree;
|
||||
|
||||
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
|
||||
|
||||
@@ -296,22 +280,33 @@ class CConfigManager {
|
||||
|
||||
bool firstExecDispatched = false;
|
||||
bool m_bManualCrashInitiated = false;
|
||||
std::vector<std::string> firstExecRequests;
|
||||
|
||||
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;
|
||||
|
||||
// internal methods
|
||||
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();
|
||||
std::optional<std::string> generateConfig(std::string configPath);
|
||||
std::optional<std::string> verifyConfigExists();
|
||||
void postConfigReload(const Hyprlang::CParseResult& result);
|
||||
void reload();
|
||||
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;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CConfigManager> g_pConfigManager;
|
||||
inline UP<CConfigManager> g_pConfigManager;
|
||||
|
@@ -3,7 +3,6 @@
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <hyprlang.hpp>
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include "ConfigManager.hpp"
|
||||
|
||||
|
81
src/config/ConfigWatcher.cpp
Normal file
81
src/config/ConfigWatcher.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#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,
|
||||
});
|
||||
}
|
||||
}
|
33
src/config/ConfigWatcher.hpp
Normal file
33
src/config/ConfigWatcher.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#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>();
|
@@ -94,6 +94,7 @@ 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
|
||||
@@ -151,10 +152,10 @@ animations {
|
||||
# uncomment all if you wish to use that.
|
||||
# workspace = w[tv1], gapsout:0, gapsin:0
|
||||
# workspace = f[1], gapsout:0, gapsin:0
|
||||
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
|
||||
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
|
||||
# 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 {
|
||||
@@ -268,7 +269,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 @DEFAULT_AUDIO_SINK@ 5%+
|
||||
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @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
|
||||
@@ -288,15 +289,12 @@ 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 v1
|
||||
# windowrule = float, ^(kitty)$
|
||||
|
||||
# Example windowrule v2
|
||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||
# Example windowrule
|
||||
# windowrule = float,class:^(kitty)$,title:^(kitty)$
|
||||
|
||||
# Ignore maximize requests from apps. You'll probably like this.
|
||||
windowrulev2 = suppressevent maximize, class:.*
|
||||
windowrule = suppressevent maximize, class:.*
|
||||
|
||||
# Fix some dragging issues with XWayland
|
||||
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
|
||||
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
|
||||
)#";
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#include <cerrno>
|
||||
#include <sys/stat.h>
|
||||
#include <filesystem>
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
|
||||
#include "../plugins/PluginSystem.hpp"
|
||||
#include "../signal-safe.hpp"
|
||||
@@ -111,7 +112,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
|
||||
#ifdef LEGACY_RENDERER
|
||||
finalCrashReport += "legacyrenderer\n";
|
||||
#endif
|
||||
#ifndef ISDEBUG
|
||||
#if ISDEBUG
|
||||
finalCrashReport += "debug\n";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
@@ -161,7 +162,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga");
|
||||
#else
|
||||
finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA");
|
||||
finalCrashReport.writeCmdOutput("lspci -vnn | grep -E '(VGA|Display|3D)'");
|
||||
#endif
|
||||
|
||||
finalCrashReport += "\n\nos-release:\n";
|
||||
|
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::OS;
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
|
||||
#include "../config/ConfigDataValues.hpp"
|
||||
@@ -39,8 +40,18 @@ using namespace Hyprutils::String;
|
||||
#include "debug/RollingLogFollow.hpp"
|
||||
#include "config/ConfigManager.hpp"
|
||||
#include "helpers/MiscFunctions.hpp"
|
||||
#include "../desktop/LayerSurface.hpp"
|
||||
#include "../version.h"
|
||||
|
||||
#include "../Compositor.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
#include "../managers/XWaylandManager.hpp"
|
||||
#include "../managers/LayoutManager.hpp"
|
||||
#include "../plugins/PluginSystem.hpp"
|
||||
#include "../managers/AnimationManager.hpp"
|
||||
#include "../debug/HyprNotificationOverlay.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
|
||||
static void trimTrailingComma(std::string& str) {
|
||||
if (!str.empty() && str.back() == ',')
|
||||
str.pop_back();
|
||||
@@ -142,7 +153,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
auto allMonitors = false;
|
||||
|
||||
@@ -248,28 +259,29 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
|
||||
"focusHistoryID": {},
|
||||
"inhibitingIdle": {}
|
||||
}},)#",
|
||||
(uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
|
||||
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
|
||||
(uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition->goal().x, (int)w->m_vRealPosition->goal().y,
|
||||
(int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
|
||||
escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"),
|
||||
(int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass),
|
||||
escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
|
||||
(uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
|
||||
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false"));
|
||||
(uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.get(),
|
||||
getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false"));
|
||||
} else {
|
||||
return std::format(
|
||||
"Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
|
||||
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
|
||||
"{}\n\txwayland: {}\n\tpinned: "
|
||||
"{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\tinhibitingIdle: {}\n\n",
|
||||
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
|
||||
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName),
|
||||
(int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(),
|
||||
(int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
|
||||
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (int)g_pInputManager->isWindowInhibiting(w, false));
|
||||
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition->goal().x, (int)w->m_vRealPosition->goal().y,
|
||||
(int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
|
||||
(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle,
|
||||
w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal,
|
||||
(uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.get(), getFocusHistoryID(w),
|
||||
(int)g_pInputManager->isWindowInhibiting(w, false));
|
||||
}
|
||||
}
|
||||
|
||||
std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[";
|
||||
@@ -307,15 +319,17 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form
|
||||
"windows": {},
|
||||
"hasfullscreen": {},
|
||||
"lastwindow": "0x{:x}",
|
||||
"lastwindowtitle": "{}"
|
||||
"lastwindowtitle": "{}",
|
||||
"ispersistent": {}
|
||||
}})#",
|
||||
w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"),
|
||||
escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"),
|
||||
(uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
|
||||
escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), w->m_bHasFullscreenWindow ? "true" : "false",
|
||||
(uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "", w->m_bPersistent ? "true" : "false");
|
||||
} else {
|
||||
return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID,
|
||||
w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow,
|
||||
(uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "");
|
||||
return std::format(
|
||||
"workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\tispersistent: {}\n\n",
|
||||
w->m_iID, w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow,
|
||||
(uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "", (int)w->m_bPersistent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +382,8 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
|
||||
return result;
|
||||
}
|
||||
}
|
||||
std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
|
||||
static std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
if (!g_pCompositor->m_pLastMonitor)
|
||||
return "unsafe state";
|
||||
|
||||
@@ -381,7 +396,7 @@ std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string requ
|
||||
return CHyprCtl::getWorkspaceData(w, format);
|
||||
}
|
||||
|
||||
std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
@@ -402,7 +417,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[";
|
||||
@@ -422,7 +437,7 @@ std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string reque
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
|
||||
|
||||
if (!validMapped(PWINDOW))
|
||||
@@ -436,7 +451,7 @@ std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
@@ -464,9 +479,11 @@ std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
"y": {},
|
||||
"w": {},
|
||||
"h": {},
|
||||
"namespace": "{}"
|
||||
"namespace": "{}",
|
||||
"pid": {}
|
||||
}},)#",
|
||||
(uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, escapeJSONStrings(layer->szNamespace));
|
||||
(uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, escapeJSONStrings(layer->szNamespace),
|
||||
layer->getPID());
|
||||
}
|
||||
|
||||
trimTrailingComma(result);
|
||||
@@ -497,8 +514,8 @@ std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]);
|
||||
|
||||
for (auto const& layer : level) {
|
||||
result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width,
|
||||
layer->geometry.height, layer->szNamespace);
|
||||
result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}, pid: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y,
|
||||
layer->geometry.width, layer->geometry.height, layer->szNamespace, layer->getPID());
|
||||
}
|
||||
|
||||
layerLevel++;
|
||||
@@ -510,7 +527,7 @@ std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[";
|
||||
@@ -532,7 +549,7 @@ std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
std::string currErrors = g_pConfigManager->getErrors();
|
||||
CVarList errLines(currErrors, 0, '\n');
|
||||
@@ -555,7 +572,7 @@ std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
|
||||
auto getModState = [](SP<IKeyboard> keyboard, const char* xkbModName) -> bool {
|
||||
@@ -725,14 +742,14 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string ret = "";
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
ret += "animations:\n";
|
||||
|
||||
for (auto const& ac : g_pConfigManager->getAnimationConfig()) {
|
||||
ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second.overridden,
|
||||
ac.second.internalBezier, ac.second.internalEnabled, ac.second.internalSpeed, ac.second.internalStyle);
|
||||
ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second->overridden,
|
||||
ac.second->internalBezier, ac.second->internalEnabled, ac.second->internalSpeed, ac.second->internalStyle);
|
||||
}
|
||||
|
||||
ret += "beziers:\n";
|
||||
@@ -754,8 +771,8 @@ std::string animationsRequest(eHyprCtlOutputFormat format, std::string request)
|
||||
"speed": {:.2f},
|
||||
"style": "{}"
|
||||
}},)#",
|
||||
ac.first, ac.second.overridden ? "true" : "false", escapeJSONStrings(ac.second.internalBezier), ac.second.internalEnabled ? "true" : "false",
|
||||
ac.second.internalSpeed, escapeJSONStrings(ac.second.internalStyle));
|
||||
ac.first, ac.second->overridden ? "true" : "false", escapeJSONStrings(ac.second->internalBezier), ac.second->internalEnabled ? "true" : "false",
|
||||
ac.second->internalSpeed, escapeJSONStrings(ac.second->internalStyle));
|
||||
}
|
||||
|
||||
ret[ret.length() - 1] = ']';
|
||||
@@ -778,7 +795,7 @@ std::string animationsRequest(eHyprCtlOutputFormat format, std::string request)
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
@@ -792,12 +809,15 @@ std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string ret = "";
|
||||
const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts();
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
for (auto const& sh : SHORTCUTS)
|
||||
for (auto const& sh : SHORTCUTS) {
|
||||
ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description);
|
||||
}
|
||||
if (ret.empty())
|
||||
ret = "none";
|
||||
} else {
|
||||
ret += "[";
|
||||
for (auto const& sh : SHORTCUTS) {
|
||||
@@ -815,7 +835,7 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string ret = "";
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
for (auto const& kb : g_pKeybindManager->m_vKeybinds) {
|
||||
@@ -883,14 +903,14 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION,
|
||||
HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION);
|
||||
|
||||
#if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND))
|
||||
#if (!defined(LEGACY_RENDERER) && !ISDEBUG && !defined(NO_XWAYLAND))
|
||||
result += "no flags were set\n";
|
||||
#else
|
||||
result += "flags set:\n";
|
||||
#ifdef LEGACY_RENDERER
|
||||
result += "legacyrenderer\n";
|
||||
#endif
|
||||
#ifdef ISDEBUG
|
||||
#if ISDEBUG
|
||||
result += "debug\n";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
@@ -921,7 +941,7 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
#ifdef LEGACY_RENDERER
|
||||
result += "\"legacyrenderer\",";
|
||||
#endif
|
||||
#ifdef ISDEBUG
|
||||
#if ISDEBUG
|
||||
result += "\"debug\",";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
@@ -976,7 +996,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
|
||||
}
|
||||
} catch (...) { GPUINFO = "error"; }
|
||||
#else
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep -E '(VGA|Display|3D)'");
|
||||
#endif
|
||||
result += "GPU information: \n" + GPUINFO;
|
||||
if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version")) {
|
||||
@@ -1018,7 +1038,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) {
|
||||
static std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) {
|
||||
// get rid of the dispatch keyword
|
||||
in = in.substr(in.find_first_of(' ') + 1);
|
||||
|
||||
@@ -1039,7 +1059,7 @@ std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) {
|
||||
return res.success ? "ok" : res.error;
|
||||
}
|
||||
|
||||
std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
|
||||
static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
|
||||
// Find the first space to strip the keyword keyword
|
||||
auto const firstSpacePos = in.find_first_of(' ');
|
||||
if (firstSpacePos == std::string::npos) // Handle the case where there's no space found (invalid input)
|
||||
@@ -1088,6 +1108,9 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
|
||||
}
|
||||
}
|
||||
|
||||
if (COMMAND.contains("misc:disable_autoreload"))
|
||||
g_pConfigManager->updateWatcher();
|
||||
|
||||
// decorations will probably need a repaint
|
||||
if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source" ||
|
||||
COMMAND.starts_with("windowrule")) {
|
||||
@@ -1105,32 +1128,29 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string reloadRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string reloadRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
|
||||
const auto REQMODE = request.substr(request.find_last_of(' ') + 1);
|
||||
|
||||
g_pConfigManager->m_bForceReload = true;
|
||||
|
||||
if (REQMODE == "config-only") {
|
||||
if (REQMODE == "config-only")
|
||||
g_pConfigManager->m_bNoMonitorReload = true;
|
||||
}
|
||||
|
||||
g_pConfigManager->tick();
|
||||
g_pConfigManager->reload();
|
||||
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string killRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string killRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
g_pInputManager->setClickMode(CLICKMODE_KILL);
|
||||
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
return g_pCompositor->m_szCurrentSplash;
|
||||
}
|
||||
|
||||
std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal().floor();
|
||||
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
@@ -1148,41 +1168,33 @@ std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
return "error";
|
||||
}
|
||||
|
||||
std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
|
||||
// split by ;
|
||||
static std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
|
||||
// split by ; ignores ; inside [] and adds ; on last command
|
||||
|
||||
request = request.substr(9);
|
||||
std::string curitem = "";
|
||||
std::string reply = "";
|
||||
|
||||
auto nextItem = [&]() {
|
||||
auto idx = request.find_first_of(';');
|
||||
|
||||
if (idx != std::string::npos) {
|
||||
curitem = request.substr(0, idx);
|
||||
request = request.substr(idx + 1);
|
||||
} else {
|
||||
curitem = request;
|
||||
request = "";
|
||||
}
|
||||
|
||||
curitem = trim(curitem);
|
||||
};
|
||||
|
||||
nextItem();
|
||||
|
||||
const std::string DELIMITER = "\n\n\n";
|
||||
int bracket = 0;
|
||||
size_t idx = 0;
|
||||
|
||||
while (curitem != "" || request != "") {
|
||||
reply += g_pHyprCtl->getReply(curitem) + DELIMITER;
|
||||
|
||||
nextItem();
|
||||
for (size_t i = 0; i <= request.size(); ++i) {
|
||||
char ch = (i < request.size()) ? request[i] : ';';
|
||||
if (ch == '[')
|
||||
++bracket;
|
||||
else if (ch == ']')
|
||||
--bracket;
|
||||
else if (ch == ';' && bracket == 0) {
|
||||
if (idx < i)
|
||||
reply += g_pHyprCtl->getReply(trim(request.substr(idx, i - idx))).append(DELIMITER);
|
||||
idx = i + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return reply.substr(0, std::max(static_cast<int>(reply.size() - DELIMITER.size()), 0));
|
||||
}
|
||||
|
||||
std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
const auto SIZESTR = vars[vars.size() - 1];
|
||||
@@ -1206,7 +1218,7 @@ std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request)
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
const auto KB = vars[1];
|
||||
@@ -1281,7 +1293,7 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
std::string errorMessage = "";
|
||||
@@ -1310,12 +1322,12 @@ std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
|
||||
auto result = g_pKeybindManager->m_mDispatchers["setprop"](request.substr(request.find_first_of(' ') + 1, -1));
|
||||
static std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
|
||||
auto result = g_pKeybindManager->m_mDispatchers["setprop"](request.substr(request.find_first_of(' ') + 1));
|
||||
return "DEPRECATED: use hyprctl dispatch setprop instead" + (result.success ? "" : "\n" + result.error);
|
||||
}
|
||||
|
||||
std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string curitem = "";
|
||||
|
||||
auto nextItem = [&]() {
|
||||
@@ -1371,7 +1383,7 @@ std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request)
|
||||
return "invalid type (internal error)";
|
||||
}
|
||||
|
||||
std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
|
||||
|
||||
@@ -1397,7 +1409,7 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
if (vars.size() < 2)
|
||||
@@ -1452,7 +1464,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
if (vars.size() < 2)
|
||||
@@ -1521,7 +1533,7 @@ std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
if (vars.size() < 5)
|
||||
@@ -1576,7 +1588,7 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
int amount = -1;
|
||||
@@ -1596,7 +1608,7 @@ std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::string reque
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string getIsLocked(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string getIsLocked(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string lockedStr = g_pSessionLockManager->isSessionLocked() ? "true" : "false";
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
|
||||
lockedStr = std::format(R"#(
|
||||
@@ -1608,7 +1620,7 @@ std::string getIsLocked(eHyprCtlOutputFormat format, std::string request) {
|
||||
return lockedStr;
|
||||
}
|
||||
|
||||
std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string json = "{";
|
||||
const auto& DESCS = g_pConfigManager->getAllDescriptions();
|
||||
|
||||
@@ -1623,7 +1635,7 @@ std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
|
||||
return json;
|
||||
}
|
||||
|
||||
std::string submapRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
static std::string submapRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string submap = g_pKeybindManager->getCurrentSubmap();
|
||||
if (submap.empty())
|
||||
submap = "default";
|
||||
@@ -1676,8 +1688,6 @@ CHyprCtl::CHyprCtl() {
|
||||
CHyprCtl::~CHyprCtl() {
|
||||
if (m_eventSource)
|
||||
wl_event_source_remove(m_eventSource);
|
||||
if (m_iSocketFD >= 0)
|
||||
close(m_iSocketFD);
|
||||
if (!m_socketPath.empty())
|
||||
unlink(m_socketPath.c_str());
|
||||
}
|
||||
@@ -1792,7 +1802,7 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) {
|
||||
return getReply(input);
|
||||
}
|
||||
|
||||
bool successWrite(int fd, const std::string& data, bool needLog = true) {
|
||||
static bool successWrite(int fd, const std::string& data, bool needLog = true) {
|
||||
if (write(fd, data.c_str(), data.length()) > 0)
|
||||
return true;
|
||||
|
||||
@@ -1805,7 +1815,7 @@ bool successWrite(int fd, const std::string& data, bool needLog = true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void runWritingDebugLogThread(const int conn) {
|
||||
static void runWritingDebugLogThread(const int conn) {
|
||||
using namespace std::chrono_literals;
|
||||
Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn);
|
||||
//will be finished, when reading side close connection
|
||||
@@ -1828,18 +1838,21 @@ void runWritingDebugLogThread(const int conn) {
|
||||
}).detach();
|
||||
}
|
||||
|
||||
bool isFollowUpRollingLogRequest(const std::string& request) {
|
||||
static bool isFollowUpRollingLogRequest(const std::string& request) {
|
||||
return request.contains("rollinglog") && request.contains("f");
|
||||
}
|
||||
|
||||
int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
static int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
|
||||
return 0;
|
||||
|
||||
if (!g_pHyprCtl->m_iSocketFD.isValid())
|
||||
return 0;
|
||||
|
||||
sockaddr_in clientAddress;
|
||||
socklen_t clientSize = sizeof(clientAddress);
|
||||
|
||||
const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
|
||||
const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
|
||||
|
||||
std::array<char, 1024> readBuffer;
|
||||
|
||||
@@ -1896,9 +1909,9 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
}
|
||||
|
||||
void CHyprCtl::startHyprCtlSocket() {
|
||||
m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
m_iSocketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)};
|
||||
|
||||
if (m_iSocketFD < 0) {
|
||||
if (!m_iSocketFD.isValid()) {
|
||||
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
|
||||
return;
|
||||
}
|
||||
@@ -1909,15 +1922,15 @@ void CHyprCtl::startHyprCtlSocket() {
|
||||
|
||||
strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str());
|
||||
|
||||
if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
|
||||
if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
|
||||
Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 10 max queued.
|
||||
listen(m_iSocketFD, 10);
|
||||
listen(m_iSocketFD.get(), 10);
|
||||
|
||||
Debug::log(LOG, "Hypr socket started at {}", m_socketPath);
|
||||
|
||||
m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
|
||||
m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
|
||||
}
|
||||
|
@@ -1,9 +1,10 @@
|
||||
#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);
|
||||
@@ -19,7 +20,7 @@ class CHyprCtl {
|
||||
void unregisterCommand(const SP<SHyprCtlCommand>& cmd);
|
||||
std::string getReply(std::string);
|
||||
|
||||
int m_iSocketFD = -1;
|
||||
Hyprutils::OS::CFileDescriptor m_iSocketFD;
|
||||
|
||||
struct {
|
||||
bool all = false;
|
||||
@@ -38,4 +39,4 @@ class CHyprCtl {
|
||||
std::string m_socketPath;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprCtl> g_pHyprCtl;
|
||||
inline UP<CHyprCtl> g_pHyprCtl;
|
||||
|
@@ -2,6 +2,9 @@
|
||||
#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>();
|
||||
@@ -195,10 +198,10 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
||||
double posX = 0, posY = 0;
|
||||
cairo_get_current_point(cr, &posX, &posY);
|
||||
|
||||
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
||||
g_pHyprRenderer->damageBox(m_wbLastDrawnBox);
|
||||
m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset + MARGIN_TOP - 1,
|
||||
(int)maxTextW + 2, posY - offset - MARGIN_TOP + 2};
|
||||
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
||||
g_pHyprRenderer->damageBox(m_wbLastDrawnBox);
|
||||
|
||||
return posY - offset;
|
||||
}
|
||||
@@ -268,6 +271,8 @@ void CHyprDebugOverlay::draw() {
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||
|
||||
CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
||||
g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f);
|
||||
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));
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../render/Texture.hpp"
|
||||
#include <cairo/cairo.h>
|
||||
#include <map>
|
||||
@@ -49,4 +48,4 @@ class CHyprDebugOverlay {
|
||||
friend class CHyprRenderer;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay;
|
||||
inline UP<CHyprDebugOverlay> g_pDebugOverlay;
|
||||
|
@@ -3,8 +3,13 @@
|
||||
#include "HyprNotificationOverlay.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../render/pass/TexPassElement.hpp"
|
||||
|
||||
inline auto iconBackendFromLayout(PangoLayout* layout) {
|
||||
#include "../managers/AnimationManager.hpp"
|
||||
#include "../managers/HookSystemManager.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
|
||||
static 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) {
|
||||
@@ -21,7 +26,7 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
||||
if (m_vNotifications.size() == 0)
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->damageBox(&m_bLastDamage);
|
||||
g_pHyprRenderer->damageBox(m_bLastDamage);
|
||||
});
|
||||
|
||||
m_pTexture = makeShared<CTexture>();
|
||||
@@ -35,7 +40,7 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() {
|
||||
}
|
||||
|
||||
void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) {
|
||||
const auto PNOTIF = m_vNotifications.emplace_back(std::make_unique<SNotification>()).get();
|
||||
const auto PNOTIF = m_vNotifications.emplace_back(makeUnique<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;
|
||||
@@ -220,8 +225,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);
|
||||
|
||||
@@ -241,8 +246,12 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||
|
||||
CBox pMonBox = {0, 0, MONSIZE.x, MONSIZE.y};
|
||||
g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f);
|
||||
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));
|
||||
}
|
||||
|
||||
bool CHyprNotificationOverlay::hasAny() {
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/Timer.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../render/Texture.hpp"
|
||||
#include "../SharedDefs.hpp"
|
||||
|
||||
@@ -50,7 +49,7 @@ class CHyprNotificationOverlay {
|
||||
CBox drawNotifications(PHLMONITOR pMonitor);
|
||||
CBox m_bLastDamage;
|
||||
|
||||
std::vector<std::unique_ptr<SNotification>> m_vNotifications;
|
||||
std::vector<UP<SNotification>> m_vNotifications;
|
||||
|
||||
cairo_surface_t* m_pCairoSurface = nullptr;
|
||||
cairo_t* m_pCairo = nullptr;
|
||||
@@ -61,4 +60,4 @@ class CHyprNotificationOverlay {
|
||||
SP<CTexture> m_pTexture;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay;
|
||||
inline UP<CHyprNotificationOverlay> g_pHyprNotificationOverlay;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#include "Log.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "RollingLogFollow.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
@@ -5,8 +5,6 @@
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include "../includes.hpp"
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
|
||||
#define LOGMESSAGESIZE 1024
|
||||
#define ROLLING_LOG_SIZE 4096
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "includes.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "helpers/Color.hpp"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "../macros.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
class CWorkspace;
|
||||
class CWindow;
|
||||
class CLayerSurface;
|
||||
|
@@ -1,3 +1,4 @@
|
||||
#include <re2/re2.h>
|
||||
#include "LayerRule.hpp"
|
||||
#include <unordered_set>
|
||||
#include <algorithm>
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include "Rule.hpp"
|
||||
|
||||
class CLayerRule {
|
||||
public:
|
||||
@@ -25,4 +26,6 @@ class CLayerRule {
|
||||
|
||||
const std::string targetNamespace;
|
||||
const std::string rule;
|
||||
|
||||
CRuleRegexContainer targetNamespaceRegex;
|
||||
};
|
@@ -4,6 +4,13 @@
|
||||
#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));
|
||||
@@ -25,22 +32,19 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
|
||||
pLS->szNamespace = resource->layerNamespace;
|
||||
|
||||
pLS->layer = resource->current.layer;
|
||||
pLS->popupHead = std::make_unique<CPopup>(pLS);
|
||||
pLS->popupHead = CPopup::create(pLS);
|
||||
pLS->monitor = pMonitor;
|
||||
pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS);
|
||||
|
||||
pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace);
|
||||
|
||||
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();
|
||||
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->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);
|
||||
|
||||
@@ -48,7 +52,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
|
||||
}
|
||||
|
||||
void CLayerSurface::registerCallbacks() {
|
||||
alpha.setUpdateCallback([this](void*) {
|
||||
alpha->setUpdateCallback([this](auto) {
|
||||
if (dimAround)
|
||||
g_pHyprRenderer->damageMonitor(monitor.lock());
|
||||
});
|
||||
@@ -93,7 +97,8 @@ void CLayerSurface::onDestroy() {
|
||||
onUnmap();
|
||||
} else {
|
||||
Debug::log(LOG, "Removing LayerSurface that wasn't mapped.");
|
||||
alpha.setValueAndWarp(0.f);
|
||||
if (alpha)
|
||||
alpha->setValueAndWarp(0.f);
|
||||
fadingOut = true;
|
||||
g_pCompositor->addToFadingOutSafe(self.lock());
|
||||
}
|
||||
@@ -110,7 +115,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;
|
||||
@@ -174,7 +179,7 @@ void CLayerSurface::onMap() {
|
||||
position = Vector2D(geometry.x, geometry.y);
|
||||
|
||||
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
|
||||
g_pHyprRenderer->damageBox(&geomFixed);
|
||||
g_pHyprRenderer->damageBox(geomFixed);
|
||||
const bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
|
||||
|
||||
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
|
||||
@@ -210,7 +215,7 @@ void CLayerSurface::onUnmap() {
|
||||
}
|
||||
|
||||
// make a snapshot and start fade
|
||||
g_pHyprOpenGL->makeLayerSnapshot(self.lock());
|
||||
g_pHyprRenderer->makeLayerSnapshot(self.lock());
|
||||
|
||||
startAnimation(false);
|
||||
|
||||
@@ -235,13 +240,13 @@ void CLayerSurface::onUnmap() {
|
||||
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->sendMotionEventsToFocused();
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
|
||||
}
|
||||
@@ -270,7 +275,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) {
|
||||
@@ -307,17 +312,17 @@ void CLayerSurface::onCommit() {
|
||||
}
|
||||
}
|
||||
|
||||
if (realPosition.goal() != geometry.pos()) {
|
||||
if (realPosition.isBeingAnimated())
|
||||
realPosition = geometry.pos();
|
||||
if (realPosition->goal() != geometry.pos()) {
|
||||
if (realPosition->isBeingAnimated())
|
||||
*realPosition = geometry.pos();
|
||||
else
|
||||
realPosition.setValueAndWarp(geometry.pos());
|
||||
realPosition->setValueAndWarp(geometry.pos());
|
||||
}
|
||||
if (realSize.goal() != geometry.size()) {
|
||||
if (realSize.isBeingAnimated())
|
||||
realSize = geometry.size();
|
||||
if (realSize->goal() != geometry.size()) {
|
||||
if (realSize->isBeingAnimated())
|
||||
*realSize = geometry.size();
|
||||
else
|
||||
realSize.setValueAndWarp(geometry.size());
|
||||
realSize->setValueAndWarp(geometry.size());
|
||||
}
|
||||
|
||||
if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) {
|
||||
@@ -327,7 +332,7 @@ void CLayerSurface::onCommit() {
|
||||
nullptr);
|
||||
if (!WASLASTFOCUS && popupHead) {
|
||||
popupHead->breadthfirst(
|
||||
[&WASLASTFOCUS](CPopup* popup, void* data) {
|
||||
[&WASLASTFOCUS](WP<CPopup> popup, void* data) {
|
||||
WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource());
|
||||
},
|
||||
nullptr);
|
||||
@@ -434,17 +439,17 @@ void CLayerSurface::applyRules() {
|
||||
}
|
||||
|
||||
void CLayerSurface::startAnimation(bool in, bool instant) {
|
||||
const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle);
|
||||
if (in) {
|
||||
realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn");
|
||||
realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn");
|
||||
alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn");
|
||||
realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn"));
|
||||
realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn"));
|
||||
alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"));
|
||||
} else {
|
||||
realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut");
|
||||
realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut");
|
||||
alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut");
|
||||
realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut"));
|
||||
realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut"));
|
||||
alpha->setConfig(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();
|
||||
@@ -485,9 +490,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;
|
||||
|
||||
@@ -512,11 +517,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")) {
|
||||
@@ -535,25 +540,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)
|
||||
@@ -564,7 +569,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() {
|
||||
@@ -572,10 +577,22 @@ int CLayerSurface::popupsCount() {
|
||||
return 0;
|
||||
|
||||
int no = -1; // we have one dummy
|
||||
popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no);
|
||||
popupHead->breadthfirst([](WP<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;
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include "../defines.hpp"
|
||||
#include "WLSurface.hpp"
|
||||
#include "../helpers/AnimatedVariable.hpp"
|
||||
#include "LayerRule.hpp"
|
||||
|
||||
class CLayerShellResource;
|
||||
|
||||
@@ -23,9 +22,9 @@ class CLayerSurface {
|
||||
bool isFadedOut();
|
||||
int popupsCount();
|
||||
|
||||
CAnimatedVariable<Vector2D> realPosition;
|
||||
CAnimatedVariable<Vector2D> realSize;
|
||||
CAnimatedVariable<float> alpha;
|
||||
PHLANIMVAR<Vector2D> realPosition;
|
||||
PHLANIMVAR<Vector2D> realSize;
|
||||
PHLANIMVAR<float> alpha;
|
||||
|
||||
WP<CLayerShellResource> layerSurface;
|
||||
wl_list link;
|
||||
@@ -60,7 +59,9 @@ class CLayerSurface {
|
||||
CBox geometry = {0, 0, 0, 0};
|
||||
Vector2D position;
|
||||
std::string szNamespace = "";
|
||||
std::unique_ptr<CPopup> popupHead;
|
||||
UP<CPopup> popupHead;
|
||||
|
||||
pid_t getPID();
|
||||
|
||||
void onDestroy();
|
||||
void onMap();
|
||||
|
@@ -6,24 +6,43 @@
|
||||
#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>
|
||||
|
||||
CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) {
|
||||
initAllSignals();
|
||||
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(PHLLS pOwner) : m_pLayerOwner(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(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) {
|
||||
m_pWLSurface = CWLSurface::create();
|
||||
m_pWLSurface->assign(popup->surface->surface.lock(), this);
|
||||
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());
|
||||
|
||||
m_vLastSize = popup->surface->current.geometry.size();
|
||||
reposition();
|
||||
popup->m_vLastSize = resource->surface->current.geometry.size();
|
||||
popup->reposition();
|
||||
|
||||
initAllSignals();
|
||||
popup->initAllSignals();
|
||||
return popup;
|
||||
}
|
||||
|
||||
CPopup::~CPopup() {
|
||||
@@ -54,7 +73,8 @@ void CPopup::initAllSignals() {
|
||||
}
|
||||
|
||||
void CPopup::onNewPopup(SP<CXDGPopupResource> popup) {
|
||||
const auto POPUP = m_vChildren.emplace_back(makeShared<CPopup>(popup, this)).get();
|
||||
const auto& POPUP = m_vChildren.emplace_back(CPopup::create(popup, m_pSelf));
|
||||
POPUP->m_pSelf = POPUP;
|
||||
Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP);
|
||||
}
|
||||
|
||||
@@ -79,13 +99,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 = std::make_unique<CSubsurface>(this);
|
||||
m_pSubsurfaceHead = CSubsurface::create(m_pSelf);
|
||||
|
||||
//unconstrain();
|
||||
sendScale();
|
||||
@@ -113,7 +133,7 @@ void CPopup::onUnmap() {
|
||||
|
||||
CBox box = m_pWLSurface->resource()->extends();
|
||||
box.translate(COORDS).expand(4);
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
g_pHyprRenderer->damageBox(box);
|
||||
|
||||
m_pSubsurfaceHead.reset();
|
||||
|
||||
@@ -122,19 +142,20 @@ void CPopup::onUnmap() {
|
||||
|
||||
// damage all children
|
||||
breadthfirst(
|
||||
[](CPopup* p, void* data) {
|
||||
[](WP<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);
|
||||
|
||||
const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource();
|
||||
// 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();
|
||||
// if (WASLASTFOCUS)
|
||||
// g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
|
||||
void CPopup::onCommit(bool ignoreSiblings) {
|
||||
@@ -166,10 +187,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;
|
||||
}
|
||||
@@ -219,7 +240,7 @@ Vector2D CPopup::coordsRelativeToParent() {
|
||||
if (!m_pResource)
|
||||
return {};
|
||||
|
||||
CPopup* current = this;
|
||||
WP<CPopup> current = m_pSelf;
|
||||
offset -= current->m_pResource->surface->current.geometry.pos();
|
||||
|
||||
while (current->m_pParent && current->m_pResource) {
|
||||
@@ -243,16 +264,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() {
|
||||
CPopup* curr = this;
|
||||
WP<CPopup> curr = m_pSelf;
|
||||
while (curr->m_pParent) {
|
||||
curr = curr->m_pParent;
|
||||
}
|
||||
@@ -261,7 +282,11 @@ void CPopup::recheckTree() {
|
||||
}
|
||||
|
||||
void CPopup::recheckChildrenRecursive() {
|
||||
auto cpy = m_vChildren;
|
||||
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); });
|
||||
for (auto const& c : cpy) {
|
||||
c->onCommit(true);
|
||||
c->recheckChildrenRecursive();
|
||||
@@ -292,17 +317,17 @@ bool CPopup::visible() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPopup::bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPopup*, void*)> fn, void* data) {
|
||||
void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(WP<CPopup>, void*)> fn, void* data) {
|
||||
for (auto const& n : nodes) {
|
||||
fn(n, data);
|
||||
}
|
||||
|
||||
std::vector<CPopup*> nodes2;
|
||||
std::vector<WP<CPopup>> nodes2;
|
||||
nodes2.reserve(nodes.size() * 2);
|
||||
|
||||
for (auto const& n : nodes) {
|
||||
for (auto const& c : n->m_vChildren) {
|
||||
nodes2.push_back(c.get());
|
||||
nodes2.push_back(c->m_pSelf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,35 +335,42 @@ void CPopup::bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPop
|
||||
bfHelper(nodes2, fn, data);
|
||||
}
|
||||
|
||||
void CPopup::breadthfirst(std::function<void(CPopup*, void*)> fn, void* data) {
|
||||
std::vector<CPopup*> popups;
|
||||
popups.push_back(this);
|
||||
void CPopup::breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data) {
|
||||
std::vector<WP<CPopup>> popups;
|
||||
popups.push_back(m_pSelf);
|
||||
bfHelper(popups, fn, data);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
for (auto const& p : popups | std::views::reverse) {
|
||||
if (!p->m_pResource || !p->m_bMapped)
|
||||
continue;
|
||||
|
||||
if (!allowsInput) {
|
||||
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();
|
||||
const bool HASSURFACE = p->m_pResource && p->m_pResource->surface;
|
||||
|
||||
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};
|
||||
if (BOX.containsPoint(globalCoords))
|
||||
return p;
|
||||
} else {
|
||||
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);
|
||||
const auto REGION = CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal());
|
||||
if (REGION.containsPoint(globalCoords))
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool CPopup::inert() const {
|
||||
return m_bInert;
|
||||
}
|
||||
|
@@ -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
|
||||
CPopup(PHLWINDOW pOwner);
|
||||
CPopup(PHLLS pOwner);
|
||||
static UP<CPopup> create(PHLWINDOW pOwner);
|
||||
static UP<CPopup> create(PHLLS pOwner);
|
||||
|
||||
// real nodes
|
||||
CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner);
|
||||
static UP<CPopup> create(SP<CXDGPopupResource> popup, WP<CPopup> pOwner);
|
||||
|
||||
~CPopup();
|
||||
|
||||
@@ -34,22 +34,26 @@ class CPopup {
|
||||
void recheckTree();
|
||||
|
||||
bool visible();
|
||||
bool inert() const;
|
||||
|
||||
// will also loop over this node
|
||||
void breadthfirst(std::function<void(CPopup*, void*)> fn, void* data);
|
||||
CPopup* at(const Vector2D& globalCoords, bool allowsInput = false);
|
||||
void breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data);
|
||||
WP<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
|
||||
CPopup* m_pParent = nullptr;
|
||||
WP<CPopup> m_pParent;
|
||||
|
||||
WP<CXDGPopupResource> m_pResource;
|
||||
|
||||
@@ -61,8 +65,8 @@ class CPopup {
|
||||
bool m_bInert = false;
|
||||
|
||||
//
|
||||
std::vector<SP<CPopup>> m_vChildren;
|
||||
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
|
||||
std::vector<UP<CPopup>> m_vChildren;
|
||||
UP<CSubsurface> m_pSubsurfaceHead;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener newPopup;
|
||||
@@ -81,5 +85,5 @@ class CPopup {
|
||||
|
||||
Vector2D localToGlobal(const Vector2D& rel);
|
||||
Vector2D t1ParentCoords();
|
||||
static void bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPopup*, void*)> fn, void* data);
|
||||
static void bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(WP<CPopup>, void*)> fn, void* data);
|
||||
};
|
||||
|
22
src/desktop/Rule.cpp
Normal file
22
src/desktop/Rule.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#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;
|
||||
}
|
21
src/desktop/Rule.hpp
Normal file
21
src/desktop/Rule.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#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,33 +4,50 @@
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../protocols/core/Subcompositor.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
|
||||
CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) {
|
||||
initSignals();
|
||||
initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
|
||||
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(CPopup* pOwner) : m_pPopupParent(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(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, 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, 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() {
|
||||
;
|
||||
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;
|
||||
}
|
||||
|
||||
void CSubsurface::initSignals() {
|
||||
@@ -90,7 +107,7 @@ void CSubsurface::onCommit() {
|
||||
|
||||
g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y);
|
||||
|
||||
if (m_pPopupParent)
|
||||
if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface)
|
||||
m_pPopupParent->recheckTree();
|
||||
if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this
|
||||
m_pWindowParent->m_pPopupHead->recheckTree();
|
||||
@@ -99,11 +116,20 @@ void CSubsurface::onCommit() {
|
||||
checkSiblingDamage();
|
||||
|
||||
if (m_vLastSize != m_pWLSurface->resource()->current.size) {
|
||||
CBox box{COORDS, m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
m_vLastSize = m_pWLSurface->resource()->current.size;
|
||||
box = {COORDS, m_vLastSize};
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,16 +147,18 @@ void CSubsurface::onDestroy() {
|
||||
}
|
||||
|
||||
void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) {
|
||||
CSubsurface* PSUBSURFACE = nullptr;
|
||||
WP<CSubsurface> PSUBSURFACE;
|
||||
|
||||
if (!m_pWindowParent.expired())
|
||||
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pWindowParent.lock())).get();
|
||||
PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pWindowParent.lock()));
|
||||
else if (m_pPopupParent)
|
||||
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pPopupParent)).get();
|
||||
PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pPopupParent));
|
||||
|
||||
PSUBSURFACE->m_pSelf = PSUBSURFACE;
|
||||
|
||||
ASSERT(PSUBSURFACE);
|
||||
|
||||
PSUBSURFACE->m_pParent = this;
|
||||
PSUBSURFACE->m_pParent = m_pSelf;
|
||||
}
|
||||
|
||||
void CSubsurface::onMap() {
|
||||
@@ -139,7 +167,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();
|
||||
@@ -149,7 +177,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();
|
||||
@@ -169,7 +197,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,14 +10,14 @@ class CWLSubsurfaceResource;
|
||||
class CSubsurface {
|
||||
public:
|
||||
// root dummy nodes
|
||||
CSubsurface(PHLWINDOW pOwner);
|
||||
CSubsurface(CPopup* pOwner);
|
||||
static UP<CSubsurface> create(PHLWINDOW pOwner);
|
||||
static UP<CSubsurface> create(WP<CPopup> pOwner);
|
||||
|
||||
// real nodes
|
||||
CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner);
|
||||
CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner);
|
||||
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner);
|
||||
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner);
|
||||
|
||||
~CSubsurface();
|
||||
~CSubsurface() = default;
|
||||
|
||||
Vector2D coordsRelativeToParent();
|
||||
Vector2D coordsGlobal();
|
||||
@@ -34,7 +34,11 @@ class CSubsurface {
|
||||
|
||||
void recheckDamageForSubsurfaces();
|
||||
|
||||
WP<CSubsurface> m_pSelf;
|
||||
|
||||
private:
|
||||
CSubsurface() = default;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener destroySubsurface;
|
||||
CHyprSignalListener commitSubsurface;
|
||||
@@ -48,12 +52,12 @@ class CSubsurface {
|
||||
Vector2D m_vLastSize = {};
|
||||
|
||||
// if nullptr, means it's a dummy node
|
||||
CSubsurface* m_pParent = nullptr;
|
||||
WP<CSubsurface> m_pParent;
|
||||
|
||||
PHLWINDOWREF m_pWindowParent;
|
||||
CPopup* m_pPopupParent = nullptr;
|
||||
WP<CPopup> m_pPopupParent;
|
||||
|
||||
std::vector<std::unique_ptr<CSubsurface>> m_vChildren;
|
||||
std::vector<UP<CSubsurface>> m_vChildren;
|
||||
|
||||
bool m_bInert = false;
|
||||
|
||||
|
@@ -1,7 +1,9 @@
|
||||
#include "WLSurface.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "LayerSurface.hpp"
|
||||
#include "../desktop/Window.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
|
||||
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
|
||||
m_pResource = pSurface;
|
||||
@@ -72,7 +74,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 {
|
||||
@@ -96,7 +98,7 @@ CRegion CWLSurface::computeDamage() const {
|
||||
if (!m_pResource->current.texture)
|
||||
return {};
|
||||
|
||||
CRegion damage = m_pResource->accumulateCurrentBufferDamage();
|
||||
CRegion damage = m_pResource->current.accumulateBufferDamage();
|
||||
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,7 +84,11 @@ class CWLSurface {
|
||||
static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface);
|
||||
|
||||
// used by the alpha-modifier protocol
|
||||
float m_pAlphaModifier = 1.F;
|
||||
float m_fAlphaModifier = 1.F;
|
||||
|
||||
// used by the hyprland-surface protocol
|
||||
float m_fOverallOpacity = 1.F;
|
||||
CRegion m_visibleRegion;
|
||||
|
||||
struct {
|
||||
CSignal destroy;
|
||||
@@ -116,4 +120,5 @@ class CWLSurface {
|
||||
} listeners;
|
||||
|
||||
friend class CPointerConstraint;
|
||||
friend class CXxColorManagerV4;
|
||||
};
|
@@ -1,3 +1,4 @@
|
||||
#include <hyprutils/animation/AnimatedVariable.hpp>
|
||||
#include <re2/re2.h>
|
||||
|
||||
#include <any>
|
||||
@@ -11,12 +12,26 @@
|
||||
#include "../render/decorations/CHyprBorderDecoration.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../managers/TokenManager.hpp"
|
||||
#include "../managers/AnimationManager.hpp"
|
||||
#include "../managers/ANRManager.hpp"
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../protocols/ContentType.hpp"
|
||||
#include "../xwayland/XWayland.hpp"
|
||||
#include "../helpers/Color.hpp"
|
||||
#include "../events/Events.hpp"
|
||||
#include "../managers/XWaylandManager.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
#include "../managers/LayoutManager.hpp"
|
||||
#include "../managers/HookSystemManager.hpp"
|
||||
#include "../managers/EventManager.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::Animation;
|
||||
using enum NContentType::eContentType;
|
||||
|
||||
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
|
||||
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
|
||||
@@ -24,18 +39,20 @@ PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
|
||||
pWindow->m_pSelf = pWindow;
|
||||
pWindow->m_bIsX11 = true;
|
||||
|
||||
pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER);
|
||||
pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER);
|
||||
pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
|
||||
pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderFadeAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderAngleAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER);
|
||||
g_pAnimationManager->createAnimation(1.f, pWindow->m_fAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(1.f, pWindow->m_fActiveInactiveAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(CHyprColor(), pWindow->m_cRealShadowColor, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
|
||||
pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
|
||||
pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
|
||||
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
|
||||
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
|
||||
|
||||
return pWindow;
|
||||
}
|
||||
@@ -46,18 +63,20 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
|
||||
pWindow->m_pSelf = pWindow;
|
||||
resource->toplevel->window = pWindow;
|
||||
|
||||
pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER);
|
||||
pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER);
|
||||
pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
|
||||
pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderFadeAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderAngleAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER);
|
||||
g_pAnimationManager->createAnimation(1.f, pWindow->m_fAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(1.f, pWindow->m_fActiveInactiveAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(CHyprColor(), pWindow->m_cRealShadowColor, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
|
||||
pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
|
||||
pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
|
||||
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
|
||||
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
|
||||
|
||||
pWindow->m_pWLSurface->assign(pWindow->m_pXDGSurface->surface.lock(), pWindow);
|
||||
|
||||
@@ -83,7 +102,7 @@ CWindow::CWindow(SP<CXWaylandSurface> surface) : m_pXWaylandSurface(surface) {
|
||||
listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); });
|
||||
listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); });
|
||||
listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); });
|
||||
listeners.configure = m_pXWaylandSurface->events.configure.registerListener([this](std::any d) { onX11Configure(std::any_cast<CBox>(d)); });
|
||||
listeners.configureRequest = m_pXWaylandSurface->events.configureRequest.registerListener([this](std::any d) { onX11ConfigureRequest(std::any_cast<CBox>(d)); });
|
||||
listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); });
|
||||
listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); });
|
||||
listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); });
|
||||
@@ -94,7 +113,7 @@ CWindow::CWindow(SP<CXWaylandSurface> surface) : m_pXWaylandSurface(surface) {
|
||||
}
|
||||
|
||||
CWindow::~CWindow() {
|
||||
if (g_pCompositor->m_pLastWindow.lock().get() == this) {
|
||||
if (g_pCompositor->m_pLastWindow == m_pSelf) {
|
||||
g_pCompositor->m_pLastFocus.reset();
|
||||
g_pCompositor->m_pLastWindow.reset();
|
||||
}
|
||||
@@ -105,7 +124,7 @@ CWindow::~CWindow() {
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return !other.first.lock() || other.first.lock().get() == this; });
|
||||
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.get() == this; });
|
||||
}
|
||||
|
||||
SBoxExtents CWindow::getFullWindowExtents() {
|
||||
@@ -116,8 +135,8 @@ SBoxExtents CWindow::getFullWindowExtents() {
|
||||
|
||||
if (m_sWindowData.dimAround.valueOrDefault()) {
|
||||
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
|
||||
return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
|
||||
{PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
|
||||
return {{m_vRealPosition->value().x - PMONITOR->vecPosition.x, m_vRealPosition->value().y - PMONITOR->vecPosition.y},
|
||||
{PMONITOR->vecSize.x - (m_vRealPosition->value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition->value().y - PMONITOR->vecPosition.y)}};
|
||||
}
|
||||
|
||||
SBoxExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||
@@ -140,7 +159,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
|
||||
CBox surfaceExtents = {0, 0, 0, 0};
|
||||
// TODO: this could be better, perhaps make a getFullWindowRegion?
|
||||
m_pPopupHead->breadthfirst(
|
||||
[](CPopup* popup, void* data) {
|
||||
[](WP<CPopup> popup, void* data) {
|
||||
if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource())
|
||||
return;
|
||||
|
||||
@@ -181,8 +200,8 @@ CBox CWindow::getFullWindowBoundingBox() {
|
||||
|
||||
auto maxExtents = getFullWindowExtents();
|
||||
|
||||
CBox finalBox = {m_vRealPosition.value().x - maxExtents.topLeft.x, m_vRealPosition.value().y - maxExtents.topLeft.y,
|
||||
m_vRealSize.value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||
CBox finalBox = {m_vRealPosition->value().x - maxExtents.topLeft.x, m_vRealPosition->value().y - maxExtents.topLeft.y,
|
||||
m_vRealSize->value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize->value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||
|
||||
return finalBox;
|
||||
}
|
||||
@@ -236,7 +255,7 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) {
|
||||
if (properties & FULL_EXTENTS)
|
||||
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(m_pSelf.lock(), false));
|
||||
|
||||
CBox box = {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
|
||||
CBox box = {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y};
|
||||
box.addExtents(EXTENTS);
|
||||
|
||||
return box;
|
||||
@@ -268,6 +287,8 @@ void CWindow::updateWindowDecos() {
|
||||
|
||||
// make a copy because updateWindow can remove decos.
|
||||
std::vector<IHyprWindowDecoration*> decos;
|
||||
// reserve to avoid reallocations
|
||||
decos.reserve(m_dWindowDecorations.size());
|
||||
|
||||
for (auto const& wd : m_dWindowDecorations) {
|
||||
decos.push_back(wd.get());
|
||||
@@ -280,7 +301,7 @@ void CWindow::updateWindowDecos() {
|
||||
}
|
||||
}
|
||||
|
||||
void CWindow::addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco) {
|
||||
void CWindow::addWindowDeco(UP<IHyprWindowDecoration> deco) {
|
||||
m_dWindowDecorations.emplace_back(std::move(deco));
|
||||
g_pDecorationPositioner->forceRecalcFor(m_pSelf.lock());
|
||||
updateWindowDecos();
|
||||
@@ -394,7 +415,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
|
||||
if (*PINITIALWSTRACKING == 2) {
|
||||
// persistent
|
||||
SInitialWorkspaceToken token = std::any_cast<SInitialWorkspaceToken>(TOKEN->data);
|
||||
if (token.primaryOwner.lock().get() == this) {
|
||||
if (token.primaryOwner == m_pSelf) {
|
||||
token.workspace = pWorkspace->getConfigName();
|
||||
TOKEN->data = token;
|
||||
}
|
||||
@@ -406,10 +427,12 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
|
||||
|
||||
const auto OLDWORKSPACE = m_pWorkspace;
|
||||
|
||||
if (OLDWORKSPACE->isVisible()) {
|
||||
m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F);
|
||||
*m_fMovingToWorkspaceAlpha = 0.F;
|
||||
m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; });
|
||||
m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1;
|
||||
m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F);
|
||||
m_fMovingToWorkspaceAlpha = 0.F;
|
||||
m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; });
|
||||
}
|
||||
|
||||
m_pWorkspace = pWorkspace;
|
||||
|
||||
@@ -432,12 +455,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
|
||||
}
|
||||
|
||||
if (const auto SWALLOWED = m_pSwallowed.lock()) {
|
||||
if (SWALLOWED->m_bCurrentlySwallowed) {
|
||||
SWALLOWED->moveToWorkspace(pWorkspace);
|
||||
SWALLOWED->m_pMonitor = m_pMonitor;
|
||||
}
|
||||
|
||||
// update xwayland coords
|
||||
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value());
|
||||
}
|
||||
|
||||
if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) {
|
||||
if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR)
|
||||
@@ -473,19 +495,6 @@ PHLWINDOW CWindow::x11TransientFor() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CWindow::removeDecorationByType(eDecorationType type) {
|
||||
for (auto const& wd : m_dWindowDecorations) {
|
||||
if (wd->getDecorationType() == type)
|
||||
m_vDecosToRemove.push_back(wd.get());
|
||||
}
|
||||
|
||||
updateWindowDecos();
|
||||
}
|
||||
|
||||
void unregisterVar(void* ptr) {
|
||||
((CBaseAnimatedVariable*)ptr)->unregister();
|
||||
}
|
||||
|
||||
void CWindow::onUnmap() {
|
||||
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
|
||||
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
|
||||
@@ -496,7 +505,7 @@ void CWindow::onUnmap() {
|
||||
if (*PINITIALWSTRACKING == 2) {
|
||||
// persistent token, but the first window got removed so the token is gone
|
||||
SInitialWorkspaceToken token = std::any_cast<SInitialWorkspaceToken>(TOKEN->data);
|
||||
if (token.primaryOwner.lock().get() == this)
|
||||
if (token.primaryOwner == m_pSelf)
|
||||
g_pTokenManager->removeToken(TOKEN);
|
||||
}
|
||||
}
|
||||
@@ -504,19 +513,7 @@ void CWindow::onUnmap() {
|
||||
|
||||
m_iLastWorkspace = m_pWorkspace->m_iID;
|
||||
|
||||
m_vRealPosition.setCallbackOnEnd(unregisterVar);
|
||||
m_vRealSize.setCallbackOnEnd(unregisterVar);
|
||||
m_fBorderFadeAnimationProgress.setCallbackOnEnd(unregisterVar);
|
||||
m_fBorderAngleAnimationProgress.setCallbackOnEnd(unregisterVar);
|
||||
m_fActiveInactiveAlpha.setCallbackOnEnd(unregisterVar);
|
||||
m_fAlpha.setCallbackOnEnd(unregisterVar);
|
||||
m_cRealShadowColor.setCallbackOnEnd(unregisterVar);
|
||||
m_fDimPercent.setCallbackOnEnd(unregisterVar);
|
||||
m_fMovingToWorkspaceAlpha.setCallbackOnEnd(unregisterVar);
|
||||
|
||||
m_vRealSize.setCallbackOnBegin(nullptr);
|
||||
|
||||
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; });
|
||||
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [this](const auto& other) { return other.expired() || other == m_pSelf; });
|
||||
|
||||
if (*PCLOSEONLASTSPECIAL && m_pWorkspace && m_pWorkspace->getWindows() == 0 && onSpecialWorkspace()) {
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
@@ -526,7 +523,7 @@ void CWindow::onUnmap() {
|
||||
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
|
||||
if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this)
|
||||
if (PMONITOR && PMONITOR->solitaryClient == m_pSelf)
|
||||
PMONITOR->solitaryClient.reset();
|
||||
|
||||
if (m_pWorkspace) {
|
||||
@@ -547,30 +544,35 @@ void CWindow::onUnmap() {
|
||||
|
||||
void CWindow::onMap() {
|
||||
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
|
||||
m_vRealPosition.resetAllCallbacks();
|
||||
m_vRealSize.resetAllCallbacks();
|
||||
m_fBorderFadeAnimationProgress.resetAllCallbacks();
|
||||
m_fBorderAngleAnimationProgress.resetAllCallbacks();
|
||||
m_fActiveInactiveAlpha.resetAllCallbacks();
|
||||
m_fAlpha.resetAllCallbacks();
|
||||
m_cRealShadowColor.resetAllCallbacks();
|
||||
m_fDimPercent.resetAllCallbacks();
|
||||
m_fMovingToWorkspaceAlpha.resetAllCallbacks();
|
||||
m_vRealPosition->resetAllCallbacks();
|
||||
m_vRealSize->resetAllCallbacks();
|
||||
m_fBorderFadeAnimationProgress->resetAllCallbacks();
|
||||
m_fBorderAngleAnimationProgress->resetAllCallbacks();
|
||||
m_fActiveInactiveAlpha->resetAllCallbacks();
|
||||
m_fAlpha->resetAllCallbacks();
|
||||
m_cRealShadowColor->resetAllCallbacks();
|
||||
m_fDimPercent->resetAllCallbacks();
|
||||
m_fMovingToWorkspaceAlpha->resetAllCallbacks();
|
||||
m_fMovingFromWorkspaceAlpha->resetAllCallbacks();
|
||||
|
||||
m_vRealPosition.registerVar();
|
||||
m_vRealSize.registerVar();
|
||||
m_fBorderFadeAnimationProgress.registerVar();
|
||||
m_fBorderAngleAnimationProgress.registerVar();
|
||||
m_fActiveInactiveAlpha.registerVar();
|
||||
m_fAlpha.registerVar();
|
||||
m_cRealShadowColor.registerVar();
|
||||
m_fDimPercent.registerVar();
|
||||
m_fMovingToWorkspaceAlpha.registerVar();
|
||||
m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F);
|
||||
|
||||
m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false);
|
||||
if (m_fBorderAngleAnimationProgress->enabled()) {
|
||||
m_fBorderAngleAnimationProgress->setValueAndWarp(0.f);
|
||||
m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP<CBaseAnimatedVariable> p) { onBorderAngleAnimEnd(p); }, false);
|
||||
*m_fBorderAngleAnimationProgress = 1.f;
|
||||
}
|
||||
|
||||
m_fBorderAngleAnimationProgress.setValueAndWarp(0.f);
|
||||
m_fBorderAngleAnimationProgress = 1.f;
|
||||
m_vRealSize->setCallbackOnBegin(
|
||||
[this](auto) {
|
||||
if (!m_bIsMapped || isX11OverrideRedirect())
|
||||
return;
|
||||
|
||||
sendWindowSize();
|
||||
},
|
||||
false);
|
||||
|
||||
m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F);
|
||||
|
||||
g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf);
|
||||
|
||||
@@ -582,32 +584,33 @@ void CWindow::onMap() {
|
||||
if (m_bIsX11)
|
||||
return;
|
||||
|
||||
m_pSubsurfaceHead = std::make_unique<CSubsurface>(m_pSelf.lock());
|
||||
m_pPopupHead = std::make_unique<CPopup>(m_pSelf.lock());
|
||||
m_pSubsurfaceHead = CSubsurface::create(m_pSelf.lock());
|
||||
m_pPopupHead = CPopup::create(m_pSelf.lock());
|
||||
}
|
||||
|
||||
void CWindow::onBorderAngleAnimEnd(void* ptr) {
|
||||
const auto PANIMVAR = (CAnimatedVariable<float>*)ptr;
|
||||
|
||||
const std::string STYLE = PANIMVAR->getConfig()->pValues->internalStyle;
|
||||
|
||||
if (STYLE != "loop" || !PANIMVAR->getConfig()->pValues->internalEnabled)
|
||||
void CWindow::onBorderAngleAnimEnd(WP<CBaseAnimatedVariable> pav) {
|
||||
const auto PAV = pav.lock();
|
||||
if (!PAV)
|
||||
return;
|
||||
|
||||
if (PAV->getStyle() != "loop" || !PAV->enabled())
|
||||
return;
|
||||
|
||||
const auto PANIMVAR = dynamic_cast<CAnimatedVariable<float>*>(PAV.get());
|
||||
|
||||
PANIMVAR->setCallbackOnEnd(nullptr); // we remove the callback here because otherwise setvalueandwarp will recurse this
|
||||
|
||||
PANIMVAR->setValueAndWarp(0);
|
||||
*PANIMVAR = 1.f;
|
||||
|
||||
PANIMVAR->setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false);
|
||||
PANIMVAR->setCallbackOnEnd([&](WP<CBaseAnimatedVariable> pav) { onBorderAngleAnimEnd(pav); }, false);
|
||||
}
|
||||
|
||||
void CWindow::setHidden(bool hidden) {
|
||||
m_bHidden = hidden;
|
||||
|
||||
if (hidden && g_pCompositor->m_pLastWindow.lock().get() == this) {
|
||||
if (hidden && g_pCompositor->m_pLastWindow == m_pSelf)
|
||||
g_pCompositor->m_pLastWindow.reset();
|
||||
}
|
||||
|
||||
setSuspended(hidden);
|
||||
}
|
||||
@@ -773,21 +776,25 @@ void CWindow::applyDynamicRule(const SP<CWindowRule>& r) {
|
||||
}
|
||||
case CWindowRule::RULE_PROP: {
|
||||
const CVarList VARS(r->szRule, 0, ' ');
|
||||
if (auto search = g_pConfigManager->miWindowProperties.find(VARS[1]); search != g_pConfigManager->miWindowProperties.end()) {
|
||||
if (auto search = NWindowProperties::intWindowProperties.find(VARS[1]); search != NWindowProperties::intWindowProperties.end()) {
|
||||
try {
|
||||
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[2]), priority);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
|
||||
} else if (auto search = g_pConfigManager->mfWindowProperties.find(VARS[1]); search != g_pConfigManager->mfWindowProperties.end()) {
|
||||
} else if (auto search = NWindowProperties::floatWindowProperties.find(VARS[1]); search != NWindowProperties::floatWindowProperties.end()) {
|
||||
try {
|
||||
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stof(VARS[2]), priority);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
|
||||
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[1]); search != g_pConfigManager->mbWindowProperties.end()) {
|
||||
} else if (auto search = NWindowProperties::boolWindowProperties.find(VARS[1]); search != NWindowProperties::boolWindowProperties.end()) {
|
||||
try {
|
||||
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(VARS[2].empty() ? true : (bool)std::stoi(VARS[2]), priority);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CWindowRule::RULE_PERSISTENTSIZE: {
|
||||
m_sWindowData.persistentSize = CWindowOverridableVar(true, PRIORITY_WINDOW_RULE);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -827,26 +834,27 @@ void CWindow::updateDynamicRules() {
|
||||
// otherwise behaviour is undefined
|
||||
bool CWindow::isInCurvedCorner(double x, double y) {
|
||||
const int ROUNDING = rounding();
|
||||
const int ROUNDINGPOWER = roundingPower();
|
||||
if (getRealBorderSize() >= ROUNDING)
|
||||
return false;
|
||||
|
||||
// (x0, y0), (x0, y1), ... are the center point of rounding at each corner
|
||||
double x0 = m_vRealPosition.value().x + ROUNDING;
|
||||
double y0 = m_vRealPosition.value().y + ROUNDING;
|
||||
double x1 = m_vRealPosition.value().x + m_vRealSize.value().x - ROUNDING;
|
||||
double y1 = m_vRealPosition.value().y + m_vRealSize.value().y - ROUNDING;
|
||||
double x0 = m_vRealPosition->value().x + ROUNDING;
|
||||
double y0 = m_vRealPosition->value().y + ROUNDING;
|
||||
double x1 = m_vRealPosition->value().x + m_vRealSize->value().x - ROUNDING;
|
||||
double y1 = m_vRealPosition->value().y + m_vRealSize->value().y - ROUNDING;
|
||||
|
||||
if (x < x0 && y < y0) {
|
||||
return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||
return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER);
|
||||
}
|
||||
if (x > x1 && y < y0) {
|
||||
return Vector2D{x1, y0}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||
return std::pow(x - x1, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER);
|
||||
}
|
||||
if (x < x0 && y > y1) {
|
||||
return Vector2D{x0, y1}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||
return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y - y1, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER);
|
||||
}
|
||||
if (x > x1 && y > y1) {
|
||||
return Vector2D{x1, y1}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||
return std::pow(x - x1, ROUNDINGPOWER) + std::pow(y - y1, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -857,7 +865,7 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
|
||||
if (m_bIsX11)
|
||||
return false;
|
||||
|
||||
CPopup* popup = m_pPopupHead->at(pos);
|
||||
auto popup = m_pPopupHead->at(pos);
|
||||
|
||||
return popup && popup->m_pWLSurface->resource();
|
||||
}
|
||||
@@ -882,7 +890,7 @@ void CWindow::createGroup() {
|
||||
m_sGroupData.locked = false;
|
||||
m_sGroupData.deny = false;
|
||||
|
||||
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock()));
|
||||
addWindowDeco(makeUnique<CHyprGroupBarDecoration>(m_pSelf.lock()));
|
||||
|
||||
if (m_pWorkspace) {
|
||||
m_pWorkspace->updateWindows();
|
||||
@@ -896,7 +904,7 @@ void CWindow::createGroup() {
|
||||
}
|
||||
|
||||
void CWindow::destroyGroup() {
|
||||
if (m_sGroupData.pNextWindow.lock().get() == this) {
|
||||
if (m_sGroupData.pNextWindow == m_pSelf) {
|
||||
if (m_eGroupRules & GROUP_SET_ALWAYS) {
|
||||
Debug::log(LOG, "destoryGroup: window:{:x},title:{} has rule [group set always], ignored", (uintptr_t)this, this->m_szTitle);
|
||||
return;
|
||||
@@ -978,7 +986,7 @@ PHLWINDOW CWindow::getGroupCurrent() {
|
||||
int CWindow::getGroupSize() {
|
||||
int size = 1;
|
||||
PHLWINDOW curr = m_pSelf.lock();
|
||||
while (curr->m_sGroupData.pNextWindow.lock().get() != this) {
|
||||
while (curr->m_sGroupData.pNextWindow != m_pSelf) {
|
||||
curr = curr->m_sGroupData.pNextWindow.lock();
|
||||
size++;
|
||||
}
|
||||
@@ -1028,22 +1036,22 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
|
||||
const auto WORKSPACE = PCURRENT->m_pWorkspace;
|
||||
const auto MODE = PCURRENT->m_sFullscreenState.internal;
|
||||
|
||||
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
|
||||
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
|
||||
|
||||
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow.lock();
|
||||
|
||||
if (FULLSCREEN)
|
||||
g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE);
|
||||
|
||||
const auto PWINDOWSIZE = PCURRENT->m_vRealSize->goal();
|
||||
const auto PWINDOWPOS = PCURRENT->m_vRealPosition->goal();
|
||||
|
||||
PCURRENT->setHidden(true);
|
||||
pWindow->setHidden(false); // can remove m_pLastWindow
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->replaceWindowDataWith(PCURRENT, pWindow);
|
||||
|
||||
if (PCURRENT->m_bIsFloating) {
|
||||
pWindow->m_vRealPosition.setValueAndWarp(PWINDOWPOS);
|
||||
pWindow->m_vRealSize.setValueAndWarp(PWINDOWSIZE);
|
||||
pWindow->m_vRealPosition->setValueAndWarp(PWINDOWPOS);
|
||||
pWindow->m_vRealSize->setValueAndWarp(PWINDOWSIZE);
|
||||
}
|
||||
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
@@ -1064,7 +1072,7 @@ void CWindow::insertWindowToGroup(PHLWINDOW pWindow) {
|
||||
const auto ENDAT = m_sGroupData.pNextWindow.lock();
|
||||
|
||||
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
|
||||
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
|
||||
pWindow->addWindowDeco(makeUnique<CHyprGroupBarDecoration>(pWindow));
|
||||
|
||||
if (!pWindow->m_sGroupData.pNextWindow.lock()) {
|
||||
BEGINAT->m_sGroupData.pNextWindow = pWindow;
|
||||
@@ -1084,7 +1092,7 @@ void CWindow::insertWindowToGroup(PHLWINDOW pWindow) {
|
||||
PHLWINDOW CWindow::getGroupPrevious() {
|
||||
PHLWINDOW curr = m_sGroupData.pNextWindow.lock();
|
||||
|
||||
while (curr != m_pSelf.lock() && curr->m_sGroupData.pNextWindow.lock().get() != this)
|
||||
while (curr != m_pSelf && curr->m_sGroupData.pNextWindow != m_pSelf)
|
||||
curr = curr->m_sGroupData.pNextWindow.lock();
|
||||
|
||||
return curr;
|
||||
@@ -1099,7 +1107,7 @@ void CWindow::switchWithWindowInGroup(PHLWINDOW pWindow) {
|
||||
m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow;
|
||||
pWindow->m_sGroupData.pNextWindow = m_pSelf;
|
||||
|
||||
} else if (pWindow->m_sGroupData.pNextWindow.lock().get() == this) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B
|
||||
} else if (pWindow->m_sGroupData.pNextWindow == m_pSelf) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B
|
||||
pWindow->getGroupPrevious()->m_sGroupData.pNextWindow = m_pSelf;
|
||||
pWindow->m_sGroupData.pNextWindow = m_sGroupData.pNextWindow;
|
||||
m_sGroupData.pNextWindow = pWindow;
|
||||
@@ -1125,22 +1133,22 @@ void CWindow::updateGroupOutputs() {
|
||||
curr->m_pMonitor = m_pMonitor;
|
||||
curr->moveToWorkspace(WS);
|
||||
|
||||
curr->m_vRealPosition = m_vRealPosition.goal();
|
||||
curr->m_vRealSize = m_vRealSize.goal();
|
||||
*curr->m_vRealPosition = m_vRealPosition->goal();
|
||||
*curr->m_vRealSize = m_vRealSize->goal();
|
||||
|
||||
curr = curr->m_sGroupData.pNextWindow.lock();
|
||||
}
|
||||
}
|
||||
|
||||
Vector2D CWindow::middle() {
|
||||
return m_vRealPosition.goal() + m_vRealSize.goal() / 2.f;
|
||||
return m_vRealPosition->goal() + m_vRealSize->goal() / 2.f;
|
||||
}
|
||||
|
||||
bool CWindow::opaque() {
|
||||
if (m_fAlpha.value() != 1.f || m_fActiveInactiveAlpha.value() != 1.f)
|
||||
if (m_fAlpha->value() != 1.f || m_fActiveInactiveAlpha->value() != 1.f)
|
||||
return false;
|
||||
|
||||
if (m_vRealSize.goal().floor() != m_vReportedSize)
|
||||
if (m_vRealSize->goal().floor() != m_vReportedSize)
|
||||
return false;
|
||||
|
||||
const auto PWORKSPACE = m_pWorkspace;
|
||||
@@ -1148,7 +1156,7 @@ bool CWindow::opaque() {
|
||||
if (m_pWLSurface->small() && !m_pWLSurface->m_bFillIgnoreSmall)
|
||||
return false;
|
||||
|
||||
if (PWORKSPACE->m_fAlpha.value() != 1.f)
|
||||
if (PWORKSPACE->m_fAlpha->value() != 1.f)
|
||||
return false;
|
||||
|
||||
if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.texture)
|
||||
@@ -1167,12 +1175,20 @@ bool CWindow::opaque() {
|
||||
|
||||
float CWindow::rounding() {
|
||||
static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding");
|
||||
static auto PROUNDINGPOWER = CConfigValue<Hyprlang::FLOAT>("decoration:rounding_power");
|
||||
|
||||
float rounding = m_sWindowData.rounding.valueOr(*PROUNDING);
|
||||
float roundingPower = m_sWindowData.roundingPower.valueOr(*PROUNDINGPOWER);
|
||||
float rounding = m_sWindowData.rounding.valueOr(*PROUNDING) * (roundingPower / 2.0); /* Make perceived roundness consistent. */
|
||||
|
||||
return m_sWindowData.noRounding.valueOrDefault() ? 0 : rounding;
|
||||
}
|
||||
|
||||
float CWindow::roundingPower() {
|
||||
static auto PROUNDINGPOWER = CConfigValue<Hyprlang::FLOAT>("decoration:rounding_power");
|
||||
|
||||
return m_sWindowData.roundingPower.valueOr(*PROUNDINGPOWER);
|
||||
}
|
||||
|
||||
void CWindow::updateWindowData() {
|
||||
const auto PWORKSPACE = m_pWorkspace;
|
||||
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
|
||||
@@ -1230,21 +1246,19 @@ void CWindow::setSuspended(bool suspend) {
|
||||
}
|
||||
|
||||
bool CWindow::visibleOnMonitor(PHLMONITOR pMonitor) {
|
||||
CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()};
|
||||
CBox wbox = {m_vRealPosition->value(), m_vRealSize->value()};
|
||||
|
||||
return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty();
|
||||
}
|
||||
|
||||
void CWindow::setAnimationsToMove() {
|
||||
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
|
||||
m_vRealPosition.setConfig(PANIMCFG);
|
||||
m_vRealSize.setConfig(PANIMCFG);
|
||||
m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
|
||||
m_bAnimatingIn = false;
|
||||
}
|
||||
|
||||
void CWindow::onWorkspaceAnimUpdate() {
|
||||
// clip box for animated offsets
|
||||
if (!m_bIsFloating || m_bPinned || isFullscreen()) {
|
||||
if (!m_bIsFloating || m_bPinned || isFullscreen() || m_bDraggingTiled) {
|
||||
m_vFloatingOffset = Vector2D(0, 0);
|
||||
return;
|
||||
}
|
||||
@@ -1259,16 +1273,16 @@ void CWindow::onWorkspaceAnimUpdate() {
|
||||
return;
|
||||
|
||||
const auto WINBB = getFullWindowBoundingBox();
|
||||
if (PWORKSPACE->m_vRenderOffset.value().x != 0) {
|
||||
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().x / PWSMON->vecSize.x;
|
||||
if (PWORKSPACE->m_vRenderOffset->value().x != 0) {
|
||||
const auto PROGRESS = PWORKSPACE->m_vRenderOffset->value().x / PWSMON->vecSize.x;
|
||||
|
||||
if (WINBB.x < PWSMON->vecPosition.x)
|
||||
offset.x += (PWSMON->vecPosition.x - WINBB.x) * PROGRESS;
|
||||
|
||||
if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x)
|
||||
offset.x += (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS;
|
||||
} else if (PWORKSPACE->m_vRenderOffset.value().y != 0) {
|
||||
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().y / PWSMON->vecSize.y;
|
||||
} else if (PWORKSPACE->m_vRenderOffset->value().y != 0) {
|
||||
const auto PROGRESS = PWORKSPACE->m_vRenderOffset->value().y / PWSMON->vecSize.y;
|
||||
|
||||
if (WINBB.y < PWSMON->vecPosition.y)
|
||||
offset.y += (PWSMON->vecPosition.y - WINBB.y) * PROGRESS;
|
||||
@@ -1280,12 +1294,20 @@ void CWindow::onWorkspaceAnimUpdate() {
|
||||
m_vFloatingOffset = offset;
|
||||
}
|
||||
|
||||
void CWindow::onFocusAnimUpdate() {
|
||||
// borderangle once
|
||||
if (m_fBorderAngleAnimationProgress->enabled() && !m_fBorderAngleAnimationProgress->isBeingAnimated()) {
|
||||
m_fBorderAngleAnimationProgress->setValueAndWarp(0.f);
|
||||
*m_fBorderAngleAnimationProgress = 1.f;
|
||||
}
|
||||
}
|
||||
|
||||
int CWindow::popupsCount() {
|
||||
if (m_bIsX11)
|
||||
return 0;
|
||||
|
||||
int no = -1;
|
||||
m_pPopupHead->breadthfirst([](CPopup* p, void* d) { *((int*)d) += 1; }, &no);
|
||||
m_pPopupHead->breadthfirst([](WP<CPopup> p, void* d) { *((int*)d) += 1; }, &no);
|
||||
return no;
|
||||
}
|
||||
|
||||
@@ -1299,13 +1321,12 @@ int CWindow::surfacesCount() {
|
||||
}
|
||||
|
||||
void CWindow::clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize) {
|
||||
const Vector2D REALSIZE = m_vRealSize.goal();
|
||||
const Vector2D REALSIZE = m_vRealSize->goal();
|
||||
const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), maxSize.value_or(Vector2D{INFINITY, INFINITY}));
|
||||
const Vector2D DELTA = REALSIZE - NEWSIZE;
|
||||
|
||||
m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0;
|
||||
m_vRealSize = NEWSIZE;
|
||||
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE);
|
||||
*m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0;
|
||||
*m_vRealSize = NEWSIZE;
|
||||
}
|
||||
|
||||
bool CWindow::isFullscreen() {
|
||||
@@ -1398,14 +1419,25 @@ void CWindow::activate(bool force) {
|
||||
|
||||
void CWindow::onUpdateState() {
|
||||
std::optional<bool> requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen;
|
||||
std::optional<MONITORID> requestsID = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreenMonitor : MONITOR_INVALID;
|
||||
std::optional<bool> requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize;
|
||||
|
||||
if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
|
||||
bool fs = requestsFS.value();
|
||||
if (requestsID.has_value() && (requestsID.value() != MONITOR_INVALID) && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT)) {
|
||||
if (m_bIsMapped) {
|
||||
g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value());
|
||||
const auto monitor = g_pCompositor->getMonitorFromID(requestsID.value());
|
||||
g_pCompositor->moveWindowToWorkspaceSafe(m_pSelf.lock(), monitor->activeWorkspace);
|
||||
g_pCompositor->setActiveMonitor(monitor);
|
||||
}
|
||||
|
||||
if (!m_bIsMapped)
|
||||
m_iWantsInitialFullscreenMonitor = requestsID.value();
|
||||
}
|
||||
|
||||
bool fs = requestsFS.value();
|
||||
if (m_bIsMapped)
|
||||
g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value());
|
||||
|
||||
if (!m_bIsMapped)
|
||||
m_bWantsInitialFullscreen = fs;
|
||||
}
|
||||
@@ -1504,21 +1536,21 @@ void CWindow::onResourceChangeX11() {
|
||||
Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface->resource().get());
|
||||
}
|
||||
|
||||
void CWindow::onX11Configure(CBox box) {
|
||||
void CWindow::onX11ConfigureRequest(CBox box) {
|
||||
|
||||
if (!m_pXWaylandSurface->surface || !m_pXWaylandSurface->mapped || !m_bIsMapped) {
|
||||
m_pXWaylandSurface->configure(box);
|
||||
m_vPendingReportedSize = box.size();
|
||||
m_vReportedSize = box.size();
|
||||
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
|
||||
m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
m_vReportedPosition = box.pos();
|
||||
updateX11SurfaceScale();
|
||||
return;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageWindow(m_pSelf.lock());
|
||||
|
||||
if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) {
|
||||
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true);
|
||||
sendWindowSize(true);
|
||||
g_pInputManager->refocus();
|
||||
g_pHyprRenderer->damageWindow(m_pSelf.lock());
|
||||
return;
|
||||
@@ -1529,33 +1561,26 @@ void CWindow::onX11Configure(CBox box) {
|
||||
else
|
||||
setHidden(true);
|
||||
|
||||
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos());
|
||||
m_vRealPosition->setValueAndWarp(xwaylandPositionToReal(box.pos()));
|
||||
m_vRealSize->setValueAndWarp(xwaylandSizeToReal(box.size()));
|
||||
|
||||
m_vRealPosition.setValueAndWarp(LOGICALPOS);
|
||||
m_vRealSize.setValueAndWarp(box.size());
|
||||
|
||||
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) {
|
||||
m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale);
|
||||
m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
}
|
||||
}
|
||||
|
||||
m_vPosition = m_vRealPosition.value();
|
||||
m_vSize = m_vRealSize.value();
|
||||
m_vPosition = m_vRealPosition->goal();
|
||||
m_vSize = m_vRealSize->goal();
|
||||
|
||||
if (m_vPendingReportedSize != box.size() || m_vReportedPosition != box.pos()) {
|
||||
m_pXWaylandSurface->configure(box);
|
||||
|
||||
m_vPendingReportedSize = box.size();
|
||||
m_vReportedSize = box.size();
|
||||
m_vPendingReportedSize = box.size();
|
||||
m_vReportedPosition = box.pos();
|
||||
}
|
||||
|
||||
updateX11SurfaceScale();
|
||||
updateWindowDecos();
|
||||
|
||||
if (!m_pWorkspace || !m_pWorkspace->isVisible())
|
||||
return; // further things are only for visible windows
|
||||
|
||||
m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace;
|
||||
m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition->goal() + m_vRealSize->goal() / 2.f)->activeWorkspace;
|
||||
|
||||
g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true);
|
||||
|
||||
@@ -1605,17 +1630,17 @@ PHLWINDOW CWindow::getSwallower() {
|
||||
if (!(*PSWALLOWREGEX).empty())
|
||||
std::erase_if(candidates, [&](const auto& other) { return !RE2::FullMatch(other->m_szClass, *PSWALLOWREGEX); });
|
||||
|
||||
if (candidates.size() <= 0)
|
||||
if (candidates.size() == 0)
|
||||
return nullptr;
|
||||
|
||||
if (!(*PSWALLOWEXREGEX).empty())
|
||||
std::erase_if(candidates, [&](const auto& other) { return RE2::FullMatch(other->m_szTitle, *PSWALLOWEXREGEX); });
|
||||
|
||||
if (candidates.size() <= 0)
|
||||
if (candidates.size() == 0)
|
||||
return nullptr;
|
||||
|
||||
if (candidates.size() == 1)
|
||||
return candidates.at(0);
|
||||
return candidates[0];
|
||||
|
||||
// walk up the focus history and find the last focused
|
||||
for (auto const& w : g_pCompositor->m_vWindowFocusHistory) {
|
||||
@@ -1627,17 +1652,17 @@ PHLWINDOW CWindow::getSwallower() {
|
||||
}
|
||||
|
||||
// if none are found (??) then just return the first one
|
||||
return candidates.at(0);
|
||||
return candidates[0];
|
||||
}
|
||||
|
||||
void CWindow::unsetWindowData(eOverridePriority priority) {
|
||||
for (auto const& element : g_pConfigManager->mbWindowProperties) {
|
||||
for (auto const& element : NWindowProperties::boolWindowProperties) {
|
||||
element.second(m_pSelf.lock())->unset(priority);
|
||||
}
|
||||
for (auto const& element : g_pConfigManager->miWindowProperties) {
|
||||
for (auto const& element : NWindowProperties::intWindowProperties) {
|
||||
element.second(m_pSelf.lock())->unset(priority);
|
||||
}
|
||||
for (auto const& element : g_pConfigManager->mfWindowProperties) {
|
||||
for (auto const& element : NWindowProperties::floatWindowProperties) {
|
||||
element.second(m_pSelf.lock())->unset(priority);
|
||||
}
|
||||
}
|
||||
@@ -1675,3 +1700,109 @@ Vector2D CWindow::requestedMaxSize() {
|
||||
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
Vector2D CWindow::realToReportSize() {
|
||||
if (!m_bIsX11)
|
||||
return m_vRealSize->goal().clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
|
||||
|
||||
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
|
||||
|
||||
const auto REPORTSIZE = m_vRealSize->goal().clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
|
||||
if (*PXWLFORCESCALEZERO && PMONITOR)
|
||||
return REPORTSIZE * PMONITOR->scale;
|
||||
|
||||
return REPORTSIZE;
|
||||
}
|
||||
|
||||
Vector2D CWindow::realToReportPosition() {
|
||||
if (!m_bIsX11)
|
||||
return m_vRealPosition->goal();
|
||||
|
||||
return g_pXWaylandManager->waylandToXWaylandCoords(m_vRealPosition->goal());
|
||||
}
|
||||
|
||||
Vector2D CWindow::xwaylandSizeToReal(Vector2D size) {
|
||||
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
|
||||
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
const auto SIZE = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
|
||||
const auto SCALE = *PXWLFORCESCALEZERO ? PMONITOR->scale : 1.0f;
|
||||
|
||||
return SIZE / SCALE;
|
||||
}
|
||||
|
||||
Vector2D CWindow::xwaylandPositionToReal(Vector2D pos) {
|
||||
return g_pXWaylandManager->xwaylandToWaylandCoords(pos);
|
||||
}
|
||||
|
||||
void CWindow::updateX11SurfaceScale() {
|
||||
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
|
||||
|
||||
m_fX11SurfaceScaledBy = 1.0f;
|
||||
if (m_bIsX11 && *PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
|
||||
m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
}
|
||||
}
|
||||
|
||||
void CWindow::sendWindowSize(bool force) {
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
|
||||
Debug::log(TRACE, "sendWindowSize: window:{:x},title:{} with real pos {}, real size {} (force: {})", (uintptr_t)this, this->m_szTitle, m_vRealPosition->goal(),
|
||||
m_vRealSize->goal(), force);
|
||||
|
||||
// TODO: this should be decoupled from setWindowSize IMO
|
||||
const auto REPORTPOS = realToReportPosition();
|
||||
|
||||
const auto REPORTSIZE = realToReportSize();
|
||||
|
||||
if (!force && m_vPendingReportedSize == REPORTSIZE && (m_vReportedPosition == REPORTPOS || !m_bIsX11))
|
||||
return;
|
||||
|
||||
m_vReportedPosition = REPORTPOS;
|
||||
m_vPendingReportedSize = REPORTSIZE;
|
||||
updateX11SurfaceScale();
|
||||
|
||||
if (m_bIsX11 && m_pXWaylandSurface)
|
||||
m_pXWaylandSurface->configure({REPORTPOS, REPORTSIZE});
|
||||
else if (m_pXDGSurface && m_pXDGSurface->toplevel)
|
||||
m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(REPORTSIZE), REPORTPOS.floor());
|
||||
}
|
||||
|
||||
NContentType::eContentType CWindow::getContentType() {
|
||||
if (!m_pWLSurface || !m_pWLSurface->resource() || !m_pWLSurface->resource()->contentType.valid())
|
||||
return CONTENT_TYPE_NONE;
|
||||
|
||||
return m_pWLSurface->resource()->contentType->value;
|
||||
}
|
||||
|
||||
void CWindow::setContentType(NContentType::eContentType contentType) {
|
||||
if (!m_pWLSurface->resource()->contentType.valid())
|
||||
m_pWLSurface->resource()->contentType = PROTO::contentType->getContentType(m_pWLSurface->resource());
|
||||
// else disallow content type change if proto is used?
|
||||
|
||||
Debug::log(INFO, "ContentType for window {}", (int)contentType);
|
||||
m_pWLSurface->resource()->contentType->value = contentType;
|
||||
}
|
||||
|
||||
void CWindow::deactivateGroupMembers() {
|
||||
auto curr = getGroupHead();
|
||||
while (curr) {
|
||||
if (curr != m_pSelf.lock()) {
|
||||
if (curr->m_bIsX11)
|
||||
curr->m_pXWaylandSurface->activate(false);
|
||||
else if (curr->m_pXDGSurface && curr->m_pXDGSurface->toplevel)
|
||||
curr->m_pXDGSurface->toplevel->setActive(false);
|
||||
}
|
||||
|
||||
curr = curr->m_sGroupData.pNextWindow.lock();
|
||||
if (curr == getGroupHead())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CWindow::isNotResponding() {
|
||||
return g_pANRManager->isNotResponding(m_pSelf.lock());
|
||||
}
|
||||
|
@@ -2,9 +2,9 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "../config/ConfigDataValues.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/AnimatedVariable.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
@@ -12,12 +12,14 @@
|
||||
#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;
|
||||
@@ -57,6 +59,7 @@ enum eSuppressEvents : uint8_t {
|
||||
SUPPRESS_MAXIMIZE = 1 << 1,
|
||||
SUPPRESS_ACTIVATE = 1 << 2,
|
||||
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
|
||||
SUPPRESS_FULLSCREEN_OUTPUT = 1 << 4,
|
||||
};
|
||||
|
||||
class IWindowTransformer;
|
||||
@@ -183,6 +186,7 @@ struct SWindowData {
|
||||
CWindowOverridableVar<bool> renderUnfocused = false;
|
||||
|
||||
CWindowOverridableVar<int> rounding;
|
||||
CWindowOverridableVar<float> roundingPower;
|
||||
CWindowOverridableVar<int> borderSize;
|
||||
|
||||
CWindowOverridableVar<float> scrollMouse;
|
||||
@@ -194,6 +198,8 @@ struct SWindowData {
|
||||
|
||||
CWindowOverridableVar<CGradientValueData> activeBorderColor;
|
||||
CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
|
||||
|
||||
CWindowOverridableVar<bool> persistentSize;
|
||||
};
|
||||
|
||||
struct SInitialWorkspaceToken {
|
||||
@@ -232,8 +238,8 @@ class CWindow {
|
||||
Vector2D m_vSize = Vector2D(0, 0);
|
||||
|
||||
// this is the real position and size used to draw the thing
|
||||
CAnimatedVariable<Vector2D> m_vRealPosition;
|
||||
CAnimatedVariable<Vector2D> m_vRealSize;
|
||||
PHLANIMVAR<Vector2D> m_vRealPosition;
|
||||
PHLANIMVAR<Vector2D> m_vRealSize;
|
||||
|
||||
// for not spamming the protocols
|
||||
Vector2D m_vReportedPosition;
|
||||
@@ -288,22 +294,23 @@ class CWindow {
|
||||
|
||||
// Fullscreen and Maximize
|
||||
bool m_bWantsInitialFullscreen = false;
|
||||
MONITORID m_iWantsInitialFullscreenMonitor = MONITOR_INVALID;
|
||||
|
||||
// bitfield eSuppressEvents
|
||||
uint64_t m_eSuppressedEvents = SUPPRESS_NONE;
|
||||
|
||||
// desktop components
|
||||
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
|
||||
std::unique_ptr<CPopup> m_pPopupHead;
|
||||
UP<CSubsurface> m_pSubsurfaceHead;
|
||||
UP<CPopup> m_pPopupHead;
|
||||
|
||||
// Animated border
|
||||
CGradientValueData m_cRealBorderColor = {0};
|
||||
CGradientValueData m_cRealBorderColorPrevious = {0};
|
||||
CAnimatedVariable<float> m_fBorderFadeAnimationProgress;
|
||||
CAnimatedVariable<float> m_fBorderAngleAnimationProgress;
|
||||
PHLANIMVAR<float> m_fBorderFadeAnimationProgress;
|
||||
PHLANIMVAR<float> m_fBorderAngleAnimationProgress;
|
||||
|
||||
// Fade in-out
|
||||
CAnimatedVariable<float> m_fAlpha;
|
||||
PHLANIMVAR<float> m_fAlpha;
|
||||
bool m_bFadingOut = false;
|
||||
bool m_bReadyToDelete = false;
|
||||
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
|
||||
@@ -325,30 +332,32 @@ class CWindow {
|
||||
|
||||
// Window decorations
|
||||
// TODO: make this a SP.
|
||||
std::vector<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations;
|
||||
std::vector<UP<IHyprWindowDecoration>> m_dWindowDecorations;
|
||||
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
|
||||
|
||||
// Special render data, rules, etc
|
||||
SWindowData m_sWindowData;
|
||||
|
||||
// Transformers
|
||||
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
|
||||
std::vector<UP<IWindowTransformer>> m_vTransformers;
|
||||
|
||||
// for alpha
|
||||
CAnimatedVariable<float> m_fActiveInactiveAlpha;
|
||||
PHLANIMVAR<float> m_fActiveInactiveAlpha;
|
||||
PHLANIMVAR<float> m_fMovingFromWorkspaceAlpha;
|
||||
|
||||
// animated shadow color
|
||||
CAnimatedVariable<CHyprColor> m_cRealShadowColor;
|
||||
PHLANIMVAR<CHyprColor> m_cRealShadowColor;
|
||||
|
||||
// animated tint
|
||||
CAnimatedVariable<float> m_fDimPercent;
|
||||
PHLANIMVAR<float> m_fDimPercent;
|
||||
|
||||
// animate moving to an invisible workspace
|
||||
int m_iMonitorMovedFrom = -1; // -1 means not moving
|
||||
CAnimatedVariable<float> m_fMovingToWorkspaceAlpha;
|
||||
PHLANIMVAR<float> m_fMovingToWorkspaceAlpha;
|
||||
|
||||
// swallowing
|
||||
PHLWINDOWREF m_pSwallowed;
|
||||
bool m_bCurrentlySwallowed = false;
|
||||
bool m_bGroupSwallowed = false;
|
||||
|
||||
// focus stuff
|
||||
@@ -381,6 +390,9 @@ class CWindow {
|
||||
// window tags
|
||||
CTagKeeper m_tags;
|
||||
|
||||
// ANR
|
||||
PHLANIMVAR<float> m_notRespondingTint;
|
||||
|
||||
// For the list lookup
|
||||
bool operator==(const CWindow& rhs) const {
|
||||
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
|
||||
@@ -392,14 +404,13 @@ class CWindow {
|
||||
SBoxExtents getFullWindowExtents();
|
||||
CBox getWindowBoxUnified(uint64_t props);
|
||||
CBox getWindowIdealBoundingBoxIgnoreReserved();
|
||||
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
|
||||
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 removeDecorationByType(eDecorationType);
|
||||
void updateToplevel();
|
||||
void updateSurfaceScaleTransformDetails(bool force = false);
|
||||
void moveToWorkspace(PHLWORKSPACE);
|
||||
@@ -414,6 +425,7 @@ class CWindow {
|
||||
Vector2D middle();
|
||||
bool opaque();
|
||||
float rounding();
|
||||
float roundingPower();
|
||||
bool canBeTorn();
|
||||
void setSuspended(bool suspend);
|
||||
bool visibleOnMonitor(PHLMONITOR pMonitor);
|
||||
@@ -430,7 +442,7 @@ class CWindow {
|
||||
float getScrollTouchpad();
|
||||
void updateWindowData();
|
||||
void updateWindowData(const struct SWorkspaceRule&);
|
||||
void onBorderAngleAnimEnd(void* ptr);
|
||||
void onBorderAngleAnimEnd(WP<Hyprutils::Animation::CBaseAnimatedVariable> pav);
|
||||
bool isInCurvedCorner(double x, double y);
|
||||
bool hasPopupAt(const Vector2D& pos);
|
||||
int popupsCount();
|
||||
@@ -450,9 +462,10 @@ class CWindow {
|
||||
void switchWithWindowInGroup(PHLWINDOW pWindow);
|
||||
void setAnimationsToMove();
|
||||
void onWorkspaceAnimUpdate();
|
||||
void onFocusAnimUpdate();
|
||||
void onUpdateState();
|
||||
void onUpdateMeta();
|
||||
void onX11Configure(CBox box);
|
||||
void onX11ConfigureRequest(CBox box);
|
||||
void onResourceChangeX11();
|
||||
std::string fetchTitle();
|
||||
std::string fetchClass();
|
||||
@@ -463,9 +476,19 @@ class CWindow {
|
||||
bool isModal();
|
||||
Vector2D requestedMinSize();
|
||||
Vector2D requestedMaxSize();
|
||||
Vector2D realToReportSize();
|
||||
Vector2D realToReportPosition();
|
||||
Vector2D xwaylandSizeToReal(Vector2D size);
|
||||
Vector2D xwaylandPositionToReal(Vector2D size);
|
||||
void updateX11SurfaceScale();
|
||||
void sendWindowSize(bool force = false);
|
||||
NContentType::eContentType getContentType();
|
||||
void setContentType(NContentType::eContentType contentType);
|
||||
void deactivateGroupMembers();
|
||||
bool isNotResponding();
|
||||
|
||||
CBox getWindowMainSurfaceBox() const {
|
||||
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
|
||||
return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y};
|
||||
}
|
||||
|
||||
// listeners
|
||||
@@ -485,7 +508,7 @@ class CWindow {
|
||||
CHyprSignalListener commit;
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener activate;
|
||||
CHyprSignalListener configure;
|
||||
CHyprSignalListener configureRequest;
|
||||
CHyprSignalListener setGeometry;
|
||||
CHyprSignalListener updateState;
|
||||
CHyprSignalListener updateMetadata;
|
||||
@@ -519,6 +542,42 @@ 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*
|
||||
|
@@ -1,22 +1,24 @@
|
||||
#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",
|
||||
"float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", "persistentsize",
|
||||
};
|
||||
static const auto RULES_PREFIX = std::unordered_set<std::string>{
|
||||
"animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity",
|
||||
"plugin:", "prop", "pseudo", "rounding", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray",
|
||||
"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); }) ||
|
||||
(g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) ||
|
||||
(g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end()) ||
|
||||
(g_pConfigManager->mfWindowProperties.find(VALS[0]) != g_pConfigManager->mfWindowProperties.end());
|
||||
(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;
|
||||
@@ -37,6 +39,8 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool
|
||||
ruleType = RULE_TILE;
|
||||
else if (rule == "renderunfocused")
|
||||
ruleType = RULE_RENDERUNFOCUSED;
|
||||
else if (rule == "persistentsize")
|
||||
ruleType = RULE_PERSISTENTSIZE;
|
||||
else if (rule.starts_with("animation"))
|
||||
ruleType = RULE_ANIMATION;
|
||||
else if (rule.starts_with("bordercolor"))
|
||||
@@ -73,12 +77,14 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool
|
||||
ruleType = RULE_WORKSPACE;
|
||||
else if (rule.starts_with("prop"))
|
||||
ruleType = RULE_PROP;
|
||||
else if (rule.starts_with("content"))
|
||||
ruleType = RULE_CONTENT;
|
||||
else {
|
||||
// check if this is a prop.
|
||||
const CVarList VARS(rule, 0, 's', true);
|
||||
if (g_pConfigManager->miWindowProperties.find(VARS[0]) != g_pConfigManager->miWindowProperties.end() ||
|
||||
g_pConfigManager->mbWindowProperties.find(VARS[0]) != g_pConfigManager->mbWindowProperties.end() ||
|
||||
g_pConfigManager->mfWindowProperties.find(VARS[0]) != g_pConfigManager->mfWindowProperties.end()) {
|
||||
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);
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include "Rule.hpp"
|
||||
|
||||
class CWindowRule {
|
||||
public:
|
||||
@@ -35,6 +36,8 @@ class CWindowRule {
|
||||
RULE_TAG,
|
||||
RULE_WORKSPACE,
|
||||
RULE_PROP,
|
||||
RULE_CONTENT,
|
||||
RULE_PERSISTENTSIZE,
|
||||
};
|
||||
|
||||
eRuleType ruleType = RULE_INVALID;
|
||||
@@ -57,4 +60,12 @@ class CWindowRule {
|
||||
std::string szFullscreenState = ""; // empty means any
|
||||
std::string szOnWorkspace = ""; // empty means any
|
||||
std::string szWorkspace = ""; // empty means any
|
||||
std::string szContentType = ""; // empty means any
|
||||
|
||||
// precompiled regexes
|
||||
CRuleRegexContainer rTitle;
|
||||
CRuleRegexContainer rClass;
|
||||
CRuleRegexContainer rInitialTitle;
|
||||
CRuleRegexContainer rInitialClass;
|
||||
CRuleRegexContainer rV1Regex;
|
||||
};
|
@@ -1,7 +1,12 @@
|
||||
#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;
|
||||
|
||||
@@ -19,16 +24,10 @@ CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, boo
|
||||
void CWorkspace::init(PHLWORKSPACE self) {
|
||||
m_pSelf = self;
|
||||
|
||||
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,
|
||||
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_fAlpha.setValueAndWarp(1.f);
|
||||
|
||||
m_vRenderOffset.registerVar();
|
||||
m_fAlpha.registerVar();
|
||||
|
||||
const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self);
|
||||
if (RULEFORTHIS.defaultName.has_value())
|
||||
@@ -55,16 +54,11 @@ void CWorkspace::init(PHLWORKSPACE self) {
|
||||
EMIT_HOOK_EVENT("createWorkspace", this);
|
||||
}
|
||||
|
||||
SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName(bool perMonitor) const {
|
||||
if (perMonitor)
|
||||
return m_sPrevWorkspacePerMonitor;
|
||||
|
||||
SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName() const {
|
||||
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.
|
||||
@@ -82,15 +76,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.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME);
|
||||
m_vRenderOffset.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME);
|
||||
m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME));
|
||||
m_vRenderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME));
|
||||
}
|
||||
|
||||
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
|
||||
const auto ANIMSTYLE = m_fAlpha->getStyle();
|
||||
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
|
||||
|
||||
// set floating windows offset callbacks
|
||||
m_vRenderOffset.setUpdateCallback([&](void*) {
|
||||
m_vRenderOffset->setUpdateCallback([&](auto) {
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (!validMapped(w) || w->workspaceID() != m_iID)
|
||||
continue;
|
||||
@@ -110,84 +104,84 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); }
|
||||
}
|
||||
|
||||
m_fAlpha.setValueAndWarp(1.f);
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
|
||||
m_fAlpha->setValueAndWarp(1.f);
|
||||
m_vRenderOffset->setValueAndWarp(Vector2D(0, 0));
|
||||
|
||||
if (ANIMSTYLE.starts_with("slidefadevert")) {
|
||||
if (in) {
|
||||
m_fAlpha.setValueAndWarp(0.f);
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
|
||||
m_fAlpha = 1.f;
|
||||
m_vRenderOffset = Vector2D(0, 0);
|
||||
m_fAlpha->setValueAndWarp(0.f);
|
||||
m_vRenderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
|
||||
*m_fAlpha = 1.f;
|
||||
*m_vRenderOffset = Vector2D(0, 0);
|
||||
} else {
|
||||
m_fAlpha.setValueAndWarp(1.f);
|
||||
m_fAlpha = 0.f;
|
||||
m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
|
||||
m_fAlpha->setValueAndWarp(1.f);
|
||||
*m_fAlpha = 0.f;
|
||||
*m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
|
||||
}
|
||||
} else {
|
||||
if (in) {
|
||||
m_fAlpha.setValueAndWarp(0.f);
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0));
|
||||
m_fAlpha = 1.f;
|
||||
m_vRenderOffset = Vector2D(0, 0);
|
||||
m_fAlpha->setValueAndWarp(0.f);
|
||||
m_vRenderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0));
|
||||
*m_fAlpha = 1.f;
|
||||
*m_vRenderOffset = Vector2D(0, 0);
|
||||
} else {
|
||||
m_fAlpha.setValueAndWarp(1.f);
|
||||
m_fAlpha = 0.f;
|
||||
m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0);
|
||||
m_fAlpha->setValueAndWarp(1.f);
|
||||
*m_fAlpha = 0.f;
|
||||
*m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0);
|
||||
}
|
||||
}
|
||||
} else if (ANIMSTYLE == "fade") {
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade.
|
||||
m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade.
|
||||
|
||||
if (in) {
|
||||
m_fAlpha.setValueAndWarp(0.f);
|
||||
m_fAlpha = 1.f;
|
||||
m_fAlpha->setValueAndWarp(0.f);
|
||||
*m_fAlpha = 1.f;
|
||||
} else {
|
||||
m_fAlpha.setValueAndWarp(1.f);
|
||||
m_fAlpha = 0.f;
|
||||
m_fAlpha->setValueAndWarp(1.f);
|
||||
*m_fAlpha = 0.f;
|
||||
}
|
||||
} else if (ANIMSTYLE == "slidevert") {
|
||||
// fallback is slide
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
|
||||
|
||||
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
|
||||
m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
|
||||
|
||||
if (in) {
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
|
||||
m_vRenderOffset = Vector2D(0, 0);
|
||||
m_vRenderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
|
||||
*m_vRenderOffset = Vector2D(0, 0);
|
||||
} else {
|
||||
m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
|
||||
*m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
|
||||
}
|
||||
} else {
|
||||
// fallback is slide
|
||||
const auto PMONITOR = m_pMonitor.lock();
|
||||
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
|
||||
|
||||
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
|
||||
m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
|
||||
|
||||
if (in) {
|
||||
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
|
||||
m_vRenderOffset = Vector2D(0, 0);
|
||||
m_vRenderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
|
||||
*m_vRenderOffset = Vector2D(0, 0);
|
||||
} else {
|
||||
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
|
||||
*m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bIsSpecialWorkspace) {
|
||||
// required for open/close animations
|
||||
if (in) {
|
||||
m_fAlpha.setValueAndWarp(0.f);
|
||||
m_fAlpha = 1.f;
|
||||
m_fAlpha->setValueAndWarp(0.f);
|
||||
*m_fAlpha = 1.f;
|
||||
} else {
|
||||
m_fAlpha.setValueAndWarp(1.f);
|
||||
m_fAlpha = 0.f;
|
||||
m_fAlpha->setValueAndWarp(1.f);
|
||||
*m_fAlpha = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
if (instant) {
|
||||
m_vRenderOffset.warp();
|
||||
m_fAlpha.warp();
|
||||
m_vRenderOffset->warp();
|
||||
m_fAlpha->warp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,10 +215,7 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
|
||||
m_sPrevWorkspace.id = prev->m_iID;
|
||||
m_sPrevWorkspace.name = prev->m_szName;
|
||||
|
||||
if (prev->m_pMonitor == m_pMonitor) {
|
||||
m_sPrevWorkspacePerMonitor.id = prev->m_iID;
|
||||
m_sPrevWorkspacePerMonitor.name = prev->m_szName;
|
||||
}
|
||||
prev->m_pMonitor->addPrevWorkspaceID(prev->m_iID);
|
||||
}
|
||||
|
||||
std::string CWorkspace::getConfigName() {
|
||||
@@ -270,6 +261,7 @@ 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
|
||||
@@ -379,6 +371,7 @@ 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;
|
||||
|
||||
@@ -390,6 +383,9 @@ 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++;
|
||||
@@ -420,9 +416,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
||||
int count;
|
||||
if (wantsCountGroup)
|
||||
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
|
||||
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
|
||||
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
|
||||
else
|
||||
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
|
||||
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
|
||||
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
|
||||
|
||||
if (count != from)
|
||||
@@ -453,10 +451,12 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
||||
|
||||
WORKSPACEID count;
|
||||
if (wantsCountGroup)
|
||||
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
|
||||
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
|
||||
count =
|
||||
getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
|
||||
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
|
||||
else
|
||||
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
|
||||
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
|
||||
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
|
||||
|
||||
if (std::clamp(count, from, to) != count)
|
||||
@@ -544,13 +544,15 @@ bool CWorkspace::isVisibleNotCovered() {
|
||||
return PMONITOR->activeWorkspace->m_iID == m_iID;
|
||||
}
|
||||
|
||||
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
|
||||
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++;
|
||||
@@ -559,7 +561,7 @@ int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> on
|
||||
return no;
|
||||
}
|
||||
|
||||
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
|
||||
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)
|
||||
@@ -568,6 +570,8 @@ int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onl
|
||||
continue;
|
||||
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
|
||||
continue;
|
||||
if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value())
|
||||
continue;
|
||||
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
|
||||
continue;
|
||||
no++;
|
||||
@@ -633,7 +637,7 @@ void CWorkspace::forceReportSizesToWindows() {
|
||||
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
|
||||
continue;
|
||||
|
||||
g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true);
|
||||
w->sendWindowSize(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,6 +648,12 @@ void CWorkspace::rename(const std::string& name) {
|
||||
Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name);
|
||||
m_szName = name;
|
||||
|
||||
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock());
|
||||
m_bPersistent = WORKSPACERULE.isPersistent;
|
||||
|
||||
if (WORKSPACERULE.isPersistent)
|
||||
g_pCompositor->ensurePersistentWorkspacesPresent(std::vector<SWorkspaceRule>{WORKSPACERULE}, m_pSelf.lock());
|
||||
|
||||
g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName});
|
||||
}
|
||||
|
||||
|
@@ -27,9 +27,6 @@ class CWorkspace {
|
||||
WORKSPACEID m_iID = WORKSPACE_INVALID;
|
||||
std::string m_szName = "";
|
||||
PHLMONITORREF m_pMonitor;
|
||||
// Previous workspace ID and name is stored during a workspace change, allowing travel
|
||||
// to the previous workspace.
|
||||
SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor;
|
||||
|
||||
bool m_bHasFullscreenWindow = false;
|
||||
eFullscreenMode m_efFullscreenMode = FSMODE_NONE;
|
||||
@@ -37,8 +34,8 @@ class CWorkspace {
|
||||
wl_array m_wlrCoordinateArr;
|
||||
|
||||
// for animations
|
||||
CAnimatedVariable<Vector2D> m_vRenderOffset;
|
||||
CAnimatedVariable<float> m_fAlpha;
|
||||
PHLANIMVAR<Vector2D> m_vRenderOffset;
|
||||
PHLANIMVAR<float> m_fAlpha;
|
||||
bool m_bForceRendering = false;
|
||||
|
||||
// allows damage to propagate.
|
||||
@@ -72,11 +69,11 @@ class CWorkspace {
|
||||
std::string getConfigName();
|
||||
bool matchesStaticSelector(const std::string& selector);
|
||||
void markInert();
|
||||
SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const;
|
||||
SWorkspaceIDName getPrevWorkspaceIDName() const;
|
||||
void updateWindowDecos();
|
||||
void updateWindowData();
|
||||
int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
|
||||
int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
|
||||
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();
|
||||
@@ -89,6 +86,9 @@ class CWorkspace {
|
||||
|
||||
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;
|
||||
|
||||
SP<HOOK_CALLBACK_FN> m_pFocusedWindowHook;
|
||||
bool m_bInert = true;
|
||||
|
@@ -8,6 +8,8 @@
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
#include <cstring>
|
||||
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
#define LED_COUNT 3
|
||||
|
||||
constexpr static std::array<const char*, 8> MODNAMES = {
|
||||
@@ -41,13 +43,14 @@ void IKeyboard::clearManuallyAllocd() {
|
||||
if (xkbKeymap)
|
||||
xkb_keymap_unref(xkbKeymap);
|
||||
|
||||
if (xkbKeymapFD >= 0)
|
||||
close(xkbKeymapFD);
|
||||
if (xkbSymState)
|
||||
xkb_state_unref(xkbSymState);
|
||||
|
||||
xkbSymState = nullptr;
|
||||
xkbKeymap = nullptr;
|
||||
xkbState = nullptr;
|
||||
xkbStaticState = nullptr;
|
||||
xkbKeymapFD = -1;
|
||||
xkbKeymapFD.reset();
|
||||
}
|
||||
|
||||
void IKeyboard::setKeymap(const SStringRuleNames& rules) {
|
||||
@@ -123,14 +126,14 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
|
||||
updateModifiers(0, 0, modifiersState.locked, modifiersState.group);
|
||||
}
|
||||
|
||||
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(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 < 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));
|
||||
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]);
|
||||
}
|
||||
|
||||
updateKeymapFD();
|
||||
@@ -143,31 +146,30 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
|
||||
void IKeyboard::updateKeymapFD() {
|
||||
Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName);
|
||||
|
||||
if (xkbKeymapFD >= 0)
|
||||
close(xkbKeymapFD);
|
||||
xkbKeymapFD = -1;
|
||||
if (xkbKeymapFD.isValid())
|
||||
xkbKeymapFD.reset();
|
||||
|
||||
auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
|
||||
xkbKeymapString = cKeymapStr;
|
||||
free(cKeymapStr);
|
||||
|
||||
int rw, ro;
|
||||
if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro))
|
||||
CFileDescriptor 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, 0);
|
||||
close(rw);
|
||||
auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw.get(), 0);
|
||||
rw.reset();
|
||||
if (keymapFDDest == MAP_FAILED) {
|
||||
Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap");
|
||||
close(ro);
|
||||
ro.reset();
|
||||
} else {
|
||||
memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length());
|
||||
munmap(keymapFDDest, xkbKeymapString.length() + 1);
|
||||
xkbKeymapFD = ro;
|
||||
xkbKeymapFD = std::move(ro);
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD);
|
||||
Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD.get());
|
||||
}
|
||||
|
||||
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
|
||||
@@ -287,8 +289,8 @@ std::optional<uint32_t> IKeyboard::getLEDs() {
|
||||
return {};
|
||||
|
||||
uint32_t leds = 0;
|
||||
for (uint32_t i = 0; i < LED_COUNT; ++i) {
|
||||
if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i)))
|
||||
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]))
|
||||
leds |= (1 << i);
|
||||
}
|
||||
|
||||
@@ -321,10 +323,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.at(i) == XKB_MOD_INVALID)
|
||||
if (modIndexes[i] == XKB_MOD_INVALID)
|
||||
continue;
|
||||
|
||||
if (!(modMask & (1 << modIndexes.at(i))))
|
||||
if (!(modMask & (1 << modIndexes[i])))
|
||||
continue;
|
||||
|
||||
mods |= (1 << i);
|
||||
|
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <optional>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
|
||||
AQUAMARINE_FORWARD(IKeyboard);
|
||||
|
||||
@@ -96,7 +97,7 @@ class IKeyboard : public IHID {
|
||||
|
||||
std::string xkbFilePath = "";
|
||||
std::string xkbKeymapString = "";
|
||||
int xkbKeymapFD = -1;
|
||||
Hyprutils::OS::CFileDescriptor xkbKeymapFD;
|
||||
|
||||
SStringRuleNames currentRules;
|
||||
int repeatRate = 0;
|
||||
|
@@ -20,6 +20,7 @@ class IPointer : public IHID {
|
||||
uint32_t timeMs = 0;
|
||||
Vector2D delta, unaccel;
|
||||
bool mouse = false;
|
||||
SP<IPointer> device;
|
||||
};
|
||||
|
||||
struct SMotionAbsoluteEvent {
|
||||
@@ -109,6 +110,9 @@ class IPointer : public IHID {
|
||||
|
||||
bool connected = false; // means connected to the cursor
|
||||
std::string boundOutput = "";
|
||||
bool flipX = false; // decide to invert horizontal movement
|
||||
bool flipY = false; // decide to invert vertical movement
|
||||
bool isTouchpad = false;
|
||||
|
||||
WP<IPointer> self;
|
||||
};
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#include "Keyboard.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
|
||||
|
@@ -14,6 +14,11 @@ 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();
|
||||
@@ -27,6 +32,7 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
|
||||
.delta = E.delta,
|
||||
.unaccel = E.unaccel,
|
||||
.mouse = true,
|
||||
.device = self.lock(),
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -11,7 +11,7 @@ SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resour
|
||||
}
|
||||
|
||||
CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : pointer(resource) {
|
||||
if (!resource->good())
|
||||
if UNLIKELY (!resource->good())
|
||||
return;
|
||||
|
||||
listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) {
|
||||
@@ -19,7 +19,11 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
|
||||
events.destroy.emit();
|
||||
});
|
||||
|
||||
listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
|
||||
listeners.motion = pointer->events.move.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<SMotionEvent>(d);
|
||||
E.device = self.lock();
|
||||
pointerEvents.motion.emit(E);
|
||||
});
|
||||
listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) {
|
||||
// we need to unpack the event and add our device here because it's required to calculate the position correctly
|
||||
auto E = std::any_cast<SMotionAbsoluteEvent>(d);
|
||||
|
@@ -11,11 +11,18 @@
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../protocols/ToplevelExport.hpp"
|
||||
#include "../protocols/types/ContentType.hpp"
|
||||
#include "../xwayland/XSurface.hpp"
|
||||
#include "managers/AnimationManager.hpp"
|
||||
#include "managers/PointerManager.hpp"
|
||||
#include "../desktop/LayerSurface.hpp"
|
||||
#include "../managers/LayoutManager.hpp"
|
||||
#include "../managers/EventManager.hpp"
|
||||
#include "../managers/AnimationManager.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::Animation;
|
||||
|
||||
// ------------------------------------------------------------ //
|
||||
// __ _______ _ _ _____ ______ _______ //
|
||||
@@ -27,15 +34,17 @@ using namespace Hyprutils::String;
|
||||
// //
|
||||
// ------------------------------------------------------------ //
|
||||
|
||||
void setAnimToMove(void* data) {
|
||||
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
|
||||
static void setVector2DAnimToMove(WP<CBaseAnimatedVariable> pav) {
|
||||
const auto PAV = pav.lock();
|
||||
if (!PAV)
|
||||
return;
|
||||
|
||||
CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data;
|
||||
CAnimatedVariable<Vector2D>* animvar = dynamic_cast<CAnimatedVariable<Vector2D>*>(PAV.get());
|
||||
animvar->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
|
||||
|
||||
animvar->setConfig(PANIMCFG);
|
||||
|
||||
if (animvar->getWindow() && !animvar->getWindow()->m_vRealPosition.isBeingAnimated() && !animvar->getWindow()->m_vRealSize.isBeingAnimated())
|
||||
animvar->getWindow()->m_bAnimatingIn = false;
|
||||
const auto PHLWINDOW = animvar->m_Context.pWindow.lock();
|
||||
if (PHLWINDOW)
|
||||
PHLWINDOW->m_bAnimatingIn = false;
|
||||
}
|
||||
|
||||
void Events::listener_mapWindow(void* owner, void* data) {
|
||||
@@ -121,22 +130,13 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->isX11OverrideRedirect() && !PWINDOW->m_pXWaylandSurface->wantsFocus());
|
||||
|
||||
if (PWORKSPACE->m_bDefaultFloating)
|
||||
PWINDOW->m_bIsFloating = true;
|
||||
|
||||
if (PWORKSPACE->m_bDefaultPseudo) {
|
||||
PWINDOW->m_bIsPseudotiled = true;
|
||||
CBox desiredGeometry = {0};
|
||||
g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry);
|
||||
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
|
||||
}
|
||||
|
||||
// window rules
|
||||
PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
|
||||
std::optional<eFullscreenMode> requestedInternalFSMode, requestedClientFSMode;
|
||||
std::optional<SFullscreenState> requestedFSState;
|
||||
if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen))
|
||||
requestedClientFSMode = FSMODE_FULLSCREEN;
|
||||
MONITORID requestedFSMonitor = PWINDOW->m_iWantsInitialFullscreenMonitor;
|
||||
|
||||
for (auto const& r : PWINDOW->m_vMatchedRules) {
|
||||
switch (r->ruleType) {
|
||||
@@ -171,8 +171,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PMONITOR = PMONITORFROMID;
|
||||
}
|
||||
PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
|
||||
PWORKSPACE = PWINDOW->m_pWorkspace;
|
||||
|
||||
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
|
||||
requestedFSMonitor = MONITOR_INVALID;
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r->szRule, r->szValue, e.what()); }
|
||||
break;
|
||||
}
|
||||
@@ -180,11 +182,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
// check if it isnt unset
|
||||
const auto WORKSPACERQ = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
|
||||
|
||||
if (WORKSPACERQ == "unset") {
|
||||
if (WORKSPACERQ == "unset")
|
||||
requestedWorkspace = "";
|
||||
} else {
|
||||
else
|
||||
requestedWorkspace = WORKSPACERQ;
|
||||
}
|
||||
|
||||
const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ;
|
||||
|
||||
@@ -192,6 +193,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
requestedWorkspace = "";
|
||||
|
||||
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r->szValue);
|
||||
requestedFSMonitor = MONITOR_INVALID;
|
||||
break;
|
||||
}
|
||||
case CWindowRule::RULE_FLOAT: {
|
||||
@@ -233,6 +235,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
|
||||
else if (vars[i] == "activatefocus")
|
||||
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
|
||||
else if (vars[i] == "fullscreenoutput")
|
||||
PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN_OUTPUT;
|
||||
else
|
||||
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
|
||||
}
|
||||
@@ -303,6 +307,13 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CWindowRule::RULE_CONTENT: {
|
||||
const CVarList VARS(r->szRule, 0, ' ');
|
||||
try {
|
||||
PWINDOW->setContentType(NContentType::fromString(VARS[1]));
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -338,20 +349,51 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (!workspaceSilent) {
|
||||
if (pWorkspace->m_bIsSpecialWorkspace)
|
||||
pWorkspace->m_pMonitor->setSpecialWorkspace(pWorkspace);
|
||||
else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID)
|
||||
else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID && !PWINDOW->m_bNoInitialFocus)
|
||||
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
|
||||
|
||||
PMONITOR = g_pCompositor->m_pLastMonitor.lock();
|
||||
}
|
||||
|
||||
requestedFSMonitor = MONITOR_INVALID;
|
||||
} else
|
||||
workspaceSilent = false;
|
||||
}
|
||||
|
||||
if (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT)
|
||||
requestedFSMonitor = MONITOR_INVALID;
|
||||
else if (requestedFSMonitor != MONITOR_INVALID) {
|
||||
if (const auto PM = g_pCompositor->getMonitorFromID(requestedFSMonitor); PM)
|
||||
PWINDOW->m_pMonitor = PM;
|
||||
|
||||
const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock();
|
||||
|
||||
if (PWINDOW->m_pMonitor != PMONITOR) {
|
||||
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID()));
|
||||
PMONITOR = PMONITORFROMID;
|
||||
}
|
||||
PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
|
||||
PWORKSPACE = PWINDOW->m_pWorkspace;
|
||||
|
||||
Debug::log(LOG, "Requested monitor, applying to {:mw}", PWINDOW);
|
||||
}
|
||||
|
||||
if (PWORKSPACE->m_bDefaultFloating)
|
||||
PWINDOW->m_bIsFloating = true;
|
||||
|
||||
if (PWORKSPACE->m_bDefaultPseudo) {
|
||||
PWINDOW->m_bIsPseudotiled = true;
|
||||
CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(PWINDOW);
|
||||
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
|
||||
}
|
||||
|
||||
PWINDOW->updateWindowData();
|
||||
|
||||
// Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped.
|
||||
const auto SWALLOWER = PWINDOW->getSwallower();
|
||||
PWINDOW->m_pSwallowed = SWALLOWER;
|
||||
if (PWINDOW->m_pSwallowed)
|
||||
PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = true;
|
||||
|
||||
if (PWINDOW->m_bIsFloating) {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
|
||||
@@ -378,10 +420,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
const auto MAXSIZE = PWINDOW->requestedMaxSize();
|
||||
|
||||
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) :
|
||||
stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x);
|
||||
stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize->goal().x, PMONITOR->vecSize.x);
|
||||
|
||||
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) :
|
||||
stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y);
|
||||
stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize->goal().y, PMONITOR->vecSize.y);
|
||||
|
||||
Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
|
||||
|
||||
@@ -418,7 +460,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
(!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
|
||||
|
||||
if (subtractWindow)
|
||||
posX -= PWINDOW->m_vRealSize.goal().x;
|
||||
posX -= PWINDOW->m_vRealSize->goal().x;
|
||||
|
||||
if (CURSOR)
|
||||
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
|
||||
@@ -430,7 +472,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
|
||||
} else {
|
||||
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
|
||||
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
|
||||
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize->goal().x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,7 +483,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
(!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
|
||||
|
||||
if (subtractWindow)
|
||||
posY -= PWINDOW->m_vRealSize.goal().y;
|
||||
posY -= PWINDOW->m_vRealSize->goal().y;
|
||||
|
||||
if (CURSOR)
|
||||
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
|
||||
@@ -453,7 +495,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
|
||||
} else {
|
||||
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
|
||||
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
|
||||
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize->goal().y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,15 +503,15 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
int borderSize = PWINDOW->getRealBorderSize();
|
||||
|
||||
posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
|
||||
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize));
|
||||
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize->goal().x - borderSize));
|
||||
|
||||
posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
|
||||
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize));
|
||||
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize->goal().y - borderSize));
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
|
||||
|
||||
PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
|
||||
*PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
|
||||
|
||||
PWINDOW->setHidden(false);
|
||||
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r->szRule, r->szValue); }
|
||||
@@ -481,7 +523,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (ARGS[1] == "1")
|
||||
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
|
||||
|
||||
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET;
|
||||
*PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize->goal() / 2.f + RESERVEDOFFSET;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -491,7 +533,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
// set the pseudo size to the GOAL of our current size
|
||||
// because the windows are animated on RealSize
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal();
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize->goal();
|
||||
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
} else {
|
||||
@@ -524,7 +566,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
|
||||
if (!setPseudo)
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10);
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize->goal() - Vector2D(10, 10);
|
||||
}
|
||||
|
||||
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock();
|
||||
@@ -554,11 +596,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
(!PWINDOW->isX11OverrideRedirect() || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) &&
|
||||
!g_pInputManager->isConstrained()) {
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH);
|
||||
PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent->setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH);
|
||||
} else {
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(0);
|
||||
PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PINACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent->setValueAndWarp(0);
|
||||
}
|
||||
|
||||
if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
|
||||
@@ -571,8 +613,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow)
|
||||
g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE);
|
||||
|
||||
PWINDOW->m_vRealPosition.warp();
|
||||
PWINDOW->m_vRealSize.warp();
|
||||
PWINDOW->m_vRealPosition->warp();
|
||||
PWINDOW->m_vRealSize->warp();
|
||||
if (requestedFSState.has_value()) {
|
||||
PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE);
|
||||
g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value());
|
||||
@@ -607,7 +649,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
PWINDOW->m_bFirstMap = false;
|
||||
|
||||
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goal(), PWINDOW->m_vRealSize.goal());
|
||||
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition->goal(), PWINDOW->m_vRealSize->goal());
|
||||
|
||||
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, PWINDOW->m_szClass, PWINDOW->m_szTitle)});
|
||||
@@ -620,17 +662,17 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
// do animations
|
||||
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
|
||||
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
|
||||
PWINDOW->m_fAlpha = 1.f;
|
||||
PWINDOW->m_fAlpha->setValueAndWarp(0.f);
|
||||
*PWINDOW->m_fAlpha = 1.f;
|
||||
|
||||
PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove);
|
||||
PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove);
|
||||
PWINDOW->m_vRealPosition->setCallbackOnEnd(setVector2DAnimToMove);
|
||||
PWINDOW->m_vRealSize->setCallbackOnEnd(setVector2DAnimToMove);
|
||||
|
||||
// recalc the values for this window
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
||||
// avoid this window being visible
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen() && !PWINDOW->m_bIsFloating)
|
||||
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
|
||||
PWINDOW->m_fAlpha->setValueAndWarp(0.f);
|
||||
|
||||
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->transform);
|
||||
@@ -666,30 +708,40 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
|
||||
const auto PMONITOR = PWINDOW->m_pMonitor.lock();
|
||||
if (PMONITOR) {
|
||||
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition;
|
||||
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value();
|
||||
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition->value() - PMONITOR->vecPosition;
|
||||
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize->value();
|
||||
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
|
||||
}
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
|
||||
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
|
||||
|
||||
if (PWINDOW->m_bIsFloating && !PWINDOW->m_bIsX11 &&
|
||||
std::any_of(PWINDOW->m_vMatchedRules.begin(), PWINDOW->m_vMatchedRules.end(), [](const auto& r) { return r->ruleType == CWindowRule::RULE_PERSISTENTSIZE; })) {
|
||||
Debug::log(LOG, "storing floating size {}x{} for window {}::{} on close", PWINDOW->m_vRealSize->value().x, PWINDOW->m_vRealSize->value().y, PWINDOW->m_szClass,
|
||||
PWINDOW->m_szTitle);
|
||||
g_pConfigManager->storeFloatingSize(PWINDOW, PWINDOW->m_vRealSize->value());
|
||||
}
|
||||
|
||||
PROTO::toplevelExport->onWindowUnmap(PWINDOW);
|
||||
|
||||
if (PWINDOW->isFullscreen())
|
||||
g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE);
|
||||
|
||||
// Allow the renderer to catch the last frame.
|
||||
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
|
||||
g_pHyprRenderer->makeWindowSnapshot(PWINDOW);
|
||||
|
||||
// swallowing
|
||||
if (valid(PWINDOW->m_pSwallowed)) {
|
||||
if (PWINDOW->m_pSwallowed->m_bCurrentlySwallowed) {
|
||||
PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = false;
|
||||
PWINDOW->m_pSwallowed->setHidden(false);
|
||||
|
||||
if (PWINDOW->m_sGroupData.pNextWindow.lock())
|
||||
PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false.
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock());
|
||||
}
|
||||
|
||||
PWINDOW->m_pSwallowed->m_bGroupSwallowed = false;
|
||||
PWINDOW->m_pSwallowed.reset();
|
||||
@@ -758,11 +810,11 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
g_pCompositor->addToFadingOutSafe(PWINDOW);
|
||||
|
||||
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
|
||||
*PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition->value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
|
||||
|
||||
// anims
|
||||
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true);
|
||||
PWINDOW->m_fAlpha = 0.f;
|
||||
*PWINDOW->m_fAlpha = 0.f;
|
||||
|
||||
// recheck idle inhibitors
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
@@ -812,7 +864,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||
g_pSeatManager->isPointerFrameSkipped = false;
|
||||
g_pSeatManager->isPointerFrameCommit = false;
|
||||
} else
|
||||
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
|
||||
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition->goal().x, PWINDOW->m_vRealPosition->goal().y,
|
||||
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
|
||||
|
||||
if (g_pSeatManager->isPointerFrameSkipped) {
|
||||
@@ -828,7 +880,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||
|
||||
// tearing: if solitary, redraw it. This still might be a single surface window
|
||||
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
|
||||
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
|
||||
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.accumulateBufferDamage()};
|
||||
|
||||
if (!damageBox.empty()) {
|
||||
if (PMONITOR->tearingState.busy) {
|
||||
@@ -872,15 +924,6 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||
PWINDOW->listeners.commit.reset();
|
||||
}
|
||||
|
||||
void Events::listener_setTitleWindow(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
if (!validMapped(PWINDOW))
|
||||
return;
|
||||
|
||||
PWINDOW->onUpdateMeta();
|
||||
}
|
||||
|
||||
void Events::listener_activateX11(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
@@ -912,8 +955,8 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
if (!PWINDOW->m_bIsMapped || !PWINDOW->m_pXWaylandSurface || !PWINDOW->m_pXWaylandSurface->overrideRedirect)
|
||||
return;
|
||||
|
||||
const auto POS = PWINDOW->m_vRealPosition.goal();
|
||||
const auto SIZ = PWINDOW->m_vRealSize.goal();
|
||||
const auto POS = PWINDOW->m_vRealPosition->goal();
|
||||
const auto SIZ = PWINDOW->m_vRealSize->goal();
|
||||
|
||||
if (PWINDOW->m_pXWaylandSurface->geometry.size() > Vector2D{1, 1})
|
||||
PWINDOW->setHidden(false);
|
||||
@@ -921,7 +964,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
PWINDOW->setHidden(true);
|
||||
|
||||
if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) {
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
|
||||
PWINDOW->sendWindowSize(true);
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
return;
|
||||
}
|
||||
@@ -935,27 +978,27 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {:j}", PWINDOW, LOGICALPOS, PWINDOW->m_pXWaylandSurface->geometry.size());
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y));
|
||||
PWINDOW->m_vRealPosition->setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y));
|
||||
|
||||
if (abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.w) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.h) > 2)
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size());
|
||||
PWINDOW->m_vRealSize->setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size());
|
||||
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = PWINDOW->m_pMonitor.lock(); PMONITOR) {
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
|
||||
PWINDOW->m_vRealSize->setValueAndWarp(PWINDOW->m_vRealSize->goal() / PMONITOR->scale);
|
||||
}
|
||||
}
|
||||
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal();
|
||||
PWINDOW->m_vSize = PWINDOW->m_vRealSize.goal();
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition->goal();
|
||||
PWINDOW->m_vSize = PWINDOW->m_vRealSize->goal();
|
||||
|
||||
PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
|
||||
PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition->value() + PWINDOW->m_vRealSize->value() / 2.f)->activeWorkspace;
|
||||
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
PWINDOW->updateWindowDecos();
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goal();
|
||||
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal();
|
||||
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition->goal();
|
||||
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize->goal();
|
||||
}
|
||||
}
|
||||
|
@@ -1,92 +0,0 @@
|
||||
#include "AnimatedVariable.hpp"
|
||||
#include "../managers/AnimationManager.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
|
||||
CBaseAnimatedVariable::CBaseAnimatedVariable(eAnimatedVarType type) : m_Type(type) {
|
||||
; // dummy var
|
||||
}
|
||||
|
||||
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) {
|
||||
m_eDamagePolicy = policy;
|
||||
m_pConfig = pAnimConfig;
|
||||
m_pWindow = pWindow;
|
||||
|
||||
m_bDummy = false;
|
||||
}
|
||||
|
||||
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) {
|
||||
m_eDamagePolicy = policy;
|
||||
m_pConfig = pAnimConfig;
|
||||
m_pLayer = pLayer;
|
||||
|
||||
m_bDummy = false;
|
||||
}
|
||||
|
||||
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) {
|
||||
m_eDamagePolicy = policy;
|
||||
m_pConfig = pAnimConfig;
|
||||
m_pWorkspace = pWorkspace;
|
||||
|
||||
m_bDummy = false;
|
||||
}
|
||||
|
||||
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) {
|
||||
m_eDamagePolicy = policy;
|
||||
m_pConfig = pAnimConfig;
|
||||
|
||||
m_bDummy = false;
|
||||
}
|
||||
|
||||
CBaseAnimatedVariable::~CBaseAnimatedVariable() {
|
||||
unregister();
|
||||
}
|
||||
|
||||
void CBaseAnimatedVariable::unregister() {
|
||||
if (!g_pAnimationManager)
|
||||
return;
|
||||
std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; });
|
||||
m_bIsRegistered = false;
|
||||
disconnectFromActive();
|
||||
}
|
||||
|
||||
void CBaseAnimatedVariable::registerVar() {
|
||||
if (!m_bIsRegistered)
|
||||
g_pAnimationManager->m_vAnimatedVariables.push_back(this);
|
||||
m_bIsRegistered = true;
|
||||
}
|
||||
|
||||
int CBaseAnimatedVariable::getDurationLeftMs() {
|
||||
return std::max(
|
||||
(int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - animationBegin).count(), 0);
|
||||
}
|
||||
|
||||
float CBaseAnimatedVariable::getPercent() {
|
||||
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - animationBegin).count();
|
||||
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
|
||||
}
|
||||
|
||||
float CBaseAnimatedVariable::getCurveValue() {
|
||||
if (!m_bIsBeingAnimated)
|
||||
return 1.f;
|
||||
|
||||
const auto SPENT = getPercent();
|
||||
|
||||
if (SPENT >= 1.f)
|
||||
return 1.f;
|
||||
|
||||
return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT);
|
||||
}
|
||||
|
||||
void CBaseAnimatedVariable::connectToActive() {
|
||||
g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up
|
||||
|
||||
if (!m_bIsConnectedToActive)
|
||||
g_pAnimationManager->m_vActiveAnimatedVariables.push_back(this);
|
||||
|
||||
m_bIsConnectedToActive = true;
|
||||
}
|
||||
|
||||
void CBaseAnimatedVariable::disconnectFromActive() {
|
||||
std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; });
|
||||
m_bIsConnectedToActive = false;
|
||||
}
|
@@ -1,15 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <any>
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
#include "math/Math.hpp"
|
||||
#include <hyprutils/animation/AnimatedVariable.hpp>
|
||||
|
||||
#include "Color.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../desktop/DesktopTypes.hpp"
|
||||
|
||||
enum eAVarDamagePolicy : int8_t {
|
||||
AVARDAMAGE_NONE = -1,
|
||||
AVARDAMAGE_ENTIRE = 0,
|
||||
AVARDAMAGE_BORDER,
|
||||
AVARDAMAGE_SHADOW
|
||||
};
|
||||
|
||||
enum eAnimatedVarType : int8_t {
|
||||
AVARTYPE_INVALID = -1,
|
||||
AVARTYPE_FLOAT,
|
||||
@@ -42,20 +45,6 @@ struct STypeToAnimatedVarType_t<CHyprColor> {
|
||||
template <class T>
|
||||
inline constexpr eAnimatedVarType typeToeAnimatedVarType = STypeToAnimatedVarType_t<T>::value;
|
||||
|
||||
enum eAVarDamagePolicy : int8_t {
|
||||
AVARDAMAGE_NONE = -1,
|
||||
AVARDAMAGE_ENTIRE = 0,
|
||||
AVARDAMAGE_BORDER,
|
||||
AVARDAMAGE_SHADOW
|
||||
};
|
||||
|
||||
class CAnimationManager;
|
||||
struct SAnimationPropertyConfig;
|
||||
class CHyprRenderer;
|
||||
class CWindow;
|
||||
class CWorkspace;
|
||||
class CLayerSurface;
|
||||
|
||||
// Utility to define a concept as a list of possible type
|
||||
template <class T, class... U>
|
||||
concept OneOf = (... or std::same_as<T, U>);
|
||||
@@ -66,247 +55,19 @@ concept OneOf = (... or std::same_as<T, U>);
|
||||
template <class T>
|
||||
concept Animable = OneOf<T, Vector2D, float, CHyprColor>;
|
||||
|
||||
class CBaseAnimatedVariable {
|
||||
public:
|
||||
CBaseAnimatedVariable(eAnimatedVarType type);
|
||||
void create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy);
|
||||
void create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy);
|
||||
void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy);
|
||||
void create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy);
|
||||
struct SAnimationContext {
|
||||
PHLWINDOWREF pWindow;
|
||||
PHLWORKSPACEREF pWorkspace;
|
||||
PHLLSREF pLayer;
|
||||
|
||||
CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
|
||||
CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
|
||||
CBaseAnimatedVariable& operator=(const CBaseAnimatedVariable&) = delete;
|
||||
CBaseAnimatedVariable& operator=(CBaseAnimatedVariable&&) = delete;
|
||||
|
||||
virtual ~CBaseAnimatedVariable();
|
||||
|
||||
void unregister();
|
||||
void registerVar();
|
||||
|
||||
virtual void warp(bool endCallback = true) = 0;
|
||||
|
||||
//
|
||||
void setConfig(SAnimationPropertyConfig* pConfig) {
|
||||
m_pConfig = pConfig;
|
||||
}
|
||||
|
||||
SAnimationPropertyConfig* getConfig() {
|
||||
return m_pConfig;
|
||||
}
|
||||
|
||||
int getDurationLeftMs();
|
||||
|
||||
/* returns the spent (completion) % */
|
||||
float getPercent();
|
||||
|
||||
/* returns the current curve value */
|
||||
float getCurveValue();
|
||||
|
||||
// checks if an animation is in progress
|
||||
bool isBeingAnimated() const {
|
||||
return m_bIsBeingAnimated;
|
||||
}
|
||||
|
||||
/* sets a function to be ran when the animation finishes.
|
||||
if an animation is not running, runs instantly.
|
||||
if "remove" is set to true, will remove the callback when ran. */
|
||||
void setCallbackOnEnd(std::function<void(void* thisptr)> func, bool remove = true) {
|
||||
m_fEndCallback = std::move(func);
|
||||
m_bRemoveEndAfterRan = remove;
|
||||
|
||||
if (!isBeingAnimated())
|
||||
onAnimationEnd();
|
||||
}
|
||||
|
||||
/* sets a function to be ran when an animation is started.
|
||||
if "remove" is set to true, will remove the callback when ran. */
|
||||
void setCallbackOnBegin(std::function<void(void* thisptr)> func, bool remove = true) {
|
||||
m_fBeginCallback = std::move(func);
|
||||
m_bRemoveBeginAfterRan = remove;
|
||||
}
|
||||
|
||||
/* Sets the update callback, called every time the value is animated and a step is done
|
||||
Warning: calling unregisterVar/registerVar in this handler will cause UB */
|
||||
void setUpdateCallback(std::function<void(void* thisptr)> func) {
|
||||
m_fUpdateCallback = std::move(func);
|
||||
}
|
||||
|
||||
/* resets all callbacks. Does not call any. */
|
||||
void resetAllCallbacks() {
|
||||
m_fBeginCallback = nullptr;
|
||||
m_fEndCallback = nullptr;
|
||||
m_fUpdateCallback = nullptr;
|
||||
m_bRemoveBeginAfterRan = false;
|
||||
m_bRemoveEndAfterRan = false;
|
||||
}
|
||||
|
||||
PHLWINDOW getWindow() {
|
||||
return m_pWindow.lock();
|
||||
}
|
||||
|
||||
protected:
|
||||
PHLWINDOWREF m_pWindow;
|
||||
PHLWORKSPACEREF m_pWorkspace;
|
||||
PHLLSREF m_pLayer;
|
||||
|
||||
SAnimationPropertyConfig* m_pConfig = nullptr;
|
||||
|
||||
bool m_bDummy = true;
|
||||
bool m_bIsRegistered = false;
|
||||
bool m_bIsBeingAnimated = false;
|
||||
|
||||
std::chrono::steady_clock::time_point animationBegin;
|
||||
|
||||
eAVarDamagePolicy m_eDamagePolicy = AVARDAMAGE_NONE;
|
||||
eAnimatedVarType m_Type;
|
||||
|
||||
bool m_bRemoveEndAfterRan = true;
|
||||
bool m_bRemoveBeginAfterRan = true;
|
||||
std::function<void(void* thisptr)> m_fEndCallback;
|
||||
std::function<void(void* thisptr)> m_fBeginCallback;
|
||||
std::function<void(void* thisptr)> m_fUpdateCallback;
|
||||
|
||||
bool m_bIsConnectedToActive = false;
|
||||
|
||||
void connectToActive();
|
||||
|
||||
void disconnectFromActive();
|
||||
|
||||
// methods
|
||||
void onAnimationEnd() {
|
||||
m_bIsBeingAnimated = false;
|
||||
disconnectFromActive();
|
||||
|
||||
if (m_fEndCallback) {
|
||||
// loading m_bRemoveEndAfterRan before calling the callback allows the callback to delete this animation safely if it is false.
|
||||
auto removeEndCallback = m_bRemoveEndAfterRan;
|
||||
m_fEndCallback(this);
|
||||
if (removeEndCallback)
|
||||
m_fEndCallback = nullptr; // reset
|
||||
}
|
||||
}
|
||||
|
||||
void onAnimationBegin() {
|
||||
m_bIsBeingAnimated = true;
|
||||
connectToActive();
|
||||
|
||||
if (m_fBeginCallback) {
|
||||
m_fBeginCallback(this);
|
||||
if (m_bRemoveBeginAfterRan)
|
||||
m_fBeginCallback = nullptr; // reset
|
||||
}
|
||||
}
|
||||
|
||||
friend class CAnimationManager;
|
||||
friend class CWorkspace;
|
||||
friend class CLayerSurface;
|
||||
friend class CHyprRenderer;
|
||||
eAVarDamagePolicy eDamagePolicy = AVARDAMAGE_NONE;
|
||||
};
|
||||
|
||||
template <Animable VarType>
|
||||
class CAnimatedVariable : public CBaseAnimatedVariable {
|
||||
public:
|
||||
CAnimatedVariable() : CBaseAnimatedVariable(typeToeAnimatedVarType<VarType>) {
|
||||
;
|
||||
} // dummy var
|
||||
using CAnimatedVariable = Hyprutils::Animation::CGenericAnimatedVariable<VarType, SAnimationContext>;
|
||||
|
||||
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) {
|
||||
create(pAnimConfig, pWindow, policy);
|
||||
m_Value = value;
|
||||
m_Goal = value;
|
||||
}
|
||||
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) {
|
||||
create(pAnimConfig, pLayer, policy);
|
||||
m_Value = value;
|
||||
m_Goal = value;
|
||||
}
|
||||
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) {
|
||||
create(pAnimConfig, pWorkspace, policy);
|
||||
m_Value = value;
|
||||
m_Goal = value;
|
||||
}
|
||||
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) {
|
||||
create(pAnimConfig, policy);
|
||||
m_Value = value;
|
||||
m_Goal = value;
|
||||
}
|
||||
template <Animable VarType>
|
||||
using PHLANIMVAR = SP<CAnimatedVariable<VarType>>;
|
||||
|
||||
using CBaseAnimatedVariable::create;
|
||||
|
||||
CAnimatedVariable(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable(CAnimatedVariable&&) = delete;
|
||||
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
|
||||
|
||||
~CAnimatedVariable() = default;
|
||||
|
||||
// gets the current vector value (real time)
|
||||
const VarType& value() const {
|
||||
return m_Value;
|
||||
}
|
||||
|
||||
// gets the goal vector value
|
||||
const VarType& goal() const {
|
||||
return m_Goal;
|
||||
}
|
||||
|
||||
CAnimatedVariable& operator=(const VarType& v) {
|
||||
if (v == m_Goal)
|
||||
return *this;
|
||||
|
||||
m_Goal = v;
|
||||
animationBegin = std::chrono::steady_clock::now();
|
||||
m_Begun = m_Value;
|
||||
|
||||
onAnimationBegin();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
void setValue(const VarType& v) {
|
||||
if (v == m_Value)
|
||||
return;
|
||||
|
||||
m_Value = v;
|
||||
animationBegin = std::chrono::steady_clock::now();
|
||||
m_Begun = m_Value;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
// Sets the actual value and goal
|
||||
void setValueAndWarp(const VarType& v) {
|
||||
m_Goal = v;
|
||||
m_bIsBeingAnimated = true;
|
||||
warp();
|
||||
}
|
||||
|
||||
void warp(bool endCallback = true) override {
|
||||
if (!m_bIsBeingAnimated)
|
||||
return;
|
||||
|
||||
m_Value = m_Goal;
|
||||
|
||||
m_bIsBeingAnimated = false;
|
||||
|
||||
if (m_fUpdateCallback)
|
||||
m_fUpdateCallback(this);
|
||||
|
||||
if (endCallback)
|
||||
onAnimationEnd();
|
||||
}
|
||||
|
||||
private:
|
||||
VarType m_Value{};
|
||||
VarType m_Goal{};
|
||||
VarType m_Begun{};
|
||||
|
||||
// owners
|
||||
|
||||
friend class CAnimationManager;
|
||||
friend class CWorkspace;
|
||||
friend class CLayerSurface;
|
||||
friend class CHyprRenderer;
|
||||
};
|
||||
template <Animable VarType>
|
||||
using PHLANIMVARREF = WP<CAnimatedVariable<VarType>>;
|
||||
|
@@ -1,90 +0,0 @@
|
||||
#include "BezierCurve.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
|
||||
void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
|
||||
const auto BEGIN = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Avoid reallocations by reserving enough memory upfront
|
||||
m_vPoints.resize(pVec->size() + 2);
|
||||
m_vPoints[0] = Vector2D(0, 0); // Start point
|
||||
size_t index = 1; // Start after the first element
|
||||
for (const auto& vec : *pVec) {
|
||||
if (index < m_vPoints.size() - 1) { // Bounds check to ensure safety
|
||||
m_vPoints[index] = vec;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
m_vPoints.back() = Vector2D(1, 1); // End point
|
||||
|
||||
RASSERT(m_vPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_vPoints.size());
|
||||
|
||||
// bake BAKEDPOINTS points for faster lookups
|
||||
// T -> X ( / BAKEDPOINTS )
|
||||
for (int i = 0; i < BAKEDPOINTS; ++i) {
|
||||
float const t = (i + 1) / (float)BAKEDPOINTS;
|
||||
m_aPointsBaked[i] = Vector2D(getXForT(t), getYForT(t));
|
||||
}
|
||||
|
||||
const auto ELAPSEDUS = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGIN).count() / 1000.f;
|
||||
const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f;
|
||||
|
||||
const auto BEGINCALC = std::chrono::high_resolution_clock::now();
|
||||
for (int j = 1; j < 10; ++j) {
|
||||
float i = j / 10.0f;
|
||||
getYForPoint(i);
|
||||
}
|
||||
const auto ELAPSEDCALCAVG = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f;
|
||||
|
||||
Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE,
|
||||
ELAPSEDUS, ELAPSEDCALCAVG);
|
||||
}
|
||||
|
||||
float CBezierCurve::getXForT(float const& t) const {
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
|
||||
return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].x + 3 * t2 * (1 - t) * m_vPoints[2].x + t3 * m_vPoints[3].x;
|
||||
}
|
||||
|
||||
float CBezierCurve::getYForT(float const& t) const {
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
|
||||
return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].y + 3 * t2 * (1 - t) * m_vPoints[2].y + t3 * m_vPoints[3].y;
|
||||
}
|
||||
|
||||
// Todo: this probably can be done better and faster
|
||||
float CBezierCurve::getYForPoint(float const& x) const {
|
||||
if (x >= 1.f)
|
||||
return 1.f;
|
||||
if (x <= 0.f)
|
||||
return 0.f;
|
||||
|
||||
int index = 0;
|
||||
bool below = true;
|
||||
for (int step = (BAKEDPOINTS + 1) / 2; step > 0; step /= 2) {
|
||||
if (below)
|
||||
index += step;
|
||||
else
|
||||
index -= step;
|
||||
|
||||
below = m_aPointsBaked[index].x < x;
|
||||
}
|
||||
|
||||
int lowerIndex = index - (!below || index == BAKEDPOINTS - 1);
|
||||
|
||||
// in the name of performance i shall make a hack
|
||||
const auto LOWERPOINT = &m_aPointsBaked[lowerIndex];
|
||||
const auto UPPERPOINT = &m_aPointsBaked[lowerIndex + 1];
|
||||
|
||||
const auto PERCINDELTA = (x - LOWERPOINT->x) / (UPPERPOINT->x - LOWERPOINT->x);
|
||||
|
||||
if (std::isnan(PERCINDELTA) || std::isinf(PERCINDELTA)) // can sometimes happen for VERY small x
|
||||
return 0.f;
|
||||
|
||||
return LOWERPOINT->y + (UPPERPOINT->y - LOWERPOINT->y) * PERCINDELTA;
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "math/Math.hpp"
|
||||
|
||||
constexpr int BAKEDPOINTS = 255;
|
||||
constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS;
|
||||
|
||||
// an implementation of a cubic bezier curve
|
||||
// might do better later
|
||||
class CBezierCurve {
|
||||
public:
|
||||
// sets up the bezier curve.
|
||||
// this EXCLUDES the 0,0 and 1,1 points,
|
||||
void setup(std::vector<Vector2D>* points);
|
||||
|
||||
float getYForT(float const& t) const;
|
||||
float getXForT(float const& t) const;
|
||||
float getYForPoint(float const& x) const;
|
||||
|
||||
private:
|
||||
// this INCLUDES the 0,0 and 1,1 points.
|
||||
std::vector<Vector2D> m_vPoints;
|
||||
|
||||
std::array<Vector2D, BAKEDPOINTS> m_aPointsBaked;
|
||||
};
|
@@ -43,3 +43,7 @@ Hyprgraphics::CColor::SHSL CHyprColor::asHSL() const {
|
||||
CHyprColor CHyprColor::stripA() const {
|
||||
return {r, g, b, 1.F};
|
||||
}
|
||||
|
||||
CHyprColor CHyprColor::modifyA(float newa) const {
|
||||
return {r, g, b, newa};
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <hyprgraphics/color/Color.hpp>
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
|
||||
class CHyprColor {
|
||||
@@ -18,6 +17,7 @@ class CHyprColor {
|
||||
Hyprgraphics::CColor::SOkLab asOkLab() const;
|
||||
Hyprgraphics::CColor::SHSL asHSL() const;
|
||||
CHyprColor stripA() const;
|
||||
CHyprColor modifyA(float newa) const;
|
||||
|
||||
//
|
||||
bool operator==(const CHyprColor& c2) const {
|
||||
@@ -45,3 +45,18 @@ class CHyprColor {
|
||||
private:
|
||||
Hyprgraphics::CColor::SOkLab okLab; // cache for the OkLab representation
|
||||
};
|
||||
|
||||
//NOLINTNEXTLINE
|
||||
namespace Colors {
|
||||
static const CHyprColor WHITE = CHyprColor(1.F, 1.F, 1.F, 1.F);
|
||||
static const CHyprColor GREEN = CHyprColor(0.F, 1.F, 0.F, 1.F);
|
||||
static const CHyprColor BLUE = CHyprColor(0.F, 0.F, 1.F, 1.F);
|
||||
static const CHyprColor RED = CHyprColor(1.F, 0.F, 0.F, 1.F);
|
||||
static const CHyprColor ORANGE = CHyprColor(1.F, 0.5F, 0.F, 1.F);
|
||||
static const CHyprColor YELLOW = CHyprColor(1.F, 1.F, 0.F, 1.F);
|
||||
static const CHyprColor MAGENTA = CHyprColor(1.F, 0.F, 1.F, 1.F);
|
||||
static const CHyprColor PURPLE = CHyprColor(0.5F, 0.F, 0.5F, 1.F);
|
||||
static const CHyprColor LIME = CHyprColor(0.5F, 1.F, 0.1F, 1.F);
|
||||
static const CHyprColor LIGHT_BLUE = CHyprColor(0.1F, 1.F, 1.F, 1.F);
|
||||
static const CHyprColor BLACK = CHyprColor(0.F, 0.F, 0.F, 1.F);
|
||||
};
|
||||
|
@@ -3,6 +3,9 @@
|
||||
#include <algorithm>
|
||||
#include "../Compositor.hpp"
|
||||
#include "../managers/TokenManager.hpp"
|
||||
#include "Monitor.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
#include "fs/FsUtils.hpp"
|
||||
#include <optional>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
@@ -46,97 +49,6 @@ using namespace Hyprutils::OS;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static const float transforms[][9] = {
|
||||
{
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
},
|
||||
{
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
},
|
||||
{
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
},
|
||||
{
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
},
|
||||
{
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
},
|
||||
{
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
},
|
||||
{
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
},
|
||||
{
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
},
|
||||
};
|
||||
|
||||
std::string absolutePath(const std::string& rawpath, const std::string& currentPath) {
|
||||
auto value = rawpath;
|
||||
|
||||
@@ -161,26 +73,6 @@ std::string absolutePath(const std::string& rawpath, const std::string& currentP
|
||||
return value;
|
||||
}
|
||||
|
||||
void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, const std::string& ownerString) {
|
||||
ASSERT(pSignal);
|
||||
ASSERT(pListener);
|
||||
|
||||
wl_signal_add(pSignal, pListener);
|
||||
|
||||
Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString);
|
||||
}
|
||||
|
||||
void removeWLSignal(wl_listener* pListener) {
|
||||
wl_list_remove(&pListener->link);
|
||||
wl_list_init(&pListener->link);
|
||||
|
||||
Debug::log(LOG, "Removed listener {:x}", (uintptr_t)pListener);
|
||||
}
|
||||
|
||||
void handleNoop(struct wl_listener* listener, void* data) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
std::string escapeJSONStrings(const std::string& str) {
|
||||
std::ostringstream oss;
|
||||
for (auto const& c : str) {
|
||||
@@ -278,7 +170,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
if (!valid(PWORKSPACE))
|
||||
return {WORKSPACE_INVALID};
|
||||
|
||||
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.id);
|
||||
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->getPrevWorkspaceIDName().id);
|
||||
|
||||
if (!PLASTWORKSPACE)
|
||||
return {WORKSPACE_INVALID};
|
||||
@@ -628,7 +520,7 @@ void logSystemInfo() {
|
||||
}
|
||||
} catch (...) { GPUINFO = "error"; }
|
||||
#else
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep -E '(VGA|Display|3D)'");
|
||||
#endif
|
||||
Debug::log(LOG, "GPU information:\n{}\n", GPUINFO);
|
||||
|
||||
@@ -639,7 +531,7 @@ void logSystemInfo() {
|
||||
// log etc
|
||||
Debug::log(LOG, "os-release:");
|
||||
|
||||
Debug::log(NONE, "{}", execAndGet("cat /etc/os-release"));
|
||||
Debug::log(NONE, "{}", NFsUtils::readFileAsString("/etc/os-release").value_or("error"));
|
||||
}
|
||||
|
||||
int64_t getPPIDof(int64_t pid) {
|
||||
@@ -853,50 +745,48 @@ bool envEnabled(const std::string& env) {
|
||||
return std::string(ENV) == "1";
|
||||
}
|
||||
|
||||
std::pair<int, std::string> openExclusiveShm() {
|
||||
std::pair<CFileDescriptor, std::string> openExclusiveShm() {
|
||||
// Only absolute paths can be shared across different shm_open() calls
|
||||
std::string name = "/" + g_pTokenManager->getRandomUUID();
|
||||
|
||||
for (size_t i = 0; i < 69; ++i) {
|
||||
int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (fd >= 0)
|
||||
return {fd, name};
|
||||
CFileDescriptor fd{shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)};
|
||||
if (fd.isValid())
|
||||
return {std::move(fd), name};
|
||||
}
|
||||
|
||||
return {-1, ""};
|
||||
return {{}, ""};
|
||||
}
|
||||
|
||||
int allocateSHMFile(size_t len) {
|
||||
CFileDescriptor allocateSHMFile(size_t len) {
|
||||
auto [fd, name] = openExclusiveShm();
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
if (!fd.isValid())
|
||||
return {};
|
||||
|
||||
shm_unlink(name.c_str());
|
||||
|
||||
int ret;
|
||||
do {
|
||||
ret = ftruncate(fd, len);
|
||||
ret = ftruncate(fd.get(), len);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
if (ret < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
return {};
|
||||
}
|
||||
|
||||
return fd;
|
||||
return std::move(fd);
|
||||
}
|
||||
|
||||
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) {
|
||||
bool allocateSHMFilePair(size_t size, CFileDescriptor& rw_fd_ptr, CFileDescriptor& ro_fd_ptr) {
|
||||
auto [fd, name] = openExclusiveShm();
|
||||
if (fd < 0) {
|
||||
if (!fd.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// CLOEXEC is guaranteed to be set by shm_open
|
||||
int ro_fd = shm_open(name.c_str(), O_RDONLY, 0);
|
||||
if (ro_fd < 0) {
|
||||
CFileDescriptor ro_fd{shm_open(name.c_str(), O_RDONLY, 0)};
|
||||
if (!ro_fd.isValid()) {
|
||||
shm_unlink(name.c_str());
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -904,24 +794,20 @@ bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) {
|
||||
|
||||
// Make sure the file cannot be re-opened in read-write mode (e.g. via
|
||||
// "/proc/self/fd/" on Linux)
|
||||
if (fchmod(fd, 0) != 0) {
|
||||
close(fd);
|
||||
close(ro_fd);
|
||||
if (fchmod(fd.get(), 0) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret;
|
||||
do {
|
||||
ret = ftruncate(fd, size);
|
||||
ret = ftruncate(fd.get(), size);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
if (ret < 0) {
|
||||
close(fd);
|
||||
close(ro_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
*rw_fd_ptr = fd;
|
||||
*ro_fd_ptr = ro_fd;
|
||||
rw_fd_ptr = std::move(fd);
|
||||
ro_fd_ptr = std::move(ro_fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -931,30 +817,3 @@ float stringToPercentage(const std::string& VALUE, const float REL) {
|
||||
else
|
||||
return std::stof(VALUE);
|
||||
}
|
||||
|
||||
bool executableExistsInPath(const std::string& exe) {
|
||||
if (!getenv("PATH"))
|
||||
return false;
|
||||
|
||||
static CVarList paths(getenv("PATH"), 0, ':', true);
|
||||
|
||||
for (auto& p : paths) {
|
||||
std::string path = p + std::string{"/"} + exe;
|
||||
std::error_code ec;
|
||||
if (!std::filesystem::exists(path, ec) || ec)
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::is_regular_file(path, ec) || ec)
|
||||
continue;
|
||||
|
||||
auto stat = std::filesystem::status(path, ec);
|
||||
if (ec)
|
||||
continue;
|
||||
|
||||
auto perms = stat.permissions();
|
||||
|
||||
return std::filesystem::perms::none != (perms & std::filesystem::perms::others_exec);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -1,12 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <wayland-server.h>
|
||||
#include "math/Math.hpp"
|
||||
#include <vector>
|
||||
#include <format>
|
||||
#include <expected>
|
||||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
#include "../SharedDefs.hpp"
|
||||
#include "../macros.hpp"
|
||||
|
||||
@@ -21,8 +20,6 @@ struct SWorkspaceIDName {
|
||||
};
|
||||
|
||||
std::string absolutePath(const std::string&, const std::string&);
|
||||
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
|
||||
void removeWLSignal(wl_listener*);
|
||||
std::string escapeJSONStrings(const std::string& str);
|
||||
bool isDirection(const std::string&);
|
||||
bool isDirection(const char&);
|
||||
@@ -39,10 +36,9 @@ double normalizeAngleRad(double ang);
|
||||
std::vector<SCallstackFrameInfo> getBacktrace();
|
||||
void throwError(const std::string& err);
|
||||
bool envEnabled(const std::string& env);
|
||||
int allocateSHMFile(size_t len);
|
||||
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr);
|
||||
Hyprutils::OS::CFileDescriptor allocateSHMFile(size_t len);
|
||||
bool allocateSHMFilePair(size_t size, Hyprutils::OS::CFileDescriptor& rw_fd_ptr, Hyprutils::OS::CFileDescriptor& ro_fd_ptr);
|
||||
float stringToPercentage(const std::string& VALUE, const float REL);
|
||||
bool executableExistsInPath(const std::string& exe);
|
||||
|
||||
template <typename... Args>
|
||||
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#include "Monitor.hpp"
|
||||
#include "MiscFunctions.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include "math/Math.hpp"
|
||||
#include "../protocols/ColorManagement.hpp"
|
||||
#include "sync/SyncReleaser.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
@@ -16,15 +18,25 @@
|
||||
#include "../managers/PointerManager.hpp"
|
||||
#include "../managers/eventLoop/EventLoopManager.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
#include "../managers/EventManager.hpp"
|
||||
#include "../managers/LayoutManager.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
#include "sync/SyncTimeline.hpp"
|
||||
#include "../desktop/LayerSurface.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include "debug/Log.hpp"
|
||||
#include "debug/HyprNotificationOverlay.hpp"
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||
#include <cstring>
|
||||
#include <ranges>
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::Utils;
|
||||
using namespace Hyprutils::OS;
|
||||
using enum NContentType::eContentType;
|
||||
|
||||
int ratHandler(void* data) {
|
||||
static int ratHandler(void* data) {
|
||||
g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock());
|
||||
|
||||
return 1;
|
||||
@@ -42,9 +54,10 @@ void CMonitor::onConnect(bool noRule) {
|
||||
EMIT_HOOK_EVENT("preMonitorAdded", self.lock());
|
||||
CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }};
|
||||
|
||||
g_pEventLoopManager->doLater([] { g_pConfigManager->ensurePersistentWorkspacesPresent(); });
|
||||
|
||||
if (output->supportsExplicit) {
|
||||
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
|
||||
outTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
|
||||
}
|
||||
|
||||
listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); });
|
||||
@@ -85,7 +98,7 @@ void CMonitor::onConnect(bool noRule) {
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName);
|
||||
g_pHyprRenderer->applyMonitorRule(self.lock(), &activeMonitorRule, true);
|
||||
applyMonitorRule(&activeMonitorRule, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -99,7 +112,7 @@ void CMonitor::onConnect(bool noRule) {
|
||||
SMonitorRule rule = activeMonitorRule;
|
||||
rule.resolution = SIZE;
|
||||
|
||||
g_pHyprRenderer->applyMonitorRule(self.lock(), &rule);
|
||||
applyMonitorRule(&rule);
|
||||
});
|
||||
|
||||
tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
|
||||
@@ -172,7 +185,7 @@ void CMonitor::onConnect(bool noRule) {
|
||||
|
||||
// set mode, also applies
|
||||
if (!noRule)
|
||||
g_pHyprRenderer->applyMonitorRule(self.lock(), &monitorRule, true);
|
||||
applyMonitorRule(&monitorRule, true);
|
||||
|
||||
if (!state.commit())
|
||||
Debug::log(WARN, "state.commit() failed in CMonitor::onCommit");
|
||||
@@ -361,6 +374,464 @@ void CMonitor::onDisconnect(bool destroy) {
|
||||
std::erase_if(g_pCompositor->m_vMonitors, [&](PHLMONITOR& el) { return el.get() == this; });
|
||||
}
|
||||
|
||||
bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
|
||||
|
||||
static auto PDISABLESCALECHECKS = CConfigValue<Hyprlang::INT>("debug:disable_scale_checks");
|
||||
|
||||
Debug::log(LOG, "Applying monitor rule for {}", szName);
|
||||
|
||||
activeMonitorRule = *pMonitorRule;
|
||||
|
||||
if (forceSize.has_value())
|
||||
activeMonitorRule.resolution = forceSize.value();
|
||||
|
||||
const auto RULE = &activeMonitorRule;
|
||||
|
||||
// if it's disabled, disable and ignore
|
||||
if (RULE->disabled) {
|
||||
if (m_bEnabled)
|
||||
onDisconnect();
|
||||
|
||||
events.modeChanged.emit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// don't touch VR headsets
|
||||
if (output->nonDesktop)
|
||||
return true;
|
||||
|
||||
if (!m_bEnabled) {
|
||||
onConnect(true); // enable it.
|
||||
Debug::log(LOG, "Monitor {} is disabled but is requested to be enabled", szName);
|
||||
force = true;
|
||||
}
|
||||
|
||||
// Check if the rule isn't already applied
|
||||
// TODO: clean this up lol
|
||||
if (!force && DELTALESSTHAN(vecPixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(vecPixelSize.y, RULE->resolution.y, 1) &&
|
||||
DELTALESSTHAN(refreshRate, RULE->refreshRate, 1) && setScale == RULE->scale &&
|
||||
((DELTALESSTHAN(vecPosition.x, RULE->offset.x, 1) && DELTALESSTHAN(vecPosition.y, RULE->offset.y, 1)) || RULE->offset == Vector2D(-INT32_MAX, -INT32_MAX)) &&
|
||||
transform == RULE->transform && RULE->enable10bit == enabled10bit && RULE->cmType == cmType && RULE->sdrSaturation == sdrSaturation &&
|
||||
RULE->sdrBrightness == sdrBrightness && !std::memcmp(&customDrmMode, &RULE->drmMode, sizeof(customDrmMode))) {
|
||||
|
||||
Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", szName);
|
||||
|
||||
setMirror(RULE->mirrorOf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool autoScale = false;
|
||||
|
||||
if (RULE->scale > 0.1) {
|
||||
scale = RULE->scale;
|
||||
} else {
|
||||
autoScale = true;
|
||||
const auto DEFAULTSCALE = getDefaultScale();
|
||||
scale = DEFAULTSCALE;
|
||||
}
|
||||
|
||||
setScale = scale;
|
||||
transform = RULE->transform;
|
||||
|
||||
// accumulate requested modes in reverse order (cause inesrting at front is inefficient)
|
||||
std::vector<SP<Aquamarine::SOutputMode>> requestedModes;
|
||||
std::string requestedStr = "unknown";
|
||||
|
||||
// use sortFunc, add best 3 to requestedModes in reverse, since we test in reverse
|
||||
auto addBest3Modes = [&](auto const& sortFunc) {
|
||||
auto sortedModes = output->modes;
|
||||
std::ranges::sort(sortedModes, sortFunc);
|
||||
if (sortedModes.size() > 3)
|
||||
sortedModes.erase(sortedModes.begin() + 3, sortedModes.end());
|
||||
requestedModes.insert(requestedModes.end(), sortedModes.rbegin(), sortedModes.rend());
|
||||
};
|
||||
|
||||
// last fallback is always preferred mode
|
||||
if (!output->preferredMode())
|
||||
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", output->name);
|
||||
else
|
||||
requestedModes.push_back(output->preferredMode());
|
||||
|
||||
if (RULE->resolution == Vector2D()) {
|
||||
requestedStr = "preferred";
|
||||
|
||||
// fallback to first 3 modes if preferred fails/doesn't exist
|
||||
requestedModes = output->modes;
|
||||
if (requestedModes.size() > 3)
|
||||
requestedModes.erase(requestedModes.begin() + 3, requestedModes.end());
|
||||
std::ranges::reverse(requestedModes.begin(), requestedModes.end());
|
||||
|
||||
if (output->preferredMode())
|
||||
requestedModes.push_back(output->preferredMode());
|
||||
} else if (RULE->resolution == Vector2D(-1, -1)) {
|
||||
requestedStr = "highrr";
|
||||
|
||||
// sort prioritizing refresh rate 1st and resolution 2nd, then add best 3
|
||||
addBest3Modes([](auto const& a, auto const& b) {
|
||||
if (std::round(a->refreshRate) > std::round(b->refreshRate))
|
||||
return true;
|
||||
else if (DELTALESSTHAN((float)a->refreshRate, (float)b->refreshRate, 1.F) && a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
} else if (RULE->resolution == Vector2D(-1, -2)) {
|
||||
requestedStr = "highres";
|
||||
|
||||
// sort prioritizing resultion 1st and refresh rate 2nd, then add best 3
|
||||
addBest3Modes([](auto const& a, auto const& b) {
|
||||
if (a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y)
|
||||
return true;
|
||||
else if (DELTALESSTHAN(a->pixelSize.x, b->pixelSize.x, 1) && DELTALESSTHAN(a->pixelSize.y, b->pixelSize.y, 1) &&
|
||||
std::round(a->refreshRate) > std::round(b->refreshRate))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
} else if (RULE->resolution != Vector2D()) {
|
||||
// user requested mode
|
||||
requestedStr = std::format("{:X0}@{:.2f}Hz", RULE->resolution, RULE->refreshRate);
|
||||
|
||||
// sort by closeness to requested, then add best 3
|
||||
addBest3Modes([&](auto const& a, auto const& b) {
|
||||
if (abs(a->pixelSize.x - RULE->resolution.x) < abs(b->pixelSize.x - RULE->resolution.x))
|
||||
return true;
|
||||
if (a->pixelSize.x == b->pixelSize.x && abs(a->pixelSize.y - RULE->resolution.y) < abs(b->pixelSize.y - RULE->resolution.y))
|
||||
return true;
|
||||
if (a->pixelSize == b->pixelSize && abs((a->refreshRate / 1000.f) - RULE->refreshRate) < abs((b->refreshRate / 1000.f) - RULE->refreshRate))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
// if the best mode isnt close to requested, then try requested as custom mode first
|
||||
if (!requestedModes.empty()) {
|
||||
auto bestMode = requestedModes.back();
|
||||
if (!DELTALESSTHAN(bestMode->pixelSize.x, RULE->resolution.x, 1) || !DELTALESSTHAN(bestMode->pixelSize.y, RULE->resolution.y, 1) ||
|
||||
!DELTALESSTHAN(bestMode->refreshRate / 1000.f, RULE->refreshRate, 1))
|
||||
requestedModes.push_back(makeShared<Aquamarine::SOutputMode>(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = RULE->refreshRate * 1000.f}));
|
||||
}
|
||||
|
||||
// then if requested is custom, try custom mode first
|
||||
if (RULE->drmMode.type == DRM_MODE_TYPE_USERDEF) {
|
||||
if (output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM)
|
||||
Debug::log(ERR, "Tried to set custom modeline on non-DRM output");
|
||||
else
|
||||
requestedModes.push_back(makeShared<Aquamarine::SOutputMode>(
|
||||
Aquamarine::SOutputMode{.pixelSize = {RULE->drmMode.hdisplay, RULE->drmMode.vdisplay}, .refreshRate = RULE->drmMode.vrefresh, .modeInfo = RULE->drmMode}));
|
||||
}
|
||||
}
|
||||
|
||||
const auto WAS10B = enabled10bit;
|
||||
const auto OLDRES = vecPixelSize;
|
||||
bool success = false;
|
||||
|
||||
// Needed in case we are switching from a custom modeline to a standard mode
|
||||
customDrmMode = {};
|
||||
currentMode = nullptr;
|
||||
|
||||
output->state->setFormat(DRM_FORMAT_XRGB8888);
|
||||
prevDrmFormat = drmFormat;
|
||||
drmFormat = DRM_FORMAT_XRGB8888;
|
||||
output->state->resetExplicitFences();
|
||||
|
||||
if (Debug::trace) {
|
||||
Debug::log(TRACE, "Monitor {} requested modes:", szName);
|
||||
if (requestedModes.empty())
|
||||
Debug::log(TRACE, "| None");
|
||||
else {
|
||||
for (auto const& mode : requestedModes | std::views::reverse) {
|
||||
Debug::log(TRACE, "| {:X0}@{:.2f}Hz", mode->pixelSize, mode->refreshRate / 1000.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& mode : requestedModes | std::views::reverse) {
|
||||
std::string modeStr = std::format("{:X0}@{:.2f}Hz", mode->pixelSize, mode->refreshRate / 1000.f);
|
||||
|
||||
if (mode->modeInfo.has_value() && mode->modeInfo->type == DRM_MODE_TYPE_USERDEF) {
|
||||
output->state->setCustomMode(mode);
|
||||
|
||||
if (!state.test()) {
|
||||
Debug::log(ERR, "Monitor {}: REJECTED custom mode {}!", szName, modeStr);
|
||||
continue;
|
||||
}
|
||||
|
||||
customDrmMode = mode->modeInfo.value();
|
||||
} else {
|
||||
output->state->setMode(mode);
|
||||
|
||||
if (!state.test()) {
|
||||
Debug::log(ERR, "Monitor {}: REJECTED available mode {}!", szName, modeStr);
|
||||
if (mode->preferred)
|
||||
Debug::log(ERR, "Monitor {}: REJECTED preferred mode!!!", szName);
|
||||
continue;
|
||||
}
|
||||
|
||||
customDrmMode = {};
|
||||
}
|
||||
|
||||
refreshRate = mode->refreshRate / 1000.f;
|
||||
vecSize = mode->pixelSize;
|
||||
currentMode = mode;
|
||||
|
||||
success = true;
|
||||
|
||||
if (mode->preferred)
|
||||
Debug::log(LOG, "Monitor {}: requested {}, using preferred mode {}", szName, requestedStr, modeStr);
|
||||
else if (mode->modeInfo.has_value() && mode->modeInfo->type == DRM_MODE_TYPE_USERDEF)
|
||||
Debug::log(LOG, "Monitor {}: requested {}, using custom mode {}", szName, requestedStr, modeStr);
|
||||
else
|
||||
Debug::log(LOG, "Monitor {}: requested {}, using available mode {}", szName, requestedStr, modeStr);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// try requested as custom mode jic it works
|
||||
if (!success && RULE->resolution != Vector2D() && RULE->resolution != Vector2D(-1, -1) && RULE->resolution != Vector2D(-1, -2)) {
|
||||
auto refreshRate = output->getBackend()->type() == Aquamarine::eBackendType::AQ_BACKEND_DRM ? RULE->refreshRate * 1000 : 0;
|
||||
auto mode = makeShared<Aquamarine::SOutputMode>(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = refreshRate});
|
||||
std::string modeStr = std::format("{:X0}@{:.2f}Hz", mode->pixelSize, mode->refreshRate / 1000.f);
|
||||
|
||||
output->state->setCustomMode(mode);
|
||||
|
||||
if (state.test()) {
|
||||
Debug::log(LOG, "Monitor {}: requested {}, using custom mode {}", szName, requestedStr, modeStr);
|
||||
|
||||
refreshRate = mode->refreshRate / 1000.f;
|
||||
vecSize = mode->pixelSize;
|
||||
currentMode = mode;
|
||||
customDrmMode = {};
|
||||
|
||||
success = true;
|
||||
} else
|
||||
Debug::log(ERR, "Monitor {}: REJECTED custom mode {}!", szName, modeStr);
|
||||
}
|
||||
|
||||
// try any of the modes if none of the above work
|
||||
if (!success) {
|
||||
for (auto const& mode : output->modes) {
|
||||
output->state->setMode(mode);
|
||||
|
||||
if (!state.test())
|
||||
continue;
|
||||
|
||||
auto errorMessage =
|
||||
std::format("Monitor {} failed to set any requested modes, falling back to mode {:X0}@{:.2f}Hz", szName, mode->pixelSize, mode->refreshRate / 1000.f);
|
||||
Debug::log(WARN, errorMessage);
|
||||
g_pHyprNotificationOverlay->addNotification(errorMessage, CHyprColor(0xff0000ff), 5000, ICON_WARNING);
|
||||
|
||||
refreshRate = mode->refreshRate / 1000.f;
|
||||
vecSize = mode->pixelSize;
|
||||
currentMode = mode;
|
||||
customDrmMode = {};
|
||||
|
||||
success = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Debug::log(ERR, "Monitor {} has NO FALLBACK MODES, and an INVALID one was requested: {:X0}@{:.2f}Hz", szName, RULE->resolution, RULE->refreshRate);
|
||||
return true;
|
||||
}
|
||||
|
||||
vrrActive = output->state->state().adaptiveSync // disabled here, will be tested in CConfigManager::ensureVRR()
|
||||
|| createdByUser; // wayland backend doesn't allow for disabling adaptive_sync
|
||||
|
||||
vecPixelSize = vecSize;
|
||||
|
||||
// clang-format off
|
||||
static const std::array<std::vector<std::pair<std::string, uint32_t>>, 2> formats{
|
||||
std::vector<std::pair<std::string, uint32_t>>{ /* 10-bit */
|
||||
{"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}
|
||||
},
|
||||
std::vector<std::pair<std::string, uint32_t>>{ /* 8-bit */
|
||||
{"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
bool set10bit = false;
|
||||
|
||||
for (auto const& fmt : formats[(int)!RULE->enable10bit]) {
|
||||
output->state->setFormat(fmt.second);
|
||||
prevDrmFormat = drmFormat;
|
||||
drmFormat = fmt.second;
|
||||
|
||||
if (!state.test()) {
|
||||
Debug::log(ERR, "output {} failed basic test on format {}", szName, fmt.first);
|
||||
} else {
|
||||
Debug::log(LOG, "output {} succeeded basic test on format {}", szName, fmt.first);
|
||||
if (RULE->enable10bit && fmt.first.contains("101010"))
|
||||
set10bit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enabled10bit = set10bit;
|
||||
|
||||
auto oldImageDescription = imageDescription;
|
||||
cmType = RULE->cmType;
|
||||
switch (cmType) {
|
||||
case CM_AUTO: cmType = enabled10bit && output->parsedEDID.supportsBT2020 ? CM_WIDE : CM_SRGB; break;
|
||||
case CM_EDID: cmType = output->parsedEDID.chromaticityCoords.has_value() ? CM_EDID : CM_SRGB; break;
|
||||
case CM_HDR:
|
||||
case CM_HDR_EDID:
|
||||
cmType = output->parsedEDID.supportsBT2020 && output->parsedEDID.hdrMetadata.has_value() && output->parsedEDID.hdrMetadata->supportsPQ ? cmType : CM_SRGB;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
switch (cmType) {
|
||||
case CM_SRGB: imageDescription = {}; break; // assumes SImageDescirption defaults to sRGB
|
||||
case CM_WIDE:
|
||||
imageDescription = {.primariesNameSet = true,
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020)};
|
||||
break;
|
||||
case CM_EDID:
|
||||
imageDescription = {.primariesNameSet = false,
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||
.primaries = {
|
||||
.red = {.x = output->parsedEDID.chromaticityCoords->red.x, .y = output->parsedEDID.chromaticityCoords->red.y},
|
||||
.green = {.x = output->parsedEDID.chromaticityCoords->green.x, .y = output->parsedEDID.chromaticityCoords->green.y},
|
||||
.blue = {.x = output->parsedEDID.chromaticityCoords->blue.x, .y = output->parsedEDID.chromaticityCoords->blue.y},
|
||||
.white = {.x = output->parsedEDID.chromaticityCoords->white.x, .y = output->parsedEDID.chromaticityCoords->white.y},
|
||||
}};
|
||||
break;
|
||||
case CM_HDR:
|
||||
imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
|
||||
.primariesNameSet = true,
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
|
||||
.luminances = {.min = 0, .max = 10000, .reference = 203}};
|
||||
break;
|
||||
case CM_HDR_EDID:
|
||||
imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
|
||||
.primariesNameSet = false,
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||
.primaries = output->parsedEDID.chromaticityCoords.has_value() ?
|
||||
NColorManagement::SPCPRimaries{
|
||||
.red = {.x = output->parsedEDID.chromaticityCoords->red.x, .y = output->parsedEDID.chromaticityCoords->red.y},
|
||||
.green = {.x = output->parsedEDID.chromaticityCoords->green.x, .y = output->parsedEDID.chromaticityCoords->green.y},
|
||||
.blue = {.x = output->parsedEDID.chromaticityCoords->blue.x, .y = output->parsedEDID.chromaticityCoords->blue.y},
|
||||
.white = {.x = output->parsedEDID.chromaticityCoords->white.x, .y = output->parsedEDID.chromaticityCoords->white.y},
|
||||
} :
|
||||
NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
|
||||
.luminances = {.min = output->parsedEDID.hdrMetadata->desiredContentMinLuminance,
|
||||
.max = output->parsedEDID.hdrMetadata->desiredContentMaxLuminance,
|
||||
.reference = output->parsedEDID.hdrMetadata->desiredMaxFrameAverageLuminance}};
|
||||
|
||||
break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
if (oldImageDescription != imageDescription)
|
||||
PROTO::colorManagement->onMonitorImageDescriptionChanged(self);
|
||||
|
||||
sdrSaturation = RULE->sdrSaturation;
|
||||
sdrBrightness = RULE->sdrBrightness;
|
||||
|
||||
Vector2D logicalSize = vecPixelSize / scale;
|
||||
if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) {
|
||||
// invalid scale, will produce fractional pixels.
|
||||
// find the nearest valid.
|
||||
|
||||
float searchScale = std::round(scale * 120.0);
|
||||
bool found = false;
|
||||
|
||||
double scaleZero = searchScale / 120.0;
|
||||
|
||||
Vector2D logicalZero = vecPixelSize / scaleZero;
|
||||
if (logicalZero == logicalZero.round())
|
||||
scale = scaleZero;
|
||||
else {
|
||||
for (size_t i = 1; i < 90; ++i) {
|
||||
double scaleUp = (searchScale + i) / 120.0;
|
||||
double scaleDown = (searchScale - i) / 120.0;
|
||||
|
||||
Vector2D logicalUp = vecPixelSize / scaleUp;
|
||||
Vector2D logicalDown = vecPixelSize / scaleDown;
|
||||
|
||||
if (logicalUp == logicalUp.round()) {
|
||||
found = true;
|
||||
searchScale = scaleUp;
|
||||
break;
|
||||
}
|
||||
if (logicalDown == logicalDown.round()) {
|
||||
found = true;
|
||||
searchScale = scaleDown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (autoScale)
|
||||
scale = std::round(scaleZero);
|
||||
else {
|
||||
Debug::log(ERR, "Invalid scale passed to monitor, {} failed to find a clean divisor", scale);
|
||||
g_pConfigManager->addParseError("Invalid scale passed to monitor " + szName + ", failed to find a clean divisor");
|
||||
scale = getDefaultScale();
|
||||
}
|
||||
} else {
|
||||
if (!autoScale) {
|
||||
Debug::log(ERR, "Invalid scale passed to monitor, {} found suggestion {}", scale, searchScale);
|
||||
g_pConfigManager->addParseError(
|
||||
std::format("Invalid scale passed to monitor {}, failed to find a clean divisor. Suggested nearest scale: {:5f}", szName, searchScale));
|
||||
scale = getDefaultScale();
|
||||
} else
|
||||
scale = searchScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output->scheduleFrame();
|
||||
|
||||
if (!state.commit())
|
||||
Debug::log(ERR, "Couldn't commit output named {}", output->name);
|
||||
|
||||
Vector2D xfmd = transform % 2 == 1 ? Vector2D{vecPixelSize.y, vecPixelSize.x} : vecPixelSize;
|
||||
vecSize = (xfmd / scale).round();
|
||||
vecTransformedSize = xfmd;
|
||||
|
||||
if (createdByUser) {
|
||||
CBox transformedBox = {0, 0, vecTransformedSize.x, vecTransformedSize.y};
|
||||
transformedBox.transform(wlTransformToHyprutils(invertTransform(transform)), vecTransformedSize.x, vecTransformedSize.y);
|
||||
|
||||
vecPixelSize = Vector2D(transformedBox.width, transformedBox.height);
|
||||
}
|
||||
|
||||
updateMatrix();
|
||||
|
||||
if (WAS10B != enabled10bit || OLDRES != vecPixelSize)
|
||||
g_pHyprOpenGL->destroyMonitorResources(self.lock());
|
||||
|
||||
g_pCompositor->arrangeMonitors();
|
||||
|
||||
damage.setSize(vecTransformedSize);
|
||||
|
||||
// Set scale for all surfaces on this monitor, needed for some clients
|
||||
// but not on unsafe state to avoid crashes
|
||||
if (!g_pCompositor->m_bUnsafeState) {
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
w->updateSurfaceScaleTransformDetails();
|
||||
}
|
||||
}
|
||||
// updato us
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(ID);
|
||||
|
||||
// reload to fix mirrors
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
|
||||
Debug::log(LOG, "Monitor {} data dump: res {:X}@{:.2f}Hz, scale {:.2f}, transform {}, pos {:X}, 10b {}", szName, vecPixelSize, refreshRate, scale, (int)transform, vecPosition,
|
||||
(int)enabled10bit);
|
||||
|
||||
EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr);
|
||||
|
||||
events.modeChanged.emit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(const pixman_region32_t* rg) {
|
||||
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
|
||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) {
|
||||
@@ -370,18 +841,18 @@ void CMonitor::addDamage(const pixman_region32_t* rg) {
|
||||
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(const CRegion* rg) {
|
||||
addDamage(const_cast<CRegion*>(rg)->pixman());
|
||||
void CMonitor::addDamage(const CRegion& rg) {
|
||||
addDamage(const_cast<CRegion*>(&rg)->pixman());
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(const CBox* box) {
|
||||
void CMonitor::addDamage(const CBox& box) {
|
||||
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
|
||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) {
|
||||
damage.damageEntire();
|
||||
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
}
|
||||
|
||||
if (damage.damage(*box))
|
||||
if (damage.damage(box))
|
||||
g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
}
|
||||
|
||||
@@ -390,8 +861,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
|
||||
static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate");
|
||||
|
||||
// skip scheduling extra frames for fullsreen apps with vrr
|
||||
bool shouldSkip =
|
||||
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
|
||||
const bool shouldSkip = activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN &&
|
||||
(*PNOBREAK == 1 || (*PNOBREAK == 2 && activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && output->state->state().adaptiveSync;
|
||||
|
||||
// keep requested minimum refresh rate
|
||||
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) {
|
||||
@@ -412,7 +883,7 @@ bool CMonitor::matchesStaticSelector(const std::string& selector) const {
|
||||
// match by description
|
||||
const auto DESCRIPTIONSELECTOR = selector.substr(5);
|
||||
|
||||
return DESCRIPTIONSELECTOR == szShortDescription || DESCRIPTIONSELECTOR == szDescription;
|
||||
return szDescription.starts_with(DESCRIPTIONSELECTOR) || szShortDescription.starts_with(DESCRIPTIONSELECTOR);
|
||||
} else {
|
||||
// match by selector
|
||||
return szName == selector;
|
||||
@@ -530,7 +1001,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||
|
||||
setupDefaultWS(RULE);
|
||||
|
||||
g_pHyprRenderer->applyMonitorRule(self.lock(), (SMonitorRule*)&RULE, true); // will apply the offset and stuff
|
||||
applyMonitorRule((SMonitorRule*)&RULE, true); // will apply the offset and stuff
|
||||
} else {
|
||||
PHLMONITOR BACKUPMON = nullptr;
|
||||
for (auto const& m : g_pCompositor->m_vMonitors) {
|
||||
@@ -610,13 +1081,15 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
|
||||
return;
|
||||
|
||||
const auto POLDWORKSPACE = activeWorkspace;
|
||||
if (POLDWORKSPACE)
|
||||
POLDWORKSPACE->m_bVisible = false;
|
||||
pWorkspace->m_bVisible = true;
|
||||
|
||||
activeWorkspace = pWorkspace;
|
||||
|
||||
if (!internal) {
|
||||
const auto ANIMTOLEFT = pWorkspace->m_iID > POLDWORKSPACE->m_iID;
|
||||
const auto ANIMTOLEFT = POLDWORKSPACE && pWorkspace->m_iID > POLDWORKSPACE->m_iID;
|
||||
if (POLDWORKSPACE)
|
||||
POLDWORKSPACE->startAnim(false, ANIMTOLEFT);
|
||||
pWorkspace->startAnim(true, ANIMTOLEFT);
|
||||
|
||||
@@ -683,6 +1156,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
activeSpecialWorkspace->m_bVisible = false;
|
||||
activeSpecialWorkspace->startAnim(false, false);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + szName});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", ",," + szName});
|
||||
}
|
||||
activeSpecialWorkspace.reset();
|
||||
|
||||
@@ -712,12 +1186,13 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
bool animate = true;
|
||||
//close if open elsewhere
|
||||
const auto PMONITORWORKSPACEOWNER = pWorkspace->m_pMonitor.lock();
|
||||
if (PMONITORWORKSPACEOWNER->activeSpecialWorkspace == pWorkspace) {
|
||||
PMONITORWORKSPACEOWNER->activeSpecialWorkspace.reset();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMONITORWORKSPACEOWNER->szName});
|
||||
if (const auto PMWSOWNER = pWorkspace->m_pMonitor.lock(); PMWSOWNER && PMWSOWNER->activeSpecialWorkspace == pWorkspace) {
|
||||
PMWSOWNER->activeSpecialWorkspace.reset();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMWSOWNER->ID);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMWSOWNER->szName});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", ",," + PMWSOWNER->szName});
|
||||
|
||||
const auto PACTIVEWORKSPACE = PMONITORWORKSPACEOWNER->activeWorkspace;
|
||||
const auto PACTIVEWORKSPACE = PMWSOWNER->activeWorkspace;
|
||||
g_pCompositor->updateFullscreenFadeOnWorkspace(PACTIVEWORKSPACE);
|
||||
|
||||
animate = false;
|
||||
@@ -740,15 +1215,15 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && !w->isX11OverrideRedirect()) {
|
||||
// if it's floating and the middle isnt on the current mon, move it to the center
|
||||
const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE);
|
||||
Vector2D pos = w->m_vRealPosition.goal();
|
||||
Vector2D pos = w->m_vRealPosition->goal();
|
||||
if (!VECINRECT(MIDDLE, PMONFROMMIDDLE->vecPosition.x, PMONFROMMIDDLE->vecPosition.y, PMONFROMMIDDLE->vecPosition.x + PMONFROMMIDDLE->vecSize.x,
|
||||
PMONFROMMIDDLE->vecPosition.y + PMONFROMMIDDLE->vecSize.y)) {
|
||||
// not on any monitor, center
|
||||
pos = middle() / 2.f - w->m_vRealSize.goal() / 2.f;
|
||||
pos = middle() / 2.f - w->m_vRealSize->goal() / 2.f;
|
||||
} else
|
||||
pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition;
|
||||
|
||||
w->m_vRealPosition = pos;
|
||||
*w->m_vRealPosition = pos;
|
||||
w->m_vPosition = pos;
|
||||
}
|
||||
}
|
||||
@@ -764,6 +1239,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
}
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", std::to_string(pWorkspace->m_iID) + "," + pWorkspace->m_szName + "," + szName});
|
||||
|
||||
g_pHyprRenderer->damageMonitor(self.lock());
|
||||
|
||||
@@ -782,6 +1258,29 @@ void CMonitor::moveTo(const Vector2D& pos) {
|
||||
vecPosition = pos;
|
||||
}
|
||||
|
||||
SWorkspaceIDName CMonitor::getPrevWorkspaceIDName(const WORKSPACEID id) {
|
||||
while (!prevWorkSpaces.empty()) {
|
||||
const int PREVID = prevWorkSpaces.top();
|
||||
prevWorkSpaces.pop();
|
||||
if (PREVID == id) // skip same workspace
|
||||
continue;
|
||||
|
||||
// recheck if previous workspace's was moved to another monitor
|
||||
const auto ws = g_pCompositor->getWorkspaceByID(PREVID);
|
||||
if (ws && ws->monitorID() == ID)
|
||||
return {.id = PREVID, .name = ws->m_szName};
|
||||
}
|
||||
|
||||
return {.id = WORKSPACE_INVALID};
|
||||
}
|
||||
|
||||
void CMonitor::addPrevWorkspaceID(const WORKSPACEID id) {
|
||||
if (!prevWorkSpaces.empty() && prevWorkSpaces.top() == id)
|
||||
return;
|
||||
|
||||
prevWorkSpaces.emplace(id);
|
||||
}
|
||||
|
||||
Vector2D CMonitor::middle() {
|
||||
return vecPosition + vecSize / 2.f;
|
||||
}
|
||||
@@ -842,23 +1341,43 @@ bool CMonitor::attemptDirectScanout() {
|
||||
|
||||
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
|
||||
|
||||
if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform)
|
||||
if (!PSURFACE || !PSURFACE->current.texture || !PSURFACE->current.buffer)
|
||||
return false;
|
||||
|
||||
if (PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform)
|
||||
return false;
|
||||
|
||||
// we can't scanout shm buffers.
|
||||
if (!PSURFACE->current.buffer || !PSURFACE->current.buffer->buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
|
||||
const auto params = PSURFACE->current.buffer->buffer->dmabuf();
|
||||
if (!params.success || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
|
||||
return false;
|
||||
|
||||
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get());
|
||||
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt, buffer {}", (uintptr_t)PSURFACE.get(), (uintptr_t)PSURFACE->current.buffer->buffer.get());
|
||||
|
||||
auto PBUFFER = PSURFACE->current.buffer->buffer;
|
||||
|
||||
if (PBUFFER == output->state->state().buffer) {
|
||||
if (scanoutNeedsCursorUpdate) {
|
||||
if (!state.test()) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed basic test");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!output->commit()) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed to commit cursor update");
|
||||
lastScanout.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
scanoutNeedsCursorUpdate = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats
|
||||
// and comes from the appropriate device. This may implode on multi-gpu!!
|
||||
|
||||
const auto params = PSURFACE->current.buffer->buffer->dmabuf();
|
||||
// scanout buffer isn't dmabuf, so no scanout
|
||||
if (!params.success)
|
||||
return false;
|
||||
|
||||
// entering into scanout, so save monitor format
|
||||
if (lastScanout.expired())
|
||||
prevDrmFormat = drmFormat;
|
||||
@@ -868,7 +1387,7 @@ bool CMonitor::attemptDirectScanout() {
|
||||
drmFormat = params.format;
|
||||
}
|
||||
|
||||
output->state->setBuffer(PSURFACE->current.buffer->buffer.lock());
|
||||
output->state->setBuffer(PBUFFER);
|
||||
output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
|
||||
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
|
||||
|
||||
@@ -877,34 +1396,28 @@ bool CMonitor::attemptDirectScanout() {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings();
|
||||
|
||||
// wait for the explicit fence if present, and if kms explicit is allowed
|
||||
bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled;
|
||||
int explicitWaitFD = -1;
|
||||
if (DOEXPLICIT) {
|
||||
explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint);
|
||||
if (explicitWaitFD < 0)
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd");
|
||||
}
|
||||
DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0;
|
||||
|
||||
auto cleanup = CScopeGuard([explicitWaitFD, this]() {
|
||||
output->state->resetExplicitFences();
|
||||
if (explicitWaitFD >= 0)
|
||||
close(explicitWaitFD);
|
||||
});
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
PSURFACE->presentFeedback(&now, self.lock());
|
||||
|
||||
output->state->addDamage(CBox{{}, vecPixelSize});
|
||||
output->state->addDamage(PSURFACE->current.accumulateBufferDamage());
|
||||
output->state->resetExplicitFences();
|
||||
|
||||
auto cleanup = CScopeGuard([this]() { output->state->resetExplicitFences(); });
|
||||
|
||||
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(output);
|
||||
|
||||
bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->current.buffer && PSURFACE->current.buffer->acquire && explicitOptions.explicitKMSEnabled;
|
||||
if (DOEXPLICIT) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD);
|
||||
output->state->setExplicitInFence(explicitWaitFD);
|
||||
// wait for surface's explicit fence if present
|
||||
inFence = PSURFACE->current.buffer->acquire->exportAsFD();
|
||||
if (inFence.isValid()) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", inFence.get());
|
||||
output->state->setExplicitInFence(inFence.get());
|
||||
} else {
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed to acquire an sync file fd for aq IN_FENCE");
|
||||
DOEXPLICIT = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = output->commit();
|
||||
@@ -916,28 +1429,26 @@ bool CMonitor::attemptDirectScanout() {
|
||||
ok = output->commit();
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (!ok) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface");
|
||||
lastScanout.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lastScanout.expired()) {
|
||||
lastScanout = PCANDIDATE;
|
||||
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
|
||||
}
|
||||
|
||||
// delay explicit sync feedback until kms release of the buffer
|
||||
if (DOEXPLICIT) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: Delaying explicit sync release feedback until kms release");
|
||||
PSURFACE->current.buffer->releaser->drop();
|
||||
scanoutNeedsCursorUpdate = false;
|
||||
|
||||
PSURFACE->current.buffer->buffer->hlEvents.backendRelease2 = PSURFACE->current.buffer->buffer->events.backendRelease.registerListener([PSURFACE](std::any d) {
|
||||
const bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.releaseTimeline && PSURFACE->syncobj->current.releaseTimeline->timeline;
|
||||
if (DOEXPLICIT)
|
||||
PSURFACE->syncobj->current.releaseTimeline->timeline->signal(PSURFACE->syncobj->current.releasePoint);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface");
|
||||
lastScanout.reset();
|
||||
return false;
|
||||
}
|
||||
if (!PBUFFER->lockedByBackend || PBUFFER->hlEvents.backendRelease)
|
||||
return true;
|
||||
|
||||
// lock buffer while DRM/KMS is using it, then release it when page flip happens since DRM/KMS should be done by then
|
||||
// btw buffer's syncReleaser will take care of signaling release point, so we don't do that here
|
||||
PBUFFER->lock();
|
||||
PBUFFER->onBackendRelease([PBUFFER]() { PBUFFER->unlock(); });
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1010,11 +1521,25 @@ void CMonitor::onMonitorFrame() {
|
||||
g_pHyprRenderer->renderMonitor(self.lock());
|
||||
}
|
||||
|
||||
CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) {
|
||||
;
|
||||
void CMonitor::onCursorMovedOnMonitor() {
|
||||
if (!tearingState.activelyTearing || !solitaryClient || !g_pHyprRenderer->shouldRenderCursor())
|
||||
return;
|
||||
|
||||
// submit a frame immediately. This will only update the cursor pos.
|
||||
// output->state->setBuffer(output->state->state().buffer);
|
||||
// output->state->addDamage(CRegion{});
|
||||
// output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE);
|
||||
// if (!output->commit())
|
||||
// Debug::log(ERR, "onCursorMovedOnMonitor: tearing and wanted to update cursor, failed.");
|
||||
|
||||
// FIXME: try to do the above. We currently can't just render because drm is a fucking bitch
|
||||
// and throws a "nO pRoP cAn Be ChAnGeD dUrInG AsYnC fLiP" on crtc_x
|
||||
// this will throw too but fix it if we use sw cursors
|
||||
|
||||
tearingState.frameScheduledWhileBusy = true;
|
||||
}
|
||||
|
||||
CMonitorState::~CMonitorState() {
|
||||
CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) {
|
||||
;
|
||||
}
|
||||
|
||||
|
@@ -1,19 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include "../SharedDefs.hpp"
|
||||
#include "MiscFunctions.hpp"
|
||||
#include "WLClasses.hpp"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include <xf86drmMode.h>
|
||||
#include "Timer.hpp"
|
||||
#include "math/Math.hpp"
|
||||
#include <optional>
|
||||
#include "../protocols/types/ColorManagement.hpp"
|
||||
#include "signal/Signal.hpp"
|
||||
#include "DamageRing.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include <aquamarine/allocator/Swapchain.hpp>
|
||||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
|
||||
// Enum for the different types of auto directions, e.g. auto-left, auto-up.
|
||||
enum eAutoDirs : uint8_t {
|
||||
@@ -24,28 +28,41 @@ enum eAutoDirs : uint8_t {
|
||||
DIR_AUTO_RIGHT
|
||||
};
|
||||
|
||||
enum eCMType : uint8_t {
|
||||
CM_AUTO = 0, // subject to change. srgb for 8bpc, wide for 10bpc if supported
|
||||
CM_SRGB, // default, sRGB primaries
|
||||
CM_WIDE, // wide color gamut, BT2020 primaries
|
||||
CM_EDID, // primaries from edid (known to be inaccurate)
|
||||
CM_HDR, // wide color gamut and HDR PQ transfer function
|
||||
CM_HDR_EDID, // same as CM_HDR with edid primaries
|
||||
};
|
||||
|
||||
struct SMonitorRule {
|
||||
eAutoDirs autoDir = DIR_AUTO_NONE;
|
||||
std::string name = "";
|
||||
Vector2D resolution = Vector2D(1280, 720);
|
||||
Vector2D offset = Vector2D(0, 0);
|
||||
float scale = 1;
|
||||
float refreshRate = 60;
|
||||
float refreshRate = 60; // Hz
|
||||
bool disabled = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
std::string mirrorOf = "";
|
||||
bool enable10bit = false;
|
||||
eCMType cmType = CM_SRGB;
|
||||
float sdrSaturation = 1.0f; // SDR -> HDR
|
||||
float sdrBrightness = 1.0f; // SDR -> HDR
|
||||
drmModeModeInfo drmMode = {};
|
||||
std::optional<int> vrr;
|
||||
};
|
||||
|
||||
class CMonitor;
|
||||
class CSyncTimeline;
|
||||
class CEGLSync;
|
||||
|
||||
class CMonitorState {
|
||||
public:
|
||||
CMonitorState(CMonitor* owner);
|
||||
~CMonitorState();
|
||||
~CMonitorState() = default;
|
||||
|
||||
bool commit();
|
||||
bool test();
|
||||
@@ -89,10 +106,8 @@ class CMonitor {
|
||||
CDamageRing damage;
|
||||
|
||||
SP<Aquamarine::IOutput> output;
|
||||
float refreshRate = 60;
|
||||
int framesToSkip = 0;
|
||||
float refreshRate = 60; // Hz
|
||||
int forceFullFrames = 0;
|
||||
bool noFrameSchedule = false;
|
||||
bool scheduledRecalc = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
float xwaylandScale = 1.f;
|
||||
@@ -106,6 +121,9 @@ class CMonitor {
|
||||
bool dpmsStatus = true;
|
||||
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
eCMType cmType = CM_SRGB;
|
||||
float sdrSaturation = 1.0f;
|
||||
float sdrBrightness = 1.0f;
|
||||
bool createdByUser = false;
|
||||
bool isUnsafeFallback = false;
|
||||
|
||||
@@ -122,8 +140,9 @@ class CMonitor {
|
||||
|
||||
// explicit sync
|
||||
SP<CSyncTimeline> inTimeline;
|
||||
SP<CSyncTimeline> outTimeline;
|
||||
uint64_t commitSeq = 0;
|
||||
Hyprutils::OS::CFileDescriptor inFence;
|
||||
SP<CEGLSync> eglSync;
|
||||
uint64_t inTimelinePoint = 0;
|
||||
|
||||
PHLMONITORREF self;
|
||||
|
||||
@@ -140,6 +159,7 @@ class CMonitor {
|
||||
|
||||
// for direct scanout
|
||||
PHLWINDOWREF lastScanout;
|
||||
bool scanoutNeedsCursorUpdate = false;
|
||||
|
||||
struct {
|
||||
bool canTear = false;
|
||||
@@ -163,9 +183,10 @@ class CMonitor {
|
||||
// methods
|
||||
void onConnect(bool noRule);
|
||||
void onDisconnect(bool destroy = false);
|
||||
bool applyMonitorRule(SMonitorRule* pMonitorRule, bool force = false);
|
||||
void addDamage(const pixman_region32_t* rg);
|
||||
void addDamage(const CRegion* rg);
|
||||
void addDamage(const CBox* box);
|
||||
void addDamage(const CRegion& rg);
|
||||
void addDamage(const CBox& box);
|
||||
bool shouldSkipScheduleFrameOnMouseEvent();
|
||||
void setMirror(const std::string&);
|
||||
bool isMirror();
|
||||
@@ -184,12 +205,15 @@ class CMonitor {
|
||||
void scheduleDone();
|
||||
bool attemptDirectScanout();
|
||||
void setCTM(const Mat3x3& ctm);
|
||||
void onCursorMovedOnMonitor();
|
||||
|
||||
void debugLastPresentation(const std::string& message);
|
||||
void onMonitorFrame();
|
||||
|
||||
bool m_bEnabled = false;
|
||||
bool m_bRenderingInitPassed = false;
|
||||
WP<CWindow> m_previousFSWindow;
|
||||
NColorManagement::SImageDescription imageDescription;
|
||||
|
||||
// For the list lookup
|
||||
|
||||
@@ -197,11 +221,16 @@ class CMonitor {
|
||||
return vecPosition == rhs.vecPosition && vecSize == rhs.vecSize && szName == rhs.szName;
|
||||
}
|
||||
|
||||
// workspace previous per monitor functionality
|
||||
SWorkspaceIDName getPrevWorkspaceIDName(const WORKSPACEID id);
|
||||
void addPrevWorkspaceID(const WORKSPACEID id);
|
||||
|
||||
private:
|
||||
void setupDefaultWS(const SMonitorRule&);
|
||||
WORKSPACEID findAvailableDefaultWS();
|
||||
|
||||
bool doneScheduled = false;
|
||||
std::stack<WORKSPACEID> prevWorkSpaces;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener frame;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#include "SdDaemon.hpp"
|
||||
#include "memory/Memory.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <cerrno>
|
||||
|
@@ -58,7 +58,7 @@ namespace NSplashes {
|
||||
"Thanks ThatOneCalculator!",
|
||||
"The AUR packages always work, except for the times they don't.",
|
||||
"Funny animation compositor woo",
|
||||
"2 years!",
|
||||
"3 years!",
|
||||
// music reference / quote section
|
||||
"J'remue le ciel, le jour, la nuit.",
|
||||
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
|
||||
|
@@ -1,14 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "../events/Events.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../desktop/Window.hpp"
|
||||
#include "../desktop/Subsurface.hpp"
|
||||
#include "../desktop/Popup.hpp"
|
||||
#include "AnimatedVariable.hpp"
|
||||
#include "../desktop/WLSurface.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include "../desktop/DesktopTypes.hpp"
|
||||
#include "memory/Memory.hpp"
|
||||
#include "signal/Signal.hpp"
|
||||
#include "math/Math.hpp"
|
||||
|
||||
class CMonitor;
|
||||
class IPointer;
|
||||
@@ -17,47 +16,6 @@ class CWLSurfaceResource;
|
||||
|
||||
AQUAMARINE_FORWARD(ISwitch);
|
||||
|
||||
struct SRenderData {
|
||||
PHLMONITORREF pMonitor;
|
||||
timespec* when;
|
||||
double x, y;
|
||||
|
||||
// for iters
|
||||
void* data = nullptr;
|
||||
SP<CWLSurfaceResource> surface = nullptr;
|
||||
double w, h;
|
||||
|
||||
// for rounding
|
||||
bool dontRound = true;
|
||||
|
||||
// for fade
|
||||
float fadeAlpha = 1.f;
|
||||
|
||||
// for alpha settings
|
||||
float alpha = 1.f;
|
||||
|
||||
// for decorations (border)
|
||||
bool decorate = false;
|
||||
|
||||
// for custom round values
|
||||
int rounding = -1; // -1 means not set
|
||||
|
||||
// for blurring
|
||||
bool blur = false;
|
||||
bool blockBlurOptimization = false;
|
||||
|
||||
// only for windows, not popups
|
||||
bool squishOversized = true;
|
||||
|
||||
// for calculating UV
|
||||
PHLWINDOW pWindow;
|
||||
|
||||
bool popup = false;
|
||||
|
||||
// counts how many surfaces this pass has rendered
|
||||
int surfaceCounter = 0;
|
||||
};
|
||||
|
||||
struct SSwipeGesture {
|
||||
PHLWORKSPACE pWorkspaceBegin = nullptr;
|
||||
|
||||
|
@@ -14,7 +14,7 @@ CWatchdog::~CWatchdog() {
|
||||
|
||||
CWatchdog::CWatchdog() : m_iMainThreadPID(pthread_self()) {
|
||||
|
||||
m_pWatchdog = std::make_unique<std::thread>([this] {
|
||||
m_pWatchdog = makeUnique<std::thread>([this] {
|
||||
static auto PTIMEOUT = CConfigValue<Hyprlang::INT>("debug:watchdog_timeout");
|
||||
|
||||
m_bWatchdogInitialized = true;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "memory/Memory.hpp"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
@@ -24,11 +24,11 @@ class CWatchdog {
|
||||
std::atomic<bool> m_bWatching = false;
|
||||
std::atomic<bool> m_bWillWatch = false;
|
||||
|
||||
std::unique_ptr<std::thread> m_pWatchdog;
|
||||
UP<std::thread> m_pWatchdog;
|
||||
std::mutex m_mWatchdogMutex;
|
||||
std::atomic<bool> m_bNotified = false;
|
||||
std::atomic<bool> m_bExitThread = false;
|
||||
std::condition_variable m_cvWatchdogCondition;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CWatchdog> g_pWatchdog;
|
||||
inline UP<CWatchdog> g_pWatchdog;
|
107
src/helpers/fs/FsUtils.cpp
Normal file
107
src/helpers/fs/FsUtils.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include "FsUtils.hpp"
|
||||
#include "../../debug/Log.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/string/VarList.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
std::optional<std::string> NFsUtils::getDataHome() {
|
||||
const auto DATA_HOME = getenv("XDG_DATA_HOME");
|
||||
|
||||
std::string dataRoot;
|
||||
|
||||
if (!DATA_HOME) {
|
||||
const auto HOME = getenv("HOME");
|
||||
|
||||
if (!HOME) {
|
||||
Debug::log(ERR, "FsUtils::getDataHome: can't get data home: no $HOME or $XDG_DATA_HOME");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
dataRoot = HOME + std::string{"/.local/share/"};
|
||||
} else
|
||||
dataRoot = DATA_HOME + std::string{"/"};
|
||||
|
||||
std::error_code ec;
|
||||
if (!std::filesystem::exists(dataRoot, ec) || ec) {
|
||||
Debug::log(ERR, "FsUtils::getDataHome: can't get data home: inaccessible / missing");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
dataRoot += "hyprland/";
|
||||
|
||||
if (!std::filesystem::exists(dataRoot, ec) || ec) {
|
||||
Debug::log(LOG, "FsUtils::getDataHome: no hyprland data home, creating.");
|
||||
std::filesystem::create_directory(dataRoot, ec);
|
||||
if (ec) {
|
||||
Debug::log(ERR, "FsUtils::getDataHome: can't create new data home for hyprland");
|
||||
return std::nullopt;
|
||||
}
|
||||
std::filesystem::permissions(dataRoot, std::filesystem::perms::owner_read | std::filesystem::perms::owner_write | std::filesystem::perms::owner_exec, ec);
|
||||
if (ec)
|
||||
Debug::log(WARN, "FsUtils::getDataHome: couldn't set perms on hyprland data store. Proceeding anyways.");
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(dataRoot, ec) || ec) {
|
||||
Debug::log(ERR, "FsUtils::getDataHome: no hyprland data home, failed to create.");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return dataRoot;
|
||||
}
|
||||
|
||||
std::optional<std::string> NFsUtils::readFileAsString(const std::string& path) {
|
||||
std::error_code ec;
|
||||
|
||||
if (!std::filesystem::exists(path, ec) || ec)
|
||||
return std::nullopt;
|
||||
|
||||
std::ifstream file(path);
|
||||
if (!file.good())
|
||||
return std::nullopt;
|
||||
|
||||
return trim(std::string((std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>())));
|
||||
}
|
||||
|
||||
bool NFsUtils::writeToFile(const std::string& path, const std::string& content) {
|
||||
std::ofstream of(path, std::ios::trunc);
|
||||
if (!of.good()) {
|
||||
Debug::log(ERR, "CVersionKeeperManager: couldn't open an ofstream for writing the version file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
of << content;
|
||||
of.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NFsUtils::executableExistsInPath(const std::string& exe) {
|
||||
if (!getenv("PATH"))
|
||||
return false;
|
||||
|
||||
static CVarList paths(getenv("PATH"), 0, ':', true);
|
||||
|
||||
for (auto& p : paths) {
|
||||
std::string path = p + std::string{"/"} + exe;
|
||||
std::error_code ec;
|
||||
if (!std::filesystem::exists(path, ec) || ec)
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::is_regular_file(path, ec) || ec)
|
||||
continue;
|
||||
|
||||
auto stat = std::filesystem::status(path, ec);
|
||||
if (ec)
|
||||
continue;
|
||||
|
||||
auto perms = stat.permissions();
|
||||
|
||||
return std::filesystem::perms::none != (perms & std::filesystem::perms::others_exec);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
15
src/helpers/fs/FsUtils.hpp
Normal file
15
src/helpers/fs/FsUtils.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace NFsUtils {
|
||||
// Returns the path to the hyprland directory in data home.
|
||||
std::optional<std::string> getDataHome();
|
||||
|
||||
std::optional<std::string> readFileAsString(const std::string& path);
|
||||
|
||||
// overwrites the file if exists
|
||||
bool writeToFile(const std::string& path, const std::string& content);
|
||||
|
||||
bool executableExistsInPath(const std::string& exe);
|
||||
};
|
@@ -7,4 +7,4 @@ using namespace Hyprutils::Memory;
|
||||
|
||||
#define SP Hyprutils::Memory::CSharedPointer
|
||||
#define WP Hyprutils::Memory::CWeakPointer
|
||||
#define UP std::unique_ptr
|
||||
#define UP Hyprutils::Memory::CUniquePointer
|
||||
|
@@ -1,25 +1,65 @@
|
||||
#include "SyncReleaser.hpp"
|
||||
#include "SyncTimeline.hpp"
|
||||
#include "../../render/OpenGL.hpp"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
CSyncReleaser::CSyncReleaser(WP<CSyncTimeline> timeline_, uint64_t point_) : timeline(timeline_), point(point_) {
|
||||
#if defined(__linux__)
|
||||
#include <linux/sync_file.h>
|
||||
#else
|
||||
struct sync_merge_data {
|
||||
char name[32];
|
||||
__s32 fd2;
|
||||
__s32 fence;
|
||||
__u32 flags;
|
||||
__u32 pad;
|
||||
};
|
||||
#define SYNC_IOC_MAGIC '>'
|
||||
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
|
||||
#endif
|
||||
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
CSyncReleaser::CSyncReleaser(SP<CSyncTimeline> timeline, uint64_t point) : m_timeline(timeline), m_point(point) {
|
||||
;
|
||||
}
|
||||
|
||||
CSyncReleaser::~CSyncReleaser() {
|
||||
if (timeline.expired())
|
||||
if (!m_timeline) {
|
||||
Debug::log(ERR, "CSyncReleaser destructing without a timeline");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sync)
|
||||
timeline->importFromSyncFileFD(point, sync->fd());
|
||||
if (m_fd.isValid())
|
||||
m_timeline->importFromSyncFileFD(m_point, m_fd);
|
||||
else
|
||||
timeline->signal(point);
|
||||
m_timeline->signal(m_point);
|
||||
}
|
||||
|
||||
void CSyncReleaser::addReleaseSync(SP<CEGLSync> sync_) {
|
||||
sync = sync_;
|
||||
CFileDescriptor CSyncReleaser::mergeSyncFds(const CFileDescriptor& fd1, const CFileDescriptor& fd2) {
|
||||
struct sync_merge_data data{
|
||||
.name = "merged release fence",
|
||||
.fd2 = fd2.get(),
|
||||
.fence = -1,
|
||||
};
|
||||
int err = -1;
|
||||
do {
|
||||
err = ioctl(fd1.get(), SYNC_IOC_MERGE, &data);
|
||||
} while (err == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
if (err < 0)
|
||||
return CFileDescriptor{};
|
||||
else
|
||||
return CFileDescriptor(data.fence);
|
||||
}
|
||||
|
||||
void CSyncReleaser::addReleaseSync(SP<CEGLSync> sync) {
|
||||
if (m_fd.isValid())
|
||||
m_fd = mergeSyncFds(m_fd, sync->takeFD());
|
||||
else
|
||||
m_fd = sync->fd().duplicate();
|
||||
|
||||
m_sync = sync;
|
||||
}
|
||||
|
||||
void CSyncReleaser::drop() {
|
||||
timeline.reset();
|
||||
m_timeline.reset();
|
||||
}
|
@@ -4,6 +4,7 @@
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
#include "../memory/Memory.hpp"
|
||||
|
||||
/*
|
||||
@@ -15,17 +16,19 @@ class CEGLSync;
|
||||
|
||||
class CSyncReleaser {
|
||||
public:
|
||||
CSyncReleaser(WP<CSyncTimeline> timeline_, uint64_t point_);
|
||||
CSyncReleaser(SP<CSyncTimeline> timeline, uint64_t point);
|
||||
~CSyncReleaser();
|
||||
|
||||
// drops the releaser, will never signal anymore
|
||||
void drop();
|
||||
|
||||
// wait for this gpu job to finish before releasing
|
||||
Hyprutils::OS::CFileDescriptor mergeSyncFds(const Hyprutils::OS::CFileDescriptor& fd1, const Hyprutils::OS::CFileDescriptor& fd2);
|
||||
void addReleaseSync(SP<CEGLSync> sync);
|
||||
|
||||
private:
|
||||
WP<CSyncTimeline> timeline;
|
||||
uint64_t point = 0;
|
||||
SP<CEGLSync> sync;
|
||||
SP<CSyncTimeline> m_timeline;
|
||||
uint64_t m_point = 0;
|
||||
Hyprutils::OS::CFileDescriptor m_fd;
|
||||
SP<CEGLSync> m_sync;
|
||||
};
|
||||
|
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <xf86drm.h>
|
||||
#include <sys/eventfd.h>
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
|
||||
auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
|
||||
@@ -18,12 +19,13 @@ SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, int drmSyncobjFD) {
|
||||
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, CFileDescriptor&& drmSyncobjFD) {
|
||||
auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
|
||||
timeline->drmFD = drmFD_;
|
||||
timeline->syncobjFd = std::move(drmSyncobjFD);
|
||||
timeline->self = timeline;
|
||||
|
||||
if (drmSyncobjFDToHandle(drmFD_, drmSyncobjFD, &timeline->handle)) {
|
||||
if (drmSyncobjFDToHandle(drmFD_, timeline->syncobjFd.get(), &timeline->handle)) {
|
||||
Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj from fd??");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -32,6 +34,13 @@ SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, int drmSyncobjFD) {
|
||||
}
|
||||
|
||||
CSyncTimeline::~CSyncTimeline() {
|
||||
for (auto& w : waiters) {
|
||||
if (w->source) {
|
||||
wl_event_source_remove(w->source);
|
||||
w->source = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
@@ -85,10 +94,9 @@ bool CSyncTimeline::addWaiter(const std::function<void()>& waiter, uint64_t poin
|
||||
auto w = makeShared<SWaiter>();
|
||||
w->fn = waiter;
|
||||
w->timeline = self;
|
||||
w->eventFd = CFileDescriptor{eventfd(0, EFD_CLOEXEC)};
|
||||
|
||||
int eventFD = eventfd(0, EFD_CLOEXEC);
|
||||
|
||||
if (eventFD < 0) {
|
||||
if (!w->eventFd.isValid()) {
|
||||
Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd");
|
||||
return false;
|
||||
}
|
||||
@@ -97,19 +105,17 @@ bool CSyncTimeline::addWaiter(const std::function<void()>& waiter, uint64_t poin
|
||||
.handle = handle,
|
||||
.flags = flags,
|
||||
.point = point,
|
||||
.fd = eventFD,
|
||||
.fd = w->eventFd.get(),
|
||||
};
|
||||
|
||||
if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) {
|
||||
Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed");
|
||||
close(eventFD);
|
||||
return false;
|
||||
}
|
||||
|
||||
w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get());
|
||||
w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, w->eventFd.get(), WL_EVENT_READABLE, ::handleWaiterFD, w.get());
|
||||
if (!w->source) {
|
||||
Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed");
|
||||
close(eventFD);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,32 +132,43 @@ void CSyncTimeline::removeWaiter(SWaiter* w) {
|
||||
std::erase_if(waiters, [w](const auto& e) { return e.get() == w; });
|
||||
}
|
||||
|
||||
int CSyncTimeline::exportAsSyncFileFD(uint64_t src) {
|
||||
void CSyncTimeline::removeAllWaiters() {
|
||||
for (auto& w : waiters) {
|
||||
if (w->source) {
|
||||
wl_event_source_remove(w->source);
|
||||
w->source = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
waiters.clear();
|
||||
}
|
||||
|
||||
CFileDescriptor CSyncTimeline::exportAsSyncFileFD(uint64_t src) {
|
||||
int sync = -1;
|
||||
|
||||
uint32_t syncHandle = 0;
|
||||
if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
|
||||
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed");
|
||||
return -1;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) {
|
||||
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed");
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return -1;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) {
|
||||
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed");
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return -1;
|
||||
return {};
|
||||
}
|
||||
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return sync;
|
||||
return CFileDescriptor{sync};
|
||||
}
|
||||
|
||||
bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) {
|
||||
bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, CFileDescriptor& fd) {
|
||||
uint32_t syncHandle = 0;
|
||||
|
||||
if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
|
||||
@@ -159,7 +176,7 @@ bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) {
|
||||
if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd.get())) {
|
||||
Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed");
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return false;
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
#include "../memory/Memory.hpp"
|
||||
|
||||
/*
|
||||
@@ -16,13 +17,14 @@ struct wl_event_source;
|
||||
class CSyncTimeline {
|
||||
public:
|
||||
static SP<CSyncTimeline> create(int drmFD_);
|
||||
static SP<CSyncTimeline> create(int drmFD_, int drmSyncobjFD);
|
||||
static SP<CSyncTimeline> create(int drmFD_, Hyprutils::OS::CFileDescriptor&& drmSyncobjFD);
|
||||
~CSyncTimeline();
|
||||
|
||||
struct SWaiter {
|
||||
std::function<void()> fn;
|
||||
wl_event_source* source = nullptr;
|
||||
WP<CSyncTimeline> timeline;
|
||||
Hyprutils::OS::CFileDescriptor eventFd;
|
||||
};
|
||||
|
||||
// check if the timeline point has been signaled
|
||||
@@ -32,12 +34,14 @@ class CSyncTimeline {
|
||||
|
||||
bool addWaiter(const std::function<void()>& waiter, uint64_t point, uint32_t flags);
|
||||
void removeWaiter(SWaiter*);
|
||||
int exportAsSyncFileFD(uint64_t src);
|
||||
bool importFromSyncFileFD(uint64_t dst, int fd);
|
||||
void removeAllWaiters();
|
||||
Hyprutils::OS::CFileDescriptor exportAsSyncFileFD(uint64_t src);
|
||||
bool importFromSyncFileFD(uint64_t dst, Hyprutils::OS::CFileDescriptor& fd);
|
||||
bool transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint);
|
||||
void signal(uint64_t point);
|
||||
|
||||
int drmFD = -1;
|
||||
Hyprutils::OS::CFileDescriptor syncobjFd;
|
||||
uint32_t handle = 0;
|
||||
WP<CSyncTimeline> self;
|
||||
|
||||
|
@@ -2,13 +2,16 @@
|
||||
#include "HyprError.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../render/pass/TexPassElement.hpp"
|
||||
#include "../managers/AnimationManager.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
#include "../managers/HookSystemManager.hpp"
|
||||
|
||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||
using namespace Hyprutils::Utils;
|
||||
using namespace Hyprutils::Animation;
|
||||
|
||||
CHyprError::CHyprError() {
|
||||
m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE);
|
||||
m_fFadeOpacity.registerVar();
|
||||
g_pAnimationManager->createAnimation(0.f, m_fFadeOpacity, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE);
|
||||
|
||||
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
|
||||
if (!m_bIsCreated)
|
||||
@@ -22,17 +25,13 @@ CHyprError::CHyprError() {
|
||||
if (!m_bIsCreated)
|
||||
return;
|
||||
|
||||
if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged)
|
||||
g_pHyprRenderer->damageBox(&m_bDamageBox);
|
||||
if (m_fFadeOpacity->isBeingAnimated() || m_bMonitorChanged)
|
||||
g_pHyprRenderer->damageBox(m_bDamageBox);
|
||||
});
|
||||
|
||||
m_pTexture = makeShared<CTexture>();
|
||||
}
|
||||
|
||||
CHyprError::~CHyprError() {
|
||||
m_fFadeOpacity.unregister();
|
||||
}
|
||||
|
||||
void CHyprError::queueCreate(std::string message, const CHyprColor& color) {
|
||||
m_szQueued = message;
|
||||
m_cQueued = color;
|
||||
@@ -42,10 +41,10 @@ void CHyprError::createQueued() {
|
||||
if (m_bIsCreated)
|
||||
m_pTexture->destroyTexture();
|
||||
|
||||
m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
|
||||
m_fFadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
|
||||
|
||||
m_fFadeOpacity.setValueAndWarp(0.f);
|
||||
m_fFadeOpacity = 1.f;
|
||||
m_fFadeOpacity->setValueAndWarp(0.f);
|
||||
*m_fFadeOpacity = 1.f;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->m_vMonitors.front();
|
||||
|
||||
@@ -175,8 +174,8 @@ void CHyprError::draw() {
|
||||
}
|
||||
|
||||
if (m_bQueuedDestroy) {
|
||||
if (!m_fFadeOpacity.isBeingAnimated()) {
|
||||
if (m_fFadeOpacity.value() == 0.f) {
|
||||
if (!m_fFadeOpacity->isBeingAnimated()) {
|
||||
if (m_fFadeOpacity->value() == 0.f) {
|
||||
m_bQueuedDestroy = false;
|
||||
m_pTexture->destroyTexture();
|
||||
m_bIsCreated = false;
|
||||
@@ -188,8 +187,8 @@ void CHyprError::draw() {
|
||||
|
||||
return;
|
||||
} else {
|
||||
m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut"));
|
||||
m_fFadeOpacity = 0.f;
|
||||
m_fFadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut"));
|
||||
*m_fFadeOpacity = 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,12 +200,17 @@ void CHyprError::draw() {
|
||||
m_bDamageBox.x = (int)PMONITOR->vecPosition.x;
|
||||
m_bDamageBox.y = (int)PMONITOR->vecPosition.y;
|
||||
|
||||
if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged)
|
||||
g_pHyprRenderer->damageBox(&m_bDamageBox);
|
||||
if (m_fFadeOpacity->isBeingAnimated() || m_bMonitorChanged)
|
||||
g_pHyprRenderer->damageBox(m_bDamageBox);
|
||||
|
||||
m_bMonitorChanged = false;
|
||||
|
||||
g_pHyprOpenGL->renderTexture(m_pTexture, &monbox, m_fFadeOpacity.value(), 0);
|
||||
CTexPassElement::SRenderData data;
|
||||
data.tex = m_pTexture;
|
||||
data.box = monbox;
|
||||
data.a = m_fFadeOpacity->value();
|
||||
|
||||
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
|
||||
}
|
||||
|
||||
void CHyprError::destroy() {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user