Compare commits

..

6 Commits

Author SHA1 Message Date
Vaxry
85917a40b0 more 2024-08-24 20:58:21 +02:00
Vaxry
d3e26652d6 better 2024-08-24 20:54:05 +02:00
Vaxry
276652b44e fix pure fade 2024-08-24 20:53:27 +02:00
Vaxry
746f804568 oops 2024-08-24 20:42:16 +02:00
Vaxry
00319c01d4 def 0% 2024-08-24 20:31:14 +02:00
Vaxry
b509273759 implement ws scaling 2024-08-24 20:29:31 +02:00
313 changed files with 6663 additions and 11752 deletions

View File

@@ -1,101 +0,0 @@
WarningsAsErrors: '*'
HeaderFilterRegex: '.*\.hpp'
FormatStyle: file
Checks: >
-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
-bugprone-forward-declararion-namespace,
-bugprone-forward-declararion-namespace,
-bugprone-macro-parentheses,
-bugprone-narrowing-conversions,
-bugprone-branch-clone,
-bugprone-assignment-in-if-condition,
concurrency-*,
-concurrency-mt-unsafe,
cppcoreguidelines-*,
-cppcoreguidelines-owning-memory,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-avoid-const-or-ref-data-members,
-cppcoreguidelines-non-private-member-variables-in-classes,
-cppcoreguidelines-avoid-goto,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-special-member-functions,
-cppcoreguidelines-explicit-virtual-functions,
-cppcoreguidelines-avoid-c-arrays,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-narrowing-conversions,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-member-init,
-cppcoreguidelines-macro-usage,
-cppcoreguidelines-macro-to-enum,
-cppcoreguidelines-init-variables,
-cppcoreguidelines-pro-type-cstyle-cast,
-cppcoreguidelines-pro-type-vararg,
-cppcoreguidelines-pro-type-reinterpret-cast,
google-global-names-in-headers,
-google-readability-casting,
google-runtime-operator,
misc-*,
-misc-unused-parameters,
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
-misc-include-cleaner,
-misc-use-anonymous-namespace,
-misc-const-correctness,
modernize-*,
-modernize-return-braced-init-list,
-modernize-use-trailing-return-type,
-modernize-use-using,
-modernize-use-override,
-modernize-avoid-c-arrays,
-modernize-macro-to-enum,
-modernize-loop-convert,
-modernize-use-nodiscard,
-modernize-pass-by-value,
-modernize-use-auto,
performance-*,
-performance-avoid-endl,
-performance-unnecessary-value-param,
portability-std-allocator-const,
readability-*,
-readability-function-cognitive-complexity,
-readability-function-size,
-readability-identifier-length,
-readability-magic-numbers,
-readability-uppercase-literal-suffix,
-readability-braces-around-statements,
-readability-redundant-access-specifiers,
-readability-else-after-return,
-readability-container-data-pointer,
-readability-implicit-bool-conversion,
-readability-avoid-nested-conditional-operator,
-readability-redundant-member-init,
-readability-redundant-string-init,
-readability-avoid-const-params-in-decls,
-readability-named-parameter,
-readability-convert-member-functions-to-static,
-readability-qualified-auto,
-readability-make-member-function-const,
-readability-isolate-declaration,
-readability-inconsistent-declaration-parameter-name,
-clang-diagnostic-error,
CheckOptions:
performance-for-range-copy.WarnOnAllAutoCopies: true
performance-inefficient-string-concatenation.StrictMode: true
readability-braces-around-statements.ShortStatementLines: 0
readability-identifier-naming.ClassCase: CamelCase
readability-identifier-naming.ClassIgnoredRegexp: I.*
readability-identifier-naming.ClassPrefix: C # We can't use regex here?!?!?!?
readability-identifier-naming.EnumCase: CamelCase
readability-identifier-naming.EnumPrefix: e
readability-identifier-naming.EnumConstantCase: UPPER_CASE
readability-identifier-naming.FunctionCase: camelBack
readability-identifier-naming.NamespaceCase: CamelCase
readability-identifier-naming.NamespacePrefix: N
readability-identifier-naming.StructPrefix: S
readability-identifier-naming.StructCase: CamelCase

View File

@@ -2,13 +2,12 @@ name: Bug Report
description: Something is not working right description: Something is not working right
labels: ["bug"] labels: ["bug"]
body: body:
- type: checkboxes - type: markdown
attributes: attributes:
label: Already reported ? * value: |
description: Before opening a new bug report, please take a moment to search through the current open and closed issues to check if it already exists. ## Before opening a new issue, please take a moment to search through the current open and closed issues to check if it already exists.
options:
- label: I have searched the existing open and closed issues. ---
required: true
- type: dropdown - type: dropdown
id: type id: type
@@ -29,10 +28,10 @@ body:
attributes: attributes:
label: System Info and Version label: System Info and Version
description: | description: |
Paste the output of `hyprctl systeminfo -c` here. If you can't Paste the output of `hyprctl systeminfo -c` here (If you are on a
launch Hyprland, paste the output of `Hyprland --systeminfo`. version that shows you help menu, omit the `-c` and attach config files
If `Hyprland --systeminfo` errors out (added in 0.44.0), find to the issue). If you have configs outside of the main config shown
and paste the Hyprland version manually. here, please attach.
value: "<details> value: "<details>
<summary>System/Version info</summary> <summary>System/Version info</summary>

View File

@@ -33,9 +33,7 @@ runs:
libfontenc \ libfontenc \
libglvnd \ libglvnd \
libinput \ libinput \
libjxl \
libliftoff \ libliftoff \
libwebp \
libxcursor \ libxcursor \
libxcvt \ libxcvt \
libxfont2 \ libxfont2 \
@@ -60,8 +58,7 @@ runs:
xcb-util \ xcb-util \
xcb-util-image \ xcb-util-image \
libzip \ libzip \
librsvg \ librsvg
re2
- name: Get hyprwayland-scanner-git - name: Get hyprwayland-scanner-git
shell: bash shell: bash
@@ -72,11 +69,6 @@ runs:
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
cmake --install build cmake --install build
- name: Get hyprgraphics-git
shell: bash
run: |
git clone https://github.com/hyprwm/hyprgraphics && cd hyprgraphics && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprgraphics && cmake --install build
- name: Get hyprutils-git - name: Get hyprutils-git
shell: bash shell: bash
run: | run: |

View File

@@ -1,9 +1,3 @@
<!--
BEFORE you submit your PR, please check out the PR guidelines
on our wiki: https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/
-->
#### Describe your PR, what does it fix/add? #### Describe your PR, what does it fix/add?

View File

@@ -39,7 +39,7 @@ jobs:
tar -cvf Hyprland.tar.xz hyprland tar -cvf Hyprland.tar.xz hyprland
- name: Release - name: Release
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: Build archive name: Build archive
path: Hyprland.tar.xz path: Hyprland.tar.xz

View File

@@ -17,14 +17,14 @@ jobs:
run: sudo apt install pandoc run: sudo apt install pandoc
- name: Clone repository - name: Clone repository
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
token: ${{ secrets.PAT }} token: ${{ secrets.PAT }}
- name: Build man pages - name: Build man pages
run: make man run: make man
- uses: stefanzweifel/git-auto-commit-action@v5 - uses: stefanzweifel/git-auto-commit-action@v4
name: Commit name: Commit
with: with:
commit_message: "[gha] build man pages" commit_message: "[gha] build man pages"

View File

@@ -1,5 +1,3 @@
name: Nix (Build)
on: on:
workflow_call: workflow_call:
secrets: secrets:
@@ -12,18 +10,21 @@ jobs:
matrix: matrix:
package: package:
- hyprland - hyprland
# - hyprland-cross # cross compiling fails due to qt
# failure chain: hyprland-qtutils -> qt6.qtsvg -> qt6.qtbase -> psqlodbc & qt6.qttranslations
- xdg-desktop-portal-hyprland - xdg-desktop-portal-hyprland
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: DeterminateSystems/nix-installer-action@main - name: Clone repository
- uses: DeterminateSystems/magic-nix-cache-action@main uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
submodules: recursive
- uses: cachix/install-nix-action@v27
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v15 - uses: cachix/cachix-action@v15
with: with:
name: hyprland name: hyprland
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- run: nix build 'github:hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" - run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"

View File

@@ -1,14 +1,15 @@
name: Nix (CI) name: Nix
on: [push, pull_request, workflow_dispatch] on: [push, pull_request, workflow_dispatch]
jobs: jobs:
update-inputs: update-inputs:
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/nix-update-inputs.yml uses: ./.github/workflows/nix-update-inputs.yml
secrets: inherit secrets: inherit
build: build:
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) && !contains(needs.*.result, 'failure')
needs: update-inputs
uses: ./.github/workflows/nix-build.yml uses: ./.github/workflows/nix-build.yml
secrets: inherit secrets: inherit

View File

@@ -1,4 +1,4 @@
name: Nix (Update Inputs) name: Nix
on: on:
workflow_call: workflow_call:
@@ -8,12 +8,11 @@ on:
jobs: jobs:
update: update:
if: github.repository == 'hyprwm/Hyprland'
name: inputs name: inputs
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clone repository - name: Clone repository
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
token: ${{ secrets.PAT }} token: ${{ secrets.PAT }}
@@ -22,6 +21,6 @@ jobs:
run: nix/update-inputs.sh run: nix/update-inputs.sh
- name: Commit - name: Commit
uses: stefanzweifel/git-auto-commit-action@v5 uses: stefanzweifel/git-auto-commit-action@v4
with: with:
commit_message: "[gha] Nix: update inputs" commit_message: "[gha] Nix: update inputs"

View File

@@ -11,7 +11,7 @@ jobs:
steps: steps:
- name: Checkout Hyprland - name: Checkout Hyprland
id: checkout id: checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
@@ -20,6 +20,7 @@ jobs:
run: | run: |
git fetch --unshallow || echo "failed unshallowing" git fetch --unshallow || echo "failed unshallowing"
bash -c scripts/generateVersion.sh bash -c scripts/generateVersion.sh
mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
- name: Create tarball with submodules - name: Create tarball with submodules
id: tar id: tar

View File

@@ -13,7 +13,7 @@ jobs:
security-events: write security-events: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Scan with Flawfinder - name: Scan with Flawfinder
uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c

View File

@@ -7,22 +7,22 @@ name: Mark stale issues and pull requests
on: on:
schedule: schedule:
- cron: "7 */4 * * *" - cron: '7 */4 * * *'
workflow_dispatch: workflow_dispatch:
jobs: jobs:
stale: stale:
if: github.repository == 'hyprwm/Hyprland'
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
issues: write issues: write
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v5
with: with:
repo-token: ${{ secrets.STALEBOT_PAT }} repo-token: ${{ secrets.STALEBOT_PAT }}
stale-issue-label: "stale" stale-issue-label: 'stale'
stale-pr-label: "stale" stale-pr-label: 'stale'
operations-per-run: 40 operations-per-run: 40
days-before-close: -1 days-before-close: -1

4
.gitignore vendored
View File

@@ -14,7 +14,6 @@ _deps
build/ build/
result* result*
/.pre-commit-config.yaml
/.vscode/ /.vscode/
/.idea/ /.idea/
.envrc .envrc
@@ -40,6 +39,3 @@ PKGBUILD
src/version.h src/version.h
hyprpm/Makefile hyprpm/Makefile
hyprctl/Makefile hyprctl/Makefile
**/.#*.*
**/#*.*#

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.30) cmake_minimum_required(VERSION 3.27)
# Get version # Get version
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
@@ -15,7 +15,6 @@ include(GNUInstallDirs)
set(HYPRLAND_VERSION ${VER}) set(HYPRLAND_VERSION ${VER})
set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(PREFIX ${CMAKE_INSTALL_PREFIX})
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
set(BINDIR ${CMAKE_INSTALL_BINDIR})
configure_file(hyprland.pc.in hyprland.pc @ONLY) configure_file(hyprland.pc.in hyprland.pc @ONLY)
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
@@ -26,18 +25,8 @@ message(STATUS "Gathering git info")
execute_process(COMMAND ./scripts/generateVersion.sh execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
find_package(PkgConfig REQUIRED) # udis
add_subdirectory("subprojects/udis86")
# Try to find canihavesomecoffee's udis86 using pkgconfig vmd/udis86 does not
# provide a .pc file and won't be detected this way
pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2)
# Fallback to subproject
if(NOT udis_dep_FOUND)
add_subdirectory("subprojects/udis86")
include_directories("subprojects/udis86")
message(STATUS "udis86 dependency not found, falling back to subproject")
endif()
if(CMAKE_BUILD_TYPE) if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
@@ -58,6 +47,8 @@ else()
set(BUILDTYPE_LOWER "release") set(BUILDTYPE_LOWER "release")
endif() endif()
find_package(PkgConfig REQUIRED)
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
@@ -72,10 +63,7 @@ else()
message(STATUS "Configuring Hyprland in Release with CMake") message(STATUS "Configuring Hyprland in Release with CMake")
endif() endif()
add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}") include_directories(. "src/" "subprojects/udis86/" "protocols/")
include_directories(. "src/" "protocols/")
set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD 26)
add_compile_options( add_compile_options(
-Wall -Wall
@@ -101,25 +89,18 @@ 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.4.5) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1)
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2)
pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7)
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.2.3)
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}")
add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}")
add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}")
add_compile_definitions(HYPRGRAPHICS_VERSION="${hyprgraphics_dep_VERSION}")
pkg_check_modules( pkg_check_modules(
deps deps
REQUIRED REQUIRED
IMPORTED_TARGET IMPORTED_TARGET
aquamarine
xkbcommon xkbcommon
uuid uuid
wayland-server>=1.22.90 wayland-server
wayland-client
wayland-cursor
wayland-protocols wayland-protocols
cairo cairo
pango pango
@@ -128,9 +109,16 @@ pkg_check_modules(
xcursor xcursor
libdrm libdrm
libinput libinput
hwdata
libseat
libdisplay-info
libliftoff
libudev
gbm gbm
gio-2.0 gio-2.0
re2) hyprlang>=0.3.2
hyprcursor>=0.1.7
hyprutils>=0.2.1)
find_package(hyprwayland-scanner 0.3.10 REQUIRED) find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -212,11 +200,14 @@ else()
REQUIRED REQUIRED
IMPORTED_TARGET IMPORTED_TARGET
xcb xcb
xwayland
xcb-util
xcb-render xcb-render
xcb-xfixes xcb-xfixes
xcb-icccm xcb-icccm
xcb-composite xcb-composite
xcb-res xcb-res
xcb-ewmh
xcb-errors) xcb-errors)
target_link_libraries(Hyprland PkgConfig::xdeps) target_link_libraries(Hyprland PkgConfig::xdeps)
endif() endif()
@@ -226,15 +217,6 @@ if(NO_SYSTEMD)
else() else()
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
add_compile_definitions(USES_SYSTEMD) add_compile_definitions(USES_SYSTEMD)
# session file -uwsm
if(NO_UWSM)
message(STATUS "UWSM support is disabled...")
else()
message(STATUS "UWSM support is enabled (NO_UWSM not defined)...")
install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
endif()
endif() endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})
@@ -248,19 +230,14 @@ target_precompile_headers(Hyprland PRIVATE
message(STATUS "Setting link libraries") message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::hyprgraphics_dep PkgConfig::deps) target_link_libraries(Hyprland rt PkgConfig::deps)
if(udis_dep_FOUND)
target_link_libraries(Hyprland PkgConfig::udis_dep)
else()
target_link_libraries(Hyprland libudis86)
endif()
# used by `make installheaders`, to ensure the headers are generated # used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers) add_custom_target(generate-protocol-headers)
function(protocolnew protoPath protoName external) function(protocolnew protoPath protoName external)
if(external) if(external)
set(path ${protoPath}) set(path ${CMAKE_SOURCE_DIR}/${protoPath})
else() else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif() endif()
@@ -288,22 +265,14 @@ function(protocolWayland)
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
endfunction() endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads
libudis86 uuid)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.4.0) protocolnew("subprojects/hyprland-protocols/protocols"
if(hyprland_protocols_dep_FOUND) "hyprland-global-shortcuts-v1" true)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
else()
set(HYPRLAND_PROTOCOLS "subprojects/hyprland-protocols")
message(STATUS "hyprland-protocols subproject set to ${HYPRLAND_PROTOCOLS}")
endif()
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1"
true)
protocolnew("unstable/text-input" "text-input-unstable-v1" false) protocolnew("unstable/text-input" "text-input-unstable-v1" false)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1" protocolnew("subprojects/hyprland-protocols/protocols"
true) "hyprland-toplevel-export-v1" true)
protocolnew("protocols" "wlr-screencopy-unstable-v1" true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) protocolnew("protocols" "wlr-gamma-control-unstable-v1" true)
protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
@@ -314,11 +283,10 @@ protocolnew("protocols" "input-method-unstable-v2" true)
protocolnew("protocols" "wlr-output-management-unstable-v1" true) protocolnew("protocols" "wlr-output-management-unstable-v1" true)
protocolnew("protocols" "kde-server-decoration" true) protocolnew("protocols" "kde-server-decoration" true)
protocolnew("protocols" "wlr-data-control-unstable-v1" true) protocolnew("protocols" "wlr-data-control-unstable-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1"
true)
protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
protocolnew("protocols" "wayland-drm" true) protocolnew("protocols" "wayland-drm" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-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)
protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false) protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false)
@@ -347,9 +315,6 @@ protocolnew("stable/viewporter" "viewporter" false)
protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false) protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
protocolnew("staging/drm-lease" "drm-lease-v1" false) protocolnew("staging/drm-lease" "drm-lease-v1" false)
protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
protocolnew("staging/security-context" "security-context-v1" false)
protocolwayland() protocolwayland()
@@ -371,14 +336,12 @@ install(
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
# allow Hyprland to find assets # allow Hyprland to find wallpapers
add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}") add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}")
# installable assets # wallpapers
file(GLOB_RECURSE INSTALLABLE_ASSETS "assets/install/*") file(GLOB_RECURSE WALLPAPERS "assets/wall*")
list(FILTER INSTALLABLE_ASSETS EXCLUDE REGEX "meson.build") install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
install(FILES ${INSTALLABLE_ASSETS}
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
# default config # default config
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf

View File

@@ -1,27 +1,28 @@
PREFIX = /usr/local PREFIX = /usr/local
stub:
@echo "Do not run $(MAKE) directly without any arguments. Please refer to the wiki on how to compile Hyprland."
legacyrenderer: legacyrenderer:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all
chmod -R 777 ./build
legacyrendererdebug: legacyrendererdebug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all
chmod -R 777 ./build
release: release:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all
chmod -R 777 ./build
debug: debug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Debug --target all
chmod -R 777 ./build
nopch: nopch:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all
clear: clear:
rm -rf build rm -rf build

View File

@@ -100,7 +100,7 @@ easy IPC, much more QoL stuff than other compositors and more...
<!-----------------------------------------------------------------------------> <!----------------------------------------------------------------------------->
[Configure]: https://wiki.hyprland.org/Configuring/ [Configure]: https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
[Stars]: https://starchart.cc/hyprwm/Hyprland [Stars]: https://starchart.cc/hyprwm/Hyprland
[Hypr]: https://github.com/hyprwm/Hypr [Hypr]: https://github.com/hyprwm/Hypr

View File

@@ -1 +1 @@
0.46.2 0.42.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -1,10 +0,0 @@
globber = run_command('sh', '-c', 'find . -type f -not -name "*.build"', check: true)
files = globber.stdout().strip().split('\n')
foreach file : files
install_data(
file,
install_dir: join_paths(get_option('datadir'), 'hypr'),
install_tag: 'runtime',
)
endforeach

View File

@@ -1,7 +1,7 @@
install_data( wallpapers = ['0', '1', '2']
'hyprland-portals.conf',
install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'),
install_tag: 'runtime',
)
subdir('install') foreach type : wallpapers
install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime')
endforeach
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')

View File

Before

Width:  |  Height:  |  Size: 14 MiB

After

Width:  |  Height:  |  Size: 14 MiB

View File

Before

Width:  |  Height:  |  Size: 5.9 MiB

After

Width:  |  Height:  |  Size: 5.9 MiB

View File

Before

Width:  |  Height:  |  Size: 27 MiB

After

Width:  |  Height:  |  Size: 27 MiB

View File

@@ -10,8 +10,8 @@ Hyprland - Dynamic tiling Wayland compositor
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]]. \f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
.SH DESCRIPTION .SH DESCRIPTION
.PP .PP
\f[B]Hyprland\f[R] is an independent, highly customizable, dynamic \f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on
tiling Wayland compositor that doesn\[aq]t sacrifice on its looks. wlroots that doesn\[aq]t sacrifice on its looks.
.PP .PP
You can launch Hyprland by either going into a TTY and executing You can launch Hyprland by either going into a TTY and executing
\f[B]Hyprland\f[R], or with a login manager. \f[B]Hyprland\f[R], or with a login manager.

View File

@@ -14,8 +14,8 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
=========== ===========
**Hyprland** is an independent, highly customizable, **Hyprland** is a dynamic tiling Wayland compositor based on
dynamic tiling Wayland compositor that doesn't sacrifice on its looks. wlroots that doesn't sacrifice on its looks.
You can launch Hyprland by either going into a TTY and You can launch Hyprland by either going into a TTY and
executing **Hyprland**, or with a login manager. executing **Hyprland**, or with a login manager.

View File

@@ -3,7 +3,7 @@
First of all, please remember to: First of all, please remember to:
- Check that your issue is not a duplicate - Check that your issue is not a duplicate
- Read the [FAQ](https://wiki.hyprland.org/FAQ/) - Read the [FAQ](https://wiki.hyprland.org/FAQ/)
- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/) - Read the [Configuring Page](https://wiki.hyprland.org/Configuring/Configuring-Hyprland)
<br/> <br/>

View File

@@ -1,2 +1,2 @@
install_man('Hyprland.1') install_man ('Hyprland.1')
install_man('hyprctl.1') install_man ('hyprctl.1')

View File

@@ -0,0 +1,14 @@
[Unit]
Description=Hyprland - Tiling compositor with the looks
Documentation=man:Hyprland(1)
BindsTo=graphical-session.target
Before=graphical-session.target
Wants=graphical-session-pre.target
After=graphical-session-pre.target
[Service]
Type=notify
ExecStart=/usr/bin/Hyprland
ExecStop=/usr/bin/hyprctl dispatch exit
Restart=on-failure
Slice=session.slice

View File

@@ -1,6 +1,5 @@
[Desktop Entry] [Desktop Entry]
Name=Hyprland (uwsm-managed) Name=Hyprland
Comment=An intelligent dynamic tiling Wayland compositor Comment=An intelligent dynamic tiling Wayland compositor
Exec=uwsm start -- hyprland.desktop Exec=systemctl --user start --wait hyprland-session
DesktopNames=Hyprland
Type=Application Type=Application

View File

@@ -1,6 +1,6 @@
# This is an example Hyprland config file. # This is an example Hyprland config file.
# Refer to the wiki for more information. # Refer to the wiki for more information.
# https://wiki.hyprland.org/Configuring/ # https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
# Please note not all available settings / options are set here. # Please note not all available settings / options are set here.
# For a full list, see the wiki # For a full list, see the wiki
@@ -59,7 +59,7 @@ env = HYPRCURSOR_SIZE,24
# Refer to https://wiki.hyprland.org/Configuring/Variables/ # Refer to https://wiki.hyprland.org/Configuring/Variables/
# https://wiki.hyprland.org/Configuring/Variables/#general # https://wiki.hyprland.org/Configuring/Variables/#general
general { general {
gaps_in = 5 gaps_in = 5
gaps_out = 20 gaps_out = 20
@@ -70,7 +70,7 @@ general {
col.inactive_border = rgba(595959aa) col.inactive_border = rgba(595959aa)
# Set to true enable resizing windows by clicking and dragging on borders and gaps # Set to true enable resizing windows by clicking and dragging on borders and gaps
resize_on_border = false resize_on_border = false
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = false allow_tearing = false
@@ -86,63 +86,37 @@ decoration {
active_opacity = 1.0 active_opacity = 1.0
inactive_opacity = 1.0 inactive_opacity = 1.0
shadow { drop_shadow = true
enabled = true shadow_range = 4
range = 4 shadow_render_power = 3
render_power = 3 col.shadow = rgba(1a1a1aee)
color = rgba(1a1a1aee)
}
# https://wiki.hyprland.org/Configuring/Variables/#blur # https://wiki.hyprland.org/Configuring/Variables/#blur
blur { blur {
enabled = true enabled = true
size = 3 size = 3
passes = 1 passes = 1
vibrancy = 0.1696 vibrancy = 0.1696
} }
} }
# https://wiki.hyprland.org/Configuring/Variables/#animations # https://wiki.hyprland.org/Configuring/Variables/#animations
animations { animations {
enabled = yes, please :) enabled = true
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = easeOutQuint,0.23,1,0.32,1 bezier = myBezier, 0.05, 0.9, 0.1, 1.05
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = global, 1, 10, default animation = windows, 1, 7, myBezier
animation = border, 1, 5.39, easeOutQuint animation = windowsOut, 1, 7, default, popin 80%
animation = windows, 1, 4.79, easeOutQuint animation = border, 1, 10, default
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% animation = borderangle, 1, 8, default
animation = windowsOut, 1, 1.49, linear, popin 87% animation = fade, 1, 7, default
animation = fadeIn, 1, 1.73, almostLinear animation = workspaces, 1, 6, default
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, fade
animation = workspacesIn, 1, 1.21, almostLinear, fade
animation = workspacesOut, 1, 1.94, almostLinear, fade
} }
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
@@ -155,7 +129,7 @@ master {
} }
# https://wiki.hyprland.org/Configuring/Variables/#misc # https://wiki.hyprland.org/Configuring/Variables/#misc
misc { misc {
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
} }
@@ -254,19 +228,6 @@ bind = $mainMod, mouse_up, workspace, e-1
bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next
bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous
############################## ##############################
### WINDOWS AND WORKSPACES ### ### WINDOWS AND WORKSPACES ###
@@ -281,8 +242,4 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# Example windowrule v2 # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0

View File

@@ -2,6 +2,4 @@
Name=Hyprland Name=Hyprland
Comment=An intelligent dynamic tiling Wayland compositor Comment=An intelligent dynamic tiling Wayland compositor
Exec=Hyprland Exec=Hyprland
Type=Application Type=Application
DesktopNames=Hyprland
Keywords=tiling;wayland;compositor;

View File

@@ -1,10 +1,2 @@
install_data( install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime')
'hyprland.conf', install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime')
install_dir: join_paths(get_option('datadir'), 'hypr'),
install_tag: 'runtime',
)
install_data(
'hyprland.desktop',
install_dir: join_paths(get_option('datadir'), 'wayland-sessions'),
install_tag: 'runtime',
)

192
flake.lock generated
View File

@@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734364797, "lastModified": 1724273991,
"narHash": "sha256-2h1c+P0v3l0Z/ypUSsAPhU/yiSRgFwjVFODWp0S3d/w=", "narHash": "sha256-+aUSOXKGpS5CRm1oTitgNAr05ThQNbKIXalZHl3nC6Y=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "8e77618b403a82fde2105a8e3cd7cabe7ef00952", "rev": "9a3161ad4c78dc420d1cbb3aae638222608c7de4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -29,43 +29,6 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"hyprcursor": { "hyprcursor": {
"inputs": { "inputs": {
"hyprlang": [ "hyprlang": [
@@ -79,11 +42,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734364709, "lastModified": 1722623071,
"narHash": "sha256-+2bZJL2u5hva7rSp65OfKJBK+k03T6GB/NCvpoS1OOo=", "narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "f388aacd22be4a6e4d634fbaf6f75eb0713d239a", "rev": "912d56025f03d41b1ad29510c423757b4379eb1c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -92,47 +55,23 @@
"type": "github" "type": "github"
} }
}, },
"hyprgraphics": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1733684019,
"narHash": "sha256-2kYREgmSmbLsmDpLEq96hxVAU3qz8aCvVhF65yCFZHY=",
"owner": "hyprwm",
"repo": "hyprgraphics",
"rev": "fb2c0268645a77403af3b8a4ce8fa7ba5917f15d",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprgraphics",
"type": "github"
}
},
"hyprland-protocols": { "hyprland-protocols": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"xdph",
"nixpkgs" "nixpkgs"
], ],
"systems": [ "systems": [
"xdph",
"systems" "systems"
] ]
}, },
"locked": { "locked": {
"lastModified": 1728345020, "lastModified": 1721326555,
"narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=", "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "a7c183800e74f337753de186522b9017a07a8cee", "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -141,32 +80,6 @@
"type": "github" "type": "github"
} }
}, },
"hyprland-qtutils": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1733940128,
"narHash": "sha256-hmfXWj2GA9cj1QUkPFYtAAeohhs615zL4E3APy3FnvQ=",
"owner": "hyprwm",
"repo": "hyprland-qtutils",
"rev": "3833097e50473a152dd614d4b468886840b4ea78",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-qtutils",
"type": "github"
}
},
"hyprlang": { "hyprlang": {
"inputs": { "inputs": {
"hyprutils": [ "hyprutils": [
@@ -180,11 +93,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734364628, "lastModified": 1724174162,
"narHash": "sha256-ii8fzJfI953n/EmIxVvq64ZAwhvwuuPHWfGd61/mJG8=", "narHash": "sha256-fOOBLwil6M9QWMCiSULwjMQzrXhHXUnEqmjHX5ZHeVI=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "16e59c1eb13d9fb6de066f54e7555eb5e8a4aba5", "rev": "16e5c9465f04477d8a3dd48a0a26bf437986336c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -203,11 +116,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1733502241, "lastModified": 1722869141,
"narHash": "sha256-KAUNC4Dgq8WQjYov5auBw/usaHixhacvb7cRDd0AG/k=", "narHash": "sha256-0KU4qhyMp441qfwbirNg3+wbm489KnEjXOz2I/RbeFs=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "104117aed6dd68561be38b50f218190aa47f2cd8", "rev": "0252fd13e78e60fb0da512a212e56007515a49f7",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -226,11 +139,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726874836, "lastModified": 1721324119,
"narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=", "narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "500c81a9e1a76760371049a8d99e008ea77aa59e", "rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -241,11 +154,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1734119587, "lastModified": 1724224976,
"narHash": "sha256-AKU6qqskl0yf2+JdRdD0cfxX4b9x3KKV5RqA6wijmPM=", "narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "3566ab7246670a43abd2ffa913cc62dad9cdf7d5", "rev": "c374d94f1536013ca8e92341b540eba4c22f9c62",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -255,57 +168,14 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-stable": {
"locked": {
"lastModified": 1730741070,
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1734279981,
"narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"aquamarine": "aquamarine", "aquamarine": "aquamarine",
"hyprcursor": "hyprcursor", "hyprcursor": "hyprcursor",
"hyprgraphics": "hyprgraphics",
"hyprland-protocols": "hyprland-protocols",
"hyprland-qtutils": "hyprland-qtutils",
"hyprlang": "hyprlang", "hyprlang": "hyprlang",
"hyprutils": "hyprutils", "hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner", "hyprwayland-scanner": "hyprwayland-scanner",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks",
"systems": "systems", "systems": "systems",
"xdph": "xdph" "xdph": "xdph"
} }
@@ -327,18 +197,10 @@
}, },
"xdph": { "xdph": {
"inputs": { "inputs": {
"hyprland-protocols": [ "hyprland-protocols": "hyprland-protocols",
"hyprland-protocols"
],
"hyprlang": [ "hyprlang": [
"hyprlang" "hyprlang"
], ],
"hyprutils": [
"hyprutils"
],
"hyprwayland-scanner": [
"hyprwayland-scanner"
],
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
@@ -347,11 +209,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734124279, "lastModified": 1724073926,
"narHash": "sha256-YNpFfiQjYt2o6LGcMN9NkjVvprC8ELrIpLHlbZbclRM=", "narHash": "sha256-nWlUL43jOFHf+KW6Hqrx+W/r1XdXuDyb0wC/SrHsOu4=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "0c6861f819f6d31f6195c9864709b2556f00b5cf", "rev": "a08ecbbf33598924e93542f737fc6169a26b481e",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -22,26 +22,6 @@
inputs.hyprlang.follows = "hyprlang"; inputs.hyprlang.follows = "hyprlang";
}; };
hyprgraphics = {
url = "github:hyprwm/hyprgraphics";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
};
hyprland-protocols = {
url = "github:hyprwm/hyprland-protocols";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
hyprland-qtutils = {
url = "github:hyprwm/hyprland-qtutils";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
};
hyprlang = { hyprlang = {
url = "github:hyprwm/hyprlang"; url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@@ -65,15 +45,7 @@
url = "github:hyprwm/xdg-desktop-portal-hyprland"; url = "github:hyprwm/xdg-desktop-portal-hyprland";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
inputs.hyprland-protocols.follows = "hyprland-protocols";
inputs.hyprlang.follows = "hyprlang"; inputs.hyprlang.follows = "hyprlang";
inputs.hyprutils.follows = "hyprutils";
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
};
pre-commit-hooks = {
url = "github:cachix/git-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
}; };
}; };
@@ -93,15 +65,6 @@
hyprland-extras hyprland-extras
]; ];
}); });
pkgsCrossFor = eachSystem (system: crossSystem:
import nixpkgs {
localSystem = system;
inherit crossSystem;
overlays = with self.overlays; [
hyprland-packages
hyprland-extras
];
});
in { in {
overlays = import ./nix/overlays.nix {inherit self lib inputs;}; overlays = import ./nix/overlays.nix {inherit self lib inputs;};
@@ -111,18 +74,6 @@
self.packages.${system}) self.packages.${system})
// { // {
inherit (self.packages.${system}) xdg-desktop-portal-hyprland; inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run {
src = ./.;
hooks = {
hyprland-treewide-formatter = {
enable = true;
entry = "${self.formatter.${system}}/bin/hyprland-treewide-formatter";
pass_filenames = false;
excludes = ["subprojects"];
always_run = true;
};
};
};
}); });
packages = eachSystem (system: { packages = eachSystem (system: {
@@ -130,30 +81,34 @@
inherit inherit
(pkgsFor.${system}) (pkgsFor.${system})
# hyprland-packages # hyprland-packages
hyprland hyprland
hyprland-debug hyprland-debug
hyprland-legacy-renderer hyprland-legacy-renderer
hyprland-unwrapped hyprland-unwrapped
# hyprland-extras # hyprland-extras
xdg-desktop-portal-hyprland xdg-desktop-portal-hyprland
; ;
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
}); });
devShells = eachSystem (system: { devShells = eachSystem (system: {
default = default =
pkgsFor.${system}.mkShell.override { pkgsFor.${system}.mkShell.override {
inherit (self.packages.${system}.default) stdenv; stdenv = pkgsFor.${system}.gcc14Stdenv;
} { } {
name = "hyprland-shell"; name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [
expat
libxml2
];
hardeningDisable = ["fortify"]; hardeningDisable = ["fortify"];
inputsFrom = [pkgsFor.${system}.hyprland]; inputsFrom = [pkgsFor.${system}.hyprland];
packages = [pkgsFor.${system}.clang-tools]; packages = [pkgsFor.${system}.clang-tools];
inherit (self.checks.${system}.pre-commit-check) shellHook;
}; };
}); });
formatter = eachSystem (system: pkgsFor.${system}.callPackage ./nix/formatter.nix {}); formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
nixosModules.default = import ./nix/module.nix inputs; nixosModules.default = import ./nix/module.nix inputs;
homeManagerModules.default = import ./nix/hm-module.nix self; homeManagerModules.default = import ./nix/hm-module.nix self;

