Compare commits

..

14 Commits

Author SHA1 Message Date
Vaxry
75dff7205f version: bump to 0.47.1 2025-01-29 23:19:39 +00:00
Vaxry
48817b97f5 subsurface: fix invalid parent typo
fixes #9224
2025-01-29 23:19:20 +00:00
Vaxry
664da71d10 popup: stop refocusing at unmap
fixes #9018
2025-01-29 23:19:20 +00:00
Vaxry
a285722bc8 monitor: round refresh rates in sorting modes
fixes #9209
2025-01-29 23:19:20 +00:00
vaxerski
bdee557d15 config/hyprctl: fix keyword not updating autoreload
ref #9139
2025-01-29 23:19:20 +00:00
vaxerski
901271fa8b pass/rect: fix bounding / opaque regions
fixes #9212
2025-01-29 23:19:20 +00:00
nyx
fa61042288 renderer: calculate UV using both pixel and monitor dimensions (#9210) 2025-01-29 23:19:20 +00:00
Vaxry
778508e39e presentation: log a fixme when there is a feedback leak
ref #8087
2025-01-29 23:19:20 +00:00
Tom Englund
762bbf5857 configmgr: properly free glob memory
globfree is only freeing internally allocated resources, so also call
free the on glob_t memory we allocated.
2025-01-29 23:19:20 +00:00
Tom Englund
c68653d7c4 ikeyboard: free xkbSymState in clearManuallyAllocd
asan reported a leak on xkbSymState on destruction, because it wasnt
beeing unrefed, was only being unrefed on calls to updateXKBTranslationState.
2025-01-29 23:19:20 +00:00
DDoSolitary
56540f5bd8 xwayland: respect window size set by configure requests (#9190) 2025-01-29 23:19:20 +00:00
Jan Beich
017f322532 deps: add libinotify-kqueue on BSDs after 8dd2cd41fb (#9197)
src/config/ConfigWatcher.cpp:2:10: fatal error: 'sys/inotify.h' file not found
    2 | #include <sys/inotify.h>
      |          ^~~~~~~~~~~~~~~
2025-01-29 23:19:20 +00:00
DDoSolitary
a7d7df5c4b xwayland: send synthetic configure events (#9193) 2025-01-29 23:19:20 +00:00
Vaxry
0d06f287d0 core: fix clang-format 2025-01-29 23:19:20 +00:00
406 changed files with 18797 additions and 25646 deletions

View File

@@ -1,15 +1,117 @@
name: Do not open issues, go to discussions please! name: Bug Report
description: Do not open an issue description: Something is not working right
labels: ["bug"]
body: body:
- type: checkboxes - type: checkboxes
attributes: attributes:
label: Please close this issue. label: Already reported ? *
description: Users cannot open issues. I want my issue to be closed. description: Before opening a new bug report, please take a moment to search through the current open issues. If the same bug is already reported, don't open new issue - instead go upvote/comment on an existing one.
options: options:
- label: Yes, I want this issue to be closed. - label: I have searched the existing open and closed issues.
required: true required: true
- type: textarea - type: dropdown
id: body id: type
attributes: attributes:
label: Issue body label: Regression?
description: |
Regression means that something used to work but no longer does.
**BEFORE CONTINUING**, please check if this bug is a regression or not, and if it is, we need you to bisect with the help of the wiki: https://wiki.hyprland.org/Crashes-and-Bugs/#bisecting-an-issue
multiple: true
options:
- "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 Hyprland Version
description: |
Paste the output of `hyprctl systeminfo` here. If you can't
launch Hyprland, paste the output of `Hyprland --systeminfo`.
value: "<details>
<summary>System/Version info</summary>
```
<Paste the output of the command here, without removing any formatting around this>
```
</details>"
validations:
required: true
- type: textarea
id: desc
attributes:
label: Description
description: "What went wrong?"
validations:
required: true
- type: textarea
id: repro
attributes:
label: How to reproduce
description: "How can someone else reproduce the issue?"
placeholder: |
1. ...
2. ...
3. ...
validations:
required: true
- type: markdown
attributes:
value: |
## Additional info section
In the section below you will be asked to upload some files.
When including text files (such as logs or config), please **always ATTACH** them, and not paste them directly.
This is important to avoid clutter, spam, and make the issues more readable.
Thanks for your understanding.
# The main reason to disallow pasting directly or in a dropdown, is to not clutter
# the issue with unnecessary keywords, making the github issue search useless.
- type: checkboxes
attributes:
label: Attach not paste
options:
- label: I understand that all text files must be *attached*, and not pasted directly. If not respected, this issue will likely get closed as spam
required: true
- type: markdown
attributes:
value: >-
Please be sure to upload the following files below if they are relevant to the issue:
- Logs can be found in $XDG_RUNTIME_DIR/hypr (sort by date to grab the latest)
- Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland
- Hyprland config files - `hyprctl systeminfo -c > /tmp/hyprland_config_dump.txt` use this command to dump full configuration to a single file.
- type: checkboxes
attributes:
label: Checklist of files to include below
options:
- label: Hyprland config - `hyprctl systeminfo -c` (always include)
- label: Crash report (always include in case of crash)
- label: Video (always include in case of a visual bug)
- label: Logs (might contain useful info such as errors)
- type: textarea
id: logs
attributes:
label: Additional info & File uploads
description: |
Tip: You can attach files by clicking this area to highlight it and then dragging files in.

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

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

View File

@@ -20,7 +20,6 @@ runs:
clang \ clang \
cmake \ cmake \
git \ git \
glaze \
glm \ glm \
glslang \ glslang \
go \ go \
@@ -36,7 +35,6 @@ runs:
libinput \ libinput \
libjxl \ libjxl \
libliftoff \ libliftoff \
libspng \
libwebp \ libwebp \
libxcursor \ libxcursor \
libxcvt \ libxcvt \
@@ -65,6 +63,15 @@ runs:
librsvg \ librsvg \
re2 re2
- name: Get glaze
shell: bash
run: |
git clone https://github.com/stephenberry/glaze.git
cd glaze
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
cmake --install build
- name: Get hyprwayland-scanner-git - name: Get hyprwayland-scanner-git
shell: bash shell: bash
run: | run: |

View File

@@ -21,7 +21,7 @@ jobs:
- name: Build Hyprland - name: Build Hyprland
run: | run: |
CFLAGS=-Werror CXXFLAGS=-Werror make all make all
- name: Compress and package artifacts - name: Compress and package artifacts
run: | run: |
@@ -127,3 +127,27 @@ jobs:
- name: clang-format check - name: clang-format check
run: ninja -C build clang-format-check run: ninja -C build clang-format-check
- name: clang-format apply
if: ${{ failure() && github.event_name == 'pull_request' }}
run: ninja -C build clang-format
- name: Create patch
if: ${{ failure() && github.event_name == 'pull_request' }}
run: |
echo 'Please fix the formatting issues by running [`clang-format`](https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/#code-style), or directly apply this patch:' > clang-format.patch
echo '<details>' >> clang-format.patch
echo '<summary>clang-format.patch</summary>' >> clang-format.patch
echo >> clang-format.patch
echo '```diff' >> clang-format.patch
git diff >> clang-format.patch
echo '```' >> clang-format.patch
echo >> clang-format.patch
echo '</details>' >> clang-format.patch
- name: Comment patch
if: ${{ failure() && github.event_name == 'pull_request' }}
uses: mshick/add-pr-comment@v2
with:
message-path: |
clang-format.patch

View File

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

View File

@@ -1,101 +0,0 @@
name: Close Unauthorized Issues
on:
workflow_dispatch:
issues:
types: [opened]
jobs:
close-unauthorized-issues:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
# XXX: This *could* be done in Bash by abusing GitHub's own tool to interact with its API
# but that's too much of a hack, and we'll be adding a layer of abstraction. github-script
# is a workflow that eases interaction with GitHub API in the workflow run context.
- name: "Close 'unauthorized' issues"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const ALLOWED_USERS = ['vaxerski', 'fufexan', 'NotAShelf'];
const CLOSING_COMMENT = 'Users are no longer allowed to open issues themselves, please open a discussion instead.\n\nPlease see the [wiki](https://wiki.hyprland.org/Contributing-and-Debugging/Issue-Guidelines/) on why this is the case.\n\nWe are volunteers, and we need your cooperation to make the best software we can. Thank you for understanding! ❤️\n\n[Open a discussion here](https://github.com/hyprwm/Hyprland/discussions)';
async function closeUnauthorizedIssue(issueNumber, userName) {
if (ALLOWED_USERS.includes(userName)) {
console.log(`Issue #${issueNumber} - Created by authorized user ${userName}`);
return;
}
console.log(`Issue #${issueNumber} - Unauthorized, closing`);
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
state: 'closed',
state_reason: 'not_planned'
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: CLOSING_COMMENT
});
}
if (context.eventName === 'issues' && context.payload.action === 'opened') {
// Direct access to the issue that triggered the workflow
const issue = context.payload.issue;
// Skip if this is a PR
if (issue.pull_request) {
console.log(`Issue #${issue.number} - Skipping, this is a pull request`);
return;
}
// Process the single issue that triggered the workflow
await closeUnauthorizedIssue(issue.number, issue.user.login);
} else {
// For manual runs, we need to handle pagination
async function* fetchAllOpenIssues() {
let page = 1;
let hasNextPage = true;
while (hasNextPage) {
const response = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100,
page: page
});
if (response.data.length === 0) {
hasNextPage = false;
} else {
for (const issue of response.data) {
yield issue;
}
page++;
}
}
}
// Process issues one by one
for await (const issue of fetchAllOpenIssues()) {
try {
// Skip pull requests
if (issue.pull_request) {
console.log(`Issue #${issue.number} - Skipping, this is a pull request`);
continue;
}
await closeUnauthorizedIssue(issue.number, issue.user.login);
} catch (error) {
console.error(`Error processing issue #${issue.number}: ${error.message}`);
}
}
}

View File

@@ -19,6 +19,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v15 - uses: cachix/cachix-action@v15
with: with:

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

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

2
.gitignore vendored
View File

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

View File

@@ -25,9 +25,6 @@ message(STATUS "Gathering git info")
# Get git info hash and branch # Get git info hash and branch
execute_process(COMMAND ./scripts/generateVersion.sh execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# Make shader files includable
execute_process(COMMAND ./scripts/generateShaderIncludes.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
@@ -80,7 +77,6 @@ add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}")
include_directories(. "src/" "protocols/") include_directories(. "src/" "protocols/")
set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD 26)
set(CXX_STANDARD_REQUIRED ON)
add_compile_options( add_compile_options(
-Wall -Wall
-Wextra -Wextra
@@ -89,7 +85,6 @@ add_compile_options(
-Wno-missing-field-initializers -Wno-missing-field-initializers
-Wno-narrowing -Wno-narrowing
-Wno-pointer-arith -Wno-pointer-arith
-Wno-clobbered
-fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=)
set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE) set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
@@ -106,21 +101,13 @@ else()
endif() endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.8.0) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5)
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) 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(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7)
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.7.0) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.4.0)
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.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="${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(HYPRLANG_VERSION="${hyprlang_dep_VERSION}")
add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}") add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}")
add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}") add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}")
@@ -133,7 +120,7 @@ pkg_check_modules(
xkbcommon xkbcommon
uuid uuid
wayland-server>=1.22.90 wayland-server>=1.22.90
wayland-protocols>=1.43 wayland-protocols
cairo cairo
pango pango
pangocairo pangocairo
@@ -317,7 +304,7 @@ endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4) pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.0)
if(hyprland_protocols_dep_FOUND) if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
@@ -349,7 +336,6 @@ protocolnew("protocols" "wayland-drm" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-mapping-v1" true)
protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/tearing-control" "tearing-control-v1" false)
protocolnew("staging/fractional-scale" "fractional-scale-v1" false) protocolnew("staging/fractional-scale" "fractional-scale-v1" false)
@@ -382,10 +368,6 @@ protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false) protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
protocolnew("staging/security-context" "security-context-v1" false) protocolnew("staging/security-context" "security-context-v1" false)
protocolnew("staging/content-type" "content-type-v1" false)
protocolnew("staging/color-management" "color-management-v1" false)
protocolnew("staging/xdg-toplevel-tag" "xdg-toplevel-tag-v1" false)
protocolnew("staging/xdg-system-bell" "xdg-system-bell-v1" false)
protocolwayland() protocolwayland()
@@ -451,7 +433,4 @@ install(
DIRECTORY ${HEADERS_SRC} DIRECTORY ${HEADERS_SRC}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING FILES_MATCHING
PATTERN "*.h" PATTERN "*.h*")
PATTERN "*.hpp"
PATTERN "*.inc"
)

View File

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

View File

@@ -1,32 +0,0 @@
# Hyprland Development Security Policy
If you have a bug that affects the security of your system, you may
want to privately disclose it instead of making it immediately public.
## Supported versions
_Only_ the most recent release on Github is supported. There are no LTS releases.
## What is not a security issue
Some examples of issues that should not be reported as security issues:
- An app can execute a command when ran outside of a sandbox
- An app can write / read hyprland sockets when ran outside of a sandbox
- Crashes
- Things that are protected via permissions when the permission system is disabled
## What is a security issue
Some examples of issues that should be reported as security issues:
- Sandboxed application executing arbitrary code via Hyprland
- Application being able to modify Hyprland's code on the fly
- Application being able to keylog / track user's activity beyond what the wayland protocols allow
## How to report security issues
Please report your security issues via either of these channels:
- Mail: `vaxry [at] vaxry [dot] net`
- Matrix: `@vaxry:matrix.vaxry.net`
- Discord: `@vaxry`

View File

@@ -1 +1 @@
0.49.0 0.47.1

View File

@@ -52,23 +52,6 @@ env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24 env = HYPRCURSOR_SIZE,24
###################
### PERMISSIONS ###
###################
# See https://wiki.hyprland.org/Configuring/Permissions/
# Please note permission changes here require a Hyprland restart and are not applied on-the-fly
# for security reasons
# ecosystem {
# enforce_permissions = 1
# }
# permission = /usr/(bin|local/bin)/grim, screencopy, allow
# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow
##################### #####################
### LOOK AND FEEL ### ### LOOK AND FEEL ###
##################### #####################
@@ -156,10 +139,10 @@ animations {
# uncomment all if you wish to use that. # uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] # windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrule = rounding 0, floating:0, onworkspace:w[tv1] # windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrule = bordersize 0, floating:0, onworkspace:f[1] # windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrule = rounding 0, floating:0, onworkspace:f[1] # windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
@@ -277,8 +260,8 @@ bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+ bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%- bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl # Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next bindl = , XF86AudioNext, exec, playerctl next
@@ -293,11 +276,14 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules # See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule # Example windowrule v1
# windowrule = float,class:^(kitty)$,title:^(kitty)$ # windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.* windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland # Fix some dragging issues with XWayland
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0

137
flake.lock generated
View File

@@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1745357003, "lastModified": 1737636397,
"narHash": "sha256-jYwzQkv1r7HN/4qrAuKp+NR4YYNp2xDrOX5O9YVqkWo=", "narHash": "sha256-F5MbBj3QVorycVSFE9qjuOTLtIQBqt2VWbXa0uwzm98=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "a19cf76ee1a15c1c12083fa372747ce46387289f", "rev": "7fe006981fae53e931f513026fc754e322f13145",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -79,11 +79,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1745948457, "lastModified": 1737634937,
"narHash": "sha256-lzTV10FJTCGNtMdgW5YAhCAqezeAzKOd/97HbQK8GTU=", "narHash": "sha256-Ffw4ujFpi++6pPHe+gCBOfDgAoNlzVPZN6MReC1beu8=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "ac903e80b33ba6a88df83d02232483d99f327573", "rev": "9c5dd1f7c825ee47f72727ad0a4e16ca46a2688e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -105,11 +105,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1745015490, "lastModified": 1737634889,
"narHash": "sha256-apEJ9zoSzmslhJ2vOKFcXTMZLUFYzh1ghfB6Rbw3Low=", "narHash": "sha256-9JZE3KxcXOqZH9zs3UeadngDiK/yIACTiAR8HSA/TNI=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprgraphics", "repo": "hyprgraphics",
"rev": "60754910946b4e2dc1377b967b7156cb989c5873", "rev": "0d77b4895ad5f1bb3b0ee43103a5246c58b65591",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -128,11 +128,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1743714874, "lastModified": 1737556638,
"narHash": "sha256-yt8F7NhMFCFHUHy/lNjH/pjZyIDFNk52Q4tivQ31WFo=", "narHash": "sha256-laKgI3mr2qz6tas/q3tuGPxMdsGhBi/w+HO+hO2f1AY=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "3a5c2bda1c1a4e55cc1330c782547695a93f05b2", "rev": "4c75dd5c015c8a0e5a34c6d02a018a650f57feb5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -143,10 +143,7 @@
}, },
"hyprland-qt-support": { "hyprland-qt-support": {
"inputs": { "inputs": {
"hyprlang": [ "hyprlang": "hyprlang",
"hyprland-qtutils",
"hyprlang"
],
"nixpkgs": [ "nixpkgs": [
"hyprland-qtutils", "hyprland-qtutils",
"nixpkgs" "nixpkgs"
@@ -173,12 +170,7 @@
"hyprland-qtutils": { "hyprland-qtutils": {
"inputs": { "inputs": {
"hyprland-qt-support": "hyprland-qt-support", "hyprland-qt-support": "hyprland-qt-support",
"hyprlang": [
"hyprlang"
],
"hyprutils": [ "hyprutils": [
"hyprland-qtutils",
"hyprlang",
"hyprutils" "hyprutils"
], ],
"nixpkgs": [ "nixpkgs": [
@@ -189,11 +181,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1745951494, "lastModified": 1737811848,
"narHash": "sha256-2dModE32doiyQMmd6EDAQeZnz+5LOs6KXyE0qX76WIg=", "narHash": "sha256-WZ7LeiKHk5Y94MU5gHIWn0r8asWxYOvie4LqfCjVIZU=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-qtutils", "repo": "hyprland-qtutils",
"rev": "4be1d324faf8d6e82c2be9f8510d299984dfdd2e", "rev": "9c0831ff98856c0f312fcb8b57553fbe3dd34d5b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -203,6 +195,34 @@
} }
}, },
"hyprlang": { "hyprlang": {
"inputs": {
"hyprutils": "hyprutils",
"nixpkgs": [
"hyprland-qtutils",
"hyprland-qt-support",
"nixpkgs"
],
"systems": [
"hyprland-qtutils",
"hyprland-qt-support",
"systems"
]
},
"locked": {
"lastModified": 1737634606,
"narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "f41271d35cc0f370d300413d756c2677f386af9d",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprlang",
"type": "github"
}
},
"hyprlang_2": {
"inputs": { "inputs": {
"hyprutils": [ "hyprutils": [
"hyprutils" "hyprutils"
@@ -215,11 +235,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1746655412, "lastModified": 1737634606,
"narHash": "sha256-kVQ0bHVtX6baYxRWWIh4u3LNJZb9Zcm2xBeDPOGz5BY=", "narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "557241780c179cf7ef224df392f8e67dab6cef83", "rev": "f41271d35cc0f370d300413d756c2677f386af9d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -229,6 +249,35 @@
} }
}, },
"hyprutils": { "hyprutils": {
"inputs": {
"nixpkgs": [
"hyprland-qtutils",
"hyprland-qt-support",
"hyprlang",
"nixpkgs"
],
"systems": [
"hyprland-qtutils",
"hyprland-qt-support",
"hyprlang",
"systems"
]
},
"locked": {
"lastModified": 1737632363,
"narHash": "sha256-X9I8POSlHxBVjD0fiX1O2j7U9Zi1+4rIkrsyHP0uHXY=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "006620eb29d54ea9086538891404c78563d1bae1",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprutils",
"type": "github"
}
},
"hyprutils_2": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
@@ -238,11 +287,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1746635225, "lastModified": 1737725508,
"narHash": "sha256-W9G9bb0zRYDBRseHbVez0J8qVpD5QbizX67H/vsudhM=", "narHash": "sha256-jGmcPc6y/prg/4A8KGYqJ27nSPaProCMiFadaxNAKvA=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "674ea57373f08b7609ce93baff131117a0dfe70d", "rev": "fb0c2d1de3d1ef7396d19c18ac09e12bd956929e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -261,11 +310,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1739870480, "lastModified": 1735493474,
"narHash": "sha256-SiDN5BGxa/1hAsqhgJsS03C3t2QrLgBT8u+ENJ0Qzwc=", "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "206367a08dc5ac4ba7ad31bdca391d098082e64b", "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -276,11 +325,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1746461020, "lastModified": 1737632463,
"narHash": "sha256-7+pG1I9jvxNlmln4YgnlW4o+w0TZX24k688mibiFDUE=", "narHash": "sha256-38J9QfeGSej341ouwzqf77WIHAScihAKCt8PQJ+NH28=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "3730d8a308f94996a9ba7c7138ede69c1b9ac4ae", "rev": "0aa475546ed21629c4f5bbf90e38c846a99ec9e9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -299,11 +348,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1746537231, "lastModified": 1737465171,
"narHash": "sha256-Wb2xeSyOsCoTCTj7LOoD6cdKLEROyFAArnYoS+noCWo=", "narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=",
"owner": "cachix", "owner": "cachix",
"repo": "git-hooks.nix", "repo": "git-hooks.nix",
"rev": "fa466640195d38ec97cf0493d6d6882bc4d14969", "rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -319,8 +368,8 @@
"hyprgraphics": "hyprgraphics", "hyprgraphics": "hyprgraphics",
"hyprland-protocols": "hyprland-protocols", "hyprland-protocols": "hyprland-protocols",
"hyprland-qtutils": "hyprland-qtutils", "hyprland-qtutils": "hyprland-qtutils",
"hyprlang": "hyprlang", "hyprlang": "hyprlang_2",
"hyprutils": "hyprutils", "hyprutils": "hyprutils_2",
"hyprwayland-scanner": "hyprwayland-scanner", "hyprwayland-scanner": "hyprwayland-scanner",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks", "pre-commit-hooks": "pre-commit-hooks",
@@ -365,11 +414,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1745871725, "lastModified": 1737634991,
"narHash": "sha256-M24SNc2flblWGXFkGQfqSlEOzAGZnMc9QG3GH4K/KbE=", "narHash": "sha256-dBAnb7Kbnier30cA7AgxVSxxARmxKZ1vHZT33THSIr8=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "76bbf1a6b1378e4ab5230bad00ad04bc287c969e", "rev": "e09dfe2726c8008f983e45a0aa1a3b7416aaeb8a",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -39,7 +39,7 @@
url = "github:hyprwm/hyprland-qtutils"; url = "github:hyprwm/hyprland-qtutils";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
inputs.hyprlang.follows = "hyprlang"; inputs.hyprutils.follows = "hyprutils";
}; };
hyprlang = { hyprlang = {
@@ -157,11 +157,5 @@
nixosModules.default = import ./nix/module.nix inputs; nixosModules.default = import ./nix/module.nix inputs;
homeManagerModules.default = import ./nix/hm-module.nix self; homeManagerModules.default = import ./nix/hm-module.nix self;
# Hydra build jobs
# Recent versions of Hydra can aggregate jobsets from 'hydraJobs' intead of a release.nix
# or similar. Remember to filter large or incompatible attributes here. More eval jobs can
# be added by merging, e.g., self.packages // self.devShells.
hydraJobs = self.packages;
}; };
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,11 +9,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.7.0) pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4)
find_package(glaze QUIET) find_package(glaze QUIET)
if (NOT glaze_FOUND) if (NOT glaze_FOUND)
set(GLAZE_VERSION v5.1.1) set(GLAZE_VERSION v4.2.3)
message(STATUS "glaze dependency not found, retrieving ${GLAZE_VERSION} with FetchContent") message(STATUS "glaze dependency not found, retrieving ${GLAZE_VERSION} with FetchContent")
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(

View File

@@ -1,41 +1,22 @@
#include "DataState.hpp" #include "DataState.hpp"
#include <sys/stat.h>
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <print> #include <print>
#include <sstream>
#include <fstream> #include <fstream>
#include "PluginManager.hpp" #include "PluginManager.hpp"
#include "../helpers/Die.hpp"
#include "../helpers/Sys.hpp"
#include "../helpers/StringUtils.hpp"
static std::string getTempRoot() {
static auto ENV = getenv("XDG_RUNTIME_DIR");
if (!ENV) {
std::cerr << "\nERROR: XDG_RUNTIME_DIR not set!\n";
exit(1);
}
const auto STR = ENV + std::string{"/hyprpm/"};
return STR;
}
// write the state to a file
static bool writeState(const std::string& str, const std::string& to) {
// create temp file in a safe temp root
std::ofstream of(getTempRoot() + ".temp-state", std::ios::trunc);
if (!of.good())
return false;
of << str;
of.close();
return NSys::root::install(getTempRoot() + ".temp-state", to, "644");
}
std::filesystem::path DataState::getDataStatePath() { std::filesystem::path DataState::getDataStatePath() {
return std::filesystem::path("/var/cache/hyprpm/" + g_pPluginManager->m_szUsername); const auto HOME = getenv("HOME");
if (!HOME) {
std::println(stderr, "DataState: no $HOME");
throw std::runtime_error("no $HOME");
return "";
}
const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME");
if (XDG_DATA_HOME)
return std::filesystem::path{XDG_DATA_HOME} / "hyprpm";
return std::filesystem::path{HOME} / ".local/share/hyprpm";
} }
std::string DataState::getHeadersPath() { std::string DataState::getHeadersPath() {
@@ -60,32 +41,21 @@ std::vector<std::filesystem::path> DataState::getPluginStates() {
} }
void DataState::ensureStateStoreExists() { void DataState::ensureStateStoreExists() {
std::error_code ec; const auto PATH = getDataStatePath();
if (!std::filesystem::exists(getHeadersPath(), ec) || ec) {
std::println("{}", infoString("The hyprpm state store doesn't exist. Creating now...")); if (!std::filesystem::exists(PATH))
if (!std::filesystem::exists("/var/cache/hyprpm/", ec) || ec) { std::filesystem::create_directories(PATH);
if (!NSys::root::createDirectory("/var/cache/hyprpm", "755"))
Debug::die("ensureStateStoreExists: Failed to run a superuser cmd"); if (!std::filesystem::exists(getHeadersPath()))
} std::filesystem::create_directories(getHeadersPath());
if (!std::filesystem::exists(getDataStatePath(), ec) || ec) {
if (!NSys::root::createDirectory(getDataStatePath().string(), "755"))
Debug::die("ensureStateStoreExists: Failed to run a superuser cmd");
}
if (!NSys::root::createDirectory(getHeadersPath(), "755"))
Debug::die("ensureStateStoreExists: Failed to run a superuser cmd");
}
} }
void DataState::addNewPluginRepo(const SPluginRepository& repo) { void DataState::addNewPluginRepo(const SPluginRepository& repo) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath() / repo.name; const auto PATH = getDataStatePath() / repo.name;
std::error_code ec; std::filesystem::create_directories(PATH);
if (!std::filesystem::exists(PATH, ec) || ec) {
if (!NSys::root::createDirectory(PATH.string(), "755"))
Debug::die("addNewPluginRepo: failed to create cache dir");
}
// clang-format off // clang-format off
auto DATA = toml::table{ auto DATA = toml::table{
{"repository", toml::table{ {"repository", toml::table{
@@ -98,11 +68,9 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
for (auto const& p : repo.plugins) { for (auto const& p : repo.plugins) {
const auto filename = p.name + ".so"; const auto filename = p.name + ".so";
// copy .so to the good place and chmod 755 // copy .so to the good place
if (std::filesystem::exists(p.filename)) { if (std::filesystem::exists(p.filename))
if (!NSys::root::install(p.filename, (PATH / filename).string(), "0755")) std::filesystem::copy_file(p.filename, PATH / filename);
Debug::die("addNewPluginRepo: failed to install so file");
}
DATA.emplace(p.name, toml::table{ DATA.emplace(p.name, toml::table{
{"filename", filename}, {"filename", filename},
@@ -112,16 +80,16 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
} }
// clang-format on // clang-format on
std::stringstream ss; std::ofstream ofs(PATH / "state.toml", std::ios::trunc);
ss << DATA; ofs << DATA;
ofs.close();
if (!writeState(ss.str(), (PATH / "state.toml").string()))
Debug::die("{}", failureString("Failed to write plugin state"));
} }
bool DataState::pluginRepoExists(const std::string& urlOrName) { bool DataState::pluginRepoExists(const std::string& urlOrName) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
const auto NAME = STATE["repository"]["name"].value_or(""); const auto NAME = STATE["repository"]["name"].value_or("");
@@ -137,6 +105,8 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
void DataState::removePluginRepo(const std::string& urlOrName) { void DataState::removePluginRepo(const std::string& urlOrName) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
const auto NAME = STATE["repository"]["name"].value_or(""); const auto NAME = STATE["repository"]["name"].value_or("");
@@ -152,14 +122,7 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false); g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
} }
const auto PATH = stateFile.parent_path().string(); std::filesystem::remove_all(stateFile.parent_path());
if (!PATH.starts_with("/var/cache/hyprpm") || PATH.contains('\''))
return; // WTF?
// scary!
if (!NSys::root::removeRecursive(PATH))
Debug::die("removePluginRepo: failed to remove dir");
return; return;
} }
} }
@@ -168,13 +131,9 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
void DataState::updateGlobalState(const SGlobalState& state) { void DataState::updateGlobalState(const SGlobalState& state) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
std::error_code ec; std::filesystem::create_directories(PATH);
if (!std::filesystem::exists(PATH, ec) || ec) {
if (!NSys::root::createDirectory(PATH.string(), "755"))
Debug::die("updateGlobalState: failed to create dir");
}
// clang-format off // clang-format off
auto DATA = toml::table{ auto DATA = toml::table{
{"state", toml::table{ {"state", toml::table{
@@ -184,20 +143,17 @@ void DataState::updateGlobalState(const SGlobalState& state) {
}; };
// clang-format on // clang-format on
std::stringstream ss; std::ofstream ofs(PATH / "state.toml", std::ios::trunc);
ss << DATA; ofs << DATA;
ofs.close();
if (!writeState(ss.str(), (PATH / "state.toml").string()))
Debug::die("{}", failureString("Failed to write plugin state"));
} }
SGlobalState DataState::getGlobalState() { SGlobalState DataState::getGlobalState() {
ensureStateStoreExists(); ensureStateStoreExists();
const auto stateFile = getDataStatePath() / "state.toml"; const auto stateFile = getDataStatePath() / "state.toml";
std::error_code ec; if (!std::filesystem::exists(stateFile))
if (!std::filesystem::exists(stateFile, ec) || ec)
return SGlobalState{}; return SGlobalState{};
auto DATA = toml::parse_file(stateFile.c_str()); auto DATA = toml::parse_file(stateFile.c_str());
@@ -212,6 +168,8 @@ SGlobalState DataState::getGlobalState() {
std::vector<SPluginRepository> DataState::getAllRepositories() { std::vector<SPluginRepository> DataState::getAllRepositories() {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
std::vector<SPluginRepository> repos; std::vector<SPluginRepository> repos;
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
@@ -247,6 +205,8 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
bool DataState::setPluginEnabled(const std::string& name, bool enabled) { bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
for (const auto& [key, val] : STATE) { for (const auto& [key, val] : STATE) {
@@ -264,11 +224,9 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
auto modifiedState = STATE; auto modifiedState = STATE;
(*modifiedState[key].as_table()).insert_or_assign("enabled", enabled); (*modifiedState[key].as_table()).insert_or_assign("enabled", enabled);
std::stringstream ss; std::ofstream state(stateFile, std::ios::trunc);
ss << modifiedState; state << modifiedState;
state.close();
if (!writeState(ss.str(), stateFile.string()))
Debug::die("{}", failureString("Failed to write plugin state"));
return true; return true;
} }
@@ -276,18 +234,3 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
return false; return false;
} }
void DataState::purgeAllCache() {
std::error_code ec;
if (!std::filesystem::exists(getDataStatePath()) && !ec) {
std::println("{}", infoString("Nothing to do"));
return;
}
const auto PATH = getDataStatePath().string();
if (PATH.contains('\''))
return;
// scary!
if (!NSys::root::removeRecursive(PATH))
Debug::die("Failed to run a superuser cmd");
}

View File

@@ -18,7 +18,6 @@ namespace DataState {
void removePluginRepo(const std::string& urlOrName); void removePluginRepo(const std::string& urlOrName);
bool pluginRepoExists(const std::string& urlOrName); bool pluginRepoExists(const std::string& urlOrName);
void updateGlobalState(const SGlobalState& state); void updateGlobalState(const SGlobalState& state);
void purgeAllCache();
SGlobalState getGlobalState(); SGlobalState getGlobalState();
bool setPluginEnabled(const std::string& name, bool enabled); bool setPluginEnabled(const std::string& name, bool enabled);
std::vector<SPluginRepository> getAllRepositories(); std::vector<SPluginRepository> getAllRepositories();

View File

@@ -1,85 +0,0 @@
#include "HyprlandSocket.hpp"
#include <pwd.h>
#include <sys/socket.h>
#include "../helpers/StringUtils.hpp"
#include <print>
#include <sys/un.h>
#include <unistd.h>
static int getUID() {
const auto UID = getuid();
const auto PWUID = getpwuid(UID);
return PWUID ? PWUID->pw_uid : UID;
}
static std::string getRuntimeDir() {
const auto XDG = getenv("XDG_RUNTIME_DIR");
if (!XDG) {
const std::string USERID = std::to_string(getUID());
return "/run/user/" + USERID + "/hypr";
}
return std::string{XDG} + "/hypr";
}
std::string NHyprlandSocket::send(const std::string& cmd) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
if (SERVERSOCKET < 0) {
std::println("{}", failureString("Couldn't open a socket (1)"));
return "";
}
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!HIS) {
std::println("{}", failureString("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?) (3)"));
return "";
}
sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX;
std::string socketPath = getRuntimeDir() + "/" + HIS + "/.socket.sock";
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
std::println("{}", failureString("Couldn't connect to " + socketPath + ". (4)"));
return "";
}
auto sizeWritten = write(SERVERSOCKET, cmd.c_str(), cmd.length());
if (sizeWritten < 0) {
std::println("{}", failureString("Couldn't write (5)"));
return "";
}
std::string reply = "";
constexpr size_t BUFFER_SIZE = 8192;
char buffer[BUFFER_SIZE] = {0};
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
if (sizeWritten < 0) {
std::println("{}", failureString("Couldn't read (6)"));
return "";
}
reply += std::string(buffer, sizeWritten);
while (sizeWritten == BUFFER_SIZE) {
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
if (sizeWritten < 0) {
std::println("{}", failureString("Couldn't read (7)"));
return "";
}
reply += std::string(buffer, sizeWritten);
}
close(SERVERSOCKET);
return reply;
}

View File

@@ -1,7 +0,0 @@
#pragma once
#include <string>
namespace NHyprlandSocket {
std::string send(const std::string& cmd);
};

View File

@@ -1,12 +1,6 @@
#include "Manifest.hpp" #include "Manifest.hpp"
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <algorithm> #include <iostream>
// Alphanumerics and -_ allowed for plugin names. No magic names.
// [A-Za-z0-9\-_]*
static bool validManifestName(const std::string_view& n) {
return std::ranges::all_of(n, [](const char& c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '-' || c == '_' || c == '=' || (c >= '0' && c <= '9'); });
}
CManifest::CManifest(const eManifestType type, const std::string& path) { CManifest::CManifest(const eManifestType type, const std::string& path) {
auto manifest = toml::parse_file(path); auto manifest = toml::parse_file(path);
@@ -17,17 +11,11 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
continue; continue;
CManifest::SManifestPlugin plugin; CManifest::SManifestPlugin plugin;
if (!validManifestName(key.str())) {
m_good = false;
return;
}
plugin.name = key; plugin.name = key;
m_plugins.push_back(plugin); m_vPlugins.push_back(plugin);
} }
for (auto& plugin : m_plugins) { for (auto& plugin : m_vPlugins) {
plugin.description = manifest[plugin.name]["description"].value_or("?"); plugin.description = manifest[plugin.name]["description"].value_or("?");
plugin.version = manifest[plugin.name]["version"].value_or("?"); plugin.version = manifest[plugin.name]["version"].value_or("?");
plugin.output = manifest[plugin.name]["build"]["output"].value_or("?"); plugin.output = manifest[plugin.name]["build"]["output"].value_or("?");
@@ -49,21 +37,21 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
} }
if (plugin.output.empty() || plugin.buildSteps.empty()) { if (plugin.output.empty() || plugin.buildSteps.empty()) {
m_good = false; m_bGood = false;
return; return;
} }
} }
} else if (type == MANIFEST_HYPRPM) { } else if (type == MANIFEST_HYPRPM) {
m_repository.name = manifest["repository"]["name"].value_or(""); m_sRepository.name = manifest["repository"]["name"].value_or("");
auto authors = manifest["repository"]["authors"].as_array(); auto authors = manifest["repository"]["authors"].as_array();
if (authors) { if (authors) {
for (auto&& a : *authors) { for (auto&& a : *authors) {
m_repository.authors.push_back(a.as_string()->value_or("?")); m_sRepository.authors.push_back(a.as_string()->value_or("?"));
} }
} else { } else {
auto author = manifest["repository"]["author"].value_or(""); auto author = manifest["repository"]["author"].value_or("");
if (!std::string{author}.empty()) if (!std::string{author}.empty())
m_repository.authors.push_back(author); m_sRepository.authors.push_back(author);
} }
auto pins = manifest["repository"]["commit_pins"].as_array(); auto pins = manifest["repository"]["commit_pins"].as_array();
@@ -71,7 +59,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
for (auto&& pin : *pins) { for (auto&& pin : *pins) {
auto pinArr = pin.as_array(); auto pinArr = pin.as_array();
if (pinArr && pinArr->get(1)) if (pinArr && pinArr->get(1))
m_repository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get())); m_sRepository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get()));
} }
} }
@@ -80,17 +68,11 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
continue; continue;
CManifest::SManifestPlugin plugin; CManifest::SManifestPlugin plugin;
if (!validManifestName(key.str())) {
m_good = false;
return;
}
plugin.name = key; plugin.name = key;
m_plugins.push_back(plugin); m_vPlugins.push_back(plugin);
} }
for (auto& plugin : m_plugins) { for (auto& plugin : m_vPlugins) {
plugin.description = manifest[plugin.name]["description"].value_or("?"); plugin.description = manifest[plugin.name]["description"].value_or("?");
plugin.output = manifest[plugin.name]["output"].value_or("?"); plugin.output = manifest[plugin.name]["output"].value_or("?");
plugin.since = manifest[plugin.name]["since_hyprland"].value_or(0); plugin.since = manifest[plugin.name]["since_hyprland"].value_or(0);
@@ -112,12 +94,12 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
} }
if (plugin.output.empty() || plugin.buildSteps.empty()) { if (plugin.output.empty() || plugin.buildSteps.empty()) {
m_good = false; m_bGood = false;
return; return;
} }
} }
} else { } else {
// ??? // ???
m_good = false; m_bGood = false;
} }
} }

View File

@@ -27,8 +27,8 @@ class CManifest {
std::string name; std::string name;
std::vector<std::string> authors; std::vector<std::string> authors;
std::vector<std::pair<std::string, std::string>> commitPins; std::vector<std::pair<std::string, std::string>> commitPins;
} m_repository; } m_sRepository;
std::vector<SManifestPlugin> m_plugins; std::vector<SManifestPlugin> m_vPlugins;
bool m_good = true; bool m_bGood = true;
}; };

View File

@@ -4,9 +4,6 @@
#include "../progress/CProgressBar.hpp" #include "../progress/CProgressBar.hpp"
#include "Manifest.hpp" #include "Manifest.hpp"
#include "DataState.hpp" #include "DataState.hpp"
#include "HyprlandSocket.hpp"
#include "../helpers/Sys.hpp"
#include "../helpers/Die.hpp"
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
@@ -52,13 +49,6 @@ static std::string getTempRoot() {
return STR; return STR;
} }
CPluginManager::CPluginManager() {
if (NSys::isSuperuser())
Debug::die("Don't run hyprpm as a superuser.");
m_szUsername = getpwuid(NSys::getUID())->pw_name;
}
SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) { SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
static bool onceRunning = false; static bool onceRunning = false;
static bool onceInstalled = false; static bool onceInstalled = false;
@@ -76,7 +66,7 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
else else
onceInstalled = true; onceInstalled = true;
const auto HLVERCALL = running ? NHyprlandSocket::send("/version") : execAndGet("Hyprland --version"); const auto HLVERCALL = running ? execAndGet("hyprctl version") : execAndGet("Hyprland --version");
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("{} version returned: {}", running ? "running" : "installed", HLVERCALL)); std::println("{}", verboseString("{} version returned: {}", running ? "running" : "installed", HLVERCALL));
@@ -139,8 +129,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) { if (!hasDeps()) {
std::println(stderr, "\n{}", std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config"));
failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config, git, g++, gcc"));
return false; return false;
} }
@@ -236,14 +225,14 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
return false; return false;
} }
if (!pManifest->m_good) { if (!pManifest->m_bGood) {
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest"));
return false; return false;
} }
progress.m_iSteps = 2; progress.m_iSteps = 2;
progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_plugins.size()) + " plugins:")); progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:"));
for (auto const& pl : pManifest->m_plugins) { for (auto const& pl : pManifest->m_vPlugins) {
std::string message = "" + pl.name + " by "; std::string message = "" + pl.name + " by ";
for (auto const& a : pl.authors) { for (auto const& a : pl.authors) {
message += a + ", "; message += a + ", ";
@@ -256,12 +245,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.printMessageAbove(message); progress.printMessageAbove(message);
} }
if (!pManifest->m_repository.commitPins.empty()) { if (!pManifest->m_sRepository.commitPins.empty()) {
// check commit pins // check commit pins
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_repository.commitPins.size())); progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size()));
for (auto const& [hl, plugin] : pManifest->m_repository.commitPins) { for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
@@ -284,7 +273,6 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
if (HEADERSSTATUS != HEADERS_OK) { if (HEADERSSTATUS != HEADERS_OK) {
std::println("\n{}", headerError(HEADERSSTATUS)); std::println("\n{}", headerError(HEADERSSTATUS));
std::println("\n{}", infoString("if the problem persists, try running hyprpm purge-cache."));
return false; return false;
} }
@@ -293,7 +281,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.m_szCurrentMessage = "Building plugin(s)"; progress.m_szCurrentMessage = "Building plugin(s)";
progress.print(); progress.print();
for (auto& p : pManifest->m_plugins) { for (auto& p : pManifest->m_vPlugins) {
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) { if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) {
@@ -336,11 +324,11 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::string repohash = execAndGet("cd " + m_szWorkingPluginDirectory + " && git rev-parse HEAD"); std::string repohash = execAndGet("cd " + m_szWorkingPluginDirectory + " && git rev-parse HEAD");
if (repohash.length() > 0) if (repohash.length() > 0)
repohash.pop_back(); repohash.pop_back();
repo.name = pManifest->m_repository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_repository.name; repo.name = pManifest->m_sRepository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_sRepository.name;
repo.url = url; repo.url = url;
repo.rev = rev; repo.rev = rev;
repo.hash = repohash; repo.hash = repohash;
for (auto const& p : pManifest->m_plugins) { for (auto const& p : pManifest->m_vPlugins) {
repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed}); repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed});
} }
DataState::addNewPluginRepo(repo); DataState::addNewPluginRepo(repo);
@@ -447,7 +435,7 @@ bool CPluginManager::updateHeaders(bool force) {
const auto HLVER = getHyprlandVersion(false); const auto HLVER = getHyprlandVersion(false);
if (!hasDeps()) { if (!hasDeps()) {
std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config, git, g++, gcc")); std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config"));
return false; return false;
} }
@@ -475,9 +463,7 @@ bool CPluginManager::updateHeaders(bool force) {
return false; return false;
} }
const auto& HL_URL = m_szCustomHlUrl.empty() ? "https://github.com/hyprwm/Hyprland" : m_szCustomHlUrl; progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment."));
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning {}, this might take a moment.", HL_URL));
const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow; const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow;
@@ -488,12 +474,12 @@ bool CPluginManager::updateHeaders(bool force) {
if (m_bVerbose && bShallow) if (m_bVerbose && bShallow)
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE)); progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE));
std::string ret = std::string ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-{}{}", getTempRoot(), USERNAME,
execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}{}", getTempRoot(), HL_URL, USERNAME, (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""))); (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")));
if (!std::filesystem::exists(WORKINGDIR)) { if (!std::filesystem::exists(WORKINGDIR)) {
progress.printMessageAbove(failureString("Clone failed. Retrying without shallow.")); progress.printMessageAbove(failureString("Clone failed. Retrying without shallow."));
ret = execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}", getTempRoot(), HL_URL, USERNAME)); ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/hyprland hyprland-{}", getTempRoot(), USERNAME));
} }
if (!std::filesystem::exists(WORKINGDIR + "/.git")) { if (!std::filesystem::exists(WORKINGDIR + "/.git")) {
@@ -560,21 +546,13 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";
progress.print(); progress.print();
std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile", DataState::getHeadersPath(), WORKINGDIR); const std::string& cmd =
std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("prepare install will run: {}", cmd)); progress.printMessageAbove(verboseString("installation will run: {}", cmd));
ret = execAndGet(cmd); ret = execAndGet(cmd);
cmd = std::format("make -C '{}' installheaders && chmod -R 644 '{}' && find '{}' -type d -exec chmod o+x {{}} \\;", WORKINGDIR, DataState::getHeadersPath(),
DataState::getHeadersPath());
if (m_bVerbose)
progress.printMessageAbove(verboseString("install will run as sudo: {}", cmd));
// WORKINGDIR and headersPath should not contain anything unsafe. Usernames can't contain cmd exec parts.
ret = NSys::root::runAsSuperuserUnsafe(cmd);
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("installer returned: {}", ret)); std::println("{}", verboseString("installer returned: {}", ret));
@@ -588,14 +566,9 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
auto GLOBALSTATE = DataState::getGlobalState();
GLOBALSTATE.headersHashCompiled = HLVER.hash;
DataState::updateGlobalState(GLOBALSTATE);
std::print("\n"); std::print("\n");
} else { } else {
progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID))); progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID)));
progress.printMessageAbove(infoString("if the problem persists, try running hyprpm purge-cache."));
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Failed"; progress.m_szCurrentMessage = "Failed";
progress.print(); progress.print();
@@ -702,17 +675,17 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
continue; continue;
} }
if (!pManifest->m_good) { if (!pManifest->m_bGood) {
std::println(stderr, "\n{}", failureString("The provided plugin repository has a bad manifest")); std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest"));
continue; continue;
} }
if (repo.rev.empty() && !pManifest->m_repository.commitPins.empty()) { if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) {
// check commit pins unless a revision is specified // check commit pins unless a revision is specified
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_repository.commitPins.size())); progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size()));
for (auto const& [hl, plugin] : pManifest->m_repository.commitPins) { for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
@@ -722,7 +695,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
} }
} }
for (auto& p : pManifest->m_plugins) { for (auto& p : pManifest->m_vPlugins) {
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) { if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) {
@@ -764,7 +737,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (repohash.length() > 0) if (repohash.length() > 0)
repohash.pop_back(); repohash.pop_back();
newrepo.hash = repohash; newrepo.hash = repohash;
for (auto const& p : pManifest->m_plugins) { for (auto const& p : pManifest->m_vPlugins) {
const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; }); const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; });
newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false}); newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false});
} }
@@ -821,9 +794,9 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload)
} }
const auto HYPRPMPATH = DataState::getDataStatePath(); const auto HYPRPMPATH = DataState::getDataStatePath();
const auto json = glz::read_json<glz::json_t::array_t>(NHyprlandSocket::send("j/plugins list")); const auto json = glz::read_json<glz::json_t::array_t>(execAndGet("hyprctl plugins list -j"));
if (!json) { if (!json) {
std::println(stderr, "PluginManager: couldn't parse plugin list output"); std::println(stderr, "PluginManager: couldn't parse hyprctl output");
return LOADSTATE_FAIL; return LOADSTATE_FAIL;
} }
@@ -907,15 +880,14 @@ bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
auto HLVER = getHyprlandVersion(true); auto HLVER = getHyprlandVersion(true);
if (state.headersHashCompiled != HLVER.hash) { if (state.headersHashCompiled != HLVER.hash) {
if (load) std::println("{}", infoString("Running Hyprland version differs from plugin state, please restart Hyprland."));
std::println("{}", infoString("Running Hyprland version ({}) differs from plugin state ({}), please restart Hyprland.", HLVER.hash, state.headersHashCompiled));
return false; return false;
} }
if (load) if (load)
NHyprlandSocket::send("/plugin load " + path); execAndGet("hyprctl plugin load " + path);
else else
NHyprlandSocket::send("/plugin unload " + path); execAndGet("hyprctl plugin unload " + path);
return true; return true;
} }
@@ -940,7 +912,7 @@ void CPluginManager::listAllPlugins() {
} }
void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message) { void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message) {
NHyprlandSocket::send("/notify " + std::to_string((int)icon) + " " + std::to_string(durationMs) + " " + std::to_string(color) + " " + message); execAndGet("hyprctl notify " + std::to_string((int)icon) + " " + std::to_string(durationMs) + " " + std::to_string(color) + " " + message);
} }
std::string CPluginManager::headerError(const eHeadersErrors err) { std::string CPluginManager::headerError(const eHeadersErrors err) {
@@ -973,7 +945,7 @@ std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {
} }
bool CPluginManager::hasDeps() { bool CPluginManager::hasDeps() {
std::vector<std::string> deps = {"meson", "cpio", "cmake", "pkg-config", "g++", "gcc", "git"}; std::vector<std::string> deps = {"meson", "cpio", "cmake", "pkg-config"};
for (auto const& d : deps) { for (auto const& d : deps) {
if (!execAndGet("command -v " + d).contains("/")) if (!execAndGet("command -v " + d).contains("/"))
return false; return false;

View File

@@ -40,8 +40,6 @@ struct SHyprlandVersion {
class CPluginManager { class CPluginManager {
public: public:
CPluginManager();
bool addNewPluginRepo(const std::string& url, const std::string& rev); bool addNewPluginRepo(const std::string& url, const std::string& rev);
bool removePluginRepo(const std::string& urlOrName); bool removePluginRepo(const std::string& urlOrName);
@@ -64,7 +62,6 @@ class CPluginManager {
bool m_bVerbose = false; bool m_bVerbose = false;
bool m_bNoShallow = false; bool m_bNoShallow = false;
std::string m_szCustomHlUrl, m_szUsername;
// will delete recursively if exists!! // will delete recursively if exists!!
bool createSafeDirectory(const std::string& path); bool createSafeDirectory(const std::string& path);

View File

@@ -1,15 +0,0 @@
#pragma once
#include <format>
#include <iostream>
// NOLINTNEXTLINE
namespace Debug {
template <typename... Args>
void die(std::format_string<Args...> fmt, Args&&... args) {
const std::string logMsg = std::vformat(fmt.get(), std::make_format_args(args...));
std::cout << "\n[ERR] " << logMsg << "\n";
exit(1);
}
};

View File

@@ -1,167 +0,0 @@
#include "Sys.hpp"
#include "Die.hpp"
#include "StringUtils.hpp"
#include <pwd.h>
#include <unistd.h>
#include <print>
#include <filesystem>
#include <algorithm>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/string/VarList.hpp>
using namespace Hyprutils::OS;
using namespace Hyprutils::String;
inline constexpr std::array<std::string_view, 3> SUPERUSER_BINARIES = {
"sudo",
"doas",
"run0",
};
static std::string validSubinsAsStr() {
std::ostringstream oss;
auto it = SUPERUSER_BINARIES.begin();
if (it != SUPERUSER_BINARIES.end()) {
oss << *it++;
for (; it != SUPERUSER_BINARIES.end(); ++it)
oss << ", " << *it;
}
return oss.str();
}
static bool executableExistsInPath(const std::string& exe) {
const char* PATHENV = std::getenv("PATH");
if (!PATHENV)
return false;
CVarList paths(PATHENV, 0, ':', true);
std::error_code ec;
for (const auto& PATH : paths) {
std::filesystem::path candidate = std::filesystem::path(PATH) / exe;
if (!std::filesystem::exists(candidate, ec) || ec)
continue;
if (!std::filesystem::is_regular_file(candidate, ec) || ec)
continue;
auto perms = std::filesystem::status(candidate, ec).permissions();
if (ec)
continue;
if ((perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none)
return true;
}
return false;
}
static std::string subin() {
static std::string bin;
static bool once = true;
if (!once)
return bin;
for (const auto& BIN : SUPERUSER_BINARIES) {
if (!executableExistsInPath(std::string{BIN}))
continue;
bin = BIN;
break;
}
once = false;
if (bin.empty())
Debug::die("{}", failureString("No valid superuser binary present. Supported: {}", validSubinsAsStr()));
return bin;
}
static bool verifyStringValid(const std::string& s) {
return std::ranges::none_of(s, [](const char& c) { return c == '`' || c == '$' || c == '(' || c == ')' || c == '\'' || c == '"'; });
}
int NSys::getUID() {
const auto UID = getuid();
const auto PWUID = getpwuid(UID);
return PWUID ? PWUID->pw_uid : UID;
}
int NSys::getEUID() {
const auto UID = geteuid();
const auto PWUID = getpwuid(UID);
return PWUID ? PWUID->pw_uid : UID;
}
bool NSys::isSuperuser() {
return getuid() != geteuid() || geteuid() == 0;
}
void NSys::root::cacheSudo() {
// "caches" the sudo so that the prompt later doesn't pop up in a weird spot
// sudo will not ask us again for a moment
CProcess proc(subin(), {"echo", "hyprland"});
proc.runSync();
}
void NSys::root::dropSudo() {
if (subin() != "sudo") {
std::println("{}", infoString("Don't know how to drop timestamp for '{}', ignoring.", subin()));
return;
}
CProcess proc(subin(), {"-k"});
proc.runSync();
}
bool NSys::root::createDirectory(const std::string& path, const std::string& mode) {
if (!verifyStringValid(path))
return false;
if (!std::ranges::all_of(mode, [](const char& c) { return c >= '0' && c <= '9'; }))
return false;
CProcess proc(subin(), {"mkdir", "-p", "-m", mode, path});
return proc.runSync() && proc.exitCode() == 0;
}
bool NSys::root::removeRecursive(const std::string& path) {
if (!verifyStringValid(path))
return false;
std::error_code ec;
const std::string PATH_ABSOLUTE = std::filesystem::canonical(path, ec);
if (ec)
return false;
if (!PATH_ABSOLUTE.starts_with("/var/cache/hyprpm"))
return false;
CProcess proc(subin(), {"rm", "-fr", PATH_ABSOLUTE});
return proc.runSync() && proc.exitCode() == 0;
}
bool NSys::root::install(const std::string& what, const std::string& where, const std::string& mode) {
if (!verifyStringValid(what) || !verifyStringValid(where))
return false;
if (!std::ranges::all_of(mode, [](const char& c) { return c >= '0' && c <= '9'; }))
return false;
CProcess proc(subin(), {"install", "-m" + mode, "-o", "root", "-g", "root", what, where});
return proc.runSync() && proc.exitCode() == 0;
}
std::string NSys::root::runAsSuperuserUnsafe(const std::string& cmd) {
CProcess proc(subin(), {"/bin/sh", "-c", cmd});
if (!proc.runSync())
return "";
return proc.stdOut();
}

View File

@@ -1,23 +0,0 @@
#pragma once
#include <string>
namespace NSys {
bool isSuperuser();
int getUID();
int getEUID();
// NOLINTNEXTLINE
namespace root {
void cacheSudo();
void dropSudo();
//
[[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool createDirectory(const std::string& path, const std::string& mode);
[[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool removeRecursive(const std::string& path);
[[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool install(const std::string& what, const std::string& where, const std::string& mode);
// Do not use this unless absolutely necessary!
std::string runAsSuperuserUnsafe(const std::string& cmd);
};
};

View File

@@ -2,36 +2,33 @@
#include "helpers/StringUtils.hpp" #include "helpers/StringUtils.hpp"
#include "core/PluginManager.hpp" #include "core/PluginManager.hpp"
#include "core/DataState.hpp" #include "core/DataState.hpp"
#include "helpers/Sys.hpp"
#include <cstdio>
#include <vector> #include <vector>
#include <string> #include <string>
#include <print> #include <print>
#include <chrono>
#include <hyprutils/utils/ScopeGuard.hpp> #include <thread>
using namespace Hyprutils::Utils;
constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
add [url] [git rev] Install a new plugin repository from git. Git revision. add [url] [git rev] Install a new plugin repository from git. Git revision
is optional, when set, commit locks are ignored. is optional, when set, commit locks are ignored.
remove [url/name] Remove an installed plugin repository. remove [url/name] Remove an installed plugin repository
enable [name] Enable a plugin. enable [name] Enable a plugin
disable [name] Disable a plugin. disable [name] Disable a plugin
update Check and update all plugins if needed. update Check and update all plugins if needed
reload Reload hyprpm state. Ensure all enabled plugins are loaded. reload Reload hyprpm state. Ensure all enabled plugins are loaded.
list List all installed plugins. list List all installed plugins
purge-cache Remove the entire hyprpm cache, built plugins, hyprpm settings and headers.
Flags: Flags:
--notify | -n Send a hyprland notification for important events (including both successes and fail events). --notify | -n Send a hyprland notification for important events (including both successes and fail events)
--notify-fail | -nn Send a hyprland notification for fail events only. --notify-fail | -nn Send a hyprland notification for fail events only
--help | -h Show this menu. --help | -h Show this menu
--verbose | -v Enable too much logging. --verbose | -v Enable too much logging
--force | -f Force an operation ignoring checks (e.g. update -f). --force | -f Force an operation ignoring checks (e.g. update -f)
--no-shallow | -s Disable shallow cloning of Hyprland sources. --no-shallow | -s Disable shallow cloning of Hyprland sources
--hl-url | Pass a custom hyprland source url.
)#"; )#";
@@ -48,7 +45,6 @@ int main(int argc, char** argv, char** envp) {
std::vector<std::string> command; std::vector<std::string> command;
bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false; bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false;
std::string customHlUrl;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) { if (ARGS[i].starts_with("-")) {
@@ -63,13 +59,6 @@ int main(int argc, char** argv, char** envp) {
verbose = true; verbose = true;
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") { } else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
noShallow = true; noShallow = true;
} else if (ARGS[i] == "--hl-url") {
if (i + 1 >= argc) {
std::println(stderr, "Missing argument for --hl-url");
return 1;
}
customHlUrl = ARGS[i + 1];
i++;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") { } else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true; force = true;
std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing.")); std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing."));
@@ -77,8 +66,9 @@ int main(int argc, char** argv, char** envp) {
std::println(stderr, "Unrecognized option {}", ARGS[i]); std::println(stderr, "Unrecognized option {}", ARGS[i]);
return 1; return 1;
} }
} else } else {
command.push_back(ARGS[i]); command.push_back(ARGS[i]);
}
} }
if (command.empty()) { if (command.empty()) {
@@ -86,10 +76,9 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} }
g_pPluginManager = std::make_unique<CPluginManager>(); g_pPluginManager = std::make_unique<CPluginManager>();
g_pPluginManager->m_bVerbose = verbose; g_pPluginManager->m_bVerbose = verbose;
g_pPluginManager->m_bNoShallow = noShallow; g_pPluginManager->m_bNoShallow = noShallow;
g_pPluginManager->m_szCustomHlUrl = customHlUrl;
if (command[0] == "add") { if (command[0] == "add") {
if (command.size() < 2) { if (command.size() < 2) {
@@ -98,11 +87,9 @@ int main(int argc, char** argv, char** envp) {
} }
std::string rev = ""; std::string rev = "";
if (command.size() >= 3) if (command.size() >= 3) {
rev = command[2]; rev = command[2];
}
NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1; return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
} else if (command[0] == "remove") { } else if (command[0] == "remove") {
@@ -111,17 +98,10 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} }
NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1; return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
} else if (command[0] == "update") { } else if (command[0] == "update") {
NSys::root::cacheSudo(); bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
CScopeGuard x([] { NSys::root::dropSudo(); }); bool headers = g_pPluginManager->updateHeaders(force);
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
bool headers = g_pPluginManager->updateHeaders(force);
if (headers) { if (headers) {
const auto HLVER = g_pPluginManager->getHyprlandVersion(false); const auto HLVER = g_pPluginManager->getHyprlandVersion(false);
auto GLOBALSTATE = DataState::getGlobalState(); auto GLOBALSTATE = DataState::getGlobalState();
@@ -152,10 +132,7 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} }
NSys::root::cacheSudo(); auto ret = g_pPluginManager->ensurePluginsLoadState();
CScopeGuard x([] { NSys::root::dropSudo(); });
auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret == LOADSTATE_HYPRLAND_UPDATED) if (ret == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland."); g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland.");
@@ -173,36 +150,25 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} }
NSys::root::cacheSudo(); auto ret = g_pPluginManager->ensurePluginsLoadState();
CScopeGuard x([] { NSys::root::dropSudo(); });
auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret != LOADSTATE_OK) if (ret != LOADSTATE_OK)
return 1; return 1;
} else if (command[0] == "reload") { } else if (command[0] == "reload") {
auto ret = g_pPluginManager->ensurePluginsLoadState(force); auto ret = g_pPluginManager->ensurePluginsLoadState(force);
if (ret != LOADSTATE_OK) { if (ret != LOADSTATE_OK && notify) {
if (notify) { switch (ret) {
switch (ret) { case LOADSTATE_FAIL:
case LOADSTATE_FAIL: case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break; case LOADSTATE_HEADERS_OUTDATED:
case LOADSTATE_HEADERS_OUTDATED: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually.");
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually."); break;
break; default: break;
default: break;
}
} }
return 1; return 1;
} else if (notify && !notifyFail) { } else if (notify && !notifyFail) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins"); g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
} }
} else if (command[0] == "purge-cache") {
NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
DataState::purgeAllCache();
} else if (command[0] == "list") { } else if (command[0] == "list") {
g_pPluginManager->listAllPlugins(); g_pPluginManager->listAllPlugins();
} else { } else {

View File

@@ -1,78 +1,82 @@
#include "CProgressBar.hpp" #include "CProgressBar.hpp"
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <unistd.h> #include <algorithm>
#include <cmath> #include <cmath>
#include <format> #include <format>
#include <print>
#include <cstdio>
#include <algorithm> #include <print>
#include <sstream> #include <stdio.h>
#include <unistd.h>
#include "../helpers/Colors.hpp" #include "../helpers/Colors.hpp"
static winsize getTerminalSize() {
winsize w{};
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
return w;
}
static void clearCurrentLine() {
std::print("\r\33[2K"); // ansi escape sequence to clear entire line
}
void CProgressBar::printMessageAbove(const std::string& msg) { void CProgressBar::printMessageAbove(const std::string& msg) {
clearCurrentLine(); struct winsize w;
std::print("\r{}\n", msg); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
print(); // reprint bar underneath std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' ';
}
std::println("\r{}\r{}", spaces, msg);
print();
} }
void CProgressBar::print() { void CProgressBar::print() {
const auto w = getTerminalSize(); struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (m_bFirstPrint) { if (m_bFirstPrint)
std::print("\n"); std::print("\n");
m_bFirstPrint = false; m_bFirstPrint = false;
std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' ';
} }
clearCurrentLine(); std::print("\r{}\r", spaces);
float percentDone = 0.0f; std::string message = "";
if (m_fPercentage >= 0.0f)
float percentDone = 0;
if (m_fPercentage >= 0)
percentDone = m_fPercentage; percentDone = m_fPercentage;
else { else
// check for divide-by-zero percentDone = (float)m_iSteps / (float)m_iMaxSteps;
percentDone = m_iMaxSteps > 0 ? static_cast<float>(m_iSteps) / m_iMaxSteps : 0.0f;
const auto BARWIDTH = std::clamp(w.ws_col - static_cast<unsigned long>(m_szCurrentMessage.length()) - 2, 0UL, 50UL);
// draw bar
message += std::string{" "} + Colors::GREEN;
size_t i = 0;
for (; i < std::floor(percentDone * BARWIDTH); ++i) {
message += "";
} }
// clamp to ensure no overflows (sanity check)
percentDone = std::clamp(percentDone, 0.0f, 1.0f);
const size_t BARWIDTH = std::clamp<size_t>(w.ws_col - m_szCurrentMessage.length() - 2, 0, 50);
std::ostringstream oss;
oss << ' ' << Colors::GREEN;
size_t filled = static_cast<size_t>(std::floor(percentDone * BARWIDTH));
size_t i = 0;
for (; i < filled; ++i)
oss << "";
if (i < BARWIDTH) { if (i < BARWIDTH) {
oss << "" << Colors::RESET; i++;
++i;
for (; i < BARWIDTH; ++i) message += std::string{""} + Colors::RESET;
oss << "";
for (; i < BARWIDTH; ++i) {
message += "";
}
} else } else
oss << Colors::RESET; message += Colors::RESET;
if (m_fPercentage >= 0.0f) // draw progress
oss << " " << std::format("{}%", static_cast<int>(percentDone * 100.0)) << ' '; if (m_fPercentage >= 0)
message += " " + std::format("{}%", static_cast<int>(percentDone * 100.0)) + " ";
else else
oss << " " << std::format("{} / {}", m_iSteps, m_iMaxSteps) << ' '; message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " ";
// draw message
std::print("{} {}", message, m_szCurrentMessage);
std::print("{} {}", oss.str(), m_szCurrentMessage);
std::fflush(stdout); std::fflush(stdout);
} }

View File

@@ -31,16 +31,12 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif endif
aquamarine = dependency('aquamarine', version: '>=0.8.0') aquamarine = dependency('aquamarine', version: '>=0.4.5')
hyprcursor = dependency('hyprcursor', version: '>=0.1.7') hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1') hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
hyprlang = dependency('hyprlang', version: '>= 0.3.2') hyprlang = dependency('hyprlang', version: '>= 0.3.2')
hyprutils = dependency('hyprutils', version: '>= 0.7.0') 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="@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(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp')
add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp') add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp')
add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp') add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp')
@@ -87,11 +83,9 @@ endif
# Generate hyprland version and populate version.h # Generate hyprland version and populate version.h
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
# Make shader files includable
run_command('sh', '-c', 'scripts/generateShaderIncludes.sh', check: true)
# Install headers # Install headers
globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.inc', check: true) globber = run_command('find', 'src', '-name', '*.h*', check: true)
headers = globber.stdout().strip().split('\n') headers = globber.stdout().strip().split('\n')
foreach file : headers foreach file : headers
install_headers(file, subdir: 'hyprland', preserve_path: true) install_headers(file, subdir: 'hyprland', preserve_path: true)

View File

@@ -11,7 +11,6 @@
aquamarine, aquamarine,
binutils, binutils,
cairo, cairo,
epoll-shim,
git, git,
glaze, glaze,
hyprcursor, hyprcursor,
@@ -27,7 +26,7 @@
libinput, libinput,
libxkbcommon, libxkbcommon,
libuuid, libuuid,
libgbm, mesa,
pango, pango,
pciutils, pciutils,
re2, re2,
@@ -131,7 +130,7 @@ in
libinput libinput
libuuid libuuid
libxkbcommon libxkbcommon
libgbm mesa
pango pango
pciutils pciutils
re2 re2
@@ -142,7 +141,6 @@ in
wayland-scanner wayland-scanner
xorg.libXcursor xorg.libXcursor
] ]
(optionals customStdenv.hostPlatform.isBSD [ epoll-shim ])
(optionals customStdenv.hostPlatform.isMusl [libexecinfo]) (optionals customStdenv.hostPlatform.isMusl [libexecinfo])
(optionals enableXWayland [ (optionals enableXWayland [
xorg.libxcb xorg.libxcb
@@ -155,18 +153,15 @@ in
(optional withSystemd systemd) (optional withSystemd systemd)
]; ];
strictDeps = true;
mesonBuildType = mesonBuildType =
if debug if debug
then "debug" then "debugoptimized"
else "release"; else "release";
mesonFlags = flatten [ mesonFlags = flatten [
(mapAttrsToList mesonEnable { (mapAttrsToList mesonEnable {
"xwayland" = enableXWayland; "xwayland" = enableXWayland;
"legacy_renderer" = legacyRenderer; "legacy_renderer" = legacyRenderer;
"systemd" = withSystemd;
"uwsm" = false; "uwsm" = false;
"hyprpm" = false; "hyprpm" = false;
}) })

View File

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

View File

@@ -5,8 +5,72 @@ inputs: {
... ...
}: let }: let
inherit (pkgs.stdenv.hostPlatform) system; inherit (pkgs.stdenv.hostPlatform) system;
selflib = import ./lib.nix lib;
cfg = config.programs.hyprland; cfg = config.programs.hyprland;
# basically 1:1 taken from https://github.com/nix-community/home-manager/blob/master/modules/services/window-managers/hyprland.nix
toHyprconf = {
attrs,
indentLevel ? 0,
importantPrefixes ? ["$"],
}: let
inherit
(lib)
all
concatMapStringsSep
concatStrings
concatStringsSep
filterAttrs
foldl
generators
hasPrefix
isAttrs
isList
mapAttrsToList
replicate
;
initialIndent = concatStrings (replicate indentLevel " ");
toHyprconf' = indent: attrs: let
sections =
filterAttrs (n: v: isAttrs v || (isList v && all isAttrs v)) attrs;
mkSection = n: attrs:
if lib.isList attrs
then (concatMapStringsSep "\n" (a: mkSection n a) attrs)
else ''
${indent}${n} {
${toHyprconf' " ${indent}" attrs}${indent}}
'';
mkFields = generators.toKeyValue {
listsAsDuplicateKeys = true;
inherit indent;
};
allFields =
filterAttrs (n: v: !(isAttrs v || (isList v && all isAttrs v)))
attrs;
isImportantField = n: _:
foldl (acc: prev:
if hasPrefix prev n
then true
else acc)
false
importantPrefixes;
importantFields = filterAttrs isImportantField allFields;
fields =
builtins.removeAttrs allFields
(mapAttrsToList (n: _: n) importantFields);
in
mkFields importantFields
+ concatStringsSep "\n" (mapAttrsToList mkSection sections)
+ mkFields fields;
in
toHyprconf' initialIndent attrs;
in { in {
options = { options = {
programs.hyprland = { programs.hyprland = {
@@ -42,9 +106,6 @@ in {
should be written as lists. Variables' and colors' names should be should be written as lists. Variables' and colors' names should be
quoted. See <https://wiki.hyprland.org> for more examples. quoted. See <https://wiki.hyprland.org> for more examples.
Special categories (e.g `devices`) should be written as
`"devices[device-name]"`.
::: {.note} ::: {.note}
Use the [](#programs.hyprland.plugins) option to Use the [](#programs.hyprland.plugins) option to
declare plugins. declare plugins.
@@ -90,21 +151,20 @@ in {
''; '';
}; };
topPrefixes = lib.mkOption { sourceFirst =
type = with lib.types; listOf str; lib.mkEnableOption ''
default = ["$" "bezier"]; putting source entries at the top of the configuration
example = ["$" "bezier" "source"]; ''
description = '' // {
List of prefix of attributes to put at the top of the config. default = true;
''; };
};
bottomPrefixes = lib.mkOption { importantPrefixes = lib.mkOption {
type = with lib.types; listOf str; type = with lib.types; listOf str;
default = []; default = ["$" "bezier" "name"] ++ lib.optionals cfg.sourceFirst ["source"];
example = ["source"]; example = ["$" "bezier"];
description = '' description = ''
List of prefix of attributes to put at the bottom of the config. List of prefix of attributes to source at the top of the config.
''; '';
}; };
}; };
@@ -113,39 +173,38 @@ in {
{ {
programs.hyprland = { programs.hyprland = {
package = lib.mkDefault inputs.self.packages.${system}.hyprland; package = lib.mkDefault inputs.self.packages.${system}.hyprland;
portalPackage = lib.mkDefault inputs.self.packages.${system}.xdg-desktop-portal-hyprland; portalPackage = lib.mkDefault (inputs.self.packages.${system}.xdg-desktop-portal-hyprland.override {
hyprland = cfg.finalPackage;
});
}; };
} }
(lib.mkIf cfg.enable { (lib.mkIf cfg.enable {
environment.etc."xdg/hypr/hyprland.conf" = let environment.etc."xdg/hypr/hyprland.conf" = let
shouldGenerate = cfg.extraConfig != "" || cfg.settings != {} || cfg.plugins != []; shouldGenerate = cfg.extraConfig != "" || cfg.settings != {} || cfg.plugins != [];
pluginsToHyprlang = plugins: pluginsToHyprconf = plugins:
selflib.toHyprlang { toHyprconf {
topCommandsPrefixes = cfg.topPrefixes; attrs = {
bottomCommandsPrefixes = cfg.bottomPrefixes; plugin = let
} mkEntry = entry:
{ if lib.types.package.check entry
"exec-once" = let then "${entry}/lib/lib${entry.pname}.so"
mkEntry = entry: else entry;
if lib.types.package.check entry in
then "${entry}/lib/lib${entry.pname}.so" map mkEntry cfg.plugins;
else entry; };
hyprctl = lib.getExe' config.programs.hyprland.package "hyprctl"; inherit (cfg) importantPrefixes;
in
map (p: "${hyprctl} plugin load ${mkEntry p}") cfg.plugins;
}; };
in in
lib.mkIf shouldGenerate { lib.mkIf shouldGenerate {
text = text =
lib.optionalString (cfg.plugins != []) lib.optionalString (cfg.plugins != [])
(pluginsToHyprlang cfg.plugins) (pluginsToHyprconf cfg.plugins)
+ lib.optionalString (cfg.settings != {}) + lib.optionalString (cfg.settings != {})
(selflib.toHyprlang { (toHyprconf {
topCommandsPrefixes = cfg.topPrefixes; attrs = cfg.settings;
bottomCommandsPrefixes = cfg.bottomPrefixes; inherit (cfg) importantPrefixes;
} })
cfg.settings)
+ lib.optionalString (cfg.extraConfig != "") cfg.extraConfig; + lib.optionalString (cfg.extraConfig != "") cfg.extraConfig;
}; };
}) })

View File

@@ -29,7 +29,6 @@ in {
inputs.hyprutils.overlays.default inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default inputs.hyprwayland-scanner.overlays.default
self.overlays.udis86 self.overlays.udis86
self.overlays.wayland-protocols
# Hyprland packages themselves # Hyprland packages themselves
(final: _prev: let (final: _prev: let
@@ -90,16 +89,4 @@ in {
patches = []; patches = [];
}); });
}; };
# TODO: remove when https://github.com/NixOS/nixpkgs/pull/397497 lands in master
wayland-protocols = final: prev: {
wayland-protocols = prev.wayland-protocols.overrideAttrs (self: super: {
version = "1.43";
src = final.fetchurl {
url = "https://gitlab.freedesktop.org/wayland/${self.pname}/-/releases/${self.version}/downloads/${self.pname}-${self.version}.tar.xz";
hash = "sha256-ujw0Jd0nxXtSkek9upe+EkeWAeALyrJNJkcZSMtkNlM=";
};
});
};
} }

View File

@@ -1,13 +1,13 @@
wayland_protos = dependency( wayland_protos = dependency(
'wayland-protocols', 'wayland-protocols',
version: '>=1.43', version: '>=1.32',
fallback: 'wayland-protocols', fallback: 'wayland-protocols',
default_options: ['tests=false'], default_options: ['tests=false'],
) )
hyprland_protos = dependency( hyprland_protos = dependency(
'hyprland-protocols', 'hyprland-protocols',
version: '>=0.6.4', version: '>=0.6',
fallback: 'hyprland-protocols', fallback: 'hyprland-protocols',
) )
@@ -37,7 +37,6 @@ protocols = [
'frog-color-management-v1.xml', 'frog-color-management-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-mapping-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-surface-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-surface-v1.xml',
@@ -71,10 +70,6 @@ protocols = [
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
wayland_protocol_dir / 'staging/security-context/security-context-v1.xml', wayland_protocol_dir / 'staging/security-context/security-context-v1.xml',
wayland_protocol_dir / 'staging/content-type/content-type-v1.xml',
wayland_protocol_dir / 'staging/color-management/color-management-v1.xml',
wayland_protocol_dir / 'staging/xdg-toplevel-tag/xdg-toplevel-tag-v1.xml',
wayland_protocol_dir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml',
] ]
wl_protocols = [] wl_protocols = []
@@ -90,7 +85,7 @@ foreach protocol : protocols
endforeach endforeach
# wayland.xml generation # wayland.xml generation
wayland_scanner = dependency('wayland-scanner', native: true) wayland_scanner = dependency('wayland-scanner')
wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir') wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir')
wayland_xml = wayland_scanner_datadir / 'wayland.xml' wayland_xml = wayland_scanner_datadir / 'wayland.xml'

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,15 @@
#pragma once #pragma once
#include <list>
#include <sys/resource.h> #include <sys/resource.h>
#include "defines.hpp"
#include "managers/XWaylandManager.hpp" #include "managers/XWaylandManager.hpp"
#include "managers/KeybindManager.hpp" #include "managers/KeybindManager.hpp"
#include "managers/SessionLockManager.hpp" #include "managers/SessionLockManager.hpp"
#include "desktop/Window.hpp" #include "desktop/Window.hpp"
#include "protocols/types/ColorManagement.hpp" #include "protocols/types/ColorManagement.hpp"
#include "helpers/memory/Memory.hpp"
#include <aquamarine/backend/Backend.hpp> #include <aquamarine/backend/Backend.hpp>
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
@@ -25,53 +28,55 @@ class CCompositor {
CCompositor(bool onlyConfig = false); CCompositor(bool onlyConfig = false);
~CCompositor(); ~CCompositor();
wl_display* m_wlDisplay = nullptr; wl_display* m_sWLDisplay;
wl_event_loop* m_wlEventLoop = nullptr; wl_event_loop* m_sWLEventLoop;
int m_drmFD = -1; int m_iDRMFD = -1;
bool m_initialized = false; bool m_bInitialized = false;
SP<Aquamarine::CBackend> m_aqBackend; SP<Aquamarine::CBackend> m_pAqBackend;
std::string m_hyprTempDataRoot = ""; std::string m_szHyprTempDataRoot = "";
std::string m_wlDisplaySocket = ""; std::string m_szWLDisplaySocket = "";
std::string m_instanceSignature = ""; std::string m_szInstanceSignature = "";
std::string m_instancePath = ""; std::string m_szInstancePath = "";
std::string m_currentSplash = "error"; std::string m_szCurrentSplash = "error";
std::vector<PHLMONITOR> m_monitors; std::vector<PHLMONITOR> m_vMonitors;
std::vector<PHLMONITOR> m_realMonitors; // for all monitors, even those turned off std::vector<PHLMONITOR> m_vRealMonitors; // for all monitors, even those turned off
std::vector<PHLWINDOW> m_windows; std::vector<PHLWINDOW> m_vWindows;
std::vector<PHLLS> m_layers; std::vector<PHLLS> m_vLayers;
std::vector<PHLWORKSPACE> m_workspaces; std::vector<PHLWORKSPACE> m_vWorkspaces;
std::vector<PHLWINDOWREF> m_windowsFadingOut; std::vector<PHLWINDOWREF> m_vWindowsFadingOut;
std::vector<PHLLSREF> m_surfacesFadingOut; std::vector<PHLLSREF> m_vSurfacesFadingOut;
std::unordered_map<std::string, MONITORID> m_monitorIDMap; std::unordered_map<std::string, MONITORID> m_mMonitorIDMap;
std::unordered_map<std::string, WORKSPACEID> m_seenMonitorWorkspaceMap; // map of seen monitor names to workspace IDs
void initServer(std::string socketName, int socketFd); void initServer(std::string socketName, int socketFd);
void startCompositor(); void startCompositor();
void stopCompositor(); void stopCompositor();
void cleanup(); void cleanup();
void bumpNofile(); void createLockFile();
void restoreNofile(); void removeLockFile();
void bumpNofile();
void restoreNofile();
WP<CWLSurfaceResource> m_lastFocus; WP<CWLSurfaceResource> m_pLastFocus;
PHLWINDOWREF m_lastWindow; PHLWINDOWREF m_pLastWindow;
PHLMONITORREF m_lastMonitor; PHLMONITORREF m_pLastMonitor;
std::vector<PHLWINDOWREF> m_windowFocusHistory; // first element is the most recently focused std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused.
bool m_readyToProcess = false; bool m_bReadyToProcess = false;
bool m_sessionActive = true; bool m_bSessionActive = true;
bool m_dpmsStateOn = true; bool m_bDPMSStateON = true;
bool m_unsafeState = false; // unsafe state is when there is no monitors bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
PHLMONITORREF m_unsafeOutput; // fallback output for the unsafe state bool m_bNextIsUnsafe = false;
bool m_isShuttingDown = false; PHLMONITORREF m_pUnsafeOutput; // fallback output for the unsafe state
bool m_finalRequests = false; bool m_bIsShuttingDown = false;
bool m_desktopEnvSet = false; bool m_bFinalRequests = false;
bool m_wantsXwayland = true; bool m_bDesktopEnvSet = false;
bool m_onlyConfigVerification = false; bool m_bWantsXwayland = true;
bool m_bOnlyConfigVerification = false;
// ------------------------------------------------- // // ------------------------------------------------- //
@@ -81,11 +86,11 @@ class CCompositor {
PHLMONITOR getMonitorFromCursor(); PHLMONITOR getMonitorFromCursor();
PHLMONITOR getMonitorFromVector(const Vector2D&); PHLMONITOR getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(PHLWINDOW); void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr, bool preserveFocusHistory = false); void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr);
void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr); void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr);
bool monitorExists(PHLMONITOR); bool monitorExists(PHLMONITOR);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*, bool aboveLockscreen = false); SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, PHLMONITOR monitor, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, PHLMONITOR monitor, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
@@ -103,8 +108,8 @@ class CCompositor {
void cleanupFadingOut(const MONITORID& monid); void cleanupFadingOut(const MONITORID& monid);
PHLWINDOW getWindowInDirection(PHLWINDOW, char); PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false); PHLWINDOW 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 getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}, bool visible = false);
PHLWINDOW getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool next = false); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}, bool visible = false);
WORKSPACEID getNextAvailableNamedWorkspace(); WORKSPACEID getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr); bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr);
@@ -147,12 +152,12 @@ class CCompositor {
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform); void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates(); void updateSuspendedStates();
void onNewMonitor(SP<Aquamarine::IOutput> output); void onNewMonitor(SP<Aquamarine::IOutput> output);
void ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules, PHLWORKSPACE pWorkspace = nullptr); void ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules);
NColorManagement::SImageDescription getPreferredImageDescription(); SImageDescription getPreferredImageDescription();
bool shouldChangePreferredImageDescription(); bool shouldChangePreferredImageDescription();
std::string m_explicitConfigPath; std::string explicitConfigPath;
private: private:
void initAllSignals(); void initAllSignals();
@@ -161,13 +166,11 @@ class CCompositor {
void setRandomSplash(); void setRandomSplash();
void initManagers(eManagersInitStage stage); void initManagers(eManagersInitStage stage);
void prepareFallbackOutput(); void prepareFallbackOutput();
void createLockFile(); bool isWindowAvailableForCycle(PHLWINDOW pWindow, PHLWINDOW w, bool focusableOnly, std::optional<bool> floating, bool anyWorkspace = false);
void removeLockFile();
void setMallocThreshold();
uint64_t m_hyprlandPID = 0; uint64_t m_iHyprlandPID = 0;
wl_event_source* m_critSigSource = nullptr; wl_event_source* m_critSigSource = nullptr;
rlimit m_originalNofile = {}; rlimit m_sOriginalNofile = {0};
}; };
inline UP<CCompositor> g_pCompositor; inline UP<CCompositor> g_pCompositor;

View File

@@ -2,18 +2,16 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/varlist/VarList.hpp" #include "../helpers/varlist/VarList.hpp"
#include <vector> #include <vector>
#include <map>
enum eConfigValueDataTypes : int8_t { enum eConfigValueDataTypes : int8_t {
CVD_TYPE_INVALID = -1, CVD_TYPE_INVALID = -1,
CVD_TYPE_GRADIENT = 0, CVD_TYPE_GRADIENT = 0,
CVD_TYPE_CSS_VALUE = 1, CVD_TYPE_CSS_VALUE = 1
CVD_TYPE_FONT_WEIGHT = 2,
}; };
class ICustomConfigValueData { class ICustomConfigValueData {
public: public:
virtual ~ICustomConfigValueData() = default; virtual ~ICustomConfigValueData() = 0;
virtual eConfigValueDataTypes getDataType() = 0; virtual eConfigValueDataTypes getDataType() = 0;
@@ -24,7 +22,7 @@ class CGradientValueData : public ICustomConfigValueData {
public: public:
CGradientValueData() = default; CGradientValueData() = default;
CGradientValueData(CHyprColor col) { CGradientValueData(CHyprColor col) {
m_colors.push_back(col); m_vColors.push_back(col);
updateColorsOk(); updateColorsOk();
}; };
virtual ~CGradientValueData() = default; virtual ~CGradientValueData() = default;
@@ -34,39 +32,39 @@ class CGradientValueData : public ICustomConfigValueData {
} }
void reset(CHyprColor col) { void reset(CHyprColor col) {
m_colors.clear(); m_vColors.clear();
m_colors.emplace_back(col); m_vColors.emplace_back(col);
m_angle = 0; m_fAngle = 0;
updateColorsOk(); updateColorsOk();
} }
void updateColorsOk() { void updateColorsOk() {
m_colorsOkLabA.clear(); m_vColorsOkLabA.clear();
for (auto& c : m_colors) { for (auto& c : m_vColors) {
const auto OKLAB = c.asOkLab(); const auto OKLAB = c.asOkLab();
m_colorsOkLabA.emplace_back(OKLAB.l); m_vColorsOkLabA.emplace_back(OKLAB.l);
m_colorsOkLabA.emplace_back(OKLAB.a); m_vColorsOkLabA.emplace_back(OKLAB.a);
m_colorsOkLabA.emplace_back(OKLAB.b); m_vColorsOkLabA.emplace_back(OKLAB.b);
m_colorsOkLabA.emplace_back(c.a); m_vColorsOkLabA.emplace_back(c.a);
} }
} }
/* Vector containing the colors */ /* Vector containing the colors */
std::vector<CHyprColor> m_colors; std::vector<CHyprColor> m_vColors;
/* Vector containing pure colors for shoving into opengl */ /* Vector containing pure colors for shoving into opengl */
std::vector<float> m_colorsOkLabA; std::vector<float> m_vColorsOkLabA;
/* Float corresponding to the angle (rad) */ /* Float corresponding to the angle (rad) */
float m_angle = 0; float m_fAngle = 0;
// //
bool operator==(const CGradientValueData& other) const { bool operator==(const CGradientValueData& other) const {
if (other.m_colors.size() != m_colors.size() || m_angle != other.m_angle) if (other.m_vColors.size() != m_vColors.size() || m_fAngle != other.m_fAngle)
return false; return false;
for (size_t i = 0; i < m_colors.size(); ++i) for (size_t i = 0; i < m_vColors.size(); ++i)
if (m_colors[i] != other.m_colors[i]) if (m_vColors[i] != other.m_vColors[i])
return false; return false;
return true; return true;
@@ -74,28 +72,28 @@ class CGradientValueData : public ICustomConfigValueData {
virtual std::string toString() { virtual std::string toString() {
std::string result; std::string result;
for (auto& c : m_colors) { for (auto& c : m_vColors) {
result += std::format("{:x} ", c.getAsHex()); result += std::format("{:x} ", c.getAsHex());
} }
result += std::format("{}deg", (int)(m_angle * 180.0 / M_PI)); result += std::format("{}deg", (int)(m_fAngle * 180.0 / M_PI));
return result; return result;
} }
}; };
class CCssGapData : public ICustomConfigValueData { class CCssGapData : public ICustomConfigValueData {
public: public:
CCssGapData() : m_top(0), m_right(0), m_bottom(0), m_left(0) {}; CCssGapData() : top(0), right(0), bottom(0), left(0) {};
CCssGapData(int64_t global) : m_top(global), m_right(global), m_bottom(global), m_left(global) {}; CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global) {};
CCssGapData(int64_t vertical, int64_t horizontal) : m_top(vertical), m_right(horizontal), m_bottom(vertical), m_left(horizontal) {}; CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal) {};
CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : m_top(top), m_right(horizontal), m_bottom(bottom), m_left(horizontal) {}; CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : top(top), right(horizontal), bottom(bottom), left(horizontal) {};
CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : m_top(top), m_right(right), m_bottom(bottom), m_left(left) {}; CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : top(top), right(right), bottom(bottom), left(left) {};
/* Css like directions */ /* Css like directions */
int64_t m_top; int64_t top;
int64_t m_right; int64_t right;
int64_t m_bottom; int64_t bottom;
int64_t m_left; int64_t left;
void parseGapData(CVarList varlist) { void parseGapData(CVarList varlist) {
switch (varlist.size()) { switch (varlist.size()) {
@@ -124,10 +122,10 @@ class CCssGapData : public ICustomConfigValueData {
} }
void reset(int64_t global) { void reset(int64_t global) {
m_top = global; top = global;
m_right = global; right = global;
m_bottom = global; bottom = global;
m_left = global; left = global;
} }
virtual eConfigValueDataTypes getDataType() { virtual eConfigValueDataTypes getDataType() {
@@ -135,44 +133,6 @@ class CCssGapData : public ICustomConfigValueData {
} }
virtual std::string toString() { virtual std::string toString() {
return std::format("{} {} {} {}", m_top, m_right, m_bottom, m_left); return std::format("{} {} {} {}", top, right, bottom, left);
}
};
class CFontWeightConfigValueData : public ICustomConfigValueData {
public:
CFontWeightConfigValueData() = default;
CFontWeightConfigValueData(const char* weight) {
parseWeight(weight);
}
int64_t m_value = 400; // default to normal weight
virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_FONT_WEIGHT;
}
virtual std::string toString() {
return std::format("{}", m_value);
}
void parseWeight(const std::string& strWeight) {
auto lcWeight{strWeight};
transform(strWeight.begin(), strWeight.end(), lcWeight.begin(), ::tolower);
// values taken from Pango weight enums
const auto WEIGHTS = std::map<std::string, int>{
{"thin", 100}, {"ultralight", 200}, {"light", 300}, {"semilight", 350}, {"book", 380}, {"normal", 400},
{"medium", 500}, {"semibold", 600}, {"bold", 700}, {"ultrabold", 800}, {"heavy", 900}, {"ultraheavy", 1000},
};
auto weight = WEIGHTS.find(lcWeight);
if (weight != WEIGHTS.end())
m_value = weight->second;
else {
int w_i = std::stoi(strWeight);
if (w_i < 100 || w_i > 1000)
m_value = 400;
}
} }
}; };

View File

@@ -247,110 +247,104 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_STRING_LONG, .type = CONFIG_OPTION_STRING_LONG,
.data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
}, },
SConfigOptionDescription{
.value = "decoration:border_part_of_window",
.description = "whether the border should be treated as a part of the window.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
/* /*
* blur: * blur:
*/ */
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:enabled", .value = "blur:enabled",
.description = "enable kawase window background blur", .description = "enable kawase window background blur",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:size", .value = "blur:size",
.description = "blur size (distance)", .description = "blur size (distance)",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{8, 0, 100}, .data = SConfigOptionDescription::SRangeData{8, 0, 100},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:passes", .value = "blur:passes",
.description = "the amount of passes to perform", .description = "the amount of passes to perform",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 10}, .data = SConfigOptionDescription::SRangeData{1, 0, 10},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:ignore_opacity", .value = "blur:ignore_opacity",
.description = "make the blur layer ignore the opacity of the window", .description = "make the blur layer ignore the opacity of the window",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:new_optimizations", .value = "blur:new_optimizations",
.description = "whether to enable further optimizations to the blur. Recommended to leave on, as it will massively improve performance.", .description = "whether to enable further optimizations to the blur. Recommended to leave on, as it will massively improve performance.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:xray", .value = "blur:xray",
.description = "if enabled, floating windows will ignore tiled windows in their blur. Only available if blur_new_optimizations is true. Will reduce overhead on floating " .description = "if enabled, floating windows will ignore tiled windows in their blur. Only available if blur_new_optimizations is true. Will reduce overhead on floating "
"blur significantly.", "blur significantly.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:noise", .value = "blur:noise",
.description = "how much noise to apply. [0.0 - 1.0]", .description = "how much noise to apply. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.0117, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.0117, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:contrast", .value = "blur:contrast",
.description = "contrast modulation for blur. [0.0 - 2.0]", .description = "contrast modulation for blur. [0.0 - 2.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.8916, 0, 2}, .data = SConfigOptionDescription::SFloatData{0.8916, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:brightness", .value = "blur:brightness",
.description = "brightness modulation for blur. [0.0 - 2.0]", .description = "brightness modulation for blur. [0.0 - 2.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.8172, 0, 2}, .data = SConfigOptionDescription::SFloatData{0.8172, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:vibrancy", .value = "blur:vibrancy",
.description = "Increase saturation of blurred colors. [0.0 - 1.0]", .description = "Increase saturation of blurred colors. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.1696, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.1696, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:vibrancy_darkness", .value = "blur:vibrancy_darkness",
.description = "How strong the effect of vibrancy is on dark areas . [0.0 - 1.0]", .description = "How strong the effect of vibrancy is on dark areas . [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0, 0, 1}, .data = SConfigOptionDescription::SFloatData{0, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:special", .value = "blur:special",
.description = "whether to blur behind the special workspace (note: expensive)", .description = "whether to blur behind the special workspace (note: expensive)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:popups", .value = "blur:popups",
.description = "whether to blur popups (e.g. right-click menus)", .description = "whether to blur popups (e.g. right-click menus)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:popups_ignorealpha", .value = "blur:popups_ignorealpha",
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]", .description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:input_methods", .value = "blur:input_methods",
.description = "whether to blur input methods (e.g. fcitx5)", .description = "whether to blur input methods (e.g. fcitx5)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:input_methods_ignorealpha", .value = "blur:input_methods_ignorealpha",
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]", .description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
@@ -372,12 +366,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "animations:workspace_wraparound",
.description = "changes the direction of slide animations between the first and last workspaces",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
/* /*
* input: * input:
@@ -513,12 +501,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 3}, .data = SConfigOptionDescription::SRangeData{1, 0, 3},
}, },
SConfigOptionDescription{
.value = "input:follow_mouse_threshold",
.description = "The smallest distance in logical pixels the mouse needs to travel for the window under it to get focused. Works only with follow_mouse = 1.",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "input:focus_on_close", .value = "input:focus_on_close",
.description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift " .description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift "
@@ -620,18 +602,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "input:touchpad:flip_x",
.description = "Inverts the horizontal movement of the touchpad",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "input:touchpad:flip_y",
.description = "Inverts the vertical movement of the touchpad",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* input:touchdevice: * input:touchdevice:
@@ -839,25 +809,25 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_active", .value = "general:col.border_active",
.description = "border color for inactive windows", .description = "border color for inactive windows",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66ffff00"}, .data = SConfigOptionDescription::SGradientData{"0x66ffff00"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_inactive", .value = "general:col.border_inactive",
.description = "border color for the active window", .description = "border color for the active window",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66777700"}, .data = SConfigOptionDescription::SGradientData{"0x66777700"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_locked_inactive", .value = "general:col.border_locked_active",
.description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)", .description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66ff5500"}, .data = SConfigOptionDescription::SGradientData{"0x66ff5500"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_locked_active", .value = "general:col.border_locked_inactive",
.description = "active border color for window that cannot be added to a group", .description = "active border color for window that cannot be added to a group",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66775500"}, .data = SConfigOptionDescription::SGradientData{"0x66775500"},
@@ -903,18 +873,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_STRING_SHORT, .type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET? .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET?
}, },
SConfigOptionDescription{
.value = "group:groupbar:font_weight_active",
.description = "weight of the font used to display active groupbar titles",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"normal"},
},
SConfigOptionDescription{
.value = "group:groupbar:font_weight_inactive",
.description = "weight of the font used to display inactive groupbar titles",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"normal"},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:font_size", .value = "group:groupbar:font_size",
.description = "font size of groupbar title", .description = "font size of groupbar title",
@@ -925,7 +883,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "group:groupbar:gradients", .value = "group:groupbar:gradients",
.description = "enables gradients", .description = "enables gradients",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:height", .value = "group:groupbar:height",
@@ -933,18 +891,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{14, 1, 64}, .data = SConfigOptionDescription::SRangeData{14, 1, 64},
}, },
SConfigOptionDescription{
.value = "group:groupbar:indicator_gap",
.description = "height of the gap between the groupbar indicator and title",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{0, 0, 64},
},
SConfigOptionDescription{
.value = "group:groupbar:indicator_height",
.description = "height of the groupbar indicator",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{3, 1, 64},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:stacked", .value = "group:groupbar:stacked",
.description = "render the groupbar as a vertical stack", .description = "render the groupbar as a vertical stack",
@@ -969,30 +915,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "group:groupbar:rounding",
.description = "how much to round the groupbar",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:gradient_rounding",
.description = "how much to round the groupbar gradient",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:round_only_edges",
.description = "if yes, will only round at the groupbar edges",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:groupbar:gradient_round_only_edges",
.description = "if yes, will only round at the groupbar gradient edges",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:text_color", .value = "group:groupbar:text_color",
.description = "controls the group bar text color", .description = "controls the group bar text color",
@@ -1023,30 +945,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_COLOR, .type = CONFIG_OPTION_COLOR,
.data = SConfigOptionDescription::SColorData{0x66775500}, .data = SConfigOptionDescription::SColorData{0x66775500},
}, },
SConfigOptionDescription{
.value = "group:groupbar:gaps_out",
.description = "gap between gradients and window",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:gaps_in",
.description = "gap between gradients",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:keep_upper_gap",
.description = "keep an upper gap above gradient",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:groupbar:text_offset",
.description = "set an offset for a text",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SRangeData{0, -20, 20},
},
/* /*
* misc: * misc:
@@ -1096,9 +994,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "misc:vrr", .value = "misc:vrr",
.description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only, 3 - fullscreen with game or video content type [0/1/2/3]", .description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only [0/1/2]",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 3}, .data = SConfigOptionDescription::SRangeData{0, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "misc:mouse_move_enables_dpms", .value = "misc:mouse_move_enables_dpms",
@@ -1253,18 +1151,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1000, 0, 5000}, .data = SConfigOptionDescription::SRangeData{1000, 0, 5000},
}, },
SConfigOptionDescription{
.value = "misc:enable_anr_dialog",
.description = "whether to enable the ANR (app not responding) dialog when your apps hang",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "misc:anr_missed_pings",
.description = "number of missed pings before showing the ANR dialog",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 1, 10},
},
/* /*
* binds: * binds:
@@ -1288,12 +1174,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "binds:hide_special_on_workspace_change",
.description = "If enabled, changing the active workspace (including to itself) will hide the special workspace on the monitor where the newly active workspace resides.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "binds:allow_workspace_cycles", .value = "binds:allow_workspace_cycles",
.description = "If enabled, workspaces dont forget their previous workspace, so cycles can be created by switching to the first workspace in a sequence, then endlessly " .description = "If enabled, workspaces dont forget their previous workspace, so cycles can be created by switching to the first workspace in a sequence, then endlessly "
@@ -1324,7 +1204,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "binds:movefocus_cycles_fullscreen", .value = "binds:movefocus_cycles_fullscreen",
.description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.", .description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "binds:movefocus_cycles_groupfirst", .value = "binds:movefocus_cycles_groupfirst",
@@ -1350,12 +1230,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "binds:drag_threshold",
.description = "Movement threshold in pixels for window dragging and c/g bind flags. 0 to disable and grab on mousedown.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{0, 0, INT_MAX},
},
/* /*
* xwayland: * xwayland:
@@ -1379,12 +1253,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "xwayland:create_abstract_socket",
.description = "Create the abstract Unix domain socket for XWayland",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* opengl: * opengl:
@@ -1396,6 +1264,13 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "opengl:force_introspection",
.description = "forces introspection at all times. Introspection is aimed at reducing GPU usage in certain cases, but might cause graphical glitches on nvidia. 0 - "
"nothing, 1 - force always on, 2 - force always on if nvidia",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 2},
},
/* /*
* render: * render:
@@ -1416,9 +1291,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
SConfigOptionDescription{ SConfigOptionDescription{
.value = "render:direct_scanout", .value = "render:direct_scanout",
.description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also " .description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also "
"recommended to set this to false if the fullscreen application shows graphical glitches. 0 - off, 1 - on, 2 - auto (on with content type 'game')", "recommended to set this to false if the fullscreen application shows graphical glitches.",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 2}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "render:expand_undersized_textures", .value = "render:expand_undersized_textures",
@@ -1439,20 +1314,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SRangeData{2, 0, 2}, .data = SConfigOptionDescription::SRangeData{2, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "render:cm_fs_passthrough", .value = "render:allow_early_buffer_release",
.description = "Passthrough color settings for fullscreen apps when possible", .description = "Allow early buffer release event. Fixes stuttering and missing frames for some apps. May cause graphical glitches and memory leaks in others",
.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},
},
SConfigOptionDescription{
.value = "render:send_content_type",
.description = "Report content type to allow monitor profile autoswitch (may result in a black screen during the switch)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
@@ -1461,18 +1324,24 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
* cursor: * cursor:
*/ */
SConfigOptionDescription{
.value = "cursor:use_nearest_neighbor",
.description = "sync xcursor theme with gsettings, it applies cursor-theme and cursor-size on theme load to gsettings making most CSD gtk based clients use same xcursor "
"theme and size.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_hardware_cursors", .value = "cursor:no_hardware_cursors",
.description = "disables hardware cursors. Auto = disable when tearing", .description = "disables hardware cursors",
.type = CONFIG_OPTION_CHOICE, .type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"}, .data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_break_fs_vrr", .value = "cursor:no_break_fs_vrr",
.description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (may require no_hardware_cursors = true) " .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)",
"0 - off, 1 - on, 2 - auto (on with content type 'game')", .type = CONFIG_OPTION_BOOL,
.type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SBoolData{false},
.data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:min_refresh_rate", .value = "cursor:min_refresh_rate",
@@ -1510,13 +1379,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_CHOICE, .type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"}, .data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"},
}, },
SConfigOptionDescription{
.value = "cursor:warp_on_toggle_special",
.description = "Move the cursor to the last focused window when toggling a special workspace. Options: 0 (Disabled), 1 (Enabled), "
"2 (Force - ignores cursor:no_warps option)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:default_monitor", .value = "cursor:default_monitor",
.description = "the name of a default monitor for the cursor to be set to on startup (see hyprctl monitors for names)", .description = "the name of a default monitor for the cursor to be set to on startup (see hyprctl monitors for names)",
@@ -1559,35 +1421,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "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: * debug:
@@ -1641,6 +1474,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "debug:watchdog_timeout",
.description = "sets the timeout in seconds for watchdog to abort processing of a signal of the main thread. Set to 0 to disable.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{5, 0, 20},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "debug:disable_scale_checks", .value = "debug:disable_scale_checks",
.description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.", .description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.",
@@ -1665,24 +1504,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "debug:log_damage",
.description = "enables logging the damage.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "debug:pass",
.description = "enables render pass debugging.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "debug:full_cm_proto",
.description = "claims support for all cm proto features (requires restart)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* dwindle: * dwindle:
@@ -1817,10 +1638,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 10}, //##TODO RANGE? .data = SConfigOptionDescription::SRangeData{2, 0, 10}, //##TODO RANGE?
}, },
SConfigOptionDescription{.value = "master:center_master_fallback", SConfigOptionDescription{
.description = "Set fallback for center master when slaves are less than slave_count_for_center_master, can be left ,right ,top ,bottom", .value = "master:center_master_slaves_on_right",
.type = CONFIG_OPTION_STRING_SHORT, .description = "set if the slaves should appear on right of master when slave_count_for_center_master > 2",
.data = SConfigOptionDescription::SStringData{"left"}}, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "master:center_ignores_reserved", .value = "master:center_ignores_reserved",
.description = "centers the master window on monitor ignoring reserved areas", .description = "centers the master window on monitor ignoring reserved areas",
@@ -1841,16 +1664,22 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "experimental:wide_color_gamut",
.description = "force wide color gamut for all supported outputs",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "experimental:hdr",
.description = "force static hdr for all supported outputs",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "experimental:xx_color_management_v4", .value = "experimental:xx_color_management_v4",
.description = "enable color management protocol", .description = "enable color management protocol",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "master:always_keep_position",
.description = "whether to keep the master window in its configured position when there are no slave windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -138,37 +138,6 @@ struct SFirstExecRequest {
bool withRules = false; bool withRules = false;
}; };
struct SFloatCache {
size_t hash;
SFloatCache(PHLWINDOW window, bool initial) {
// Base hash from class/title
size_t baseHash = initial ? (std::hash<std::string>{}(window->m_initialClass) ^ (std::hash<std::string>{}(window->m_initialTitle) << 1)) :
(std::hash<std::string>{}(window->m_class) ^ (std::hash<std::string>{}(window->m_title) << 1));
// Use empty string as default tag value
std::string tagValue = "";
if (auto xdgTag = window->xdgTag())
tagValue = xdgTag.value();
// Combine hashes
hash = baseHash ^ (std::hash<std::string>{}(tagValue) << 2);
}
bool operator==(const SFloatCache& other) const {
return hash == other.hash;
}
};
namespace std {
template <>
struct hash<SFloatCache> {
size_t operator()(const SFloatCache& id) const {
return id.hash;
}
};
}
class CConfigManager { class CConfigManager {
public: public:
CConfigManager(); CConfigManager();
@@ -220,7 +189,7 @@ class CConfigManager {
void ensureMonitorStatus(); void ensureMonitorStatus();
void ensureVRR(PHLMONITOR pMonitor = nullptr); void ensureVRR(PHLMONITOR pMonitor = nullptr);
bool shouldUseSoftwareCursors(PHLMONITOR pMonitor); bool shouldUseSoftwareCursors();
void updateWatcher(); void updateWatcher();
std::string parseKeyword(const std::string&, const std::string&); std::string parseKeyword(const std::string&, const std::string&);
@@ -235,89 +204,107 @@ class CConfigManager {
std::string getErrors(); std::string getErrors();
// keywords // keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&); std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExec(const std::string&, const std::string&); std::optional<std::string> handleExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&); std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleExecRawOnce(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> handleExecShutdown(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&); std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&); std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&); std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&); std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&); std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&); std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&); std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&); std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&); std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&); std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&); std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&); std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&); std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&); std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePermission(const std::string&, const std::string&); std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::string m_configCurrentPath; std::string configCurrentPath;
bool m_wantsMonitorReload = false; std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> mbWindowProperties = {
bool m_noMonitorReload = false; {"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
bool m_isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking {"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.dimAround; }},
bool m_lastConfigVerificationWasSuccessful = true; {"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }},
};
void storeFloatingSize(PHLWINDOW window, const Vector2D& size); std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> miWindowProperties = {
std::optional<Vector2D> getStoredFloatingSize(PHLWINDOW window); {"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 = {
{"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; }}};
bool m_bWantsMonitorReload = false;
bool m_bNoMonitorReload = false;
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
bool m_bLastConfigVerificationWasSuccessful = true;
private: private:
UP<Hyprlang::CConfig> m_config; UP<Hyprlang::CConfig> m_pConfig;
std::vector<std::string> m_configPaths; std::vector<std::string> m_configPaths;
Hyprutils::Animation::CAnimationConfigTree m_animationTree; Hyprutils::Animation::CAnimationConfigTree m_AnimationTree;
std::string m_currentSubmap = ""; // For storing the current keybind submap std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
std::vector<SExecRequestedRule> m_execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
std::vector<std::string> m_declaredPlugins; std::vector<std::string> m_vDeclaredPlugins;
std::vector<SPluginKeyword> m_pluginKeywords; std::vector<SPluginKeyword> pluginKeywords;
std::vector<SPluginVariable> m_pluginVariables; std::vector<SPluginVariable> pluginVariables;
bool m_isFirstLaunch = true; // For exec-once bool isFirstLaunch = true; // For exec-once
std::vector<SMonitorRule> m_monitorRules; std::vector<SMonitorRule> m_vMonitorRules;
std::vector<SWorkspaceRule> m_workspaceRules; std::vector<SWorkspaceRule> m_vWorkspaceRules;
std::vector<SP<CWindowRule>> m_windowRules; std::vector<SP<CWindowRule>> m_vWindowRules;
std::vector<SP<CLayerRule>> m_layerRules; std::vector<SP<CLayerRule>> m_vLayerRules;
std::vector<std::string> m_blurLSNamespaces; std::vector<std::string> m_dBlurLSNamespaces;
bool m_firstExecDispatched = false; bool firstExecDispatched = false;
bool m_manualCrashInitiated = false; bool m_bManualCrashInitiated = false;
std::vector<SFirstExecRequest> m_firstExecRequests; // bool is for if with rules std::vector<SFirstExecRequest> firstExecRequests; // bool is for if with rules
std::vector<std::string> m_finalExecRequests; std::vector<std::string> finalExecRequests;
std::vector<std::pair<std::string, std::string>> m_failedPluginConfigValues; // for plugin values of unloaded plugins std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_configErrors = ""; std::string m_szConfigErrors = "";
uint32_t m_configValueNumber = 0;
// internal methods // internal methods
void updateBlurredLS(const std::string&, const bool); void updateBlurredLS(const std::string&, const bool);
void setDefaultAnimationVars(); void setDefaultAnimationVars();
std::optional<std::string> resetHLConfig(); std::optional<std::string> resetHLConfig();
std::optional<std::string> generateConfig(std::string configPath); std::optional<std::string> generateConfig(std::string configPath);
std::optional<std::string> verifyConfigExists(); std::optional<std::string> verifyConfigExists();
void postConfigReload(const Hyprlang::CParseResult& result); void postConfigReload(const Hyprlang::CParseResult& result);
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); 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 UP<CConfigManager> g_pConfigManager; inline UP<CConfigManager> g_pConfigManager;

View File

@@ -1,15 +0,0 @@
#include "ConfigValue.hpp"
#include "ConfigManager.hpp"
#include "../macros.hpp"
void local__configValuePopulate(void* const** p, const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
*p = PVHYPRLANG->getDataStaticPtr();
}
std::type_index local__configValueTypeIdx(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
const auto ANY = PVHYPRLANG->getValue();
return std::type_index(ANY.type());
}

View File

@@ -4,19 +4,21 @@
#include <typeindex> #include <typeindex>
#include <hyprlang.hpp> #include <hyprlang.hpp>
#include "../macros.hpp" #include "../macros.hpp"
#include "ConfigManager.hpp"
// giga hack to avoid including configManager here
// NOLINTNEXTLINE
void local__configValuePopulate(void* const** p, const std::string& val);
std::type_index local__configValueTypeIdx(const std::string& val);
template <typename T> template <typename T>
class CConfigValue { class CConfigValue {
public: public:
CConfigValue(const std::string& val) { CConfigValue(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
// NOLINTNEXTLINE
p_ = PVHYPRLANG->getDataStaticPtr();
#ifdef HYPRLAND_DEBUG #ifdef HYPRLAND_DEBUG
// verify type // verify type
const auto TYPE = local__configValueTypeIdx(val); const auto ANY = PVHYPRLANG->getValue();
const auto TYPE = std::type_index(ANY.type());
// exceptions // exceptions
const bool STRINGEX = (typeid(T) == typeid(std::string) && TYPE == typeid(Hyprlang::STRING)); const bool STRINGEX = (typeid(T) == typeid(std::string) && TYPE == typeid(Hyprlang::STRING));
@@ -24,8 +26,6 @@ class CConfigValue {
RASSERT(typeid(T) == TYPE || STRINGEX || CUSTOMEX, "Mismatched type in CConfigValue<T>, got {} but has {}", typeid(T).name(), TYPE.name()); RASSERT(typeid(T) == TYPE || STRINGEX || CUSTOMEX, "Mismatched type in CConfigValue<T>, got {} but has {}", typeid(T).name(), TYPE.name());
#endif #endif
local__configValuePopulate(&p_, val);
} }
T* ptr() const { T* ptr() const {

View File

@@ -4,26 +4,28 @@
#include <ranges> #include <ranges>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <filesystem>
using namespace Hyprutils::OS;
CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) { CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) {
if (!m_inotifyFd.isValid()) { if (m_inotifyFd < 0) {
Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded"); Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded");
return; return;
} }
// TODO: make CFileDescriptor take F_GETFL, F_SETFL const int FLAGS = fcntl(m_inotifyFd, F_GETFL, 0);
const int FLAGS = fcntl(m_inotifyFd.get(), F_GETFL, 0); if (fcntl(m_inotifyFd, F_SETFL, FLAGS | O_NONBLOCK) < 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"); Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded");
m_inotifyFd.reset(); close(m_inotifyFd);
m_inotifyFd = -1;
return; return;
} }
} }
CFileDescriptor& CConfigWatcher::getInotifyFD() { CConfigWatcher::~CConfigWatcher() {
if (m_inotifyFd >= 0)
close(m_inotifyFd);
}
int CConfigWatcher::getInotifyFD() {
return m_inotifyFd; return m_inotifyFd;
} }
@@ -36,7 +38,7 @@ void CConfigWatcher::setWatchList(const std::vector<std::string>& paths) {
// cleanup old paths // cleanup old paths
for (auto& watch : m_watches) { for (auto& watch : m_watches) {
inotify_rm_watch(m_inotifyFd.get(), watch.wd); inotify_rm_watch(m_inotifyFd, watch.wd);
} }
m_watches.clear(); m_watches.clear();
@@ -44,19 +46,9 @@ void CConfigWatcher::setWatchList(const std::vector<std::string>& paths) {
// add new paths // add new paths
for (const auto& path : paths) { for (const auto& path : paths) {
m_watches.emplace_back(SInotifyWatch{ m_watches.emplace_back(SInotifyWatch{
.wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY | IN_DONT_FOLLOW), .wd = inotify_add_watch(m_inotifyFd, path.c_str(), IN_MODIFY),
.file = path, .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,
});
}
} }
} }
@@ -66,7 +58,7 @@ void CConfigWatcher::setOnChange(const std::function<void(const SConfigWatchEven
void CConfigWatcher::onInotifyEvent() { void CConfigWatcher::onInotifyEvent() {
inotify_event ev; inotify_event ev;
while (read(m_inotifyFd.get(), &ev, sizeof(ev)) > 0) { while (read(m_inotifyFd, &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; }); 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()) { if (WD == m_watches.end()) {

View File

@@ -3,21 +3,20 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <functional> #include <functional>
#include <hyprutils/os/FileDescriptor.hpp>
class CConfigWatcher { class CConfigWatcher {
public: public:
CConfigWatcher(); CConfigWatcher();
~CConfigWatcher() = default; ~CConfigWatcher();
struct SConfigWatchEvent { struct SConfigWatchEvent {
std::string file; std::string file;
}; };
Hyprutils::OS::CFileDescriptor& getInotifyFD(); int getInotifyFD();
void setWatchList(const std::vector<std::string>& paths); void setWatchList(const std::vector<std::string>& paths);
void setOnChange(const std::function<void(const SConfigWatchEvent&)>& fn); void setOnChange(const std::function<void(const SConfigWatchEvent&)>& fn);
void onInotifyEvent(); void onInotifyEvent();
private: private:
struct SInotifyWatch { struct SInotifyWatch {
@@ -27,7 +26,7 @@ class CConfigWatcher {
std::function<void(const SConfigWatchEvent&)> m_watchCallback; std::function<void(const SConfigWatchEvent&)> m_watchCallback;
std::vector<SInotifyWatch> m_watches; std::vector<SInotifyWatch> m_watches;
Hyprutils::OS::CFileDescriptor m_inotifyFd; int m_inotifyFd = -1;
}; };
inline UP<CConfigWatcher> g_pConfigWatcher = makeUnique<CConfigWatcher>(); inline UP<CConfigWatcher> g_pConfigWatcher = makeUnique<CConfigWatcher>();

View File

@@ -65,23 +65,6 @@ env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24 env = HYPRCURSOR_SIZE,24
###################
### PERMISSIONS ###
###################
# See https://wiki.hyprland.org/Configuring/Permissions/
# Please note permission changes here require a Hyprland restart and are not applied on-the-fly
# for security reasons
# ecosystem {
# enforce_permissions = 1
# }
# permission = /usr/(bin|local/bin)/grim, screencopy, allow
# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow
##################### #####################
### LOOK AND FEEL ### ### LOOK AND FEEL ###
##################### #####################
@@ -169,10 +152,10 @@ animations {
# uncomment all if you wish to use that. # uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] # windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrule = rounding 0, floating:0, onworkspace:w[tv1] # windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrule = bordersize 0, floating:0, onworkspace:f[1] # windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrule = rounding 0, floating:0, onworkspace:f[1] # windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
@@ -286,12 +269,12 @@ bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness # Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+ bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%- bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl # Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next bindl = , XF86AudioNext, exec, playerctl next
@@ -306,12 +289,15 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules # See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule # Example windowrule v1
# windowrule = float,class:^(kitty)$,title:^(kitty)$ # windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.* windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland # Fix some dragging issues with XWayland
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
)#"; )#";

View File

@@ -130,11 +130,11 @@ void NCrashReporter::createAndSaveCrash(int sig) {
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
auto p = plugins[i]; auto p = plugins[i];
finalCrashReport += '\t'; finalCrashReport += '\t';
finalCrashReport += p->m_name; finalCrashReport += p->name;
finalCrashReport += " ("; finalCrashReport += " (";
finalCrashReport += p->m_author; finalCrashReport += p->author;
finalCrashReport += ") "; finalCrashReport += ") ";
finalCrashReport += p->m_version; finalCrashReport += p->version;
finalCrashReport += '\n'; finalCrashReport += '\n';
} }
@@ -192,7 +192,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
#endif #endif
}; };
u_int miblen = sizeof(mib) / sizeof(mib[0]); u_int miblen = sizeof(mib) / sizeof(mib[0]);
char exe[PATH_MAX] = "/nonexistent"; char exe[PATH_MAX] = "";
size_t sz = sizeof(exe); size_t sz = sizeof(exe);
sysctl(mib, miblen, &exe, &sz, NULL, 0); sysctl(mib, miblen, &exe, &sz, NULL, 0);
const auto FPATH = std::filesystem::canonical(exe); const auto FPATH = std::filesystem::canonical(exe);
@@ -242,5 +242,5 @@ void NCrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "\n\nLog tail:\n"; finalCrashReport += "\n\nLog tail:\n";
finalCrashReport += std::string_view(Debug::m_rollingLog).substr(Debug::m_rollingLog.find('\n') + 1); finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find('\n') + 1);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -2,11 +2,8 @@
#include <fstream> #include <fstream>
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#include "../helpers/defer/Promise.hpp"
#include "../desktop/Window.hpp" #include "../desktop/Window.hpp"
#include <functional> #include <functional>
#include <sys/types.h>
#include <hyprutils/os/FileDescriptor.hpp>
// exposed for main.cpp // exposed for main.cpp
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request);
@@ -17,19 +14,17 @@ class CHyprCtl {
CHyprCtl(); CHyprCtl();
~CHyprCtl(); ~CHyprCtl();
std::string makeDynamicCall(const std::string& input); std::string makeDynamicCall(const std::string& input);
SP<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd); SP<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd);
void unregisterCommand(const SP<SHyprCtlCommand>& cmd); void unregisterCommand(const SP<SHyprCtlCommand>& cmd);
std::string getReply(std::string); std::string getReply(std::string);
Hyprutils::OS::CFileDescriptor m_socketFD; int m_iSocketFD = -1;
struct { struct {
bool all = false; bool all = false;
bool sysInfoConfig = false; bool sysInfoConfig = false;
pid_t pid = 0; } m_sCurrentRequestParams;
SP<CPromise<std::string>> pendingPromise;
} m_currentRequestParams;
static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format); static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format);
static std::string getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format); static std::string getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format);
@@ -38,7 +33,7 @@ class CHyprCtl {
private: private:
void startHyprCtlSocket(); void startHyprCtlSocket();
std::vector<SP<SHyprCtlCommand>> m_commands; std::vector<SP<SHyprCtlCommand>> m_vCommands;
wl_event_source* m_eventSource = nullptr; wl_event_source* m_eventSource = nullptr;
std::string m_socketPath; std::string m_socketPath;
}; };

View File

@@ -7,7 +7,7 @@
#include "../managers/AnimationManager.hpp" #include "../managers/AnimationManager.hpp"
CHyprDebugOverlay::CHyprDebugOverlay() { CHyprDebugOverlay::CHyprDebugOverlay() {
m_texture = makeShared<CTexture>(); m_pTexture = makeShared<CTexture>();
} }
void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
@@ -16,13 +16,13 @@ void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs)
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_lastRenderTimes.emplace_back(durationUs / 1000.f); m_dLastRenderTimes.emplace_back(durationUs / 1000.f);
if (m_lastRenderTimes.size() > (long unsigned int)pMonitor->m_refreshRate) if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
m_lastRenderTimes.pop_front(); m_dLastRenderTimes.pop_front();
if (!m_monitor) if (!m_pMonitor)
m_monitor = pMonitor; m_pMonitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
@@ -31,13 +31,13 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float du
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_lastRenderTimesNoOverlay.emplace_back(durationUs / 1000.f); m_dLastRenderTimesNoOverlay.emplace_back(durationUs / 1000.f);
if (m_lastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->m_refreshRate) if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
m_lastRenderTimesNoOverlay.pop_front(); m_dLastRenderTimesNoOverlay.pop_front();
if (!m_monitor) if (!m_pMonitor)
m_monitor = pMonitor; m_pMonitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) { void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
@@ -46,36 +46,36 @@ void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_lastFrametimes.emplace_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_lastFrame).count() / 1000.f); m_dLastFrametimes.emplace_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
if (m_lastFrametimes.size() > (long unsigned int)pMonitor->m_refreshRate) if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate)
m_lastFrametimes.pop_front(); m_dLastFrametimes.pop_front();
m_lastFrame = std::chrono::high_resolution_clock::now(); m_tpLastFrame = std::chrono::high_resolution_clock::now();
if (!m_monitor) if (!m_pMonitor)
m_monitor = pMonitor; m_pMonitor = pMonitor;
// anim data too // anim data too
const auto PMONITORFORTICKS = g_pHyprRenderer->m_mostHzMonitor ? g_pHyprRenderer->m_mostHzMonitor.lock() : g_pCompositor->m_lastMonitor.lock(); const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor.lock() : g_pCompositor->m_pLastMonitor.lock();
if (PMONITORFORTICKS) { if (PMONITORFORTICKS) {
if (m_lastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->m_refreshRate) if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate)
m_lastAnimationTicks.pop_front(); m_dLastAnimationTicks.pop_front();
m_lastAnimationTicks.push_back(g_pAnimationManager->m_lastTickTimeMs); m_dLastAnimationTicks.push_back(g_pAnimationManager->m_fLastTickTime);
} }
} }
int CHyprMonitorDebugOverlay::draw(int offset) { int CHyprMonitorDebugOverlay::draw(int offset) {
if (!m_monitor) if (!m_pMonitor)
return 0; return 0;
// get avg fps // get avg fps
float avgFrametime = 0; float avgFrametime = 0;
float maxFrametime = 0; float maxFrametime = 0;
float minFrametime = 9999; float minFrametime = 9999;
for (auto const& ft : m_lastFrametimes) { for (auto const& ft : m_dLastFrametimes) {
if (ft > maxFrametime) if (ft > maxFrametime)
maxFrametime = ft; maxFrametime = ft;
if (ft < minFrametime) if (ft < minFrametime)
@@ -83,12 +83,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
avgFrametime += ft; avgFrametime += ft;
} }
float varFrametime = maxFrametime - minFrametime; float varFrametime = maxFrametime - minFrametime;
avgFrametime /= m_lastFrametimes.size() == 0 ? 1 : m_lastFrametimes.size(); avgFrametime /= m_dLastFrametimes.size() == 0 ? 1 : m_dLastFrametimes.size();
float avgRenderTime = 0; float avgRenderTime = 0;
float maxRenderTime = 0; float maxRenderTime = 0;
float minRenderTime = 9999; float minRenderTime = 9999;
for (auto const& rt : m_lastRenderTimes) { for (auto const& rt : m_dLastRenderTimes) {
if (rt > maxRenderTime) if (rt > maxRenderTime)
maxRenderTime = rt; maxRenderTime = rt;
if (rt < minRenderTime) if (rt < minRenderTime)
@@ -96,12 +96,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
avgRenderTime += rt; avgRenderTime += rt;
} }
float varRenderTime = maxRenderTime - minRenderTime; float varRenderTime = maxRenderTime - minRenderTime;
avgRenderTime /= m_lastRenderTimes.size() == 0 ? 1 : m_lastRenderTimes.size(); avgRenderTime /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size();
float avgRenderTimeNoOverlay = 0; float avgRenderTimeNoOverlay = 0;
float maxRenderTimeNoOverlay = 0; float maxRenderTimeNoOverlay = 0;
float minRenderTimeNoOverlay = 9999; float minRenderTimeNoOverlay = 9999;
for (auto const& rt : m_lastRenderTimesNoOverlay) { for (auto const& rt : m_dLastRenderTimesNoOverlay) {
if (rt > maxRenderTimeNoOverlay) if (rt > maxRenderTimeNoOverlay)
maxRenderTimeNoOverlay = rt; maxRenderTimeNoOverlay = rt;
if (rt < minRenderTimeNoOverlay) if (rt < minRenderTimeNoOverlay)
@@ -109,12 +109,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
avgRenderTimeNoOverlay += rt; avgRenderTimeNoOverlay += rt;
} }
float varRenderTimeNoOverlay = maxRenderTimeNoOverlay - minRenderTimeNoOverlay; float varRenderTimeNoOverlay = maxRenderTimeNoOverlay - minRenderTimeNoOverlay;
avgRenderTimeNoOverlay /= m_lastRenderTimes.size() == 0 ? 1 : m_lastRenderTimes.size(); avgRenderTimeNoOverlay /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size();
float avgAnimMgrTick = 0; float avgAnimMgrTick = 0;
float maxAnimMgrTick = 0; float maxAnimMgrTick = 0;
float minAnimMgrTick = 9999; float minAnimMgrTick = 9999;
for (auto const& at : m_lastAnimationTicks) { for (auto const& at : m_dLastAnimationTicks) {
if (at > maxAnimMgrTick) if (at > maxAnimMgrTick)
maxAnimMgrTick = at; maxAnimMgrTick = at;
if (at < minAnimMgrTick) if (at < minAnimMgrTick)
@@ -122,13 +122,13 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
avgAnimMgrTick += at; avgAnimMgrTick += at;
} }
float varAnimMgrTick = maxAnimMgrTick - minAnimMgrTick; float varAnimMgrTick = maxAnimMgrTick - minAnimMgrTick;
avgAnimMgrTick /= m_lastAnimationTicks.size() == 0 ? 1 : m_lastAnimationTicks.size(); avgAnimMgrTick /= m_dLastAnimationTicks.size() == 0 ? 1 : m_dLastAnimationTicks.size();
const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms
const float idealFPS = m_lastFrametimes.size(); const float idealFPS = m_dLastFrametimes.size();
static auto fontFamily = CConfigValue<std::string>("misc:font_family"); static auto fontFamily = CConfigValue<std::string>("misc:font_family");
PangoLayout* layoutText = pango_cairo_create_layout(g_pDebugOverlay->m_cairo); PangoLayout* layoutText = pango_cairo_create_layout(g_pDebugOverlay->m_pCairo);
PangoFontDescription* pangoFD = pango_font_description_new(); PangoFontDescription* pangoFD = pango_font_description_new();
pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); pango_font_description_set_family(pangoFD, (*fontFamily).c_str());
@@ -137,7 +137,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float maxTextW = 0; float maxTextW = 0;
int fontSize = 0; int fontSize = 0;
auto cr = g_pDebugOverlay->m_cairo; auto cr = g_pDebugOverlay->m_pCairo;
auto showText = [cr, layoutText, pangoFD, &maxTextW, &fontSize](const char* text, int size) { auto showText = [cr, layoutText, pangoFD, &maxTextW, &fontSize](const char* text, int size) {
if (fontSize != size) { if (fontSize != size) {
@@ -163,22 +163,22 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
const int MARGIN_TOP = 8; const int MARGIN_TOP = 8;
const int MARGIN_LEFT = 4; const int MARGIN_LEFT = 4;
cairo_move_to(cr, MARGIN_LEFT, MARGIN_TOP + offset); cairo_move_to(cr, MARGIN_LEFT, MARGIN_TOP + offset);
cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 1.f, 1.f, 1.f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
std::string text; std::string text;
showText(m_monitor->m_name.c_str(), 10); showText(m_pMonitor->szName.c_str(), 10);
if (FPS > idealFPS * 0.95f) if (FPS > idealFPS * 0.95f)
cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 0.2f, 1.f, 0.2f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 0.2f, 1.f, 0.2f, 1.f);
else if (FPS > idealFPS * 0.8f) else if (FPS > idealFPS * 0.8f)
cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 1.f, 1.f, 0.2f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 0.2f, 1.f);
else else
cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 1.f, 0.2f, 0.2f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 0.2f, 0.2f, 1.f);
text = std::format("{} FPS", (int)FPS); text = std::format("{} FPS", (int)FPS);
showText(text.c_str(), 16); showText(text.c_str(), 16);
cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 1.f, 1.f, 1.f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime); text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime);
showText(text.c_str(), 10); showText(text.c_str(), 10);
@@ -198,10 +198,10 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
double posX = 0, posY = 0; double posX = 0, posY = 0;
cairo_get_current_point(cr, &posX, &posY); cairo_get_current_point(cr, &posX, &posY);
g_pHyprRenderer->damageBox(m_lastDrawnBox); g_pHyprRenderer->damageBox(m_wbLastDrawnBox);
m_lastDrawnBox = {(int)g_pCompositor->m_monitors.front()->m_position.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_monitors.front()->m_position.y + offset + MARGIN_TOP - 1, m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset + MARGIN_TOP - 1,
(int)maxTextW + 2, posY - offset - MARGIN_TOP + 2}; (int)maxTextW + 2, posY - offset - MARGIN_TOP + 2};
g_pHyprRenderer->damageBox(m_lastDrawnBox); g_pHyprRenderer->damageBox(m_wbLastDrawnBox);
return posY - offset; return posY - offset;
} }
@@ -212,7 +212,7 @@ void CHyprDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_monitorOverlays[pMonitor].renderData(pMonitor, durationUs); m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs);
} }
void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
@@ -221,7 +221,7 @@ void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationU
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_monitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs); m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
} }
void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) { void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) {
@@ -230,37 +230,37 @@ void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) {
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_monitorOverlays[pMonitor].frameData(pMonitor); m_mMonitorOverlays[pMonitor].frameData(pMonitor);
} }
void CHyprDebugOverlay::draw() { void CHyprDebugOverlay::draw() {
const auto PMONITOR = g_pCompositor->m_monitors.front(); const auto PMONITOR = g_pCompositor->m_vMonitors.front();
if (!m_cairoSurface || !m_cairo) { if (!m_pCairoSurface || !m_pCairo) {
m_cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y); m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
m_cairo = cairo_create(m_cairoSurface); m_pCairo = cairo_create(m_pCairoSurface);
} }
// clear the pixmap // clear the pixmap
cairo_save(m_cairo); cairo_save(m_pCairo);
cairo_set_operator(m_cairo, CAIRO_OPERATOR_CLEAR); cairo_set_operator(m_pCairo, CAIRO_OPERATOR_CLEAR);
cairo_paint(m_cairo); cairo_paint(m_pCairo);
cairo_restore(m_cairo); cairo_restore(m_pCairo);
// draw the things // draw the things
int offsetY = 0; int offsetY = 0;
for (auto const& m : g_pCompositor->m_monitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
offsetY += m_monitorOverlays[m].draw(offsetY); offsetY += m_mMonitorOverlays[m].draw(offsetY);
offsetY += 5; // for padding between mons offsetY += 5; // for padding between mons
} }
cairo_surface_flush(m_cairoSurface); cairo_surface_flush(m_pCairoSurface);
// copy the data to an OpenGL texture we have // copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(m_cairoSurface); const auto DATA = cairo_image_surface_get_data(m_pCairoSurface);
m_texture->allocate(); m_pTexture->allocate();
glBindTexture(GL_TEXTURE_2D, m_texture->m_texID); glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -269,10 +269,10 @@ void CHyprDebugOverlay::draw() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
#endif #endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CTexPassElement::SRenderData data; CTexPassElement::SRenderData data;
data.tex = m_texture; data.tex = m_pTexture;
data.box = {0, 0, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y}; data.box = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
g_pHyprRenderer->m_renderPass.add(makeShared<CTexPassElement>(data)); g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
} }

View File

@@ -17,13 +17,13 @@ class CHyprMonitorDebugOverlay {
void frameData(PHLMONITOR pMonitor); void frameData(PHLMONITOR pMonitor);
private: private:
std::deque<float> m_lastFrametimes; std::deque<float> m_dLastFrametimes;
std::deque<float> m_lastRenderTimes; std::deque<float> m_dLastRenderTimes;
std::deque<float> m_lastRenderTimesNoOverlay; std::deque<float> m_dLastRenderTimesNoOverlay;
std::deque<float> m_lastAnimationTicks; std::deque<float> m_dLastAnimationTicks;
std::chrono::high_resolution_clock::time_point m_lastFrame; std::chrono::high_resolution_clock::time_point m_tpLastFrame;
PHLMONITORREF m_monitor; PHLMONITORREF m_pMonitor;
CBox m_lastDrawnBox; CBox m_wbLastDrawnBox;
friend class CHyprRenderer; friend class CHyprRenderer;
}; };
@@ -37,12 +37,12 @@ class CHyprDebugOverlay {
void frameData(PHLMONITOR); void frameData(PHLMONITOR);
private: private:
std::map<PHLMONITORREF, CHyprMonitorDebugOverlay> m_monitorOverlays; std::map<PHLMONITORREF, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
cairo_surface_t* m_cairoSurface = nullptr; cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_cairo = nullptr; cairo_t* m_pCairo = nullptr;
SP<CTexture> m_texture; SP<CTexture> m_pTexture;
friend class CHyprMonitorDebugOverlay; friend class CHyprMonitorDebugOverlay;
friend class CHyprRenderer; friend class CHyprRenderer;

View File

@@ -23,24 +23,24 @@ static inline auto iconBackendFromLayout(PangoLayout* layout) {
CHyprNotificationOverlay::CHyprNotificationOverlay() { CHyprNotificationOverlay::CHyprNotificationOverlay() {
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (m_notifications.size() == 0) if (m_vNotifications.size() == 0)
return; return;
g_pHyprRenderer->damageBox(m_lastDamage); g_pHyprRenderer->damageBox(m_bLastDamage);
}); });
m_texture = makeShared<CTexture>(); m_pTexture = makeShared<CTexture>();
} }
CHyprNotificationOverlay::~CHyprNotificationOverlay() { CHyprNotificationOverlay::~CHyprNotificationOverlay() {
if (m_cairo) if (m_pCairo)
cairo_destroy(m_cairo); cairo_destroy(m_pCairo);
if (m_cairoSurface) if (m_pCairoSurface)
cairo_surface_destroy(m_cairoSurface); cairo_surface_destroy(m_pCairoSurface);
} }
void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) { void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) {
const auto PNOTIF = m_notifications.emplace_back(makeUnique<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->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text;
PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color; PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color;
@@ -49,19 +49,19 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CH
PNOTIF->icon = icon; PNOTIF->icon = icon;
PNOTIF->fontSize = fontSize; PNOTIF->fontSize = fontSize;
for (auto const& m : g_pCompositor->m_monitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m); g_pCompositor->scheduleFrameForMonitor(m);
} }
} }
void CHyprNotificationOverlay::dismissNotifications(const int amount) { void CHyprNotificationOverlay::dismissNotifications(const int amount) {
if (amount == -1) if (amount == -1)
m_notifications.clear(); m_vNotifications.clear();
else { else {
const int AMT = std::min(amount, static_cast<int>(m_notifications.size())); const int AMT = std::min(amount, static_cast<int>(m_vNotifications.size()));
for (int i = 0; i < AMT; ++i) { for (int i = 0; i < AMT; ++i) {
m_notifications.erase(m_notifications.begin()); m_vNotifications.erase(m_vNotifications.begin());
} }
} }
} }
@@ -77,12 +77,12 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
float offsetY = 10; float offsetY = 10;
float maxWidth = 0; float maxWidth = 0;
const auto SCALE = pMonitor->m_scale; const auto SCALE = pMonitor->scale;
const auto MONSIZE = pMonitor->m_transformedSize; const auto MONSIZE = pMonitor->vecTransformedSize;
static auto fontFamily = CConfigValue<std::string>("misc:font_family"); static auto fontFamily = CConfigValue<std::string>("misc:font_family");
PangoLayout* layout = pango_cairo_create_layout(m_cairo); PangoLayout* layout = pango_cairo_create_layout(m_pCairo);
PangoFontDescription* pangoFD = pango_font_description_new(); PangoFontDescription* pangoFD = pango_font_description_new();
pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); pango_font_description_set_family(pangoFD, (*fontFamily).c_str());
@@ -92,9 +92,9 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
const auto iconBackendID = iconBackendFromLayout(layout); const auto iconBackendID = iconBackendFromLayout(layout);
const auto PBEZIER = g_pAnimationManager->getBezier("default"); const auto PBEZIER = g_pAnimationManager->getBezier("default");
for (auto const& notif : m_notifications) { for (auto const& notif : m_vNotifications) {
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->m_pixelSize.x * SCALE) / 1920.f)), 8, 40); const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
// first rect (bg, col) // first rect (bg, col)
const float FIRSTRECTANIMP = const float FIRSTRECTANIMP =
@@ -139,17 +139,17 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
const auto NOTIFSIZE = Vector2D{textW + 20.0 + iconW + 2 * ICONPADFORNOTIF, textH + 10.0}; const auto NOTIFSIZE = Vector2D{textW + 20.0 + iconW + 2 * ICONPADFORNOTIF, textH + 10.0};
// draw rects // draw rects
cairo_set_source_rgba(m_cairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
cairo_rectangle(m_cairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y); cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y);
cairo_fill(m_cairo); cairo_fill(m_pCairo);
cairo_set_source_rgb(m_cairo, 0.f, 0.f, 0.f); cairo_set_source_rgb(m_pCairo, 0.f, 0.f, 0.f);
cairo_rectangle(m_cairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC, offsetY, NOTIFSIZE.x * SECONDRECTPERC, NOTIFSIZE.y); cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC, offsetY, NOTIFSIZE.x * SECONDRECTPERC, NOTIFSIZE.y);
cairo_fill(m_cairo); cairo_fill(m_pCairo);
cairo_set_source_rgba(m_cairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
cairo_rectangle(m_cairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2); cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2);
cairo_fill(m_cairo); cairo_fill(m_pCairo);
// draw gradient // draw gradient
if (notif->icon != ICON_NONE) { if (notif->icon != ICON_NONE) {
@@ -158,23 +158,23 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC + GRADIENT_SIZE, offsetY); MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC + GRADIENT_SIZE, offsetY);
cairo_pattern_add_color_stop_rgba(pattern, 0, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, ICONCOLOR.a / 3.0); cairo_pattern_add_color_stop_rgba(pattern, 0, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, ICONCOLOR.a / 3.0);
cairo_pattern_add_color_stop_rgba(pattern, 1, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, 0); cairo_pattern_add_color_stop_rgba(pattern, 1, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, 0);
cairo_rectangle(m_cairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, GRADIENT_SIZE, NOTIFSIZE.y); cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, GRADIENT_SIZE, NOTIFSIZE.y);
cairo_set_source(m_cairo, pattern); cairo_set_source(m_pCairo, pattern);
cairo_fill(m_cairo); cairo_fill(m_pCairo);
cairo_pattern_destroy(pattern); cairo_pattern_destroy(pattern);
// draw icon // draw icon
cairo_set_source_rgb(m_cairo, 1.f, 1.f, 1.f); cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f);
cairo_move_to(m_cairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY - 2 + std::round((NOTIFSIZE.y - iconH) / 2.0)); cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY - 2 + std::round((NOTIFSIZE.y - iconH) / 2.0));
pango_layout_set_text(layout, ICON.c_str(), -1); pango_layout_set_text(layout, ICON.c_str(), -1);
pango_cairo_show_layout(m_cairo, layout); pango_cairo_show_layout(m_pCairo, layout);
} }
// draw text // draw text
cairo_set_source_rgb(m_cairo, 1.f, 1.f, 1.f); cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f);
cairo_move_to(m_cairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY - 2 + std::round((NOTIFSIZE.y - textH) / 2.0)); cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY - 2 + std::round((NOTIFSIZE.y - textH) / 2.0));
pango_layout_set_text(layout, notif->text.c_str(), -1); pango_layout_set_text(layout, notif->text.c_str(), -1);
pango_cairo_show_layout(m_cairo, layout); pango_cairo_show_layout(m_pCairo, layout);
// adjust offset and move on // adjust offset and move on
offsetY += NOTIFSIZE.y + 10; offsetY += NOTIFSIZE.y + 10;
@@ -187,55 +187,55 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
g_object_unref(layout); g_object_unref(layout);
// cleanup notifs // cleanup notifs
std::erase_if(m_notifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; }); std::erase_if(m_vNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
return CBox{(int)(pMonitor->m_position.x + pMonitor->m_size.x - maxWidth - 20), (int)pMonitor->m_position.y, (int)maxWidth + 20, (int)offsetY + 10}; return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
} }
void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) { void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
const auto MONSIZE = pMonitor->m_transformedSize; const auto MONSIZE = pMonitor->vecTransformedSize;
if (m_lastMonitor != pMonitor || m_lastSize != MONSIZE || !m_cairo || !m_cairoSurface) { if (m_pLastMonitor != pMonitor || m_vecLastSize != MONSIZE || !m_pCairo || !m_pCairoSurface) {
if (m_cairo && m_cairoSurface) { if (m_pCairo && m_pCairoSurface) {
cairo_destroy(m_cairo); cairo_destroy(m_pCairo);
cairo_surface_destroy(m_cairoSurface); cairo_surface_destroy(m_pCairoSurface);
} }
m_cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, MONSIZE.x, MONSIZE.y); m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, MONSIZE.x, MONSIZE.y);
m_cairo = cairo_create(m_cairoSurface); m_pCairo = cairo_create(m_pCairoSurface);
m_lastMonitor = pMonitor; m_pLastMonitor = pMonitor;
m_lastSize = MONSIZE; m_vecLastSize = MONSIZE;
} }
// Draw the notifications // Draw the notifications
if (m_notifications.size() == 0) if (m_vNotifications.size() == 0)
return; return;
// Render to the monitor // Render to the monitor
// clear the pixmap // clear the pixmap
cairo_save(m_cairo); cairo_save(m_pCairo);
cairo_set_operator(m_cairo, CAIRO_OPERATOR_CLEAR); cairo_set_operator(m_pCairo, CAIRO_OPERATOR_CLEAR);
cairo_paint(m_cairo); cairo_paint(m_pCairo);
cairo_restore(m_cairo); cairo_restore(m_pCairo);
cairo_surface_flush(m_cairoSurface); cairo_surface_flush(m_pCairoSurface);
CBox damage = drawNotifications(pMonitor); CBox damage = drawNotifications(pMonitor);
g_pHyprRenderer->damageBox(damage); g_pHyprRenderer->damageBox(damage);
g_pHyprRenderer->damageBox(m_lastDamage); g_pHyprRenderer->damageBox(m_bLastDamage);
g_pCompositor->scheduleFrameForMonitor(pMonitor); g_pCompositor->scheduleFrameForMonitor(pMonitor);
m_lastDamage = damage; m_bLastDamage = damage;
// copy the data to an OpenGL texture we have // copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(m_cairoSurface); const auto DATA = cairo_image_surface_get_data(m_pCairoSurface);
m_texture->allocate(); m_pTexture->allocate();
glBindTexture(GL_TEXTURE_2D, m_texture->m_texID); glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -247,13 +247,13 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CTexPassElement::SRenderData data; CTexPassElement::SRenderData data;
data.tex = m_texture; data.tex = m_pTexture;
data.box = {0, 0, MONSIZE.x, MONSIZE.y}; data.box = {0, 0, MONSIZE.x, MONSIZE.y};
data.a = 1.F; data.a = 1.F;
g_pHyprRenderer->m_renderPass.add(makeShared<CTexPassElement>(data)); g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
} }
bool CHyprNotificationOverlay::hasAny() { bool CHyprNotificationOverlay::hasAny() {
return !m_notifications.empty(); return !m_vNotifications.empty();
} }

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/time/Timer.hpp" #include "../helpers/Timer.hpp"
#include "../render/Texture.hpp" #include "../render/Texture.hpp"
#include "../SharedDefs.hpp" #include "../SharedDefs.hpp"
@@ -47,17 +47,17 @@ class CHyprNotificationOverlay {
private: private:
CBox drawNotifications(PHLMONITOR pMonitor); CBox drawNotifications(PHLMONITOR pMonitor);
CBox m_lastDamage; CBox m_bLastDamage;
std::vector<UP<SNotification>> m_notifications; std::vector<UP<SNotification>> m_vNotifications;
cairo_surface_t* m_cairoSurface = nullptr; cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_cairo = nullptr; cairo_t* m_pCairo = nullptr;
PHLMONITORREF m_lastMonitor; PHLMONITORREF m_pLastMonitor;
Vector2D m_lastSize = Vector2D(-1, -1); Vector2D m_vecLastSize = Vector2D(-1, -1);
SP<CTexture> m_texture; SP<CTexture> m_pTexture;
}; };
inline UP<CHyprNotificationOverlay> g_pHyprNotificationOverlay; inline UP<CHyprNotificationOverlay> g_pHyprNotificationOverlay;

View File

@@ -7,21 +7,21 @@
#include <fcntl.h> #include <fcntl.h>
void Debug::init(const std::string& IS) { void Debug::init(const std::string& IS) {
m_logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
m_logOfs.open(m_logFile, std::ios::out | std::ios::app); logOfs.open(logFile, std::ios::out | std::ios::app);
auto handle = m_logOfs.native_handle(); auto handle = logOfs.native_handle();
fcntl(handle, F_SETFD, FD_CLOEXEC); fcntl(handle, F_SETFD, FD_CLOEXEC);
} }
void Debug::close() { void Debug::close() {
m_logOfs.close(); logOfs.close();
} }
void Debug::log(eLogLevel level, std::string str) { void Debug::log(eLogLevel level, std::string str) {
if (level == TRACE && !m_trace) if (level == TRACE && !trace)
return; return;
if (m_shuttingDown) if (shuttingDown)
return; return;
std::string coloredStr = str; std::string coloredStr = str;
@@ -55,20 +55,20 @@ void Debug::log(eLogLevel level, std::string str) {
} }
//NOLINTEND //NOLINTEND
m_rollingLog += str + "\n"; rollingLog += str + "\n";
if (m_rollingLog.size() > ROLLING_LOG_SIZE) if (rollingLog.size() > ROLLING_LOG_SIZE)
m_rollingLog = m_rollingLog.substr(m_rollingLog.size() - ROLLING_LOG_SIZE); rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
if (SRollingLogFollow::get().isRunning()) if (SRollingLogFollow::get().isRunning())
SRollingLogFollow::get().addLog(str); SRollingLogFollow::get().addLog(str);
if (!m_disableLogs || !**m_disableLogs) { if (!disableLogs || !**disableLogs) {
// log to a file // log to a file
m_logOfs << str << "\n"; logOfs << str << "\n";
m_logOfs.flush(); logOfs.flush();
} }
// log it to the stdout too. // log it to the stdout too.
if (!m_disableStdout) if (!disableStdout)
std::println("{}", ((m_coloredLogs && !**m_coloredLogs) ? str : coloredStr)); std::println("{}", ((coloredLogs && !**coloredLogs) ? str : coloredStr));
} }

View File

@@ -21,17 +21,17 @@ enum eLogLevel : int8_t {
// NOLINTNEXTLINE(readability-identifier-naming) // NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug { namespace Debug {
inline std::string m_logFile; inline std::string logFile;
inline std::ofstream m_logOfs; inline std::ofstream logOfs;
inline int64_t* const* m_disableLogs = nullptr; inline int64_t* const* disableLogs = nullptr;
inline int64_t* const* m_disableTime = nullptr; inline int64_t* const* disableTime = nullptr;
inline bool m_disableStdout = false; inline bool disableStdout = false;
inline bool m_trace = false; inline bool trace = false;
inline bool m_shuttingDown = false; inline bool shuttingDown = false;
inline int64_t* const* m_coloredLogs = nullptr; inline int64_t* const* coloredLogs = nullptr;
inline std::string m_rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
inline std::mutex m_logMutex; inline std::mutex logMutex;
void init(const std::string& IS); void init(const std::string& IS);
void close(); void close();
@@ -42,18 +42,18 @@ namespace Debug {
template <typename... Args> template <typename... Args>
//NOLINTNEXTLINE //NOLINTNEXTLINE
void log(eLogLevel level, std::format_string<Args...> fmt, Args&&... args) { void log(eLogLevel level, std::format_string<Args...> fmt, Args&&... args) {
std::lock_guard<std::mutex> guard(m_logMutex); std::lock_guard<std::mutex> guard(logMutex);
if (level == TRACE && !m_trace) if (level == TRACE && !trace)
return; return;
if (m_shuttingDown) if (shuttingDown)
return; return;
std::string logMsg = ""; std::string logMsg = "";
// print date and time to the ofs // print date and time to the ofs
if (m_disableTime && !**m_disableTime) { if (disableTime && !**disableTime) {
#ifndef _LIBCPP_VERSION #ifndef _LIBCPP_VERSION
static auto current_zone = std::chrono::current_zone(); static auto current_zone = std::chrono::current_zone();
const auto zt = std::chrono::zoned_time{current_zone, std::chrono::system_clock::now()}; const auto zt = std::chrono::zoned_time{current_zone, std::chrono::system_clock::now()};

View File

@@ -5,55 +5,55 @@
// NOLINTNEXTLINE(readability-identifier-naming) // NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug { namespace Debug {
struct SRollingLogFollow { struct SRollingLogFollow {
std::unordered_map<int, std::string> m_socketToRollingLogFollowQueue; std::unordered_map<int, std::string> socketToRollingLogFollowQueue;
std::shared_mutex m_mutex; std::shared_mutex m;
bool m_running = false; bool running = false;
static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192; static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192;
// Returns true if the queue is empty for the given socket // Returns true if the queue is empty for the given socket
bool isEmpty(int socket) { bool isEmpty(int socket) {
std::shared_lock<std::shared_mutex> r(m_mutex); std::shared_lock<std::shared_mutex> r(m);
return m_socketToRollingLogFollowQueue[socket].empty(); return socketToRollingLogFollowQueue[socket].empty();
} }
std::string debugInfo() { std::string debugInfo() {
std::shared_lock<std::shared_mutex> r(m_mutex); std::shared_lock<std::shared_mutex> r(m);
return std::format("RollingLogFollow, got {} connections", m_socketToRollingLogFollowQueue.size()); return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size());
} }
std::string getLog(int socket) { std::string getLog(int socket) {
std::unique_lock<std::shared_mutex> w(m_mutex); std::unique_lock<std::shared_mutex> w(m);
const std::string ret = m_socketToRollingLogFollowQueue[socket]; const std::string ret = socketToRollingLogFollowQueue[socket];
m_socketToRollingLogFollowQueue[socket] = ""; socketToRollingLogFollowQueue[socket] = "";
return ret; return ret;
}; };
void addLog(const std::string& log) { void addLog(const std::string& log) {
std::unique_lock<std::shared_mutex> w(m_mutex); std::unique_lock<std::shared_mutex> w(m);
m_running = true; running = true;
std::vector<int> to_erase; std::vector<int> to_erase;
for (const auto& p : m_socketToRollingLogFollowQueue) for (const auto& p : socketToRollingLogFollowQueue)
m_socketToRollingLogFollowQueue[p.first] += log + "\n"; socketToRollingLogFollowQueue[p.first] += log + "\n";
} }
bool isRunning() { bool isRunning() {
std::shared_lock<std::shared_mutex> r(m_mutex); std::shared_lock<std::shared_mutex> r(m);
return m_running; return running;
} }
void stopFor(int socket) { void stopFor(int socket) {
std::unique_lock<std::shared_mutex> w(m_mutex); std::unique_lock<std::shared_mutex> w(m);
m_socketToRollingLogFollowQueue.erase(socket); socketToRollingLogFollowQueue.erase(socket);
if (m_socketToRollingLogFollowQueue.empty()) if (socketToRollingLogFollowQueue.empty())
m_running = false; running = false;
} }
void startFor(int socket) { void startFor(int socket) {
std::unique_lock<std::shared_mutex> w(m_mutex); std::unique_lock<std::shared_mutex> w(m);
m_socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket); socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket);
m_running = true; running = true;
} }
static SRollingLogFollow& get() { static SRollingLogFollow& get() {

View File

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

View File

@@ -14,7 +14,6 @@ class CLayerRule {
RULE_BLUR, RULE_BLUR,
RULE_BLURPOPUPS, RULE_BLURPOPUPS,
RULE_DIMAROUND, RULE_DIMAROUND,
RULE_ABOVELOCK,
RULE_IGNOREALPHA, RULE_IGNOREALPHA,
RULE_IGNOREZERO, RULE_IGNOREZERO,
RULE_XRAY, RULE_XRAY,
@@ -23,10 +22,10 @@ class CLayerRule {
RULE_ZUMBA, RULE_ZUMBA,
}; };
eRuleType m_ruleType = RULE_INVALID; eRuleType ruleType = RULE_INVALID;
const std::string m_targetNamespace; const std::string targetNamespace;
const std::string m_rule; const std::string rule;
CRuleRegexContainer m_targetNamespaceRegex; CRuleRegexContainer targetNamespaceRegex;
}; };

View File

@@ -15,436 +15,424 @@
PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) { PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource)); PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource));
auto pMonitor = resource->m_monitor.empty() ? g_pCompositor->m_lastMonitor.lock() : g_pCompositor->getMonitorFromName(resource->m_monitor); auto pMonitor = resource->monitor.empty() ? g_pCompositor->m_pLastMonitor.lock() : g_pCompositor->getMonitorFromName(resource->monitor);
pLS->m_surface->assign(resource->m_surface.lock(), pLS); pLS->surface->assign(resource->surface.lock(), pLS);
if (!pMonitor) { if (!pMonitor) {
Debug::log(ERR, "New LS has no monitor??"); Debug::log(ERR, "New LS has no monitor??");
return pLS; return pLS;
} }
if (pMonitor->m_mirrorOf) if (pMonitor->pMirrorOf)
pMonitor = g_pCompositor->m_monitors.front(); pMonitor = g_pCompositor->m_vMonitors.front();
pLS->m_self = pLS; pLS->self = pLS;
pLS->m_namespace = resource->m_layerNamespace; pLS->szNamespace = resource->layerNamespace;
pLS->m_layer = resource->m_current.layer; pLS->layer = resource->current.layer;
pLS->m_popupHead = CPopup::create(pLS); pLS->popupHead = makeUnique<CPopup>(pLS);
pLS->m_monitor = pMonitor; pLS->popupHead->m_pSelf = pLS->popupHead;
pMonitor->m_layerSurfaceLayers[resource->m_current.layer].emplace_back(pLS); pLS->monitor = pMonitor;
pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS);
pLS->m_forceBlur = g_pConfigManager->shouldBlurLS(pLS->m_namespace); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace);
g_pAnimationManager->createAnimation(0.f, pLS->m_alpha, g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pLS->alpha, g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->m_realPosition, g_pConfigManager->getAnimationPropertyConfig("layersIn"), 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->m_realSize, 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->registerCallbacks();
pLS->m_alpha->setValueAndWarp(0.f); pLS->alpha->setValueAndWarp(0.f);
Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->m_layerNamespace, (int)pLS->m_layer, pMonitor->m_name); Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName);
return pLS; return pLS;
} }
void CLayerSurface::registerCallbacks() { void CLayerSurface::registerCallbacks() {
m_alpha->setUpdateCallback([this](auto) { alpha->setUpdateCallback([this](auto) {
if (m_dimAround) if (dimAround)
g_pHyprRenderer->damageMonitor(m_monitor.lock()); g_pHyprRenderer->damageMonitor(monitor.lock());
}); });
} }
CLayerSurface::CLayerSurface(SP<CLayerShellResource> resource_) : m_layerSurface(resource_) { CLayerSurface::CLayerSurface(SP<CLayerShellResource> resource_) : layerSurface(resource_) {
m_listeners.commit = m_layerSurface->m_events.commit.registerListener([this](std::any d) { onCommit(); }); listeners.commit = layerSurface->events.commit.registerListener([this](std::any d) { onCommit(); });
m_listeners.map = m_layerSurface->m_events.map.registerListener([this](std::any d) { onMap(); }); listeners.map = layerSurface->events.map.registerListener([this](std::any d) { onMap(); });
m_listeners.unmap = m_layerSurface->m_events.unmap.registerListener([this](std::any d) { onUnmap(); }); listeners.unmap = layerSurface->events.unmap.registerListener([this](std::any d) { onUnmap(); });
m_listeners.destroy = m_layerSurface->m_events.destroy.registerListener([this](std::any d) { onDestroy(); }); listeners.destroy = layerSurface->events.destroy.registerListener([this](std::any d) { onDestroy(); });
m_surface = CWLSurface::create(); surface = CWLSurface::create();
} }
CLayerSurface::~CLayerSurface() { CLayerSurface::~CLayerSurface() {
if (!g_pHyprOpenGL) if (!g_pHyprOpenGL)
return; return;
if (m_surface) if (surface)
m_surface->unassign(); surface->unassign();
g_pHyprRenderer->makeEGLCurrent(); g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_layerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == m_self.lock(); }); std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); });
for (auto const& mon : g_pCompositor->m_realMonitors) { for (auto const& mon : g_pCompositor->m_vRealMonitors) {
for (auto& lsl : mon->m_layerSurfaceLayers) { for (auto& lsl : mon->m_aLayerSurfaceLayers) {
std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; });
} }
} }
} }
void CLayerSurface::onDestroy() { void CLayerSurface::onDestroy() {
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)m_layerSurface.get()); Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get());
const auto PMONITOR = m_monitor.lock(); const auto PMONITOR = monitor.lock();
if (!PMONITOR) if (!PMONITOR)
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)"); Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
if (!m_fadingOut) { if (!fadingOut) {
if (m_mapped) { if (mapped) {
Debug::log(LOG, "Forcing an unmap of a LS that did a straight destroy!"); Debug::log(LOG, "Forcing an unmap of a LS that did a straight destroy!");
onUnmap(); onUnmap();
} else { } else {
Debug::log(LOG, "Removing LayerSurface that wasn't mapped."); Debug::log(LOG, "Removing LayerSurface that wasn't mapped.");
if (m_alpha) alpha->setValueAndWarp(0.f);
m_alpha->setValueAndWarp(0.f); fadingOut = true;
m_fadingOut = true; g_pCompositor->addToFadingOutSafe(self.lock());
g_pCompositor->addToFadingOutSafe(m_self.lock());
} }
} }
m_popupHead.reset(); popupHead.reset();
m_noProcess = true; noProcess = true;
// rearrange to fix the reserved areas // rearrange to fix the reserved areas
if (PMONITOR) { if (PMONITOR) {
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
PMONITOR->m_scheduledRecalc = true; PMONITOR->scheduledRecalc = true;
// and damage // and damage
CBox geomFixed = {m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y, m_geometry.width, m_geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
} }
m_readyToDelete = true; readyToDelete = true;
m_layerSurface.reset(); layerSurface.reset();
if (m_surface) if (surface)
m_surface->unassign(); surface->unassign();
m_listeners.unmap.reset(); listeners.unmap.reset();
m_listeners.destroy.reset(); listeners.destroy.reset();
m_listeners.map.reset(); listeners.map.reset();
m_listeners.commit.reset(); listeners.commit.reset();
} }
void CLayerSurface::onMap() { void CLayerSurface::onMap() {
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)m_layerSurface.get()); Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface.get());
m_mapped = true; mapped = true;
m_interactivity = m_layerSurface->m_current.interactivity; interactivity = layerSurface->current.interactivity;
m_layerSurface->m_surface->map(); layerSurface->surface->map();
// this layer might be re-mapped. // this layer might be re-mapped.
m_fadingOut = false; fadingOut = false;
g_pCompositor->removeFromFadingOutSafe(m_self.lock()); g_pCompositor->removeFromFadingOutSafe(self.lock());
// fix if it changed its mon // fix if it changed its mon
const auto PMONITOR = m_monitor.lock(); const auto PMONITOR = monitor.lock();
if (!PMONITOR) if (!PMONITOR)
return; return;
applyRules(); applyRules();
PMONITOR->m_scheduledRecalc = true; PMONITOR->scheduledRecalc = true;
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
m_surface->resource()->enter(PMONITOR->m_self.lock()); surface->resource()->enter(PMONITOR->self.lock());
const bool ISEXCLUSIVE = m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
if (ISEXCLUSIVE) if (ISEXCLUSIVE)
g_pInputManager->m_exclusiveLSes.push_back(m_self); g_pInputManager->m_dExclusiveLSes.push_back(self);
const bool GRABSFOCUS = ISEXCLUSIVE || const bool GRABSFOCUS = ISEXCLUSIVE ||
(m_layerSurface->m_current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && (layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained // don't focus if constrained
(g_pSeatManager->m_mouse.expired() || !g_pInputManager->isConstrained())); (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()));
if (GRABSFOCUS) { if (GRABSFOCUS) {
// TODO: use the new superb really very cool grab // TODO: use the new superb really very cool grab
g_pSeatManager->setGrab(nullptr); g_pSeatManager->setGrab(nullptr);
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
g_pCompositor->focusSurface(m_surface->resource()); g_pCompositor->focusSurface(surface->resource());
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y);
g_pSeatManager->setPointerFocus(m_surface->resource(), LOCAL); g_pSeatManager->setPointerFocus(surface->resource(), LOCAL);
g_pInputManager->m_emptyFocusCursorSet = false; g_pInputManager->m_bEmptyFocusCursorSet = false;
} }
m_position = Vector2D(m_geometry.x, m_geometry.y); position = Vector2D(geometry.x, geometry.y);
CBox geomFixed = {m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y, m_geometry.width, m_geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
const bool FULLSCREEN = PMONITOR->m_activeWorkspace && PMONITOR->m_activeWorkspace->m_hasFullscreenWindow && PMONITOR->m_activeWorkspace->m_fullscreenMode == FSMODE_FULLSCREEN; const bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
startAnimation(!(m_layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
m_readyToDelete = false; readyToDelete = false;
m_fadingOut = false; fadingOut = false;
g_pEventManager->postEvent(SHyprIPCEvent{.event = "openlayer", .data = m_namespace}); g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", szNamespace});
EMIT_HOOK_EVENT("openLayer", m_self.lock()); EMIT_HOOK_EVENT("openLayer", self.lock());
g_pCompositor->setPreferredScaleForSurface(m_surface->resource(), PMONITOR->m_scale); g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(m_surface->resource(), PMONITOR->m_transform); g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform);
} }
void CLayerSurface::onUnmap() { void CLayerSurface::onUnmap() {
Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)m_layerSurface.get()); Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface.get());
g_pEventManager->postEvent(SHyprIPCEvent{.event = "closelayer", .data = m_layerSurface->m_layerNamespace}); g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace});
EMIT_HOOK_EVENT("closeLayer", m_self.lock()); EMIT_HOOK_EVENT("closeLayer", self.lock());
std::erase_if(g_pInputManager->m_exclusiveLSes, [this](const auto& other) { return !other || other == m_self; }); std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
if (!m_monitor || g_pCompositor->m_unsafeState) { if (!monitor || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
g_pCompositor->addToFadingOutSafe(m_self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
m_mapped = false; mapped = false;
if (m_layerSurface && m_layerSurface->m_surface) if (layerSurface && layerSurface->surface)
m_layerSurface->m_surface->unmap(); layerSurface->surface->unmap();
startAnimation(false); startAnimation(false);
return; return;
} }
// end any pending animations so that snapshot has right dimensions
m_realPosition->warp();
m_realSize->warp();
// make a snapshot and start fade // make a snapshot and start fade
g_pHyprRenderer->makeLayerSnapshot(m_self.lock()); g_pHyprRenderer->makeLayerSnapshot(self.lock());
startAnimation(false); startAnimation(false);
m_mapped = false; mapped = false;
if (m_layerSurface && m_layerSurface->m_surface) if (layerSurface && layerSurface->surface)
m_layerSurface->m_surface->unmap(); layerSurface->surface->unmap();
g_pCompositor->addToFadingOutSafe(m_self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
const auto PMONITOR = m_monitor.lock(); const auto PMONITOR = monitor.lock();
const bool WASLASTFOCUS = g_pSeatManager->m_state.keyboardFocus == m_surface->resource() || g_pSeatManager->m_state.pointerFocus == m_surface->resource(); const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == surface->resource() || g_pSeatManager->state.pointerFocus == surface->resource();
if (!PMONITOR) if (!PMONITOR)
return; return;
// refocus if needed // refocus if needed
// vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
if (WASLASTFOCUS || (g_pCompositor->m_lastFocus && g_pCompositor->m_lastFocus->m_hlSurface && !g_pCompositor->m_lastFocus->m_hlSurface->keyboardFocusable())) { if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
if (!g_pInputManager->refocusLastWindow(PMONITOR)) g_pInputManager->refocusLastWindow(PMONITOR);
g_pInputManager->refocus(); else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource())
} else if (g_pCompositor->m_lastFocus && g_pCompositor->m_lastFocus != m_surface->resource()) g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_lastFocus.lock());
CBox geomFixed = {m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y, m_geometry.width, m_geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
geomFixed = {m_geometry.x + (int)PMONITOR->m_position.x, m_geometry.y + (int)PMONITOR->m_position.y, (int)m_layerSurface->m_surface->m_current.size.x, geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.size.x,
(int)m_layerSurface->m_surface->m_current.size.y}; (int)layerSurface->surface->current.size.y};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
} }
void CLayerSurface::onCommit() { void CLayerSurface::onCommit() {
if (!m_layerSurface) if (!layerSurface)
return; return;
if (!m_mapped) { if (!mapped) {
// we're re-mapping if this is the case // we're re-mapping if this is the case
if (m_layerSurface->m_surface && !m_layerSurface->m_surface->m_current.texture) { if (layerSurface->surface && !layerSurface->surface->current.texture) {
m_fadingOut = false; fadingOut = false;
m_geometry = {}; geometry = {};
g_pHyprRenderer->arrangeLayersForMonitor(monitorID()); g_pHyprRenderer->arrangeLayersForMonitor(monitorID());
} }
return; return;
} }
const auto PMONITOR = m_monitor.lock(); const auto PMONITOR = monitor.lock();
if (!PMONITOR) if (!PMONITOR)
return; return;
if (m_layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || m_layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) if (layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
CBox geomFixed = {m_geometry.x, m_geometry.y, m_geometry.width, m_geometry.height}; CBox geomFixed = {geometry.x, geometry.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
if (m_layerSurface->m_current.committed != 0) { if (layerSurface->current.committed != 0) {
if (m_layerSurface->m_current.committed & CLayerShellResource::eCommittedState::STATE_LAYER) { if (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_LAYER) {
for (auto it = PMONITOR->m_layerSurfaceLayers[m_layer].begin(); it != PMONITOR->m_layerSurfaceLayers[m_layer].end(); it++) { for (auto it = PMONITOR->m_aLayerSurfaceLayers[layer].begin(); it != PMONITOR->m_aLayerSurfaceLayers[layer].end(); it++) {
if (*it == m_self) { if (*it == self) {
if (m_layerSurface->m_current.layer == m_layer) if (layerSurface->current.layer == layer)
break; break;
PMONITOR->m_layerSurfaceLayers[m_layerSurface->m_current.layer].emplace_back(*it); PMONITOR->m_aLayerSurfaceLayers[layerSurface->current.layer].emplace_back(*it);
PMONITOR->m_layerSurfaceLayers[m_layer].erase(it); PMONITOR->m_aLayerSurfaceLayers[layer].erase(it);
break; break;
} }
} }
m_layer = m_layerSurface->m_current.layer; layer = layerSurface->current.layer;
if (m_layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || m_layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) if (layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
} }
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
PMONITOR->m_scheduledRecalc = true; PMONITOR->scheduledRecalc = true;
} else { } else {
m_position = Vector2D(m_geometry.x, m_geometry.y); position = Vector2D(geometry.x, geometry.y);
// update geom if it changed // update geom if it changed
if (m_layerSurface->m_surface->m_current.scale == 1 && PMONITOR->m_scale != 1.f && m_layerSurface->m_surface->m_current.viewport.hasDestination) { if (layerSurface->surface->current.scale == 1 && PMONITOR->scale != 1.f && layerSurface->surface->current.viewport.hasDestination) {
// fractional scaling. Dirty hack. // fractional scaling. Dirty hack.
m_geometry = {m_geometry.pos(), m_layerSurface->m_surface->m_current.viewport.destination}; geometry = {geometry.pos(), layerSurface->surface->current.viewport.destination};
} else { } else {
// this is because some apps like e.g. rofi-lbonn can't fucking use the protocol correctly. // this is because some apps like e.g. rofi-lbonn can't fucking use the protocol correctly.
m_geometry = {m_geometry.pos(), m_layerSurface->m_surface->m_current.size}; geometry = {geometry.pos(), layerSurface->surface->current.size};
} }
} }
if (m_realPosition->goal() != m_geometry.pos()) { if (realPosition->goal() != geometry.pos()) {
if (m_realPosition->isBeingAnimated()) if (realPosition->isBeingAnimated())
*m_realPosition = m_geometry.pos(); *realPosition = geometry.pos();
else else
m_realPosition->setValueAndWarp(m_geometry.pos()); realPosition->setValueAndWarp(geometry.pos());
} }
if (m_realSize->goal() != m_geometry.size()) { if (realSize->goal() != geometry.size()) {
if (m_realSize->isBeingAnimated()) if (realSize->isBeingAnimated())
*m_realSize = m_geometry.size(); *realSize = geometry.size();
else else
m_realSize->setValueAndWarp(m_geometry.size()); realSize->setValueAndWarp(geometry.size());
} }
if (m_mapped && (m_layerSurface->m_current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) { if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) {
bool WASLASTFOCUS = false; bool WASLASTFOCUS = false;
m_layerSurface->m_surface->breadthfirst( layerSurface->surface->breadthfirst(
[&WASLASTFOCUS](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->m_state.keyboardFocus == surf; }, [&WASLASTFOCUS](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->state.keyboardFocus == surf; },
nullptr); nullptr);
if (!WASLASTFOCUS && m_popupHead) { if (!WASLASTFOCUS && popupHead) {
m_popupHead->breadthfirst( popupHead->breadthfirst(
[&WASLASTFOCUS](WP<CPopup> popup, void* data) { [&WASLASTFOCUS](WP<CPopup> popup, void* data) {
WASLASTFOCUS = WASLASTFOCUS || (popup->m_wlSurface && g_pSeatManager->m_state.keyboardFocus == popup->m_wlSurface->resource()); WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource());
}, },
nullptr); nullptr);
} }
const bool WASEXCLUSIVE = m_interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
const bool ISEXCLUSIVE = m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
if (!WASEXCLUSIVE && ISEXCLUSIVE) if (!WASEXCLUSIVE && ISEXCLUSIVE)
g_pInputManager->m_exclusiveLSes.push_back(m_self); g_pInputManager->m_dExclusiveLSes.push_back(self);
else if (WASEXCLUSIVE && !ISEXCLUSIVE) else if (WASEXCLUSIVE && !ISEXCLUSIVE)
std::erase_if(g_pInputManager->m_exclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == m_self.lock(); }); std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
// if the surface was focused and interactive but now isn't, refocus // if the surface was focused and interactive but now isn't, refocus
if (WASLASTFOCUS && m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) { if (WASLASTFOCUS && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) {
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either, // moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
// so unfocus the surface here. // so unfocus the surface here.
g_pCompositor->focusSurface(nullptr); g_pCompositor->focusSurface(nullptr);
g_pInputManager->refocusLastWindow(m_monitor.lock()); g_pInputManager->refocusLastWindow(monitor.lock());
} else if (WASLASTFOCUS && WASEXCLUSIVE && m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { } else if (WASLASTFOCUS && WASEXCLUSIVE && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) {
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
} else if (!WASEXCLUSIVE && ISEXCLUSIVE) { } else if (!WASEXCLUSIVE && ISEXCLUSIVE) {
// if now exclusive and not previously // if now exclusive and not previously
g_pSeatManager->setGrab(nullptr); g_pSeatManager->setGrab(nullptr);
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
g_pCompositor->focusSurface(m_surface->resource()); g_pCompositor->focusSurface(surface->resource());
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y);
g_pSeatManager->setPointerFocus(m_surface->resource(), LOCAL); g_pSeatManager->setPointerFocus(surface->resource(), LOCAL);
g_pInputManager->m_emptyFocusCursorSet = false; g_pInputManager->m_bEmptyFocusCursorSet = false;
} }
} }
m_interactivity = m_layerSurface->m_current.interactivity; interactivity = layerSurface->current.interactivity;
g_pHyprRenderer->damageSurface(m_surface->resource(), m_position.x, m_position.y); g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y);
g_pCompositor->setPreferredScaleForSurface(m_surface->resource(), PMONITOR->m_scale); g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(m_surface->resource(), PMONITOR->m_transform); g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform);
} }
void CLayerSurface::applyRules() { void CLayerSurface::applyRules() {
m_noAnimations = false; noAnimations = false;
m_forceBlur = false; forceBlur = false;
m_ignoreAlpha = false; ignoreAlpha = false;
m_ignoreAlphaValue = 0.f; ignoreAlphaValue = 0.f;
m_dimAround = false; dimAround = false;
m_xray = -1; xray = -1;
m_animationStyle.reset(); animationStyle.reset();
for (auto const& rule : g_pConfigManager->getMatchingRules(m_self.lock())) { for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) {
switch (rule->m_ruleType) { switch (rule->ruleType) {
case CLayerRule::RULE_NOANIM: { case CLayerRule::RULE_NOANIM: {
m_noAnimations = true; noAnimations = true;
break; break;
} }
case CLayerRule::RULE_BLUR: { case CLayerRule::RULE_BLUR: {
m_forceBlur = true; forceBlur = true;
break; break;
} }
case CLayerRule::RULE_BLURPOPUPS: { case CLayerRule::RULE_BLURPOPUPS: {
m_forceBlurPopups = true; forceBlurPopups = true;
break; break;
} }
case CLayerRule::RULE_IGNOREALPHA: case CLayerRule::RULE_IGNOREALPHA:
case CLayerRule::RULE_IGNOREZERO: { case CLayerRule::RULE_IGNOREZERO: {
const auto FIRST_SPACE_POS = rule->m_rule.find_first_of(' '); const auto FIRST_SPACE_POS = rule->rule.find_first_of(' ');
std::string alphaValue = ""; std::string alphaValue = "";
if (FIRST_SPACE_POS != std::string::npos) if (FIRST_SPACE_POS != std::string::npos)
alphaValue = rule->m_rule.substr(FIRST_SPACE_POS + 1); alphaValue = rule->rule.substr(FIRST_SPACE_POS + 1);
try { try {
m_ignoreAlpha = true; ignoreAlpha = true;
if (!alphaValue.empty()) if (!alphaValue.empty())
m_ignoreAlphaValue = std::stof(alphaValue); ignoreAlphaValue = std::stof(alphaValue);
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); } } catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
break; break;
} }
case CLayerRule::RULE_DIMAROUND: { case CLayerRule::RULE_DIMAROUND: {
m_dimAround = true; dimAround = true;
break; break;
} }
case CLayerRule::RULE_XRAY: { case CLayerRule::RULE_XRAY: {
CVarList vars{rule->m_rule, 0, ' '}; CVarList vars{rule->rule, 0, ' '};
m_xray = configStringToInt(vars[1]).value_or(false); try {
xray = configStringToInt(vars[1]).value_or(false);
} catch (...) {}
break; break;
} }
case CLayerRule::RULE_ANIMATION: { case CLayerRule::RULE_ANIMATION: {
CVarList vars{rule->m_rule, 2, 's'}; CVarList vars{rule->rule, 2, 's'};
m_animationStyle = vars[1]; animationStyle = vars[1];
break; break;
} }
case CLayerRule::RULE_ORDER: { case CLayerRule::RULE_ORDER: {
CVarList vars{rule->m_rule, 2, 's'}; CVarList vars{rule->rule, 2, 's'};
try { try {
m_order = std::stoi(vars[1]); order = std::stoi(vars[1]);
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); } } catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
break; break;
} }
case CLayerRule::RULE_ABOVELOCK: {
m_aboveLockscreen = true;
CVarList vars{rule->m_rule, 0, ' '};
m_aboveLockscreenInteractable = configStringToInt(vars[1]).value_or(false);
break;
}
default: break; default: break;
} }
} }
@@ -452,19 +440,19 @@ void CLayerSurface::applyRules() {
void CLayerSurface::startAnimation(bool in, bool instant) { void CLayerSurface::startAnimation(bool in, bool instant) {
if (in) { if (in) {
m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn"));
m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn"));
m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn")); alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"));
} else { } else {
m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut"));
m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut"));
m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut")); alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut"));
} }
const auto ANIMSTYLE = m_animationStyle.value_or(m_realPosition->getStyle()); const auto ANIMSTYLE = animationStyle.value_or(realPosition->getStyle());
if (ANIMSTYLE.starts_with("slide")) { if (ANIMSTYLE.starts_with("slide")) {
// get closest edge // get closest edge
const auto MIDDLE = m_geometry.middle(); const auto MIDDLE = geometry.middle();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE); const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE);
@@ -484,10 +472,10 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
} }
const std::array<Vector2D, 4> edgePoints = { const std::array<Vector2D, 4> edgePoints = {
PMONITOR->m_position + Vector2D{PMONITOR->m_size.x / 2, 0.0}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0.0},
PMONITOR->m_position + Vector2D{PMONITOR->m_size.x / 2, PMONITOR->m_size.y}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y},
PMONITOR->m_position + Vector2D{0.0, PMONITOR->m_size.y}, PMONITOR->vecPosition + Vector2D{0.0, PMONITOR->vecSize.y},
PMONITOR->m_position + Vector2D{PMONITOR->m_size.x, PMONITOR->m_size.y / 2}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2},
}; };
float closest = std::numeric_limits<float>::max(); float closest = std::numeric_limits<float>::max();
@@ -502,38 +490,38 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
} }
} }
m_realSize->setValueAndWarp(m_geometry.size()); realSize->setValueAndWarp(geometry.size());
m_alpha->setValueAndWarp(in ? 0.f : 1.f); alpha->setValueAndWarp(in ? 0.f : 1.f);
*m_alpha = in ? 1.f : 0.f; *alpha = in ? 1.f : 0.f;
Vector2D prePos; Vector2D prePos;
switch (leader) { switch (leader) {
case 0: case 0:
// TOP // TOP
prePos = {m_geometry.x, PMONITOR->m_position.y - m_geometry.h}; prePos = {geometry.x, PMONITOR->vecPosition.y - geometry.h};
break; break;
case 1: case 1:
// BOTTOM // BOTTOM
prePos = {m_geometry.x, PMONITOR->m_position.y + PMONITOR->m_size.y}; prePos = {geometry.x, PMONITOR->vecPosition.y + PMONITOR->vecSize.y};
break; break;
case 2: case 2:
// LEFT // LEFT
prePos = {PMONITOR->m_position.x - m_geometry.w, m_geometry.y}; prePos = {PMONITOR->vecPosition.x - geometry.w, geometry.y};
break; break;
case 3: case 3:
// RIGHT // RIGHT
prePos = {PMONITOR->m_position.x + PMONITOR->m_size.x, m_geometry.y}; prePos = {PMONITOR->vecPosition.x + PMONITOR->vecSize.x, geometry.y};
break; break;
default: UNREACHABLE(); default: UNREACHABLE();
} }
if (in) { if (in) {
m_realPosition->setValueAndWarp(prePos); realPosition->setValueAndWarp(prePos);
*m_realPosition = m_geometry.pos(); *realPosition = geometry.pos();
} else { } else {
m_realPosition->setValueAndWarp(m_geometry.pos()); realPosition->setValueAndWarp(geometry.pos());
*m_realPosition = prePos; *realPosition = prePos;
} }
} else if (ANIMSTYLE.starts_with("popin")) { } else if (ANIMSTYLE.starts_with("popin")) {
@@ -549,62 +537,50 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
minPerc *= 0.01; minPerc *= 0.01;
const auto GOALSIZE = (m_geometry.size() * minPerc).clamp({5, 5}); const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5});
const auto GOALPOS = m_geometry.pos() + (m_geometry.size() - GOALSIZE) / 2.f; const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f;
m_alpha->setValueAndWarp(in ? 0.f : 1.f); alpha->setValueAndWarp(in ? 0.f : 1.f);
*m_alpha = in ? 1.f : 0.f; *alpha = in ? 1.f : 0.f;
if (in) { if (in) {
m_realSize->setValueAndWarp(GOALSIZE); realSize->setValueAndWarp(GOALSIZE);
m_realPosition->setValueAndWarp(GOALPOS); realPosition->setValueAndWarp(GOALPOS);
*m_realSize = m_geometry.size(); *realSize = geometry.size();
*m_realPosition = m_geometry.pos(); *realPosition = geometry.pos();
} else { } else {
m_realSize->setValueAndWarp(m_geometry.size()); realSize->setValueAndWarp(geometry.size());
m_realPosition->setValueAndWarp(m_geometry.pos()); realPosition->setValueAndWarp(geometry.pos());
*m_realSize = GOALSIZE; *realSize = GOALSIZE;
*m_realPosition = GOALPOS; *realPosition = GOALPOS;
} }
} else { } else {
// fade // fade
m_realPosition->setValueAndWarp(m_geometry.pos()); realPosition->setValueAndWarp(geometry.pos());
m_realSize->setValueAndWarp(m_geometry.size()); realSize->setValueAndWarp(geometry.size());
*m_alpha = in ? 1.f : 0.f; *alpha = in ? 1.f : 0.f;
} }
if (!in) if (!in)
m_fadingOut = true; fadingOut = true;
} }
bool CLayerSurface::isFadedOut() { bool CLayerSurface::isFadedOut() {
if (!m_fadingOut) if (!fadingOut)
return false; return false;
return !m_realPosition->isBeingAnimated() && !m_realSize->isBeingAnimated() && !m_alpha->isBeingAnimated(); return !realPosition->isBeingAnimated() && !realSize->isBeingAnimated() && !alpha->isBeingAnimated();
} }
int CLayerSurface::popupsCount() { int CLayerSurface::popupsCount() {
if (!m_layerSurface || !m_mapped || m_fadingOut) if (!layerSurface || !mapped || fadingOut)
return 0; return 0;
int no = -1; // we have one dummy int no = -1; // we have one dummy
m_popupHead->breadthfirst([](WP<CPopup> p, void* data) { *(int*)data += 1; }, &no); popupHead->breadthfirst([](WP<CPopup> p, void* data) { *(int*)data += 1; }, &no);
return no; return no;
} }
MONITORID CLayerSurface::monitorID() { MONITORID CLayerSurface::monitorID() {
return m_monitor ? m_monitor->m_id : MONITOR_INVALID; return monitor ? monitor->ID : MONITOR_INVALID;
}
pid_t CLayerSurface::getPID() {
pid_t PID = -1;
if (!m_layerSurface || !m_layerSurface->m_surface || !m_layerSurface->m_surface->getResource() || !m_layerSurface->m_surface->getResource()->resource() ||
!m_layerSurface->m_surface->getResource()->resource()->client)
return -1;
wl_client_get_credentials(m_layerSurface->m_surface->getResource()->resource()->client, &PID, nullptr, nullptr);
return PID;
} }

View File

@@ -22,47 +22,44 @@ class CLayerSurface {
bool isFadedOut(); bool isFadedOut();
int popupsCount(); int popupsCount();
PHLANIMVAR<Vector2D> m_realPosition; PHLANIMVAR<Vector2D> realPosition;
PHLANIMVAR<Vector2D> m_realSize; PHLANIMVAR<Vector2D> realSize;
PHLANIMVAR<float> m_alpha; PHLANIMVAR<float> alpha;
WP<CLayerShellResource> m_layerSurface; WP<CLayerShellResource> layerSurface;
wl_list link;
// the header providing the enum type cannot be imported here // the header providing the enum type cannot be imported here
int m_interactivity = 0; int interactivity = 0;
SP<CWLSurface> m_surface; SP<CWLSurface> surface;
bool m_mapped = false; bool mapped = false;
uint32_t m_layer = 0; uint32_t layer = 0;
PHLMONITORREF m_monitor; PHLMONITORREF monitor;
bool m_fadingOut = false; bool fadingOut = false;
bool m_readyToDelete = false; bool readyToDelete = false;
bool m_noProcess = false; bool noProcess = false;
bool m_noAnimations = false; bool noAnimations = false;
bool m_forceBlur = false; bool forceBlur = false;
bool m_forceBlurPopups = false; bool forceBlurPopups = false;
int64_t m_xray = -1; int64_t xray = -1;
bool m_ignoreAlpha = false; bool ignoreAlpha = false;
float m_ignoreAlphaValue = 0.f; float ignoreAlphaValue = 0.f;
bool m_dimAround = false; bool dimAround = false;
int64_t m_order = 0; int64_t order = 0;
bool m_aboveLockscreen = false;
bool m_aboveLockscreenInteractable = false;
std::optional<std::string> m_animationStyle; std::optional<std::string> animationStyle;
PHLLSREF m_self; PHLLSREF self;
CBox m_geometry = {0, 0, 0, 0}; CBox geometry = {0, 0, 0, 0};
Vector2D m_position; Vector2D position;
std::string m_namespace = ""; std::string szNamespace = "";
UP<CPopup> m_popupHead; UP<CPopup> popupHead;
pid_t getPID();
void onDestroy(); void onDestroy();
void onMap(); void onMap();
@@ -76,12 +73,12 @@ class CLayerSurface {
CHyprSignalListener map; CHyprSignalListener map;
CHyprSignalListener unmap; CHyprSignalListener unmap;
CHyprSignalListener commit; CHyprSignalListener commit;
} m_listeners; } listeners;
void registerCallbacks(); void registerCallbacks();
// For the list lookup // For the list lookup
bool operator==(const CLayerSurface& rhs) const { bool operator==(const CLayerSurface& rhs) const {
return m_layerSurface == rhs.m_layerSurface && m_monitor == rhs.m_monitor; return layerSurface == rhs.layerSurface && monitor == rhs.monitor;
} }
}; };

View File

@@ -5,154 +5,132 @@
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp" #include "../managers/SeatManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include "../desktop/LayerSurface.hpp" #include "../desktop/LayerSurface.hpp"
#include "../managers/input/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
#include "../render/OpenGL.hpp" #include "../render/OpenGL.hpp"
#include <ranges> #include <ranges>
UP<CPopup> CPopup::create(PHLWINDOW pOwner) { CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) {
auto popup = UP<CPopup>(new CPopup()); initAllSignals();
popup->m_windowOwner = pOwner;
popup->m_self = popup;
popup->initAllSignals();
return popup;
} }
UP<CPopup> CPopup::create(PHLLS pOwner) { CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) {
auto popup = UP<CPopup>(new CPopup()); initAllSignals();
popup->m_layerOwner = pOwner;
popup->m_self = popup;
popup->initAllSignals();
return popup;
} }
UP<CPopup> CPopup::create(SP<CXDGPopupResource> resource, WP<CPopup> pOwner) { CPopup::CPopup(SP<CXDGPopupResource> popup, WP<CPopup> pOwner) :
auto popup = UP<CPopup>(new CPopup()); m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) {
popup->m_resource = resource; m_pWLSurface = CWLSurface::create();
popup->m_windowOwner = pOwner->m_windowOwner; m_pWLSurface->assign(popup->surface->surface.lock(), this);
popup->m_layerOwner = pOwner->m_layerOwner;
popup->m_parent = pOwner;
popup->m_self = popup;
popup->m_wlSurface = CWLSurface::create();
popup->m_wlSurface->assign(resource->m_surface->m_surface.lock(), popup.get());
popup->m_lastSize = resource->m_surface->m_current.geometry.size(); m_vLastSize = popup->surface->current.geometry.size();
popup->reposition(); reposition();
popup->initAllSignals(); initAllSignals();
return popup;
} }
CPopup::~CPopup() { CPopup::~CPopup() {
if (m_wlSurface) if (m_pWLSurface)
m_wlSurface->unassign(); m_pWLSurface->unassign();
} }
void CPopup::initAllSignals() { void CPopup::initAllSignals() {
if (!m_resource) { if (!m_pResource) {
if (!m_windowOwner.expired()) if (!m_pWindowOwner.expired())
m_listeners.newPopup = listeners.newPopup = m_pWindowOwner->m_pXDGSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
m_windowOwner->m_xdgSurface->m_events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); }); else if (!m_pLayerOwner.expired())
else if (!m_layerOwner.expired()) listeners.newPopup = m_pLayerOwner->layerSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
m_listeners.newPopup =
m_layerOwner->m_layerSurface->m_events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
else else
ASSERT(false); ASSERT(false);
return; return;
} }
m_listeners.reposition = m_resource->m_events.reposition.registerListener([this](std::any d) { this->onReposition(); }); listeners.reposition = m_pResource->events.reposition.registerListener([this](std::any d) { this->onReposition(); });
m_listeners.map = m_resource->m_surface->m_events.map.registerListener([this](std::any d) { this->onMap(); }); listeners.map = m_pResource->surface->events.map.registerListener([this](std::any d) { this->onMap(); });
m_listeners.unmap = m_resource->m_surface->m_events.unmap.registerListener([this](std::any d) { this->onUnmap(); }); listeners.unmap = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); });
m_listeners.dismissed = m_resource->m_events.dismissed.registerListener([this](std::any d) { this->onUnmap(); }); listeners.dismissed = m_pResource->events.dismissed.registerListener([this](std::any d) { this->onUnmap(); });
m_listeners.destroy = m_resource->m_surface->m_events.destroy.registerListener([this](std::any d) { this->onDestroy(); }); listeners.destroy = m_pResource->surface->events.destroy.registerListener([this](std::any d) { this->onDestroy(); });
m_listeners.commit = m_resource->m_surface->m_events.commit.registerListener([this](std::any d) { this->onCommit(); }); listeners.commit = m_pResource->surface->events.commit.registerListener([this](std::any d) { this->onCommit(); });
m_listeners.newPopup = m_resource->m_surface->m_events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); }); listeners.newPopup = m_pResource->surface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
} }
void CPopup::onNewPopup(SP<CXDGPopupResource> popup) { void CPopup::onNewPopup(SP<CXDGPopupResource> popup) {
const auto& POPUP = m_children.emplace_back(CPopup::create(popup, m_self)); const auto& POPUP = m_vChildren.emplace_back(makeShared<CPopup>(popup, m_pSelf));
POPUP->m_self = POPUP; POPUP->m_pSelf = POPUP;
Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP);
} }
void CPopup::onDestroy() { void CPopup::onDestroy() {
m_inert = true; m_bInert = true;
if (!m_parent) if (!m_pParent)
return; // head node return; // head node
std::erase_if(m_parent->m_children, [this](const auto& other) { return other.get() == this; }); std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
} }
void CPopup::onMap() { void CPopup::onMap() {
if (m_mapped) if (m_bMapped)
return; return;
m_mapped = true; m_bMapped = true;
m_lastSize = m_resource->m_surface->m_surface->m_current.size; m_vLastSize = m_pResource->surface->surface->current.size;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS); const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
CBox box = m_wlSurface->resource()->extends(); CBox box = m_pWLSurface->resource()->extends();
box.translate(COORDS).expand(4); box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
m_lastPos = coordsRelativeToParent(); m_vLastPos = coordsRelativeToParent();
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
m_subsurfaceHead = CSubsurface::create(m_self); m_pSubsurfaceHead = makeUnique<CSubsurface>(m_pSelf);
m_pSubsurfaceHead->m_pSelf = m_pSubsurfaceHead;
//unconstrain(); //unconstrain();
sendScale(); sendScale();
m_resource->m_surface->m_surface->enter(PMONITOR->m_self.lock()); m_pResource->surface->surface->enter(PMONITOR->self.lock());
if (!m_layerOwner.expired() && m_layerOwner->m_layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_layerOwner->m_layer)); g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
} }
void CPopup::onUnmap() { void CPopup::onUnmap() {
if (!m_mapped) if (!m_bMapped)
return; return;
if (!m_resource || !m_resource->m_surface) { if (!m_pResource || !m_pResource->surface) {
Debug::log(ERR, "CPopup: orphaned (no surface/resource) and unmaps??"); Debug::log(ERR, "CPopup: orphaned (no surface/resource) and unmaps??");
onDestroy(); onDestroy();
return; return;
} }
m_mapped = false; m_bMapped = false;
// if the popup committed a different size right now, we also need to damage the old size. m_vLastSize = m_pResource->surface->surface->current.size;
const Vector2D MAX_DAMAGE_SIZE = {std::max(m_lastSize.x, m_resource->m_surface->m_surface->m_current.size.x),
std::max(m_lastSize.y, m_resource->m_surface->m_surface->m_current.size.y)};
m_lastSize = m_resource->m_surface->m_surface->m_current.size;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
CBox box = m_wlSurface->resource()->extends(); CBox box = m_pWLSurface->resource()->extends();
box.translate(COORDS).expand(4); box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
// damage the last popup's explicit max size as well m_pSubsurfaceHead.reset();
box = CBox{COORDS, MAX_DAMAGE_SIZE}.expand(4);
g_pHyprRenderer->damageBox(box);
m_subsurfaceHead.reset(); if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
if (!m_layerOwner.expired() && m_layerOwner->m_layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_layerOwner->m_layer));
// damage all children // damage all children
breadthfirst( breadthfirst(
[](WP<CPopup> p, void* data) { [](WP<CPopup> p, void* data) {
if (!p->m_resource) if (!p->m_pResource)
return; return;
auto box = CBox{p->coordsGlobal(), p->size()}; auto box = CBox{p->coordsGlobal(), p->size()};
@@ -168,59 +146,59 @@ void CPopup::onUnmap() {
} }
void CPopup::onCommit(bool ignoreSiblings) { void CPopup::onCommit(bool ignoreSiblings) {
if (!m_resource || !m_resource->m_surface) { if (!m_pResource || !m_pResource->surface) {
Debug::log(ERR, "CPopup: orphaned (no surface/resource) and commits??"); Debug::log(ERR, "CPopup: orphaned (no surface/resource) and commits??");
onDestroy(); onDestroy();
return; return;
} }
if (m_resource->m_surface->m_initialCommit) { if (m_pResource->surface->initialCommit) {
m_resource->m_surface->scheduleConfigure(); m_pResource->surface->scheduleConfigure();
return; return;
} }
if (!m_windowOwner.expired() && (!m_windowOwner->m_isMapped || !m_windowOwner->m_workspace->m_visible)) { if (!m_pWindowOwner.expired() && (!m_pWindowOwner->m_bIsMapped || !m_pWindowOwner->m_pWorkspace->m_bVisible)) {
m_lastSize = m_resource->m_surface->m_surface->m_current.size; m_vLastSize = m_pResource->surface->surface->current.size;
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage"); static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
if (*PLOGDAMAGE) if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_windowOwner.lock()); Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_pWindowOwner.lock());
return; return;
} }
if (!m_resource->m_surface->m_mapped) if (!m_pResource->surface->mapped)
return; return;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
const auto COORDSLOCAL = coordsRelativeToParent(); const auto COORDSLOCAL = coordsRelativeToParent();
if (m_lastSize != m_resource->m_surface->m_surface->m_current.size || m_requestedReposition || m_lastPos != COORDSLOCAL) { if (m_vLastSize != m_pResource->surface->surface->current.size || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) {
CBox box = {localToGlobal(m_lastPos), m_lastSize}; CBox box = {localToGlobal(m_vLastPos), m_vLastSize};
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
m_lastSize = m_resource->m_surface->m_surface->m_current.size; m_vLastSize = m_pResource->surface->surface->current.size;
box = {COORDS, m_lastSize}; box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
m_lastPos = COORDSLOCAL; m_vLastPos = COORDSLOCAL;
} }
if (!ignoreSiblings && m_subsurfaceHead) if (!ignoreSiblings && m_pSubsurfaceHead)
m_subsurfaceHead->recheckDamageForSubsurfaces(); m_pSubsurfaceHead->recheckDamageForSubsurfaces();
g_pHyprRenderer->damageSurface(m_wlSurface->resource(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y);
m_requestedReposition = false; m_bRequestedReposition = false;
if (!m_layerOwner.expired() && m_layerOwner->m_layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_layerOwner->m_layer)); g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
} }
void CPopup::onReposition() { void CPopup::onReposition() {
Debug::log(LOG, "Popup {:x} requests reposition", (uintptr_t)this); Debug::log(LOG, "Popup {:x} requests reposition", (uintptr_t)this);
m_requestedReposition = true; m_bRequestedReposition = true;
m_lastPos = coordsRelativeToParent(); m_vLastPos = coordsRelativeToParent();
reposition(); reposition();
} }
@@ -232,32 +210,32 @@ void CPopup::reposition() {
if (!PMONITOR) if (!PMONITOR)
return; return;
CBox box = {PMONITOR->m_position.x, PMONITOR->m_position.y, PMONITOR->m_size.x, PMONITOR->m_size.y}; CBox box = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
m_resource->applyPositioning(box, COORDS); m_pResource->applyPositioning(box, COORDS);
} }
SP<CWLSurface> CPopup::getT1Owner() { SP<CWLSurface> CPopup::getT1Owner() {
if (m_windowOwner) if (m_pWindowOwner)
return m_windowOwner->m_wlSurface; return m_pWindowOwner->m_pWLSurface;
else else
return m_layerOwner->m_surface; return m_pLayerOwner->surface;
} }
Vector2D CPopup::coordsRelativeToParent() { Vector2D CPopup::coordsRelativeToParent() {
Vector2D offset; Vector2D offset;
if (!m_resource) if (!m_pResource)
return {}; return {};
WP<CPopup> current = m_self; WP<CPopup> current = m_pSelf;
offset -= current->m_resource->m_surface->m_current.geometry.pos(); offset -= current->m_pResource->surface->current.geometry.pos();
while (current->m_parent && current->m_resource) { while (current->m_pParent && current->m_pResource) {
offset += current->m_wlSurface->resource()->m_current.offset; offset += current->m_pWLSurface->resource()->current.offset;
offset += current->m_resource->m_geometry.pos(); offset += current->m_pResource->geometry.pos();
current = current->m_parent; current = current->m_pParent;
} }
return offset; return offset;
@@ -272,30 +250,26 @@ Vector2D CPopup::localToGlobal(const Vector2D& rel) {
} }
Vector2D CPopup::t1ParentCoords() { Vector2D CPopup::t1ParentCoords() {
if (!m_windowOwner.expired()) if (!m_pWindowOwner.expired())
return m_windowOwner->m_realPosition->value(); return m_pWindowOwner->m_vRealPosition->value();
if (!m_layerOwner.expired()) if (!m_pLayerOwner.expired())
return m_layerOwner->m_realPosition->value(); return m_pLayerOwner->realPosition->value();
ASSERT(false); ASSERT(false);
return {}; return {};
} }
void CPopup::recheckTree() { void CPopup::recheckTree() {
WP<CPopup> curr = m_self; WP<CPopup> curr = m_pSelf;
while (curr->m_parent) { while (curr->m_pParent) {
curr = curr->m_parent; curr = curr->m_pParent;
} }
curr->recheckChildrenRecursive(); curr->recheckChildrenRecursive();
} }
void CPopup::recheckChildrenRecursive() { void CPopup::recheckChildrenRecursive() {
if (m_inert || !m_wlSurface) auto cpy = m_vChildren;
return;
std::vector<WP<CPopup>> cpy;
std::ranges::for_each(m_children, [&cpy](const auto& el) { cpy.emplace_back(el); });
for (auto const& c : cpy) { for (auto const& c : cpy) {
c->onCommit(true); c->onCommit(true);
c->recheckChildrenRecursive(); c->recheckChildrenRecursive();
@@ -303,25 +277,25 @@ void CPopup::recheckChildrenRecursive() {
} }
Vector2D CPopup::size() { Vector2D CPopup::size() {
return m_lastSize; return m_vLastSize;
} }
void CPopup::sendScale() { void CPopup::sendScale() {
if (!m_windowOwner.expired()) if (!m_pWindowOwner.expired())
g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), m_windowOwner->m_wlSurface->m_lastScaleFloat); g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pWindowOwner->m_pWLSurface->m_fLastScale);
else if (!m_layerOwner.expired()) else if (!m_pLayerOwner.expired())
g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), m_layerOwner->m_surface->m_lastScaleFloat); g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pLayerOwner->surface->m_fLastScale);
else else
UNREACHABLE(); UNREACHABLE();
} }
bool CPopup::visible() { bool CPopup::visible() {
if (!m_windowOwner.expired()) if (!m_pWindowOwner.expired())
return g_pHyprRenderer->shouldRenderWindow(m_windowOwner.lock()); return g_pHyprRenderer->shouldRenderWindow(m_pWindowOwner.lock());
if (!m_layerOwner.expired()) if (!m_pLayerOwner.expired())
return true; return true;
if (m_parent) if (m_pParent)
return m_parent->visible(); return m_pParent->visible();
return false; return false;
} }
@@ -335,8 +309,8 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
nodes2.reserve(nodes.size() * 2); nodes2.reserve(nodes.size() * 2);
for (auto const& n : nodes) { for (auto const& n : nodes) {
for (auto const& c : n->m_children) { for (auto const& c : n->m_vChildren) {
nodes2.push_back(c->m_self); nodes2.push_back(c->m_pSelf);
} }
} }
@@ -346,32 +320,29 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
void CPopup::breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data) { void CPopup::breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data) {
std::vector<WP<CPopup>> popups; std::vector<WP<CPopup>> popups;
popups.push_back(m_self); popups.push_back(m_pSelf);
bfHelper(popups, fn, data); bfHelper(popups, fn, data);
} }
WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) { WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
std::vector<WP<CPopup>> popups; std::vector<WP<CPopup>> popups;
breadthfirst([&popups](WP<CPopup> popup, void* data) { popups.push_back(popup); }, &popups); breadthfirst([](WP<CPopup> popup, void* data) { ((std::vector<WP<CPopup>>*)data)->push_back(popup); }, &popups);
for (auto const& p : popups | std::views::reverse) { for (auto const& p : popups | std::views::reverse) {
if (!p->m_resource || !p->m_mapped) if (!p->m_pResource || !p->m_bMapped)
continue; continue;
if (!allowsInput) { if (!allowsInput) {
const bool HASSURFACE = p->m_resource && p->m_resource->m_surface; const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{};
const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size();
Vector2D offset = HASSURFACE ? p->m_resource->m_surface->m_current.geometry.pos() : Vector2D{}; const auto BOX = CBox{p->coordsGlobal() + offset, size};
Vector2D size = HASSURFACE ? p->m_resource->m_surface->m_current.geometry.size() : p->size();
if (size == Vector2D{})
size = p->size();
const auto BOX = CBox{p->coordsGlobal() + offset, size};
if (BOX.containsPoint(globalCoords)) if (BOX.containsPoint(globalCoords))
return p; return p;
} else { } else {
const auto REGION = CRegion{p->m_wlSurface->resource()->m_current.input}.intersect(CBox{{}, p->m_wlSurface->resource()->m_current.size}).translate(p->coordsGlobal()); const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{};
const auto REGION =
CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset);
if (REGION.containsPoint(globalCoords)) if (REGION.containsPoint(globalCoords))
return p; return p;
} }
@@ -379,7 +350,3 @@ WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
return {}; return {};
} }
bool CPopup::inert() const {
return m_inert;
}

View File

@@ -10,11 +10,11 @@ class CXDGPopupResource;
class CPopup { class CPopup {
public: public:
// dummy head nodes // dummy head nodes
static UP<CPopup> create(PHLWINDOW pOwner); CPopup(PHLWINDOW pOwner);
static UP<CPopup> create(PHLLS pOwner); CPopup(PHLLS pOwner);
// real nodes // real nodes
static UP<CPopup> create(SP<CXDGPopupResource> popup, WP<CPopup> pOwner); CPopup(SP<CXDGPopupResource> popup, WP<CPopup> pOwner);
~CPopup(); ~CPopup();
@@ -34,39 +34,36 @@ class CPopup {
void recheckTree(); void recheckTree();
bool visible(); bool visible();
bool inert() const;
// will also loop over this node // will also loop over this node
void breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data); void breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data);
WP<CPopup> at(const Vector2D& globalCoords, bool allowsInput = false); WP<CPopup> at(const Vector2D& globalCoords, bool allowsInput = false);
// //
SP<CWLSurface> m_wlSurface; SP<CWLSurface> m_pWLSurface;
WP<CPopup> m_self; WP<CPopup> m_pSelf;
bool m_mapped = false; bool m_bMapped = false;
private: private:
CPopup() = default;
// T1 owners, each popup has to have one of these // T1 owners, each popup has to have one of these
PHLWINDOWREF m_windowOwner; PHLWINDOWREF m_pWindowOwner;
PHLLSREF m_layerOwner; PHLLSREF m_pLayerOwner;
// T2 owners // T2 owners
WP<CPopup> m_parent; WP<CPopup> m_pParent;
WP<CXDGPopupResource> m_resource; WP<CXDGPopupResource> m_pResource;
Vector2D m_lastSize = {}; Vector2D m_vLastSize = {};
Vector2D m_lastPos = {}; Vector2D m_vLastPos = {};
bool m_requestedReposition = false; bool m_bRequestedReposition = false;
bool m_inert = false; bool m_bInert = false;
// //
std::vector<UP<CPopup>> m_children; std::vector<SP<CPopup>> m_vChildren;
UP<CSubsurface> m_subsurfaceHead; UP<CSubsurface> m_pSubsurfaceHead;
struct { struct {
CHyprSignalListener newPopup; CHyprSignalListener newPopup;
@@ -76,7 +73,7 @@ class CPopup {
CHyprSignalListener commit; CHyprSignalListener commit;
CHyprSignalListener dismissed; CHyprSignalListener dismissed;
CHyprSignalListener reposition; CHyprSignalListener reposition;
} m_listeners; } listeners;
void initAllSignals(); void initAllSignals();
void reposition(); void reposition();

View File

@@ -6,17 +6,17 @@
CRuleRegexContainer::CRuleRegexContainer(const std::string& regex_) { CRuleRegexContainer::CRuleRegexContainer(const std::string& regex_) {
const bool NEGATIVE = regex_.starts_with("negative:"); const bool NEGATIVE = regex_.starts_with("negative:");
m_negative = NEGATIVE; negative = NEGATIVE;
m_regex = makeUnique<RE2>(NEGATIVE ? regex_.substr(9) : regex_); regex = makeUnique<RE2>(NEGATIVE ? regex_.substr(9) : regex_);
// TODO: maybe pop an error? // TODO: maybe pop an error?
if (!m_regex->ok()) if (!regex->ok())
Debug::log(ERR, "RuleRegexContainer: regex {} failed to parse!", regex_); Debug::log(ERR, "RuleRegexContainer: regex {} failed to parse!", regex_);
} }
bool CRuleRegexContainer::passes(const std::string& str) const { bool CRuleRegexContainer::passes(const std::string& str) const {
if (!m_regex) if (!regex)
return false; return false;
return RE2::FullMatch(str, *m_regex) != m_negative; return RE2::FullMatch(str, *regex) != negative;
} }

View File

@@ -16,6 +16,6 @@ class CRuleRegexContainer {
bool passes(const std::string& str) const; bool passes(const std::string& str) const;
private: private:
Hyprutils::Memory::CUniquePointer<re2::RE2> m_regex; Hyprutils::Memory::CUniquePointer<re2::RE2> regex;
bool m_negative = false; bool negative = false;
}; };

View File

@@ -7,63 +7,48 @@
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
#include "../managers/input/InputManager.hpp" #include "../managers/input/InputManager.hpp"
UP<CSubsurface> CSubsurface::create(PHLWINDOW pOwner) { CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); initSignals();
subsurface->m_windowParent = pOwner; initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
subsurface->m_self = subsurface;
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_wlSurface->resource());
return subsurface;
} }
UP<CSubsurface> CSubsurface::create(WP<CPopup> pOwner) { CSubsurface::CSubsurface(WP<CPopup> pOwner) : m_pPopupParent(pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); initSignals();
subsurface->m_popupParent = pOwner; initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
subsurface->m_self = subsurface;
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_wlSurface->resource());
return subsurface;
} }
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) { CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); m_pWLSurface = CWLSurface::create();
subsurface->m_windowParent = pOwner; m_pWLSurface->assign(pSubsurface->surface.lock(), this);
subsurface->m_subsurface = pSubsurface; initSignals();
subsurface->m_self = subsurface; initExistingSubsurfaces(pSubsurface->surface.lock());
subsurface->m_wlSurface = CWLSurface::create();
subsurface->m_wlSurface->assign(pSubsurface->m_surface.lock(), subsurface.get());
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pSubsurface->m_surface.lock());
return subsurface;
} }
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner) { CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); m_pWLSurface = CWLSurface::create();
subsurface->m_popupParent = pOwner; m_pWLSurface->assign(pSubsurface->surface.lock(), this);
subsurface->m_subsurface = pSubsurface; initSignals();
subsurface->m_self = subsurface; initExistingSubsurfaces(pSubsurface->surface.lock());
subsurface->m_wlSurface = CWLSurface::create(); }
subsurface->m_wlSurface->assign(pSubsurface->m_surface.lock(), subsurface.get());
subsurface->initSignals(); CSubsurface::~CSubsurface() {
subsurface->initExistingSubsurfaces(pSubsurface->m_surface.lock()); ;
return subsurface;
} }
void CSubsurface::initSignals() { void CSubsurface::initSignals() {
if (m_subsurface) { if (m_pSubsurface) {
m_listeners.commitSubsurface = m_subsurface->m_surface->m_events.commit.registerListener([this](std::any d) { onCommit(); }); listeners.commitSubsurface = m_pSubsurface->surface->events.commit.registerListener([this](std::any d) { onCommit(); });
m_listeners.destroySubsurface = m_subsurface->m_events.destroy.registerListener([this](std::any d) { onDestroy(); }); listeners.destroySubsurface = m_pSubsurface->events.destroy.registerListener([this](std::any d) { onDestroy(); });
m_listeners.mapSubsurface = m_subsurface->m_surface->m_events.map.registerListener([this](std::any d) { onMap(); }); listeners.mapSubsurface = m_pSubsurface->surface->events.map.registerListener([this](std::any d) { onMap(); });
m_listeners.unmapSubsurface = m_subsurface->m_surface->m_events.unmap.registerListener([this](std::any d) { onUnmap(); }); listeners.unmapSubsurface = m_pSubsurface->surface->events.unmap.registerListener([this](std::any d) { onUnmap(); });
m_listeners.newSubsurface = listeners.newSubsurface =
m_subsurface->m_surface->m_events.newSubsurface.registerListener([this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); }); m_pSubsurface->surface->events.newSubsurface.registerListener([this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); });
} else { } else {
if (m_windowParent) if (m_pWindowParent)
m_listeners.newSubsurface = m_windowParent->m_wlSurface->resource()->m_events.newSubsurface.registerListener( listeners.newSubsurface = m_pWindowParent->m_pWLSurface->resource()->events.newSubsurface.registerListener(
[this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); }); [this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); });
else if (m_popupParent) else if (m_pPopupParent)
m_listeners.newSubsurface = m_popupParent->m_wlSurface->resource()->m_events.newSubsurface.registerListener( listeners.newSubsurface = m_pPopupParent->m_pWLSurface->resource()->events.newSubsurface.registerListener(
[this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); }); [this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); });
else else
ASSERT(false); ASSERT(false);
@@ -71,102 +56,115 @@ void CSubsurface::initSignals() {
} }
void CSubsurface::checkSiblingDamage() { void CSubsurface::checkSiblingDamage() {
if (!m_parent) if (!m_pParent)
return; // ?????????? return; // ??????????
const double SCALE = m_windowParent.lock() && m_windowParent->m_isX11 ? 1.0 / m_windowParent->m_X11SurfaceScaledBy : 1.0; const double SCALE = m_pWindowParent.lock() && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0;
for (auto const& n : m_parent->m_children) { for (auto const& n : m_pParent->m_vChildren) {
if (n.get() == this) if (n.get() == this)
continue; continue;
const auto COORDS = n->coordsGlobal(); const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_wlSurface->resource(), COORDS.x, COORDS.y, SCALE); g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y, SCALE);
} }
} }
void CSubsurface::recheckDamageForSubsurfaces() { void CSubsurface::recheckDamageForSubsurfaces() {
for (auto const& n : m_children) { for (auto const& n : m_vChildren) {
const auto COORDS = n->coordsGlobal(); const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_wlSurface->resource(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y);
} }
} }
void CSubsurface::onCommit() { void CSubsurface::onCommit() {
// no damaging if it's not visible // no damaging if it's not visible
if (!m_windowParent.expired() && (!m_windowParent->m_isMapped || !m_windowParent->m_workspace->m_visible)) { if (!m_pWindowParent.expired() && (!m_pWindowParent->m_bIsMapped || !m_pWindowParent->m_pWorkspace->m_bVisible)) {
m_lastSize = m_wlSurface->resource()->m_current.size; m_vLastSize = m_pWLSurface->resource()->current.size;
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage"); static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
if (*PLOGDAMAGE) if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_windowParent.lock()); Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_pWindowParent.lock());
return; return;
} }
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
g_pHyprRenderer->damageSurface(m_wlSurface->resource(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y);
if (m_popupParent && !m_popupParent->inert() && m_popupParent->m_wlSurface) if (m_pPopupParent)
m_popupParent->recheckTree(); m_pPopupParent->recheckTree();
if (!m_windowParent.expired()) // I hate you firefox why are you doing this if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this
m_windowParent->m_popupHead->recheckTree(); m_pWindowParent->m_pPopupHead->recheckTree();
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox) // I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
checkSiblingDamage(); checkSiblingDamage();
if (m_lastSize != m_wlSurface->resource()->m_current.size || m_lastPosition != m_subsurface->m_position) { if (m_vLastSize != m_pWLSurface->resource()->current.size) {
damageLastArea(); // TODO: fix this
m_lastSize = m_wlSurface->resource()->m_current.size; // CBox box{COORDS, m_vLastSize};
m_lastPosition = m_subsurface->m_position; // g_pHyprRenderer->damageBox(box);
// m_vLastSize = m_pWLSurface->resource()->current.size;
// box = {COORDS, m_vLastSize};
// g_pHyprRenderer->damageBox(box);
CBox box;
if (m_pPopupParent)
box = m_pPopupParent->m_pWLSurface->getSurfaceBoxGlobal().value_or(CBox{});
else if (m_pWindowParent)
box = m_pWindowParent->getWindowMainSurfaceBox();
g_pHyprRenderer->damageBox(box);
} }
} }
void CSubsurface::onDestroy() { void CSubsurface::onDestroy() {
// destroy children // destroy children
m_children.clear(); m_vChildren.clear();
m_inert = true; m_bInert = true;
if (!m_subsurface) if (!m_pSubsurface)
return; // dummy node, nothing to do, it's the parent dying return; // dummy node, nothing to do, it's the parent dying
// kill ourselves // kill ourselves
std::erase_if(m_parent->m_children, [this](const auto& other) { return other.get() == this; }); std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
} }
void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) { void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) {
WP<CSubsurface> PSUBSURFACE; WP<CSubsurface> PSUBSURFACE;
if (!m_windowParent.expired()) if (!m_pWindowParent.expired())
PSUBSURFACE = m_children.emplace_back(CSubsurface::create(pSubsurface, m_windowParent.lock())); PSUBSURFACE = m_vChildren.emplace_back(makeUnique<CSubsurface>(pSubsurface, m_pWindowParent.lock()));
else if (m_popupParent) else if (m_pPopupParent)
PSUBSURFACE = m_children.emplace_back(CSubsurface::create(pSubsurface, m_popupParent)); PSUBSURFACE = m_vChildren.emplace_back(makeUnique<CSubsurface>(pSubsurface, m_pPopupParent));
PSUBSURFACE->m_self = PSUBSURFACE; PSUBSURFACE->m_pSelf = PSUBSURFACE;
ASSERT(PSUBSURFACE); ASSERT(PSUBSURFACE);
PSUBSURFACE->m_parent = m_self; PSUBSURFACE->m_pParent = m_pSelf;
} }
void CSubsurface::onMap() { void CSubsurface::onMap() {
m_lastSize = m_wlSurface->resource()->m_current.size; m_vLastSize = m_pWLSurface->resource()->current.size;
m_lastPosition = m_subsurface->m_position;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
CBox box{COORDS, m_lastSize}; CBox box{COORDS, m_vLastSize};
box.expand(4); box.expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
if (!m_windowParent.expired()) if (!m_pWindowParent.expired())
m_windowParent->updateSurfaceScaleTransformDetails(); m_pWindowParent->updateSurfaceScaleTransformDetails();
} }
void CSubsurface::onUnmap() { void CSubsurface::onUnmap() {
damageLastArea(); const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize};
box.expand(4);
g_pHyprRenderer->damageBox(box);
if (m_wlSurface->resource() == g_pCompositor->m_lastFocus) if (m_pWLSurface->resource() == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
@@ -174,49 +172,42 @@ void CSubsurface::onUnmap() {
// TODO: should this remove children? Currently it won't, only on .destroy // TODO: should this remove children? Currently it won't, only on .destroy
} }
void CSubsurface::damageLastArea() {
const auto COORDS = coordsGlobal() + m_lastPosition - m_subsurface->m_position;
CBox box{COORDS, m_lastSize};
box.expand(4);
g_pHyprRenderer->damageBox(box);
}
Vector2D CSubsurface::coordsRelativeToParent() { Vector2D CSubsurface::coordsRelativeToParent() {
if (!m_subsurface) if (!m_pSubsurface)
return {}; return {};
return m_subsurface->posRelativeToParent(); return m_pSubsurface->posRelativeToParent();
} }
Vector2D CSubsurface::coordsGlobal() { Vector2D CSubsurface::coordsGlobal() {
Vector2D coords = coordsRelativeToParent(); Vector2D coords = coordsRelativeToParent();
if (!m_windowParent.expired()) if (!m_pWindowParent.expired())
coords += m_windowParent->m_realPosition->value(); coords += m_pWindowParent->m_vRealPosition->value();
else if (m_popupParent) else if (m_pPopupParent)
coords += m_popupParent->coordsGlobal(); coords += m_pPopupParent->coordsGlobal();
return coords; return coords;
} }
void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) { void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) {
for (auto const& s : pSurface->m_subsurfaces) { for (auto const& s : pSurface->subsurfaces) {
if (!s || s->m_surface->m_hlSurface /* already assigned */) if (!s || s->surface->hlSurface /* already assigned */)
continue; continue;
onNewSubsurface(s.lock()); onNewSubsurface(s.lock());
} }
} }
Vector2D CSubsurface::size() { Vector2D CSubsurface::size() {
return m_wlSurface->resource()->m_current.size; return m_pWLSurface->resource()->current.size;
} }
bool CSubsurface::visible() { bool CSubsurface::visible() {
if (!m_windowParent.expired()) if (!m_pWindowParent.expired())
return g_pHyprRenderer->shouldRenderWindow(m_windowParent.lock()); return g_pHyprRenderer->shouldRenderWindow(m_pWindowParent.lock());
if (m_popupParent) if (m_pPopupParent)
return m_popupParent->visible(); return m_pPopupParent->visible();
if (m_parent) if (m_pParent)
return m_parent->visible(); return m_pParent->visible();
return false; return false;
} }

View File

@@ -10,14 +10,14 @@ class CWLSubsurfaceResource;
class CSubsurface { class CSubsurface {
public: public:
// root dummy nodes // root dummy nodes
static UP<CSubsurface> create(PHLWINDOW pOwner); CSubsurface(PHLWINDOW pOwner);
static UP<CSubsurface> create(WP<CPopup> pOwner); CSubsurface(WP<CPopup> pOwner);
// real nodes // real nodes
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner); CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner);
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner); CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner);
~CSubsurface() = default; ~CSubsurface();
Vector2D coordsRelativeToParent(); Vector2D coordsRelativeToParent();
Vector2D coordsGlobal(); Vector2D coordsGlobal();
@@ -34,36 +34,32 @@ class CSubsurface {
void recheckDamageForSubsurfaces(); void recheckDamageForSubsurfaces();
WP<CSubsurface> m_self; WP<CSubsurface> m_pSelf;
private: private:
CSubsurface() = default;
struct { struct {
CHyprSignalListener destroySubsurface; CHyprSignalListener destroySubsurface;
CHyprSignalListener commitSubsurface; CHyprSignalListener commitSubsurface;
CHyprSignalListener mapSubsurface; CHyprSignalListener mapSubsurface;
CHyprSignalListener unmapSubsurface; CHyprSignalListener unmapSubsurface;
CHyprSignalListener newSubsurface; CHyprSignalListener newSubsurface;
} m_listeners; } listeners;
WP<CWLSubsurfaceResource> m_subsurface; WP<CWLSubsurfaceResource> m_pSubsurface;
SP<CWLSurface> m_wlSurface; SP<CWLSurface> m_pWLSurface;
Vector2D m_lastSize = {}; Vector2D m_vLastSize = {};
Vector2D m_lastPosition = {};
// if nullptr, means it's a dummy node // if nullptr, means it's a dummy node
WP<CSubsurface> m_parent; WP<CSubsurface> m_pParent;
PHLWINDOWREF m_windowParent; PHLWINDOWREF m_pWindowParent;
WP<CPopup> m_popupParent; WP<CPopup> m_pPopupParent;
std::vector<UP<CSubsurface>> m_children; std::vector<UP<CSubsurface>> m_vChildren;
bool m_inert = false; bool m_bInert = false;
void initSignals(); void initSignals();
void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface); void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface);
void checkSiblingDamage(); void checkSiblingDamage();
void damageLastArea();
}; };

View File

@@ -6,37 +6,37 @@
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_resource = pSurface; m_pResource = pSurface;
init(); init();
m_inert = false; m_bInert = false;
} }
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner) {
m_windowOwner = pOwner; m_pWindowOwner = pOwner;
m_resource = pSurface; m_pResource = pSurface;
init(); init();
m_inert = false; m_bInert = false;
} }
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner) {
m_layerOwner = pOwner; m_pLayerOwner = pOwner;
m_resource = pSurface; m_pResource = pSurface;
init(); init();
m_inert = false; m_bInert = false;
} }
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner) {
m_subsurfaceOwner = pOwner; m_pSubsurfaceOwner = pOwner;
m_resource = pSurface; m_pResource = pSurface;
init(); init();
m_inert = false; m_bInert = false;
} }
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner) {
m_popupOwner = pOwner; m_pPopupOwner = pOwner;
m_resource = pSurface; m_pResource = pSurface;
init(); init();
m_inert = false; m_bInert = false;
} }
void CWLSurface::unassign() { void CWLSurface::unassign() {
@@ -48,67 +48,66 @@ CWLSurface::~CWLSurface() {
} }
bool CWLSurface::exists() const { bool CWLSurface::exists() const {
return m_resource; return m_pResource;
} }
SP<CWLSurfaceResource> CWLSurface::resource() const { SP<CWLSurfaceResource> CWLSurface::resource() const {
return m_resource.lock(); return m_pResource.lock();
} }
bool CWLSurface::small() const { bool CWLSurface::small() const {
if (!validMapped(m_windowOwner) || !exists()) if (!validMapped(m_pWindowOwner) || !exists())
return false; return false;
if (!m_resource->m_current.texture) if (!m_pResource->current.texture)
return false; return false;
const auto O = m_windowOwner.lock(); const auto O = m_pWindowOwner.lock();
return O->m_reportedSize.x > m_resource->m_current.size.x + 1 || O->m_reportedSize.y > m_resource->m_current.size.y + 1; return O->m_vReportedSize.x > m_pResource->current.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1;
} }
Vector2D CWLSurface::correctSmallVec() const { Vector2D CWLSurface::correctSmallVec() const {
if (!validMapped(m_windowOwner) || !exists() || !small() || m_fillIgnoreSmall) if (!validMapped(m_pWindowOwner) || !exists() || !small() || m_bFillIgnoreSmall)
return {}; return {};
const auto SIZE = getViewporterCorrectedSize(); const auto SIZE = getViewporterCorrectedSize();
const auto O = m_windowOwner.lock(); const auto O = m_pWindowOwner.lock();
return Vector2D{(O->m_reportedSize.x - SIZE.x) / 2, (O->m_reportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_realSize->value() / O->m_reportedSize); return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize->value() / O->m_vReportedSize);
} }
Vector2D CWLSurface::correctSmallVecBuf() const { Vector2D CWLSurface::correctSmallVecBuf() const {
if (!exists() || !small() || m_fillIgnoreSmall || !m_resource->m_current.texture) if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.texture)
return {}; return {};
const auto SIZE = getViewporterCorrectedSize(); const auto SIZE = getViewporterCorrectedSize();
const auto BS = m_resource->m_current.bufferSize; const auto BS = m_pResource->current.bufferSize;
return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}); return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY});
} }
Vector2D CWLSurface::getViewporterCorrectedSize() const { Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists() || !m_resource->m_current.texture) if (!exists() || !m_pResource->current.texture)
return {}; return {};
return m_resource->m_current.viewport.hasDestination ? m_resource->m_current.viewport.destination : m_resource->m_current.bufferSize; return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.bufferSize;
} }
CRegion CWLSurface::computeDamage() const { CRegion CWLSurface::computeDamage() const {
if (!m_resource->m_current.texture) if (!m_pResource->current.texture)
return {}; return {};
CRegion damage = m_resource->m_current.accumulateBufferDamage(); CRegion damage = m_pResource->accumulateCurrentBufferDamage();
damage.transform(wlTransformToHyprutils(m_resource->m_current.transform), m_resource->m_current.bufferSize.x, m_resource->m_current.bufferSize.y); damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y);
const auto BUFSIZE = m_resource->m_current.bufferSize; const auto BUFSIZE = m_pResource->current.bufferSize;
const auto CORRECTVEC = correctSmallVecBuf(); const auto CORRECTVEC = correctSmallVecBuf();
if (m_resource->m_current.viewport.hasSource) if (m_pResource->current.viewport.hasSource)
damage.intersect(m_resource->m_current.viewport.source); damage.intersect(m_pResource->current.viewport.source);
const auto SCALEDSRCSIZE = const auto SCALEDSRCSIZE = m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.bufferSize;
m_resource->m_current.viewport.hasSource ? m_resource->m_current.viewport.source.size() * m_resource->m_current.scale : m_resource->m_current.bufferSize;
damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y}); damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
damage.translate(CORRECTVEC); damage.translate(CORRECTVEC);
@@ -116,120 +115,120 @@ CRegion CWLSurface::computeDamage() const {
// go from buffer coords in the damage to hl logical // go from buffer coords in the damage to hl logical
const auto BOX = getSurfaceBoxGlobal(); const auto BOX = getSurfaceBoxGlobal();
const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_resource->m_current.bufferSize : const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.bufferSize :
Vector2D{1.0 / m_resource->m_current.scale, 1.0 / m_resource->m_current.scale /* Wrong... but we can't really do better */}; Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */};
damage.scale(SCALE); damage.scale(SCALE);
if (m_windowOwner) if (m_pWindowOwner)
damage.scale(m_windowOwner->m_X11SurfaceScaledBy); // fix xwayland:force_zero_scaling stuff that will be fucked by the above a bit damage.scale(m_pWindowOwner->m_fX11SurfaceScaledBy); // fix xwayland:force_zero_scaling stuff that will be fucked by the above a bit
return damage; return damage;
} }
void CWLSurface::destroy() { void CWLSurface::destroy() {
if (!m_resource) if (!m_pResource)
return; return;
m_events.destroy.emit(); events.destroy.emit();
m_constraint.reset(); m_pConstraint.reset();
m_listeners.destroy.reset(); listeners.destroy.reset();
m_resource->m_hlSurface.reset(); m_pResource->hlSurface.reset();
m_windowOwner.reset(); m_pWindowOwner.reset();
m_layerOwner.reset(); m_pLayerOwner.reset();
m_popupOwner = nullptr; m_pPopupOwner = nullptr;
m_subsurfaceOwner = nullptr; m_pSubsurfaceOwner = nullptr;
m_inert = true; m_bInert = true;
if (g_pHyprRenderer && g_pHyprRenderer->m_lastCursorData.surf && g_pHyprRenderer->m_lastCursorData.surf->get() == this) if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf && g_pHyprRenderer->m_sLastCursorData.surf->get() == this)
g_pHyprRenderer->m_lastCursorData.surf.reset(); g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_resource.reset(); m_pResource.reset();
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this); Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
} }
void CWLSurface::init() { void CWLSurface::init() {
if (!m_resource) if (!m_pResource)
return; return;
RASSERT(!m_resource->m_hlSurface, "Attempted to duplicate CWLSurface ownership!"); RASSERT(!m_pResource->hlSurface, "Attempted to duplicate CWLSurface ownership!");
m_resource->m_hlSurface = m_self.lock(); m_pResource->hlSurface = self.lock();
m_listeners.destroy = m_resource->m_events.destroy.registerListener([this](std::any d) { destroy(); }); listeners.destroy = m_pResource->events.destroy.registerListener([this](std::any d) { destroy(); });
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this); Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
} }
PHLWINDOW CWLSurface::getWindow() const { PHLWINDOW CWLSurface::getWindow() const {
return m_windowOwner.lock(); return m_pWindowOwner.lock();
} }
PHLLS CWLSurface::getLayer() const { PHLLS CWLSurface::getLayer() const {
return m_layerOwner.lock(); return m_pLayerOwner.lock();
} }
CPopup* CWLSurface::getPopup() const { CPopup* CWLSurface::getPopup() const {
return m_popupOwner; return m_pPopupOwner;
} }
CSubsurface* CWLSurface::getSubsurface() const { CSubsurface* CWLSurface::getSubsurface() const {
return m_subsurfaceOwner; return m_pSubsurfaceOwner;
} }
bool CWLSurface::desktopComponent() const { bool CWLSurface::desktopComponent() const {
return !m_layerOwner.expired() || !m_windowOwner.expired() || m_subsurfaceOwner || m_popupOwner; return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner;
} }
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const { std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const {
if (!desktopComponent()) if (!desktopComponent())
return {}; return {};
if (!m_windowOwner.expired()) if (!m_pWindowOwner.expired())
return m_windowOwner->getWindowMainSurfaceBox(); return m_pWindowOwner->getWindowMainSurfaceBox();
if (!m_layerOwner.expired()) if (!m_pLayerOwner.expired())
return m_layerOwner->m_geometry; return m_pLayerOwner->geometry;
if (m_popupOwner) if (m_pPopupOwner)
return CBox{m_popupOwner->coordsGlobal(), m_popupOwner->size()}; return CBox{m_pPopupOwner->coordsGlobal(), m_pPopupOwner->size()};
if (m_subsurfaceOwner) if (m_pSubsurfaceOwner)
return CBox{m_subsurfaceOwner->coordsGlobal(), m_subsurfaceOwner->size()}; return CBox{m_pSubsurfaceOwner->coordsGlobal(), m_pSubsurfaceOwner->size()};
return {}; return {};
} }
void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) { void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) {
m_constraint = constraint; m_pConstraint = constraint;
} }
SP<CPointerConstraint> CWLSurface::constraint() const { SP<CPointerConstraint> CWLSurface::constraint() const {
return m_constraint.lock(); return m_pConstraint.lock();
} }
bool CWLSurface::visible() { bool CWLSurface::visible() {
if (!m_windowOwner.expired()) if (!m_pWindowOwner.expired())
return g_pHyprRenderer->shouldRenderWindow(m_windowOwner.lock()); return g_pHyprRenderer->shouldRenderWindow(m_pWindowOwner.lock());
if (!m_layerOwner.expired()) if (!m_pLayerOwner.expired())
return true; return true;
if (m_popupOwner) if (m_pPopupOwner)
return m_popupOwner->visible(); return m_pPopupOwner->visible();
if (m_subsurfaceOwner) if (m_pSubsurfaceOwner)
return m_subsurfaceOwner->visible(); return m_pSubsurfaceOwner->visible();
return true; // non-desktop, we don't know much. return true; // non-desktop, we don't know much.
} }
SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) { SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
if (!pSurface) if (!pSurface)
return nullptr; return nullptr;
return pSurface->m_hlSurface.lock(); return pSurface->hlSurface.lock();
} }
bool CWLSurface::keyboardFocusable() const { bool CWLSurface::keyboardFocusable() const {
if (m_windowOwner || m_popupOwner || m_subsurfaceOwner) if (m_pWindowOwner || m_pPopupOwner || m_pSubsurfaceOwner)
return true; return true;
if (m_layerOwner && m_layerOwner->m_layerSurface) if (m_pLayerOwner && m_pLayerOwner->layerSurface)
return m_layerOwner->m_layerSurface->m_current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; return m_pLayerOwner->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
return false; return false;
} }

View File

@@ -12,8 +12,8 @@ class CWLSurfaceResource;
class CWLSurface { class CWLSurface {
public: public:
static SP<CWLSurface> create() { static SP<CWLSurface> create() {
auto p = SP<CWLSurface>(new CWLSurface); auto p = SP<CWLSurface>(new CWLSurface);
p->m_self = p; p->self = p;
return p; return p;
} }
~CWLSurface(); ~CWLSurface();
@@ -53,17 +53,17 @@ class CWLSurface {
SP<CPointerConstraint> constraint() const; SP<CPointerConstraint> constraint() const;
// allow stretching. Useful for plugins. // allow stretching. Useful for plugins.
bool m_fillIgnoreSmall = false; bool m_bFillIgnoreSmall = false;
// track surface data and avoid dupes // track surface data and avoid dupes
float m_lastScaleFloat = 0; float m_fLastScale = 0;
int m_lastScaleInt = 0; int m_iLastScale = 0;
wl_output_transform m_lastTransform = (wl_output_transform)-1; wl_output_transform m_eLastTransform = (wl_output_transform)-1;
// //
CWLSurface& operator=(SP<CWLSurfaceResource> pSurface) { CWLSurface& operator=(SP<CWLSurfaceResource> pSurface) {
destroy(); destroy();
m_resource = pSurface; m_pResource = pSurface;
init(); init();
return *this; return *this;
@@ -84,32 +84,32 @@ class CWLSurface {
static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface); static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface);
// used by the alpha-modifier protocol // used by the alpha-modifier protocol
float m_alphaModifier = 1.F; float m_fAlphaModifier = 1.F;
// used by the hyprland-surface protocol // used by the hyprland-surface protocol
float m_overallOpacity = 1.F; float m_fOverallOpacity = 1.F;
CRegion m_visibleRegion; CRegion m_visibleRegion;
struct { struct {
CSignal destroy; CSignal destroy;
} m_events; } events;
WP<CWLSurface> m_self; WP<CWLSurface> self;
private: private:
CWLSurface() = default; CWLSurface() = default;
bool m_inert = true; bool m_bInert = true;
WP<CWLSurfaceResource> m_resource; WP<CWLSurfaceResource> m_pResource;
PHLWINDOWREF m_windowOwner; PHLWINDOWREF m_pWindowOwner;
PHLLSREF m_layerOwner; PHLLSREF m_pLayerOwner;
CPopup* m_popupOwner = nullptr; CPopup* m_pPopupOwner = nullptr;
CSubsurface* m_subsurfaceOwner = nullptr; CSubsurface* m_pSubsurfaceOwner = nullptr;
// //
WP<CPointerConstraint> m_constraint; WP<CPointerConstraint> m_pConstraint;
void destroy(); void destroy();
void init(); void init();
@@ -117,7 +117,7 @@ class CWLSurface {
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
} m_listeners; } listeners;
friend class CPointerConstraint; friend class CPointerConstraint;
friend class CXxColorManagerV4; friend class CXxColorManagerV4;

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,8 @@
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/TagKeeper.hpp" #include "../helpers/TagKeeper.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../managers/XWaylandManager.hpp" #include "../managers/XWaylandManager.hpp"
@@ -17,8 +19,6 @@
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "Workspace.hpp" #include "Workspace.hpp"
#include "WindowRule.hpp" #include "WindowRule.hpp"
#include "WindowOverridableVar.hpp"
#include "../protocols/types/ContentType.hpp"
class CXDGSurfaceResource; class CXDGSurfaceResource;
class CXWaylandSurface; class CXWaylandSurface;
@@ -43,14 +43,13 @@ enum eGroupRules : uint8_t {
}; };
enum eGetWindowProperties : uint8_t { enum eGetWindowProperties : uint8_t {
WINDOW_ONLY = 0, WINDOW_ONLY = 0,
RESERVED_EXTENTS = 1 << 0, RESERVED_EXTENTS = 1 << 0,
INPUT_EXTENTS = 1 << 1, INPUT_EXTENTS = 1 << 1,
FULL_EXTENTS = 1 << 2, FULL_EXTENTS = 1 << 2,
FLOATING_ONLY = 1 << 3, FLOATING_ONLY = 1 << 3,
ALLOW_FLOATING = 1 << 4, ALLOW_FLOATING = 1 << 4,
USE_PROP_TILED = 1 << 5, USE_PROP_TILED = 1 << 5,
SKIP_FULLSCREEN_PRIORITY = 1 << 6,
}; };
enum eSuppressEvents : uint8_t { enum eSuppressEvents : uint8_t {
@@ -65,21 +64,103 @@ enum eSuppressEvents : uint8_t {
class IWindowTransformer; class IWindowTransformer;
struct SAlphaValue { struct SAlphaValue {
float alpha; float m_fAlpha;
bool overridden; bool m_bOverride;
float applyAlpha(float a) const { float applyAlpha(float alpha) const {
if (overridden) if (m_bOverride)
return alpha; return m_fAlpha;
else else
return alpha * a; return m_fAlpha * alpha;
}; };
}; };
enum eOverridePriority : uint8_t {
PRIORITY_LAYOUT = 0,
PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP,
};
template <typename T>
class CWindowOverridableVar {
public:
CWindowOverridableVar(T const& value, eOverridePriority priority) {
values[priority] = value;
}
CWindowOverridableVar(T const& value) : defaultValue{value} {}
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default;
CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> const& other) {
// Self-assignment check
if (this == &other)
return *this;
for (auto const& value : other.values) {
values[value.first] = value.second;
}
return *this;
}
void unset(eOverridePriority priority) {
values.erase(priority);
}
bool hasValue() {
return !values.empty();
}
T value() {
if (!values.empty())
return std::prev(values.end())->second;
else
throw std::bad_optional_access();
}
T valueOr(T const& other) {
if (hasValue())
return value();
else
return other;
}
T valueOrDefault() {
return valueOr(defaultValue);
}
eOverridePriority getPriority() {
if (!values.empty())
return std::prev(values.end())->first;
else
throw std::bad_optional_access();
}
void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
if (optValue.has_value())
values[priority] = optValue.value();
else
unset(priority);
}
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private:
std::map<eOverridePriority, T> values;
T defaultValue; // used for toggling, so required for bool
};
struct SWindowData { struct SWindowData {
CWindowOverridableVar<SAlphaValue> alpha = SAlphaValue{.alpha = 1.f, .overridden = false}; CWindowOverridableVar<SAlphaValue> alpha = SAlphaValue{1.f, false};
CWindowOverridableVar<SAlphaValue> alphaInactive = SAlphaValue{.alpha = 1.f, .overridden = false}; CWindowOverridableVar<SAlphaValue> alphaInactive = SAlphaValue{1.f, false};
CWindowOverridableVar<SAlphaValue> alphaFullscreen = SAlphaValue{.alpha = 1.f, .overridden = false}; CWindowOverridableVar<SAlphaValue> alphaFullscreen = SAlphaValue{1.f, false};
CWindowOverridableVar<bool> allowsInput = false; CWindowOverridableVar<bool> allowsInput = false;
CWindowOverridableVar<bool> dimAround = false; CWindowOverridableVar<bool> dimAround = false;
@@ -102,14 +183,13 @@ struct SWindowData {
CWindowOverridableVar<bool> tearing = false; CWindowOverridableVar<bool> tearing = false;
CWindowOverridableVar<bool> xray = false; CWindowOverridableVar<bool> xray = false;
CWindowOverridableVar<bool> renderUnfocused = false; CWindowOverridableVar<bool> renderUnfocused = false;
CWindowOverridableVar<bool> noFollowMouse = false;
CWindowOverridableVar<Hyprlang::INT> borderSize = {std::string("general:border_size"), Hyprlang::INT(0), std::nullopt}; CWindowOverridableVar<int> rounding;
CWindowOverridableVar<Hyprlang::INT> rounding = {std::string("decoration:rounding"), Hyprlang::INT(0), std::nullopt}; CWindowOverridableVar<float> roundingPower;
CWindowOverridableVar<int> borderSize;
CWindowOverridableVar<Hyprlang::FLOAT> roundingPower = {std::string("decoration:rounding_power")}; CWindowOverridableVar<float> scrollMouse;
CWindowOverridableVar<Hyprlang::FLOAT> scrollMouse = {std::string("input:scroll_factor")}; CWindowOverridableVar<float> scrollTouchpad;
CWindowOverridableVar<Hyprlang::FLOAT> scrollTouchpad = {std::string("input:touchpad:scroll_factor")};
CWindowOverridableVar<std::string> animationStyle; CWindowOverridableVar<std::string> animationStyle;
CWindowOverridableVar<Vector2D> maxSize; CWindowOverridableVar<Vector2D> maxSize;
@@ -117,8 +197,6 @@ struct SWindowData {
CWindowOverridableVar<CGradientValueData> activeBorderColor; CWindowOverridableVar<CGradientValueData> activeBorderColor;
CWindowOverridableVar<CGradientValueData> inactiveBorderColor; CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
CWindowOverridableVar<bool> persistentSize;
}; };
struct SInitialWorkspaceToken { struct SInitialWorkspaceToken {
@@ -143,151 +221,153 @@ class CWindow {
public: public:
~CWindow(); ~CWindow();
SP<CWLSurface> m_wlSurface; SP<CWLSurface> m_pWLSurface;
struct { struct {
CSignal destroy; CSignal destroy;
} m_events; } events;
WP<CXDGSurfaceResource> m_xdgSurface; WP<CXDGSurfaceResource> m_pXDGSurface;
WP<CXWaylandSurface> m_xwaylandSurface; WP<CXWaylandSurface> m_pXWaylandSurface;
// this is the position and size of the "bounding box" // this is the position and size of the "bounding box"
Vector2D m_position = Vector2D(0, 0); Vector2D m_vPosition = Vector2D(0, 0);
Vector2D m_size = Vector2D(0, 0); Vector2D m_vSize = Vector2D(0, 0);
// this is the real position and size used to draw the thing // this is the real position and size used to draw the thing
PHLANIMVAR<Vector2D> m_realPosition; PHLANIMVAR<Vector2D> m_vRealPosition;
PHLANIMVAR<Vector2D> m_realSize; PHLANIMVAR<Vector2D> m_vRealSize;
// for not spamming the protocols // for not spamming the protocols
Vector2D m_reportedPosition; Vector2D m_vReportedPosition;
Vector2D m_reportedSize; Vector2D m_vReportedSize;
Vector2D m_pendingReportedSize; Vector2D m_vPendingReportedSize;
std::optional<std::pair<uint32_t, Vector2D>> m_pendingSizeAck; std::optional<std::pair<uint32_t, Vector2D>> m_pPendingSizeAck;
std::vector<std::pair<uint32_t, Vector2D>> m_pendingSizeAcks; std::vector<std::pair<uint32_t, Vector2D>> m_vPendingSizeAcks;
// for restoring floating statuses // for restoring floating statuses
Vector2D m_lastFloatingSize; Vector2D m_vLastFloatingSize;
Vector2D m_lastFloatingPosition; Vector2D m_vLastFloatingPosition;
// for floating window offset in workspace animations // for floating window offset in workspace animations
Vector2D m_floatingOffset = Vector2D(0, 0); Vector2D m_vFloatingOffset = Vector2D(0, 0);
// this is used for pseudotiling // this is used for pseudotiling
bool m_isPseudotiled = false; bool m_bIsPseudotiled = false;
Vector2D m_pseudoSize = Vector2D(1280, 720); Vector2D m_vPseudoSize = Vector2D(1280, 720);
// for recovering relative cursor position // for recovering relative cursor position
Vector2D m_relativeCursorCoordsOnLastWarp = Vector2D(-1, -1); Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1);
bool m_firstMap = false; // for layouts bool m_bFirstMap = false; // for layouts
bool m_isFloating = false; bool m_bIsFloating = false;
bool m_draggingTiled = false; // for dragging around tiled windows bool m_bDraggingTiled = false; // for dragging around tiled windows
SFullscreenState m_fullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE}; bool m_bWasMaximized = false;
std::string m_title = ""; SFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
std::string m_class = ""; std::string m_szTitle = "";
std::string m_initialTitle = ""; std::string m_szClass = "";
std::string m_initialClass = ""; std::string m_szInitialTitle = "";
PHLWORKSPACE m_workspace; std::string m_szInitialClass = "";
PHLMONITORREF m_monitor; PHLWORKSPACE m_pWorkspace;
PHLMONITORREF m_pMonitor;
bool m_isMapped = false; bool m_bIsMapped = false;
bool m_requestsFloat = false; bool m_bRequestsFloat = false;
// This is for fullscreen apps // This is for fullscreen apps
bool m_createdOverFullscreen = false; bool m_bCreatedOverFullscreen = false;
// XWayland stuff // XWayland stuff
bool m_isX11 = false; bool m_bIsX11 = false;
bool m_X11DoesntWantBorders = false; PHLWINDOWREF m_pX11Parent;
bool m_X11ShouldntFocus = false; bool m_bX11DoesntWantBorders = false;
float m_X11SurfaceScaledBy = 1.f; bool m_bX11ShouldntFocus = false;
float m_fX11SurfaceScaledBy = 1.f;
// //
// For nofocus // For nofocus
bool m_noInitialFocus = false; bool m_bNoInitialFocus = false;
// Fullscreen and Maximize // Fullscreen and Maximize
bool m_wantsInitialFullscreen = false; bool m_bWantsInitialFullscreen = false;
MONITORID m_wantsInitialFullscreenMonitor = MONITOR_INVALID; MONITORID m_iWantsInitialFullscreenMonitor = MONITOR_INVALID;
// bitfield suppressEvents // bitfield eSuppressEvents
uint64_t m_suppressedEvents = SUPPRESS_NONE; uint64_t m_eSuppressedEvents = SUPPRESS_NONE;
// desktop components // desktop components
UP<CSubsurface> m_subsurfaceHead; UP<CSubsurface> m_pSubsurfaceHead;
UP<CPopup> m_popupHead; UP<CPopup> m_pPopupHead;
// Animated border // Animated border
CGradientValueData m_realBorderColor = {0}; CGradientValueData m_cRealBorderColor = {0};
CGradientValueData m_realBorderColorPrevious = {0}; CGradientValueData m_cRealBorderColorPrevious = {0};
PHLANIMVAR<float> m_borderFadeAnimationProgress; PHLANIMVAR<float> m_fBorderFadeAnimationProgress;
PHLANIMVAR<float> m_borderAngleAnimationProgress; PHLANIMVAR<float> m_fBorderAngleAnimationProgress;
// Fade in-out // Fade in-out
PHLANIMVAR<float> m_alpha; PHLANIMVAR<float> m_fAlpha;
bool m_fadingOut = false; bool m_bFadingOut = false;
bool m_readyToDelete = false; bool m_bReadyToDelete = false;
Vector2D m_originalClosedPos; // these will be used for calculations later on in Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
Vector2D m_originalClosedSize; // drawing the closing animations Vector2D m_vOriginalClosedSize; // drawing the closing animations
SBoxExtents m_originalClosedExtents; SBoxExtents m_eOriginalClosedExtents;
bool m_animatingIn = false; bool m_bAnimatingIn = false;
// For pinned (sticky) windows // For pinned (sticky) windows
bool m_pinned = false; bool m_bPinned = false;
// For preserving pinned state when fullscreening a pinned window // For preserving pinned state when fullscreening a pinned window
bool m_pinFullscreened = false; bool m_bPinFullscreened = false;
// urgency hint // urgency hint
bool m_isUrgent = false; bool m_bIsUrgent = false;
// for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window. // for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window.
PHLWINDOWREF m_lastCycledWindow; PHLWINDOWREF m_pLastCycledWindow;
// Window decorations // Window decorations
// TODO: make this a SP. // TODO: make this a SP.
std::vector<UP<IHyprWindowDecoration>> m_windowDecorations; std::vector<UP<IHyprWindowDecoration>> m_dWindowDecorations;
std::vector<IHyprWindowDecoration*> m_decosToRemove; std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
// Special render data, rules, etc // Special render data, rules, etc
SWindowData m_windowData; SWindowData m_sWindowData;
// Transformers // Transformers
std::vector<UP<IWindowTransformer>> m_transformers; std::vector<UP<IWindowTransformer>> m_vTransformers;
// for alpha // for alpha
PHLANIMVAR<float> m_activeInactiveAlpha; PHLANIMVAR<float> m_fActiveInactiveAlpha;
PHLANIMVAR<float> m_movingFromWorkspaceAlpha; PHLANIMVAR<float> m_fMovingFromWorkspaceAlpha;
// animated shadow color // animated shadow color
PHLANIMVAR<CHyprColor> m_realShadowColor; PHLANIMVAR<CHyprColor> m_cRealShadowColor;
// animated tint // animated tint
PHLANIMVAR<float> m_dimPercent; PHLANIMVAR<float> m_fDimPercent;
// animate moving to an invisible workspace // animate moving to an invisible workspace
int m_monitorMovedFrom = -1; // -1 means not moving int m_iMonitorMovedFrom = -1; // -1 means not moving
PHLANIMVAR<float> m_movingToWorkspaceAlpha; PHLANIMVAR<float> m_fMovingToWorkspaceAlpha;
// swallowing // swallowing
PHLWINDOWREF m_swallowed; PHLWINDOWREF m_pSwallowed;
bool m_currentlySwallowed = false; bool m_bGroupSwallowed = false;
bool m_groupSwallowed = false;
// focus stuff // focus stuff
bool m_stayFocused = false; bool m_bStayFocused = false;
// for toplevel monitor events // for toplevel monitor events
MONITORID m_lastSurfaceMonitorID = -1; MONITORID m_iLastToplevelMonitorID = -1;
MONITORID m_iLastSurfaceMonitorID = -1;
// for idle inhibiting windows // for idle inhibiting windows
eIdleInhibitMode m_idleInhibitMode = IDLEINHIBIT_NONE; eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE;
// initial token. Will be unregistered on workspace change or timeout of 2 minutes // initial token. Will be unregistered on workspace change or timeout of 2 minutes
std::string m_initialWorkspaceToken = ""; std::string m_szInitialWorkspaceToken = "";
// for groups // for groups
struct SGroupData { struct SGroupData {
@@ -295,122 +375,104 @@ class CWindow {
bool head = false; bool head = false;
bool locked = false; // per group lock bool locked = false; // per group lock
bool deny = false; // deny window from enter a group or made a group bool deny = false; // deny window from enter a group or made a group
} m_groupData; } m_sGroupData;
uint16_t m_groupRules = GROUP_NONE; uint16_t m_eGroupRules = GROUP_NONE;
bool m_tearingHint = false; bool m_bTearingHint = false;
// stores the currently matched window rules // stores the currently matched window rules
std::vector<SP<CWindowRule>> m_matchedRules; std::vector<SP<CWindowRule>> m_vMatchedRules;
// window tags // window tags
CTagKeeper m_tags; CTagKeeper m_tags;
// ANR
PHLANIMVAR<float> m_notRespondingTint;
// For the noclosefor windowrule
Time::steady_tp m_closeableSince = Time::steadyNow();
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) const { bool operator==(const CWindow& rhs) const {
return m_xdgSurface == rhs.m_xdgSurface && m_xwaylandSurface == rhs.m_xwaylandSurface && m_position == rhs.m_position && m_size == rhs.m_size && return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
m_fadingOut == rhs.m_fadingOut; m_bFadingOut == rhs.m_bFadingOut;
} }
// methods // methods
CBox getFullWindowBoundingBox(); CBox getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents(); SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props); CBox getWindowBoxUnified(uint64_t props);
CBox getWindowIdealBoundingBoxIgnoreReserved(); CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(UP<IHyprWindowDecoration> deco); void addWindowDeco(UP<IHyprWindowDecoration> deco);
void updateWindowDecos(); void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco); void removeWindowDeco(IHyprWindowDecoration* deco);
void uncacheWindowDecos(); void uncacheWindowDecos();
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {}); bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
pid_t getPID(); pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType); IHyprWindowDecoration* getDecorationByType(eDecorationType);
void updateToplevel(); void updateToplevel();
void updateSurfaceScaleTransformDetails(bool force = false); void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE); void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW x11TransientFor(); PHLWINDOW x11TransientFor();
void onUnmap(); void onUnmap();
void onMap(); void onMap();
void setHidden(bool hidden); void setHidden(bool hidden);
bool isHidden(); bool isHidden();
void applyDynamicRule(const SP<CWindowRule>& r); void applyDynamicRule(const SP<CWindowRule>& r);
void updateDynamicRules(); void updateDynamicRules();
SBoxExtents getFullWindowReservedArea(); SBoxExtents getFullWindowReservedArea();
Vector2D middle(); Vector2D middle();
bool opaque(); bool opaque();
float rounding(); float rounding();
float roundingPower(); float roundingPower();
bool canBeTorn(); bool canBeTorn();
void setSuspended(bool suspend); void setSuspended(bool suspend);
bool visibleOnMonitor(PHLMONITOR pMonitor); bool visibleOnMonitor(PHLMONITOR pMonitor);
WORKSPACEID workspaceID(); WORKSPACEID workspaceID();
MONITORID monitorID(); MONITORID monitorID();
bool onSpecialWorkspace(); bool onSpecialWorkspace();
void activate(bool force = false); void activate(bool force = false);
int surfacesCount(); int surfacesCount();
void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize); void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
bool isFullscreen(); bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode); bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize(); int getRealBorderSize();
float getScrollMouse(); float getScrollMouse();
float getScrollTouchpad(); float getScrollTouchpad();
void updateWindowData(); void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&); void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(WP<Hyprutils::Animation::CBaseAnimatedVariable> pav); void onBorderAngleAnimEnd(WP<Hyprutils::Animation::CBaseAnimatedVariable> pav);
bool isInCurvedCorner(double x, double y); bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos); bool hasPopupAt(const Vector2D& pos);
int popupsCount(); int popupsCount();
void applyGroupRules(); void applyGroupRules();
void createGroup(); void createGroup();
void destroyGroup(); void destroyGroup();
PHLWINDOW getGroupHead(); PHLWINDOW getGroupHead();
PHLWINDOW getGroupTail(); PHLWINDOW getGroupTail();
PHLWINDOW getGroupCurrent(); PHLWINDOW getGroupCurrent();
PHLWINDOW getGroupPrevious(); PHLWINDOW getGroupPrevious();
PHLWINDOW getGroupWindowByIndex(int); PHLWINDOW getGroupWindowByIndex(int);
int getGroupSize(); int getGroupSize();
bool canBeGroupedInto(PHLWINDOW pWindow); bool canBeGroupedInto(PHLWINDOW pWindow);
void setGroupCurrent(PHLWINDOW pWindow); void setGroupCurrent(PHLWINDOW pWindow);
void insertWindowToGroup(PHLWINDOW pWindow); void insertWindowToGroup(PHLWINDOW pWindow);
void updateGroupOutputs(); void updateGroupOutputs();
void switchWithWindowInGroup(PHLWINDOW pWindow); void switchWithWindowInGroup(PHLWINDOW pWindow);
void setAnimationsToMove(); void setAnimationsToMove();
void onWorkspaceAnimUpdate(); void onWorkspaceAnimUpdate();
void onFocusAnimUpdate(); void onFocusAnimUpdate();
void onUpdateState(); void onUpdateState();
void onUpdateMeta(); void onUpdateMeta();
void onX11ConfigureRequest(CBox box); void onX11Configure(CBox box);
void onResourceChangeX11(); void onResourceChangeX11();
std::string fetchTitle(); std::string fetchTitle();
std::string fetchClass(); std::string fetchClass();
void warpCursor(bool force = false); void warpCursor(bool force = false);
PHLWINDOW getSwallower(); PHLWINDOW getSwallower();
void unsetWindowData(eOverridePriority priority); void unsetWindowData(eOverridePriority priority);
bool isX11OverrideRedirect(); bool isX11OverrideRedirect();
bool isModal(); bool isModal();
Vector2D requestedMinSize(); Vector2D requestedMinSize();
Vector2D requestedMaxSize(); Vector2D requestedMaxSize();
Vector2D realToReportSize(); void sendWindowSize(Vector2D size, bool force = false, std::optional<Vector2D> overridePos = std::nullopt);
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();
std::optional<std::string> xdgTag();
std::optional<std::string> xdgDescription();
PHLWINDOW parent();
CBox getWindowMainSurfaceBox() const { CBox getWindowMainSurfaceBox() const {
return {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y}; return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y};
} }
// listeners // listeners
@@ -420,7 +482,7 @@ class CWindow {
std::unordered_map<std::string, std::string> getEnv(); std::unordered_map<std::string, std::string> getEnv();
// //
PHLWINDOWREF m_self; PHLWINDOWREF m_pSelf;
// make private once we move listeners to inside CWindow // make private once we move listeners to inside CWindow
struct { struct {
@@ -430,18 +492,18 @@ class CWindow {
CHyprSignalListener commit; CHyprSignalListener commit;
CHyprSignalListener destroy; CHyprSignalListener destroy;
CHyprSignalListener activate; CHyprSignalListener activate;
CHyprSignalListener configureRequest; CHyprSignalListener configure;
CHyprSignalListener setGeometry; CHyprSignalListener setGeometry;
CHyprSignalListener updateState; CHyprSignalListener updateState;
CHyprSignalListener updateMetadata; CHyprSignalListener updateMetadata;
CHyprSignalListener resourceChange; CHyprSignalListener resourceChange;
} m_listeners; } listeners;
private: private:
// For hidden windows and stuff // For hidden windows and stuff
bool m_hidden = false; bool m_bHidden = false;
bool m_suspended = false; bool m_bSuspended = false;
WORKSPACEID m_lastWorkspace = WORKSPACE_INVALID; WORKSPACEID m_iLastWorkspace = WORKSPACE_INVALID;
}; };
inline bool valid(PHLWINDOW w) { inline bool valid(PHLWINDOW w) {
@@ -455,52 +517,15 @@ inline bool valid(PHLWINDOWREF w) {
inline bool validMapped(PHLWINDOW w) { inline bool validMapped(PHLWINDOW w) {
if (!valid(w)) if (!valid(w))
return false; return false;
return w->m_isMapped; return w->m_bIsMapped;
} }
inline bool validMapped(PHLWINDOWREF w) { inline bool validMapped(PHLWINDOWREF w) {
if (!valid(w)) if (!valid(w))
return false; return false;
return w->m_isMapped; 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_windowData.allowsInput; }},
{"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.dimAround; }},
{"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.decorate; }},
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.focusOnActivate; }},
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.keepAspectRatio; }},
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.nearestNeighbor; }},
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noAnim; }},
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noBlur; }},
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noBorder; }},
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noDim; }},
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noFocus; }},
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noMaxSize; }},
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noRounding; }},
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noShadow; }},
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noShortcutsInhibit; }},
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.opaque; }},
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.RGBX; }},
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.syncFullscreen; }},
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.tearing; }},
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.xray; }},
{"nofollowmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noFollowMouse; }},
};
const std::unordered_map<std::string, std::function<CWindowOverridableVar<Hyprlang::INT>*(const PHLWINDOW&)>> intWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.rounding; }},
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.borderSize; }},
};
const std::unordered_map<std::string, std::function<CWindowOverridableVar<Hyprlang::FLOAT>*(PHLWINDOW)>> floatWindowProperties = {
{"roundingpower", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.roundingPower; }},
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.scrollTouchpad; }},
};
};
/** /**
format specification format specification
- 'x', only address, equivalent of (uintpr_t)CWindow* - 'x', only address, equivalent of (uintpr_t)CWindow*
@@ -531,13 +556,13 @@ struct std::formatter<PHLWINDOW, CharT> : std::formatter<CharT> {
return std::format_to(out, "[Window nullptr]"); return std::format_to(out, "[Window nullptr]");
std::format_to(out, "["); std::format_to(out, "[");
std::format_to(out, "Window {:x}: title: \"{}\"", (uintptr_t)w.get(), w->m_title); std::format_to(out, "Window {:x}: title: \"{}\"", (uintptr_t)w.get(), w->m_szTitle);
if (formatWorkspace) if (formatWorkspace)
std::format_to(out, ", workspace: {}", w->m_workspace ? w->workspaceID() : WORKSPACE_INVALID); std::format_to(out, ", workspace: {}", w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID);
if (formatMonitor) if (formatMonitor)
std::format_to(out, ", monitor: {}", w->monitorID()); std::format_to(out, ", monitor: {}", w->monitorID());
if (formatClass) if (formatClass)
std::format_to(out, ", class: {}", w->m_class); std::format_to(out, ", class: {}", w->m_szClass);
return std::format_to(out, "]"); return std::format_to(out, "]");
} }
}; };

View File

@@ -1,132 +0,0 @@
#pragma once
#include <cstdint>
#include <type_traits>
#include <any>
#include "../config/ConfigValue.hpp"
enum eOverridePriority : uint8_t {
PRIORITY_LAYOUT = 0,
PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP,
};
template <typename T>
T clampOptional(T const& value, std::optional<T> const& min, std::optional<T> const& max) {
return std::clamp(value, min.value_or(std::numeric_limits<T>::min()), max.value_or(std::numeric_limits<T>::max()));
}
template <typename T, bool Extended = std::is_same_v<T, bool> || std::is_same_v<T, Hyprlang::INT> || std::is_same_v<T, Hyprlang::FLOAT>>
class CWindowOverridableVar {
public:
CWindowOverridableVar(T const& value, eOverridePriority priority) {
m_values[priority] = value;
}
CWindowOverridableVar(T const& value) : m_defaultValue{value} {}
CWindowOverridableVar(T const& value, std::optional<T> const& min, std::optional<T> const& max = std::nullopt) : m_defaultValue{value}, m_minValue{min}, m_maxValue{max} {}
CWindowOverridableVar(std::string const& value)
requires(Extended && !std::is_same_v<T, bool>)
: m_configValue(SP<CConfigValue<T>>(new CConfigValue<T>(value))) {}
CWindowOverridableVar(std::string const& value, std::optional<T> const& min, std::optional<T> const& max = std::nullopt)
requires(Extended && !std::is_same_v<T, bool>)
: m_minValue(min), m_maxValue(max), m_configValue(SP<CConfigValue<T>>(new CConfigValue<T>(value))) {}
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default;
CWindowOverridableVar& operator=(CWindowOverridableVar<T> const& other) {
// Self-assignment check
if (this == &other)
return *this;
for (auto const& value : other.m_values) {
if constexpr (Extended && !std::is_same_v<T, bool>)
m_values[value.first] = clampOptional(value.second, m_minValue, m_maxValue);
else
m_values[value.first] = value.second;
}
return *this;
}
void unset(eOverridePriority priority) {
m_values.erase(priority);
}
bool hasValue() {
return !m_values.empty();
}
T value() {
if (!m_values.empty())
return std::prev(m_values.end())->second;
else
throw std::bad_optional_access();
}
T valueOr(T const& other) {
if (hasValue())
return value();
else
return other;
}
T valueOrDefault()
requires(Extended && !std::is_same_v<T, bool>)
{
if (hasValue())
return value();
else if (m_defaultValue.has_value())
return m_defaultValue.value();
else
return **std::any_cast<SP<CConfigValue<T>>>(m_configValue);
}
T valueOrDefault()
requires(!Extended || std::is_same_v<T, bool>)
{
if (hasValue())
return value();
else if (!m_defaultValue.has_value())
throw std::bad_optional_access();
else
return m_defaultValue.value();
}
eOverridePriority getPriority() {
if (!m_values.empty())
return std::prev(m_values.end())->first;
else
throw std::bad_optional_access();
}
void increment(T const& other, eOverridePriority priority) {
if constexpr (std::is_same_v<T, bool>)
m_values[priority] = valueOr(false) ^ other;
else
m_values[priority] = clampOptional(valueOrDefault() + other, m_minValue, m_maxValue);
}
void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
if (optValue.has_value())
m_values[priority] = optValue.value();
else
unset(priority);
}
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private:
std::map<eOverridePriority, T> m_values;
std::optional<T> m_defaultValue; // used for toggling, so required for bool
std::optional<T> m_minValue;
std::optional<T> m_maxValue;
std::any m_configValue; // only there for select variables
};

View File

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

View File

@@ -36,38 +36,33 @@ class CWindowRule {
RULE_TAG, RULE_TAG,
RULE_WORKSPACE, RULE_WORKSPACE,
RULE_PROP, RULE_PROP,
RULE_CONTENT,
RULE_PERSISTENTSIZE,
RULE_NOCLOSEFOR,
}; };
eRuleType m_ruleType = RULE_INVALID; eRuleType ruleType = RULE_INVALID;
const std::string m_value; const std::string szValue;
const std::string m_rule; const std::string szRule;
const bool m_v2 = false; const bool v2 = false;
const bool m_execRule = false; const bool execRule = false;
std::string m_title; std::string szTitle;
std::string m_class; std::string szClass;
std::string m_initialTitle; std::string szInitialTitle;
std::string m_initialClass; std::string szInitialClass;
std::string m_tag; std::string szTag;
int m_X11 = -1; // -1 means "ANY" int bX11 = -1; // -1 means "ANY"
int m_floating = -1; int bFloating = -1;
int m_fullscreen = -1; int bFullscreen = -1;
int m_pinned = -1; int bPinned = -1;
int m_focus = -1; int bFocus = -1;
std::string m_fullscreenState = ""; // empty means any std::string szFullscreenState = ""; // empty means any
std::string m_onWorkspace = ""; // empty means any std::string szOnWorkspace = ""; // empty means any
std::string m_workspace = ""; // empty means any std::string szWorkspace = ""; // empty means any
std::string m_contentType = ""; // empty means any
std::string m_xdgTag = ""; // empty means any
// precompiled regexes // precompiled regexes
CRuleRegexContainer m_titleRegex; CRuleRegexContainer rTitle;
CRuleRegexContainer m_classRegex; CRuleRegexContainer rClass;
CRuleRegexContainer m_initialTitleRegex; CRuleRegexContainer rInitialTitle;
CRuleRegexContainer m_initialClassRegex; CRuleRegexContainer rInitialClass;
CRuleRegexContainer m_v1Regex; CRuleRegexContainer rV1Regex;
}; };

View File

@@ -17,76 +17,76 @@ PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string
} }
CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) : CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) :
m_id(id), m_name(name), m_monitor(monitor), m_isSpecialWorkspace(special), m_wasCreatedEmpty(isEmpty) { m_iID(id), m_szName(name), m_pMonitor(monitor), m_bIsSpecialWorkspace(special), m_bWasCreatedEmpty(isEmpty) {
; ;
} }
void CWorkspace::init(PHLWORKSPACE self) { void CWorkspace::init(PHLWORKSPACE self) {
m_self = self; m_pSelf = self;
g_pAnimationManager->createAnimation(Vector2D(0, 0), m_renderOffset, g_pConfigManager->getAnimationPropertyConfig(m_isSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), g_pAnimationManager->createAnimation(Vector2D(0, 0), m_vRenderOffset,
self, AVARDAMAGE_ENTIRE); g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(1.f, m_alpha, g_pConfigManager->getAnimationPropertyConfig(m_isSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, g_pAnimationManager->createAnimation(1.f, m_fAlpha, g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self,
AVARDAMAGE_ENTIRE); AVARDAMAGE_ENTIRE);
const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self); const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self);
if (RULEFORTHIS.defaultName.has_value()) if (RULEFORTHIS.defaultName.has_value())
m_name = RULEFORTHIS.defaultName.value(); m_szName = RULEFORTHIS.defaultName.value();
m_focusedWindowHook = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any param) { m_pFocusedWindowHook = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any param) {
const auto PWINDOW = std::any_cast<PHLWINDOW>(param); const auto PWINDOW = std::any_cast<PHLWINDOW>(param);
if (PWINDOW == m_lastFocusedWindow.lock()) if (PWINDOW == m_pLastFocusedWindow.lock())
m_lastFocusedWindow.reset(); m_pLastFocusedWindow.reset();
}); });
m_inert = false; m_bInert = false;
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self);
m_persistent = WORKSPACERULE.isPersistent; m_bPersistent = WORKSPACERULE.isPersistent;
if (self->m_wasCreatedEmpty) if (self->m_bWasCreatedEmpty)
if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd)
CKeybindManager::spawnWithRules(*cmd, self); g_pKeybindManager->spawnWithRules(*cmd, self);
g_pEventManager->postEvent({.event = "createworkspace", .data = m_name}); g_pEventManager->postEvent({"createworkspace", m_szName});
g_pEventManager->postEvent({.event = "createworkspacev2", .data = std::format("{},{}", m_id, m_name)}); g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)});
EMIT_HOOK_EVENT("createWorkspace", this); EMIT_HOOK_EVENT("createWorkspace", this);
} }
SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName() const { SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName() const {
return m_prevWorkspace; return m_sPrevWorkspace;
} }
CWorkspace::~CWorkspace() { CWorkspace::~CWorkspace() {
Debug::log(LOG, "Destroying workspace ID {}", m_id); Debug::log(LOG, "Destroying workspace ID {}", m_iID);
// check if g_pHookSystem and g_pEventManager exist, they might be destroyed as in when the compositor is closing. // check if g_pHookSystem and g_pEventManager exist, they might be destroyed as in when the compositor is closing.
if (g_pHookSystem) if (g_pHookSystem)
g_pHookSystem->unhook(m_focusedWindowHook); g_pHookSystem->unhook(m_pFocusedWindowHook);
if (g_pEventManager) { if (g_pEventManager) {
g_pEventManager->postEvent({.event = "destroyworkspace", .data = m_name}); g_pEventManager->postEvent({"destroyworkspace", m_szName});
g_pEventManager->postEvent({.event = "destroyworkspacev2", .data = std::format("{},{}", m_id, m_name)}); g_pEventManager->postEvent({"destroyworkspacev2", std::format("{},{}", m_iID, m_szName)});
EMIT_HOOK_EVENT("destroyWorkspace", this); EMIT_HOOK_EVENT("destroyWorkspace", this);
} }
} }
void CWorkspace::startAnim(bool in, bool left, bool instant) { void CWorkspace::startAnim(bool in, bool left, bool instant) {
if (!instant) { if (!instant) {
const std::string ANIMNAME = std::format("{}{}", m_isSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out"); const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out");
m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME));
m_renderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); m_vRenderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME));
} }
const auto ANIMSTYLE = m_alpha->getStyle(); const auto ANIMSTYLE = m_fAlpha->getStyle();
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
// set floating windows offset callbacks // set floating windows offset callbacks
m_renderOffset->setUpdateCallback([&](auto) { m_vRenderOffset->setUpdateCallback([&](auto) {
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (!validMapped(w) || w->workspaceID() != m_id) if (!validMapped(w) || w->workspaceID() != m_iID)
continue; continue;
w->onWorkspaceAnimUpdate(); w->onWorkspaceAnimUpdate();
@@ -94,7 +94,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
}); });
if (ANIMSTYLE.starts_with("slidefade")) { if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = m_monitor.lock(); const auto PMONITOR = m_pMonitor.lock();
float movePerc = 100.f; float movePerc = 100.f;
if (ANIMSTYLE.find('%') != std::string::npos) { if (ANIMSTYLE.find('%') != std::string::npos) {
@@ -104,84 +104,84 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); } } catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); }
} }
m_alpha->setValueAndWarp(1.f); m_fAlpha->setValueAndWarp(1.f);
m_renderOffset->setValueAndWarp(Vector2D(0, 0)); m_vRenderOffset->setValueAndWarp(Vector2D(0, 0));
if (ANIMSTYLE.starts_with("slidefadevert")) { if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) { if (in) {
m_alpha->setValueAndWarp(0.f); m_fAlpha->setValueAndWarp(0.f);
m_renderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->m_size.y : -PMONITOR->m_size.y) * (movePerc / 100.f))); m_vRenderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
*m_alpha = 1.f; *m_fAlpha = 1.f;
*m_renderOffset = Vector2D(0, 0); *m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_alpha->setValueAndWarp(1.f); m_fAlpha->setValueAndWarp(1.f);
*m_alpha = 0.f; *m_fAlpha = 0.f;
*m_renderOffset = Vector2D(0.0, (left ? -PMONITOR->m_size.y : PMONITOR->m_size.y) * (movePerc / 100.f)); *m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
} }
} else { } else {
if (in) { if (in) {
m_alpha->setValueAndWarp(0.f); m_fAlpha->setValueAndWarp(0.f);
m_renderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->m_size.x : -PMONITOR->m_size.x) * (movePerc / 100.f), 0.0)); m_vRenderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0));
*m_alpha = 1.f; *m_fAlpha = 1.f;
*m_renderOffset = Vector2D(0, 0); *m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_alpha->setValueAndWarp(1.f); m_fAlpha->setValueAndWarp(1.f);
*m_alpha = 0.f; *m_fAlpha = 0.f;
*m_renderOffset = Vector2D((left ? -PMONITOR->m_size.x : PMONITOR->m_size.x) * (movePerc / 100.f), 0.0); *m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0);
} }
} }
} else if (ANIMSTYLE == "fade") { } else if (ANIMSTYLE == "fade") {
m_renderOffset->setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade. m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade.
if (in) { if (in) {
m_alpha->setValueAndWarp(0.f); m_fAlpha->setValueAndWarp(0.f);
*m_alpha = 1.f; *m_fAlpha = 1.f;
} else { } else {
m_alpha->setValueAndWarp(1.f); m_fAlpha->setValueAndWarp(1.f);
*m_alpha = 0.f; *m_fAlpha = 0.f;
} }
} else if (ANIMSTYLE == "slidevert") { } else if (ANIMSTYLE == "slidevert") {
// fallback is slide // fallback is slide
const auto PMONITOR = m_monitor.lock(); const auto PMONITOR = m_pMonitor.lock();
const auto YDISTANCE = PMONITOR->m_size.y + *PWORKSPACEGAP; const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
m_alpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) { if (in) {
m_renderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE)); m_vRenderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
*m_renderOffset = Vector2D(0, 0); *m_vRenderOffset = Vector2D(0, 0);
} else { } else {
*m_renderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE); *m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
} }
} else { } else {
// fallback is slide // fallback is slide
const auto PMONITOR = m_monitor.lock(); const auto PMONITOR = m_pMonitor.lock();
const auto XDISTANCE = PMONITOR->m_size.x + *PWORKSPACEGAP; const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
m_alpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) { if (in) {
m_renderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0)); m_vRenderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
*m_renderOffset = Vector2D(0, 0); *m_vRenderOffset = Vector2D(0, 0);
} else { } else {
*m_renderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0); *m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
} }
} }
if (m_isSpecialWorkspace) { if (m_bIsSpecialWorkspace) {
// required for open/close animations // required for open/close animations
if (in) { if (in) {
m_alpha->setValueAndWarp(0.f); m_fAlpha->setValueAndWarp(0.f);
*m_alpha = 1.f; *m_fAlpha = 1.f;
} else { } else {
m_alpha->setValueAndWarp(1.f); m_fAlpha->setValueAndWarp(1.f);
*m_alpha = 0.f; *m_fAlpha = 0.f;
} }
} }
if (instant) { if (instant) {
m_renderOffset->warp(); m_vRenderOffset->warp();
m_alpha->warp(); m_fAlpha->warp();
} }
} }
@@ -194,39 +194,39 @@ void CWorkspace::moveToMonitor(const MONITORID& id) {
} }
PHLWINDOW CWorkspace::getLastFocusedWindow() { PHLWINDOW CWorkspace::getLastFocusedWindow() {
if (!validMapped(m_lastFocusedWindow) || m_lastFocusedWindow->workspaceID() != m_id) if (!validMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow->workspaceID() != m_iID)
return nullptr; return nullptr;
return m_lastFocusedWindow.lock(); return m_pLastFocusedWindow.lock();
} }
void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) { void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
if (!prev) { if (!prev) {
m_prevWorkspace.id = -1; m_sPrevWorkspace.id = -1;
m_prevWorkspace.name = ""; m_sPrevWorkspace.name = "";
return; return;
} }
if (prev->m_id == m_id) { if (prev->m_iID == m_iID) {
Debug::log(LOG, "Tried to set prev workspace to the same as current one"); Debug::log(LOG, "Tried to set prev workspace to the same as current one");
return; return;
} }
m_prevWorkspace.id = prev->m_id; m_sPrevWorkspace.id = prev->m_iID;
m_prevWorkspace.name = prev->m_name; m_sPrevWorkspace.name = prev->m_szName;
prev->m_monitor->addPrevWorkspaceID(prev->m_id); prev->m_pMonitor->addPrevWorkspaceID(prev->m_iID);
} }
std::string CWorkspace::getConfigName() { std::string CWorkspace::getConfigName() {
if (m_isSpecialWorkspace) { if (m_bIsSpecialWorkspace) {
return m_name; return m_szName;
} }
if (m_id > 0) if (m_iID > 0)
return std::to_string(m_id); return std::to_string(m_iID);
return "name:" + m_name; return "name:" + m_szName;
} }
bool CWorkspace::matchesStaticSelector(const std::string& selector_) { bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
@@ -241,12 +241,12 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
if (wsid == WORKSPACE_INVALID) if (wsid == WORKSPACE_INVALID)
return false; return false;
return wsid == m_id; return wsid == m_iID;
} else if (selector.starts_with("name:")) { } else if (selector.starts_with("name:")) {
return m_name == selector.substr(5); return m_szName == selector.substr(5);
} else if (selector.starts_with("special")) { } else if (selector.starts_with("special")) {
return m_name == selector; return m_szName == selector;
} else { } else {
// parse selector // parse selector
@@ -261,7 +261,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
// n - named: n[true] or n[s:string] or n[e:string] // n - named: n[true] or n[s:string] or n[e:string]
// m - monitor: m[monitor_selector] // m - monitor: m[monitor_selector]
// w - windowCount: w[1-4] or w[1], optional flag t or f for tiled or floating and // w - windowCount: w[1-4] or w[1], optional flag t or f for tiled or floating and
// flag p to count only pinned windows, e.g. w[p1-2], w[pg4]
// flag g to count groups instead of windows, e.g. w[t1-2], w[fg4] // flag g to count groups instead of windows, e.g. w[t1-2], w[fg4]
// flag v will count only visible windows // flag v will count only visible windows
// f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states // f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states
@@ -306,7 +305,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false; return false;
} }
if (std::clamp(m_id, from, to) != m_id) if (std::clamp(m_iID, from, to) != m_iID)
return false; return false;
continue; continue;
} }
@@ -321,7 +320,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto SHOULDBESPECIAL = configStringToInt(prop); const auto SHOULDBESPECIAL = configStringToInt(prop);
if (SHOULDBESPECIAL && (bool)*SHOULDBESPECIAL != m_isSpecialWorkspace) if (SHOULDBESPECIAL && (bool)*SHOULDBESPECIAL != m_bIsSpecialWorkspace)
return false; return false;
continue; continue;
} }
@@ -336,7 +335,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto PMONITOR = g_pCompositor->getMonitorFromString(prop); const auto PMONITOR = g_pCompositor->getMonitorFromString(prop);
if (!(PMONITOR ? PMONITOR == m_monitor : false)) if (!(PMONITOR ? PMONITOR == m_pMonitor : false))
return false; return false;
continue; continue;
} }
@@ -349,14 +348,14 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
prop = prop.substr(2, prop.length() - 3); prop = prop.substr(2, prop.length() - 3);
if (prop.starts_with("s:") && !m_name.starts_with(prop.substr(2))) if (prop.starts_with("s:") && !m_szName.starts_with(prop.substr(2)))
return false; return false;
if (prop.starts_with("e:") && !m_name.ends_with(prop.substr(2))) if (prop.starts_with("e:") && !m_szName.ends_with(prop.substr(2)))
return false; return false;
const auto WANTSNAMED = configStringToInt(prop); const auto WANTSNAMED = configStringToInt(prop);
if (WANTSNAMED && *WANTSNAMED != (m_id <= -1337)) if (WANTSNAMED && *WANTSNAMED != (m_iID <= -1337))
return false; return false;
continue; continue;
} }
@@ -371,7 +370,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
prop = prop.substr(2, prop.length() - 3); prop = prop.substr(2, prop.length() - 3);
int wantsOnlyTiled = -1; int wantsOnlyTiled = -1;
int wantsOnlyPinned = false;
bool wantsCountGroup = false; bool wantsCountGroup = false;
bool wantsCountVisible = false; bool wantsCountVisible = false;
@@ -383,9 +381,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
} else if (flag == 'f' && wantsOnlyTiled == -1) { } else if (flag == 'f' && wantsOnlyTiled == -1) {
wantsOnlyTiled = 0; wantsOnlyTiled = 0;
flagCount++; flagCount++;
} else if (flag == 'p' && !wantsOnlyPinned) {
wantsOnlyPinned = true;
flagCount++;
} else if (flag == 'g' && !wantsCountGroup) { } else if (flag == 'g' && !wantsCountGroup) {
wantsCountGroup = true; wantsCountGroup = true;
flagCount++; flagCount++;
@@ -416,11 +411,9 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
int count; int count;
if (wantsCountGroup) if (wantsCountGroup)
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (count != from) if (count != from)
@@ -451,12 +444,10 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
WORKSPACEID count; WORKSPACEID count;
if (wantsCountGroup) if (wantsCountGroup)
count = count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (std::clamp(count, from, to) != count) if (std::clamp(count, from, to) != count)
@@ -481,15 +472,15 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
switch (FSSTATE) { switch (FSSTATE) {
case -1: // no fullscreen case -1: // no fullscreen
if (m_hasFullscreenWindow) if (m_bHasFullscreenWindow)
return false; return false;
break; break;
case 0: // fullscreen full case 0: // fullscreen full
if (!m_hasFullscreenWindow || m_fullscreenMode != FSMODE_FULLSCREEN) if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_FULLSCREEN)
return false; return false;
break; break;
case 1: // maximized case 1: // maximized
if (!m_hasFullscreenWindow || m_fullscreenMode != FSMODE_MAXIMIZED) if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_MAXIMIZED)
return false; return false;
break; break;
default: break; default: break;
@@ -509,23 +500,23 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
} }
void CWorkspace::markInert() { void CWorkspace::markInert() {
m_inert = true; m_bInert = true;
m_id = WORKSPACE_INVALID; m_iID = WORKSPACE_INVALID;
m_visible = false; m_bVisible = false;
m_monitor.reset(); m_pMonitor.reset();
} }
bool CWorkspace::inert() { bool CWorkspace::inert() {
return m_inert; return m_bInert;
} }
MONITORID CWorkspace::monitorID() { MONITORID CWorkspace::monitorID() {
return m_monitor ? m_monitor->m_id : MONITOR_INVALID; return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID;
} }
PHLWINDOW CWorkspace::getFullscreenWindow() { PHLWINDOW CWorkspace::getFullscreenWindow() {
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_workspace == m_self && w->isFullscreen()) if (w->m_pWorkspace == m_pSelf && w->isFullscreen())
return w; return w;
} }
@@ -533,25 +524,23 @@ PHLWINDOW CWorkspace::getFullscreenWindow() {
} }
bool CWorkspace::isVisible() { bool CWorkspace::isVisible() {
return m_visible; return m_bVisible;
} }
bool CWorkspace::isVisibleNotCovered() { bool CWorkspace::isVisibleNotCovered() {
const auto PMONITOR = m_monitor.lock(); const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR->m_activeSpecialWorkspace) if (PMONITOR->activeSpecialWorkspace)
return PMONITOR->m_activeSpecialWorkspace->m_id == m_id; return PMONITOR->activeSpecialWorkspace->m_iID == m_iID;
return PMONITOR->m_activeWorkspace->m_id == m_id; return PMONITOR->activeWorkspace->m_iID == m_iID;
} }
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) { int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0; int no = 0;
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_id || !w->m_isMapped) if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue; continue;
if (onlyTiled.has_value() && w->m_isFloating == onlyTiled.value()) if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyPinned.has_value() && w->m_pinned != onlyPinned.value())
continue; continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue; continue;
@@ -561,16 +550,14 @@ int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> on
return no; return no;
} }
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) { int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0; int no = 0;
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_id || !w->m_isMapped) if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue; continue;
if (!w->m_groupData.head) if (!w->m_sGroupData.head)
continue; continue;
if (onlyTiled.has_value() && w->m_isFloating == onlyTiled.value()) if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyPinned.has_value() && w->m_pinned != onlyPinned.value())
continue; continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue; continue;
@@ -580,8 +567,8 @@ int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onl
} }
PHLWINDOW CWorkspace::getFirstWindow() { PHLWINDOW CWorkspace::getFirstWindow() {
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_workspace == m_self && w->m_isMapped && !w->isHidden()) if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && !w->isHidden())
return w; return w;
} }
@@ -589,27 +576,32 @@ PHLWINDOW CWorkspace::getFirstWindow() {
} }
PHLWINDOW CWorkspace::getTopLeftWindow() { PHLWINDOW CWorkspace::getTopLeftWindow() {
const auto PMONITOR = m_monitor.lock(); const auto PMONITOR = m_pMonitor.lock();
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_workspace != m_self || !w->m_isMapped || w->isHidden()) if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue; continue;
const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
if (WINDOWIDEALBB.x <= PMONITOR->m_position.x + 1 && WINDOWIDEALBB.y <= PMONITOR->m_position.y + 1) if (WINDOWIDEALBB.x <= PMONITOR->vecPosition.x + 1 && WINDOWIDEALBB.y <= PMONITOR->vecPosition.y + 1)
return w; return w;
} }
return nullptr; return nullptr;
} }
bool CWorkspace::hasUrgentWindow() { bool CWorkspace::hasUrgentWindow() {
return std::ranges::any_of(g_pCompositor->m_windows, [this](const auto& w) { return w->m_workspace == m_self && w->m_isMapped && w->m_isUrgent; }); for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && w->m_bIsUrgent)
return true;
}
return false;
} }
void CWorkspace::updateWindowDecos() { void CWorkspace::updateWindowDecos() {
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_workspace != m_self) if (w->m_pWorkspace != m_pSelf)
continue; continue;
w->updateWindowDecos(); w->updateWindowDecos();
@@ -617,10 +609,10 @@ void CWorkspace::updateWindowDecos() {
} }
void CWorkspace::updateWindowData() { void CWorkspace::updateWindowData() {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_self.lock()); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock());
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_workspace != m_self) if (w->m_pWorkspace != m_pSelf)
continue; continue;
w->updateWindowData(WORKSPACERULE); w->updateWindowData(WORKSPACERULE);
@@ -628,35 +620,29 @@ void CWorkspace::updateWindowData() {
} }
void CWorkspace::forceReportSizesToWindows() { void CWorkspace::forceReportSizesToWindows() {
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_workspace != m_self || !w->m_isMapped || w->isHidden()) if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue; continue;
w->sendWindowSize(true); w->sendWindowSize(w->m_vRealSize->goal(), true);
} }
} }
void CWorkspace::rename(const std::string& name) { void CWorkspace::rename(const std::string& name) {
if (g_pCompositor->isWorkspaceSpecial(m_id)) if (g_pCompositor->isWorkspaceSpecial(m_iID))
return; return;
Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_id, name); Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name);
m_name = name; m_szName = name;
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_self.lock()); g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName});
m_persistent = WORKSPACERULE.isPersistent;
if (WORKSPACERULE.isPersistent)
g_pCompositor->ensurePersistentWorkspacesPresent(std::vector<SWorkspaceRule>{WORKSPACERULE}, m_self.lock());
g_pEventManager->postEvent({.event = "renameworkspace", .data = std::to_string(m_id) + "," + m_name});
} }
void CWorkspace::updateWindows() { void CWorkspace::updateWindows() {
m_hasFullscreenWindow = std::ranges::any_of(g_pCompositor->m_windows, [this](const auto& w) { return w->m_isMapped && w->m_workspace == m_self && w->isFullscreen(); }); m_bHasFullscreenWindow = std::ranges::any_of(g_pCompositor->m_vWindows, [this](const auto& w) { return w->m_bIsMapped && w->m_pWorkspace == m_pSelf && w->isFullscreen(); });
for (auto const& w : g_pCompositor->m_windows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (!w->m_isMapped || w->m_workspace != m_self) if (!w->m_bIsMapped || w->m_pWorkspace != m_pSelf)
continue; continue;
w->updateDynamicRules(); w->updateDynamicRules();

View File

@@ -2,6 +2,7 @@
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include <string> #include <string>
#include "../defines.hpp"
#include "DesktopTypes.hpp" #include "DesktopTypes.hpp"
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
@@ -23,39 +24,39 @@ class CWorkspace {
// Workspaces ID-based have IDs > 0 // Workspaces ID-based have IDs > 0
// and workspaces name-based have IDs starting with -1337 // and workspaces name-based have IDs starting with -1337
WORKSPACEID m_id = WORKSPACE_INVALID; WORKSPACEID m_iID = WORKSPACE_INVALID;
std::string m_name = ""; std::string m_szName = "";
PHLMONITORREF m_monitor; PHLMONITORREF m_pMonitor;
bool m_hasFullscreenWindow = false; bool m_bHasFullscreenWindow = false;
eFullscreenMode m_fullscreenMode = FSMODE_NONE; eFullscreenMode m_efFullscreenMode = FSMODE_NONE;
wl_array m_wlrCoordinateArr; wl_array m_wlrCoordinateArr;
// for animations // for animations
PHLANIMVAR<Vector2D> m_renderOffset; PHLANIMVAR<Vector2D> m_vRenderOffset;
PHLANIMVAR<float> m_alpha; PHLANIMVAR<float> m_fAlpha;
bool m_forceRendering = false; bool m_bForceRendering = false;
// allows damage to propagate. // allows damage to propagate.
bool m_visible = false; bool m_bVisible = false;
// "scratchpad" // "scratchpad"
bool m_isSpecialWorkspace = false; bool m_bIsSpecialWorkspace = false;
// last window // last window
PHLWINDOWREF m_lastFocusedWindow; PHLWINDOWREF m_pLastFocusedWindow;
// user-set // user-set
bool m_defaultFloating = false; bool m_bDefaultFloating = false;
bool m_defaultPseudo = false; bool m_bDefaultPseudo = false;
// last monitor (used on reconnect) // last monitor (used on reconnect)
std::string m_lastMonitor = ""; std::string m_szLastMonitor = "";
bool m_wasCreatedEmpty = true; bool m_bWasCreatedEmpty = true;
bool m_persistent = false; bool m_bPersistent = false;
// Inert: destroyed and invalid. If this is true, release the ptr you have. // Inert: destroyed and invalid. If this is true, release the ptr you have.
bool inert(); bool inert();
@@ -71,8 +72,8 @@ class CWorkspace {
SWorkspaceIDName getPrevWorkspaceIDName() const; SWorkspaceIDName getPrevWorkspaceIDName() const;
void updateWindowDecos(); void updateWindowDecos();
void updateWindowData(); void updateWindowData();
int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyPinned = {}, std::optional<bool> onlyVisible = {}); int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyPinned = {}, std::optional<bool> onlyVisible = {}); int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
bool hasUrgentWindow(); bool hasUrgentWindow();
PHLWINDOW getFirstWindow(); PHLWINDOW getFirstWindow();
PHLWINDOW getTopLeftWindow(); PHLWINDOW getTopLeftWindow();
@@ -87,11 +88,11 @@ class CWorkspace {
void init(PHLWORKSPACE self); void init(PHLWORKSPACE self);
// Previous workspace ID and name is stored during a workspace change, allowing travel // Previous workspace ID and name is stored during a workspace change, allowing travel
// to the previous workspace. // to the previous workspace.
SWorkspaceIDName m_prevWorkspace; SWorkspaceIDName m_sPrevWorkspace;
SP<HOOK_CALLBACK_FN> m_focusedWindowHook; SP<HOOK_CALLBACK_FN> m_pFocusedWindowHook;
bool m_inert = true; bool m_bInert = true;
WP<CWorkspace> m_self; WP<CWorkspace> m_pSelf;
}; };
inline bool valid(const PHLWORKSPACE& ref) { inline bool valid(const PHLWORKSPACE& ref) {

View File

@@ -34,8 +34,7 @@ class IHID {
struct { struct {
CSignal destroy; CSignal destroy;
} m_events; } events;
std::string m_deviceName; std::string deviceName, hlName;
std::string m_hlName;
}; };

View File

@@ -8,8 +8,6 @@
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>
#include <cstring> #include <cstring>
using namespace Hyprutils::OS;
#define LED_COUNT 3 #define LED_COUNT 3
constexpr static std::array<const char*, 8> MODNAMES = { constexpr static std::array<const char*, 8> MODNAMES = {
@@ -28,38 +26,41 @@ eHIDType IKeyboard::getType() {
} }
IKeyboard::~IKeyboard() { IKeyboard::~IKeyboard() {
m_events.destroy.emit(); events.destroy.emit();
clearManuallyAllocd(); clearManuallyAllocd();
} }
void IKeyboard::clearManuallyAllocd() { void IKeyboard::clearManuallyAllocd() {
if (m_xkbStaticState) if (xkbStaticState)
xkb_state_unref(m_xkbStaticState); xkb_state_unref(xkbStaticState);
if (m_xkbState) if (xkbState)
xkb_state_unref(m_xkbState); xkb_state_unref(xkbState);
if (m_xkbKeymap) if (xkbKeymap)
xkb_keymap_unref(m_xkbKeymap); xkb_keymap_unref(xkbKeymap);
if (m_xkbSymState) if (xkbKeymapFD >= 0)
xkb_state_unref(m_xkbSymState); close(xkbKeymapFD);
m_xkbSymState = nullptr; if (xkbSymState)
m_xkbKeymap = nullptr; xkb_state_unref(xkbSymState);
m_xkbState = nullptr;
m_xkbStaticState = nullptr; xkbSymState = nullptr;
m_xkbKeymapFD.reset(); xkbKeymap = nullptr;
xkbState = nullptr;
xkbStaticState = nullptr;
xkbKeymapFD = -1;
} }
void IKeyboard::setKeymap(const SStringRuleNames& rules) { void IKeyboard::setKeymap(const SStringRuleNames& rules) {
if (m_keymapOverridden) { if (keymapOverridden) {
Debug::log(LOG, "Ignoring setKeymap: keymap is overridden"); Debug::log(LOG, "Ignoring setKeymap: keymap is overridden");
return; return;
} }
m_currentRules = rules; currentRules = rules;
xkb_rule_names XKBRULES = { xkb_rule_names XKBRULES = {
.rules = rules.rules.c_str(), .rules = rules.rules.c_str(),
.model = rules.model.c_str(), .model = rules.model.c_str(),
@@ -80,21 +81,21 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model, Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model,
rules.options); rules.options);
if (!m_xkbFilePath.empty()) { if (!xkbFilePath.empty()) {
auto path = absolutePath(m_xkbFilePath, g_pConfigManager->m_configCurrentPath); auto path = absolutePath(xkbFilePath, g_pConfigManager->configCurrentPath);
if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE) if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE)
Debug::log(ERR, "Cannot open input:kb_file= file for reading"); Debug::log(ERR, "Cannot open input:kb_file= file for reading");
else { else {
m_xkbKeymap = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); xkbKeymap = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
fclose(KEYMAPFILE); fclose(KEYMAPFILE);
} }
} }
if (!m_xkbKeymap) if (!xkbKeymap)
m_xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS); xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!m_xkbKeymap) { if (!xkbKeymap) {
g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant + g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant +
", options: " + rules.options + ", layout: " + rules.layout + " )"); ", options: " + rules.options + ", layout: " + rules.layout + " )");
@@ -102,38 +103,38 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
rules.options); rules.options);
memset(&XKBRULES, 0, sizeof(XKBRULES)); memset(&XKBRULES, 0, sizeof(XKBRULES));
m_currentRules.rules = ""; currentRules.rules = "";
m_currentRules.model = ""; currentRules.model = "";
m_currentRules.variant = ""; currentRules.variant = "";
m_currentRules.options = ""; currentRules.options = "";
m_currentRules.layout = "us"; currentRules.layout = "us";
m_xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS); xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
} }
updateXKBTranslationState(m_xkbKeymap); updateXKBTranslationState(xkbKeymap);
const auto NUMLOCKON = g_pConfigManager->getDeviceInt(m_hlName, "numlock_by_default", "input:numlock_by_default"); const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default");
if (NUMLOCKON == 1) { if (NUMLOCKON == 1) {
// lock numlock // lock numlock
const auto IDX = xkb_map_mod_get_index(m_xkbKeymap, XKB_MOD_NAME_NUM); const auto IDX = xkb_map_mod_get_index(xkbKeymap, XKB_MOD_NAME_NUM);
if (IDX != XKB_MOD_INVALID) if (IDX != XKB_MOD_INVALID)
m_modifiersState.locked |= (uint32_t)1 << IDX; modifiersState.locked |= (uint32_t)1 << IDX;
// 0 to avoid mods getting stuck if depressed during reload // 0 to avoid mods getting stuck if depressed during reload
updateModifiers(0, 0, m_modifiersState.locked, m_modifiersState.group); updateModifiers(0, 0, modifiersState.locked, modifiersState.group);
} }
for (size_t i = 0; i < std::min(LEDNAMES.size(), m_ledIndexes.size()); ++i) { for (size_t i = 0; i < LEDNAMES.size(); ++i) {
m_ledIndexes[i] = xkb_map_led_get_index(m_xkbKeymap, LEDNAMES[i]); ledIndexes.at(i) = xkb_map_led_get_index(xkbKeymap, LEDNAMES.at(i));
Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES[i], m_ledIndexes[i]); Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES.at(i), ledIndexes.at(i));
} }
for (size_t i = 0; i < std::min(MODNAMES.size(), m_modIndexes.size()); ++i) { for (size_t i = 0; i < MODNAMES.size(); ++i) {
m_modIndexes[i] = xkb_map_mod_get_index(m_xkbKeymap, MODNAMES[i]); modIndexes.at(i) = xkb_map_mod_get_index(xkbKeymap, MODNAMES.at(i));
Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES[i], m_modIndexes[i]); Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i));
} }
updateKeymapFD(); updateKeymapFD();
@@ -144,59 +145,60 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
} }
void IKeyboard::updateKeymapFD() { void IKeyboard::updateKeymapFD() {
Debug::log(LOG, "Updating keymap fd for keyboard {}", m_deviceName); Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName);
if (m_xkbKeymapFD.isValid()) if (xkbKeymapFD >= 0)
m_xkbKeymapFD.reset(); close(xkbKeymapFD);
xkbKeymapFD = -1;
auto cKeymapStr = xkb_keymap_get_as_string(m_xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
m_xkbKeymapString = cKeymapStr; xkbKeymapString = cKeymapStr;
free(cKeymapStr); free(cKeymapStr);
CFileDescriptor rw, ro; int rw, ro;
if (!allocateSHMFilePair(m_xkbKeymapString.length() + 1, rw, ro)) if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro))
Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap"); Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap");
else { else {
auto keymapFDDest = mmap(nullptr, m_xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw.get(), 0); auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0);
rw.reset(); close(rw);
if (keymapFDDest == MAP_FAILED) { if (keymapFDDest == MAP_FAILED) {
Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap"); Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap");
ro.reset(); close(ro);
} else { } else {
memcpy(keymapFDDest, m_xkbKeymapString.c_str(), m_xkbKeymapString.length()); memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length());
munmap(keymapFDDest, m_xkbKeymapString.length() + 1); munmap(keymapFDDest, xkbKeymapString.length() + 1);
m_xkbKeymapFD = std::move(ro); xkbKeymapFD = ro;
} }
} }
Debug::log(LOG, "Updated keymap fd to {}", m_xkbKeymapFD.get()); Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD);
} }
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (m_xkbStaticState) if (xkbStaticState)
xkb_state_unref(m_xkbStaticState); xkb_state_unref(xkbStaticState);
if (m_xkbState) if (xkbState)
xkb_state_unref(m_xkbState); xkb_state_unref(xkbState);
if (m_xkbSymState) if (xkbSymState)
xkb_state_unref(m_xkbSymState); xkb_state_unref(xkbSymState);
m_xkbState = nullptr; xkbState = nullptr;
m_xkbStaticState = nullptr; xkbStaticState = nullptr;
m_xkbSymState = nullptr; xkbSymState = nullptr;
if (keymap) { if (keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
m_xkbStaticState = xkb_state_new(keymap); xkbStaticState = xkb_state_new(keymap);
m_xkbState = xkb_state_new(keymap); xkbState = xkb_state_new(keymap);
m_xkbSymState = xkb_state_new(keymap); xkbSymState = xkb_state_new(keymap);
return; return;
} }
const auto KEYMAP = m_xkbKeymap; const auto KEYMAP = xkbKeymap;
const auto STATE = m_xkbState; const auto STATE = xkbState;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
@@ -205,9 +207,9 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE) == 1) { if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE) == 1) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an active index {}", (uintptr_t)this, i); Debug::log(LOG, "Updating keyboard {:x}'s translation state from an active index {}", (uintptr_t)this, i);
CVarList keyboardLayouts(m_currentRules.layout, 0, ','); CVarList keyboardLayouts(currentRules.layout, 0, ',');
CVarList keyboardModels(m_currentRules.model, 0, ','); CVarList keyboardModels(currentRules.model, 0, ',');
CVarList keyboardVariants(m_currentRules.variant, 0, ','); CVarList keyboardVariants(currentRules.variant, 0, ',');
xkb_rule_names rules = {.rules = "", .model = "", .layout = "", .variant = "", .options = ""}; xkb_rule_names rules = {.rules = "", .model = "", .layout = "", .variant = "", .options = ""};
@@ -235,9 +237,9 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
} }
m_xkbState = xkb_state_new(KEYMAP); xkbState = xkb_state_new(KEYMAP);
m_xkbStaticState = xkb_state_new(KEYMAP); xkbStaticState = xkb_state_new(KEYMAP);
m_xkbSymState = xkb_state_new(KEYMAP); xkbSymState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP); xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
@@ -249,26 +251,26 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an unknown index", (uintptr_t)this); Debug::log(LOG, "Updating keyboard {:x}'s translation state from an unknown index", (uintptr_t)this);
xkb_rule_names rules = { xkb_rule_names rules = {
.rules = m_currentRules.rules.c_str(), .rules = currentRules.rules.c_str(),
.model = m_currentRules.model.c_str(), .model = currentRules.model.c_str(),
.layout = m_currentRules.layout.c_str(), .layout = currentRules.layout.c_str(),
.variant = m_currentRules.variant.c_str(), .variant = currentRules.variant.c_str(),
.options = m_currentRules.options.c_str(), .options = currentRules.options.c_str(),
}; };
const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
m_xkbState = xkb_state_new(NEWKEYMAP); xkbState = xkb_state_new(NEWKEYMAP);
m_xkbStaticState = xkb_state_new(NEWKEYMAP); xkbStaticState = xkb_state_new(NEWKEYMAP);
m_xkbSymState = xkb_state_new(NEWKEYMAP); xkbSymState = xkb_state_new(NEWKEYMAP);
xkb_keymap_unref(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
} }
std::string IKeyboard::getActiveLayout() { std::string IKeyboard::getActiveLayout() {
const auto KEYMAP = m_xkbKeymap; const auto KEYMAP = xkbKeymap;
const auto STATE = m_xkbState; const auto STATE = xkbState;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) { for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
@@ -285,12 +287,12 @@ std::string IKeyboard::getActiveLayout() {
} }
std::optional<uint32_t> IKeyboard::getLEDs() { std::optional<uint32_t> IKeyboard::getLEDs() {
if (m_xkbState == nullptr) if (xkbState == nullptr)
return {}; return {};
uint32_t leds = 0; uint32_t leds = 0;
for (uint32_t i = 0; i < std::min((size_t)LED_COUNT, m_ledIndexes.size()); ++i) { for (uint32_t i = 0; i < LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(m_xkbState, m_ledIndexes[i])) if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i)))
leds |= (1 << i); leds |= (1 << i);
} }
@@ -307,10 +309,10 @@ void IKeyboard::updateLEDs() {
} }
void IKeyboard::updateLEDs(uint32_t leds) { void IKeyboard::updateLEDs(uint32_t leds) {
if (!m_xkbState) if (!xkbState)
return; return;
if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(m_self.lock())) if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock()))
return; return;
if (!aq()) if (!aq())
@@ -320,13 +322,13 @@ void IKeyboard::updateLEDs(uint32_t leds) {
} }
uint32_t IKeyboard::getModifiers() { uint32_t IKeyboard::getModifiers() {
uint32_t modMask = m_modifiersState.depressed | m_modifiersState.latched; uint32_t modMask = modifiersState.depressed | modifiersState.latched;
uint32_t mods = 0; uint32_t mods = 0;
for (size_t i = 0; i < m_modIndexes.size(); ++i) { for (size_t i = 0; i < modIndexes.size(); ++i) {
if (m_modIndexes[i] == XKB_MOD_INVALID) if (modIndexes.at(i) == XKB_MOD_INVALID)
continue; continue;
if (!(modMask & (1 << m_modIndexes[i]))) if (!(modMask & (1 << modIndexes.at(i))))
continue; continue;
mods |= (1 << i); mods |= (1 << i);
@@ -336,50 +338,50 @@ uint32_t IKeyboard::getModifiers() {
} }
void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
if (!m_xkbState) if (!xkbState)
return; return;
xkb_state_update_mask(m_xkbState, depressed, latched, locked, 0, 0, group); xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group);
if (m_xkbSymState) if (xkbSymState)
xkb_state_update_mask(m_xkbSymState, 0, 0, 0, 0, 0, group); xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, group);
if (!updateModifiersState()) if (!updateModifiersState())
return; return;
m_keyboardEvents.modifiers.emit(SModifiersEvent{ keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = m_modifiersState.depressed, .depressed = modifiersState.depressed,
.latched = m_modifiersState.latched, .latched = modifiersState.latched,
.locked = m_modifiersState.locked, .locked = modifiersState.locked,
.group = m_modifiersState.group, .group = modifiersState.group,
}); });
updateLEDs(); updateLEDs();
} }
bool IKeyboard::updateModifiersState() { bool IKeyboard::updateModifiersState() {
if (!m_xkbState) if (!xkbState)
return false; return false;
auto depressed = xkb_state_serialize_mods(m_xkbState, XKB_STATE_MODS_DEPRESSED); auto depressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED);
auto latched = xkb_state_serialize_mods(m_xkbState, XKB_STATE_MODS_LATCHED); auto latched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
auto locked = xkb_state_serialize_mods(m_xkbState, XKB_STATE_MODS_LOCKED); auto locked = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
auto group = xkb_state_serialize_layout(m_xkbState, XKB_STATE_LAYOUT_EFFECTIVE); auto group = xkb_state_serialize_layout(xkbState, XKB_STATE_LAYOUT_EFFECTIVE);
if (depressed == m_modifiersState.depressed && latched == m_modifiersState.latched && locked == m_modifiersState.locked && group == m_modifiersState.group) if (depressed == modifiersState.depressed && latched == modifiersState.latched && locked == modifiersState.locked && group == modifiersState.group)
return false; return false;
m_modifiersState.depressed = depressed; modifiersState.depressed = depressed;
m_modifiersState.latched = latched; modifiersState.latched = latched;
m_modifiersState.locked = locked; modifiersState.locked = locked;
m_modifiersState.group = group; modifiersState.group = group;
return true; return true;
} }
void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) { void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
const auto contains = std::find(m_pressedXKB.begin(), m_pressedXKB.end(), xkbKey) != m_pressedXKB.end(); const auto contains = std::find(pressedXKB.begin(), pressedXKB.end(), xkbKey) != pressedXKB.end();
if (contains && pressed) if (contains && pressed)
return; return;
@@ -387,21 +389,21 @@ void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
return; return;
if (contains) if (contains)
std::erase(m_pressedXKB, xkbKey); std::erase(pressedXKB, xkbKey);
else else
m_pressedXKB.emplace_back(xkbKey); pressedXKB.emplace_back(xkbKey);
xkb_state_update_key(m_xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
if (updateModifiersState()) { if (updateModifiersState()) {
if (m_xkbSymState) if (xkbSymState)
xkb_state_update_mask(m_xkbSymState, 0, 0, 0, 0, 0, m_modifiersState.group); xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, modifiersState.group);
m_keyboardEvents.modifiers.emit(SModifiersEvent{ keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = m_modifiersState.depressed, .depressed = modifiersState.depressed,
.latched = m_modifiersState.latched, .latched = modifiersState.latched,
.locked = m_modifiersState.locked, .locked = modifiersState.locked,
.group = m_modifiersState.group, .group = modifiersState.group,
}); });
} }
} }

View File

@@ -6,7 +6,6 @@
#include <optional> #include <optional>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <hyprutils/os/FileDescriptor.hpp>
AQUAMARINE_FORWARD(IKeyboard); AQUAMARINE_FORWARD(IKeyboard);
@@ -52,7 +51,7 @@ class IKeyboard : public IHID {
CSignal modifiers; CSignal modifiers;
CSignal keymap; CSignal keymap;
CSignal repeatInfo; CSignal repeatInfo;
} m_keyboardEvents; } keyboardEvents;
struct SStringRuleNames { struct SStringRuleNames {
std::string layout = ""; std::string layout = "";
@@ -74,46 +73,41 @@ class IKeyboard : public IHID {
void updateXkbStateWithKey(uint32_t xkbKey, bool pressed); void updateXkbStateWithKey(uint32_t xkbKey, bool pressed);
void updateKeymapFD(); void updateKeymapFD();
bool m_active = false; bool active = false;
bool m_enabled = true; bool enabled = true;
bool m_allowBinds = true;
// if the keymap is overridden by the implementation, // if the keymap is overridden by the implementation,
// don't try to set keyboard rules anymore, to avoid overwriting the requested one. // don't try to set keyboard rules anymore, to avoid overwriting the requested one.
// e.g. Virtual keyboards with custom maps. // e.g. Virtual keyboards with custom maps.
bool m_keymapOverridden = false; bool keymapOverridden = false;
xkb_layout_index_t m_activeLayout = 0; xkb_layout_index_t activeLayout = 0;
xkb_state* m_xkbState = nullptr; xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr,
*xkbSymState = nullptr /* Same as static but gets layouts */;
// never gets modifiers or layout changes sent, used for keybinds xkb_keymap* xkbKeymap = nullptr;
xkb_state* m_xkbStaticState = nullptr;
xkb_state* m_xkbSymState = nullptr; // same as static but gets layouts
xkb_keymap* m_xkbKeymap = nullptr;
struct { struct {
uint32_t depressed = 0, latched = 0, locked = 0, group = 0; uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
} m_modifiersState; } modifiersState;
std::array<xkb_led_index_t, 3> m_ledIndexes = {XKB_MOD_INVALID}; std::array<xkb_led_index_t, 3> ledIndexes = {XKB_MOD_INVALID};
std::array<xkb_mod_index_t, 8> m_modIndexes = {XKB_MOD_INVALID}; std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID};
uint32_t m_leds = 0; uint32_t leds = 0;
std::string m_xkbFilePath = ""; std::string xkbFilePath = "";
std::string m_xkbKeymapString = ""; std::string xkbKeymapString = "";
Hyprutils::OS::CFileDescriptor m_xkbKeymapFD; int xkbKeymapFD = -1;
SStringRuleNames m_currentRules; SStringRuleNames currentRules;
int m_repeatRate = 0; int repeatRate = 0;
int m_repeatDelay = 0; int repeatDelay = 0;
int m_numlockOn = -1; int numlockOn = -1;
bool m_resolveBindsBySym = false; bool resolveBindsBySym = false;
WP<IKeyboard> m_self; WP<IKeyboard> self;
private: private:
void clearManuallyAllocd(); void clearManuallyAllocd();
std::vector<uint32_t> m_pressedXKB; std::vector<uint32_t> pressedXKB;
}; };

View File

@@ -17,10 +17,9 @@ class IPointer : public IHID {
virtual SP<Aquamarine::IPointer> aq() = 0; virtual SP<Aquamarine::IPointer> aq() = 0;
struct SMotionEvent { struct SMotionEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;
Vector2D delta, unaccel; Vector2D delta, unaccel;
bool mouse = false; bool mouse = false;
SP<IPointer> device;
}; };
struct SMotionAbsoluteEvent { struct SMotionAbsoluteEvent {
@@ -106,13 +105,10 @@ class IPointer : public IHID {
CSignal holdBegin; CSignal holdBegin;
CSignal holdEnd; CSignal holdEnd;
} m_pointerEvents; } pointerEvents;
bool m_connected = false; // means connected to the cursor bool connected = false; // means connected to the cursor
std::string m_boundOutput = ""; std::string boundOutput = "";
bool m_flipX = false; // decide to invert horizontal movement
bool m_flipY = false; // decide to invert vertical movement
bool m_isTouchpad = false;
WP<IPointer> m_self; WP<IPointer> self;
}; };

View File

@@ -42,9 +42,9 @@ class ITouch : public IHID {
CSignal motion; CSignal motion;
CSignal cancel; CSignal cancel;
CSignal frame; CSignal frame;
} m_touchEvents; } touchEvents;
std::string m_boundOutput = ""; std::string boundOutput = "";
WP<ITouch> m_self; WP<ITouch> self;
}; };

View File

@@ -6,7 +6,7 @@
SP<CKeyboard> CKeyboard::create(SP<Aquamarine::IKeyboard> keeb) { SP<CKeyboard> CKeyboard::create(SP<Aquamarine::IKeyboard> keeb) {
SP<CKeyboard> pKeeb = SP<CKeyboard>(new CKeyboard(keeb)); SP<CKeyboard> pKeeb = SP<CKeyboard>(new CKeyboard(keeb));
pKeeb->m_self = pKeeb; pKeeb->self = pKeeb;
return pKeeb; return pKeeb;
} }
@@ -16,22 +16,22 @@ bool CKeyboard::isVirtual() {
} }
SP<Aquamarine::IKeyboard> CKeyboard::aq() { SP<Aquamarine::IKeyboard> CKeyboard::aq() {
return m_keyboard.lock(); return keyboard.lock();
} }
CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : m_keyboard(keeb) { CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : keyboard(keeb) {
if (!keeb) if (!keeb)
return; return;
m_listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) { listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) {
m_keyboard.reset(); keyboard.reset();
m_events.destroy.emit(); events.destroy.emit();
}); });
m_listeners.key = keeb->events.key.registerListener([this](std::any d) { listeners.key = keeb->events.key.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d); auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
m_keyboardEvents.key.emit(SKeyEvent{ keyboardEvents.key.emit(SKeyEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.keycode = E.key, .keycode = E.key,
.state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED, .state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
@@ -40,16 +40,16 @@ CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : m_keyboard(keeb) {
updateXkbStateWithKey(E.key + 8, E.pressed); updateXkbStateWithKey(E.key + 8, E.pressed);
}); });
m_listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) { listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
updateModifiersState(); updateModifiersState();
m_keyboardEvents.modifiers.emit(SModifiersEvent{ keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = m_modifiersState.depressed, .depressed = modifiersState.depressed,
.latched = m_modifiersState.latched, .latched = modifiersState.latched,
.locked = m_modifiersState.locked, .locked = modifiersState.locked,
.group = m_modifiersState.group, .group = modifiersState.group,
}); });
}); });
m_deviceName = keeb->getName(); deviceName = keeb->getName();
} }

View File

@@ -12,11 +12,11 @@ class CKeyboard : public IKeyboard {
private: private:
CKeyboard(SP<Aquamarine::IKeyboard> keeb); CKeyboard(SP<Aquamarine::IKeyboard> keeb);
WP<Aquamarine::IKeyboard> m_keyboard; WP<Aquamarine::IKeyboard> keyboard;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
CHyprSignalListener key; CHyprSignalListener key;
CHyprSignalListener modifiers; CHyprSignalListener modifiers;
} m_listeners; } listeners;
}; };

View File

@@ -5,51 +5,45 @@
SP<CMouse> CMouse::create(SP<Aquamarine::IPointer> mouse) { SP<CMouse> CMouse::create(SP<Aquamarine::IPointer> mouse) {
SP<CMouse> pMouse = SP<CMouse>(new CMouse(mouse)); SP<CMouse> pMouse = SP<CMouse>(new CMouse(mouse));
pMouse->m_self = pMouse; pMouse->self = pMouse;
return pMouse; return pMouse;
} }
CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : m_mouse(mouse_) { CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
if (!m_mouse) if (!mouse)
return; return;
if (auto handle = m_mouse->getLibinputHandle()) { listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) {
double w = 0, h = 0; mouse.reset();
m_isTouchpad = libinput_device_has_capability(handle, LIBINPUT_DEVICE_CAP_POINTER) && libinput_device_get_size(handle, &w, &h) == 0; events.destroy.emit();
}
m_listeners.destroy = m_mouse->events.destroy.registerListener([this](std::any d) {
m_mouse.reset();
m_events.destroy.emit();
}); });
m_listeners.motion = m_mouse->events.move.registerListener([this](std::any d) { listeners.motion = mouse->events.move.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SMoveEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SMoveEvent>(d);
m_pointerEvents.motion.emit(SMotionEvent{ pointerEvents.motion.emit(SMotionEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.delta = E.delta, .delta = E.delta,
.unaccel = E.unaccel, .unaccel = E.unaccel,
.mouse = true, .mouse = true,
.device = m_self.lock(),
}); });
}); });
m_listeners.motionAbsolute = m_mouse->events.warp.registerListener([this](std::any d) { listeners.motionAbsolute = mouse->events.warp.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SWarpEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SWarpEvent>(d);
m_pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.absolute = E.absolute, .absolute = E.absolute,
.device = m_self.lock(), .device = self.lock(),
}); });
}); });
m_listeners.button = m_mouse->events.button.registerListener([this](std::any d) { listeners.button = mouse->events.button.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SButtonEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SButtonEvent>(d);
m_pointerEvents.button.emit(SButtonEvent{ pointerEvents.button.emit(SButtonEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.button = E.button, .button = E.button,
.state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED, .state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
@@ -57,10 +51,10 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : m_mouse(mouse_) {
}); });
}); });
m_listeners.axis = m_mouse->events.axis.registerListener([this](std::any d) { listeners.axis = mouse->events.axis.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SAxisEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SAxisEvent>(d);
m_pointerEvents.axis.emit(SAxisEvent{ pointerEvents.axis.emit(SAxisEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.source = (wl_pointer_axis_source)E.source, .source = (wl_pointer_axis_source)E.source,
.axis = (wl_pointer_axis)E.axis, .axis = (wl_pointer_axis)E.axis,
@@ -71,58 +65,58 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : m_mouse(mouse_) {
}); });
}); });
m_listeners.frame = m_mouse->events.frame.registerListener([this](std::any d) { m_pointerEvents.frame.emit(); }); listeners.frame = mouse->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
m_listeners.swipeBegin = m_mouse->events.swipeBegin.registerListener([this](std::any d) { listeners.swipeBegin = mouse->events.swipeBegin.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SSwipeBeginEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SSwipeBeginEvent>(d);
m_pointerEvents.swipeBegin.emit(SSwipeBeginEvent{ pointerEvents.swipeBegin.emit(SSwipeBeginEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
}); });
}); });
m_listeners.swipeEnd = m_mouse->events.swipeEnd.registerListener([this](std::any d) { listeners.swipeEnd = mouse->events.swipeEnd.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SSwipeEndEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SSwipeEndEvent>(d);
m_pointerEvents.swipeEnd.emit(SSwipeEndEvent{ pointerEvents.swipeEnd.emit(SSwipeEndEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.cancelled = E.cancelled, .cancelled = E.cancelled,
}); });
}); });
m_listeners.swipeUpdate = m_mouse->events.swipeUpdate.registerListener([this](std::any d) { listeners.swipeUpdate = mouse->events.swipeUpdate.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SSwipeUpdateEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SSwipeUpdateEvent>(d);
m_pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{ pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
.delta = E.delta, .delta = E.delta,
}); });
}); });
m_listeners.pinchBegin = m_mouse->events.pinchBegin.registerListener([this](std::any d) { listeners.pinchBegin = mouse->events.pinchBegin.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SPinchBeginEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SPinchBeginEvent>(d);
m_pointerEvents.pinchBegin.emit(SPinchBeginEvent{ pointerEvents.pinchBegin.emit(SPinchBeginEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
}); });
}); });
m_listeners.pinchEnd = m_mouse->events.pinchEnd.registerListener([this](std::any d) { listeners.pinchEnd = mouse->events.pinchEnd.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SPinchEndEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SPinchEndEvent>(d);
m_pointerEvents.pinchEnd.emit(SPinchEndEvent{ pointerEvents.pinchEnd.emit(SPinchEndEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.cancelled = E.cancelled, .cancelled = E.cancelled,
}); });
}); });
m_listeners.pinchUpdate = m_mouse->events.pinchUpdate.registerListener([this](std::any d) { listeners.pinchUpdate = mouse->events.pinchUpdate.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SPinchUpdateEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SPinchUpdateEvent>(d);
m_pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{ pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
.delta = E.delta, .delta = E.delta,
@@ -131,25 +125,25 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : m_mouse(mouse_) {
}); });
}); });
m_listeners.holdBegin = m_mouse->events.holdBegin.registerListener([this](std::any d) { listeners.holdBegin = mouse->events.holdBegin.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SHoldBeginEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SHoldBeginEvent>(d);
m_pointerEvents.holdBegin.emit(SHoldBeginEvent{ pointerEvents.holdBegin.emit(SHoldBeginEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
}); });
}); });
m_listeners.holdEnd = m_mouse->events.holdEnd.registerListener([this](std::any d) { listeners.holdEnd = mouse->events.holdEnd.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SHoldEndEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SHoldEndEvent>(d);
m_pointerEvents.holdEnd.emit(SHoldEndEvent{ pointerEvents.holdEnd.emit(SHoldEndEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.cancelled = E.cancelled, .cancelled = E.cancelled,
}); });
}); });
m_deviceName = m_mouse->getName(); deviceName = mouse->getName();
} }
bool CMouse::isVirtual() { bool CMouse::isVirtual() {
@@ -157,5 +151,5 @@ bool CMouse::isVirtual() {
} }
SP<Aquamarine::IPointer> CMouse::aq() { SP<Aquamarine::IPointer> CMouse::aq() {
return m_mouse.lock(); return mouse.lock();
} }

View File

@@ -12,7 +12,7 @@ class CMouse : public IPointer {
private: private:
CMouse(SP<Aquamarine::IPointer> mouse); CMouse(SP<Aquamarine::IPointer> mouse);
WP<Aquamarine::IPointer> m_mouse; WP<Aquamarine::IPointer> mouse;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
@@ -33,5 +33,5 @@ class CMouse : public IPointer {
CHyprSignalListener holdBegin; CHyprSignalListener holdBegin;
CHyprSignalListener holdEnd; CHyprSignalListener holdEnd;
} m_listeners; } listeners;
}; };

View File

@@ -7,7 +7,7 @@
SP<CTablet> CTablet::create(SP<Aquamarine::ITablet> tablet) { SP<CTablet> CTablet::create(SP<Aquamarine::ITablet> tablet) {
SP<CTablet> pTab = SP<CTablet>(new CTablet(tablet)); SP<CTablet> pTab = SP<CTablet>(new CTablet(tablet));
pTab->m_self = pTab; pTab->self = pTab;
PROTO::tablet->registerDevice(pTab); PROTO::tablet->registerDevice(pTab);
@@ -17,7 +17,7 @@ SP<CTablet> CTablet::create(SP<Aquamarine::ITablet> tablet) {
SP<CTabletTool> CTabletTool::create(SP<Aquamarine::ITabletTool> tablet) { SP<CTabletTool> CTabletTool::create(SP<Aquamarine::ITabletTool> tablet) {
SP<CTabletTool> pTab = SP<CTabletTool>(new CTabletTool(tablet)); SP<CTabletTool> pTab = SP<CTabletTool>(new CTabletTool(tablet));
pTab->m_self = pTab; pTab->self = pTab;
PROTO::tablet->registerDevice(pTab); PROTO::tablet->registerDevice(pTab);
@@ -27,7 +27,7 @@ SP<CTabletTool> CTabletTool::create(SP<Aquamarine::ITabletTool> tablet) {
SP<CTabletPad> CTabletPad::create(SP<Aquamarine::ITabletPad> tablet) { SP<CTabletPad> CTabletPad::create(SP<Aquamarine::ITabletPad> tablet) {
SP<CTabletPad> pTab = SP<CTabletPad>(new CTabletPad(tablet)); SP<CTabletPad> pTab = SP<CTabletPad>(new CTabletPad(tablet));
pTab->m_self = pTab; pTab->self = pTab;
PROTO::tablet->registerDevice(pTab); PROTO::tablet->registerDevice(pTab);
@@ -62,24 +62,24 @@ uint32_t CTablet::getCapabilities() {
} }
SP<Aquamarine::ITablet> CTablet::aq() { SP<Aquamarine::ITablet> CTablet::aq() {
return m_tablet.lock(); return tablet.lock();
} }
CTablet::CTablet(SP<Aquamarine::ITablet> tablet_) : m_tablet(tablet_) { CTablet::CTablet(SP<Aquamarine::ITablet> tablet_) : tablet(tablet_) {
if (!m_tablet) if (!tablet)
return; return;
m_listeners.destroy = m_tablet->events.destroy.registerListener([this](std::any d) { listeners.destroy = tablet->events.destroy.registerListener([this](std::any d) {
m_tablet.reset(); tablet.reset();
m_events.destroy.emit(); events.destroy.emit();
}); });
m_listeners.axis = m_tablet->events.axis.registerListener([this](std::any d) { listeners.axis = tablet->events.axis.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITablet::SAxisEvent>(d); auto E = std::any_cast<Aquamarine::ITablet::SAxisEvent>(d);
m_tabletEvents.axis.emit(SAxisEvent{ tabletEvents.axis.emit(SAxisEvent{
.tool = E.tool, .tool = E.tool,
.tablet = m_self.lock(), .tablet = self.lock(),
.timeMs = E.timeMs, .timeMs = E.timeMs,
.updatedAxes = aqUpdateToHl(E.updatedAxes), .updatedAxes = aqUpdateToHl(E.updatedAxes),
.axis = E.absolute, .axis = E.absolute,
@@ -93,43 +93,43 @@ CTablet::CTablet(SP<Aquamarine::ITablet> tablet_) : m_tablet(tablet_) {
}); });
}); });
m_listeners.proximity = m_tablet->events.proximity.registerListener([this](std::any d) { listeners.proximity = tablet->events.proximity.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITablet::SProximityEvent>(d); auto E = std::any_cast<Aquamarine::ITablet::SProximityEvent>(d);
m_tabletEvents.proximity.emit(SProximityEvent{ tabletEvents.proximity.emit(SProximityEvent{
.tool = E.tool, .tool = E.tool,
.tablet = m_self.lock(), .tablet = self.lock(),
.timeMs = E.timeMs, .timeMs = E.timeMs,
.proximity = E.absolute, .proximity = E.absolute,
.in = E.in, .in = E.in,
}); });
}); });
m_listeners.tip = m_tablet->events.tip.registerListener([this](std::any d) { listeners.tip = tablet->events.tip.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITablet::STipEvent>(d); auto E = std::any_cast<Aquamarine::ITablet::STipEvent>(d);
m_tabletEvents.tip.emit(STipEvent{ tabletEvents.tip.emit(STipEvent{
.tool = E.tool, .tool = E.tool,
.tablet = m_self.lock(), .tablet = self.lock(),
.timeMs = E.timeMs, .timeMs = E.timeMs,
.tip = E.absolute, .tip = E.absolute,
.in = E.down, .in = E.down,
}); });
}); });
m_listeners.button = m_tablet->events.button.registerListener([this](std::any d) { listeners.button = tablet->events.button.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITablet::SButtonEvent>(d); auto E = std::any_cast<Aquamarine::ITablet::SButtonEvent>(d);
m_tabletEvents.button.emit(SButtonEvent{ tabletEvents.button.emit(SButtonEvent{
.tool = E.tool, .tool = E.tool,
.tablet = m_self.lock(), .tablet = self.lock(),
.timeMs = E.timeMs, .timeMs = E.timeMs,
.button = E.button, .button = E.button,
.down = E.down, .down = E.down,
}); });
}); });
m_deviceName = m_tablet->getName(); deviceName = tablet->getName();
} }
CTablet::~CTablet() { CTablet::~CTablet() {
@@ -145,26 +145,26 @@ uint32_t CTabletPad::getCapabilities() {
} }
SP<Aquamarine::ITabletPad> CTabletPad::aq() { SP<Aquamarine::ITabletPad> CTabletPad::aq() {
return m_pad.lock(); return pad.lock();
} }
eHIDType CTabletPad::getType() { eHIDType CTabletPad::getType() {
return HID_TYPE_TABLET_PAD; return HID_TYPE_TABLET_PAD;
} }
CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : m_pad(pad_) { CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
if (!m_pad) if (!pad)
return; return;
m_listeners.destroy = m_pad->events.destroy.registerListener([this](std::any d) { listeners.destroy = pad->events.destroy.registerListener([this](std::any d) {
m_pad.reset(); pad.reset();
m_events.destroy.emit(); events.destroy.emit();
}); });
m_listeners.button = m_pad->events.button.registerListener([this](std::any d) { listeners.button = pad->events.button.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITabletPad::SButtonEvent>(d); auto E = std::any_cast<Aquamarine::ITabletPad::SButtonEvent>(d);
m_padEvents.button.emit(SButtonEvent{ padEvents.button.emit(SButtonEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.button = E.button, .button = E.button,
.down = E.down, .down = E.down,
@@ -173,10 +173,10 @@ CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : m_pad(pad_) {
}); });
}); });
m_listeners.ring = m_pad->events.ring.registerListener([this](std::any d) { listeners.ring = pad->events.ring.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITabletPad::SRingEvent>(d); auto E = std::any_cast<Aquamarine::ITabletPad::SRingEvent>(d);
m_padEvents.ring.emit(SRingEvent{ padEvents.ring.emit(SRingEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_RING_SOURCE_FINGER, .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_RING_SOURCE_FINGER,
.ring = E.ring, .ring = E.ring,
@@ -185,10 +185,10 @@ CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : m_pad(pad_) {
}); });
}); });
m_listeners.strip = m_pad->events.strip.registerListener([this](std::any d) { listeners.strip = pad->events.strip.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITabletPad::SStripEvent>(d); auto E = std::any_cast<Aquamarine::ITabletPad::SStripEvent>(d);
m_padEvents.strip.emit(SStripEvent{ padEvents.strip.emit(SStripEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_STRIP_SOURCE_FINGER, .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_STRIP_SOURCE_FINGER,
.strip = E.strip, .strip = E.strip,
@@ -197,11 +197,11 @@ CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : m_pad(pad_) {
}); });
}); });
m_listeners.attach = m_pad->events.attach.registerListener([](std::any d) { listeners.attach = pad->events.attach.registerListener([](std::any d) {
; // TODO: this doesn't do anything in aq atm ; // TODO: this doesn't do anything in aq atm
}); });
m_deviceName = m_pad->getName(); deviceName = pad->getName();
} }
CTabletPad::~CTabletPad() { CTabletPad::~CTabletPad() {
@@ -213,36 +213,36 @@ uint32_t CTabletTool::getCapabilities() {
} }
SP<Aquamarine::ITabletTool> CTabletTool::aq() { SP<Aquamarine::ITabletTool> CTabletTool::aq() {
return m_tool.lock(); return tool.lock();
} }
eHIDType CTabletTool::getType() { eHIDType CTabletTool::getType() {
return HID_TYPE_TABLET_TOOL; return HID_TYPE_TABLET_TOOL;
} }
CTabletTool::CTabletTool(SP<Aquamarine::ITabletTool> tool_) : m_tool(tool_) { CTabletTool::CTabletTool(SP<Aquamarine::ITabletTool> tool_) : tool(tool_) {
if (!m_tool) if (!tool)
return; return;
m_listeners.destroyTool = m_tool->events.destroy.registerListener([this](std::any d) { listeners.destroyTool = tool->events.destroy.registerListener([this](std::any d) {
m_tool.reset(); tool.reset();
m_events.destroy.emit(); events.destroy.emit();
}); });
if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_TILT) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_TILT)
m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT;
if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_PRESSURE) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_PRESSURE)
m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE;
if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_DISTANCE) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_DISTANCE)
m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE;
if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_ROTATION) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_ROTATION)
m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION;
if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_SLIDER) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_SLIDER)
m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER;
if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_WHEEL) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_WHEEL)
m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL;
m_deviceName = std::format("{:x}-{:x}", m_tool->serial, m_tool->id); deviceName = std::format("{:x}-{:x}", tool->serial, tool->id);
} }
CTabletTool::~CTabletTool() { CTabletTool::~CTabletTool() {
@@ -250,25 +250,25 @@ CTabletTool::~CTabletTool() {
} }
SP<CWLSurfaceResource> CTabletTool::getSurface() { SP<CWLSurfaceResource> CTabletTool::getSurface() {
return m_surface.lock(); return pSurface.lock();
} }
void CTabletTool::setSurface(SP<CWLSurfaceResource> surf) { void CTabletTool::setSurface(SP<CWLSurfaceResource> surf) {
if (surf == m_surface) if (surf == pSurface)
return; return;
if (m_surface) { if (pSurface) {
m_listeners.destroySurface.reset(); listeners.destroySurface.reset();
m_surface.reset(); pSurface.reset();
} }
m_surface = surf; pSurface = surf;
if (surf) { if (surf) {
m_listeners.destroySurface = surf->m_events.destroy.registerListener([this](std::any d) { listeners.destroySurface = surf->events.destroy.registerListener([this](std::any d) {
PROTO::tablet->proximityOut(m_self.lock()); PROTO::tablet->proximityOut(self.lock());
m_surface.reset(); pSurface.reset();
m_listeners.destroySurface.reset(); listeners.destroySurface.reset();
}); });
} }
} }

View File

@@ -86,20 +86,20 @@ class CTablet : public IHID {
CSignal proximity; CSignal proximity;
CSignal tip; CSignal tip;
CSignal button; CSignal button;
} m_tabletEvents; } tabletEvents;
WP<CTablet> m_self; WP<CTablet> self;
bool m_relativeInput = false; bool relativeInput = false;
bool m_absolutePos = false; bool absolutePos = false;
std::string m_boundOutput = ""; std::string boundOutput = "";
CBox m_activeArea; CBox activeArea;
CBox m_boundBox; CBox boundBox;
private: private:
CTablet(SP<Aquamarine::ITablet> tablet); CTablet(SP<Aquamarine::ITablet> tablet);
WP<Aquamarine::ITablet> m_tablet; WP<Aquamarine::ITablet> tablet;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
@@ -107,7 +107,7 @@ class CTablet : public IHID {
CHyprSignalListener proximity; CHyprSignalListener proximity;
CHyprSignalListener tip; CHyprSignalListener tip;
CHyprSignalListener button; CHyprSignalListener button;
} m_listeners; } listeners;
}; };
class CTabletPad : public IHID { class CTabletPad : public IHID {
@@ -148,15 +148,15 @@ class CTabletPad : public IHID {
CSignal ring; CSignal ring;
CSignal strip; CSignal strip;
CSignal attach; CSignal attach;
} m_padEvents; } padEvents;
WP<CTabletPad> m_self; WP<CTabletPad> self;
WP<CTabletTool> m_parent; WP<CTabletTool> parent;
private: private:
CTabletPad(SP<Aquamarine::ITabletPad> pad); CTabletPad(SP<Aquamarine::ITabletPad> pad);
WP<Aquamarine::ITabletPad> m_pad; WP<Aquamarine::ITabletPad> pad;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
@@ -164,7 +164,7 @@ class CTabletPad : public IHID {
CHyprSignalListener strip; CHyprSignalListener strip;
CHyprSignalListener button; CHyprSignalListener button;
CHyprSignalListener attach; CHyprSignalListener attach;
} m_listeners; } listeners;
}; };
class CTabletTool : public IHID { class CTabletTool : public IHID {
@@ -198,23 +198,23 @@ class CTabletTool : public IHID {
SP<CWLSurfaceResource> getSurface(); SP<CWLSurfaceResource> getSurface();
void setSurface(SP<CWLSurfaceResource>); void setSurface(SP<CWLSurfaceResource>);
WP<CTabletTool> m_self; WP<CTabletTool> self;
Vector2D m_tilt; Vector2D tilt;
bool m_active = false; // true if in proximity bool active = false; // true if in proximity
uint32_t m_toolCapabilities = 0; uint32_t toolCapabilities = 0;
bool m_isDown = false; bool isDown = false;
std::vector<uint32_t> m_buttonsDown; std::vector<uint32_t> buttonsDown;
Vector2D m_absolutePos; // last known absolute position. Vector2D absolutePos; // last known absolute position.
private: private:
CTabletTool(SP<Aquamarine::ITabletTool> tool); CTabletTool(SP<Aquamarine::ITabletTool> tool);
WP<CWLSurfaceResource> m_surface; WP<CWLSurfaceResource> pSurface;
WP<Aquamarine::ITabletTool> m_tool; WP<Aquamarine::ITabletTool> tool;
struct { struct {
CHyprSignalListener destroySurface; CHyprSignalListener destroySurface;
CHyprSignalListener destroyTool; CHyprSignalListener destroyTool;
} m_listeners; } listeners;
}; };

View File

@@ -5,62 +5,62 @@
SP<CTouchDevice> CTouchDevice::create(SP<Aquamarine::ITouch> touch) { SP<CTouchDevice> CTouchDevice::create(SP<Aquamarine::ITouch> touch) {
SP<CTouchDevice> pTouch = SP<CTouchDevice>(new CTouchDevice(touch)); SP<CTouchDevice> pTouch = SP<CTouchDevice>(new CTouchDevice(touch));
pTouch->m_self = pTouch; pTouch->self = pTouch;
return pTouch; return pTouch;
} }
CTouchDevice::CTouchDevice(SP<Aquamarine::ITouch> touch_) : m_touch(touch_) { CTouchDevice::CTouchDevice(SP<Aquamarine::ITouch> touch_) : touch(touch_) {
if (!m_touch) if (!touch)
return; return;
m_listeners.destroy = m_touch->events.destroy.registerListener([this](std::any d) { listeners.destroy = touch->events.destroy.registerListener([this](std::any d) {
m_events.destroy.emit(); events.destroy.emit();
m_touch.reset(); touch.reset();
}); });
m_listeners.down = m_touch->events.down.registerListener([this](std::any d) { listeners.down = touch->events.down.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SDownEvent>(d); auto E = std::any_cast<Aquamarine::ITouch::SDownEvent>(d);
m_touchEvents.down.emit(SDownEvent{ touchEvents.down.emit(SDownEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.touchID = E.touchID, .touchID = E.touchID,
.pos = E.pos, .pos = E.pos,
.device = m_self.lock(), .device = self.lock(),
}); });
}); });
m_listeners.up = m_touch->events.up.registerListener([this](std::any d) { listeners.up = touch->events.up.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SUpEvent>(d); auto E = std::any_cast<Aquamarine::ITouch::SUpEvent>(d);
m_touchEvents.up.emit(SUpEvent{ touchEvents.up.emit(SUpEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.touchID = E.touchID, .touchID = E.touchID,
}); });
}); });
m_listeners.motion = m_touch->events.move.registerListener([this](std::any d) { listeners.motion = touch->events.move.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SMotionEvent>(d); auto E = std::any_cast<Aquamarine::ITouch::SMotionEvent>(d);
m_touchEvents.motion.emit(SMotionEvent{ touchEvents.motion.emit(SMotionEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.touchID = E.touchID, .touchID = E.touchID,
.pos = E.pos, .pos = E.pos,
}); });
}); });
m_listeners.cancel = m_touch->events.cancel.registerListener([this](std::any d) { listeners.cancel = touch->events.cancel.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SCancelEvent>(d); auto E = std::any_cast<Aquamarine::ITouch::SCancelEvent>(d);
m_touchEvents.cancel.emit(SCancelEvent{ touchEvents.cancel.emit(SCancelEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.touchID = E.touchID, .touchID = E.touchID,
}); });
}); });
m_listeners.frame = m_touch->events.frame.registerListener([this](std::any d) { m_touchEvents.frame.emit(); }); listeners.frame = touch->events.frame.registerListener([this](std::any d) { touchEvents.frame.emit(); });
m_deviceName = m_touch->getName(); deviceName = touch->getName();
} }
bool CTouchDevice::isVirtual() { bool CTouchDevice::isVirtual() {
@@ -68,5 +68,5 @@ bool CTouchDevice::isVirtual() {
} }
SP<Aquamarine::ITouch> CTouchDevice::aq() { SP<Aquamarine::ITouch> CTouchDevice::aq() {
return m_touch.lock(); return touch.lock();
} }

View File

@@ -12,7 +12,7 @@ class CTouchDevice : public ITouch {
private: private:
CTouchDevice(SP<Aquamarine::ITouch> touch); CTouchDevice(SP<Aquamarine::ITouch> touch);
WP<Aquamarine::ITouch> m_touch; WP<Aquamarine::ITouch> touch;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
@@ -21,5 +21,5 @@ class CTouchDevice : public ITouch {
CHyprSignalListener motion; CHyprSignalListener motion;
CHyprSignalListener cancel; CHyprSignalListener cancel;
CHyprSignalListener frame; CHyprSignalListener frame;
} m_listeners; } listeners;
}; };

View File

@@ -5,43 +5,43 @@
SP<CVirtualKeyboard> CVirtualKeyboard::create(SP<CVirtualKeyboardV1Resource> keeb) { SP<CVirtualKeyboard> CVirtualKeyboard::create(SP<CVirtualKeyboardV1Resource> keeb) {
SP<CVirtualKeyboard> pKeeb = SP<CVirtualKeyboard>(new CVirtualKeyboard(keeb)); SP<CVirtualKeyboard> pKeeb = SP<CVirtualKeyboard>(new CVirtualKeyboard(keeb));
pKeeb->m_self = pKeeb; pKeeb->self = pKeeb;
return pKeeb; return pKeeb;
} }
CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : m_keyboard(keeb_) { CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : keyboard(keeb_) {
if (!keeb_) if (!keeb_)
return; return;
m_listeners.destroy = keeb_->m_events.destroy.registerListener([this](std::any d) { listeners.destroy = keeb_->events.destroy.registerListener([this](std::any d) {
m_keyboard.reset(); keyboard.reset();
m_events.destroy.emit(); events.destroy.emit();
}); });
m_listeners.key = keeb_->m_events.key.registerListener([this](std::any d) { m_keyboardEvents.key.emit(d); }); listeners.key = keeb_->events.key.registerListener([this](std::any d) { keyboardEvents.key.emit(d); });
m_listeners.modifiers = keeb_->m_events.modifiers.registerListener([this](std::any d) { listeners.modifiers = keeb_->events.modifiers.registerListener([this](std::any d) {
auto E = std::any_cast<SModifiersEvent>(d); auto E = std::any_cast<SModifiersEvent>(d);
updateModifiers(E.depressed, E.latched, E.locked, E.group); updateModifiers(E.depressed, E.latched, E.locked, E.group);
m_keyboardEvents.modifiers.emit(SModifiersEvent{ keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = m_modifiersState.depressed, .depressed = modifiersState.depressed,
.latched = m_modifiersState.latched, .latched = modifiersState.latched,
.locked = m_modifiersState.locked, .locked = modifiersState.locked,
.group = m_modifiersState.group, .group = modifiersState.group,
}); });
}); });
m_listeners.keymap = keeb_->m_events.keymap.registerListener([this](std::any d) { listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) {
auto E = std::any_cast<SKeymapEvent>(d); auto E = std::any_cast<SKeymapEvent>(d);
if (m_xkbKeymap) if (xkbKeymap)
xkb_keymap_unref(m_xkbKeymap); xkb_keymap_unref(xkbKeymap);
m_xkbKeymap = xkb_keymap_ref(E.keymap); xkbKeymap = xkb_keymap_ref(E.keymap);
m_keymapOverridden = true; keymapOverridden = true;
updateXKBTranslationState(m_xkbKeymap); updateXKBTranslationState(xkbKeymap);
updateKeymapFD(); updateKeymapFD();
m_keyboardEvents.keymap.emit(d); keyboardEvents.keymap.emit(d);
}); });
m_deviceName = keeb_->m_name; deviceName = keeb_->name;
} }
bool CVirtualKeyboard::isVirtual() { bool CVirtualKeyboard::isVirtual() {
@@ -53,7 +53,7 @@ SP<Aquamarine::IKeyboard> CVirtualKeyboard::aq() {
} }
wl_client* CVirtualKeyboard::getClient() { wl_client* CVirtualKeyboard::getClient() {
if (m_keyboard.expired()) if (keyboard.expired())
return nullptr; return nullptr;
return m_keyboard->client(); return keyboard->client();
} }

View File

@@ -16,12 +16,12 @@ class CVirtualKeyboard : public IKeyboard {
private: private:
CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb); CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb);
WP<CVirtualKeyboardV1Resource> m_keyboard; WP<CVirtualKeyboardV1Resource> keyboard;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
CHyprSignalListener key; CHyprSignalListener key;
CHyprSignalListener modifiers; CHyprSignalListener modifiers;
CHyprSignalListener keymap; CHyprSignalListener keymap;
} m_listeners; } listeners;
}; };

View File

@@ -5,46 +5,42 @@
SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resource) { SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resource) {
SP<CVirtualPointer> pPointer = SP<CVirtualPointer>(new CVirtualPointer(resource)); SP<CVirtualPointer> pPointer = SP<CVirtualPointer>(new CVirtualPointer(resource));
pPointer->m_self = pPointer; pPointer->self = pPointer;
return pPointer; return pPointer;
} }
CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : m_pointer(resource) { CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : pointer(resource) {
if UNLIKELY (!resource->good()) if UNLIKELY (!resource->good())
return; return;
m_listeners.destroy = m_pointer->m_events.destroy.registerListener([this](std::any d) { listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) {
m_pointer.reset(); pointer.reset();
m_events.destroy.emit(); events.destroy.emit();
}); });
m_listeners.motion = m_pointer->m_events.move.registerListener([this](std::any d) { listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
auto E = std::any_cast<SMotionEvent>(d); listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) {
E.device = m_self.lock();
m_pointerEvents.motion.emit(E);
});
m_listeners.motionAbsolute = m_pointer->m_events.warp.registerListener([this](std::any d) {
// we need to unpack the event and add our device here because it's required to calculate the position correctly // we need to unpack the event and add our device here because it's required to calculate the position correctly
auto E = std::any_cast<SMotionAbsoluteEvent>(d); auto E = std::any_cast<SMotionAbsoluteEvent>(d);
E.device = m_self.lock(); E.device = self.lock();
m_pointerEvents.motionAbsolute.emit(E); pointerEvents.motionAbsolute.emit(E);
}); });
m_listeners.button = m_pointer->m_events.button.registerListener([this](std::any d) { m_pointerEvents.button.emit(d); }); listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); });
m_listeners.axis = m_pointer->m_events.axis.registerListener([this](std::any d) { m_pointerEvents.axis.emit(d); }); listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); });
m_listeners.frame = m_pointer->m_events.frame.registerListener([this](std::any d) { m_pointerEvents.frame.emit(); }); listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
m_listeners.swipeBegin = m_pointer->m_events.swipeBegin.registerListener([this](std::any d) { m_pointerEvents.swipeBegin.emit(d); }); listeners.swipeBegin = pointer->events.swipeBegin.registerListener([this](std::any d) { pointerEvents.swipeBegin.emit(d); });
m_listeners.swipeEnd = m_pointer->m_events.swipeEnd.registerListener([this](std::any d) { m_pointerEvents.swipeEnd.emit(d); }); listeners.swipeEnd = pointer->events.swipeEnd.registerListener([this](std::any d) { pointerEvents.swipeEnd.emit(d); });
m_listeners.swipeUpdate = m_pointer->m_events.swipeUpdate.registerListener([this](std::any d) { m_pointerEvents.swipeUpdate.emit(d); }); listeners.swipeUpdate = pointer->events.swipeUpdate.registerListener([this](std::any d) { pointerEvents.swipeUpdate.emit(d); });
m_listeners.pinchBegin = m_pointer->m_events.pinchBegin.registerListener([this](std::any d) { m_pointerEvents.pinchBegin.emit(d); }); listeners.pinchBegin = pointer->events.pinchBegin.registerListener([this](std::any d) { pointerEvents.pinchBegin.emit(d); });
m_listeners.pinchEnd = m_pointer->m_events.pinchEnd.registerListener([this](std::any d) { m_pointerEvents.pinchEnd.emit(d); }); listeners.pinchEnd = pointer->events.pinchEnd.registerListener([this](std::any d) { pointerEvents.pinchEnd.emit(d); });
m_listeners.pinchUpdate = m_pointer->m_events.pinchUpdate.registerListener([this](std::any d) { m_pointerEvents.pinchUpdate.emit(d); }); listeners.pinchUpdate = pointer->events.pinchUpdate.registerListener([this](std::any d) { pointerEvents.pinchUpdate.emit(d); });
m_listeners.holdBegin = m_pointer->m_events.holdBegin.registerListener([this](std::any d) { m_pointerEvents.holdBegin.emit(d); }); listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); });
m_listeners.holdEnd = m_pointer->m_events.holdEnd.registerListener([this](std::any d) { m_pointerEvents.holdEnd.emit(d); }); listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); });
m_boundOutput = resource->m_boundOutput ? resource->m_boundOutput->m_name : ""; boundOutput = resource->boundOutput ? resource->boundOutput->szName : "";
m_deviceName = m_pointer->m_name; deviceName = pointer->name;
} }
bool CVirtualPointer::isVirtual() { bool CVirtualPointer::isVirtual() {

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