View File

@@ -5,7 +5,7 @@ project(
DESCRIPTION "Control utility for Hyprland" DESCRIPTION "Control utility for Hyprland"
) )
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.4 re2) pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1)
add_executable(hyprctl "main.cpp") add_executable(hyprctl "main.cpp")

View File

@@ -1,7 +1,5 @@
#pragma once #pragma once
#include <string_view>
const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help] const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help]
commands: commands:

View File

@@ -1,5 +1,3 @@
#include <re2/re2.h>
#include <cctype> #include <cctype>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
@@ -19,12 +17,13 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <print>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <deque>
#include <filesystem> #include <filesystem>
#include <cstdarg> #include <cstdarg>
#include <regex>
#include <sys/socket.h> #include <sys/socket.h>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <cstring> #include <cstring>
@@ -45,24 +44,18 @@ struct SInstanceData {
bool valid = true; bool valid = true;
}; };
void log(const std::string& str) { void log(std::string str) {
if (quiet) if (quiet)
return; return;
std::println("{}", str); std::cout << str << "\n";
}
static int getUID() {
const auto UID = getuid();
const auto PWUID = getpwuid(UID);
return PWUID ? PWUID->pw_uid : UID;
} }
std::string getRuntimeDir() { std::string getRuntimeDir() {
const auto XDG = getenv("XDG_RUNTIME_DIR"); const auto XDG = getenv("XDG_RUNTIME_DIR");
if (!XDG) { if (!XDG) {
const std::string USERID = std::to_string(getUID()); const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
return "/run/user/" + USERID + "/hypr"; return "/run/user/" + USERID + "/hypr";
} }
@@ -72,11 +65,6 @@ std::string getRuntimeDir() {
std::vector<SInstanceData> instances() { std::vector<SInstanceData> instances() {
std::vector<SInstanceData> result; std::vector<SInstanceData> result;
try {
if (!std::filesystem::exists(getRuntimeDir()))
return {};
} catch (std::exception& e) { return {}; }
for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) { for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) {
if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock")) if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock"))
continue; continue;
@@ -117,7 +105,7 @@ std::vector<SInstanceData> instances() {
static volatile bool sigintReceived = false; static volatile bool sigintReceived = false;
void intHandler(int sig) { void intHandler(int sig) {
sigintReceived = true; sigintReceived = true;
std::println("[hyprctl] SIGINT received, closing connection"); std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl;
} }
int rollingRead(const int socket) { int rollingRead(const int socket) {
@@ -127,12 +115,12 @@ int rollingRead(const int socket) {
constexpr size_t BUFFER_SIZE = 8192; constexpr size_t BUFFER_SIZE = 8192;
std::array<char, BUFFER_SIZE> buffer = {0}; std::array<char, BUFFER_SIZE> buffer = {0};
long sizeWritten = 0; long sizeWritten = 0;
std::println("[hyprctl] reading from socket following up log:"); std::cout << "[hyprctl] reading from socket following up log:" << std::endl;
while (!sigintReceived) { while (!sigintReceived) {
sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
if (sizeWritten < 0 && errno != EAGAIN) { if (sizeWritten < 0 && errno != EAGAIN) {
if (errno != EINTR) if (errno != EINTR)
std::println("Couldn't read (5): {}: {}", strerror(errno), errno); std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl;
close(socket); close(socket);
return 5; return 5;
} }
@@ -141,7 +129,7 @@ int rollingRead(const int socket) {
break; break;
if (sizeWritten > 0) { if (sizeWritten > 0) {
std::println("{}", std::string(buffer.data(), sizeWritten)); std::cout << std::string(buffer.data(), sizeWritten);
buffer.fill('\0'); buffer.fill('\0');
} }
@@ -174,7 +162,7 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
return 2; return 2;
} }
const std::string USERID = std::to_string(getUID()); const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
sockaddr_un serverAddress = {0}; sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX; serverAddress.sun_family = AF_UNIX;
@@ -244,7 +232,7 @@ int requestHyprpaper(std::string arg) {
sockaddr_un serverAddress = {0}; sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX; serverAddress.sun_family = AF_UNIX;
const std::string USERID = std::to_string(getUID()); const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock"; std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock";
@@ -282,11 +270,10 @@ int requestHyprpaper(std::string arg) {
} }
void batchRequest(std::string arg, bool json) { void batchRequest(std::string arg, bool json) {
std::string commands = arg.substr(arg.find_first_of(' ') + 1); std::string commands = arg.substr(arg.find_first_of(" ") + 1);
if (json) { if (json) {
RE2::GlobalReplace(&commands, ";\\s*", ";j/"); commands = "j/" + std::regex_replace(commands, std::regex(";\\s*"), ";j/");
commands.insert(0, "j/");
} }
std::string rq = "[[BATCH]]" + commands; std::string rq = "[[BATCH]]" + commands;
@@ -300,12 +287,12 @@ void instancesRequest(bool json) {
std::vector<SInstanceData> inst = instances(); std::vector<SInstanceData> inst = instances();
if (!json) { if (!json) {
for (auto const& el : inst) { for (auto& el : inst) {
result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket); result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket);
} }
} else { } else {
result += '['; result += '[';
for (auto const& el : inst) { for (auto& el : inst) {
result += std::format(R"#( result += std::format(R"#(
{{ {{
"instance": "{}", "instance": "{}",
@@ -323,11 +310,11 @@ void instancesRequest(bool json) {
log(result + "\n"); log(result + "\n");
} }
std::vector<std::string> splitArgs(int argc, char** argv) { std::deque<std::string> splitArgs(int argc, char** argv) {
std::vector<std::string> result; std::deque<std::string> result;
for (auto i = 1 /* skip the executable */; i < argc; ++i) for (auto i = 1 /* skip the executable */; i < argc; ++i)
result.emplace_back(argv[i]); result.push_back(std::string(argv[i]));
return result; return result;
} }
@@ -336,7 +323,7 @@ int main(int argc, char** argv) {
bool parseArgs = true; bool parseArgs = true;
if (argc < 2) { if (argc < 2) {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -373,7 +360,7 @@ int main(int argc, char** argv) {
++i; ++i;
if (i >= ARGS.size()) { if (i >= ARGS.size()) {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -384,24 +371,24 @@ int main(int argc, char** argv) {
const std::string& cmd = ARGS[0]; const std::string& cmd = ARGS[0];
if (cmd == "hyprpaper") { if (cmd == "hyprpaper") {
std::println("{}", HYPRPAPER_HELP); std::cout << HYPRPAPER_HELP << std::endl;
} else if (cmd == "notify") { } else if (cmd == "notify") {
std::println("{}", NOTIFY_HELP); std::cout << NOTIFY_HELP << std::endl;
} else if (cmd == "output") { } else if (cmd == "output") {
std::println("{}", OUTPUT_HELP); std::cout << OUTPUT_HELP << std::endl;
} else if (cmd == "plugin") { } else if (cmd == "plugin") {
std::println("{}", PLUGIN_HELP); std::cout << PLUGIN_HELP << std::endl;
} else if (cmd == "setprop") { } else if (cmd == "setprop") {
std::println("{}", SETPROP_HELP); std::cout << SETPROP_HELP << std::endl;
} else if (cmd == "switchxkblayout") { } else if (cmd == "switchxkblayout") {
std::println("{}", SWITCHXKBLAYOUT_HELP); std::cout << SWITCHXKBLAYOUT_HELP << std::endl;
} else { } else {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
} }
return 1; return 1;
} else { } else {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -412,7 +399,7 @@ int main(int argc, char** argv) {
} }
if (fullRequest.empty()) { if (fullRequest.empty()) {
std::println("{}", USAGE); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -489,7 +476,7 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/decorations")) else if (fullRequest.contains("/decorations"))
exitStatus = request(fullRequest, 1); exitStatus = request(fullRequest, 1);
else if (fullRequest.contains("/--help")) else if (fullRequest.contains("/--help"))
std::println("{}", USAGE); std::cout << USAGE << std::endl;
else if (fullRequest.contains("/rollinglog") && needRoll) else if (fullRequest.contains("/rollinglog") && needRoll)
exitStatus = request(fullRequest, 0, true); exitStatus = request(fullRequest, 0, true);
else { else {

View File

@@ -1,27 +1,10 @@
executable( executable('hyprctl', 'main.cpp',
'hyprctl',
'main.cpp',
dependencies: [ dependencies: [
dependency('hyprutils', version: '>= 0.1.1'), dependency('hyprutils', version: '>= 0.1.1'),
dependency('re2', required: true)
], ],
install: true, install: true
) )
install_data( install_data('hyprctl.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprctl')
'hyprctl.bash', install_data('hyprctl.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime')
install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_data('hyprctl.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprctl')
install_tag: 'runtime',
rename: 'hyprctl',
)
install_data(
'hyprctl.fish',
install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'),
install_tag: 'runtime',
)
install_data(
'hyprctl.zsh',
install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'),
install_tag: 'runtime',
rename: '_hyprctl',
)

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.2.4) pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1)
add_executable(hyprpm ${SRCFILES}) add_executable(hyprpm ${SRCFILES})
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps) target_link_libraries(hyprpm PUBLIC PkgConfig::deps)
# binary # binary
install(TARGETS hyprpm) install(TARGETS hyprpm)

View File

@@ -1,6 +1,6 @@
#include "DataState.hpp" #include "DataState.hpp"
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <print> #include <iostream>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include "PluginManager.hpp" #include "PluginManager.hpp"
@@ -8,7 +8,7 @@
std::string DataState::getDataStatePath() { std::string DataState::getDataStatePath() {
const auto HOME = getenv("HOME"); const auto HOME = getenv("HOME");
if (!HOME) { if (!HOME) {
std::println(stderr, "DataState: no $HOME"); std::cerr << "DataState: no $HOME\n";
throw std::runtime_error("no $HOME"); throw std::runtime_error("no $HOME");
return ""; return "";
} }
@@ -49,7 +49,7 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
{"rev", repo.rev} {"rev", repo.rev}
}} }}
}; };
for (auto const& p : repo.plugins) { for (auto& p : repo.plugins) {
// copy .so to the good place // copy .so to the good place
if (std::filesystem::exists(p.filename)) if (std::filesystem::exists(p.filename))
std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so"); std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so");
@@ -242,4 +242,4 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
} }
return false; return false;
} }

View File

@@ -6,7 +6,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
auto manifest = toml::parse_file(path); auto manifest = toml::parse_file(path);
if (type == MANIFEST_HYPRLOAD) { if (type == MANIFEST_HYPRLOAD) {
for (auto const& [key, val] : manifest) { for (auto& [key, val] : manifest) {
if (key.str().ends_with(".build")) if (key.str().ends_with(".build"))
continue; continue;
@@ -63,7 +63,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
} }
} }
for (auto const& [key, val] : manifest) { for (auto& [key, val] : manifest) {
if (key.str() == "repository") if (key.str() == "repository")
continue; continue;

View File

@@ -1,15 +1,12 @@
#include "PluginManager.hpp" #include "PluginManager.hpp"
#include "../helpers/Colors.hpp" #include "../helpers/Colors.hpp"
#include "../helpers/StringUtils.hpp"
#include "../progress/CProgressBar.hpp" #include "../progress/CProgressBar.hpp"
#include "Manifest.hpp" #include "Manifest.hpp"
#include "DataState.hpp" #include "DataState.hpp"
#include <cstdio>
#include <iostream> #include <iostream>
#include <array> #include <array>
#include <filesystem> #include <filesystem>
#include <print>
#include <thread> #include <thread>
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
@@ -23,56 +20,37 @@
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <hyprutils/os/Process.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::OS;
static std::string execAndGet(std::string cmd) { static std::string execAndGet(std::string cmd) {
cmd += " 2>&1"; cmd += " 2>&1";
std::array<char, 128> buffer;
std::string result;
using PcloseType = int (*)(FILE*);
const std::unique_ptr<FILE, PcloseType> pipe(popen(cmd.c_str(), "r"), static_cast<PcloseType>(pclose));
if (!pipe)
return "";
CProcess proc("/bin/sh", {"-c", cmd}); while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
if (!proc.runSync())
return "error";
return proc.stdOut();
}
static std::string getTempRoot() {
static auto ENV = getenv("XDG_RUNTIME_DIR");
if (!ENV) {
std::cerr << "\nERROR: XDG_RUNTIME_DIR not set!\n";
exit(1);
} }
return result;
const auto STR = ENV + std::string{"/hyprpm/"};
return STR;
} }
SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) { SHyprlandVersion CPluginManager::getHyprlandVersion() {
static bool onceRunning = false; static SHyprlandVersion ver;
static bool onceInstalled = false; static bool once = false;
static SHyprlandVersion verRunning;
static SHyprlandVersion verInstalled;
if (onceRunning && running) if (once)
return verRunning; return ver;
if (onceInstalled && !running) once = true;
return verInstalled; const auto HLVERCALL = execAndGet("hyprctl version");
if (running)
onceRunning = true;
else
onceInstalled = true;
const auto HLVERCALL = running ? execAndGet("hyprctl version") : execAndGet("Hyprland --version");
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("{} version returned: {}", running ? "running" : "installed", HLVERCALL)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "version returned: " << HLVERCALL << "\n";
if (!HLVERCALL.contains("Tag:")) { if (!HLVERCALL.contains("Tag:")) {
std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland.")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " You don't seem to be running Hyprland.";
return SHyprlandVersion{}; return SHyprlandVersion{};
} }
@@ -98,20 +76,14 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
} catch (...) { ; } } catch (...) { ; }
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << " on " << hldate << ", commits " << commits << "\n";
auto ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
if (running)
verRunning = ver;
else
verInstalled = ver;
ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
return ver; return ver;
} }
bool CPluginManager::createSafeDirectory(const std::string& path) { bool CPluginManager::createSafeDirectory(const std::string& path) {
if (path.empty() || !path.starts_with(getTempRoot())) if (path.empty() || !path.starts_with("/tmp"))
return false; return false;
if (std::filesystem::exists(path)) if (std::filesystem::exists(path))
@@ -130,21 +102,20 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) { if (!hasDeps()) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
return false; return false;
} }
if (DataState::pluginRepoExists(url)) { if (DataState::pluginRepoExists(url)) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Repository already installed.")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
return false; return false;
} }
auto GLOBALSTATE = DataState::getGlobalState(); auto GLOBALSTATE = DataState::getGlobalState();
if (!GLOBALSTATE.dontWarnInstall) { if (!GLOBALSTATE.dontWarnInstall) {
std::println("{}!{} Disclaimer: {}", Colors::YELLOW, Colors::RED, Colors::RESET); std::cout << Colors::YELLOW << "!" << Colors::RED << " Disclaimer:\n " << Colors::RESET
std::println("plugins, especially not official, have no guarantee of stability, availablity or security.\n" << "plugins, especially not official, have no guarantee of stability, availablity or security.\n Run them at your own risk.\n "
"Run them at your own risk.\n" << "This message will not appear again.\n";
"This message will not appear again.");
GLOBALSTATE.dontWarnInstall = true; GLOBALSTATE.dontWarnInstall = true;
DataState::updateGlobalState(GLOBALSTATE); DataState::updateGlobalState(GLOBALSTATE);
} }
@@ -158,7 +129,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::getline(std::cin, input); std::getline(std::cin, input);
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
std::println(stderr, "Aborting."); std::cout << "Aborting.\n";
return false; return false;
} }
@@ -169,73 +140,73 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.print(); progress.print();
if (!std::filesystem::exists(getTempRoot())) { if (!std::filesystem::exists("/tmp/hyprpm")) {
std::filesystem::create_directory(getTempRoot()); std::filesystem::create_directory("/tmp/hyprpm");
std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace); std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
} else if (!std::filesystem::is_directory(getTempRoot())) { } else if (!std::filesystem::is_directory("/tmp/hyprpm")) {
std::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for hyprpm\n";
return false; return false;
} }
const std::string USERNAME = getpwuid(getuid())->pw_name; const std::string USERNAME = getpwuid(getuid())->pw_name;
m_szWorkingPluginDirectory = getTempRoot() + USERNAME; m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
if (!createSafeDirectory(m_szWorkingPluginDirectory)) { if (!createSafeDirectory(m_szWorkingPluginDirectory)) {
std::println(stderr, "\n{}", failureString("Could not prepare working dir for repo")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for repo\n";
return false; return false;
} }
progress.printMessageAbove(infoString("Cloning {}", url)); progress.printMessageAbove(std::string{Colors::RESET} + "Cloning " + url);
std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), url, USERNAME)); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME);
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret)); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. shell returned:\n" << ret << "\n";
return false; return false;
} }
if (!rev.empty()) { if (!rev.empty()) {
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev); std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev);
if (ret.compare(0, 6, "fatal:") == 0) { if (ret.compare(0, 6, "fatal:") == 0) {
std::println(stderr, "\n{}", failureString("Could not check out revision {}. shell returned:\n{}", rev, ret)); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n";
return false; return false;
} }
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("git submodule update --init returned: {}", ret)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
} }
progress.m_iSteps = 1; progress.m_iSteps = 1;
progress.printMessageAbove(successString("cloned")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " cloned");
progress.m_szCurrentMessage = "Reading the manifest"; progress.m_szCurrentMessage = "Reading the manifest";
progress.print(); progress.print();
std::unique_ptr<CManifest> pManifest; std::unique_ptr<CManifest> pManifest;
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
progress.printMessageAbove(successString("found hyprpm manifest")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprpm manifest");
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
progress.printMessageAbove(successString("found hyprload manifest")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprload manifest");
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
} }
if (!pManifest) { if (!pManifest) {
std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
return false; return false;
} }
if (!pManifest->m_bGood) { if (!pManifest->m_bGood) {
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
return false; return false;
} }
progress.m_iSteps = 2; progress.m_iSteps = 2;
progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:");
for (auto const& pl : pManifest->m_vPlugins) { for (auto& pl : pManifest->m_vPlugins) {
std::string message = "" + pl.name + " by "; std::string message = std::string{Colors::RESET} + " " + pl.name + " by ";
for (auto const& a : pl.authors) { for (auto& a : pl.authors) {
message += a + ", "; message += a + ", ";
} }
if (pl.authors.size() > 0) { if (pl.authors.size() > 0) {
@@ -249,19 +220,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
if (!pManifest->m_sRepository.commitPins.empty()) { if (!pManifest->m_sRepository.commitPins.empty()) {
// check commit pins // check commit pins
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); progress.printMessageAbove(std::string{Colors::RESET} + "Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("git submodule update --init returned: {}", ret)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
break; break;
} }
@@ -273,12 +244,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HEADERSSTATUS = headersValid(); const auto HEADERSSTATUS = headersValid();
if (HEADERSSTATUS != HEADERS_OK) { if (HEADERSSTATUS != HEADERS_OK) {
std::println("\n{}", headerError(HEADERSSTATUS)); std::cerr << "\n" << headerError(HEADERSSTATUS);
return false; return false;
} }
progress.m_iSteps = 3; progress.m_iSteps = 3;
progress.printMessageAbove(successString("Hyprland headers OK")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " Hyprland headers OK");
progress.m_szCurrentMessage = "Building plugin(s)"; progress.m_szCurrentMessage = "Building plugin(s)";
progress.print(); progress.print();
@@ -286,36 +257,35 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
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. */) {
progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name)); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(infoString("Building {}", p.name)); progress.printMessageAbove(std::string{Colors::RESET} + "Building " + p.name);
for (auto const& bs : p.buildSteps) { for (auto& bs : p.buildSteps) {
const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("shell returned: {}", out)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
progress.printMessageAbove(failureString("Plugin {} failed to build.\n" progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Plugin " + p.name + " failed to build.\n" +
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update "
" If you are on -git, update first\n" "first.\n Try re-running with -v to see "
" Try re-running with -v to see more verbose output.\n", "more verbose output.\n");
p.name));
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(successString("built {} into {}", p.name, p.output)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output);
} }
progress.printMessageAbove(successString("all plugins built")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " all plugins built");
progress.m_iSteps = 4; progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing repository"; progress.m_szCurrentMessage = "Installing repository";
progress.print(); progress.print();
@@ -329,18 +299,18 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
repo.url = url; repo.url = url;
repo.rev = rev; repo.rev = rev;
repo.hash = repohash; repo.hash = repohash;
for (auto const& p : pManifest->m_vPlugins) { for (auto& 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);
progress.printMessageAbove(successString("installed repository")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " installed repository");
progress.printMessageAbove(successString("you can now enable the plugin(s) with hyprpm enable")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " you can now enable the plugin(s) with hyprpm enable");
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
std::print("\n"); std::cout << "\n";
// remove build files // remove build files
std::filesystem::remove_all(m_szWorkingPluginDirectory); std::filesystem::remove_all(m_szWorkingPluginDirectory);
@@ -350,7 +320,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
bool CPluginManager::removePluginRepo(const std::string& urlOrName) { bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
if (!DataState::pluginRepoExists(urlOrName)) { if (!DataState::pluginRepoExists(urlOrName)) {
std::println(stderr, "\n{}", failureString("Could not remove the repository. Repository is not installed.")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not remove the repository. Repository is not installed.\n";
return false; return false;
} }
@@ -361,7 +331,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
std::getline(std::cin, input); std::getline(std::cin, input);
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
std::println("Aborting."); std::cout << "Aborting.\n";
return false; return false;
} }
@@ -371,21 +341,21 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
} }
eHeadersErrors CPluginManager::headersValid() { eHeadersErrors CPluginManager::headersValid() {
const auto HLVER = getHyprlandVersion(false); const auto HLVER = getHyprlandVersion();
if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc")) if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc"))
return HEADERS_MISSING; return HEADERS_MISSING;
// find headers commit // find headers commit
const std::string& cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath()); std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
auto headers = execAndGet(cmd.c_str()); auto headers = execAndGet(cmd.c_str());
if (!headers.contains("-I/")) if (!headers.contains("-I/"))
return HEADERS_MISSING; return HEADERS_MISSING;
headers.pop_back(); // pop newline headers.pop_back(); // pop newline
std::string verHeader; std::string verHeader = "";
while (!headers.empty()) { while (!headers.empty()) {
const auto PATH = headers.substr(0, headers.find(" -I/", 3)); const auto PATH = headers.substr(0, headers.find(" -I/", 3));
@@ -433,20 +403,20 @@ bool CPluginManager::updateHeaders(bool force) {
DataState::ensureStateStoreExists(); DataState::ensureStateStoreExists();
const auto HLVER = getHyprlandVersion(false); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) { if (!hasDeps()) {
std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
return false; return false;
} }
if (!std::filesystem::exists(getTempRoot())) { if (!std::filesystem::exists("/tmp/hyprpm")) {
std::filesystem::create_directory(getTempRoot()); std::filesystem::create_directory("/tmp/hyprpm");
std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace); std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
} }
if (!force && headersValid() == HEADERS_OK) { if (!force && headersValid() == HEADERS_OK) {
std::println("\n{}", successString("Headers up to date.")); std::cout << "\n" << std::string{Colors::GREEN} + "" + Colors::RESET + " Headers up to date.\n";
return true; return true;
} }
@@ -457,76 +427,77 @@ bool CPluginManager::updateHeaders(bool force) {
progress.print(); progress.print();
const std::string USERNAME = getpwuid(getuid())->pw_name; const std::string USERNAME = getpwuid(getuid())->pw_name;
const auto WORKINGDIR = getTempRoot() + "hyprland-" + USERNAME; const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME;
if (!createSafeDirectory(WORKINGDIR)) { if (!createSafeDirectory(WORKINGDIR)) {
std::println("\n{}", failureString("Could not prepare working dir for hl")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for hl\n";
return false; return false;
} }
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment.")); progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment.");
const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow; const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow;
// let us give a bit of leg-room for shallowing // let us give a bit of leg-room for shallowing
// due to timezones, etc. // due to timezones, etc.
const std::string SHALLOW_DATE = trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+%a %b %d %H:%M:%S %Y'"); const std::string SHALLOW_DATE =
trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'");
if (m_bVerbose && bShallow) if (m_bVerbose && bShallow)
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE);
std::string ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-{}{}", getTempRoot(), USERNAME, std::string ret =
(bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""))); execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""));
if (!std::filesystem::exists(WORKINGDIR)) { if (!std::filesystem::exists(WORKINGDIR)) {
progress.printMessageAbove(failureString("Clone failed. Retrying without shallow.")); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Clone failed. Retrying without shallow.");
ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/hyprland hyprland-{}", getTempRoot(), USERNAME)); ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME);
} }
if (!std::filesystem::exists(WORKINGDIR + "/.git")) { if (!std::filesystem::exists(WORKINGDIR + "/.git")) {
std::println(stderr, "\n{}", failureString("Could not clone the Hyprland repository. shell returned:\n{}", ret)); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n";
return false; return false;
} }
progress.printMessageAbove(successString("Hyprland cloned")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " cloned");
progress.m_iSteps = 2; progress.m_iSteps = 2;
progress.m_szCurrentMessage = "Checking out sources"; progress.m_szCurrentMessage = "Checking out sources";
progress.print(); progress.print();
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("will run: cd {} && git checkout {} 2>&1", WORKINGDIR, HLVER.hash)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
if (ret.contains("fatal: unable to read tree")) { if (ret.contains("fatal: unable to read tree")) {
std::println(stderr, "\n{}", std::cerr << "\n"
failureString("Could not checkout the running Hyprland commit. If you are on -git, try updating.\n" << Colors::RED << "" << Colors::RESET
"You can also try re-running hyprpm update with --no-shallow.")); << " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n";
return false; return false;
} }
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("git returned (co): {}", ret)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret);
ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash); ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("git returned (rs): {}", ret)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret);
progress.printMessageAbove(successString("checked out to running ver")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " checked out to running ver");
progress.m_iSteps = 3; progress.m_iSteps = 3;
progress.m_szCurrentMessage = "Building Hyprland"; progress.m_szCurrentMessage = "Building Hyprland";
progress.print(); progress.print();
progress.printMessageAbove(statusString("!", Colors::YELLOW, "configuring Hyprland")); progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland");
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("setting PREFIX for cmake to {}", DataState::getHeadersPath())); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath());
ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR, ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR,
DataState::getHeadersPath())); DataState::getHeadersPath()));
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("cmake returned: {}", ret)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
if (ret.contains("CMake Error at")) { if (ret.contains("CMake Error at")) {
// missing deps, let the user know. // missing deps, let the user know.
@@ -535,46 +506,48 @@ bool CPluginManager::updateHeaders(bool force) {
missing = missing.substr(0, missing.find("-- Configuring incomplete")); missing = missing.substr(0, missing.find("-- Configuring incomplete"));
missing = missing.substr(0, missing.find_last_of('\n')); missing = missing.substr(0, missing.find_last_of('\n'));
std::println(stderr, "\n{}", std::cerr << "\n"
failureString("Could not configure the hyprland source, cmake complained:\n{}\n\n" << Colors::RED << "" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n"
"This likely means that you are missing the above dependencies or they are out of date.", << missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n";
missing));
return false; return false;
} }
progress.printMessageAbove(successString("configured Hyprland")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland");
progress.m_iSteps = 4; progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";
progress.print(); progress.print();
const std::string& cmd = std::string cmd =
std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR); 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("installation will run: {}", cmd)); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd);
ret = execAndGet(cmd); ret = execAndGet(cmd);
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("installer returned: {}", ret)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n";
// remove build files // remove build files
std::filesystem::remove_all(WORKINGDIR); std::filesystem::remove_all(WORKINGDIR);
auto HEADERSVALID = headersValid(); auto HEADERSVALID = headersValid();
if (HEADERSVALID == HEADERS_OK) { if (HEADERSVALID == HEADERS_OK) {
progress.printMessageAbove(successString("installed headers")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " installed headers");
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
std::print("\n"); std::cout << "\n";
} else { } else {
progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID))); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" +
headerErrorShort(HEADERSVALID) + ")");
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Failed"; progress.m_szCurrentMessage = "Failed";
progress.print(); progress.print();
std::print(stderr, "\n\n{}", headerError(HEADERSVALID)); std::cout << "\n";
std::cerr << "\n" << headerError(HEADERSVALID);
return false; return false;
} }
@@ -584,18 +557,18 @@ bool CPluginManager::updateHeaders(bool force) {
bool CPluginManager::updatePlugins(bool forceUpdateAll) { bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (headersValid() != HEADERS_OK) { if (headersValid() != HEADERS_OK) {
std::println("{}", failureString("headers are not up-to-date, please run hyprpm update.")); std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
return false; return false;
} }
const auto REPOS = DataState::getAllRepositories(); const auto REPOS = DataState::getAllRepositories();
if (REPOS.size() < 1) { if (REPOS.size() < 1) {
std::println("{}", failureString("No repos to update.")); std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " No repos to update.\n";
return true; return true;
} }
const auto HLVER = getHyprlandVersion(false); const auto HLVER = getHyprlandVersion();
CProgressBar progress; CProgressBar progress;
progress.m_iMaxSteps = REPOS.size() * 2 + 2; progress.m_iMaxSteps = REPOS.size() * 2 + 2;
@@ -604,35 +577,34 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.print(); progress.print();
const std::string USERNAME = getpwuid(getuid())->pw_name; const std::string USERNAME = getpwuid(getuid())->pw_name;
m_szWorkingPluginDirectory = getTempRoot() + USERNAME; m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
for (auto const& repo : REPOS) { for (auto& repo : REPOS) {
bool update = forceUpdateAll; bool update = forceUpdateAll;
progress.m_iSteps++; progress.m_iSteps++;
progress.m_szCurrentMessage = "Updating " + repo.name; progress.m_szCurrentMessage = "Updating " + repo.name;
progress.print(); progress.print();
progress.printMessageAbove(infoString("checking for updates for {}", repo.name)); progress.printMessageAbove(std::string{Colors::RESET} + "checking for updates for " + repo.name);
createSafeDirectory(m_szWorkingPluginDirectory); createSafeDirectory(m_szWorkingPluginDirectory);
progress.printMessageAbove(infoString("Cloning {}", repo.url)); progress.printMessageAbove(std::string{Colors::RESET} + "Cloning " + repo.url);
std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), repo.url, USERNAME)); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME);
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::println("{}", failureString("could not clone repo: shell returned: {}", ret)); std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not clone repo: shell returned:\n" + ret;
return false; return false;
} }
if (!repo.rev.empty()) { if (!repo.rev.empty()) {
progress.printMessageAbove(infoString("Plugin has revision set, resetting: {}", repo.rev)); progress.printMessageAbove(std::string{Colors::RESET} + "Plugin has revision set, resetting: " + repo.rev);
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev); std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev);
if (ret.compare(0, 6, "fatal:") == 0) { if (ret.compare(0, 6, "fatal:") == 0) {
std::println(stderr, "\n{}", failureString("could not check out revision {}: shell returned:\n{}", repo.rev, ret)); std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret;
return false; return false;
} }
} }
@@ -648,7 +620,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (!update) { if (!update) {
std::filesystem::remove_all(m_szWorkingPluginDirectory); std::filesystem::remove_all(m_szWorkingPluginDirectory);
progress.printMessageAbove(successString("repository {} is up-to-date.", repo.name)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " repository " + repo.name + " is up-to-date.");
progress.m_iSteps++; progress.m_iSteps++;
progress.print(); progress.print();
continue; continue;
@@ -656,41 +628,41 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
// we need to update // we need to update
progress.printMessageAbove(successString("repository {} has updates.", repo.name)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " repository " + repo.name + " has updates.");
progress.printMessageAbove(infoString("Building {}", repo.name)); progress.printMessageAbove(std::string{Colors::RESET} + "Building " + repo.name);
progress.m_iSteps++; progress.m_iSteps++;
progress.print(); progress.print();
std::unique_ptr<CManifest> pManifest; std::unique_ptr<CManifest> pManifest;
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
progress.printMessageAbove(successString("found hyprpm manifest")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprpm manifest");
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
progress.printMessageAbove(successString("found hyprload manifest")); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprload manifest");
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
} }
if (!pManifest) { if (!pManifest) {
std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
continue; continue;
} }
if (!pManifest->m_bGood) { if (!pManifest->m_bGood) {
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
continue; continue;
} }
if (repo.rev.empty() && !pManifest->m_sRepository.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_sRepository.commitPins.size())); progress.printMessageAbove(std::string{Colors::RESET} + "Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
} }
@@ -700,33 +672,32 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
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. */) {
progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name)); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(infoString("Building {}", p.name)); progress.printMessageAbove(std::string{Colors::RESET} + "Building " + p.name);
for (auto const& bs : p.buildSteps) { for (auto& bs : p.buildSteps) {
const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("shell returned: {}", out)); std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
std::println(stderr, std::cerr << "\n"
"\n{}\n" << Colors::RED << "" << Colors::RESET << " Plugin " << p.name << " failed to build.\n"
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" << " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update first.\n Try "
"If you are on -git, update first.\n" "re-running with -v to see more verbose "
"Try re-running with -v to see more verbose output.", "output.\n";
failureString("Plugin {} failed to build.", p.name));
p.failed = true; p.failed = true;
continue; continue;
} }
progress.printMessageAbove(successString("built {} into {}", p.name, p.output)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output);
} }
// add repo toml to DataState // add repo toml to DataState
@@ -738,7 +709,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_vPlugins) { for (auto& 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});
} }
@@ -747,7 +718,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
std::filesystem::remove_all(m_szWorkingPluginDirectory); std::filesystem::remove_all(m_szWorkingPluginDirectory);
progress.printMessageAbove(successString("updated {}", repo.name)); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " updated " + repo.name);
} }
progress.m_iSteps++; progress.m_iSteps++;
@@ -762,7 +733,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
std::print("\n"); std::cout << "\n";
return true; return true;
} }
@@ -770,27 +741,27 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
bool CPluginManager::enablePlugin(const std::string& name) { bool CPluginManager::enablePlugin(const std::string& name) {
bool ret = DataState::setPluginEnabled(name, true); bool ret = DataState::setPluginEnabled(name, true);
if (ret) if (ret)
std::println("{}", successString("Enabled {}", name)); std::cout << Colors::GREEN << "" << Colors::RESET << " Enabled " << name << "\n";
return ret; return ret;
} }
bool CPluginManager::disablePlugin(const std::string& name) { bool CPluginManager::disablePlugin(const std::string& name) {
bool ret = DataState::setPluginEnabled(name, false); bool ret = DataState::setPluginEnabled(name, false);
if (ret) if (ret)
std::println("{}", successString("Disabled {}", name)); std::cout << Colors::GREEN << "" << Colors::RESET << " Disabled " << name << "\n";
return ret; return ret;
} }
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (headersValid() != HEADERS_OK) { if (headersValid() != HEADERS_OK) {
std::println(stderr, "\n{}", failureString("headers are not up-to-date, please run hyprpm update.")); std::cerr << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
return LOADSTATE_HEADERS_OUTDATED; return LOADSTATE_HEADERS_OUTDATED;
} }
const auto HOME = getenv("HOME"); const auto HOME = getenv("HOME");
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE"); const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!HOME || !HIS) { if (!HOME || !HIS) {
std::println(stderr, "PluginManager: no $HOME or HIS"); std::cerr << "PluginManager: no $HOME or HIS\n";
return LOADSTATE_FAIL; return LOADSTATE_FAIL;
} }
const auto HYPRPMPATH = DataState::getDataStatePath() + "/"; const auto HYPRPMPATH = DataState::getDataStatePath() + "/";
@@ -799,14 +770,14 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
std::vector<std::string> loadedPlugins; std::vector<std::string> loadedPlugins;
std::println("{}", successString("Ensuring plugin load state")); std::cout << Colors::GREEN << "" << Colors::RESET << " Ensuring plugin load state\n";
// iterate line by line // iterate line by line
while (!pluginLines.empty()) { while (!pluginLines.empty()) {
auto plLine = pluginLines.substr(0, pluginLines.find('\n')); auto plLine = pluginLines.substr(0, pluginLines.find("\n"));
if (pluginLines.find('\n') != std::string::npos) if (pluginLines.find("\n") != std::string::npos)
pluginLines = pluginLines.substr(pluginLines.find('\n') + 1); pluginLines = pluginLines.substr(pluginLines.find("\n") + 1);
else else
pluginLines = ""; pluginLines = "";
@@ -823,8 +794,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
const auto REPOS = DataState::getAllRepositories(); const auto REPOS = DataState::getAllRepositories();
auto enabled = [REPOS](const std::string& plugin) -> bool { auto enabled = [REPOS](const std::string& plugin) -> bool {
for (auto const& r : REPOS) { for (auto& r : REPOS) {
for (auto const& p : r.plugins) { for (auto& p : r.plugins) {
if (p.name == plugin && p.enabled) if (p.name == plugin && p.enabled)
return true; return true;
} }
@@ -834,8 +805,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
}; };
auto repoForName = [REPOS](const std::string& name) -> std::string { auto repoForName = [REPOS](const std::string& name) -> std::string {
for (auto const& r : REPOS) { for (auto& r : REPOS) {
for (auto const& p : r.plugins) { for (auto& p : r.plugins) {
if (p.name == name) if (p.name == name)
return r.name; return r.name;
} }
@@ -844,54 +815,35 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
return ""; return "";
}; };
// if any of the loadUnloadPlugin calls return false, this is true
// bcs that means the header version doesn't match the running version
// (and Hyprland needs to restart)
bool hyprlandVersionMismatch = false;
// unload disabled plugins // unload disabled plugins
for (auto const& p : loadedPlugins) { for (auto& p : loadedPlugins) {
if (!enabled(p)) { if (!enabled(p)) {
// unload // unload
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false)) { loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false);
std::println("{}", infoString("{} will be unloaded after restarting Hyprland", p)); std::cout << Colors::GREEN << "" << Colors::RESET << " Unloaded " << p << "\n";
hyprlandVersionMismatch = true;
} else
std::println("{}", successString("Unloaded {}", p));
} }
} }
// load enabled plugins // load enabled plugins
for (auto const& r : REPOS) { for (auto& r : REPOS) {
for (auto const& p : r.plugins) { for (auto& p : r.plugins) {
if (!p.enabled) if (!p.enabled)
continue; continue;
if (std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end()) if (std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end())
continue; continue;
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true)) { loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true);
std::println("{}", infoString("{} will be loaded after restarting Hyprland", p.name)); std::cout << Colors::GREEN << "" << Colors::RESET << " Loaded " << p.name << "\n";
hyprlandVersionMismatch = true;
} else
std::println("{}", successString("Loaded {}", p.name));
} }
} }
std::println("{}", successString("Plugin load state ensured")); std::cout << Colors::GREEN << "" << Colors::RESET << " Plugin load state ensured\n";
return hyprlandVersionMismatch ? LOADSTATE_HYPRLAND_UPDATED : LOADSTATE_OK; return LOADSTATE_OK;
} }
bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) { bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
auto state = DataState::getGlobalState();
auto HLVER = getHyprlandVersion(true);
if (state.headersHashCompiled != HLVER.hash) {
std::println("{}", infoString("Running Hyprland version differs from plugin state, please restart Hyprland."));
return false;
}
if (load) if (load)
execAndGet("hyprctl plugin load " + path); execAndGet("hyprctl plugin load " + path);
else else
@@ -903,18 +855,17 @@ bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
void CPluginManager::listAllPlugins() { void CPluginManager::listAllPlugins() {
const auto REPOS = DataState::getAllRepositories(); const auto REPOS = DataState::getAllRepositories();
for (auto const& r : REPOS) { for (auto& r : REPOS) {
std::println("{}", infoString("Repository {}:", r.name)); std::cout << std::string{Colors::RESET} + "Repository " + r.name + ":\n";
for (auto const& p : r.plugins) { for (auto& p : r.plugins) {
std::println(" │ Plugin {}", p.name);
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
if (!p.failed) if (!p.failed)
std::println(" └─ enabled: {}", (p.enabled ? std::string{Colors::GREEN} + "true" : std::string{Colors::RED} + "false")); std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n";
else else
std::println(" └─ enabled: {}Plugin failed to build", Colors::RED); std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n";
std::println("{}", Colors::RESET);
} }
} }
} }
@@ -925,19 +876,19 @@ void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int duratio
std::string CPluginManager::headerError(const eHeadersErrors err) { std::string CPluginManager::headerError(const eHeadersErrors err) {
switch (err) { switch (err) {
case HEADERS_CORRUPTED: return failureString("Headers corrupted. Please run hyprpm update to fix those.\n"); case HEADERS_CORRUPTED: return std::string{Colors::RED} + "" + Colors::RESET + " Headers corrupted. Please run hyprpm update to fix those.\n";
case HEADERS_MISMATCHED: return failureString("Headers version mismatch. Please run hyprpm update to fix those.\n"); case HEADERS_MISMATCHED: return std::string{Colors::RED} + "" + Colors::RESET + " Headers version mismatch. Please run hyprpm update to fix those.\n";
case HEADERS_NOT_HYPRLAND: return failureString("It doesn't seem you are running on hyprland.\n"); case HEADERS_NOT_HYPRLAND: return std::string{Colors::RED} + "" + Colors::RESET + " It doesn't seem you are running on hyprland.\n";
case HEADERS_MISSING: return failureString("Headers missing. Please run hyprpm update to fix those.\n"); case HEADERS_MISSING: return std::string{Colors::RED} + "" + Colors::RESET + " Headers missing. Please run hyprpm update to fix those.\n";
case HEADERS_DUPLICATED: { case HEADERS_DUPLICATED: {
return failureString("Headers duplicated!!! This is a very bad sign.\n" return std::string{Colors::RED} + "" + Colors::RESET + " Headers duplicated!!! This is a very bad sign.\n" +
"This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" " This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" +
"If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n"); " If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n";
} }
default: break; default: break;
} }
return failureString("Unknown header error. Please run hyprpm update to fix those.\n"); return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n";
} }
std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {
@@ -953,9 +904,9 @@ std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {
} }
bool CPluginManager::hasDeps() { bool CPluginManager::hasDeps() {
std::vector<std::string> deps = {"meson", "cpio", "cmake", "pkg-config"}; std::vector<std::string> deps = {"meson", "cpio", "cmake"};
for (auto const& d : deps) { for (auto& d : deps) {
if (!execAndGet("command -v " + d).contains("/")) if (!execAndGet("which " + d + " 2>&1").contains("/"))
return false; return false;
} }

View File

@@ -2,7 +2,6 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
enum eHeadersErrors { enum eHeadersErrors {
HEADERS_OK = 0, HEADERS_OK = 0,
@@ -27,8 +26,7 @@ enum ePluginLoadStateReturn {
LOADSTATE_OK = 0, LOADSTATE_OK = 0,
LOADSTATE_FAIL, LOADSTATE_FAIL,
LOADSTATE_PARTIAL_FAIL, LOADSTATE_PARTIAL_FAIL,
LOADSTATE_HEADERS_OUTDATED, LOADSTATE_HEADERS_OUTDATED
LOADSTATE_HYPRLAND_UPDATED
}; };
struct SHyprlandVersion { struct SHyprlandVersion {
@@ -54,7 +52,7 @@ class CPluginManager {
ePluginLoadStateReturn ensurePluginsLoadState(); ePluginLoadStateReturn ensurePluginsLoadState();
bool loadUnloadPlugin(const std::string& path, bool load); bool loadUnloadPlugin(const std::string& path, bool load);
SHyprlandVersion getHyprlandVersion(bool running = true); SHyprlandVersion getHyprlandVersion();
void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message); void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message);
@@ -70,7 +68,7 @@ class CPluginManager {
std::string headerError(const eHeadersErrors err); std::string headerError(const eHeadersErrors err);
std::string headerErrorShort(const eHeadersErrors err); std::string headerErrorShort(const eHeadersErrors err);
std::string m_szWorkingPluginDirectory; std::string m_szWorkingPluginDirectory = "";
}; };
inline std::unique_ptr<CPluginManager> g_pPluginManager; inline std::unique_ptr<CPluginManager> g_pPluginManager;

View File

@@ -1,32 +0,0 @@
#pragma once
#include <format>
#include <string>
#include "Colors.hpp"
template <typename... Args>
std::string statusString(const std::string_view emoji, const std::string_view color, const std::string_view fmt, Args&&... args) {
std::string ret = std::format("{}{}{} ", color, emoji, Colors::RESET);
ret += std::vformat(fmt, std::make_format_args(args...));
return ret;
}
template <typename... Args>
std::string successString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::GREEN, fmt, args...);
}
template <typename... Args>
std::string failureString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::RED, fmt, args...);
}
template <typename... Args>
std::string verboseString(const std::string_view fmt, Args&&... args) {
return statusString("[v]", Colors::BLUE, fmt, args...);
}
template <typename... Args>
std::string infoString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::RESET, fmt, args...);
}

View File

@@ -1,16 +1,15 @@
#include "progress/CProgressBar.hpp"
#include "helpers/Colors.hpp" #include "helpers/Colors.hpp"
#include "helpers/StringUtils.hpp"
#include "core/PluginManager.hpp" #include "core/PluginManager.hpp"
#include "core/DataState.hpp" #include "core/DataState.hpp"
#include <cstdio> #include <iostream>
#include <vector> #include <vector>
#include <string> #include <string>
#include <print>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
add [url] [git rev] Install a new plugin repository from git. Git revision 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.
@@ -23,8 +22,7 @@ constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
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 (e.g. load fail)
--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)
@@ -32,38 +30,36 @@ constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
)#"; )#";
int main(int argc, char** argv, char** envp) { int main(int argc, char** argv, char** envp) {
std::vector<std::string> ARGS{argc}; std::vector<std::string> ARGS{argc};
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
ARGS[i] = std::string{argv[i]}; ARGS[i] = std::string{argv[i]};
} }
if (ARGS.size() < 2) { if (ARGS.size() < 2) {
std::println(stderr, "{}", HELP); std::cout << HELP;
return 1; return 1;
} }
std::vector<std::string> command; std::vector<std::string> command;
bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false; bool notify = false, verbose = false, force = false, noShallow = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) { if (ARGS[i].starts_with("-")) {
if (ARGS[i] == "--help" || ARGS[i] == "-h") { if (ARGS[i] == "--help" || ARGS[i] == "-h") {
std::println("{}", HELP); std::cout << HELP;
return 0; return 0;
} else if (ARGS[i] == "--notify" || ARGS[i] == "-n") { } else if (ARGS[i] == "--notify" || ARGS[i] == "-n") {
notify = true; notify = true;
} else if (ARGS[i] == "--notify-fail" || ARGS[i] == "-nn") {
notifyFail = notify = true;
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") { } else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
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] == "--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::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
} else { } else {
std::println(stderr, "Unrecognized option {}", ARGS[i]); std::cerr << "Unrecognized option " << ARGS[i] << "\n";
return 1; return 1;
} }
} else { } else {
@@ -72,8 +68,8 @@ int main(int argc, char** argv, char** envp) {
} }
if (command.empty()) { if (command.empty()) {
std::println(stderr, "{}", HELP); std::cout << HELP;
return 1; return 0;
} }
g_pPluginManager = std::make_unique<CPluginManager>(); g_pPluginManager = std::make_unique<CPluginManager>();
@@ -82,7 +78,7 @@ int main(int argc, char** argv, char** envp) {
if (command[0] == "add") { if (command[0] == "add") {
if (command.size() < 2) { if (command.size() < 2) {
std::println(stderr, "{}", failureString("Not enough args for add.")); std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for add.\n";
return 1; return 1;
} }
@@ -94,7 +90,7 @@ int main(int argc, char** argv, char** envp) {
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") {
if (ARGS.size() < 2) { if (ARGS.size() < 2) {
std::println(stderr, "{}", failureString("Not enough args for remove.")); std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for remove.\n";
return 1; return 1;
} }
@@ -103,7 +99,7 @@ int main(int argc, char** argv, char** envp) {
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK; bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
bool headers = g_pPluginManager->updateHeaders(force); bool headers = g_pPluginManager->updateHeaders(force);
if (headers) { if (headers) {
const auto HLVER = g_pPluginManager->getHyprlandVersion(false); const auto HLVER = g_pPluginManager->getHyprlandVersion();
auto GLOBALSTATE = DataState::getGlobalState(); auto GLOBALSTATE = DataState::getGlobalState();
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled; const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
@@ -114,39 +110,32 @@ int main(int argc, char** argv, char** envp) {
auto ret2 = g_pPluginManager->ensurePluginsLoadState(); auto ret2 = g_pPluginManager->ensurePluginsLoadState();
if (ret2 == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Updated plugins, but Hyprland was updated. Please restart Hyprland.");
if (ret2 != LOADSTATE_OK) if (ret2 != LOADSTATE_OK)
return 1; return 1;
} else if (notify) } else if (notify)
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers"); g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers");
} else if (command[0] == "enable") { } else if (command[0] == "enable") {
if (ARGS.size() < 2) { if (ARGS.size() < 2) {
std::println(stderr, "{}", failureString("Not enough args for enable.")); std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for enable.\n";
return 1; return 1;
} }
if (!g_pPluginManager->enablePlugin(command[1])) { if (!g_pPluginManager->enablePlugin(command[1])) {
std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)")); std::cerr << Colors::RED << "" << Colors::RESET << " Couldn't enable plugin (missing?)\n";
return 1; return 1;
} }
auto ret = g_pPluginManager->ensurePluginsLoadState(); auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland.");
if (ret != LOADSTATE_OK) if (ret != LOADSTATE_OK)
return 1; return 1;
} else if (command[0] == "disable") { } else if (command[0] == "disable") {
if (command.size() < 2) { if (command.size() < 2) {
std::println(stderr, "{}", failureString("Not enough args for disable.")); std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for disable.\n";
return 1; return 1;
} }
if (!g_pPluginManager->disablePlugin(command[1])) { if (!g_pPluginManager->disablePlugin(command[1])) {
std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)")); std::cerr << Colors::RED << "" << Colors::RESET << " Couldn't disable plugin (missing?)\n";
return 1; return 1;
} }
@@ -165,16 +154,15 @@ int main(int argc, char** argv, char** envp) {
break; break;
default: break; default: break;
} }
return 1; } else if (notify) {
} 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] == "list") { } else if (command[0] == "list") {
g_pPluginManager->listAllPlugins(); g_pPluginManager->listAllPlugins();
} else { } else {
std::println(stderr, "{}", HELP); std::cout << HELP;
return 1; return 1;
} }
return 0; return 0;
} }

View File

@@ -1,31 +1,15 @@
globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true) globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
src = globber.stdout().strip().split('\n') src = globber.stdout().strip().split('\n')
executable( executable('hyprpm', src,
'hyprpm',
src,
dependencies: [ dependencies: [
dependency('hyprutils', version: '>= 0.1.1'), dependency('hyprutils', version: '>= 0.1.1'),
dependency('threads'), dependency('threads'),
dependency('tomlplusplus'), dependency('tomlplusplus')
], ],
install: true, install : true
) )
install_data( install_data('../hyprpm.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprpm')
'../hyprpm.bash', install_data('../hyprpm.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime')
install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_data('../hyprpm.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprpm')
install_tag: 'runtime',
rename: 'hyprpm',
)
install_data(
'../hyprpm.fish',
install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'),
install_tag: 'runtime',
)
install_data(
'../hyprpm.zsh',
install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'),
install_tag: 'runtime',
rename: '_hyprpm',
)

View File

@@ -1,11 +1,11 @@
#include "CProgressBar.hpp" #include "CProgressBar.hpp"
#include <sys/ioctl.h> #include <iostream>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <format> #include <format>
#include <print> #include <sys/ioctl.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@@ -16,12 +16,11 @@ void CProgressBar::printMessageAbove(const std::string& msg) {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
std::string spaces; std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) { for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' '; spaces += ' ';
} }
std::println("\r{}\r{}", spaces, msg); std::cout << "\r" << spaces << "\r" << msg << "\n";
print(); print();
} }
@@ -30,16 +29,15 @@ void CProgressBar::print() {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (m_bFirstPrint) if (m_bFirstPrint)
std::print("\n"); std::cout << "\n";
m_bFirstPrint = false; m_bFirstPrint = false;
std::string spaces; std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) { for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' '; spaces += ' ';
} }
std::print("\r{}\r", spaces); std::cout << "\r" << spaces << "\r";
std::string message = ""; std::string message = "";
@@ -76,7 +74,7 @@ void CProgressBar::print() {
message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " "; message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " ";
// draw message // draw message
std::print("{} {}", message, m_szCurrentMessage); std::cout << message + " " + m_szCurrentMessage;
std::fflush(stdout); std::fflush(stdout);
} }

View File

@@ -14,4 +14,4 @@ class CProgressBar {
private: private:
bool m_bFirstPrint = true; bool m_bFirstPrint = true;
}; };

View File

@@ -1,17 +1,13 @@
project( project('Hyprland', 'cpp', 'c',
'Hyprland', version : run_command('cat', join_paths(meson.source_root(), 'VERSION'), check: true).stdout().strip(),
'cpp', default_options : [
'c',
version: run_command('cat', join_paths(meson.project_source_root(), 'VERSION'), check: true).stdout().strip(),
default_options: [
'warning_level=2', 'warning_level=2',
'default_library=static', 'default_library=static',
'optimization=3', 'optimization=3',
'buildtype=release', 'buildtype=release',
'debug=false', 'debug=false',
'cpp_std=c++26', 'cpp_std=c++26',
], ])
)
datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"' datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"'
add_project_arguments( add_project_arguments(
@@ -20,28 +16,16 @@ add_project_arguments(
'-Wno-unused-value', '-Wno-unused-value',
'-Wno-missing-field-initializers', '-Wno-missing-field-initializers',
'-Wno-narrowing', '-Wno-narrowing',
'-Wno-pointer-arith', datarootdir, '-Wno-pointer-arith',
'-DHYPRLAND_VERSION="' + meson.project_version() + '"', datarootdir,
], ],
language: 'cpp', language: 'cpp')
)
cpp_compiler = meson.get_compiler('cpp') cpp_compiler = meson.get_compiler('cpp')
if cpp_compiler.check_header('execinfo.h') 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.4.5')
hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
hyprlang = dependency('hyprlang', version: '>= 0.3.2')
hyprutils = dependency('hyprutils', version: '>= 0.2.3')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.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(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp')
add_project_arguments(['-DHYPRUTILS_VERSION="@0@"'.format(hyprutils.version())], language: 'cpp')
xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_dep = dependency('xcb', required: get_option('xwayland'))
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland')) xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland'))
@@ -50,7 +34,11 @@ xcb_render_dep = dependency('xcb-render', required: get_option('xwayland'))
xcb_res_dep = dependency('xcb-res', required: get_option('xwayland')) xcb_res_dep = dependency('xcb-res', required: get_option('xwayland'))
xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland'))
gio_dep = dependency('gio-2.0', required: true) gio_dep = dependency('gio-2.0', required:true)
cmake = import('cmake')
udis = cmake.subproject('udis86')
udis86 = udis.dependency('libudis86')
if not xcb_dep.found() if not xcb_dep.found()
add_project_arguments('-DNO_XWAYLAND', language: 'cpp') add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
@@ -59,17 +47,8 @@ endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false) backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs
re2 = dependency('re2', required: true) if get_option('systemd').enabled()
# Handle options
systemd_option = get_option('systemd')
systemd = dependency('systemd', required: systemd_option)
systemd_option.enable_auto_if(systemd.found())
if (systemd_option.enabled())
message('Enabling systemd integration')
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp') add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
subdir('systemd')
endif endif
if get_option('legacy_renderer').enabled() if get_option('legacy_renderer').enabled()
@@ -80,24 +59,14 @@ if get_option('buildtype') == 'debug'
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp') add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
endif endif
# Generate hyprland version and populate version.h version_h = run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
# Install headers
globber = run_command('find', 'src', '-name', '*.h*', check: true) globber = run_command('find', 'src', '-name', '*.h*', 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)
endforeach endforeach
tracy = dependency('tracy', static: true, required: get_option('tracy_enable'))
if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized'
warning('Profiling builds should set -- buildtype = debugoptimized')
endif
subdir('protocols') subdir('protocols')
subdir('src') subdir('src')
subdir('hyprctl') subdir('hyprctl')
@@ -106,7 +75,6 @@ subdir('assets')
subdir('example') subdir('example')
subdir('docs') subdir('docs')
# Generate hyprland.pc
pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig') pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')
import('pkgconfig').generate( import('pkgconfig').generate(

View File

@@ -1,5 +1,3 @@
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration') option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration')
option('uwsm', type: 'feature', value: 'enabled', description: 'Enable uwsm integration (only if systemd is enabled)')
option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer') option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer')
option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling')

View File

@@ -1,36 +1,43 @@
{ {
lib, lib,
stdenv, stdenv,
stdenvAdapters,
pkg-config, pkg-config,
pkgconf, pkgconf,
makeWrapper, makeWrapper,
meson, cmake,
ninja, ninja,
aquamarine, aquamarine,
binutils, binutils,
cairo, cairo,
expat,
fribidi,
git, git,
hwdata,
hyprcursor, hyprcursor,
hyprgraphics,
hyprland-protocols,
hyprland-qtutils,
hyprlang, hyprlang,
hyprutils, hyprutils,
hyprwayland-scanner, hyprwayland-scanner,
jq,
libGL, libGL,
libdatrie,
libdisplay-info,
libdrm, libdrm,
libexecinfo, libexecinfo,
libinput, libinput,
libxkbcommon, libliftoff,
libselinux,
libsepol,
libthai,
libuuid, libuuid,
libxkbcommon,
mesa, mesa,
pango, pango,
pciutils, pciutils,
re2, pcre2,
python3,
seatd,
systemd, systemd,
tomlplusplus, tomlplusplus,
udis86-hyprland,
wayland, wayland,
wayland-protocols, wayland-protocols,
wayland-scanner, wayland-scanner,
@@ -43,148 +50,140 @@
wrapRuntimeDeps ? true, wrapRuntimeDeps ? true,
version ? "git", version ? "git",
commit, commit,
revCount,
date, date,
# deprecated flags # deprecated flags
enableNvidiaPatches ? false, enableNvidiaPatches ? false,
nvidiaPatches ? false, nvidiaPatches ? false,
hidpiXWayland ? false, hidpiXWayland ? false,
}: let }:
inherit (builtins) baseNameOf foldl'; assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
inherit (lib.asserts) assertMsg; assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
inherit (lib.attrsets) mapAttrsToList; assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
inherit (lib.lists) flatten concatLists optional optionals; stdenv.mkDerivation {
inherit (lib.sources) cleanSourceWith cleanSource; pname = "hyprland${lib.optionalString debug "-debug"}";
inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable; inherit version;
adapters = flatten [ src = lib.cleanSourceWith {
stdenvAdapters.useMoldLinker filter = name: type: let
(lib.optional debug stdenvAdapters.keepDebugInfo) baseName = baseNameOf (toString name);
]; in
! (lib.hasSuffix ".nix" baseName);
src = lib.cleanSource ../.;
};
customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters; patches = [
in # forces GCC to use -std=c++26
assert assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; ./stdcxx.patch
assert assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; ];
assert assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
customStdenv.mkDerivation (finalAttrs: {
pname = "hyprland${optionalString debug "-debug"}";
inherit version;
src = cleanSourceWith { postPatch = ''
filter = name: _type: let # Fix hardcoded paths to /usr installation
baseName = baseNameOf (toString name); sed -i "s#/usr#$out#" src/render/OpenGL.cpp
in
! (hasSuffix ".nix" baseName);
src = cleanSource ../.;
};
postPatch = '' # Remove extra @PREFIX@ to fix pkg-config paths
# Fix hardcoded paths to /usr installation sed -i "s#@PREFIX@/##g" hyprland.pc.in
sed -i "s#/usr#$out#" src/render/OpenGL.cpp '';
# Remove extra @PREFIX@ to fix pkg-config paths COMMITS = commit;
sed -i "s#@PREFIX@/##g" hyprland.pc.in DATE = date;
''; DIRTY = lib.optionalString (commit == "") "dirty";
HASH = commit;
COMMITS = revCount; nativeBuildInputs = [
DATE = date; hyprwayland-scanner
DIRTY = optionalString (commit == "") "dirty"; jq
HASH = commit; makeWrapper
TAG = "v${builtins.readFile "${finalAttrs.src}/VERSION"}"; cmake
ninja
pkg-config
python3 # for udis86
# re-add after https://github.com/NixOS/nixpkgs/pull/214906 hits nixos-unstable
# wayland-scanner
];
depsBuildBuild = [ outputs = [
pkg-config "out"
]; "man"
"dev"
];
nativeBuildInputs = [ buildInputs = lib.concatLists [
hyprwayland-scanner [
makeWrapper aquamarine
meson cairo
ninja expat
pkg-config fribidi
]; git
hwdata
hyprcursor
hyprlang
hyprutils
libdatrie
libdisplay-info
libdrm
libGL
libinput
libliftoff
libselinux
libsepol
libthai
libuuid
libxkbcommon
mesa
pango
pciutils
pcre2
seatd
tomlplusplus
wayland
wayland-protocols
xorg.libXcursor
]
(lib.optionals stdenv.hostPlatform.isMusl [libexecinfo])
(lib.optionals enableXWayland [
xorg.libxcb
xorg.libXdmcp
xorg.xcbutil
xorg.xcbutilerrors
xorg.xcbutilrenderutil
xorg.xcbutilwm
xwayland
])
(lib.optionals withSystemd [systemd])
];
outputs = [ cmakeBuildType =
"out" if debug
"man" then "Debug"
"dev" else "RelWithDebInfo";
];
buildInputs = concatLists [ # we want as much debug info as possible
[ dontStrip = debug;
aquamarine
cairo cmakeFlags = [
git (lib.cmakeBool "NO_XWAYLAND" (!enableXWayland))
hyprcursor (lib.cmakeBool "LEGACY_RENDERER" legacyRenderer)
hyprgraphics (lib.cmakeBool "NO_SYSTEMD" (!withSystemd))
hyprland-protocols ];
hyprlang
hyprutils postInstall = ''
libdrm ${lib.optionalString wrapRuntimeDeps ''
libGL wrapProgram $out/bin/Hyprland \
libinput --suffix PATH : ${lib.makeBinPath [
libuuid binutils
libxkbcommon
mesa
pango
pciutils pciutils
re2 pkgconf
tomlplusplus ]}
udis86-hyprland ''}
wayland '';
wayland-protocols
wayland-scanner
xorg.libXcursor
]
(optionals customStdenv.hostPlatform.isMusl [libexecinfo])
(optionals enableXWayland [
xorg.libxcb
xorg.libXdmcp
xorg.xcbutilerrors
xorg.xcbutilrenderutil
xorg.xcbutilwm
xwayland
])
(optional withSystemd systemd)
];
mesonBuildType = passthru.providedSessions = ["hyprland"];
if debug
then "debugoptimized"
else "release";
mesonFlags = flatten [ meta = {
(mapAttrsToList mesonEnable { homepage = "https://github.com/hyprwm/Hyprland";
"xwayland" = enableXWayland; description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
"legacy_renderer" = legacyRenderer; license = lib.licenses.bsd3;
"uwsm" = false; platforms = lib.platforms.linux;
}) mainProgram = "Hyprland";
(mapAttrsToList mesonBool { };
"b_pch" = false; }
"tracy_enable" = false;
})
];
postInstall = ''
${optionalString wrapRuntimeDeps ''
wrapProgram $out/bin/Hyprland \
--suffix PATH : ${makeBinPath [
binutils
hyprland-qtutils
pciutils
pkgconf
]}
''}
'';
passthru.providedSessions = ["hyprland"];
meta = {
homepage = "https://github.com/hyprwm/Hyprland";
description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
license = lib.licenses.bsd3;
platforms = lib.platforms.linux;
mainProgram = "Hyprland";
};
})

View File

@@ -1,64 +0,0 @@
{
writeShellApplication,
deadnix,
statix,
alejandra,
llvmPackages_19,
fd,
}:
writeShellApplication {
name = "hyprland-treewide-formatter";
runtimeInputs = [
deadnix
statix
alejandra
llvmPackages_19.clang-tools
fd
];
text = ''
# shellcheck disable=SC2148
# common excludes
excludes="subprojects"
nix_format() {
if [ "$*" = 0 ]; then
fd '.*\.nix' . -E "$excludes" -x statix fix -- {} \;
fd '.*\.nix' . -E "$excludes" -X deadnix -e -- {} \; -X alejandra {} \;
elif [ -d "$1" ]; then
fd '.*\.nix' "$1" -E "$excludes" -i -x statix fix -- {} \;
fd '.*\.nix' "$1" -E "$excludes" -i -X deadnix -e -- {} \; -X alejandra {} \;
else
statix fix -- "$1"
deadnix -e "$1"
alejandra "$1"
fi
}
cpp_format() {
if [ "$*" = 0 ] || [ "$1" = "." ]; then
fd '.*\.cpp' . -E "$excludes" | xargs clang-format --verbose -i
elif [ -d "$1" ]; then
fd '.*\.cpp' "$1" -E "$excludes" | xargs clang-format --verbose -i
else
clang-format --verbose -i "$1"
fi
}
for i in "$@"; do
case ''${i##*.} in
"nix")
nix_format "$i"
;;
"cpp")
cpp_format "$i"
;;
*)
nix_format "$i"
cpp_format "$i"
;;
esac
done
'';
}

View File

@@ -22,33 +22,22 @@ in {
# Dependencies # Dependencies
inputs.aquamarine.overlays.default inputs.aquamarine.overlays.default
inputs.hyprcursor.overlays.default inputs.hyprcursor.overlays.default
inputs.hyprgraphics.overlays.default
inputs.hyprland-protocols.overlays.default
inputs.hyprland-qtutils.overlays.default
inputs.hyprlang.overlays.default inputs.hyprlang.overlays.default
inputs.hyprutils.overlays.default inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default inputs.hyprwayland-scanner.overlays.default
self.overlays.udis86
# Hyprland packages themselves # Hyprland packages themselves
(final: _prev: let (final: prev: let
date = mkDate (self.lastModifiedDate or "19700101"); date = mkDate (self.lastModifiedDate or "19700101");
in { in {
hyprland = final.callPackage ./default.nix { hyprland = final.callPackage ./default.nix {
stdenv = final.gcc14Stdenv; stdenv = final.gcc14Stdenv;
version = "${version}+date=${date}_${self.shortRev or "dirty"}"; version = "${version}+date=${date}_${self.shortRev or "dirty"}";
commit = self.rev or ""; commit = self.rev or "";
revCount = self.sourceInfo.revCount or "";
inherit date; inherit date;
}; };
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;}; hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
hyprland-debug = final.hyprland.override {debug = true;};
# Build major libs with debug to get as much info as possible in a stacktrace
hyprland-debug = final.hyprland.override {
aquamarine = final.aquamarine.override {debug = true;};
hyprutils = final.hyprutils.override {debug = true;};
debug = true;
};
hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;}; hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;};
# deprecated packages # deprecated packages
@@ -71,22 +60,6 @@ in {
# Packages for extra software recommended for usage with Hyprland, # Packages for extra software recommended for usage with Hyprland,
# including forked or patched packages for compatibility. # including forked or patched packages for compatibility.
hyprland-extras = lib.composeManyExtensions [ hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.default inputs.xdph.overlays.xdg-desktop-portal-hyprland
]; ];
# udis86 from nixpkgs is too old, and also does not provide a .pc file
# this version is the one used in the git submodule, and allows us to
# fetch the source without '?submodules=1'
udis86 = final: prev: {
udis86-hyprland = prev.udis86.overrideAttrs (_self: _super: {
src = final.fetchFromGitHub {
owner = "canihavesomecoffee";
repo = "udis86";
rev = "5336633af70f3917760a6d441ff02d93477b0c86";
hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g=";
};
patches = [];
});
};
} }

12
nix/stdcxx.patch Normal file
View File

@@ -0,0 +1,12 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cfbd431f..73e8e0c2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,6 +64,7 @@ endif()
include_directories(. "src/" "subprojects/udis86/" "protocols/")
set(CMAKE_CXX_STANDARD 26)
add_compile_options(
+ -std=c++26
-Wall
-Wextra
-Wno-unused-parameter

View File

@@ -1,78 +1,76 @@
wayland_protos = dependency( wayland_protos = dependency('wayland-protocols',
'wayland-protocols',
version: '>=1.32', 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.2',
version: '>=0.4', fallback: 'hyprland-protocols',
fallback: 'hyprland-protocols',
) )
wayland_protocol_dir = wayland_protos.get_variable('pkgdatadir') wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
hyprland_protocol_dir = hyprland_protos.get_variable('pkgdatadir') hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.10', native: true) hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true)
hyprwayland_scanner = find_program( hyprwayland_scanner = find_program(
hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'),
native: true, native: true,
) )
protocols = [ new_protocols = [
'wlr-gamma-control-unstable-v1.xml', ['wlr-gamma-control-unstable-v1.xml'],
'wlr-foreign-toplevel-management-unstable-v1.xml', ['wlr-foreign-toplevel-management-unstable-v1.xml'],
'wlr-output-power-management-unstable-v1.xml', ['wlr-output-power-management-unstable-v1.xml'],
'input-method-unstable-v2.xml', ['input-method-unstable-v2.xml'],
'virtual-keyboard-unstable-v1.xml', ['virtual-keyboard-unstable-v1.xml'],
'wlr-virtual-pointer-unstable-v1.xml', ['wlr-virtual-pointer-unstable-v1.xml'],
'wlr-output-management-unstable-v1.xml', ['wlr-output-management-unstable-v1.xml'],
'kde-server-decoration.xml', ['kde-server-decoration.xml'],
'wlr-layer-shell-unstable-v1.xml', ['wlr-layer-shell-unstable-v1.xml'],
'wayland-drm.xml', ['wayland-drm.xml'],
'wlr-data-control-unstable-v1.xml', ['wlr-data-control-unstable-v1.xml'],
'wlr-screencopy-unstable-v1.xml', ['wlr-screencopy-unstable-v1.xml'],
hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'],
hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'],
hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml', [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml', [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', [wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
wayland_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
wayland_protocol_dir / 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml', [wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'],
wayland_protocol_dir / 'unstable/relative-pointer/relative-pointer-unstable-v1.xml', [wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'],
wayland_protocol_dir / 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml', [wl_protocol_dir, 'staging/alpha-modifier/alpha-modifier-v1.xml'],
wayland_protocol_dir / 'staging/alpha-modifier/alpha-modifier-v1.xml', [wl_protocol_dir, 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml'],
wayland_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml', [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'],
wayland_protocol_dir / 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml', [wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'],
wayland_protocol_dir / 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml', [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'],
wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml', [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v1.xml', [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'],
wayland_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml', [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'],
wayland_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'],
wayland_protocol_dir / 'staging/ext-idle-notify/ext-idle-notify-v1.xml', [wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'],
wayland_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml', [wl_protocol_dir, 'stable/tablet/tablet-v2.xml'],
wayland_protocol_dir / 'stable/tablet/tablet-v2.xml', [wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'],
wayland_protocol_dir / 'stable/presentation-time/presentation-time.xml', [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
wayland_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', [wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'],
wayland_protocol_dir / 'unstable/primary-selection/primary-selection-unstable-v1.xml', [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'],
wayland_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml', [wl_protocol_dir, 'stable/viewporter/viewporter.xml'],
wayland_protocol_dir / 'stable/viewporter/viewporter.xml', [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'],
wayland_protocol_dir / 'stable/linux-dmabuf/linux-dmabuf-v1.xml', [wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'],
wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', [wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'],
wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml',
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
wayland_protocol_dir / 'staging/security-context/security-context-v1.xml',
] ]
wl_protocols = [] wl_protos_src = []
foreach protocol : protocols wl_protos_headers = []
wl_protocols += custom_target(
protocol.underscorify(), new_wl_protos = []
input: protocol, foreach p : new_protocols
xml = join_paths(p)
new_wl_protos += custom_target(
xml.underscorify(),
input: xml,
install: true, install: true,
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
@@ -80,26 +78,31 @@ foreach protocol : protocols
) )
endforeach endforeach
# wayland.xml generation wayland_server_dep = dependency('wayland-server', version: '>=1.20.0')
wayland_scanner = dependency('wayland-scanner') wayland_server_dir = wayland_server_dep.get_variable('pkgdatadir')
wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir')
wayland_xml = wayland_scanner_datadir / 'wayland.xml' wl_server_protos = [
wayland_protocol = custom_target( wayland_server_dir / 'wayland.xml'
wayland_xml.underscorify(), ]
input: wayland_xml, wl_server_protos_gen = []
install: true, foreach p : wl_server_protos
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], wl_server_protos_gen += custom_target(
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], p.underscorify(),
command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'], input: p,
) install: true,
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'],
)
endforeach
lib_server_protos = static_library( lib_server_protos = static_library(
'server_protos', 'server_protos',
wl_protocols + wayland_protocol, wl_protos_src + wl_protos_headers + new_wl_protos + wl_server_protos_gen,
dependencies: wayland_server_dep.partial_dependency(compile_args: true),
) )
server_protos = declare_dependency( server_protos = declare_dependency(
link_with: lib_server_protos, link_with: lib_server_protos,
sources: wl_protocols + wayland_protocol, sources: wl_protos_headers + new_wl_protos,
) )

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <deque>
#include <list> #include <list>
#include <sys/resource.h> #include <sys/resource.h>
@@ -34,7 +35,7 @@
class CWLSurfaceResource; class CWLSurfaceResource;
enum eManagersInitStage : uint8_t { enum eManagersInitStage {
STAGE_PRIORITY = 0, STAGE_PRIORITY = 0,
STAGE_BASICINIT, STAGE_BASICINIT,
STAGE_LATE STAGE_LATE
@@ -58,8 +59,8 @@ class CCompositor {
std::string m_szInstancePath = ""; std::string m_szInstancePath = "";
std::string m_szCurrentSplash = "error"; std::string m_szCurrentSplash = "error";
std::vector<PHLMONITOR> m_vMonitors; std::vector<SP<CMonitor>> m_vMonitors;
std::vector<PHLMONITOR> m_vRealMonitors; // for all monitors, even those turned off std::vector<SP<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
std::vector<PHLWINDOW> m_vWindows; std::vector<PHLWINDOW> m_vWindows;
std::vector<PHLLS> m_vLayers; std::vector<PHLLS> m_vLayers;
std::vector<PHLWORKSPACE> m_vWorkspaces; std::vector<PHLWORKSPACE> m_vWorkspaces;
@@ -79,7 +80,7 @@ class CCompositor {
WP<CWLSurfaceResource> m_pLastFocus; WP<CWLSurfaceResource> m_pLastFocus;
PHLWINDOWREF m_pLastWindow; PHLWINDOWREF m_pLastWindow;
PHLMONITORREF m_pLastMonitor; WP<CMonitor> m_pLastMonitor;
std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused. std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused.
@@ -88,37 +89,45 @@ class CCompositor {
bool m_bDPMSStateON = true; bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; bool m_bNextIsUnsafe = false;
PHLMONITORREF m_pUnsafeOutput; // fallback output for the unsafe state CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bIsShuttingDown = false; bool m_bIsShuttingDown = false;
bool m_bFinalRequests = false;
bool m_bDesktopEnvSet = false; bool m_bDesktopEnvSet = false;
bool m_bEnableXwayland = true;
// ------------------------------------------------- // // ------------------------------------------------- //
PHLMONITOR getMonitorFromID(const MONITORID&); CMonitor* getMonitorFromID(const MONITORID&);
PHLMONITOR getMonitorFromName(const std::string&); CMonitor* getMonitorFromName(const std::string&);
PHLMONITOR getMonitorFromDesc(const std::string&); CMonitor* getMonitorFromDesc(const std::string&);
PHLMONITOR getMonitorFromCursor(); CMonitor* getMonitorFromCursor();
PHLMONITOR getMonitorFromVector(const Vector2D&); CMonitor* getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(PHLWINDOW); void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr); 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(CMonitor*);
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*); SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, PHLMONITOR monitor, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
PHLMONITOR getMonitorFromOutput(SP<Aquamarine::IOutput>); CMonitor* getMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLMONITOR getRealMonitorFromOutput(SP<Aquamarine::IOutput>); CMonitor* getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>); PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
PHLWINDOW getWindowFromHandle(uint32_t); PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE);
bool isWorkspaceVisibleNotCovered(PHLWORKSPACE);
PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&); PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&);
PHLWORKSPACE getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByName(const std::string&);
PHLWORKSPACE getWorkspaceByString(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces(); void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const WORKSPACEID&);
void updateWorkspaceWindowData(const WORKSPACEID&);
int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
PHLWINDOW getUrgentWindow(); PHLWINDOW getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&);
bool isWindowActive(PHLWINDOW); bool isWindowActive(PHLWINDOW);
void changeWindowZOrder(PHLWINDOW, bool); void changeWindowZOrder(PHLWINDOW, bool);
void cleanupFadingOut(const MONITORID& monid); void cleanupFadingOut(const MONITORID& monid);
@@ -127,24 +136,25 @@ class CCompositor {
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
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 CMonitor* monitor = nullptr);
PHLMONITOR getMonitorInDirection(const char&); CMonitor* getMonitorInDirection(const char&);
PHLMONITOR getMonitorInDirection(PHLMONITOR, const char&); CMonitor* getMonitorInDirection(CMonitor*, const char&);
void updateAllWindowsAnimatedDecorationValues(); void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const WORKSPACEID& id);
void updateWindowAnimatedDecorationValues(PHLWINDOW); void updateWindowAnimatedDecorationValues(PHLWINDOW);
MONITORID getNextAvailableMonitorID(std::string const& name); MONITORID getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false); void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(PHLMONITOR, PHLMONITOR); void swapActiveWorkspaces(CMonitor*, CMonitor*);
PHLMONITOR getMonitorFromString(const std::string&); CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const WORKSPACEID&); bool workspaceIDOutOfBounds(const WORKSPACEID&);
void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const SFullscreenState state); void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state);
void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON); void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON); void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW); PHLWINDOW getX11Parent(PHLWINDOW);
void scheduleFrameForMonitor(PHLMONITOR, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN); void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
void addToFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLLS);
void removeFromFadingOutSafe(PHLLS); void removeFromFadingOutSafe(PHLLS);
void addToFadingOutSafe(PHLWINDOW); void addToFadingOutSafe(PHLWINDOW);
@@ -153,9 +163,11 @@ class CCompositor {
PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>); PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>);
void closeWindow(PHLWINDOW); void closeWindow(PHLWINDOW);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&);
PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "",
bool isEmpty = true); // will be deleted next frame if left empty and unfocused! bool isEmtpy = true); // will be deleted next frame if left empty and unfocused!
void setActiveMonitor(PHLMONITOR); void renameWorkspace(const WORKSPACEID&, const std::string& name = "");
void setActiveMonitor(CMonitor*);
bool isWorkspaceSpecial(const WORKSPACEID&); bool isWorkspaceSpecial(const WORKSPACEID&);
WORKSPACEID getNewSpecialID(); WORKSPACEID getNewSpecialID();
void performUserChecks(); void performUserChecks();

View File

@@ -5,7 +5,9 @@
#include <any> #include <any>
#include <hyprutils/math/Box.hpp> #include <hyprutils/math/Box.hpp>
enum eIcons : uint8_t { using namespace Hyprutils::Math;
enum eIcons {
ICON_WARNING = 0, ICON_WARNING = 0,
ICON_INFO, ICON_INFO,
ICON_HINT, ICON_HINT,
@@ -15,7 +17,7 @@ enum eIcons : uint8_t {
ICON_NONE ICON_NONE
}; };
enum eRenderStage : uint8_t { enum eRenderStage {
RENDER_PRE = 0, /* Before binding the gl context */ RENDER_PRE = 0, /* Before binding the gl context */
RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */ RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */
RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */ RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */
@@ -27,7 +29,7 @@ enum eRenderStage : uint8_t {
RENDER_POST_WINDOW, /* After rendering a window (any pass) */ RENDER_POST_WINDOW, /* After rendering a window (any pass) */
}; };
enum eInputType : uint8_t { enum eInputType {
INPUT_TYPE_AXIS = 0, INPUT_TYPE_AXIS = 0,
INPUT_TYPE_BUTTON, INPUT_TYPE_BUTTON,
INPUT_TYPE_DRAG_START, INPUT_TYPE_DRAG_START,
@@ -39,7 +41,7 @@ struct SCallbackInfo {
bool cancelled = false; /* on cancellable events, will cancel the event. */ bool cancelled = false; /* on cancellable events, will cancel the event. */
}; };
enum eHyprCtlOutputFormat : uint8_t { enum eHyprCtlOutputFormat {
FORMAT_NORMAL = 0, FORMAT_NORMAL = 0,
FORMAT_JSON FORMAT_JSON
}; };

View File

@@ -3,7 +3,7 @@
#include "../helpers/varlist/VarList.hpp" #include "../helpers/varlist/VarList.hpp"
#include <vector> #include <vector>
enum eConfigValueDataTypes : int8_t { enum eConfigValueDataTypes {
CVD_TYPE_INVALID = -1, CVD_TYPE_INVALID = -1,
CVD_TYPE_GRADIENT = 0, CVD_TYPE_GRADIENT = 0,
CVD_TYPE_CSS_VALUE = 1 CVD_TYPE_CSS_VALUE = 1
@@ -20,40 +20,24 @@ class ICustomConfigValueData {
class CGradientValueData : public ICustomConfigValueData { class CGradientValueData : public ICustomConfigValueData {
public: public:
CGradientValueData() = default; CGradientValueData() {};
CGradientValueData(CHyprColor col) { CGradientValueData(CColor col) {
m_vColors.push_back(col); m_vColors.push_back(col);
updateColorsOk();
}; };
virtual ~CGradientValueData() = default; virtual ~CGradientValueData() {};
virtual eConfigValueDataTypes getDataType() { virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_GRADIENT; return CVD_TYPE_GRADIENT;
} }
void reset(CHyprColor col) { void reset(CColor col) {
m_vColors.clear(); m_vColors.clear();
m_vColors.emplace_back(col); m_vColors.emplace_back(col);
m_fAngle = 0; m_fAngle = 0;
updateColorsOk();
}
void updateColorsOk() {
m_vColorsOkLabA.clear();
for (auto& c : m_vColors) {
const auto OKLAB = c.asOkLab();
m_vColorsOkLabA.emplace_back(OKLAB.l);
m_vColorsOkLabA.emplace_back(OKLAB.a);
m_vColorsOkLabA.emplace_back(OKLAB.b);
m_vColorsOkLabA.emplace_back(c.a);
}
} }
/* Vector containing the colors */ /* Vector containing the colors */
std::vector<CHyprColor> m_vColors; std::vector<CColor> m_vColors;
/* Vector containing pure colors for shoving into opengl */
std::vector<float> m_vColorsOkLabA;
/* Float corresponding to the angle (rad) */ /* Float corresponding to the angle (rad) */
float m_fAngle = 0; float m_fAngle = 0;

View File

@@ -104,30 +104,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{0, 0, 4}, .data = SConfigOptionDescription::SRangeData{0, 0, 4},
}, },
SConfigOptionDescription{
.value = "general:snap:enabled",
.description = "enable snapping for floating windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "general:snap:window_gap",
.description = "minimum gap in pixels between windows before snapping",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{10, 0, 100},
},
SConfigOptionDescription{
.value = "general:snap:monitor_gap",
.description = "minimum gap in pixels between window and monitor edges before snapping",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{10, 0, 100},
},
SConfigOptionDescription{
.value = "general:snap:border_overlap",
.description = "if true, windows snap such that only one border's worth of space is between them",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* decoration: * decoration:
@@ -158,55 +134,49 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SFloatData{1, 0, 1}, .data = SConfigOptionDescription::SFloatData{1, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:enabled", .value = "decoration:drop_shadow",
.description = "enable drop shadows on windows", .description = "enable drop shadows on windows",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:range", .value = "decoration:shadow_range",
.description = "Shadow range (size) in layout px", .description = "Shadow range (size) in layout px",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{4, 0, 100}, .data = SConfigOptionDescription::SRangeData{4, 0, 100},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:render_power", .value = "decoration:shadow_render_power",
.description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]", .description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{3, 1, 4}, .data = SConfigOptionDescription::SRangeData{3, 1, 4},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:sharp", .value = "decoration:shadow_ignore_window",
.description = "whether the shadow should be sharp or not. Akin to an infinitely high render power.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "decoration:shadow:ignore_window",
.description = "if true, the shadow will not be rendered behind the window itself, only around it.", .description = "if true, the shadow will not be rendered behind the window itself, only around it.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:color", .value = "decoration:col.shadow",
.description = "shadow's color. Alpha dictates shadow's opacity.", .description = "shadow's color. Alpha dictates shadow's opacity.",
.type = CONFIG_OPTION_COLOR, .type = CONFIG_OPTION_COLOR,
.data = SConfigOptionDescription::SColorData{0xee1a1a1a}, .data = SConfigOptionDescription::SColorData{0xee1a1a1a},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:color_inactive", .value = "decoration:col.shadow_inactive",
.description = "inactive shadow color. (if not set, will fall back to col.shadow)", .description = "inactive shadow color. (if not set, will fall back to col.shadow)",
.type = CONFIG_OPTION_COLOR, .type = CONFIG_OPTION_COLOR,
.data = SConfigOptionDescription::SColorData{}, //TODO: UNSET? .data = SConfigOptionDescription::SColorData{}, //##TODO UNSET?
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:offset", .value = "decoration:shadow_offset",
.description = "shadow's rendering offset.", .description = "shadow's rendering offset.",
.type = CONFIG_OPTION_VECTOR, .type = CONFIG_OPTION_VECTOR,
.data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}}, .data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:shadow:scale", .value = "decoration:shadow_scale",
.description = "shadow's scale. [0.0 - 1.0]", .description = "shadow's scale. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1}, .data = SConfigOptionDescription::SFloatData{1, 0, 1},
@@ -268,7 +238,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "blur:ignore_opacity", .value = "blur:ignore_opacity",
.description = "make the blur layer ignore the opacity of the window", .description = "make the blur layer ignore the opacity of the window",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "blur:new_optimizations", .value = "blur:new_optimizations",
@@ -331,18 +301,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
}, },
SConfigOptionDescription{
.value = "blur:input_methods",
.description = "whether to blur input methods (e.g. fcitx5)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "blur:input_methods_ignorealpha",
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
},
/* /*
* animations: * animations:
@@ -632,22 +590,16 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "input:tablet:output", .value = "input:tablet:output",
.description = "the monitor to bind tablets. Can be current or a monitor name. Leave empty to map across all monitors.", .description = "the monitor to bind tablets. Empty means unbound..",
.type = CONFIG_OPTION_STRING_SHORT, .type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "input:tablet:region_position", .value = "input:tablet:region_position",
.description = "position of the mapped region in monitor layout relative to the top left corner of the bound monitor or all monitors.", .description = "position of the mapped region in monitor layout.",
.type = CONFIG_OPTION_VECTOR, .type = CONFIG_OPTION_VECTOR,
.data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}}, .data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}},
}, },
SConfigOptionDescription{
.value = "input:tablet:absolute_region_position",
.description = "whether to treat the region_position as an absolute position in monitor layout. Only applies when output is empty.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "input:tablet:region_size", .value = "input:tablet:region_size",
.description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.", .description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.",
@@ -790,18 +742,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:merge_groups_on_drag",
.description = "whether window groups can be dragged into other groups",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:merge_groups_on_groupbar",
.description = "whether one group will be merged with another when dragged into its groupbar",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "general:col.border_active", .value = "general:col.border_active",
.description = "border color for inactive windows", .description = "border color for inactive windows",
@@ -826,30 +766,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66775500"}, .data = SConfigOptionDescription::SGradientData{"0x66775500"},
}, },
SConfigOptionDescription{
.value = "group:auto_group",
.description = "automatically group new windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:drag_into_group",
.description = "whether dragging a window into a unlocked group will merge them. Options: 0 (disabled), 1 (enabled), 2 (only when dragging into the groupbar)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "disabled,enabled,only when dragging into the groupbar"},
},
SConfigOptionDescription{
.value = "group:merge_floated_into_tiled_on_groupbar",
.description = "whether dragging a floating window into a tiled window groupbar will merge them",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "group:group_on_movetoworkspace",
.description = "whether using movetoworkspace[silent] will merge the window into the workspace's solitary unlocked group",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* group:groupbar: * group:groupbar:
@@ -1121,30 +1037,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 = "misc:render_unfocused_fps",
.description = "the maximum limit for renderunfocused windows' fps in the background",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{15, 1, 120},
},
SConfigOptionDescription{
.value = "misc:disable_xdg_env_checks",
.description = "disable the warning if XDG environment is externally managed",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "misc:disable_hyprland_qtutils_check",
.description = "disable the warning if hyprland-qtutils is missing",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "misc:lockdead_screen_delay",
.description = "the delay in ms after the lockdead screen appears if the lock screen did not appear after a lock event occurred.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1000, 0, 5000},
},
/* /*
* binds: * binds:
@@ -1200,12 +1092,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "binds:movefocus_cycles_groupfirst",
.description = "If enabled, when in a grouped window, movefocus will cycle windows in the groups first, then at each ends of tabs, it'll move on to other windows/groups",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "binds:disable_keybind_grabbing", .value = "binds:disable_keybind_grabbing",
.description = "If enabled, apps that request keybinds to be disabled (e.g. VMs) will not be able to do so.", .description = "If enabled, apps that request keybinds to be disabled (e.g. VMs) will not be able to do so.",
@@ -1218,23 +1104,11 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "binds:allow_pin_fullscreen",
.description = "Allows fullscreen to pinned windows, and restore their pinned status afterwards",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* xwayland: * xwayland:
*/ */
SConfigOptionDescription{
.value = "xwayland:enabled",
.description = "allow running applications using X11",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "xwayland:use_nearest_neighbor", .value = "xwayland:use_nearest_neighbor",
.description = "uses the nearest neighbor filtering for xwayland apps, making them pixelated rather than blurry", .description = "uses the nearest neighbor filtering for xwayland apps, making them pixelated rather than blurry",
@@ -1304,8 +1178,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_hardware_cursors", .value = "cursor:no_hardware_cursors",
.description = "disables hardware cursors", .description = "disables hardware cursors",
.type = CONFIG_OPTION_CHOICE, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_break_fs_vrr", .value = "cursor:no_break_fs_vrr",
@@ -1345,9 +1219,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:warp_on_change_workspace", .value = "cursor:warp_on_change_workspace",
.description = "Move the cursor to the last focused window after changing the workspace. Options: 0 (Disabled), 1 (Enabled), 2 (Force - ignores cursor:no_warps option)", .description = "If true, move the cursor to the last focused window after changing the workspace.",
.type = CONFIG_OPTION_CHOICE, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:default_monitor", .value = "cursor:default_monitor",
@@ -1386,8 +1260,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:use_cpu_buffer", .value = "cursor:allow_dumb_copy",
.description = "Makes HW cursors use a CPU buffer. Required on Nvidia to have HW cursors. Experimental", .description = "Makes HW cursors work on Nvidia, at the cost of a possible hitch whenever the image changes",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
@@ -1474,158 +1348,4 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
/*
* dwindle:
*/
SConfigOptionDescription{
.value = "dwindle:pseudotile",
.description = "enable pseudotiling. Pseudotiled windows retain their floating size when tiled.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:force_split",
.description = "0 -> split follows mouse, 1 -> always split to the left (new = left or top) 2 -> always split to the right (new = right or bottom)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "follow mouse,left or top,right or bottom"},
},
SConfigOptionDescription{
.value = "dwindle:preserve_split",
.description = "if enabled, the split (side/top) will not change regardless of what happens to the container.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:smart_split",
.description = "if enabled, allows a more precise control over the window split direction based on the cursor's position. The window is conceptually divided into four "
"triangles, and cursor's triangle determines the split direction. This feature also turns on preserve_split.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:smart_resizing",
.description =
"if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "dwindle:permanent_direction_override",
.description = "if enabled, makes the preselect direction persist until either this mode is turned off, another direction is specified, or a non-direction is specified "
"(anything other than l,r,u/t,d/b)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:special_scale_factor",
.description = "specifies the scale factor of windows on the special workspace [0 - 1]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
},
SConfigOptionDescription{
.value = "dwindle:split_width_multiplier",
.description = "specifies the auto-split width multiplier",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0.1, 3},
},
SConfigOptionDescription{
.value = "dwindle:use_active_for_splits",
.description = "whether to prefer the active window or the mouse position for splits",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "dwindle:default_split_ratio",
.description = "the default split ratio on window open. 1 means even 50/50 split. [0.1 - 1.9]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0.1, 1.9},
},
SConfigOptionDescription{
.value = "dwindle:split_bias",
.description = "specifies which window will receive the larger half of a split. positional - 0, current window - 1, opening window - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "positional,current,opening"},
},
/*
* master:
*/
SConfigOptionDescription{
.value = "master:allow_small_split",
.description = "enable adding additional master windows in a horizontal split style",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:special_scale_factor",
.description = "the scale of the special workspace windows. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
},
SConfigOptionDescription{
.value = "master:mfact",
.description =
"the size as a percentage of the master window, for example `mfact = 0.70` would mean 70% of the screen will be the master window, and 30% the slave [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.55, 0, 1},
},
SConfigOptionDescription{
.value = "master:new_status",
.description = "`master`: new window becomes master; `slave`: new windows are added to slave stack; `inherit`: inherit from focused window",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"slave"},
},
SConfigOptionDescription{
.value = "master:new_on_top",
.description = "whether a newly open window should be on the top of the stack",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:new_on_active",
.description = "`before`, `after`: place new window relative to the focused window; `none`: place new window according to the value of `new_on_top`. ",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"none"},
},
SConfigOptionDescription{
.value = "master:orientation",
.description = "default placement of the master area, can be left, right, top, bottom or center",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"left"},
},
SConfigOptionDescription{
.value = "master:inherit_fullscreen",
.description = "inherit fullscreen status when cycling/swapping to another window (e.g. monocle layout)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:always_center_master",
.description = "when using orientation=center, keep the master window centered, even when it is the only window in the workspace.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:center_ignores_reserved",
.description = "centers the master window on monitor ignoring reserved areas",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:smart_resizing",
.description =
"if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:drop_at_cursor",
.description = "when enabled, dragging and dropping windows will put them at the cursor position. Otherwise, when dropped at the stack side, they will go to the "
"top/bottom of the stack depending on new_on_top.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,9 @@
#include "../defines.hpp" #include "../defines.hpp"
#include <variant> #include <variant>
#include <vector> #include <vector>
#include <deque>
#include <algorithm> #include <algorithm>
#include <regex>
#include <optional> #include <optional>
#include <functional> #include <functional>
#include <xf86drmMode.h> #include <xf86drmMode.h>
@@ -67,13 +69,13 @@ struct SAnimationPropertyConfig {
}; };
struct SPluginKeyword { struct SPluginKeyword {
HANDLE handle = nullptr; HANDLE handle = 0;
std::string name = ""; std::string name = "";
Hyprlang::PCONFIGHANDLERFUNC fn = nullptr; Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
}; };
struct SPluginVariable { struct SPluginVariable {
HANDLE handle = nullptr; HANDLE handle = 0;
std::string name = ""; std::string name = "";
}; };
@@ -82,7 +84,7 @@ struct SExecRequestedRule {
uint64_t iPid = 0; uint64_t iPid = 0;
}; };
enum eConfigOptionType : uint8_t { enum eConfigOptionType : uint16_t {
CONFIG_OPTION_BOOL = 0, CONFIG_OPTION_BOOL = 0,
CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/ CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/
CONFIG_OPTION_FLOAT = 2, CONFIG_OPTION_FLOAT = 2,
@@ -94,7 +96,7 @@ enum eConfigOptionType : uint8_t {
CONFIG_OPTION_VECTOR = 8, CONFIG_OPTION_VECTOR = 8,
}; };
enum eConfigOptionFlags : uint8_t { enum eConfigOptionFlags : uint32_t {
CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0), CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0),
}; };
@@ -117,7 +119,7 @@ struct SConfigOptionDescription {
}; };
struct SColorData { struct SColorData {
CHyprColor color; CColor color;
}; };
struct SChoiceData { struct SChoiceData {
@@ -165,18 +167,18 @@ class CConfigManager {
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = ""); Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load); void onPluginLoadUnload(const std::string& name, bool load);
static std::string getMainConfigPath(); static std::string getMainConfigPath();
std::string getConfigString(); const std::string getConfigString();
SMonitorRule getMonitorRuleFor(const PHLMONITOR); SMonitorRule getMonitorRuleFor(const CMonitor&);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
std::string getDefaultWorkspaceFor(const std::string&); std::string getDefaultWorkspaceFor(const std::string&);
PHLMONITOR getBoundMonitorForWS(const std::string&); CMonitor* getBoundMonitorForWS(const std::string&);
std::string getBoundMonitorStringForWS(const std::string&); std::string getBoundMonitorStringForWS(const std::string&);
const std::vector<SWorkspaceRule>& getAllWorkspaceRules(); const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
std::vector<SP<CWindowRule>> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false); std::vector<SWindowRule> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
std::vector<SP<CLayerRule>> getMatchingRules(PHLLS); std::vector<SLayerRule> getMatchingRules(PHLLS);
const std::vector<SConfigOptionDescription>& getAllDescriptions(); const std::vector<SConfigOptionDescription>& getAllDescriptions();
@@ -190,15 +192,12 @@ class CConfigManager {
// no-op when done. // no-op when done.
void dispatchExecOnce(); void dispatchExecOnce();
void dispatchExecShutdown();
void performMonitorReload(); void performMonitorReload();
void appendMonitorRule(const SMonitorRule&); void appendMonitorRule(const SMonitorRule&);
bool replaceMonitorRule(const SMonitorRule&); bool replaceMonitorRule(const SMonitorRule&);
void ensureMonitorStatus(); void ensureMonitorStatus();
void ensureVRR(PHLMONITOR pMonitor = nullptr); void ensureVRR(CMonitor* pMonitor = nullptr);
bool shouldUseSoftwareCursors();
std::string parseKeyword(const std::string&, const std::string&); std::string parseKeyword(const std::string&, const std::string&);
@@ -212,58 +211,51 @@ 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> handleExecOnce(const std::string&, const std::string&); std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleExecShutdown(const std::string&, const std::string&); std::optional<std::string> 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> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&); std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&); std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&); std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&); std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&); std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&); std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&); std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&); std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&); std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::string configCurrentPath; std::string configCurrentPath;
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> mbWindowProperties = { std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(PHLWINDOW)>> mbWindowProperties = {
{"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.allowsInput; }}, {"allowsinput", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.dimAround; }}, {"dimaround", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.decorate; }}, {"decorate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }}, {"focusonactivate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }}, {"keepaspectratio", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }}, {"nearestneighbor", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noAnim; }}, {"noanim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBlur; }}, {"noblur", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBorder; }}, {"noborder", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noDim; }}, {"nodim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noFocus; }}, {"nofocus", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noMaxSize; }}, {"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noRounding; }}, {"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShadow; }}, {"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }}, {"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.opaque; }}, {"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.RGBX; }}, {"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }}, {"syncfullscreen", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.tearing; }}, {"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }}, {"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }},
}; };
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> miWindowProperties = { std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(PHLWINDOW)>> miWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> mfWindowProperties = {
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}};
bool m_bWantsMonitorReload = false; bool m_bWantsMonitorReload = false;
bool m_bForceReload = false; bool m_bForceReload = false;
@@ -273,7 +265,7 @@ class CConfigManager {
private: private:
std::unique_ptr<Hyprlang::CConfig> m_pConfig; std::unique_ptr<Hyprlang::CConfig> m_pConfig;
std::vector<std::string> configPaths; // stores all the config paths std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
@@ -288,16 +280,15 @@ class CConfigManager {
bool isFirstLaunch = true; // For exec-once bool isFirstLaunch = true; // For exec-once
std::vector<SMonitorRule> m_vMonitorRules; std::deque<SMonitorRule> m_dMonitorRules;
std::vector<SWorkspaceRule> m_vWorkspaceRules; std::deque<SWorkspaceRule> m_dWorkspaceRules;
std::vector<SP<CWindowRule>> m_vWindowRules; std::deque<SWindowRule> m_dWindowRules;
std::vector<SP<CLayerRule>> m_vLayerRules; std::deque<SLayerRule> m_dLayerRules;
std::vector<std::string> m_dBlurLSNamespaces; std::deque<std::string> m_dBlurLSNamespaces;
bool firstExecDispatched = false; bool firstExecDispatched = false;
bool m_bManualCrashInitiated = false; bool m_bManualCrashInitiated = false;
std::vector<std::string> firstExecRequests; std::deque<std::string> firstExecRequests;
std::vector<std::string> finalExecRequests;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // 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_szConfigErrors = ""; std::string m_szConfigErrors = "";

View File

@@ -13,7 +13,6 @@ class CConfigValue {
CConfigValue(const std::string& val) { CConfigValue(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val); const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
// NOLINTNEXTLINE
p_ = PVHYPRLANG->getDataStaticPtr(); p_ = PVHYPRLANG->getDataStaticPtr();
#ifdef HYPRLAND_DEBUG #ifdef HYPRLAND_DEBUG

View File

@@ -4,8 +4,8 @@
inline const std::string AUTOCONFIG = R"#( inline const std::string AUTOCONFIG = R"#(
# ####################################################################################### # #######################################################################################
# AUTOGENERATED HYPRLAND CONFIG. # AUTOGENERATED HYPR CONFIG.
# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hyprland.conf AND EDIT IT, # PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS. # OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
# ####################################################################################### # #######################################################################################
@@ -13,7 +13,7 @@ autogenerated = 1 # remove this line to remove the warning
# This is an example Hyprland config file. # This is an example Hyprland config file.
# Refer to the wiki for more information. # Refer to the wiki for more information.
# https://wiki.hyprland.org/Configuring/ # https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
# Please note not all available settings / options are set here. # Please note not all available settings / options are set here.
# For a full list, see the wiki # For a full list, see the wiki
@@ -72,7 +72,7 @@ env = HYPRCURSOR_SIZE,24
# Refer to https://wiki.hyprland.org/Configuring/Variables/ # Refer to https://wiki.hyprland.org/Configuring/Variables/
# https://wiki.hyprland.org/Configuring/Variables/#general # https://wiki.hyprland.org/Configuring/Variables/#general
general { general {
gaps_in = 5 gaps_in = 5
gaps_out = 20 gaps_out = 20
@@ -83,7 +83,7 @@ general {
col.inactive_border = rgba(595959aa) col.inactive_border = rgba(595959aa)
# Set to true enable resizing windows by clicking and dragging on borders and gaps # Set to true enable resizing windows by clicking and dragging on borders and gaps
resize_on_border = false resize_on_border = false
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = false allow_tearing = false
@@ -99,63 +99,37 @@ decoration {
active_opacity = 1.0 active_opacity = 1.0
inactive_opacity = 1.0 inactive_opacity = 1.0
shadow { drop_shadow = true
enabled = true shadow_range = 4
range = 4 shadow_render_power = 3
render_power = 3 col.shadow = rgba(1a1a1aee)
color = rgba(1a1a1aee)
}
# https://wiki.hyprland.org/Configuring/Variables/#blur # https://wiki.hyprland.org/Configuring/Variables/#blur
blur { blur {
enabled = true enabled = true
size = 3 size = 3
passes = 1 passes = 1
vibrancy = 0.1696 vibrancy = 0.1696
} }
} }
# https://wiki.hyprland.org/Configuring/Variables/#animations # https://wiki.hyprland.org/Configuring/Variables/#animations
animations { animations {
enabled = yes, please :) enabled = true
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = easeOutQuint,0.23,1,0.32,1 bezier = myBezier, 0.05, 0.9, 0.1, 1.05
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = global, 1, 10, default animation = windows, 1, 7, myBezier
animation = border, 1, 5.39, easeOutQuint animation = windowsOut, 1, 7, default, popin 80%
animation = windows, 1, 4.79, easeOutQuint animation = border, 1, 10, default
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% animation = borderangle, 1, 8, default
animation = windowsOut, 1, 1.49, linear, popin 87% animation = fade, 1, 7, default
animation = fadeIn, 1, 1.73, almostLinear animation = workspaces, 1, 6, default
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, fade
animation = workspacesIn, 1, 1.21, almostLinear, fade
animation = workspacesOut, 1, 1.94, almostLinear, fade
} }
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
@@ -168,7 +142,7 @@ master {
} }
# https://wiki.hyprland.org/Configuring/Variables/#misc # https://wiki.hyprland.org/Configuring/Variables/#misc
misc { misc {
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
} }
@@ -267,19 +241,6 @@ bind = $mainMod, mouse_up, workspace, e-1
bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next
bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous
############################## ##############################
### WINDOWS AND WORKSPACES ### ### WINDOWS AND WORKSPACES ###
@@ -294,9 +255,5 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# Example windowrule v2 # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
)#"; )#";

View File

@@ -2,8 +2,8 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <link.h> #include <link.h>
#include <ctime> #include <time.h>
#include <cerrno> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <filesystem> #include <filesystem>
@@ -31,10 +31,10 @@ static char const* const MESSAGES[] = {"Sorry, didn't mean to...",
// <random> is not async-signal-safe, fake it with time(NULL) instead // <random> is not async-signal-safe, fake it with time(NULL) instead
char const* getRandomMessage() { char const* getRandomMessage() {
return MESSAGES[time(nullptr) % (sizeof(MESSAGES) / sizeof(MESSAGES[0]))]; return MESSAGES[time(NULL) % (sizeof(MESSAGES) / sizeof(MESSAGES[0]))];
} }
[[noreturn]] inline void exitWithError(char const* err) { [[noreturn]] inline void exit_with_error(char const* err) {
write(STDERR_FILENO, err, strlen(err)); write(STDERR_FILENO, err, strlen(err));
// perror() is not signal-safe, but we use it here // perror() is not signal-safe, but we use it here
// because if the crash-handler already crashed, it can't get any worse. // because if the crash-handler already crashed, it can't get any worse.
@@ -42,17 +42,17 @@ char const* getRandomMessage() {
abort(); abort();
} }
void NCrashReporter::createAndSaveCrash(int sig) { void CrashReporter::createAndSaveCrash(int sig) {
int reportFd = -1; int reportFd;
// We're in the signal handler, so we *only* have stack memory. // We're in the signal handler, so we *only* have stack memory.
// To save as much stack memory as possible, // To save as much stack memory as possible,
// destroy things as soon as possible. // destroy things as soon as possible.
{ {
CMaxLengthCString<255> reportPath; MaxLengthCString<255> reportPath;
const auto HOME = sigGetenv("HOME"); const auto HOME = sig_getenv("HOME");
const auto CACHE_HOME = sigGetenv("XDG_CACHE_HOME"); const auto CACHE_HOME = sig_getenv("XDG_CACHE_HOME");
if (CACHE_HOME && CACHE_HOME[0] != '\0') { if (CACHE_HOME && CACHE_HOME[0] != '\0') {
reportPath += CACHE_HOME; reportPath += CACHE_HOME;
@@ -61,24 +61,24 @@ void NCrashReporter::createAndSaveCrash(int sig) {
reportPath += HOME; reportPath += HOME;
reportPath += "/.cache/hyprland"; reportPath += "/.cache/hyprland";
} else { } else {
exitWithError("$CACHE_HOME and $HOME not set, nowhere to report crash\n"); exit_with_error("$CACHE_HOME and $HOME not set, nowhere to report crash\n");
return; return;
} }
int ret = mkdir(reportPath.getStr(), S_IRWXU); int ret = mkdir(reportPath.get_str(), S_IRWXU);
//__asm__("int $3"); //__asm__("int $3");
if (ret < 0 && errno != EEXIST) { if (ret < 0 && errno != EEXIST) {
exitWithError("failed to mkdir() crash report directory\n"); exit_with_error("failed to mkdir() crash report directory\n");
} }
reportPath += "/hyprlandCrashReport"; reportPath += "/hyprlandCrashReport";
reportPath.writeNum(getpid()); reportPath.write_num(getpid());
reportPath += ".txt"; reportPath += ".txt";
{ {
CBufFileWriter<64> stderr(2); BufFileWriter<64> stderr(2);
stderr += "Hyprland has crashed :( Consult the crash report at "; stderr += "Hyprland has crashed :( Consult the crash report at ";
if (!reportPath.boundsExceeded()) { if (!reportPath.boundsExceeded()) {
stderr += reportPath.getStr(); stderr += reportPath.get_str();
} else { } else {
stderr += "[ERROR: Crash report path does not fit into memory! Check if your $CACHE_HOME/$HOME is too deeply nested. Max 255 characters.]"; stderr += "[ERROR: Crash report path does not fit into memory! Check if your $CACHE_HOME/$HOME is too deeply nested. Max 255 characters.]";
} }
@@ -86,12 +86,12 @@ void NCrashReporter::createAndSaveCrash(int sig) {
stderr.flush(); stderr.flush();
} }
reportFd = open(reportPath.getStr(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (reportFd < 0) { if (reportFd < 0) {
exitWithError("Failed to open crash report path for writing"); exit_with_error("Failed to open crash report path for writing");
} }
} }
CBufFileWriter<512> finalCrashReport(reportFd); BufFileWriter<512> finalCrashReport(reportFd);
finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n"; finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n";
finalCrashReport += getRandomMessage(); finalCrashReport += getRandomMessage();
@@ -100,7 +100,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "Hyprland received signal "; finalCrashReport += "Hyprland received signal ";
finalCrashReport.writeNum(sig); finalCrashReport.writeNum(sig);
finalCrashReport += '('; finalCrashReport += '(';
finalCrashReport += sigStrsignal(sig); finalCrashReport += sig_strsignal(sig);
finalCrashReport += ")\nVersion: "; finalCrashReport += ")\nVersion: ";
finalCrashReport += GIT_COMMIT_HASH; finalCrashReport += GIT_COMMIT_HASH;
finalCrashReport += "\nTag: "; finalCrashReport += "\nTag: ";
@@ -122,9 +122,9 @@ void NCrashReporter::createAndSaveCrash(int sig) {
if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) { if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) {
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n"; finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
const size_t count = g_pPluginSystem->pluginCount(); size_t count = g_pPluginSystem->pluginCount();
std::vector<CPlugin*> plugins(count); CPlugin* plugins[count];
g_pPluginSystem->sigGetPlugins(plugins.data(), count); g_pPluginSystem->sig_getPlugins(plugins, count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
auto p = plugins[i]; auto p = plugins[i];
@@ -159,7 +159,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "GPU:\n\t"; finalCrashReport += "GPU:\n\t";
#if defined(__DragonFly__) || defined(__FreeBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__)
finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga"); finalCrashReport.writeCmdOutput("pciconf -lv | fgrep -A4 vga");
#else #else
finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA"); finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA");
#endif #endif
@@ -241,5 +241,5 @@ void NCrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "\n\nLog tail:\n"; finalCrashReport += "\n\nLog tail:\n";
finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find('\n') + 1); finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find("\n") + 1);
} }

View File

@@ -2,6 +2,6 @@
#include "../defines.hpp" #include "../defines.hpp"
namespace NCrashReporter { namespace CrashReporter {
void createAndSaveCrash(int sig); void createAndSaveCrash(int sig);
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -5,10 +5,6 @@
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#include <functional> #include <functional>
// exposed for main.cpp
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request);
std::string versionRequest(eHyprCtlOutputFormat format, std::string request);
class CHyprCtl { class CHyprCtl {
public: public:
CHyprCtl(); CHyprCtl();

View File

@@ -7,13 +7,8 @@ CHyprDebugOverlay::CHyprDebugOverlay() {
m_pTexture = makeShared<CTexture>(); m_pTexture = makeShared<CTexture>();
} }
void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay"); m_dLastRenderTimes.push_back(durationUs / 1000.f);
if (!*PDEBUGOVERLAY)
return;
m_dLastRenderTimes.emplace_back(durationUs / 1000.f);
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimes.pop_front(); m_dLastRenderTimes.pop_front();
@@ -22,13 +17,8 @@ void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs)
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay"); m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f);
if (!*PDEBUGOVERLAY)
return;
m_dLastRenderTimesNoOverlay.emplace_back(durationUs / 1000.f);
if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimesNoOverlay.pop_front(); m_dLastRenderTimesNoOverlay.pop_front();
@@ -37,13 +27,8 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float du
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) { void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay"); m_dLastFrametimes.push_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
if (!*PDEBUGOVERLAY)
return;
m_dLastFrametimes.emplace_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastFrametimes.pop_front(); m_dLastFrametimes.pop_front();
@@ -54,7 +39,7 @@ void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
// anim data too // anim data too
const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor.lock() : g_pCompositor->m_pLastMonitor.lock(); const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor.get();
if (PMONITORFORTICKS) { if (PMONITORFORTICKS) {
if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate) if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate)
m_dLastAnimationTicks.pop_front(); m_dLastAnimationTicks.pop_front();
@@ -72,7 +57,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float avgFrametime = 0; float avgFrametime = 0;
float maxFrametime = 0; float maxFrametime = 0;
float minFrametime = 9999; float minFrametime = 9999;
for (auto const& ft : m_dLastFrametimes) { for (auto& ft : m_dLastFrametimes) {
if (ft > maxFrametime) if (ft > maxFrametime)
maxFrametime = ft; maxFrametime = ft;
if (ft < minFrametime) if (ft < minFrametime)
@@ -85,7 +70,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float avgRenderTime = 0; float avgRenderTime = 0;
float maxRenderTime = 0; float maxRenderTime = 0;
float minRenderTime = 9999; float minRenderTime = 9999;
for (auto const& rt : m_dLastRenderTimes) { for (auto& rt : m_dLastRenderTimes) {
if (rt > maxRenderTime) if (rt > maxRenderTime)
maxRenderTime = rt; maxRenderTime = rt;
if (rt < minRenderTime) if (rt < minRenderTime)
@@ -98,7 +83,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float avgRenderTimeNoOverlay = 0; float avgRenderTimeNoOverlay = 0;
float maxRenderTimeNoOverlay = 0; float maxRenderTimeNoOverlay = 0;
float minRenderTimeNoOverlay = 9999; float minRenderTimeNoOverlay = 9999;
for (auto const& rt : m_dLastRenderTimesNoOverlay) { for (auto& rt : m_dLastRenderTimesNoOverlay) {
if (rt > maxRenderTimeNoOverlay) if (rt > maxRenderTimeNoOverlay)
maxRenderTimeNoOverlay = rt; maxRenderTimeNoOverlay = rt;
if (rt < minRenderTimeNoOverlay) if (rt < minRenderTimeNoOverlay)
@@ -111,7 +96,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float avgAnimMgrTick = 0; float avgAnimMgrTick = 0;
float maxAnimMgrTick = 0; float maxAnimMgrTick = 0;
float minAnimMgrTick = 9999; float minAnimMgrTick = 9999;
for (auto const& at : m_dLastAnimationTicks) { for (auto& at : m_dLastAnimationTicks) {
if (at > maxAnimMgrTick) if (at > maxAnimMgrTick)
maxAnimMgrTick = at; maxAnimMgrTick = at;
if (at < minAnimMgrTick) if (at < minAnimMgrTick)
@@ -203,36 +188,21 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
return posY - offset; return posY - offset;
} }
void CHyprDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs); m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs);
} }
void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs); m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
} }
void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) { void CHyprDebugOverlay::frameData(CMonitor* pMonitor) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].frameData(pMonitor); m_mMonitorOverlays[pMonitor].frameData(pMonitor);
} }
void CHyprDebugOverlay::draw() { void CHyprDebugOverlay::draw() {
const auto PMONITOR = g_pCompositor->m_vMonitors.front(); const auto PMONITOR = g_pCompositor->m_vMonitors.front().get();
if (!m_pCairoSurface || !m_pCairo) { if (!m_pCairoSurface || !m_pCairo) {
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
@@ -247,8 +217,8 @@ void CHyprDebugOverlay::draw() {
// draw the things // draw the things
int offsetY = 0; int offsetY = 0;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
offsetY += m_mMonitorOverlays[m].draw(offsetY); offsetY += m_mMonitorOverlays[m.get()].draw(offsetY);
offsetY += 5; // for padding between mons offsetY += 5; // for padding between mons
} }

View File

@@ -3,9 +3,9 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/Monitor.hpp" #include "../helpers/Monitor.hpp"
#include "../render/Texture.hpp" #include "../render/Texture.hpp"
#include <cairo/cairo.h>
#include <map>
#include <deque> #include <deque>
#include <cairo/cairo.h>
#include <unordered_map>
class CHyprRenderer; class CHyprRenderer;
@@ -13,9 +13,9 @@ class CHyprMonitorDebugOverlay {
public: public:
int draw(int offset); int draw(int offset);
void renderData(PHLMONITOR pMonitor, float durationUs); void renderData(CMonitor* pMonitor, float durationUs);
void renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs); void renderDataNoOverlay(CMonitor* pMonitor, float durationUs);
void frameData(PHLMONITOR pMonitor); void frameData(CMonitor* pMonitor);
private: private:
std::deque<float> m_dLastFrametimes; std::deque<float> m_dLastFrametimes;
@@ -23,7 +23,7 @@ class CHyprMonitorDebugOverlay {
std::deque<float> m_dLastRenderTimesNoOverlay; std::deque<float> m_dLastRenderTimesNoOverlay;
std::deque<float> m_dLastAnimationTicks; std::deque<float> m_dLastAnimationTicks;
std::chrono::high_resolution_clock::time_point m_tpLastFrame; std::chrono::high_resolution_clock::time_point m_tpLastFrame;
PHLMONITORREF m_pMonitor; CMonitor* m_pMonitor = nullptr;
CBox m_wbLastDrawnBox; CBox m_wbLastDrawnBox;
friend class CHyprRenderer; friend class CHyprRenderer;
@@ -33,17 +33,17 @@ class CHyprDebugOverlay {
public: public:
CHyprDebugOverlay(); CHyprDebugOverlay();
void draw(); void draw();
void renderData(PHLMONITOR, float durationUs); void renderData(CMonitor*, float durationUs);
void renderDataNoOverlay(PHLMONITOR, float durationUs); void renderDataNoOverlay(CMonitor*, float durationUs);
void frameData(PHLMONITOR); void frameData(CMonitor*);
private: private:
std::map<PHLMONITORREF, CHyprMonitorDebugOverlay> m_mMonitorOverlays; std::unordered_map<CMonitor*, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
cairo_surface_t* m_pCairoSurface = nullptr; cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr; cairo_t* m_pCairo = nullptr;
SP<CTexture> m_pTexture; SP<CTexture> m_pTexture;
friend class CHyprMonitorDebugOverlay; friend class CHyprMonitorDebugOverlay;
friend class CHyprRenderer; friend class CHyprRenderer;

View File

@@ -18,7 +18,7 @@ inline auto iconBackendFromLayout(PangoLayout* layout) {
CHyprNotificationOverlay::CHyprNotificationOverlay() { CHyprNotificationOverlay::CHyprNotificationOverlay() {
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (m_vNotifications.size() == 0) if (m_dNotifications.size() == 0)
return; return;
g_pHyprRenderer->damageBox(&m_bLastDamage); g_pHyprRenderer->damageBox(&m_bLastDamage);
@@ -34,34 +34,34 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() {
cairo_surface_destroy(m_pCairoSurface); cairo_surface_destroy(m_pCairoSurface);
} }
void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) { void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) {
const auto PNOTIF = m_vNotifications.emplace_back(std::make_unique<SNotification>()).get(); const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text; PNOTIF->text = text;
PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color; PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color;
PNOTIF->started.reset(); PNOTIF->started.reset();
PNOTIF->timeMs = timeMs; PNOTIF->timeMs = timeMs;
PNOTIF->icon = icon; PNOTIF->icon = icon;
PNOTIF->fontSize = fontSize; PNOTIF->fontSize = fontSize;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m); g_pCompositor->scheduleFrameForMonitor(m.get());
} }
} }
void CHyprNotificationOverlay::dismissNotifications(const int amount) { void CHyprNotificationOverlay::dismissNotifications(const int amount) {
if (amount == -1) if (amount == -1)
m_vNotifications.clear(); m_dNotifications.clear();
else { else {
const int AMT = std::min(amount, static_cast<int>(m_vNotifications.size())); const int AMT = std::min(amount, static_cast<int>(m_dNotifications.size()));
for (int i = 0; i < AMT; ++i) { for (int i = 0; i < AMT; ++i) {
m_vNotifications.erase(m_vNotifications.begin()); m_dNotifications.pop_front();
} }
} }
} }
CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) { CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
static constexpr auto ANIM_DURATION_MS = 600.0; static constexpr auto ANIM_DURATION_MS = 600.0;
static constexpr auto ANIM_LAG_MS = 100.0; static constexpr auto ANIM_LAG_MS = 100.0;
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0; static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
@@ -87,7 +87,7 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
const auto iconBackendID = iconBackendFromLayout(layout); const auto iconBackendID = iconBackendFromLayout(layout);
const auto PBEZIER = g_pAnimationManager->getBezier("default"); const auto PBEZIER = g_pAnimationManager->getBezier("default");
for (auto const& notif : m_vNotifications) { for (auto& notif : m_dNotifications) {
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40); const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
@@ -182,12 +182,12 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
g_object_unref(layout); g_object_unref(layout);
// cleanup notifs // cleanup notifs
std::erase_if(m_vNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; }); std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10}; return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
} }
void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) { void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
const auto MONSIZE = pMonitor->vecTransformedSize; const auto MONSIZE = pMonitor->vecTransformedSize;
@@ -205,7 +205,7 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
} }
// Draw the notifications // Draw the notifications
if (m_vNotifications.size() == 0) if (m_dNotifications.size() == 0)
return; return;
// Render to the monitor // Render to the monitor
@@ -246,5 +246,5 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
} }
bool CHyprNotificationOverlay::hasAny() { bool CHyprNotificationOverlay::hasAny() {
return !m_vNotifications.empty(); return !m_dNotifications.empty();
} }

View File

@@ -6,11 +6,11 @@
#include "../render/Texture.hpp" #include "../render/Texture.hpp"
#include "../SharedDefs.hpp" #include "../SharedDefs.hpp"
#include <vector> #include <deque>
#include <cairo/cairo.h> #include <cairo/cairo.h>
enum eIconBackend : uint8_t { enum eIconBackend {
ICONS_BACKEND_NONE = 0, ICONS_BACKEND_NONE = 0,
ICONS_BACKEND_NF, ICONS_BACKEND_NF,
ICONS_BACKEND_FA ICONS_BACKEND_FA
@@ -19,17 +19,17 @@ enum eIconBackend : uint8_t {
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = { static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""},
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "󰸞", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}}; std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "󰸞", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
static const std::array<CHyprColor, ICON_NONE + 1> ICONS_COLORS = {CHyprColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0}, static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
CHyprColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0}, CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
CHyprColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0}, CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
CHyprColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0}, CColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
CHyprColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0}, CColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
CHyprColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0}, CColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
CHyprColor{0, 0, 0, 1.0}}; CColor{0, 0, 0, 1.0}};
struct SNotification { struct SNotification {
std::string text = ""; std::string text = "";
CHyprColor color; CColor color;
CTimer started; CTimer started;
float timeMs = 0; float timeMs = 0;
eIcons icon = ICON_NONE; eIcons icon = ICON_NONE;
@@ -41,24 +41,24 @@ class CHyprNotificationOverlay {
CHyprNotificationOverlay(); CHyprNotificationOverlay();
~CHyprNotificationOverlay(); ~CHyprNotificationOverlay();
void draw(PHLMONITOR pMonitor); void draw(CMonitor* pMonitor);
void addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f); void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
void dismissNotifications(const int amount); void dismissNotifications(const int amount);
bool hasAny(); bool hasAny();
private: private:
CBox drawNotifications(PHLMONITOR pMonitor); CBox drawNotifications(CMonitor* pMonitor);
CBox m_bLastDamage; CBox m_bLastDamage;
std::vector<std::unique_ptr<SNotification>> m_vNotifications; std::deque<std::unique_ptr<SNotification>> m_dNotifications;
cairo_surface_t* m_pCairoSurface = nullptr; cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr; cairo_t* m_pCairo = nullptr;
PHLMONITORREF m_pLastMonitor; CMonitor* m_pLastMonitor = nullptr;
Vector2D m_vecLastSize = Vector2D(-1, -1); Vector2D m_vecLastSize = Vector2D(-1, -1);
SP<CTexture> m_pTexture; SP<CTexture> m_pTexture;
}; };
inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay; inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay;

View File

@@ -4,7 +4,7 @@
#include "RollingLogFollow.hpp" #include "RollingLogFollow.hpp"
#include <fstream> #include <fstream>
#include <print> #include <iostream>
#include <fcntl.h> #include <fcntl.h>
void Debug::init(const std::string& IS) { void Debug::init(const std::string& IS) {
@@ -18,7 +18,7 @@ void Debug::close() {
logOfs.close(); logOfs.close();
} }
void Debug::log(eLogLevel level, std::string str) { void Debug::log(LogLevel level, std::string str) {
if (level == TRACE && !trace) if (level == TRACE && !trace)
return; return;
@@ -26,7 +26,6 @@ void Debug::log(eLogLevel level, std::string str) {
return; return;
std::string coloredStr = str; std::string coloredStr = str;
//NOLINTBEGIN
switch (level) { switch (level) {
case LOG: case LOG:
str = "[LOG] " + str; str = "[LOG] " + str;
@@ -54,14 +53,13 @@ void Debug::log(eLogLevel level, std::string str) {
break; break;
default: break; default: break;
} }
//NOLINTEND
rollingLog += str + "\n"; rollingLog += str + "\n";
if (rollingLog.size() > ROLLING_LOG_SIZE) if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE); rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
if (SRollingLogFollow::get().isRunning()) if (RollingLogFollow::Get().IsRunning())
SRollingLogFollow::get().addLog(str); RollingLogFollow::Get().AddLog(str);
if (!disableLogs || !**disableLogs) { if (!disableLogs || !**disableLogs) {
// log to a file // log to a file
@@ -71,5 +69,5 @@ void Debug::log(eLogLevel level, std::string str) {
// log it to the stdout too. // log it to the stdout too.
if (!disableStdout) if (!disableStdout)
std::println("{}", ((coloredLogs && !**coloredLogs) ? str : coloredStr)); std::cout << ((coloredLogs && !**coloredLogs) ? str : coloredStr) << "\n";
} }

View File

@@ -11,7 +11,7 @@
#define LOGMESSAGESIZE 1024 #define LOGMESSAGESIZE 1024
#define ROLLING_LOG_SIZE 4096 #define ROLLING_LOG_SIZE 4096
enum eLogLevel : int8_t { enum LogLevel {
NONE = -1, NONE = -1,
LOG = 0, LOG = 0,
WARN, WARN,
@@ -21,7 +21,6 @@ enum eLogLevel : int8_t {
TRACE TRACE
}; };
// NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug { namespace Debug {
inline std::string logFile; inline std::string logFile;
inline std::ofstream logOfs; inline std::ofstream logOfs;
@@ -39,11 +38,10 @@ namespace Debug {
void close(); void close();
// //
void log(eLogLevel level, std::string str); void log(LogLevel level, std::string str);
template <typename... Args> template <typename... Args>
//NOLINTNEXTLINE void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
void log(eLogLevel level, std::format_string<Args...> fmt, Args&&... args) {
std::lock_guard<std::mutex> guard(logMutex); std::lock_guard<std::mutex> guard(logMutex);
if (level == TRACE && !trace) if (level == TRACE && !trace)
@@ -57,9 +55,8 @@ namespace Debug {
// print date and time to the ofs // print date and time to the ofs
if (disableTime && !**disableTime) { if (disableTime && !**disableTime) {
#ifndef _LIBCPP_VERSION #ifndef _LIBCPP_VERSION
static auto current_zone = std::chrono::current_zone(); const auto zt = std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::system_clock::now()};
const auto zt = std::chrono::zoned_time{current_zone, std::chrono::system_clock::now()}; const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor<std::chrono::days>(zt.get_local_time())};
const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor<std::chrono::days>(zt.get_local_time())};
#else #else
// TODO: current clang 17 does not support `zoned_time`, remove this once clang 19 is ready // TODO: current clang 17 does not support `zoned_time`, remove this once clang 19 is ready
const auto hms = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())}; const auto hms = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())};

View File

@@ -2,9 +2,8 @@
#include <shared_mutex> #include <shared_mutex>
// NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug { namespace Debug {
struct SRollingLogFollow { struct RollingLogFollow {
std::unordered_map<int, std::string> socketToRollingLogFollowQueue; std::unordered_map<int, std::string> socketToRollingLogFollowQueue;
std::shared_mutex m; std::shared_mutex m;
bool running = false; bool running = false;
@@ -16,12 +15,12 @@ namespace Debug {
return socketToRollingLogFollowQueue[socket].empty(); return socketToRollingLogFollowQueue[socket].empty();
} }
std::string debugInfo() { std::string DebugInfo() {
std::shared_lock<std::shared_mutex> r(m); std::shared_lock<std::shared_mutex> r(m);
return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size()); return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size());
} }
std::string getLog(int socket) { std::string GetLog(int socket) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m);
const std::string ret = socketToRollingLogFollowQueue[socket]; const std::string ret = socketToRollingLogFollowQueue[socket];
@@ -30,7 +29,7 @@ namespace Debug {
return ret; return ret;
}; };
void addLog(const std::string& log) { void AddLog(std::string log) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m);
running = true; running = true;
std::vector<int> to_erase; std::vector<int> to_erase;
@@ -38,26 +37,26 @@ namespace Debug {
socketToRollingLogFollowQueue[p.first] += log + "\n"; socketToRollingLogFollowQueue[p.first] += log + "\n";
} }
bool isRunning() { bool IsRunning() {
std::shared_lock<std::shared_mutex> r(m); std::shared_lock<std::shared_mutex> r(m);
return running; return running;
} }
void stopFor(int socket) { void StopFor(int socket) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m);
socketToRollingLogFollowQueue.erase(socket); socketToRollingLogFollowQueue.erase(socket);
if (socketToRollingLogFollowQueue.empty()) if (socketToRollingLogFollowQueue.empty())
running = false; running = false;
} }
void startFor(int socket) { void StartFor(int socket) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m);
socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket); socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket);
running = true; running = true;
} }
static SRollingLogFollow& get() { static RollingLogFollow& Get() {
static SRollingLogFollow instance; static RollingLogFollow instance;
static std::mutex gm; static std::mutex gm;
std::lock_guard<std::mutex> lock(gm); std::lock_guard<std::mutex> lock(gm);
return instance; return instance;

View File

@@ -1,5 +1,6 @@
#include "includes.hpp" #include "includes.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
#include "helpers/WLListener.hpp"
#include "helpers/Color.hpp" #include "helpers/Color.hpp"
#include "macros.hpp" #include "macros.hpp"
#include "desktop/DesktopTypes.hpp" #include "desktop/DesktopTypes.hpp"

View File

@@ -3,7 +3,6 @@
class CWorkspace; class CWorkspace;
class CWindow; class CWindow;
class CLayerSurface; class CLayerSurface;
class CMonitor;
/* Shared pointer to a workspace */ /* Shared pointer to a workspace */
typedef SP<CWorkspace> PHLWORKSPACE; typedef SP<CWorkspace> PHLWORKSPACE;
@@ -19,8 +18,3 @@ typedef WP<CWindow> PHLWINDOWREF;
typedef SP<CLayerSurface> PHLLS; typedef SP<CLayerSurface> PHLLS;
/* Weak pointer to a layer surface */ /* Weak pointer to a layer surface */
typedef WP<CLayerSurface> PHLLSREF; typedef WP<CLayerSurface> PHLLSREF;
/* Shared pointer to a monitor */
typedef SP<CMonitor> PHLMONITOR;
/* Weak pointer to a monitor */
typedef WP<CMonitor> PHLMONITORREF;

View File

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

View File

@@ -1,28 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
class CLayerRule {
public:
CLayerRule(const std::string& rule, const std::string& targetNS);
enum eRuleType : uint8_t {
RULE_INVALID = 0,
RULE_NOANIM,
RULE_BLUR,
RULE_BLURPOPUPS,
RULE_DIMAROUND,
RULE_IGNOREALPHA,
RULE_IGNOREZERO,
RULE_XRAY,
RULE_ANIMATION,
RULE_ORDER,
RULE_ZUMBA,
};
eRuleType ruleType = RULE_INVALID;
const std::string targetNamespace;
const std::string rule;
};

View File

@@ -6,9 +6,9 @@
#include "../managers/SeatManager.hpp" #include "../managers/SeatManager.hpp"
PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) { PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource)); PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource));
auto pMonitor = resource->monitor.empty() ? g_pCompositor->m_pLastMonitor.lock() : g_pCompositor->getMonitorFromName(resource->monitor); CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor);
pLS->surface->assign(resource->surface.lock(), pLS); pLS->surface->assign(resource->surface.lock(), pLS);
@@ -18,7 +18,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
} }
if (pMonitor->pMirrorOf) if (pMonitor->pMirrorOf)
pMonitor = g_pCompositor->m_vMonitors.front(); pMonitor = g_pCompositor->m_vMonitors.front().get();
pLS->self = pLS; pLS->self = pLS;
@@ -26,7 +26,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
pLS->layer = resource->current.layer; pLS->layer = resource->current.layer;
pLS->popupHead = std::make_unique<CPopup>(pLS); pLS->popupHead = std::make_unique<CPopup>(pLS);
pLS->monitor = pMonitor; pLS->monitorID = pMonitor->ID;
pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS);
pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace);
@@ -50,7 +50,7 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
void CLayerSurface::registerCallbacks() { void CLayerSurface::registerCallbacks() {
alpha.setUpdateCallback([this](void*) { alpha.setUpdateCallback([this](void*) {
if (dimAround) if (dimAround)
g_pHyprRenderer->damageMonitor(monitor.lock()); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(monitorID));
}); });
} }
@@ -72,7 +72,7 @@ CLayerSurface::~CLayerSurface() {
g_pHyprRenderer->makeEGLCurrent(); g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == 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_vRealMonitors) { for (auto& mon : g_pCompositor->m_vRealMonitors) {
for (auto& lsl : mon->m_aLayerSurfaceLayers) { 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; });
} }
@@ -82,9 +82,9 @@ CLayerSurface::~CLayerSurface() {
void CLayerSurface::onDestroy() { void CLayerSurface::onDestroy() {
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get()); Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get());
const auto PMONITOR = monitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) if (!g_pCompositor->getMonitorFromID(monitorID))
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)"); Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
if (!fadingOut) { if (!fadingOut) {
@@ -137,7 +137,7 @@ void CLayerSurface::onMap() {
g_pCompositor->removeFromFadingOutSafe(self.lock()); g_pCompositor->removeFromFadingOutSafe(self.lock());
// fix if it changed its mon // fix if it changed its mon
const auto PMONITOR = monitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -175,7 +175,8 @@ void CLayerSurface::onMap() {
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
const bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; const auto WORKSPACE = PMONITOR->activeWorkspace;
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN;
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
readyToDelete = false; readyToDelete = false;
@@ -196,7 +197,7 @@ void CLayerSurface::onUnmap() {
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
if (!monitor || g_pCompositor->m_bUnsafeState) { if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
@@ -220,9 +221,9 @@ void CLayerSurface::onUnmap() {
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
const auto PMONITOR = monitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == surface->resource() || g_pSeatManager->state.pointerFocus == surface->resource(); const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -231,7 +232,7 @@ void CLayerSurface::onUnmap() {
// vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable())) if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
g_pInputManager->refocusLastWindow(PMONITOR); g_pInputManager->refocusLastWindow(PMONITOR);
else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource()) else if (g_pCompositor->m_pLastFocus)
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock()); g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
@@ -255,13 +256,13 @@ void CLayerSurface::onCommit() {
if (layerSurface->surface && !layerSurface->surface->current.texture) { if (layerSurface->surface && !layerSurface->surface->current.texture) {
fadingOut = false; fadingOut = false;
geometry = {}; geometry = {};
g_pHyprRenderer->arrangeLayersForMonitor(monitorID()); g_pHyprRenderer->arrangeLayersForMonitor(monitorID);
} }
return; return;
} }
const auto PMONITOR = monitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) if (!PMONITOR)
return; return;
@@ -320,18 +321,8 @@ void CLayerSurface::onCommit() {
realSize.setValueAndWarp(geometry.size()); realSize.setValueAndWarp(geometry.size());
} }
if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) { if (mapped) {
bool WASLASTFOCUS = false; const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
layerSurface->surface->breadthfirst(
[&WASLASTFOCUS](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->state.keyboardFocus == surf; },
nullptr);
if (!WASLASTFOCUS && popupHead) {
popupHead->breadthfirst(
[&WASLASTFOCUS](CPopup* popup, void* data) {
WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource());
},
nullptr);
}
const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
@@ -341,13 +332,11 @@ void CLayerSurface::onCommit() {
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == 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 && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) { if (WASLASTFOCUS && !layerSurface->current.interactivity) {
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either, // 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(monitor.lock()); g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID));
} else if (WASLASTFOCUS && WASEXCLUSIVE && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) {
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);
@@ -377,58 +366,34 @@ void CLayerSurface::applyRules() {
xray = -1; xray = -1;
animationStyle.reset(); animationStyle.reset();
for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) { for (auto& rule : g_pConfigManager->getMatchingRules(self.lock())) {
switch (rule->ruleType) { if (rule.rule == "noanim")
case CLayerRule::RULE_NOANIM: { noAnimations = true;
noAnimations = true; else if (rule.rule == "blur")
break; forceBlur = true;
} else if (rule.rule == "blurpopups")
case CLayerRule::RULE_BLUR: { forceBlurPopups = true;
forceBlur = true; else if (rule.rule.starts_with("ignorealpha") || rule.rule.starts_with("ignorezero")) {
break; const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
} std::string alphaValue = "";
case CLayerRule::RULE_BLURPOPUPS: { if (FIRST_SPACE_POS != std::string::npos)
forceBlurPopups = true; alphaValue = rule.rule.substr(FIRST_SPACE_POS + 1);
break;
}
case CLayerRule::RULE_IGNOREALPHA:
case CLayerRule::RULE_IGNOREZERO: {
const auto FIRST_SPACE_POS = rule->rule.find_first_of(' ');
std::string alphaValue = "";
if (FIRST_SPACE_POS != std::string::npos)
alphaValue = rule->rule.substr(FIRST_SPACE_POS + 1);
try { try {
ignoreAlpha = true; ignoreAlpha = true;
if (!alphaValue.empty()) if (!alphaValue.empty())
ignoreAlphaValue = std::stof(alphaValue); ignoreAlphaValue = std::stof(alphaValue);
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); } } catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
break; } else if (rule.rule == "dimaround") {
} dimAround = true;
case CLayerRule::RULE_DIMAROUND: { } else if (rule.rule.starts_with("xray")) {
dimAround = true; CVarList vars{rule.rule, 0, ' '};
break; try {
} xray = configStringToInt(vars[1]);
case CLayerRule::RULE_XRAY: { } catch (...) {}
CVarList vars{rule->rule, 0, ' '}; } else if (rule.rule.starts_with("animation")) {
try { CVarList vars{rule.rule, 2, 's'};
xray = configStringToInt(vars[1]).value_or(false); animationStyle = vars[1];
} catch (...) {}
break;
}
case CLayerRule::RULE_ANIMATION: {
CVarList vars{rule->rule, 2, 's'};
animationStyle = vars[1];
break;
}
case CLayerRule::RULE_ORDER: {
CVarList vars{rule->rule, 2, 's'};
try {
order = std::stoi(vars[1]);
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
break;
}
default: break;
} }
} }
} }
@@ -575,7 +540,3 @@ int CLayerSurface::popupsCount() {
popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no);
return no; return no;
} }
MONITORID CLayerSurface::monitorID() {
return monitor ? monitor->ID : MONITOR_INVALID;
}

View File

@@ -4,7 +4,11 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include "LayerRule.hpp"
struct SLayerRule {
std::string targetNamespace = "";
std::string rule = "";
};
class CLayerShellResource; class CLayerShellResource;
@@ -38,7 +42,7 @@ class CLayerSurface {
bool mapped = false; bool mapped = false;
uint32_t layer = 0; uint32_t layer = 0;
PHLMONITORREF monitor; MONITORID monitorID = -1;
bool fadingOut = false; bool fadingOut = false;
bool readyToDelete = false; bool readyToDelete = false;
@@ -51,7 +55,6 @@ class CLayerSurface {
bool ignoreAlpha = false; bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f; float ignoreAlphaValue = 0.f;
bool dimAround = false; bool dimAround = false;
int64_t order = 0;
std::optional<std::string> animationStyle; std::optional<std::string> animationStyle;
@@ -66,7 +69,6 @@ class CLayerSurface {
void onMap(); void onMap();
void onUnmap(); void onUnmap();
void onCommit(); void onCommit();
MONITORID monitorID();
private: private:
struct { struct {
@@ -80,6 +82,6 @@ class CLayerSurface {
// For the list lookup // For the list lookup
bool operator==(const CLayerSurface& rhs) const { bool operator==(const CLayerSurface& rhs) const {
return layerSurface == rhs.layerSurface && monitor == rhs.monitor; return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID;
} }
}; };

View File

@@ -4,8 +4,6 @@
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include <ranges> #include <ranges>
CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) {
@@ -16,10 +14,13 @@ CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) {
initAllSignals(); initAllSignals();
} }
CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) { CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner), m_pResource(popup) {
m_pWLSurface = CWLSurface::create(); m_pWLSurface = CWLSurface::create();
m_pWLSurface->assign(popup->surface->surface.lock(), this); m_pWLSurface->assign(popup->surface->surface.lock(), this);
m_pLayerOwner = pOwner->m_pLayerOwner;
m_pWindowOwner = pOwner->m_pWindowOwner;
m_vLastSize = popup->surface->current.geometry.size(); m_vLastSize = popup->surface->current.geometry.size();
reposition(); reposition();
@@ -105,8 +106,6 @@ void CPopup::onUnmap() {
return; return;
} }
m_bMapped = false;
m_vLastSize = m_pResource->surface->surface->current.size; m_vLastSize = m_pResource->surface->surface->current.size;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
@@ -117,6 +116,8 @@ void CPopup::onUnmap() {
m_pSubsurfaceHead.reset(); m_pSubsurfaceHead.reset();
g_pInputManager->simulateMouseMovement();
if (!m_pLayerOwner.expired() && m_pLayerOwner->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_pLayerOwner->layer)); g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
@@ -130,11 +131,6 @@ void CPopup::onUnmap() {
g_pHyprRenderer->damageBox(&box); g_pHyprRenderer->damageBox(&box);
}, },
nullptr); nullptr);
const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource();
if (WASLASTFOCUS)
g_pInputManager->simulateMouseMovement();
} }
void CPopup::onCommit(bool ignoreSiblings) { void CPopup::onCommit(bool ignoreSiblings) {
@@ -206,13 +202,6 @@ void CPopup::reposition() {
m_pResource->applyPositioning(box, COORDS); m_pResource->applyPositioning(box, COORDS);
} }
SP<CWLSurface> CPopup::getT1Owner() {
if (m_pWindowOwner)
return m_pWindowOwner->m_pWLSurface;
else
return m_pLayerOwner->surface;
}
Vector2D CPopup::coordsRelativeToParent() { Vector2D CPopup::coordsRelativeToParent() {
Vector2D offset; Vector2D offset;
@@ -262,7 +251,7 @@ void CPopup::recheckTree() {
void CPopup::recheckChildrenRecursive() { void CPopup::recheckChildrenRecursive() {
auto cpy = m_vChildren; auto cpy = m_vChildren;
for (auto const& c : cpy) { for (auto& c : cpy) {
c->onCommit(true); c->onCommit(true);
c->recheckChildrenRecursive(); c->recheckChildrenRecursive();
} }
@@ -292,16 +281,15 @@ bool CPopup::visible() {
return false; return false;
} }
void CPopup::bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPopup*, void*)> fn, void* data) { void CPopup::bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data) {
for (auto const& n : nodes) { for (auto& n : nodes) {
fn(n, data); fn(n, data);
} }
std::vector<CPopup*> nodes2; std::vector<CPopup*> nodes2;
nodes2.reserve(nodes.size() * 2);
for (auto const& n : nodes) { for (auto& n : nodes) {
for (auto const& c : n->m_vChildren) { for (auto& c : n->m_vChildren) {
nodes2.push_back(c.get()); nodes2.push_back(c.get());
} }
} }
@@ -320,8 +308,8 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
std::vector<CPopup*> popups; std::vector<CPopup*> popups;
breadthfirst([](CPopup* popup, void* data) { ((std::vector<CPopup*>*)data)->push_back(popup); }, &popups); breadthfirst([](CPopup* popup, void* data) { ((std::vector<CPopup*>*)data)->push_back(popup); }, &popups);
for (auto const& p : popups | std::views::reverse) { for (auto& p : popups | std::views::reverse) {
if (!p->m_pResource || !p->m_bMapped) if (!p->m_pResource)
continue; continue;
if (!allowsInput) { if (!allowsInput) {

View File

@@ -18,22 +18,21 @@ class CPopup {
~CPopup(); ~CPopup();
SP<CWLSurface> getT1Owner(); Vector2D coordsRelativeToParent();
Vector2D coordsRelativeToParent(); Vector2D coordsGlobal();
Vector2D coordsGlobal();
Vector2D size(); Vector2D size();
void onNewPopup(SP<CXDGPopupResource> popup); void onNewPopup(SP<CXDGPopupResource> popup);
void onDestroy(); void onDestroy();
void onMap(); void onMap();
void onUnmap(); void onUnmap();
void onCommit(bool ignoreSiblings = false); void onCommit(bool ignoreSiblings = false);
void onReposition(); void onReposition();
void recheckTree(); void recheckTree();
bool visible(); bool visible();
// will also loop over this node // will also loop over this node
void breadthfirst(std::function<void(CPopup*, void*)> fn, void* data); void breadthfirst(std::function<void(CPopup*, void*)> fn, void* data);
@@ -41,7 +40,6 @@ class CPopup {
// //
SP<CWLSurface> m_pWLSurface; SP<CWLSurface> m_pWLSurface;
bool m_bMapped = false;
private: private:
// T1 owners, each popup has to have one of these // T1 owners, each popup has to have one of these
@@ -58,7 +56,8 @@ class CPopup {
bool m_bRequestedReposition = false; bool m_bRequestedReposition = false;
bool m_bInert = false; bool m_bInert = false;
bool m_bMapped = false;
// //
std::vector<SP<CPopup>> m_vChildren; std::vector<SP<CPopup>> m_vChildren;
@@ -81,5 +80,5 @@ class CPopup {
Vector2D localToGlobal(const Vector2D& rel); Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords(); Vector2D t1ParentCoords();
static void bfHelper(std::vector<CPopup*> const& nodes, std::function<void(CPopup*, void*)> fn, void* data); static void bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data);
}; };

View File

@@ -30,7 +30,13 @@ CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner)
} }
CSubsurface::~CSubsurface() { CSubsurface::~CSubsurface() {
; hyprListener_newSubsurface.removeCallback();
if (!m_pSubsurface)
return;
hyprListener_commitSubsurface.removeCallback();
hyprListener_destroySubsurface.removeCallback();
} }
void CSubsurface::initSignals() { void CSubsurface::initSignals() {
@@ -59,7 +65,7 @@ void CSubsurface::checkSiblingDamage() {
const double SCALE = m_pWindowParent.lock() && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 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_pParent->m_vChildren) { for (auto& n : m_pParent->m_vChildren) {
if (n.get() == this) if (n.get() == this)
continue; continue;
@@ -69,7 +75,7 @@ void CSubsurface::checkSiblingDamage() {
} }
void CSubsurface::recheckDamageForSubsurfaces() { void CSubsurface::recheckDamageForSubsurfaces() {
for (auto const& n : m_vChildren) { for (auto& n : m_vChildren) {
const auto COORDS = n->coordsGlobal(); const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y);
} }
@@ -177,7 +183,7 @@ Vector2D CSubsurface::coordsGlobal() {
} }
void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) { void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) {
for (auto const& s : pSurface->subsurfaces) { for (auto& s : pSurface->subsurfaces) {
if (!s || s->surface->hlSurface /* already assigned */) if (!s || s->surface->hlSurface /* already assigned */)
continue; continue;
onNewSubsurface(s.lock()); onNewSubsurface(s.lock());

View File

@@ -35,6 +35,10 @@ class CSubsurface {
void recheckDamageForSubsurfaces(); void recheckDamageForSubsurfaces();
private: private:
DYNLISTENER(destroySubsurface);
DYNLISTENER(commitSubsurface);
DYNLISTENER(newSubsurface);
struct { struct {
CHyprSignalListener destroySubsurface; CHyprSignalListener destroySubsurface;
CHyprSignalListener commitSubsurface; CHyprSignalListener commitSubsurface;

View File

@@ -62,7 +62,7 @@ bool CWLSurface::small() const {
const auto O = m_pWindowOwner.lock(); const auto O = m_pWindowOwner.lock();
return O->m_vReportedSize.x > m_pResource->current.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1; return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1;
} }
Vector2D CWLSurface::correctSmallVec() const { Vector2D CWLSurface::correctSmallVec() const {

View File

@@ -1,5 +1,3 @@
#include <re2/re2.h>
#include <any> #include <any>
#include <bit> #include <bit>
#include <string_view> #include <string_view>
@@ -21,8 +19,9 @@ using namespace Hyprutils::String;
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) { PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface)); PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
pWindow->m_pSelf = pWindow; pWindow->m_pSelf = pWindow;
pWindow->m_bIsX11 = true; pWindow->m_bIsX11 = true;
pWindow->m_iX11Type = surface->overrideRedirect ? 2 : 1;
pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
@@ -32,7 +31,6 @@ PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow)); pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow)); pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
@@ -54,7 +52,6 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow)); pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow)); pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
@@ -115,7 +112,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
const int BORDERSIZE = getRealBorderSize(); const int BORDERSIZE = getRealBorderSize();
if (m_sWindowData.dimAround.valueOrDefault()) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
} }
@@ -175,7 +172,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
CBox CWindow::getFullWindowBoundingBox() { CBox CWindow::getFullWindowBoundingBox() {
if (m_sWindowData.dimAround.valueOrDefault()) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
} }
@@ -188,7 +185,7 @@ CBox CWindow::getFullWindowBoundingBox() {
} }
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (!PMONITOR) if (!PMONITOR)
return {m_vPosition, m_vSize}; return {m_vPosition, m_vSize};
@@ -223,7 +220,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
CBox CWindow::getWindowBoxUnified(uint64_t properties) { CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_sWindowData.dimAround.valueOrDefault()) { if (m_sWindowData.dimAround.valueOrDefault()) {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR) if (PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
} }
@@ -242,6 +239,10 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) {
return box; return box;
} }
CBox CWindow::getWindowMainSurfaceBox() {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
SBoxExtents CWindow::getFullWindowReservedArea() { SBoxExtents CWindow::getFullWindowReservedArea() {
return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock()); return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock());
} }
@@ -251,7 +252,7 @@ void CWindow::updateWindowDecos() {
if (!m_bIsMapped || isHidden()) if (!m_bIsMapped || isHidden())
return; return;
for (auto const& wd : m_vDecosToRemove) { for (auto& wd : m_vDecosToRemove) {
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) { for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
if (it->get() == wd) { if (it->get() == wd) {
g_pDecorationPositioner->uncacheDecoration(it->get()); g_pDecorationPositioner->uncacheDecoration(it->get());
@@ -269,11 +270,11 @@ void CWindow::updateWindowDecos() {
// make a copy because updateWindow can remove decos. // make a copy because updateWindow can remove decos.
std::vector<IHyprWindowDecoration*> decos; std::vector<IHyprWindowDecoration*> decos;
for (auto const& wd : m_dWindowDecorations) { for (auto& wd : m_dWindowDecorations) {
decos.push_back(wd.get()); decos.push_back(wd.get());
} }
for (auto const& wd : decos) { for (auto& wd : decos) {
if (std::find_if(m_dWindowDecorations.begin(), m_dWindowDecorations.end(), [wd](const auto& other) { return other.get() == wd; }) == m_dWindowDecorations.end()) if (std::find_if(m_dWindowDecorations.begin(), m_dWindowDecorations.end(), [wd](const auto& other) { return other.get() == wd; }) == m_dWindowDecorations.end())
continue; continue;
wd->updateWindow(m_pSelf.lock()); wd->updateWindow(m_pSelf.lock());
@@ -295,7 +296,7 @@ void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
} }
void CWindow::uncacheWindowDecos() { void CWindow::uncacheWindowDecos() {
for (auto const& wd : m_dWindowDecorations) { for (auto& wd : m_dWindowDecorations) {
g_pDecorationPositioner->uncacheDecoration(wd.get()); g_pDecorationPositioner->uncacheDecoration(wd.get());
} }
} }
@@ -304,7 +305,7 @@ bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoor
if (type != INPUT_TYPE_DRAG_END && hasPopupAt(mouseCoords)) if (type != INPUT_TYPE_DRAG_END && hasPopupAt(mouseCoords))
return false; return false;
for (auto const& wd : m_dWindowDecorations) { for (auto& wd : m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue; continue;
@@ -336,7 +337,7 @@ pid_t CWindow::getPID() {
} }
IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) { IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) {
for (auto const& wd : m_dWindowDecorations) { for (auto& wd : m_dWindowDecorations) {
if (wd->getDecorationType() == type) if (wd->getDecorationType() == type)
return wd.get(); return wd.get();
} }
@@ -354,9 +355,9 @@ void CWindow::updateSurfaceScaleTransformDetails(bool force) {
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID); const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
m_iLastSurfaceMonitorID = monitorID(); m_iLastSurfaceMonitorID = m_iMonitorID;
const auto PNEWMONITOR = m_pMonitor.lock(); const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (!PNEWMONITOR) if (!PNEWMONITOR)
return; return;
@@ -368,10 +369,10 @@ void CWindow::updateSurfaceScaleTransformDetails(bool force) {
m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr); m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr);
} }
const auto PMONITOR = m_pMonitor.lock();
m_pWLSurface->resource()->breadthfirst( m_pWLSurface->resource()->breadthfirst(
[PMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { [this](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto PSURFACE = CWLSurface::fromResource(s); const auto PSURFACE = CWLSurface::fromResource(s);
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale) if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
return; return;
@@ -406,22 +407,17 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
const auto OLDWORKSPACE = m_pWorkspace; const auto OLDWORKSPACE = m_pWorkspace;
m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1;
m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F);
m_fMovingToWorkspaceAlpha = 0.F;
m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; });
m_pWorkspace = pWorkspace; m_pWorkspace = pWorkspace;
setAnimationsToMove(); setAnimationsToMove();
OLDWORKSPACE->updateWindows(); g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID);
OLDWORKSPACE->updateWindowData(); g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->monitorID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->m_iMonitorID);
pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindows(workspaceID());
pWorkspace->updateWindowData(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -433,38 +429,32 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
if (const auto SWALLOWED = m_pSwallowed.lock()) { if (const auto SWALLOWED = m_pSwallowed.lock()) {
SWALLOWED->moveToWorkspace(pWorkspace); SWALLOWED->moveToWorkspace(pWorkspace);
SWALLOWED->m_pMonitor = m_pMonitor; SWALLOWED->m_iMonitorID = m_iMonitorID;
} }
// update xwayland coords // update xwayland coords
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value()); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value());
if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE->m_iID) == 0 && *PCLOSEONLASTSPECIAL) {
if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(OLDWORKSPACE->m_iMonitorID); PMONITOR)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
} }
PHLWINDOW CWindow::x11TransientFor() { PHLWINDOW CWindow::X11TransientFor() {
if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent) if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent)
return nullptr; return nullptr;
auto s = m_pXWaylandSurface->parent; auto s = m_pXWaylandSurface->parent;
std::vector<SP<CXWaylandSurface>> visited; auto oldParent = s;
while (s) { while (s) {
// break loops. Some X apps make them, and it seems like it's valid behavior?!?!?! // break cyclic loop of m_pXWaylandSurface being parent of itself, #TODO reject this from even being created?
// TODO: we should reject loops being created in the first place. if (!s->parent || s->parent == oldParent)
if (std::find(visited.begin(), visited.end(), s) != visited.end())
break; break;
visited.emplace_back(s.lock());
s = s->parent; s = s->parent;
} }
if (s == m_pXWaylandSurface) for (auto& w : g_pCompositor->m_vWindows) {
return nullptr; // dead-ass circle
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pXWaylandSurface != s) if (w->m_pXWaylandSurface != s)
continue; continue;
return w; return w;
@@ -474,7 +464,7 @@ PHLWINDOW CWindow::x11TransientFor() {
} }
void CWindow::removeDecorationByType(eDecorationType type) { void CWindow::removeDecorationByType(eDecorationType type) {
for (auto const& wd : m_dWindowDecorations) { for (auto& wd : m_dWindowDecorations) {
if (wd->getDecorationType() == type) if (wd->getDecorationType() == type)
m_vDecosToRemove.push_back(wd.get()); m_vDecosToRemove.push_back(wd.get());
} }
@@ -512,28 +502,25 @@ void CWindow::onUnmap() {
m_fAlpha.setCallbackOnEnd(unregisterVar); m_fAlpha.setCallbackOnEnd(unregisterVar);
m_cRealShadowColor.setCallbackOnEnd(unregisterVar); m_cRealShadowColor.setCallbackOnEnd(unregisterVar);
m_fDimPercent.setCallbackOnEnd(unregisterVar); m_fDimPercent.setCallbackOnEnd(unregisterVar);
m_fMovingToWorkspaceAlpha.setCallbackOnEnd(unregisterVar);
m_vRealSize.setCallbackOnBegin(nullptr); m_vRealSize.setCallbackOnBegin(nullptr);
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; }); std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; });
if (*PCLOSEONLASTSPECIAL && m_pWorkspace && m_pWorkspace->getWindows() == 0 && onSpecialWorkspace()) { if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace) if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this) if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this)
PMONITOR->solitaryClient.reset(); PMONITOR->solitaryClient.reset();
if (m_pWorkspace) { g_pCompositor->updateWorkspaceWindows(workspaceID());
m_pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
m_pWorkspace->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
m_pWorkspace.reset(); m_pWorkspace.reset();
@@ -555,7 +542,6 @@ void CWindow::onMap() {
m_fAlpha.resetAllCallbacks(); m_fAlpha.resetAllCallbacks();
m_cRealShadowColor.resetAllCallbacks(); m_cRealShadowColor.resetAllCallbacks();
m_fDimPercent.resetAllCallbacks(); m_fDimPercent.resetAllCallbacks();
m_fMovingToWorkspaceAlpha.resetAllCallbacks();
m_vRealPosition.registerVar(); m_vRealPosition.registerVar();
m_vRealSize.registerVar(); m_vRealSize.registerVar();
@@ -565,7 +551,6 @@ void CWindow::onMap() {
m_fAlpha.registerVar(); m_fAlpha.registerVar();
m_cRealShadowColor.registerVar(); m_cRealShadowColor.registerVar();
m_fDimPercent.registerVar(); m_fDimPercent.registerVar();
m_fMovingToWorkspaceAlpha.registerVar();
m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false); m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false);
@@ -616,179 +601,153 @@ bool CWindow::isHidden() {
return m_bHidden; return m_bHidden;
} }
void CWindow::applyDynamicRule(const SP<CWindowRule>& r) { void CWindow::applyDynamicRule(const SWindowRule& r) {
const eOverridePriority priority = r->execRule ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE; const eOverridePriority priority = r.szValue == "execRule" ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
const CVarList VARS(r.szRule, 0, ' ');
if (r.szRule.starts_with("tag")) {
CVarList vars{r.szRule, 0, 's', true};
switch (r->ruleType) { if (vars.size() == 2 && vars[0] == "tag")
case CWindowRule::RULE_TAG: { m_tags.applyTag(vars[1], true);
CVarList vars{r->szRule, 0, 's', true}; else
Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
} else if (r.szRule.starts_with("opacity")) {
try {
CVarList vars(r.szRule, 0, ' ');
if (vars.size() == 2 && vars[0] == "tag") int opacityIDX = 0;
m_tags.applyTag(vars[1], true);
else
Debug::log(ERR, "Tag rule invalid: {}", r->szRule);
break;
}
case CWindowRule::RULE_OPACITY: {
try {
CVarList vars(r->szRule, 0, ' ');
int opacityIDX = 0; for (auto& r : vars) {
if (r == "opacity")
continue;
for (auto const& r : vars) { if (r == "override") {
if (r == "opacity") if (opacityIDX == 1)
continue; m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
else if (opacityIDX == 2)
if (r == "override") { m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority);
if (opacityIDX == 1) else if (opacityIDX == 3)
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority); m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
else if (opacityIDX == 2) } else {
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority); if (opacityIDX == 0) {
else if (opacityIDX == 3) m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority); } else if (opacityIDX == 1) {
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 2) {
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else { } else {
if (opacityIDX == 0) { throw std::runtime_error("more than 3 alpha values");
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 1) {
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 2) {
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else {
throw std::runtime_error("more than 3 alpha values");
}
opacityIDX++;
} }
opacityIDX++;
} }
if (opacityIDX == 1) {
m_sWindowData.alphaInactive = m_sWindowData.alpha;
m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_ANIMATION: {
auto STYLE = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
break;
}
case CWindowRule::RULE_BORDERCOLOR: {
try {
// Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {};
bool active = true;
CVarList colorsAndAngles = CVarList(trim(r->szRule.substr(r->szRule.find_first_of(' ') + 1)), 0, 's', true);
// Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority);
return;
}
for (auto const& token : colorsAndAngles) {
// The first angle, or an explicit "0deg", splits the two gradients
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false;
} else if (token.contains("deg"))
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
else if (active)
activeBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
}
activeBorderGradient.updateColorsOk();
// Includes sanity checks for the number of colors in each gradient
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r->szRule);
else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r->szRule);
else if (inactiveBorderGradient.m_vColors.empty())
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else {
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_IDLEINHIBIT: {
auto IDLERULE = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
if (IDLERULE == "none")
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
else if (IDLERULE == "always")
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
else if (IDLERULE == "focus")
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
else if (IDLERULE == "fullscreen")
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
break;
}
case CWindowRule::RULE_MAXSIZE: {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r->szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for maxsize");
return;
}
m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(std::nullopt, m_sWindowData.maxSize.value());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_MINSIZE: {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r->szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for minsize");
return;
}
m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(m_sWindowData.minSize.value(), std::nullopt);
if (m_sGroupData.pNextWindow.expired())
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_RENDERUNFOCUSED: {
m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority);
g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock());
break;
}
case CWindowRule::RULE_PROP: {
const CVarList VARS(r->szRule, 0, ' ');
if (auto search = g_pConfigManager->miWindowProperties.find(VARS[1]); search != g_pConfigManager->miWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = g_pConfigManager->mfWindowProperties.find(VARS[1]); search != g_pConfigManager->mfWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stof(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[1]); search != g_pConfigManager->mbWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(VARS[2].empty() ? true : (bool)std::stoi(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} }
break;
if (opacityIDX == 1) {
m_sWindowData.alphaInactive = m_sWindowData.alpha;
m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("animation")) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
} else if (r.szRule.starts_with("bordercolor")) {
try {
// Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {};
bool active = true;
CVarList colorsAndAngles = CVarList(trim(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
// Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))), priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))), priority);
return;
}
for (auto& token : colorsAndAngles) {
// The first angle, or an explicit "0deg", splits the two gradients
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false;
} else if (token.contains("deg"))
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
else if (active)
activeBorderGradient.m_vColors.push_back(configStringToInt(token));
else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
}
// Includes sanity checks for the number of colors in each gradient
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
else if (inactiveBorderGradient.m_vColors.empty())
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else {
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[0]); search != g_pConfigManager->mbWindowProperties.end()) {
if (VARS[1].empty()) {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority);
} else {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]), priority);
} catch (...) {}
} }
default: break; } else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[1]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (IDLERULE == "none")
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
else if (IDLERULE == "always")
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
else if (IDLERULE == "focus")
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
else if (IDLERULE == "fullscreen")
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
} else if (r.szRule.starts_with("maxsize")) {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r.szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for maxsize");
return;
}
m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
m_vRealSize =
Vector2D(std::min((double)m_sWindowData.maxSize.value().x, m_vRealSize.goal().x), std::min((double)m_sWindowData.maxSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("minsize")) {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r.szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for minsize");
return;
}
m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
m_vRealSize =
Vector2D(std::max((double)m_sWindowData.minSize.value().x, m_vRealSize.goal().x), std::max((double)m_sWindowData.minSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
if (m_sGroupData.pNextWindow.expired())
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} }
} }
@@ -806,20 +765,18 @@ void CWindow::updateDynamicRules() {
m_sWindowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE); m_sWindowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE);
m_sWindowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE); m_sWindowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE);
m_sWindowData.renderUnfocused.unset(PRIORITY_WINDOW_RULE);
m_eIdleInhibitMode = IDLEINHIBIT_NONE; m_eIdleInhibitMode = IDLEINHIBIT_NONE;
m_tags.removeDynamicTags(); m_tags.removeDynamicTags();
m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock()); m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock());
for (const auto& r : m_vMatchedRules) { for (auto& r : m_vMatchedRules) {
applyDynamicRule(r); applyDynamicRule(r);
} }
EMIT_HOOK_EVENT("windowUpdateRules", m_pSelf.lock()); EMIT_HOOK_EVENT("windowUpdateRules", m_pSelf.lock());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
} }
// check if the point is "hidden" under a rounded corner of the window // check if the point is "hidden" under a rounded corner of the window
@@ -884,11 +841,9 @@ void CWindow::createGroup() {
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock())); addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock()));
if (m_pWorkspace) { g_pCompositor->updateWorkspaceWindows(workspaceID());
m_pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
m_pWorkspace->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("1,{:x}", (uintptr_t)this)}); g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("1,{:x}", (uintptr_t)this)});
@@ -904,11 +859,9 @@ void CWindow::destroyGroup() {
m_sGroupData.pNextWindow.reset(); m_sGroupData.pNextWindow.reset();
m_sGroupData.head = false; m_sGroupData.head = false;
updateWindowDecos(); updateWindowDecos();
if (m_pWorkspace) { g_pCompositor->updateWorkspaceWindows(workspaceID());
m_pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
m_pWorkspace->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("0,{:x}", (uintptr_t)this)}); g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("0,{:x}", (uintptr_t)this)});
@@ -928,7 +881,7 @@ void CWindow::destroyGroup() {
addresses += std::format("{:x},", (uintptr_t)curr.get()); addresses += std::format("{:x},", (uintptr_t)curr.get());
} while (curr.get() != this); } while (curr.get() != this);
for (auto const& w : members) { for (auto& w : members) {
if (w->m_sGroupData.head) if (w->m_sGroupData.head)
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr);
w->m_sGroupData.head = false; w->m_sGroupData.head = false;
@@ -936,17 +889,15 @@ void CWindow::destroyGroup() {
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked; const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked;
g_pKeybindManager->m_bGroupsLocked = true; g_pKeybindManager->m_bGroupsLocked = true;
for (auto const& w : members) { for (auto& w : members) {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(w); g_pLayoutManager->getCurrentLayout()->onWindowCreated(w);
w->updateWindowDecos(); w->updateWindowDecos();
} }
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
if (m_pWorkspace) { g_pCompositor->updateWorkspaceWindows(workspaceID());
m_pWorkspace->updateWindows(); g_pCompositor->updateWorkspaceWindowData(workspaceID());
m_pWorkspace->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!addresses.empty()) if (!addresses.empty())
@@ -986,16 +937,12 @@ int CWindow::getGroupSize() {
} }
bool CWindow::canBeGroupedInto(PHLWINDOW pWindow) { bool CWindow::canBeGroupedInto(PHLWINDOW pWindow) {
static auto ALLOWGROUPMERGE = CConfigValue<Hyprlang::INT>("group:merge_groups_on_drag");
bool isGroup = m_sGroupData.pNextWindow;
bool disallowDragIntoGroup = g_pInputManager->m_bWasDraggingWindow && isGroup && !bool(*ALLOWGROUPMERGE);
return !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged return !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
&& ((m_eGroupRules & GROUP_INVADE && m_bFirstMap) // window ignore local group locks, or && ((m_eGroupRules & GROUP_INVADE && m_bFirstMap) // window ignore local group locks, or
|| (!pWindow->getGroupHead()->m_sGroupData.locked // target unlocked || (!pWindow->getGroupHead()->m_sGroupData.locked // target unlocked
&& !(m_sGroupData.pNextWindow.lock() && getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group && !(m_sGroupData.pNextWindow.lock() && getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group
&& !m_sGroupData.deny // source is not denied entry && !m_sGroupData.deny // source is not denied entry
&& !(m_eGroupRules & GROUP_BARRED && m_bFirstMap) // group rule doesn't prevent adding window && !(m_eGroupRules & GROUP_BARRED && m_bFirstMap); // group rule doesn't prevent adding window
&& !disallowDragIntoGroup; // config allows groups to be merged
} }
PHLWINDOW CWindow::getGroupWindowByIndex(int index) { PHLWINDOW CWindow::getGroupWindowByIndex(int index) {
@@ -1026,7 +973,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
const auto PCURRENT = getGroupCurrent(); const auto PCURRENT = getGroupCurrent();
const bool FULLSCREEN = PCURRENT->isFullscreen(); const bool FULLSCREEN = PCURRENT->isFullscreen();
const auto WORKSPACE = PCURRENT->m_pWorkspace; const auto WORKSPACE = PCURRENT->m_pWorkspace;
const auto MODE = PCURRENT->m_sFullscreenState.internal; const auto MODE = PCURRENT->m_sFullscreenState.client;
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
@@ -1122,7 +1069,7 @@ void CWindow::updateGroupOutputs() {
const auto WS = m_pWorkspace; const auto WS = m_pWorkspace;
while (curr.get() != this) { while (curr.get() != this) {
curr->m_pMonitor = m_pMonitor; curr->m_iMonitorID = m_iMonitorID;
curr->moveToWorkspace(WS); curr->moveToWorkspace(WS);
curr->m_vRealPosition = m_vRealPosition.goal(); curr->m_vRealPosition = m_vRealPosition.goal();
@@ -1203,16 +1150,6 @@ int CWindow::getRealBorderSize() {
return m_sWindowData.borderSize.valueOr(*PBORDERSIZE); return m_sWindowData.borderSize.valueOr(*PBORDERSIZE);
} }
float CWindow::getScrollMouse() {
static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor");
return m_sWindowData.scrollMouse.valueOr(*PINPUTSCROLLFACTOR);
}
float CWindow::getScrollTouchpad() {
static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor");
return m_sWindowData.scrollTouchpad.valueOr(*PTOUCHPADSCROLLFACTOR);
}
bool CWindow::canBeTorn() { bool CWindow::canBeTorn() {
static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing"); static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING; return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING;
@@ -1229,7 +1166,7 @@ void CWindow::setSuspended(bool suspend) {
m_bSuspended = suspend; m_bSuspended = suspend;
} }
bool CWindow::visibleOnMonitor(PHLMONITOR pMonitor) { bool CWindow::visibleOnMonitor(CMonitor* pMonitor) {
CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()}; CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()};
return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty(); return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty();
@@ -1254,7 +1191,7 @@ void CWindow::onWorkspaceAnimUpdate() {
if (!PWORKSPACE) if (!PWORKSPACE)
return; return;
const auto PWSMON = m_pMonitor.lock(); const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
if (!PWSMON) if (!PWSMON)
return; return;
@@ -1298,16 +1235,6 @@ int CWindow::surfacesCount() {
return no; return no;
} }
void CWindow::clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize) {
const Vector2D REALSIZE = m_vRealSize.goal();
const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), maxSize.value_or(Vector2D{INFINITY, INFINITY}));
const Vector2D DELTA = REALSIZE - NEWSIZE;
m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0;
m_vRealSize = NEWSIZE;
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE);
}
bool CWindow::isFullscreen() { bool CWindow::isFullscreen() {
return m_sFullscreenState.internal != FSMODE_NONE; return m_sFullscreenState.internal != FSMODE_NONE;
} }
@@ -1320,10 +1247,6 @@ WORKSPACEID CWindow::workspaceID() {
return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace; return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace;
} }
MONITORID CWindow::monitorID() {
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID;
}
bool CWindow::onSpecialWorkspace() { bool CWindow::onSpecialWorkspace() {
return m_pWorkspace ? m_pWorkspace->m_bIsSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_iLastWorkspace); return m_pWorkspace ? m_pWorkspace->m_bIsSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_iLastWorkspace);
} }
@@ -1359,7 +1282,7 @@ std::unordered_map<std::string, std::string> CWindow::getEnv() {
CVarList envs(std::string{buffer.data(), buffer.size() - 1}, 0, '\n', true); CVarList envs(std::string{buffer.data(), buffer.size() - 1}, 0, '\n', true);
for (auto const& e : envs) { for (auto& e : envs) {
if (!e.contains('=')) if (!e.contains('='))
continue; continue;
@@ -1384,11 +1307,6 @@ void CWindow::activate(bool force) {
if (!force && (!m_sWindowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE))) if (!force && (!m_sWindowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)))
return; return;
if (!m_bIsMapped) {
Debug::log(LOG, "Ignoring CWindow::activate focus/warp, window is not mapped yet.");
return;
}
if (m_bIsFloating) if (m_bIsFloating)
g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true); g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true);
@@ -1510,7 +1428,7 @@ void CWindow::onX11Configure(CBox box) {
m_pXWaylandSurface->configure(box); m_pXWaylandSurface->configure(box);
m_vPendingReportedSize = box.size(); m_vPendingReportedSize = box.size();
m_vReportedSize = box.size(); m_vReportedSize = box.size();
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
m_fX11SurfaceScaledBy = PMONITOR->scale; m_fX11SurfaceScaledBy = PMONITOR->scale;
return; return;
} }
@@ -1536,7 +1454,7 @@ void CWindow::onX11Configure(CBox box) {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling"); static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (*PXWLFORCESCALEZERO) { if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) { if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) {
m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale); m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale);
m_fX11SurfaceScaledBy = PMONITOR->scale; m_fX11SurfaceScaledBy = PMONITOR->scale;
} }
@@ -1552,7 +1470,7 @@ void CWindow::onX11Configure(CBox box) {
updateWindowDecos(); updateWindowDecos();
if (!m_pWorkspace || !m_pWorkspace->isVisible()) if (!g_pCompositor->isWorkspaceVisible(m_pWorkspace))
return; // further things are only for visible windows return; // further things are only for visible windows
m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace; m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace;
@@ -1564,15 +1482,15 @@ void CWindow::onX11Configure(CBox box) {
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());
} }
void CWindow::warpCursor(bool force) { void CWindow::warpCursor() {
static auto PERSISTENTWARPS = CConfigValue<Hyprlang::INT>("cursor:persistent_warps"); static auto PERSISTENTWARPS = CConfigValue<Hyprlang::INT>("cursor:persistent_warps");
const auto coords = m_vRelativeCursorCoordsOnLastWarp; const auto coords = m_vRelativeCursorCoordsOnLastWarp;
m_vRelativeCursorCoordsOnLastWarp.x = -1; // reset m_vRelativeCursorCoordsOnLastWarp m_vRelativeCursorCoordsOnLastWarp.x = -1; // reset m_vRelativeCursorCoordsOnLastWarp
if (*PERSISTENTWARPS && coords.x > 0 && coords.y > 0 && coords < m_vSize) // don't warp cursor outside the window if (*PERSISTENTWARPS && coords.x > 0 && coords.y > 0 && coords < m_vSize) // don't warp cursor outside the window
g_pCompositor->warpCursorTo(m_vPosition + coords, force); g_pCompositor->warpCursorTo(m_vPosition + coords);
else else
g_pCompositor->warpCursorTo(middle(), force); g_pCompositor->warpCursorTo(middle());
} }
PHLWINDOW CWindow::getSwallower() { PHLWINDOW CWindow::getSwallower() {
@@ -1580,7 +1498,7 @@ PHLWINDOW CWindow::getSwallower() {
static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex"); static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex");
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow"); static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
if (!*PSWALLOW || std::string{*PSWALLOWREGEX} == STRVAL_EMPTY || (*PSWALLOWREGEX).empty()) if (!*PSWALLOW || (*PSWALLOWREGEX).empty())
return nullptr; return nullptr;
// check parent // check parent
@@ -1593,7 +1511,7 @@ PHLWINDOW CWindow::getSwallower() {
if (!currentPid) if (!currentPid)
break; break;
for (auto const& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->isHidden()) if (!w->m_bIsMapped || w->isHidden())
continue; continue;
@@ -1603,13 +1521,13 @@ PHLWINDOW CWindow::getSwallower() {
} }
if (!(*PSWALLOWREGEX).empty()) if (!(*PSWALLOWREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return !RE2::FullMatch(other->m_szClass, *PSWALLOWREGEX); }); std::erase_if(candidates, [&](const auto& other) { return !std::regex_match(other->m_szClass, std::regex(*PSWALLOWREGEX)); });
if (candidates.size() <= 0) if (candidates.size() <= 0)
return nullptr; return nullptr;
if (!(*PSWALLOWEXREGEX).empty()) if (!(*PSWALLOWEXREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return RE2::FullMatch(other->m_szTitle, *PSWALLOWEXREGEX); }); std::erase_if(candidates, [&](const auto& other) { return std::regex_match(other->m_szTitle, std::regex(*PSWALLOWEXREGEX)); });
if (candidates.size() <= 0) if (candidates.size() <= 0)
return nullptr; return nullptr;
@@ -1618,7 +1536,7 @@ PHLWINDOW CWindow::getSwallower() {
return candidates.at(0); return candidates.at(0);
// walk up the focus history and find the last focused // walk up the focus history and find the last focused
for (auto const& w : g_pCompositor->m_vWindowFocusHistory) { for (auto& w : g_pCompositor->m_vWindowFocusHistory) {
if (!w) if (!w)
continue; continue;
@@ -1637,41 +1555,4 @@ void CWindow::unsetWindowData(eOverridePriority priority) {
for (auto const& element : g_pConfigManager->miWindowProperties) { for (auto const& element : g_pConfigManager->miWindowProperties) {
element.second(m_pSelf.lock())->unset(priority); element.second(m_pSelf.lock())->unset(priority);
} }
for (auto const& element : g_pConfigManager->mfWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
}
bool CWindow::isX11OverrideRedirect() {
return m_pXWaylandSurface && m_pXWaylandSurface->overrideRedirect;
}
bool CWindow::isModal() {
return (m_pXWaylandSurface && m_pXWaylandSurface->modal);
}
Vector2D CWindow::requestedMinSize() {
if ((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel))
return Vector2D(1, 1);
Vector2D minSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->min_width, m_pXWaylandSurface->sizeHints->min_height) : m_pXDGSurface->toplevel->layoutMinSize();
minSize = minSize.clamp({1, 1});
return minSize;
}
Vector2D CWindow::requestedMaxSize() {
constexpr int NO_MAX_SIZE_LIMIT = 99999;
if (((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel) || m_sWindowData.noMaxSize.valueOrDefault()))
return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT);
Vector2D maxSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->max_width, m_pXWaylandSurface->sizeHints->max_height) : m_pXDGSurface->toplevel->layoutMaxSize();
if (maxSize.x < 5)
maxSize.x = NO_MAX_SIZE_LIMIT;
if (maxSize.y < 5)
maxSize.y = NO_MAX_SIZE_LIMIT;
return maxSize;
} }

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include <vector> #include <deque>
#include <string> #include <string>
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
@@ -17,19 +17,18 @@
#include "Subsurface.hpp" #include "Subsurface.hpp"
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "Workspace.hpp" #include "Workspace.hpp"
#include "WindowRule.hpp"
class CXDGSurfaceResource; class CXDGSurfaceResource;
class CXWaylandSurface; class CXWaylandSurface;
enum eIdleInhibitMode : uint8_t { enum eIdleInhibitMode {
IDLEINHIBIT_NONE = 0, IDLEINHIBIT_NONE = 0,
IDLEINHIBIT_ALWAYS, IDLEINHIBIT_ALWAYS,
IDLEINHIBIT_FULLSCREEN, IDLEINHIBIT_FULLSCREEN,
IDLEINHIBIT_FOCUS IDLEINHIBIT_FOCUS
}; };
enum eGroupRules : uint8_t { enum eGroupRules {
// effective only during first map, except for _ALWAYS variant // effective only during first map, except for _ALWAYS variant
GROUP_NONE = 0, GROUP_NONE = 0,
GROUP_SET = 1 << 0, // Open as new group or add to focused group GROUP_SET = 1 << 0, // Open as new group or add to focused group
@@ -41,7 +40,7 @@ enum eGroupRules : uint8_t {
GROUP_OVERRIDE = 1 << 6, // Override other rules GROUP_OVERRIDE = 1 << 6, // Override other rules
}; };
enum eGetWindowProperties : uint8_t { enum eGetWindowProperties {
WINDOW_ONLY = 0, WINDOW_ONLY = 0,
RESERVED_EXTENTS = 1 << 0, RESERVED_EXTENTS = 1 << 0,
INPUT_EXTENTS = 1 << 1, INPUT_EXTENTS = 1 << 1,
@@ -51,7 +50,7 @@ enum eGetWindowProperties : uint8_t {
USE_PROP_TILED = 1 << 5, USE_PROP_TILED = 1 << 5,
}; };
enum eSuppressEvents : uint8_t { enum eSuppressEvents {
SUPPRESS_NONE = 0, SUPPRESS_NONE = 0,
SUPPRESS_FULLSCREEN = 1 << 0, SUPPRESS_FULLSCREEN = 1 << 0,
SUPPRESS_MAXIMIZE = 1 << 1, SUPPRESS_MAXIMIZE = 1 << 1,
@@ -65,7 +64,7 @@ struct SAlphaValue {
float m_fAlpha; float m_fAlpha;
bool m_bOverride; bool m_bOverride;
float applyAlpha(float alpha) const { float applyAlpha(float alpha) {
if (m_bOverride) if (m_bOverride)
return m_fAlpha; return m_fAlpha;
else else
@@ -73,8 +72,8 @@ struct SAlphaValue {
}; };
}; };
enum eOverridePriority : uint8_t { enum eOverridePriority {
PRIORITY_LAYOUT = 0, PRIORITY_LAYOUT,
PRIORITY_WORKSPACE_RULE, PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE, PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP, PRIORITY_SET_PROP,
@@ -86,7 +85,9 @@ class CWindowOverridableVar {
CWindowOverridableVar(T const& value, eOverridePriority priority) { CWindowOverridableVar(T const& value, eOverridePriority priority) {
values[priority] = value; values[priority] = value;
} }
CWindowOverridableVar(T const& value) : defaultValue{value} {} CWindowOverridableVar(T const& value) {
defaultValue = value;
}
CWindowOverridableVar() = default; CWindowOverridableVar() = default;
~CWindowOverridableVar() = default; ~CWindowOverridableVar() = default;
@@ -143,13 +144,6 @@ class CWindowOverridableVar {
unset(priority); unset(priority);
} }
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private: private:
std::map<eOverridePriority, T> values; std::map<eOverridePriority, T> values;
T defaultValue; // used for toggling, so required for bool T defaultValue; // used for toggling, so required for bool
@@ -180,14 +174,10 @@ struct SWindowData {
CWindowOverridableVar<bool> syncFullscreen = true; CWindowOverridableVar<bool> syncFullscreen = true;
CWindowOverridableVar<bool> tearing = false; CWindowOverridableVar<bool> tearing = false;
CWindowOverridableVar<bool> xray = false; CWindowOverridableVar<bool> xray = false;
CWindowOverridableVar<bool> renderUnfocused = false;
CWindowOverridableVar<int> rounding; CWindowOverridableVar<int> rounding;
CWindowOverridableVar<int> borderSize; CWindowOverridableVar<int> borderSize;
CWindowOverridableVar<float> scrollMouse;
CWindowOverridableVar<float> scrollTouchpad;
CWindowOverridableVar<std::string> animationStyle; CWindowOverridableVar<std::string> animationStyle;
CWindowOverridableVar<Vector2D> maxSize; CWindowOverridableVar<Vector2D> maxSize;
CWindowOverridableVar<Vector2D> minSize; CWindowOverridableVar<Vector2D> minSize;
@@ -196,12 +186,32 @@ struct SWindowData {
CWindowOverridableVar<CGradientValueData> inactiveBorderColor; CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
}; };
struct SWindowRule {
std::string szRule;
std::string szValue;
bool v2 = false;
std::string szTitle;
std::string szClass;
std::string szInitialTitle;
std::string szInitialClass;
std::string szTag;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
int bFullscreen = -1;
int bPinned = -1;
int bFocus = -1;
std::string szFullscreenState = ""; // empty means any
std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any
};
struct SInitialWorkspaceToken { struct SInitialWorkspaceToken {
PHLWINDOWREF primaryOwner; PHLWINDOWREF primaryOwner;
std::string workspace; std::string workspace;
}; };
struct SFullscreenState { struct sFullscreenState {
eFullscreenMode internal = FSMODE_NONE; eFullscreenMode internal = FSMODE_NONE;
eFullscreenMode client = FSMODE_NONE; eFullscreenMode client = FSMODE_NONE;
}; };
@@ -260,13 +270,13 @@ class CWindow {
bool m_bIsFloating = false; bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bWasMaximized = false; bool m_bWasMaximized = false;
SFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE}; sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
MONITORID m_iMonitorID = -1;
std::string m_szTitle = ""; std::string m_szTitle = "";
std::string m_szClass = ""; std::string m_szClass = "";
std::string m_szInitialTitle = ""; std::string m_szInitialTitle = "";
std::string m_szInitialClass = ""; std::string m_szInitialClass = "";
PHLWORKSPACE m_pWorkspace; PHLWORKSPACE m_pWorkspace;
PHLMONITORREF m_pMonitor;
bool m_bIsMapped = false; bool m_bIsMapped = false;
@@ -278,6 +288,8 @@ class CWindow {
// XWayland stuff // XWayland stuff
bool m_bIsX11 = false; bool m_bIsX11 = false;
PHLWINDOWREF m_pX11Parent; PHLWINDOWREF m_pX11Parent;
uint64_t m_iX11Type = 0;
bool m_bIsModal = false;
bool m_bX11DoesntWantBorders = false; bool m_bX11DoesntWantBorders = false;
bool m_bX11ShouldntFocus = false; bool m_bX11ShouldntFocus = false;
float m_fX11SurfaceScaledBy = 1.f; float m_fX11SurfaceScaledBy = 1.f;
@@ -314,9 +326,6 @@ class CWindow {
// For pinned (sticky) windows // For pinned (sticky) windows
bool m_bPinned = false; bool m_bPinned = false;
// For preserving pinned state when fullscreening a pinned window
bool m_bPinFullscreened = false;
// urgency hint // urgency hint
bool m_bIsUrgent = false; bool m_bIsUrgent = false;
@@ -325,8 +334,8 @@ class CWindow {
// Window decorations // Window decorations
// TODO: make this a SP. // TODO: make this a SP.
std::vector<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations; std::deque<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations;
std::vector<IHyprWindowDecoration*> m_vDecosToRemove; std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
// Special render data, rules, etc // Special render data, rules, etc
SWindowData m_sWindowData; SWindowData m_sWindowData;
@@ -338,18 +347,13 @@ class CWindow {
CAnimatedVariable<float> m_fActiveInactiveAlpha; CAnimatedVariable<float> m_fActiveInactiveAlpha;
// animated shadow color // animated shadow color
CAnimatedVariable<CHyprColor> m_cRealShadowColor; CAnimatedVariable<CColor> m_cRealShadowColor;
// animated tint // animated tint
CAnimatedVariable<float> m_fDimPercent; CAnimatedVariable<float> m_fDimPercent;
// animate moving to an invisible workspace
int m_iMonitorMovedFrom = -1; // -1 means not moving
CAnimatedVariable<float> m_fMovingToWorkspaceAlpha;
// swallowing // swallowing
PHLWINDOWREF m_pSwallowed; PHLWINDOWREF m_pSwallowed;
bool m_bGroupSwallowed = false;
// focus stuff // focus stuff
bool m_bStayFocused = false; bool m_bStayFocused = false;
@@ -376,13 +380,13 @@ class CWindow {
bool m_bTearingHint = false; bool m_bTearingHint = false;
// stores the currently matched window rules // stores the currently matched window rules
std::vector<SP<CWindowRule>> m_vMatchedRules; std::vector<SWindowRule> m_vMatchedRules;
// window tags // window tags
CTagKeeper m_tags; CTagKeeper m_tags;
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) const { bool operator==(const CWindow& rhs) {
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
m_bFadingOut == rhs.m_bFadingOut; m_bFadingOut == rhs.m_bFadingOut;
} }
@@ -391,6 +395,7 @@ class CWindow {
CBox getFullWindowBoundingBox(); CBox getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents(); SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props); CBox getWindowBoxUnified(uint64_t props);
CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved(); CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco); void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos(); void updateWindowDecos();
@@ -403,12 +408,12 @@ class CWindow {
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 SWindowRule& r);
void updateDynamicRules(); void updateDynamicRules();
SBoxExtents getFullWindowReservedArea(); SBoxExtents getFullWindowReservedArea();
Vector2D middle(); Vector2D middle();
@@ -416,24 +421,24 @@ class CWindow {
float rounding(); float rounding();
bool canBeTorn(); bool canBeTorn();
void setSuspended(bool suspend); void setSuspended(bool suspend);
bool visibleOnMonitor(PHLMONITOR pMonitor); bool visibleOnMonitor(CMonitor* pMonitor);
WORKSPACEID workspaceID(); WORKSPACEID workspaceID();
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);
bool isFullscreen(); bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode); bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize(); int getRealBorderSize();
float getScrollMouse();
float getScrollTouchpad();
void updateWindowData(); void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&); void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(void* ptr); void onBorderAngleAnimEnd(void* ptr);
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();
@@ -456,17 +461,9 @@ class CWindow {
void onResourceChangeX11(); void onResourceChangeX11();
std::string fetchTitle(); std::string fetchTitle();
std::string fetchClass(); std::string fetchClass();
void warpCursor(bool force = false); void warpCursor();
PHLWINDOW getSwallower(); PHLWINDOW getSwallower();
void unsetWindowData(eOverridePriority priority); void unsetWindowData(eOverridePriority priority);
bool isX11OverrideRedirect();
bool isModal();
Vector2D requestedMinSize();
Vector2D requestedMaxSize();
CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
// listeners // listeners
void onAck(uint32_t serial); void onAck(uint32_t serial);
@@ -553,7 +550,7 @@ struct std::formatter<PHLWINDOW, CharT> : std::formatter<CharT> {
if (formatWorkspace) if (formatWorkspace)
std::format_to(out, ", workspace: {}", w->m_pWorkspace ? 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->m_iMonitorID);
if (formatClass) if (formatClass)
std::format_to(out, ", class: {}", w->m_szClass); std::format_to(out, ", class: {}", w->m_szClass);
return std::format_to(out, "]"); return std::format_to(out, "]");

View File

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

View File

@@ -1,60 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
class CWindowRule {
public:
CWindowRule(const std::string& rule, const std::string& value, bool isV2 = false, bool isExecRule = false);
enum eRuleType : uint8_t {
RULE_INVALID = 0,
RULE_FLOAT,
RULE_FULLSCREEN,
RULE_MAXIMIZE,
RULE_NOINITIALFOCUS,
RULE_PIN,
RULE_STAYFOCUSED,
RULE_TILE,
RULE_RENDERUNFOCUSED,
RULE_ANIMATION,
RULE_BORDERCOLOR,
RULE_CENTER,
RULE_FULLSCREENSTATE,
RULE_GROUP,
RULE_IDLEINHIBIT,
RULE_MAXSIZE,
RULE_MINSIZE,
RULE_MONITOR,
RULE_MOVE,
RULE_OPACITY,
RULE_PLUGIN,
RULE_PSEUDO,
RULE_SIZE,
RULE_SUPPRESSEVENT,
RULE_TAG,
RULE_WORKSPACE,
RULE_PROP,
};
eRuleType ruleType = RULE_INVALID;
const std::string szValue;
const std::string szRule;
const bool v2 = false;
const bool execRule = false;
std::string szTitle;
std::string szClass;
std::string szInitialTitle;
std::string szInitialClass;
std::string szTag;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
int bFullscreen = -1;
int bPinned = -1;
int bFocus = -1;
std::string szFullscreenState = ""; // empty means any
std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any
};

View File

@@ -5,15 +5,18 @@
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) { PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) {
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitor, name, special, isEmpty); PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmtpy);
workspace->init(workspace); workspace->init(workspace);
return workspace; return workspace;
} }
CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) : CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) {
m_iID(id), m_szName(name), m_pMonitor(monitor), m_bIsSpecialWorkspace(special), m_bWasCreatedEmpty(isEmpty) { m_iMonitorID = monitorID;
; m_iID = id;
m_szName = name;
m_bIsSpecialWorkspace = special;
m_bWasCreatedEmtpy = isEmtpy;
} }
void CWorkspace::init(PHLWORKSPACE self) { void CWorkspace::init(PHLWORKSPACE self) {
@@ -23,12 +26,18 @@ void CWorkspace::init(PHLWORKSPACE self) {
g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), g_pConfigManager->getAnimationPropertyConfig("workspacesIn"),
self, AVARDAMAGE_ENTIRE); self, AVARDAMAGE_ENTIRE);
m_fAlpha.create(AVARTYPE_FLOAT, m_fAlpha.create(AVARTYPE_FLOAT,
m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), self, m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("fadeSpecialWorkspaceIn") :
AVARDAMAGE_ENTIRE); g_pConfigManager->getAnimationPropertyConfig("fadeWorkspacesIn"),
self, AVARDAMAGE_ENTIRE);
m_fAlpha.setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
m_fScaleClients.create(
AVARTYPE_FLOAT, m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : g_pConfigManager->getAnimationPropertyConfig("workspacesIn"),
self, AVARDAMAGE_ENTIRE);
m_fScaleClients.setValueAndWarp(1.f);
m_vRenderOffset.registerVar(); m_vRenderOffset.registerVar();
m_fAlpha.registerVar(); m_fAlpha.registerVar();
m_fScaleClients.registerVar();
const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self); const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self);
if (RULEFORTHIS.defaultName.has_value()) if (RULEFORTHIS.defaultName.has_value())
@@ -46,9 +55,9 @@ void CWorkspace::init(PHLWORKSPACE self) {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self);
m_bPersistent = WORKSPACERULE.isPersistent; m_bPersistent = WORKSPACERULE.isPersistent;
if (self->m_bWasCreatedEmpty) if (self->m_bWasCreatedEmtpy)
if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd)
g_pKeybindManager->spawnWithRules(*cmd, self); g_pKeybindManager->spawn(*cmd);
g_pEventManager->postEvent({"createworkspace", m_szName}); g_pEventManager->postEvent({"createworkspace", m_szName});
g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)}); g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)});
@@ -80,18 +89,20 @@ CWorkspace::~CWorkspace() {
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_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out"); const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out");
const std::string ANIMNAME2 = std::format("fade{}{}", m_bIsSpecialWorkspace ? "SpecialWorkspace" : "Workspaces", in ? "In" : "Out");
m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME2);
m_vRenderOffset.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); m_vRenderOffset.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME);
m_fScaleClients.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME);
} }
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle; const auto ANIMSTYLE = m_vRenderOffset.m_pConfig->pValues->internalStyle;
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
// set floating windows offset callbacks // set floating windows offset callbacks
m_vRenderOffset.setUpdateCallback([&](void*) { m_vRenderOffset.setUpdateCallback([&](void*) {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!validMapped(w) || w->workspaceID() != m_iID) if (!validMapped(w) || w->workspaceID() != m_iID)
continue; continue;
@@ -99,95 +110,73 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
}; };
}); });
if (ANIMSTYLE.starts_with("slidefade")) { m_fAlpha.setValueAndWarp(in ? 0.F : 1.F);
const auto PMONITOR = m_pMonitor.lock(); m_fAlpha = in ? 1.F : 0.F;
float movePerc = 100.f;
// handle animation styles for the movement one
if (m_vRenderOffset.m_pConfig->pValues->internalEnabled) {
if (ANIMSTYLE.starts_with("slide") && ANIMSTYLE.contains("%")) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
float movePerc = 0.F;
if (ANIMSTYLE.find('%') != std::string::npos) {
try { try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1); auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1);
movePerc = std::stoi(percstr.substr(0, percstr.length() - 1)); movePerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); } } catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); }
}
m_fAlpha.setValueAndWarp(1.f); m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); m_fScaleClients.setValueAndWarp(1.F);
if (ANIMSTYLE.starts_with("slidevert")) {
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
m_vRenderOffset = Vector2D(0, 0);
} else
m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_fAlpha.setValueAndWarp(1.f); if (in) {
m_fAlpha = 0.f; m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0));
m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); m_vRenderOffset = Vector2D(0, 0);
} else
m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0);
}
} else if (ANIMSTYLE.starts_with("popin")) {
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
float startPerc = 0.F;
try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1);
startPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); }
if (in) {
m_fScaleClients.setValueAndWarp(startPerc / 100.F);
m_fScaleClients = 1.F;
} else {
m_fScaleClients.setValueAndWarp(1.F);
m_fScaleClients = startPerc / 100.F;
} }
} else { } else {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
m_fScaleClients.setValueAndWarp(1.F);
if (in) { if (in) {
m_fAlpha.setValueAndWarp(0.f); m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0));
m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else
m_fAlpha.setValueAndWarp(1.f); m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
m_fAlpha = 0.f;
m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0);
}
}
} else if (ANIMSTYLE == "fade") {
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade.
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_fAlpha = 1.f;
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
}
} else if (ANIMSTYLE == "slidevert") {
// fallback is slide
const auto PMONITOR = m_pMonitor.lock();
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
}
} else {
// fallback is slide
const auto PMONITOR = m_pMonitor.lock();
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
}
}
if (m_bIsSpecialWorkspace) {
// required for open/close animations
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_fAlpha = 1.f;
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
} }
} }
if (instant) { if (instant) {
m_vRenderOffset.warp(); m_vRenderOffset.warp();
m_fAlpha.warp(); m_fAlpha.warp();
m_fScaleClients.warp();
} }
} }
@@ -221,7 +210,7 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
m_sPrevWorkspace.id = prev->m_iID; m_sPrevWorkspace.id = prev->m_iID;
m_sPrevWorkspace.name = prev->m_szName; m_sPrevWorkspace.name = prev->m_szName;
if (prev->m_pMonitor == m_pMonitor) { if (prev->m_iMonitorID == m_iMonitorID) {
m_sPrevWorkspacePerMonitor.id = prev->m_iID; m_sPrevWorkspacePerMonitor.id = prev->m_iID;
m_sPrevWorkspacePerMonitor.name = prev->m_szName; m_sPrevWorkspacePerMonitor.name = prev->m_szName;
} }
@@ -275,9 +264,9 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
// f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states // f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states
// -1: no fullscreen, 0: fullscreen, 1: maximized, 2: fullscreen without sending fs state to window // -1: no fullscreen, 0: fullscreen, 1: maximized, 2: fullscreen without sending fs state to window
const auto CLOSING_BRACKET = selector.find_first_of(']', i); const auto NEXTSPACE = selector.find_first_of(' ', i);
std::string prop = selector.substr(i, CLOSING_BRACKET == std::string::npos ? std::string::npos : CLOSING_BRACKET + 1 - i); std::string prop = selector.substr(i, NEXTSPACE == std::string::npos ? std::string::npos : NEXTSPACE - i);
i = std::min(CLOSING_BRACKET, std::string::npos - 1); i = std::min(NEXTSPACE, std::string::npos - 1);
if (cur == 'r') { if (cur == 'r') {
WORKSPACEID from = 0, to = 0; WORKSPACEID from = 0, to = 0;
@@ -293,7 +282,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false; return false;
} }
const auto DASHPOS = prop.find('-'); const auto DASHPOS = prop.find("-");
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1); const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) { if (!isNumber(LHS) || !isNumber(RHS)) {
@@ -329,7 +318,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto SHOULDBESPECIAL = configStringToInt(prop); const auto SHOULDBESPECIAL = configStringToInt(prop);
if (SHOULDBESPECIAL && (bool)*SHOULDBESPECIAL != m_bIsSpecialWorkspace) if ((bool)SHOULDBESPECIAL != m_bIsSpecialWorkspace)
return false; return false;
continue; continue;
} }
@@ -344,7 +333,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_pMonitor : false)) if (!(PMONITOR ? PMONITOR->ID == m_iMonitorID : false))
return false; return false;
continue; continue;
} }
@@ -364,7 +353,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto WANTSNAMED = configStringToInt(prop); const auto WANTSNAMED = configStringToInt(prop);
if (WANTSNAMED && *WANTSNAMED != (m_iID <= -1337)) if (WANTSNAMED != (m_iID <= -1337))
return false; return false;
continue; continue;
} }
@@ -383,7 +372,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
bool wantsCountVisible = false; bool wantsCountVisible = false;
int flagCount = 0; int flagCount = 0;
for (auto const& flag : prop) { for (auto& flag : prop) {
if (flag == 't' && wantsOnlyTiled == -1) { if (flag == 't' && wantsOnlyTiled == -1) {
wantsOnlyTiled = 1; wantsOnlyTiled = 1;
flagCount++; flagCount++;
@@ -419,18 +408,18 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
int count; int count;
if (wantsCountGroup) if (wantsCountGroup)
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (count != from) if (count != from)
return false; return false;
continue; continue;
} }
const auto DASHPOS = prop.find('-'); const auto DASHPOS = prop.find("-");
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1); const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) { if (!isNumber(LHS) || !isNumber(RHS)) {
@@ -453,11 +442,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
WORKSPACEID count; WORKSPACEID count;
if (wantsCountGroup) if (wantsCountGroup)
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (std::clamp(count, from, to) != count) if (std::clamp(count, from, to) != count)
return false; return false;
@@ -509,151 +498,12 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
} }
void CWorkspace::markInert() { void CWorkspace::markInert() {
m_bInert = true; m_bInert = true;
m_iID = WORKSPACE_INVALID; m_iID = WORKSPACE_INVALID;
m_bVisible = false; m_iMonitorID = MONITOR_INVALID;
m_pMonitor.reset(); m_bVisible = false;
} }
bool CWorkspace::inert() { bool CWorkspace::inert() {
return m_bInert; return m_bInert;
} }
MONITORID CWorkspace::monitorID() {
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID;
}
PHLWINDOW CWorkspace::getFullscreenWindow() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->isFullscreen())
return w;
}
return nullptr;
}
bool CWorkspace::isVisible() {
return m_bVisible;
}
bool CWorkspace::isVisibleNotCovered() {
const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR->activeSpecialWorkspace)
return PMONITOR->activeSpecialWorkspace->m_iID == m_iID;
return PMONITOR->activeWorkspace->m_iID == m_iID;
}
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
}
return no;
}
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue;
if (!w->m_sGroupData.head)
continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
}
return no;
}
PHLWINDOW CWorkspace::getFirstWindow() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && !w->isHidden())
return w;
}
return nullptr;
}
PHLWINDOW CWorkspace::getTopLeftWindow() {
const auto PMONITOR = m_pMonitor.lock();
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue;
const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
if (WINDOWIDEALBB.x <= PMONITOR->vecPosition.x + 1 && WINDOWIDEALBB.y <= PMONITOR->vecPosition.y + 1)
return w;
}
return nullptr;
}
bool CWorkspace::hasUrgentWindow() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && w->m_bIsUrgent)
return true;
}
return false;
}
void CWorkspace::updateWindowDecos() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf)
continue;
w->updateWindowDecos();
}
}
void CWorkspace::updateWindowData() {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock());
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf)
continue;
w->updateWindowData(WORKSPACERULE);
}
}
void CWorkspace::forceReportSizesToWindows() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue;
g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true);
}
}
void CWorkspace::rename(const std::string& name) {
if (g_pCompositor->isWorkspaceSpecial(m_iID))
return;
Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name);
m_szName = name;
g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName});
}
void CWorkspace::updateWindows() {
m_bHasFullscreenWindow = std::ranges::any_of(g_pCompositor->m_vWindows, [this](const auto& w) { return w->m_bIsMapped && w->m_pWorkspace == m_pSelf && w->isFullscreen(); });
for (auto const& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_pWorkspace != m_pSelf)
continue;
w->updateDynamicRules();
}
}

View File

@@ -17,16 +17,16 @@ class CWindow;
class CWorkspace { class CWorkspace {
public: public:
static PHLWORKSPACE create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true); static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmtpy = true);
// use create() don't use this // use create() don't use this
CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true); CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true);
~CWorkspace(); ~CWorkspace();
// Workspaces ID-based have IDs > 0 // Workspaces ID-based have IDs > 0
// and workspaces name-based have IDs starting with -1337 // and workspaces name-based have IDs starting with -1337
WORKSPACEID m_iID = WORKSPACE_INVALID; WORKSPACEID m_iID = WORKSPACE_INVALID;
std::string m_szName = ""; std::string m_szName = "";
PHLMONITORREF m_pMonitor; MONITORID m_iMonitorID = MONITOR_INVALID;
// 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_sPrevWorkspace, m_sPrevWorkspacePerMonitor; SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor;
@@ -39,6 +39,7 @@ class CWorkspace {
// for animations // for animations
CAnimatedVariable<Vector2D> m_vRenderOffset; CAnimatedVariable<Vector2D> m_vRenderOffset;
CAnimatedVariable<float> m_fAlpha; CAnimatedVariable<float> m_fAlpha;
CAnimatedVariable<float> m_fScaleClients;
bool m_bForceRendering = false; bool m_bForceRendering = false;
// allows damage to propagate. // allows damage to propagate.
@@ -57,35 +58,28 @@ class CWorkspace {
// last monitor (used on reconnect) // last monitor (used on reconnect)
std::string m_szLastMonitor = ""; std::string m_szLastMonitor = "";
bool m_bWasCreatedEmpty = true; bool m_bWasCreatedEmtpy = true;
bool m_bPersistent = 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();
void startAnim(bool in, bool left, bool instant = false); void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on); void setActive(bool on);
void moveToMonitor(const MONITORID&); void moveToMonitor(const MONITORID&);
MONITORID monitorID();
PHLWINDOW getLastFocusedWindow(); PHLWINDOW getLastFocusedWindow();
void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);
std::string getConfigName(); std::string getConfigName();
bool matchesStaticSelector(const std::string& selector); bool matchesStaticSelector(const std::string& selector);
void markInert(); void markInert();
SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const; SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const;
void updateWindowDecos();
void updateWindowData();
int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
bool hasUrgentWindow();
PHLWINDOW getFirstWindow();
PHLWINDOW getTopLeftWindow();
PHLWINDOW getFullscreenWindow();
bool isVisible();
bool isVisibleNotCovered();
void rename(const std::string& name = "");
void forceReportSizesToWindows();
void updateWindows();
private: private:
void init(PHLWORKSPACE self); void init(PHLWORKSPACE self);

View File

@@ -4,14 +4,14 @@
#include <string> #include <string>
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
enum eHIDCapabilityType : uint8_t { enum eHIDCapabilityType : uint32_t {
HID_INPUT_CAPABILITY_KEYBOARD = (1 << 0), HID_INPUT_CAPABILITY_KEYBOARD = (1 << 0),
HID_INPUT_CAPABILITY_POINTER = (1 << 1), HID_INPUT_CAPABILITY_POINTER = (1 << 1),
HID_INPUT_CAPABILITY_TOUCH = (1 << 2), HID_INPUT_CAPABILITY_TOUCH = (1 << 2),
HID_INPUT_CAPABILITY_TABLET = (1 << 3), HID_INPUT_CAPABILITY_TABLET = (1 << 3),
}; };
enum eHIDType : uint8_t { enum eHIDType {
HID_TYPE_UNKNOWN = 0, HID_TYPE_UNKNOWN = 0,
HID_TYPE_POINTER, HID_TYPE_POINTER,
HID_TYPE_KEYBOARD, HID_TYPE_KEYBOARD,
@@ -27,7 +27,7 @@ enum eHIDType : uint8_t {
*/ */
class IHID { class IHID {
public: public:
virtual ~IHID() = default; virtual ~IHID() {}
virtual uint32_t getCapabilities() = 0; virtual uint32_t getCapabilities() = 0;
virtual eHIDType getType(); virtual eHIDType getType();
@@ -36,5 +36,5 @@ class IHID {
CSignal destroy; CSignal destroy;
} events; } events;
std::string deviceName, hlName; std::string deviceName;
}; };

View File

@@ -178,18 +178,13 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (xkbState) if (xkbState)
xkb_state_unref(xkbState); xkb_state_unref(xkbState);
if (xkbSymState)
xkb_state_unref(xkbSymState);
xkbState = nullptr; xkbState = nullptr;
xkbStaticState = nullptr; xkbStaticState = 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);
xkbStaticState = xkb_state_new(keymap); xkbStaticState = xkb_state_new(keymap);
xkbState = xkb_state_new(keymap); xkbState = xkb_state_new(keymap);
xkbSymState = xkb_state_new(keymap);
return; return;
} }
@@ -235,7 +230,6 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkbState = xkb_state_new(KEYMAP); xkbState = xkb_state_new(KEYMAP);
xkbStaticState = xkb_state_new(KEYMAP); xkbStaticState = 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);
@@ -258,7 +252,6 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkbState = xkb_state_new(NEWKEYMAP); xkbState = xkb_state_new(NEWKEYMAP);
xkbStaticState = xkb_state_new(NEWKEYMAP); xkbStaticState = 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);
@@ -339,9 +332,6 @@ void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t l
xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group); xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group);
if (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, group);
if (!updateModifiersState()) if (!updateModifiersState())
return; return;
@@ -392,9 +382,6 @@ void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
xkb_state_update_key(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 (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, modifiersState.group);
keyboardEvents.modifiers.emit(SModifiersEvent{ keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed, .depressed = modifiersState.depressed,
.latched = modifiersState.latched, .latched = modifiersState.latched,

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
@@ -82,9 +83,8 @@ class IKeyboard : public IHID {
bool keymapOverridden = false; bool keymapOverridden = false;
xkb_layout_index_t activeLayout = 0; xkb_layout_index_t activeLayout = 0;
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = 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 */; xkb_keymap* xkbKeymap = nullptr;
xkb_keymap* xkbKeymap = nullptr;
struct { struct {
uint32_t depressed = 0, latched = 0, locked = 0, group = 0; uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
@@ -94,6 +94,7 @@ class IKeyboard : public IHID {
std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID}; std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID};
uint32_t leds = 0; uint32_t leds = 0;
std::string hlName = "";
std::string xkbFilePath = ""; std::string xkbFilePath = "";
std::string xkbKeymapString = ""; std::string xkbKeymapString = "";
int xkbKeymapFD = -1; int xkbKeymapFD = -1;

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
@@ -19,7 +20,6 @@ class IPointer : public IHID {
struct SMotionEvent { struct SMotionEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;
Vector2D delta, unaccel; Vector2D delta, unaccel;
bool mouse = false;
}; };
struct SMotionAbsoluteEvent { struct SMotionAbsoluteEvent {
@@ -32,7 +32,6 @@ class IPointer : public IHID {
uint32_t timeMs = 0; uint32_t timeMs = 0;
uint32_t button = 0; uint32_t button = 0;
wl_pointer_button_state state = WL_POINTER_BUTTON_STATE_PRESSED; wl_pointer_button_state state = WL_POINTER_BUTTON_STATE_PRESSED;
bool mouse = false;
}; };
struct SAxisEvent { struct SAxisEvent {
@@ -42,7 +41,6 @@ class IPointer : public IHID {
wl_pointer_axis_relative_direction relativeDirection = WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL; wl_pointer_axis_relative_direction relativeDirection = WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL;
double delta = 0.0; double delta = 0.0;
int32_t deltaDiscrete = 0; int32_t deltaDiscrete = 0;
bool mouse = false;
}; };
struct SSwipeBeginEvent { struct SSwipeBeginEvent {
@@ -107,6 +105,7 @@ class IPointer : public IHID {
CSignal holdEnd; CSignal holdEnd;
} pointerEvents; } pointerEvents;
std::string hlName;
bool connected = false; // means connected to the cursor bool connected = false; // means connected to the cursor
std::string boundOutput = ""; std::string boundOutput = "";

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
@@ -44,6 +45,7 @@ class ITouch : public IHID {
CSignal frame; CSignal frame;
} touchEvents; } touchEvents;
std::string hlName = "";
std::string boundOutput = ""; std::string boundOutput = "";
WP<ITouch> self; WP<ITouch> self;

View File

@@ -26,7 +26,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.timeMs = E.timeMs, .timeMs = E.timeMs,
.delta = E.delta, .delta = E.delta,
.unaccel = E.unaccel, .unaccel = E.unaccel,
.mouse = true,
}); });
}); });
@@ -47,7 +46,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.timeMs = E.timeMs, .timeMs = E.timeMs,
.button = E.button, .button = E.button,
.state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED, .state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
.mouse = true,
}); });
}); });
@@ -61,7 +59,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.relativeDirection = (wl_pointer_axis_relative_direction)E.direction, .relativeDirection = (wl_pointer_axis_relative_direction)E.direction,
.delta = E.delta, .delta = E.delta,
.deltaDiscrete = E.discrete, .deltaDiscrete = E.discrete,
.mouse = true,
}); });
}); });

View File

@@ -197,7 +197,7 @@ CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
}); });
}); });
listeners.attach = pad->events.attach.registerListener([](std::any d) { listeners.attach = pad->events.attach.registerListener([this](std::any d) {
; // TODO: this doesn't do anything in aq atm ; // TODO: this doesn't do anything in aq atm
}); });

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