Compare commits

..

25 Commits

Author SHA1 Message Date
Vaxry
882f7ad7d2 version: bump to 0.47.2 2025-02-02 00:47:17 +00:00
Vaxry
3822673c05 desktop: move popups to UPs and fix missing subsurface resource
fixes #9283
2025-02-02 00:47:17 +00:00
Vaxry
bdbfa93371 popup: take xdg geometry into account in input calcs
fixes #9023
2025-02-02 00:47:17 +00:00
Vaxry
f827690983 desktop: move popup and subsurface ctors to factories
makes sure m_pSelf is set before we do anything like possibly adding children

fixes #9275

supersedes #9276
2025-02-02 00:47:17 +00:00
Maximilian Seidler
ff8b5b70fa animation: don't immediately disconnect active vars during tick (#9272) 2025-02-02 00:47:17 +00:00
nyx
3236566939 xwayland: correct pointer coordinate mismatch in X11 windows (#9259)
refactor(xwayland): add back comments
2025-02-02 00:47:17 +00:00
Mihai Fufezan
dd64757602 configWatcher: watch both symlinks and canonical paths (#9219) 2025-02-02 00:47:16 +00:00
Brayden Zee
047ea02820 desktop: fix segfault when destroying a partially create layer surface (#9247) 2025-02-02 00:45:37 +00:00
nyx
c8eec1916d xwayland: prevent invalid window configurations for X11 apps (#9253)
* fix(xwayland): prevent invalid window configurations for X11 apps

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

View File

@@ -35,7 +35,6 @@ runs:
libinput \ libinput \
libjxl \ libjxl \
libliftoff \ libliftoff \
libspng \
libwebp \ libwebp \
libxcursor \ libxcursor \
libxcvt \ libxcvt \

View File

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

View File

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

View File

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

View File

@@ -77,7 +77,6 @@ add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}")
include_directories(. "src/" "protocols/") include_directories(. "src/" "protocols/")
set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD 26)
set(CXX_STANDARD_REQUIRED ON)
add_compile_options( add_compile_options(
-Wall -Wall
-Wextra -Wextra
@@ -102,21 +101,13 @@ else()
endif() endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.8.0) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5)
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2)
pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7)
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.1) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.0)
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION})
list(GET AQ_VERSION_LIST 0 AQ_VERSION_MAJOR)
list(GET AQ_VERSION_LIST 1 AQ_VERSION_MINOR)
list(GET AQ_VERSION_LIST 2 AQ_VERSION_PATCH)
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
add_compile_definitions(AQUAMARINE_VERSION_MAJOR=${AQ_VERSION_MAJOR})
add_compile_definitions(AQUAMARINE_VERSION_MINOR=${AQ_VERSION_MINOR})
add_compile_definitions(AQUAMARINE_VERSION_PATCH=${AQ_VERSION_PATCH})
add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}") add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}")
add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}") add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}")
add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}") add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}")
@@ -129,7 +120,7 @@ pkg_check_modules(
xkbcommon xkbcommon
uuid uuid
wayland-server>=1.22.90 wayland-server>=1.22.90
wayland-protocols>=1.41 wayland-protocols
cairo cairo
pango pango
pangocairo pangocairo
@@ -313,7 +304,7 @@ endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.2) pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.0)
if(hyprland_protocols_dep_FOUND) if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
@@ -377,8 +368,6 @@ protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false) protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
protocolnew("staging/security-context" "security-context-v1" false) protocolnew("staging/security-context" "security-context-v1" false)
protocolnew("staging/content-type" "content-type-v1" false)
protocolnew("staging/color-management" "color-management-v1" false)
protocolwayland() protocolwayland()
@@ -444,5 +433,4 @@ install(
DIRECTORY ${HEADERS_SRC} DIRECTORY ${HEADERS_SRC}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING FILES_MATCHING
PATTERN "*.h*" PATTERN "*.h*")
PATTERN "*.frag")

View File

@@ -1 +1 @@
0.48.1 0.47.2

View File

@@ -139,10 +139,10 @@ animations {
# uncomment all if you wish to use that. # uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] # windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrule = rounding 0, floating:0, onworkspace:w[tv1] # windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrule = bordersize 0, floating:0, onworkspace:f[1] # windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrule = rounding 0, floating:0, onworkspace:f[1] # windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
@@ -276,11 +276,14 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules # See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule # Example windowrule v1
# windowrule = float,class:^(kitty)$,title:^(kitty)$ # windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.* windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland # Fix some dragging issues with XWayland
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0

137
flake.lock generated
View File

@@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1742213273, "lastModified": 1737636397,
"narHash": "sha256-0l0vDb4anfsBu1rOs94bC73Hub+xEivgBAo6QXl2MmU=", "narHash": "sha256-F5MbBj3QVorycVSFE9qjuOTLtIQBqt2VWbXa0uwzm98=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "484b732195cc53f4536ce4bd59a5c6402b1e7ccf", "rev": "7fe006981fae53e931f513026fc754e322f13145",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -79,11 +79,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1742215578, "lastModified": 1737634937,
"narHash": "sha256-zfs71PXVVPEe56WEyNi2TJQPs0wabU4WAlq0XV7GcdE=", "narHash": "sha256-Ffw4ujFpi++6pPHe+gCBOfDgAoNlzVPZN6MReC1beu8=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "2fd36421c21aa87e2fe3bee11067540ae612f719", "rev": "9c5dd1f7c825ee47f72727ad0a4e16ca46a2688e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -105,11 +105,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1739049071, "lastModified": 1737634889,
"narHash": "sha256-3+7TpXMrbsUXSwgr5VAKAnmkzMb6JO+Rvc9XRb5NMg4=", "narHash": "sha256-9JZE3KxcXOqZH9zs3UeadngDiK/yIACTiAR8HSA/TNI=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprgraphics", "repo": "hyprgraphics",
"rev": "175c6b29b6ff82100539e7c4363a35a02c74dd73", "rev": "0d77b4895ad5f1bb3b0ee43103a5246c58b65591",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -128,11 +128,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1738422629, "lastModified": 1737556638,
"narHash": "sha256-5v+bv75wJWvahyM2xcMTSNNxmV8a7hb01Eey5zYnBJw=", "narHash": "sha256-laKgI3mr2qz6tas/q3tuGPxMdsGhBi/w+HO+hO2f1AY=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "755aef8dab49d0fc4663c715fa4ad221b2aedaed", "rev": "4c75dd5c015c8a0e5a34c6d02a018a650f57feb5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -143,10 +143,7 @@
}, },
"hyprland-qt-support": { "hyprland-qt-support": {
"inputs": { "inputs": {
"hyprlang": [ "hyprlang": "hyprlang",
"hyprland-qtutils",
"hyprlang"
],
"nixpkgs": [ "nixpkgs": [
"hyprland-qtutils", "hyprland-qtutils",
"nixpkgs" "nixpkgs"
@@ -173,12 +170,7 @@
"hyprland-qtutils": { "hyprland-qtutils": {
"inputs": { "inputs": {
"hyprland-qt-support": "hyprland-qt-support", "hyprland-qt-support": "hyprland-qt-support",
"hyprlang": [
"hyprlang"
],
"hyprutils": [ "hyprutils": [
"hyprland-qtutils",
"hyprlang",
"hyprutils" "hyprutils"
], ],
"nixpkgs": [ "nixpkgs": [
@@ -189,11 +181,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1739048983, "lastModified": 1737811848,
"narHash": "sha256-REhTcXq4qs3B3cCDtLlYDz0GZvmsBSh947Ub6pQWGTQ=", "narHash": "sha256-WZ7LeiKHk5Y94MU5gHIWn0r8asWxYOvie4LqfCjVIZU=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-qtutils", "repo": "hyprland-qtutils",
"rev": "3504a293c8f8db4127cb0f7cfc1a318ffb4316f8", "rev": "9c0831ff98856c0f312fcb8b57553fbe3dd34d5b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -203,6 +195,34 @@
} }
}, },
"hyprlang": { "hyprlang": {
"inputs": {
"hyprutils": "hyprutils",
"nixpkgs": [
"hyprland-qtutils",
"hyprland-qt-support",
"nixpkgs"
],
"systems": [
"hyprland-qtutils",
"hyprland-qt-support",
"systems"
]
},
"locked": {
"lastModified": 1737634606,
"narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "f41271d35cc0f370d300413d756c2677f386af9d",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprlang",
"type": "github"
}
},
"hyprlang_2": {
"inputs": { "inputs": {
"hyprutils": [ "hyprutils": [
"hyprutils" "hyprutils"
@@ -215,11 +235,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741191527, "lastModified": 1737634606,
"narHash": "sha256-kM+11Nch47Xwfgtw2EpRitJuORy4miwoMuRi5tyMBDY=", "narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "72df3861f1197e41b078faa3e38eedd60e00018d", "rev": "f41271d35cc0f370d300413d756c2677f386af9d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -229,6 +249,35 @@
} }
}, },
"hyprutils": { "hyprutils": {
"inputs": {
"nixpkgs": [
"hyprland-qtutils",
"hyprland-qt-support",
"hyprlang",
"nixpkgs"
],
"systems": [
"hyprland-qtutils",
"hyprland-qt-support",
"hyprlang",
"systems"
]
},
"locked": {
"lastModified": 1737632363,
"narHash": "sha256-X9I8POSlHxBVjD0fiX1O2j7U9Zi1+4rIkrsyHP0uHXY=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "006620eb29d54ea9086538891404c78563d1bae1",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprutils",
"type": "github"
}
},
"hyprutils_2": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
@@ -238,11 +287,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741534688, "lastModified": 1737725508,
"narHash": "sha256-EV3945SnjOCuRVbGRghsWx/9D89FyshnSO1Q6/TuQ14=", "narHash": "sha256-jGmcPc6y/prg/4A8KGYqJ27nSPaProCMiFadaxNAKvA=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "dd1f720cbc2dbb3c71167c9598045dd3261d27b3", "rev": "fb0c2d1de3d1ef7396d19c18ac09e12bd956929e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -261,11 +310,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1739870480, "lastModified": 1735493474,
"narHash": "sha256-SiDN5BGxa/1hAsqhgJsS03C3t2QrLgBT8u+ENJ0Qzwc=", "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "206367a08dc5ac4ba7ad31bdca391d098082e64b", "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -276,11 +325,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1742069588, "lastModified": 1737632463,
"narHash": "sha256-C7jVfohcGzdZRF6DO+ybyG/sqpo1h6bZi9T56sxLy+k=", "narHash": "sha256-38J9QfeGSej341ouwzqf77WIHAScihAKCt8PQJ+NH28=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c80f6a7e10b39afcc1894e02ef785b1ad0b0d7e5", "rev": "0aa475546ed21629c4f5bbf90e38c846a99ec9e9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -299,11 +348,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1742058297, "lastModified": 1737465171,
"narHash": "sha256-b4SZc6TkKw8WQQssbN5O2DaCEzmFfvSTPYHlx/SFW9Y=", "narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=",
"owner": "cachix", "owner": "cachix",
"repo": "git-hooks.nix", "repo": "git-hooks.nix",
"rev": "59f17850021620cd348ad2e9c0c64f4e6325ce2a", "rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -319,8 +368,8 @@
"hyprgraphics": "hyprgraphics", "hyprgraphics": "hyprgraphics",
"hyprland-protocols": "hyprland-protocols", "hyprland-protocols": "hyprland-protocols",
"hyprland-qtutils": "hyprland-qtutils", "hyprland-qtutils": "hyprland-qtutils",
"hyprlang": "hyprlang", "hyprlang": "hyprlang_2",
"hyprutils": "hyprutils", "hyprutils": "hyprutils_2",
"hyprwayland-scanner": "hyprwayland-scanner", "hyprwayland-scanner": "hyprwayland-scanner",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks", "pre-commit-hooks": "pre-commit-hooks",
@@ -365,11 +414,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741934139, "lastModified": 1737634991,
"narHash": "sha256-ZhTcTH9FoeAtbPfWGrhkH7RjLJZ7GeF18nygLAMR+WE=", "narHash": "sha256-dBAnb7Kbnier30cA7AgxVSxxARmxKZ1vHZT33THSIr8=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "150b0b6f52bb422a1b232a53698606fe0320dde0", "rev": "e09dfe2726c8008f983e45a0aa1a3b7416aaeb8a",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

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

View File

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

View File

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

View File

@@ -463,9 +463,7 @@ bool CPluginManager::updateHeaders(bool force) {
return false; return false;
} }
const auto& HL_URL = m_szCustomHlUrl.empty() ? "https://github.com/hyprwm/Hyprland" : m_szCustomHlUrl; progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment."));
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning {}, this might take a moment.", HL_URL));
const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow; const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow;
@@ -476,12 +474,12 @@ bool CPluginManager::updateHeaders(bool force) {
if (m_bVerbose && bShallow) if (m_bVerbose && bShallow)
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE)); progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE));
std::string ret = std::string ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-{}{}", getTempRoot(), USERNAME,
execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}{}", getTempRoot(), HL_URL, USERNAME, (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""))); (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")));
if (!std::filesystem::exists(WORKINGDIR)) { if (!std::filesystem::exists(WORKINGDIR)) {
progress.printMessageAbove(failureString("Clone failed. Retrying without shallow.")); progress.printMessageAbove(failureString("Clone failed. Retrying without shallow."));
ret = execAndGet(std::format("cd {} && git clone --recursive {} hyprland-{}", getTempRoot(), HL_URL, USERNAME)); ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/hyprland hyprland-{}", getTempRoot(), USERNAME));
} }
if (!std::filesystem::exists(WORKINGDIR + "/.git")) { if (!std::filesystem::exists(WORKINGDIR + "/.git")) {

View File

@@ -62,7 +62,6 @@ class CPluginManager {
bool m_bVerbose = false; bool m_bVerbose = false;
bool m_bNoShallow = false; bool m_bNoShallow = false;
std::string m_szCustomHlUrl;
// will delete recursively if exists!! // will delete recursively if exists!!
bool createSafeDirectory(const std::string& path); bool createSafeDirectory(const std::string& path);

View File

@@ -29,7 +29,6 @@ constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
--verbose | -v Enable too much logging --verbose | -v Enable too much logging
--force | -f Force an operation ignoring checks (e.g. update -f) --force | -f Force an operation ignoring checks (e.g. update -f)
--no-shallow | -s Disable shallow cloning of Hyprland sources --no-shallow | -s Disable shallow cloning of Hyprland sources
--hl-url | Pass a custom hyprland source url
)#"; )#";
@@ -46,7 +45,6 @@ int main(int argc, char** argv, char** envp) {
std::vector<std::string> command; std::vector<std::string> command;
bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false; bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false;
std::string customHlUrl;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) { if (ARGS[i].starts_with("-")) {
@@ -61,13 +59,6 @@ int main(int argc, char** argv, char** envp) {
verbose = true; verbose = true;
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") { } else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
noShallow = true; noShallow = true;
} else if (ARGS[i] == "--hl-url") {
if (i + 1 >= argc) {
std::println(stderr, "Missing argument for --hl-url");
return 1;
}
customHlUrl = ARGS[i + 1];
i++;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") { } else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true; force = true;
std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing.")); std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing."));
@@ -75,9 +66,10 @@ int main(int argc, char** argv, char** envp) {
std::println(stderr, "Unrecognized option {}", ARGS[i]); std::println(stderr, "Unrecognized option {}", ARGS[i]);
return 1; return 1;
} }
} else } else {
command.push_back(ARGS[i]); command.push_back(ARGS[i]);
} }
}
if (command.empty()) { if (command.empty()) {
std::println(stderr, "{}", HELP); std::println(stderr, "{}", HELP);
@@ -87,7 +79,6 @@ int main(int argc, char** argv, char** envp) {
g_pPluginManager = std::make_unique<CPluginManager>(); g_pPluginManager = std::make_unique<CPluginManager>();
g_pPluginManager->m_bVerbose = verbose; g_pPluginManager->m_bVerbose = verbose;
g_pPluginManager->m_bNoShallow = noShallow; g_pPluginManager->m_bNoShallow = noShallow;
g_pPluginManager->m_szCustomHlUrl = customHlUrl;
if (command[0] == "add") { if (command[0] == "add") {
if (command.size() < 2) { if (command.size() < 2) {
@@ -165,8 +156,7 @@ int main(int argc, char** argv, char** envp) {
} else if (command[0] == "reload") { } else if (command[0] == "reload") {
auto ret = g_pPluginManager->ensurePluginsLoadState(force); auto ret = g_pPluginManager->ensurePluginsLoadState(force);
if (ret != LOADSTATE_OK) { if (ret != LOADSTATE_OK && notify) {
if (notify) {
switch (ret) { switch (ret) {
case LOADSTATE_FAIL: case LOADSTATE_FAIL:
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break; case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
@@ -175,8 +165,6 @@ int main(int argc, char** argv, char** envp) {
break; break;
default: break; default: break;
} }
}
return 1; return 1;
} else if (notify && !notifyFail) { } else if (notify && !notifyFail) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins"); g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");

View File

@@ -31,16 +31,12 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif endif
aquamarine = dependency('aquamarine', version: '>=0.8.0') aquamarine = dependency('aquamarine', version: '>=0.4.5')
hyprcursor = dependency('hyprcursor', version: '>=0.1.7') hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1') hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
hyprlang = dependency('hyprlang', version: '>= 0.3.2') hyprlang = dependency('hyprlang', version: '>= 0.3.2')
hyprutils = dependency('hyprutils', version: '>= 0.2.3') hyprutils = dependency('hyprutils', version: '>= 0.2.3')
aquamarine_version_list = aquamarine.version().split('.')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
add_project_arguments(['-DAQUAMARINE_VERSION_MAJOR=@0@'.format(aquamarine_version_list.get(0))], language: 'cpp')
add_project_arguments(['-DAQUAMARINE_VERSION_MINOR=@0@'.format(aquamarine_version_list.get(1))], language: 'cpp')
add_project_arguments(['-DAQUAMARINE_VERSION_PATCH=@0@'.format(aquamarine_version_list.get(2))], language: 'cpp')
add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp') add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp')
add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp') add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp')
add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp') add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp')
@@ -89,7 +85,7 @@ endif
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
# Install headers # Install headers
globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.frag', check: true) globber = run_command('find', 'src', '-name', '*.h*', check: true)
headers = globber.stdout().strip().split('\n') headers = globber.stdout().strip().split('\n')
foreach file : headers foreach file : headers
install_headers(file, subdir: 'hyprland', preserve_path: true) install_headers(file, subdir: 'hyprland', preserve_path: true)

View File

@@ -26,7 +26,7 @@
libinput, libinput,
libxkbcommon, libxkbcommon,
libuuid, libuuid,
libgbm, mesa,
pango, pango,
pciutils, pciutils,
re2, re2,
@@ -130,7 +130,7 @@ in
libinput libinput
libuuid libuuid
libxkbcommon libxkbcommon
libgbm mesa
pango pango
pciutils pciutils
re2 re2
@@ -155,7 +155,7 @@ in
mesonBuildType = mesonBuildType =
if debug if debug
then "debug" then "debugoptimized"
else "release"; else "release";
mesonFlags = flatten [ mesonFlags = flatten [

View File

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

View File

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

View File

@@ -1,13 +1,13 @@
wayland_protos = dependency( wayland_protos = dependency(
'wayland-protocols', 'wayland-protocols',
version: '>=1.41', version: '>=1.32',
fallback: 'wayland-protocols', fallback: 'wayland-protocols',
default_options: ['tests=false'], default_options: ['tests=false'],
) )
hyprland_protos = dependency( hyprland_protos = dependency(
'hyprland-protocols', 'hyprland-protocols',
version: '>=0.6.2', version: '>=0.6',
fallback: 'hyprland-protocols', fallback: 'hyprland-protocols',
) )
@@ -70,8 +70,6 @@ protocols = [
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
wayland_protocol_dir / 'staging/security-context/security-context-v1.xml', wayland_protocol_dir / 'staging/security-context/security-context-v1.xml',
wayland_protocol_dir / 'staging/content-type/content-type-v1.xml',
wayland_protocol_dir / 'staging/color-management/color-management-v1.xml',
] ]
wl_protocols = [] wl_protocols = []

View File

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

View File

@@ -1,4 +1,3 @@
#include <ranges>
#include <re2/re2.h> #include <re2/re2.h>
#include "Compositor.hpp" #include "Compositor.hpp"
@@ -13,7 +12,6 @@
#include "managers/SeatManager.hpp" #include "managers/SeatManager.hpp"
#include "managers/VersionKeeperManager.hpp" #include "managers/VersionKeeperManager.hpp"
#include "managers/DonationNagManager.hpp" #include "managers/DonationNagManager.hpp"
#include "managers/ANRManager.hpp"
#include "managers/eventLoop/EventLoopManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp"
#include <algorithm> #include <algorithm>
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
@@ -23,12 +21,15 @@
#include <print> #include <print>
#include <cstring> #include <cstring>
#include <filesystem> #include <filesystem>
#include <ranges>
#include <print>
#include <unordered_set> #include <unordered_set>
#include "debug/HyprCtl.hpp" #include "debug/HyprCtl.hpp"
#include "debug/CrashReporter.hpp" #include "debug/CrashReporter.hpp"
#ifdef USES_SYSTEMD #ifdef USES_SYSTEMD
#include <helpers/SdDaemon.hpp> // for SdNotify #include <helpers/SdDaemon.hpp> // for SdNotify
#endif #endif
#include "helpers/varlist/VarList.hpp"
#include "helpers/fs/FsUtils.hpp" #include "helpers/fs/FsUtils.hpp"
#include "protocols/FractionalScale.hpp" #include "protocols/FractionalScale.hpp"
#include "protocols/PointerConstraints.hpp" #include "protocols/PointerConstraints.hpp"
@@ -70,13 +71,9 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <malloc.h>
#include <unistd.h>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Aquamarine; using namespace Aquamarine;
using enum NContentType::eContentType;
using namespace NColorManagement;
static int handleCritSignal(int signo, void* data) { static int handleCritSignal(int signo, void* data) {
Debug::log(LOG, "Hyprland received signal {}", signo); Debug::log(LOG, "Hyprland received signal {}", signo);
@@ -166,22 +163,10 @@ void CCompositor::restoreNofile() {
Debug::log(ERR, "Failed restoring NOFILE limits"); Debug::log(ERR, "Failed restoring NOFILE limits");
} }
void CCompositor::setMallocThreshold() {
#ifdef M_TRIM_THRESHOLD
// The default is 128 pages,
// which is very large and can lead to a lot of memory used for no reason
// because trimming hasn't happened
static const int PAGESIZE = sysconf(_SC_PAGESIZE);
mallopt(M_TRIM_THRESHOLD, 6 * PAGESIZE);
#endif
}
CCompositor::CCompositor(bool onlyConfig) : m_bOnlyConfigVerification(onlyConfig), m_iHyprlandPID(getpid()) { CCompositor::CCompositor(bool onlyConfig) : m_bOnlyConfigVerification(onlyConfig), m_iHyprlandPID(getpid()) {
if (onlyConfig) if (onlyConfig)
return; return;
setMallocThreshold();
m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr"; m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr";
if (m_szHyprTempDataRoot.starts_with("/hypr")) { if (m_szHyprTempDataRoot.starts_with("/hypr")) {
@@ -280,6 +265,7 @@ static bool filterGlobals(const wl_client* client, const wl_global* global, void
// //
void CCompositor::initServer(std::string socketName, int socketFd) { void CCompositor::initServer(std::string socketName, int socketFd) {
if (m_bOnlyConfigVerification) { if (m_bOnlyConfigVerification) {
g_pHookSystem = makeUnique<CHookSystemManager>(); g_pHookSystem = makeUnique<CHookSystemManager>();
g_pKeybindManager = makeUnique<CKeybindManager>(); g_pKeybindManager = makeUnique<CKeybindManager>();
@@ -388,6 +374,7 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
} }
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
setenv("XDG_SESSION_TYPE", "wayland", 1);
if (!getenv("XDG_CURRENT_DESKTOP")) { if (!getenv("XDG_CURRENT_DESKTOP")) {
setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1); setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1);
m_bDesktopEnvSet = true; m_bDesktopEnvSet = true;
@@ -514,7 +501,7 @@ void CCompositor::cleanEnvironment() {
"dbus-update-activation-environment 2>/dev/null && " "dbus-update-activation-environment 2>/dev/null && "
#endif #endif
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"; "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS";
CKeybindManager::spawn(CMD); g_pKeybindManager->spawn(CMD);
} }
} }
@@ -594,7 +581,6 @@ void CCompositor::cleanup() {
g_pEventLoopManager.reset(); g_pEventLoopManager.reset();
g_pVersionKeeperMgr.reset(); g_pVersionKeeperMgr.reset();
g_pDonationNagManager.reset(); g_pDonationNagManager.reset();
g_pANRManager.reset();
g_pConfigWatcher.reset(); g_pConfigWatcher.reset();
if (m_pAqBackend) if (m_pAqBackend)
@@ -697,9 +683,6 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the DonationNag!"); Debug::log(LOG, "Creating the DonationNag!");
g_pDonationNagManager = makeUnique<CDonationNagManager>(); g_pDonationNagManager = makeUnique<CDonationNagManager>();
Debug::log(LOG, "Creating the ANRManager!");
g_pANRManager = makeUnique<CANRManager>();
Debug::log(LOG, "Starting XWayland"); Debug::log(LOG, "Starting XWayland");
g_pXWayland = makeUnique<CXWayland>(g_pCompositor->m_bWantsXwayland); g_pXWayland = makeUnique<CXWayland>(g_pCompositor->m_bWantsXwayland);
} break; } break;
@@ -756,7 +739,7 @@ void CCompositor::startCompositor() {
"dbus-update-activation-environment 2>/dev/null && " "dbus-update-activation-environment 2>/dev/null && "
#endif #endif
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"; "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS";
CKeybindManager::spawn(CMD); g_pKeybindManager->spawn(CMD);
} }
Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket); Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket);
@@ -815,11 +798,6 @@ PHLMONITOR CCompositor::getMonitorFromCursor() {
} }
PHLMONITOR CCompositor::getMonitorFromVector(const Vector2D& point) { PHLMONITOR CCompositor::getMonitorFromVector(const Vector2D& point) {
if (m_vMonitors.empty()) {
Debug::log(WARN, "getMonitorFromVector called with empty monitor list");
return nullptr;
}
PHLMONITOR mon; PHLMONITOR mon;
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) { if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) {
@@ -862,7 +840,12 @@ void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) {
} }
bool CCompositor::monitorExists(PHLMONITOR pMonitor) { bool CCompositor::monitorExists(PHLMONITOR pMonitor) {
return std::ranges::any_of(m_vRealMonitors, [&](const PHLMONITOR& m) { return m == pMonitor; }); for (auto const& m : m_vRealMonitors) {
if (m == pMonitor)
return true;
}
return false;
} }
PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, PHLWINDOW pIgnoreWindow) { PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, PHLWINDOW pIgnoreWindow) {
@@ -1082,7 +1065,7 @@ PHLMONITOR CCompositor::getRealMonitorFromOutput(SP<Aquamarine::IOutput> out) {
return nullptr; return nullptr;
} }
void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, bool preserveFocusHistory) { void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse"); static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
static auto PSPECIALFALLTHROUGH = CConfigValue<Hyprlang::INT>("input:special_fallthrough"); static auto PSPECIALFALLTHROUGH = CConfigValue<Hyprlang::INT>("input:special_fallthrough");
@@ -1193,8 +1176,8 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface
pWindow->m_bIsUrgent = false; pWindow->m_bIsUrgent = false;
// Send an event // Send an event
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = pWindow->m_szClass + "," + pWindow->m_szTitle}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", pWindow->m_szClass + "," + pWindow->m_szTitle});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", (uintptr_t)pWindow.get())}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)pWindow.get())});
EMIT_HOOK_EVENT("activeWindow", pWindow); EMIT_HOOK_EVENT("activeWindow", pWindow);
@@ -1202,20 +1185,16 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
if (!preserveFocusHistory) {
// move to front of the window history // move to front of the window history
const auto HISTORYPIVOT = std::ranges::find_if(m_vWindowFocusHistory, [&](const auto& other) { return other.lock() == pWindow; }); const auto HISTORYPIVOT = std::find_if(m_vWindowFocusHistory.begin(), m_vWindowFocusHistory.end(), [&](const auto& other) { return other.lock() == pWindow; });
if (HISTORYPIVOT == m_vWindowFocusHistory.end()) if (HISTORYPIVOT == m_vWindowFocusHistory.end()) {
Debug::log(ERR, "BUG THIS: {} has no pivot in history", pWindow); Debug::log(ERR, "BUG THIS: {} has no pivot in history", pWindow);
else } else {
std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1); std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1);
} }
if (*PFOLLOWMOUSE == 0) if (*PFOLLOWMOUSE == 0)
g_pInputManager->sendMotionEventsToFocused(); g_pInputManager->sendMotionEventsToFocused();
if (pWindow->m_sGroupData.pNextWindow)
pWindow->deactivateGroupMembers();
} }
void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindowOwner) { void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindowOwner) {
@@ -1239,8 +1218,8 @@ void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindo
if (!pSurface) { if (!pSurface) {
g_pSeatManager->setKeyboardFocus(nullptr); g_pSeatManager->setKeyboardFocus(nullptr);
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = ","}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = ""}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""});
EMIT_HOOK_EVENT("keyboardFocus", (SP<CWLSurfaceResource>)nullptr); EMIT_HOOK_EVENT("keyboardFocus", (SP<CWLSurfaceResource>)nullptr);
m_pLastFocus.reset(); m_pLastFocus.reset();
return; return;
@@ -1272,7 +1251,7 @@ void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindo
SP<CWLSurfaceResource> CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, PHLMONITOR monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { SP<CWLSurfaceResource> CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, PHLMONITOR monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) {
for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) {
for (auto const& ls : lsl | std::views::reverse) { for (auto const& ls : lsl | std::views::reverse) {
if (!ls->mapped || ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha->value() == 0.f) if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha->value() == 0.f)
continue; continue;
auto SURFACEAT = ls->popupHead->at(pos, true); auto SURFACEAT = ls->popupHead->at(pos, true);
@@ -1290,7 +1269,7 @@ SP<CWLSurfaceResource> CCompositor::vectorToLayerPopupSurface(const Vector2D& po
SP<CWLSurfaceResource> CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<PHLLSREF>* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { SP<CWLSurfaceResource> CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<PHLLSREF>* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) {
for (auto const& ls : *layerSurfaces | std::views::reverse) { for (auto const& ls : *layerSurfaces | std::views::reverse) {
if (!ls->mapped || ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha->value() == 0.f) if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha->value() == 0.f)
continue; continue;
auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos(), true); auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos(), true);
@@ -1417,13 +1396,14 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
toMove.insert(toMove.begin(), pw); toMove.insert(toMove.begin(), pw);
for (auto const& w : m_vWindows) { for (auto const& w : m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->x11TransientFor() == pw && w != pw && std::ranges::find(toMove, w) == toMove.end()) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->x11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) {
x11Stack(w, top, x11Stack); x11Stack(w, top, x11Stack);
} }
} }
}; };
x11Stack(pWindow, top, x11Stack); x11Stack(pWindow, top, x11Stack);
for (const auto& it : toMove) { for (const auto& it : toMove) {
moveToZ(it, top); moveToZ(it, top);
} }
@@ -1475,7 +1455,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) {
if (ls->fadingOut && ls->readyToDelete && ls->isFadedOut()) { if (ls->fadingOut && ls->readyToDelete && ls->isFadedOut()) {
for (auto const& m : m_vMonitors) { for (auto const& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLayers) { for (auto& lsl : m->m_aLayerSurfaceLayers) {
if (!lsl.empty() && std::ranges::find_if(lsl, [&](auto& other) { return other == ls; }) != lsl.end()) { if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](auto& other) { return other == ls; }) != lsl.end()) {
std::erase_if(lsl, [&](auto& other) { return other == ls || !other; }); std::erase_if(lsl, [&](auto& other) { return other == ls || !other; });
} }
} }
@@ -1498,7 +1478,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) {
} }
void CCompositor::addToFadingOutSafe(PHLLS pLS) { void CCompositor::addToFadingOutSafe(PHLLS pLS) {
const auto FOUND = std::ranges::find_if(m_vSurfacesFadingOut, [&](auto& other) { return other.lock() == pLS; }); const auto FOUND = std::find_if(m_vSurfacesFadingOut.begin(), m_vSurfacesFadingOut.end(), [&](auto& other) { return other.lock() == pLS; });
if (FOUND != m_vSurfacesFadingOut.end()) if (FOUND != m_vSurfacesFadingOut.end())
return; // if it's already added, don't add it. return; // if it's already added, don't add it.
@@ -1511,7 +1491,7 @@ void CCompositor::removeFromFadingOutSafe(PHLLS ls) {
} }
void CCompositor::addToFadingOutSafe(PHLWINDOW pWindow) { void CCompositor::addToFadingOutSafe(PHLWINDOW pWindow) {
const auto FOUND = std::ranges::find_if(m_vWindowsFadingOut, [&](PHLWINDOWREF& other) { return other.lock() == pWindow; }); const auto FOUND = std::find_if(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), [&](PHLWINDOWREF& other) { return other.lock() == pWindow; });
if (FOUND != m_vWindowsFadingOut.end()) if (FOUND != m_vWindowsFadingOut.end())
return; // if it's already added, don't add it. return; // if it's already added, don't add it.
@@ -1630,7 +1610,7 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks
// //
auto vectorAngles = [](const Vector2D& a, const Vector2D& b) -> double { auto vectorAngles = [](const Vector2D& a, const Vector2D& b) -> double {
double dot = (a.x * b.x) + (a.y * b.y); double dot = a.x * b.x + a.y * b.y;
double ang = std::acos(dot / (a.size() * b.size())); double ang = std::acos(dot / (a.size() * b.size()));
return ang; return ang;
}; };
@@ -1674,52 +1654,37 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks
return nullptr; return nullptr;
} }
template <typename WINDOWPTR> PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional<bool> floating, bool visible) {
static bool isWorkspaceMatches(WINDOWPTR pWindow, const WINDOWPTR w, bool anyWorkspace) { auto it = std::ranges::find(m_vWindows, pWindow);
const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); };
const auto IN_RIGHT = std::find_if(it, m_vWindows.end(), FINDER);
if (IN_RIGHT != m_vWindows.end())
return *IN_RIGHT;
const auto IN_LEFT = std::find_if(m_vWindows.begin(), it, FINDER);
return *IN_LEFT;
}
PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional<bool> floating, bool visible) {
auto it = std::ranges::find(std::ranges::reverse_view(m_vWindows), pWindow);
const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); };
const auto IN_LEFT = std::find_if(it, m_vWindows.rend(), FINDER);
if (IN_LEFT != m_vWindows.rend())
return *IN_LEFT;
const auto IN_RIGHT = std::find_if(m_vWindows.rbegin(), it, FINDER);
return *IN_RIGHT;
}
inline static bool isWorkspaceMatches(PHLWINDOW pWindow, const PHLWINDOW w, bool anyWorkspace) {
return anyWorkspace ? w->m_pWorkspace && w->m_pWorkspace->isVisible() : w->m_pWorkspace == pWindow->m_pWorkspace; return anyWorkspace ? w->m_pWorkspace && w->m_pWorkspace->isVisible() : w->m_pWorkspace == pWindow->m_pWorkspace;
} }
template <typename WINDOWPTR> inline static bool isFloatingMatches(PHLWINDOW w, std::optional<bool> floating) {
static bool isFloatingMatches(WINDOWPTR w, std::optional<bool> floating) {
return !floating.has_value() || w->m_bIsFloating == floating.value(); return !floating.has_value() || w->m_bIsFloating == floating.value();
} };
template <typename WINDOWPTR> bool CCompositor::isWindowAvailableForCycle(PHLWINDOW pWindow, const PHLWINDOW w, bool focusableOnly, std::optional<bool> floating, bool anyWorkspace) {
static bool isWindowAvailableForCycle(WINDOWPTR pWindow, WINDOWPTR w, bool focusableOnly, std::optional<bool> floating, bool anyWorkspace = false) { return isFloatingMatches(w, floating) && w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_bIsMapped && !w->isHidden() &&
return isFloatingMatches(w, floating) && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault());
(w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()));
}
template <typename Iterator>
static PHLWINDOW getWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function<bool(const PHLWINDOW&)> PRED) {
const auto IN_ONE_SIDE = std::find_if(cur, end, PRED);
if (IN_ONE_SIDE != end)
return *IN_ONE_SIDE;
const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED);
return *IN_OTHER_SIDE;
}
template <typename Iterator>
static PHLWINDOW getWeakWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function<bool(const PHLWINDOWREF&)> PRED) {
const auto IN_ONE_SIDE = std::find_if(cur, end, PRED);
if (IN_ONE_SIDE != end)
return IN_ONE_SIDE->lock();
const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED);
return IN_OTHER_SIDE->lock();
}
PHLWINDOW CCompositor::getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly, std::optional<bool> floating, bool visible, bool next) {
const auto FINDER = [&](const PHLWINDOWREF& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); };
// also m_vWindowFocusHistory has reverse order, so when it is next - we need to reverse again
return next ?
getWeakWindowPred(std::ranges::find(std::ranges::reverse_view(m_vWindowFocusHistory), cur), m_vWindowFocusHistory.rend(), m_vWindowFocusHistory.rbegin(), FINDER) :
getWeakWindowPred(std::ranges::find(m_vWindowFocusHistory, cur), m_vWindowFocusHistory.end(), m_vWindowFocusHistory.begin(), FINDER);
}
PHLWINDOW CCompositor::getWindowCycle(PHLWINDOW cur, bool focusableOnly, std::optional<bool> floating, bool visible, bool prev) {
const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); };
return prev ? getWindowPred(std::ranges::find(std::ranges::reverse_view(m_vWindows), cur), m_vWindows.rend(), m_vWindows.rbegin(), FINDER) :
getWindowPred(std::ranges::find(m_vWindows, cur), m_vWindows.end(), m_vWindows.begin(), FINDER);
} }
WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() {
@@ -1764,7 +1729,7 @@ bool CCompositor::isPointOnReservedArea(const Vector2D& point, const PHLMONITOR
const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
const auto XY2 = PMONITOR->vecPosition + PMONITOR->vecSize - PMONITOR->vecReservedBottomRight; const auto XY2 = PMONITOR->vecPosition + PMONITOR->vecSize - PMONITOR->vecReservedBottomRight;
return VECNOTINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y); return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y);
} }
PHLMONITOR CCompositor::getMonitorInDirection(const char& dir) { PHLMONITOR CCompositor::getMonitorInDirection(const char& dir) {
@@ -1938,7 +1903,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) {
// reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor // reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor
if (m_mMonitorIDMap.contains(name) && !std::ranges::any_of(m_vRealMonitors, [&](auto m) { return m->ID == m_mMonitorIDMap[name]; })) if (m_mMonitorIDMap.contains(name) && !std::any_of(m_vRealMonitors.begin(), m_vRealMonitors.end(), [&](auto m) { return m->ID == m_mMonitorIDMap[name]; }))
return m_mMonitorIDMap[name]; return m_mMonitorIDMap[name];
// otherwise, find minimum available ID that is not in the map // otherwise, find minimum available ID that is not in the map
@@ -1948,7 +1913,7 @@ MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) {
} }
MONITORID nextID = 0; MONITORID nextID = 0;
while (usedIDs.contains(nextID)) { while (usedIDs.count(nextID) > 0) {
nextID++; nextID++;
} }
m_mMonitorIDMap[name] = nextID; m_mMonitorIDMap[name] = nextID;
@@ -1956,6 +1921,7 @@ MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) {
} }
void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitorB) { void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitorB) {
const auto PWORKSPACEA = pMonitorA->activeWorkspace; const auto PWORKSPACEA = pMonitorA->activeWorkspace;
const auto PWORKSPACEB = pMonitorB->activeWorkspace; const auto PWORKSPACEB = pMonitorB->activeWorkspace;
@@ -2027,18 +1993,17 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor
(g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING))); (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING)));
const auto PNEWWORKSPACE = pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID ? PWORKSPACEB : PWORKSPACEA; const auto PNEWWORKSPACE = pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID ? PWORKSPACEB : PWORKSPACEA;
g_pEventManager->postEvent(SHyprIPCEvent{.event = "workspace", .data = PNEWWORKSPACE->m_szName}); g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PNEWWORKSPACE->m_szName});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "workspacev2", .data = std::format("{},{}", PNEWWORKSPACE->m_iID, PNEWWORKSPACE->m_szName)}); g_pEventManager->postEvent(SHyprIPCEvent{"workspacev2", std::format("{},{}", PNEWWORKSPACE->m_iID, PNEWWORKSPACE->m_szName)});
EMIT_HOOK_EVENT("workspace", PNEWWORKSPACE); EMIT_HOOK_EVENT("workspace", PNEWWORKSPACE);
} }
// event // event
g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspace", .data = PWORKSPACEA->m_szName + "," + pMonitorB->szName}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspacev2", .data = std::format("{},{},{}", PWORKSPACEA->m_iID, PWORKSPACEA->m_szName, pMonitorB->szName)}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEA->m_iID, PWORKSPACEA->m_szName, pMonitorB->szName)});
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{PWORKSPACEA, pMonitorB})); EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{PWORKSPACEA, pMonitorB}));
g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspace", .data = PWORKSPACEB->m_szName + "," + pMonitorA->szName}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEB->m_szName + "," + pMonitorA->szName});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspacev2", .data = std::format("{},{},{}", PWORKSPACEB->m_iID, PWORKSPACEB->m_szName, pMonitorA->szName)}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEB->m_iID, PWORKSPACEB->m_szName, pMonitorA->szName)});
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{PWORKSPACEB, pMonitorA})); EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{PWORKSPACEB, pMonitorA}));
} }
@@ -2117,6 +2082,7 @@ PHLMONITOR CCompositor::getMonitorFromString(const std::string& name) {
} }
void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMonitor, bool noWarpCursor) { void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMonitor, bool noWarpCursor) {
if (!pWorkspace || !pMonitor) if (!pWorkspace || !pMonitor)
return; return;
@@ -2215,7 +2181,6 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo
// finalize // finalize
if (POLDMON) { if (POLDMON) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
if (valid(POLDMON->activeWorkspace))
updateFullscreenFadeOnWorkspace(POLDMON->activeWorkspace); updateFullscreenFadeOnWorkspace(POLDMON->activeWorkspace);
updateSuspendedStates(); updateSuspendedStates();
} }
@@ -2224,8 +2189,8 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo
updateSuspendedStates(); updateSuspendedStates();
// event // event
g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspace", .data = pWorkspace->m_szName + "," + pMonitor->szName}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", pWorkspace->m_szName + "," + pMonitor->szName});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspacev2", .data = std::format("{},{},{}", pWorkspace->m_iID, pWorkspace->m_szName, pMonitor->szName)}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", pWorkspace->m_iID, pWorkspace->m_szName, pMonitor->szName)});
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{pWorkspace, pMonitor})); EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{pWorkspace, pMonitor}));
} }
@@ -2236,8 +2201,12 @@ bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) {
for (auto const& w : m_vWorkspaces) { for (auto const& w : m_vWorkspaces) {
if (w->m_bIsSpecialWorkspace) if (w->m_bIsSpecialWorkspace)
continue; continue;
lowestID = std::min(w->m_iID, lowestID);
highestID = std::max(w->m_iID, highestID); if (w->m_iID < lowestID)
lowestID = w->m_iID;
if (w->m_iID > highestID)
highestID = w->m_iID;
} }
return std::clamp(id, lowestID, highestID) != id; return std::clamp(id, lowestID, highestID) != id;
@@ -2245,9 +2214,6 @@ bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) {
void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) {
if (!pWorkspace)
return;
const auto FULLSCREEN = pWorkspace->m_bHasFullscreenWindow; const auto FULLSCREEN = pWorkspace->m_bHasFullscreenWindow;
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
@@ -2316,7 +2282,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen()) if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen())
setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE); setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE);
const bool CHANGEINTERNAL = !PWINDOW->m_bPinned && CURRENT_EFFECTIVE_MODE != EFFECTIVE_MODE; const bool CHANGEINTERNAL = !(PWINDOW->m_bPinned || CURRENT_EFFECTIVE_MODE == EFFECTIVE_MODE);
if (*PALLOWPINFULLSCREEN && PWINDOW->m_bPinFullscreened && PWINDOW->isFullscreen() && !PWINDOW->m_bPinned && state.internal == FSMODE_NONE) { if (*PALLOWPINFULLSCREEN && PWINDOW->m_bPinFullscreened && PWINDOW->isFullscreen() && !PWINDOW->m_bPinned && state.internal == FSMODE_NONE) {
PWINDOW->m_bPinned = true; PWINDOW->m_bPinned = true;
@@ -2343,7 +2309,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS
PWORKSPACE->m_efFullscreenMode = EFFECTIVE_MODE; PWORKSPACE->m_efFullscreenMode = EFFECTIVE_MODE;
PWORKSPACE->m_bHasFullscreenWindow = EFFECTIVE_MODE != FSMODE_NONE; PWORKSPACE->m_bHasFullscreenWindow = EFFECTIVE_MODE != FSMODE_NONE;
g_pEventManager->postEvent(SHyprIPCEvent{.event = "fullscreen", .data = std::to_string((int)EFFECTIVE_MODE != FSMODE_NONE)}); g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)EFFECTIVE_MODE != FSMODE_NONE)});
EMIT_HOOK_EVENT("fullscreen", PWINDOW); EMIT_HOOK_EVENT("fullscreen", PWINDOW);
PWINDOW->updateDynamicRules(); PWINDOW->updateDynamicRules();
@@ -2358,7 +2324,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS
updateFullscreenFadeOnWorkspace(PWORKSPACE); updateFullscreenFadeOnWorkspace(PWORKSPACE);
PWINDOW->sendWindowSize(true); PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true);
PWORKSPACE->forceReportSizesToWindows(); PWORKSPACE->forceReportSizesToWindows();
@@ -2370,7 +2336,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS
// send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't.
// ignore if DS is disabled. // ignore if DS is disabled.
if (*PDIRECTSCANOUT == 1 || (*PDIRECTSCANOUT == 2 && PWINDOW->getContentType() == CONTENT_TYPE_GAME)) if (*PDIRECTSCANOUT)
g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr); g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr);
g_pConfigManager->ensureVRR(PMONITOR); g_pConfigManager->ensureVRR(PMONITOR);
@@ -2610,8 +2576,8 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
X = xIsPercent ? std::stof(x) * 0.01 * PMONITOR->vecSize.x : std::stoi(x); X = xIsPercent ? std::stof(x) * 0.01 * PMONITOR->vecSize.x : std::stoi(x);
Y = yIsPercent ? std::stof(y) * 0.01 * PMONITOR->vecSize.y : std::stoi(y); Y = yIsPercent ? std::stof(y) * 0.01 * PMONITOR->vecSize.y : std::stoi(y);
} else { } else {
X = xIsPercent ? (std::stof(x) * 0.01 * relativeTo.x) + relativeTo.x : std::stoi(x) + relativeTo.x; X = xIsPercent ? std::stof(x) * 0.01 * relativeTo.x + relativeTo.x : std::stoi(x) + relativeTo.x;
Y = yIsPercent ? (std::stof(y) * 0.01 * relativeTo.y) + relativeTo.y : std::stoi(y) + relativeTo.y; Y = yIsPercent ? std::stof(y) * 0.01 * relativeTo.y + relativeTo.y : std::stoi(y) + relativeTo.y;
} }
return Vector2D(X, Y); return Vector2D(X, Y);
@@ -2627,13 +2593,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO
const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2; const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2;
const auto PMONITOR = getMonitorFromID(monID); const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, getMonitorFromID(monID), NAME, SPECIAL, isEmpty));
if (!PMONITOR) {
Debug::log(ERR, "BUG THIS: No pMonitor for new workspace in createNewWorkspace");
return nullptr;
}
const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, PMONITOR, NAME, SPECIAL, isEmpty));
PWORKSPACE->m_fAlpha->setValueAndWarp(0); PWORKSPACE->m_fAlpha->setValueAndWarp(0);
@@ -2654,8 +2614,8 @@ void CCompositor::setActiveMonitor(PHLMONITOR pMonitor) {
const auto WORKSPACE_ID = PWORKSPACE ? std::to_string(PWORKSPACE->m_iID) : std::to_string(WORKSPACE_INVALID); const auto WORKSPACE_ID = PWORKSPACE ? std::to_string(PWORKSPACE->m_iID) : std::to_string(WORKSPACE_INVALID);
const auto WORKSPACE_NAME = PWORKSPACE ? PWORKSPACE->m_szName : "?"; const auto WORKSPACE_NAME = PWORKSPACE ? PWORKSPACE->m_szName : "?";
g_pEventManager->postEvent(SHyprIPCEvent{.event = "focusedmon", .data = pMonitor->szName + "," + WORKSPACE_NAME}); g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + WORKSPACE_NAME});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "focusedmonv2", .data = pMonitor->szName + "," + WORKSPACE_ID}); g_pEventManager->postEvent(SHyprIPCEvent{"focusedmonv2", pMonitor->szName + "," + WORKSPACE_ID});
EMIT_HOOK_EVENT("focusedMon", pMonitor); EMIT_HOOK_EVENT("focusedMon", pMonitor);
m_pLastMonitor = pMonitor->self; m_pLastMonitor = pMonitor->self;
@@ -2711,9 +2671,6 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor
if (pWindow->m_bPinned && pWorkspace->m_bIsSpecialWorkspace) if (pWindow->m_bPinned && pWorkspace->m_bIsSpecialWorkspace)
return; return;
if (pWindow->m_pWorkspace == pWorkspace)
return;
const bool FULLSCREEN = pWindow->isFullscreen(); const bool FULLSCREEN = pWindow->isFullscreen();
const auto FULLSCREENMODE = pWindow->m_sFullscreenState.internal; const auto FULLSCREENMODE = pWindow->m_sFullscreenState.internal;
const bool WASVISIBLE = pWindow->m_pWorkspace && pWindow->m_pWorkspace->isVisible(); const bool WASVISIBLE = pWindow->m_pWorkspace && pWindow->m_pWorkspace->isVisible();
@@ -2848,10 +2805,14 @@ void CCompositor::arrangeMonitors() {
// Finds the max and min values of explicitely placed monitors. // Finds the max and min values of explicitely placed monitors.
for (auto const& m : arranged) { for (auto const& m : arranged) {
maxXOffsetRight = std::max<double>(m->vecPosition.x + m->vecSize.x, maxXOffsetRight); if (m->vecPosition.x + m->vecSize.x > maxXOffsetRight)
maxXOffsetLeft = std::min<double>(m->vecPosition.x, maxXOffsetLeft); maxXOffsetRight = m->vecPosition.x + m->vecSize.x;
maxYOffsetDown = std::max<double>(m->vecPosition.y + m->vecSize.y, maxYOffsetDown); if (m->vecPosition.x < maxXOffsetLeft)
maxYOffsetUp = std::min<double>(m->vecPosition.y, maxYOffsetUp); maxXOffsetLeft = m->vecPosition.x;
if (m->vecPosition.y + m->vecSize.y > maxYOffsetDown)
maxYOffsetDown = m->vecPosition.y + m->vecSize.y;
if (m->vecPosition.y < maxYOffsetUp)
maxYOffsetUp = m->vecPosition.y;
} }
}; };
@@ -3045,10 +3006,8 @@ void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) {
g_pHyprRenderer->damageMonitor(PNEWMONITOR); g_pHyprRenderer->damageMonitor(PNEWMONITOR);
PNEWMONITOR->onMonitorFrame(); PNEWMONITOR->onMonitorFrame();
if (PROTO::colorManagement && shouldChangePreferredImageDescription()) { if (PROTO::colorManagement && shouldChangePreferredImageDescription())
Debug::log(ERR, "FIXME: color management protocol is enabled, need a preferred image description id"); PROTO::colorManagement->onImagePreferredChanged();
PROTO::colorManagement->onImagePreferredChanged(0);
}
} }
SImageDescription CCompositor::getPreferredImageDescription() { SImageDescription CCompositor::getPreferredImageDescription() {
@@ -3066,31 +3025,20 @@ bool CCompositor::shouldChangePreferredImageDescription() {
return false; return false;
} }
void CCompositor::ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules, PHLWORKSPACE pWorkspace) { void CCompositor::ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules) {
if (!m_pLastMonitor)
return;
for (const auto& rule : rules) { for (const auto& rule : rules) {
if (!rule.isPersistent) if (!rule.isPersistent)
continue; continue;
PHLWORKSPACE PWORKSPACE = nullptr; const auto PMONITOR = getMonitorFromString(rule.monitor);
if (pWorkspace) {
if (pWorkspace->matchesStaticSelector(rule.workspaceString)) if (!PMONITOR) {
PWORKSPACE = pWorkspace; Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve monitor for {}, skipping", rule.monitor);
else
continue; continue;
} }
const auto PMONITOR = getMonitorFromString(rule.monitor);
if (!rule.monitor.empty() && !PMONITOR)
continue; // don't do anything yet, as the monitor is not yet present.
if (!PWORKSPACE) {
WORKSPACEID id = rule.workspaceId; WORKSPACEID id = rule.workspaceId;
std::string wsname = rule.workspaceName; std::string wsname = rule.workspaceName;
if (id == WORKSPACE_INVALID) { if (id == WORKSPACE_INVALID) {
const auto R = getWorkspaceIDNameFromString(rule.workspaceString); const auto R = getWorkspaceIDNameFromString(rule.workspaceString);
id = R.id; id = R.id;
@@ -3101,23 +3049,10 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vector<SWorkspace
Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve id for workspace {}", rule.workspaceString); Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve id for workspace {}", rule.workspaceString);
continue; continue;
} }
PWORKSPACE = getWorkspaceByID(id);
if (!PWORKSPACE)
createNewWorkspace(id, PMONITOR ? PMONITOR->ID : m_pLastMonitor->ID, wsname, false);
}
if (PWORKSPACE) if (const auto PWORKSPACE = getWorkspaceByID(id); PWORKSPACE) {
PWORKSPACE->m_bPersistent = true;
if (!PMONITOR) {
Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve monitor for {}, skipping", rule.monitor);
continue;
}
if (PWORKSPACE) {
if (PWORKSPACE->m_pMonitor == PMONITOR) { if (PWORKSPACE->m_pMonitor == PMONITOR) {
Debug::log(LOG, "ensurePersistentWorkspacesPresent: workspace persistent {} already on {}", rule.workspaceString, PMONITOR->szName); Debug::log(LOG, "ensurePersistentWorkspacesPresent: workspace persistent {} already on {}", rule.workspaceString, PMONITOR->szName);
continue; continue;
} }
@@ -3125,6 +3060,8 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vector<SWorkspace
moveWorkspaceToMonitor(PWORKSPACE, PMONITOR); moveWorkspaceToMonitor(PWORKSPACE, PMONITOR);
continue; continue;
} }
createNewWorkspace(id, PMONITOR ? PMONITOR : m_pLastMonitor.lock(), wsname, false);
} }
// cleanup old // cleanup old

View File

@@ -1,12 +1,15 @@
#pragma once #pragma once
#include <list>
#include <sys/resource.h> #include <sys/resource.h>
#include "defines.hpp"
#include "managers/XWaylandManager.hpp" #include "managers/XWaylandManager.hpp"
#include "managers/KeybindManager.hpp" #include "managers/KeybindManager.hpp"
#include "managers/SessionLockManager.hpp" #include "managers/SessionLockManager.hpp"
#include "desktop/Window.hpp" #include "desktop/Window.hpp"
#include "protocols/types/ColorManagement.hpp" #include "protocols/types/ColorManagement.hpp"
#include "helpers/memory/Memory.hpp"
#include <aquamarine/backend/Backend.hpp> #include <aquamarine/backend/Backend.hpp>
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
@@ -25,8 +28,8 @@ class CCompositor {
CCompositor(bool onlyConfig = false); CCompositor(bool onlyConfig = false);
~CCompositor(); ~CCompositor();
wl_display* m_sWLDisplay = nullptr; wl_display* m_sWLDisplay;
wl_event_loop* m_sWLEventLoop = nullptr; wl_event_loop* m_sWLEventLoop;
int m_iDRMFD = -1; int m_iDRMFD = -1;
bool m_bInitialized = false; bool m_bInitialized = false;
SP<Aquamarine::CBackend> m_pAqBackend; SP<Aquamarine::CBackend> m_pAqBackend;
@@ -52,6 +55,8 @@ class CCompositor {
void startCompositor(); void startCompositor();
void stopCompositor(); void stopCompositor();
void cleanup(); void cleanup();
void createLockFile();
void removeLockFile();
void bumpNofile(); void bumpNofile();
void restoreNofile(); void restoreNofile();
@@ -81,7 +86,7 @@ class CCompositor {
PHLMONITOR getMonitorFromCursor(); PHLMONITOR getMonitorFromCursor();
PHLMONITOR getMonitorFromVector(const Vector2D&); PHLMONITOR getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(PHLWINDOW); void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr, bool preserveFocusHistory = false); void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr);
void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr); void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr);
bool monitorExists(PHLMONITOR); bool monitorExists(PHLMONITOR);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
@@ -103,8 +108,8 @@ class CCompositor {
void cleanupFadingOut(const MONITORID& monid); void cleanupFadingOut(const MONITORID& monid);
PHLWINDOW getWindowInDirection(PHLWINDOW, char); PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false); PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false);
PHLWINDOW getWindowCycle(PHLWINDOW cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool prev = false); PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}, bool visible = false);
PHLWINDOW getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool next = false); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}, bool visible = false);
WORKSPACEID getNextAvailableNamedWorkspace(); WORKSPACEID getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr); bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr);
@@ -147,9 +152,9 @@ class CCompositor {
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform); void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates(); void updateSuspendedStates();
void onNewMonitor(SP<Aquamarine::IOutput> output); void onNewMonitor(SP<Aquamarine::IOutput> output);
void ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules, PHLWORKSPACE pWorkspace = nullptr); void ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules);
NColorManagement::SImageDescription getPreferredImageDescription(); SImageDescription getPreferredImageDescription();
bool shouldChangePreferredImageDescription(); bool shouldChangePreferredImageDescription();
std::string explicitConfigPath; std::string explicitConfigPath;
@@ -161,13 +166,11 @@ class CCompositor {
void setRandomSplash(); void setRandomSplash();
void initManagers(eManagersInitStage stage); void initManagers(eManagersInitStage stage);
void prepareFallbackOutput(); void prepareFallbackOutput();
void createLockFile(); bool isWindowAvailableForCycle(PHLWINDOW pWindow, PHLWINDOW w, bool focusableOnly, std::optional<bool> floating, bool anyWorkspace = false);
void removeLockFile();
void setMallocThreshold();
uint64_t m_iHyprlandPID = 0; uint64_t m_iHyprlandPID = 0;
wl_event_source* m_critSigSource = nullptr; wl_event_source* m_critSigSource = nullptr;
rlimit m_sOriginalNofile = {}; rlimit m_sOriginalNofile = {0};
}; };
inline UP<CCompositor> g_pCompositor; inline UP<CCompositor> g_pCompositor;

View File

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

View File

@@ -253,98 +253,98 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
*/ */
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:enabled", .value = "blur:enabled",
.description = "enable kawase window background blur", .description = "enable kawase window background blur",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:size", .value = "blur:size",
.description = "blur size (distance)", .description = "blur size (distance)",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{8, 0, 100}, .data = SConfigOptionDescription::SRangeData{8, 0, 100},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:passes", .value = "blur:passes",
.description = "the amount of passes to perform", .description = "the amount of passes to perform",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 10}, .data = SConfigOptionDescription::SRangeData{1, 0, 10},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:ignore_opacity", .value = "blur:ignore_opacity",
.description = "make the blur layer ignore the opacity of the window", .description = "make the blur layer ignore the opacity of the window",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:new_optimizations", .value = "blur:new_optimizations",
.description = "whether to enable further optimizations to the blur. Recommended to leave on, as it will massively improve performance.", .description = "whether to enable further optimizations to the blur. Recommended to leave on, as it will massively improve performance.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:xray", .value = "blur:xray",
.description = "if enabled, floating windows will ignore tiled windows in their blur. Only available if blur_new_optimizations is true. Will reduce overhead on floating " .description = "if enabled, floating windows will ignore tiled windows in their blur. Only available if blur_new_optimizations is true. Will reduce overhead on floating "
"blur significantly.", "blur significantly.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:noise", .value = "blur:noise",
.description = "how much noise to apply. [0.0 - 1.0]", .description = "how much noise to apply. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.0117, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.0117, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:contrast", .value = "blur:contrast",
.description = "contrast modulation for blur. [0.0 - 2.0]", .description = "contrast modulation for blur. [0.0 - 2.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.8916, 0, 2}, .data = SConfigOptionDescription::SFloatData{0.8916, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:brightness", .value = "blur:brightness",
.description = "brightness modulation for blur. [0.0 - 2.0]", .description = "brightness modulation for blur. [0.0 - 2.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.8172, 0, 2}, .data = SConfigOptionDescription::SFloatData{0.8172, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:vibrancy", .value = "blur:vibrancy",
.description = "Increase saturation of blurred colors. [0.0 - 1.0]", .description = "Increase saturation of blurred colors. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.1696, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.1696, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:vibrancy_darkness", .value = "blur:vibrancy_darkness",
.description = "How strong the effect of vibrancy is on dark areas . [0.0 - 1.0]", .description = "How strong the effect of vibrancy is on dark areas . [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0, 0, 1}, .data = SConfigOptionDescription::SFloatData{0, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:special", .value = "blur:special",
.description = "whether to blur behind the special workspace (note: expensive)", .description = "whether to blur behind the special workspace (note: expensive)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:popups", .value = "blur:popups",
.description = "whether to blur popups (e.g. right-click menus)", .description = "whether to blur popups (e.g. right-click menus)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:popups_ignorealpha", .value = "blur:popups_ignorealpha",
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]", .description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:input_methods", .value = "blur:input_methods",
.description = "whether to blur input methods (e.g. fcitx5)", .description = "whether to blur input methods (e.g. fcitx5)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "decoration:blur:input_methods_ignorealpha", .value = "blur:input_methods_ignorealpha",
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]", .description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT, .type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, .data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
@@ -501,12 +501,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 3}, .data = SConfigOptionDescription::SRangeData{1, 0, 3},
}, },
SConfigOptionDescription{
.value = "input:follow_mouse_threshold",
.description = "The smallest distance in logical pixels the mouse needs to travel for the window under it to get focused. Works only with follow_mouse = 1.",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "input:focus_on_close", .value = "input:focus_on_close",
.description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift " .description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift "
@@ -608,18 +602,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "input:touchpad:flip_x",
.description = "Inverts the horizontal movement of the touchpad",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "input:touchpad:flip_y",
.description = "Inverts the vertical movement of the touchpad",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* input:touchdevice: * input:touchdevice:
@@ -827,25 +809,25 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_active", .value = "general:col.border_active",
.description = "border color for inactive windows", .description = "border color for inactive windows",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66ffff00"}, .data = SConfigOptionDescription::SGradientData{"0x66ffff00"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_inactive", .value = "general:col.border_inactive",
.description = "border color for the active window", .description = "border color for the active window",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66777700"}, .data = SConfigOptionDescription::SGradientData{"0x66777700"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_locked_inactive", .value = "general:col.border_locked_active",
.description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)", .description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66ff5500"}, .data = SConfigOptionDescription::SGradientData{"0x66ff5500"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:col.border_locked_active", .value = "general:col.border_locked_inactive",
.description = "active border color for window that cannot be added to a group", .description = "active border color for window that cannot be added to a group",
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66775500"}, .data = SConfigOptionDescription::SGradientData{"0x66775500"},
@@ -901,7 +883,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "group:groupbar:gradients", .value = "group:groupbar:gradients",
.description = "enables gradients", .description = "enables gradients",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:height", .value = "group:groupbar:height",
@@ -909,12 +891,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{14, 1, 64}, .data = SConfigOptionDescription::SRangeData{14, 1, 64},
}, },
SConfigOptionDescription{
.value = "group:groupbar:indicator_height",
.description = "height of the groupbar indicator",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{3, 1, 64},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:stacked", .value = "group:groupbar:stacked",
.description = "render the groupbar as a vertical stack", .description = "render the groupbar as a vertical stack",
@@ -939,30 +915,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "group:groupbar:rounding",
.description = "how much to round the groupbar",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:gradient_rounding",
.description = "how much to round the groupbar gradient",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:round_only_edges",
.description = "if yes, will only round at the groupbar edges",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:groupbar:gradient_round_only_edges",
.description = "if yes, will only round at the groupbar gradient edges",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:text_color", .value = "group:groupbar:text_color",
.description = "controls the group bar text color", .description = "controls the group bar text color",
@@ -993,18 +945,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_COLOR, .type = CONFIG_OPTION_COLOR,
.data = SConfigOptionDescription::SColorData{0x66775500}, .data = SConfigOptionDescription::SColorData{0x66775500},
}, },
SConfigOptionDescription{
.value = "group:groupbar:gaps_out",
.description = "gap between gradients and window",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 20},
},
SConfigOptionDescription{
.value = "group:groupbar:gaps_in",
.description = "gap between gradients",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 20},
},
/* /*
* misc: * misc:
@@ -1054,9 +994,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "misc:vrr", .value = "misc:vrr",
.description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only, 3 - fullscreen with game or video content type [0/1/2/3]", .description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only [0/1/2]",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 3}, .data = SConfigOptionDescription::SRangeData{0, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "misc:mouse_move_enables_dpms", .value = "misc:mouse_move_enables_dpms",
@@ -1211,12 +1151,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1000, 0, 5000}, .data = SConfigOptionDescription::SRangeData{1000, 0, 5000},
}, },
SConfigOptionDescription{
.value = "misc:enable_anr_dialog",
.description = "whether to enable the ANR (app not responding) dialog when your apps hang",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
/* /*
* binds: * binds:
@@ -1270,7 +1204,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "binds:movefocus_cycles_fullscreen", .value = "binds:movefocus_cycles_fullscreen",
.description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.", .description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "binds:movefocus_cycles_groupfirst", .value = "binds:movefocus_cycles_groupfirst",
@@ -1319,12 +1253,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "xwayland:create_abstract_socket",
.description = "Create the abstract Unix domain socket for XWayland",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* opengl: * opengl:
@@ -1336,6 +1264,13 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "opengl:force_introspection",
.description = "forces introspection at all times. Introspection is aimed at reducing GPU usage in certain cases, but might cause graphical glitches on nvidia. 0 - "
"nothing, 1 - force always on, 2 - force always on if nvidia",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 2},
},
/* /*
* render: * render:
@@ -1356,9 +1291,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
SConfigOptionDescription{ SConfigOptionDescription{
.value = "render:direct_scanout", .value = "render:direct_scanout",
.description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also " .description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also "
"recommended to set this to false if the fullscreen application shows graphical glitches. 0 - off, 1 - on, 2 - auto (on with content type 'game')", "recommended to set this to false if the fullscreen application shows graphical glitches.",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 2}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "render:expand_undersized_textures", .value = "render:expand_undersized_textures",
@@ -1379,14 +1314,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SRangeData{2, 0, 2}, .data = SConfigOptionDescription::SRangeData{2, 0, 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "render:cm_fs_passthrough", .value = "render:allow_early_buffer_release",
.description = "Passthrough color settings for fullscreen apps when possible", .description = "Allow early buffer release event. Fixes stuttering and missing frames for some apps. May cause graphical glitches and memory leaks in others",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2},
},
SConfigOptionDescription{
.value = "render:cm_enabled",
.description = "Enable Color Management pipelines (requires restart to fully take effect)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
@@ -1395,18 +1324,24 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
* cursor: * cursor:
*/ */
SConfigOptionDescription{
.value = "cursor:use_nearest_neighbor",
.description = "sync xcursor theme with gsettings, it applies cursor-theme and cursor-size on theme load to gsettings making most CSD gtk based clients use same xcursor "
"theme and size.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_hardware_cursors", .value = "cursor:no_hardware_cursors",
.description = "disables hardware cursors. Auto = disable when tearing", .description = "disables hardware cursors",
.type = CONFIG_OPTION_CHOICE, .type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"}, .data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:no_break_fs_vrr", .value = "cursor:no_break_fs_vrr",
.description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (may require no_hardware_cursors = true) " .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)",
"0 - off, 1 - on, 2 - auto (on with content type 'game')", .type = CONFIG_OPTION_BOOL,
.type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SBoolData{false},
.data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "cursor:min_refresh_rate", .value = "cursor:min_refresh_rate",
@@ -1486,35 +1421,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "cursor:sync_gsettings_theme",
.description = "sync xcursor theme with gsettings, it applies cursor-theme and cursor-size on theme load to gsettings making most CSD gtk based clients use same xcursor "
"theme and size.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "cursor:warp_back_after_non_mouse_input",
.description = "warp the cursor back to where it was after using a non-mouse input to move it, and then returning back to mouse.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/*
* ecosystem:
*/
SConfigOptionDescription{
.value = "ecosystem:no_update_news",
.description = "disable the popup that shows up when you update hyprland to a new version.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "ecosystem:no_donation_nag",
.description = "disable the popup that shows up twice a year encouraging to donate.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* debug: * debug:
@@ -1598,24 +1504,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "debug:log_damage",
.description = "enables logging the damage.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "debug:pass",
.description = "enables render pass debugging.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "debug:full_cm_proto",
.description = "claims support for all cm proto features (requires restart)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* dwindle: * dwindle:
@@ -1776,16 +1664,22 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "experimental:wide_color_gamut",
.description = "force wide color gamut for all supported outputs",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "experimental:hdr",
.description = "force static hdr for all supported outputs",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "experimental:xx_color_management_v4", .value = "experimental:xx_color_management_v4",
.description = "enable color management protocol", .description = "enable color management protocol",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "master:always_keep_position",
.description = "whether to keep the master window in its configured position when there are no slave windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -138,27 +138,6 @@ struct SFirstExecRequest {
bool withRules = false; bool withRules = false;
}; };
struct SFloatCache {
size_t hash;
SFloatCache(PHLWINDOW window) {
hash = std::hash<std::string>{}(window->m_szClass) ^ (std::hash<std::string>{}(window->m_szTitle) << 1);
}
bool operator==(const SFloatCache& other) const {
return hash == other.hash;
}
};
namespace std {
template <>
struct hash<SFloatCache> {
size_t operator()(const SFloatCache& id) const {
return id.hash;
}
};
}
class CConfigManager { class CConfigManager {
public: public:
CConfigManager(); CConfigManager();
@@ -210,7 +189,7 @@ class CConfigManager {
void ensureMonitorStatus(); void ensureMonitorStatus();
void ensureVRR(PHLMONITOR pMonitor = nullptr); void ensureVRR(PHLMONITOR pMonitor = nullptr);
bool shouldUseSoftwareCursors(PHLMONITOR pMonitor); bool shouldUseSoftwareCursors();
void updateWatcher(); void updateWatcher();
std::string parseKeyword(const std::string&, const std::string&); std::string parseKeyword(const std::string&, const std::string&);
@@ -235,6 +214,7 @@ class CConfigManager {
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> 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&);
@@ -247,14 +227,44 @@ class CConfigManager {
std::string configCurrentPath; std::string configCurrentPath;
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> mbWindowProperties = {
{"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> miWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }},
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> mfWindowProperties = {
{"roundingpower", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.roundingPower; }},
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}};
bool m_bWantsMonitorReload = false; bool m_bWantsMonitorReload = false;
bool m_bNoMonitorReload = false; bool m_bNoMonitorReload = false;
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
bool m_bLastConfigVerificationWasSuccessful = true; bool m_bLastConfigVerificationWasSuccessful = true;
void storeFloatingSize(PHLWINDOW window, const Vector2D& size);
std::optional<Vector2D> getStoredFloatingSize(PHLWINDOW window);
private: private:
UP<Hyprlang::CConfig> m_pConfig; UP<Hyprlang::CConfig> m_pConfig;
@@ -287,8 +297,6 @@ class CConfigManager {
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 = "";
uint32_t m_configValueNumber = 0;
// internal methods // internal methods
void updateBlurredLS(const std::string&, const bool); void updateBlurredLS(const std::string&, const bool);
void setDefaultAnimationVars(); void setDefaultAnimationVars();
@@ -297,16 +305,6 @@ class CConfigManager {
std::optional<std::string> verifyConfigExists(); std::optional<std::string> verifyConfigExists();
void postConfigReload(const Hyprlang::CParseResult& result); void postConfigReload(const Hyprlang::CParseResult& result);
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);
void registerConfigVar(const char* name, const Hyprlang::INT& val);
void registerConfigVar(const char* name, const Hyprlang::FLOAT& val);
void registerConfigVar(const char* name, const Hyprlang::VEC2& val);
void registerConfigVar(const char* name, const Hyprlang::STRING& val);
void registerConfigVar(const char* name, Hyprlang::CUSTOMTYPE&& val);
std::unordered_map<SFloatCache, Vector2D> m_mStoredFloatingSizes;
friend struct SConfigOptionDescription;
}; };
inline UP<CConfigManager> g_pConfigManager; inline UP<CConfigManager> g_pConfigManager;

View File

@@ -6,24 +6,27 @@
#include <unistd.h> #include <unistd.h>
#include <filesystem> #include <filesystem>
using namespace Hyprutils::OS;
CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) { CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) {
if (!m_inotifyFd.isValid()) { if (m_inotifyFd < 0) {
Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded"); Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded");
return; return;
} }
// TODO: make CFileDescriptor take F_GETFL, F_SETFL const int FLAGS = fcntl(m_inotifyFd, F_GETFL, 0);
const int FLAGS = fcntl(m_inotifyFd.get(), F_GETFL, 0); if (fcntl(m_inotifyFd, F_SETFL, FLAGS | O_NONBLOCK) < 0) {
if (fcntl(m_inotifyFd.get(), F_SETFL, FLAGS | O_NONBLOCK) < 0) {
Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded"); Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded");
m_inotifyFd.reset(); close(m_inotifyFd);
m_inotifyFd = -1;
return; return;
} }
} }
CFileDescriptor& CConfigWatcher::getInotifyFD() { CConfigWatcher::~CConfigWatcher() {
if (m_inotifyFd >= 0)
close(m_inotifyFd);
}
int CConfigWatcher::getInotifyFD() {
return m_inotifyFd; return m_inotifyFd;
} }
@@ -36,7 +39,7 @@ void CConfigWatcher::setWatchList(const std::vector<std::string>& paths) {
// cleanup old paths // cleanup old paths
for (auto& watch : m_watches) { for (auto& watch : m_watches) {
inotify_rm_watch(m_inotifyFd.get(), watch.wd); inotify_rm_watch(m_inotifyFd, watch.wd);
} }
m_watches.clear(); m_watches.clear();
@@ -44,7 +47,7 @@ void CConfigWatcher::setWatchList(const std::vector<std::string>& paths) {
// add new paths // add new paths
for (const auto& path : paths) { for (const auto& path : paths) {
m_watches.emplace_back(SInotifyWatch{ m_watches.emplace_back(SInotifyWatch{
.wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY | IN_DONT_FOLLOW), .wd = inotify_add_watch(m_inotifyFd, path.c_str(), IN_MODIFY | IN_DONT_FOLLOW),
.file = path, .file = path,
}); });
@@ -53,7 +56,7 @@ void CConfigWatcher::setWatchList(const std::vector<std::string>& paths) {
const auto IS_SYMLINK = std::filesystem::is_symlink(path, ec2); const auto IS_SYMLINK = std::filesystem::is_symlink(path, ec2);
if (!ec && !ec2 && IS_SYMLINK) { if (!ec && !ec2 && IS_SYMLINK) {
m_watches.emplace_back(SInotifyWatch{ m_watches.emplace_back(SInotifyWatch{
.wd = inotify_add_watch(m_inotifyFd.get(), CANONICAL.c_str(), IN_MODIFY), .wd = inotify_add_watch(m_inotifyFd, CANONICAL.c_str(), IN_MODIFY),
.file = path, .file = path,
}); });
} }
@@ -66,7 +69,7 @@ void CConfigWatcher::setOnChange(const std::function<void(const SConfigWatchEven
void CConfigWatcher::onInotifyEvent() { void CConfigWatcher::onInotifyEvent() {
inotify_event ev; inotify_event ev;
while (read(m_inotifyFd.get(), &ev, sizeof(ev)) > 0) { while (read(m_inotifyFd, &ev, sizeof(ev)) > 0) {
const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; }); const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; });
if (WD == m_watches.end()) { if (WD == m_watches.end()) {

View File

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

View File

@@ -152,10 +152,10 @@ animations {
# uncomment all if you wish to use that. # uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] # windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrule = rounding 0, floating:0, onworkspace:w[tv1] # windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrule = bordersize 0, floating:0, onworkspace:f[1] # windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrule = rounding 0, floating:0, onworkspace:f[1] # windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
@@ -269,7 +269,7 @@ bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness # Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
@@ -289,12 +289,15 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules # See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule # Example windowrule v1
# windowrule = float,class:^(kitty)$,title:^(kitty)$ # windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.* windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland # Fix some dragging issues with XWayland
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
)#"; )#";

View File

@@ -25,7 +25,6 @@
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::OS;
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
@@ -264,8 +263,8 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"),
(int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), (int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass),
escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
(uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.get(), (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false")); (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false"));
} else { } else {
return std::format( return std::format(
"Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: " "Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
@@ -276,7 +275,7 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
(int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle,
w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal,
(uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.get(), getFocusHistoryID(w), (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w),
(int)g_pInputManager->isWindowInhibiting(w, false)); (int)g_pInputManager->isWindowInhibiting(w, false));
} }
} }
@@ -319,17 +318,15 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form
"windows": {}, "windows": {},
"hasfullscreen": {}, "hasfullscreen": {},
"lastwindow": "0x{:x}", "lastwindow": "0x{:x}",
"lastwindowtitle": "{}", "lastwindowtitle": "{}"
"ispersistent": {}
}})#", }})#",
w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"), w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"),
escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), w->m_bHasFullscreenWindow ? "true" : "false", escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"),
(uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "", w->m_bPersistent ? "true" : "false"); (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
} else { } else {
return std::format( return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID,
"workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\tispersistent: {}\n\n", w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow,
w->m_iID, w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow, (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "");
(uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "", (int)w->m_bPersistent);
} }
} }
@@ -479,11 +476,9 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
"y": {}, "y": {},
"w": {}, "w": {},
"h": {}, "h": {},
"namespace": "{}", "namespace": "{}"
"pid": {}
}},)#", }},)#",
(uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, escapeJSONStrings(layer->szNamespace), (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, escapeJSONStrings(layer->szNamespace));
layer->getPID());
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -514,8 +509,8 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]); result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]);
for (auto const& layer : level) { for (auto const& layer : level) {
result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}, pid: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width,
layer->geometry.width, layer->geometry.height, layer->szNamespace, layer->getPID()); layer->geometry.height, layer->szNamespace);
} }
layerLevel++; layerLevel++;
@@ -813,11 +808,8 @@ static std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::stri
std::string ret = ""; std::string ret = "";
const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts(); const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts();
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto const& sh : SHORTCUTS) { for (auto const& sh : SHORTCUTS)
ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description);
}
if (ret.empty())
ret = "none";
} else { } else {
ret += "["; ret += "[";
for (auto const& sh : SHORTCUTS) { for (auto const& sh : SHORTCUTS) {
@@ -1688,6 +1680,8 @@ CHyprCtl::CHyprCtl() {
CHyprCtl::~CHyprCtl() { CHyprCtl::~CHyprCtl() {
if (m_eventSource) if (m_eventSource)
wl_event_source_remove(m_eventSource); wl_event_source_remove(m_eventSource);
if (m_iSocketFD >= 0)
close(m_iSocketFD);
if (!m_socketPath.empty()) if (!m_socketPath.empty())
unlink(m_socketPath.c_str()); unlink(m_socketPath.c_str());
} }
@@ -1846,13 +1840,10 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
return 0; return 0;
if (!g_pHyprCtl->m_iSocketFD.isValid())
return 0;
sockaddr_in clientAddress; sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress); socklen_t clientSize = sizeof(clientAddress);
const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
std::array<char, 1024> readBuffer; std::array<char, 1024> readBuffer;
@@ -1909,9 +1900,9 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
} }
void CHyprCtl::startHyprCtlSocket() { void CHyprCtl::startHyprCtlSocket() {
m_iSocketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)}; m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (!m_iSocketFD.isValid()) { if (m_iSocketFD < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
return; return;
} }
@@ -1922,15 +1913,15 @@ void CHyprCtl::startHyprCtlSocket() {
strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str()); strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str());
if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work.");
return; return;
} }
// 10 max queued. // 10 max queued.
listen(m_iSocketFD.get(), 10); listen(m_iSocketFD, 10);
Debug::log(LOG, "Hypr socket started at {}", m_socketPath); Debug::log(LOG, "Hypr socket started at {}", m_socketPath);
m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr); m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
} }

View File

@@ -4,7 +4,6 @@
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#include "../desktop/Window.hpp" #include "../desktop/Window.hpp"
#include <functional> #include <functional>
#include <hyprutils/os/FileDescriptor.hpp>
// exposed for main.cpp // exposed for main.cpp
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request);
@@ -20,7 +19,7 @@ class CHyprCtl {
void unregisterCommand(const SP<SHyprCtlCommand>& cmd); void unregisterCommand(const SP<SHyprCtlCommand>& cmd);
std::string getReply(std::string); std::string getReply(std::string);
Hyprutils::OS::CFileDescriptor m_iSocketFD; int m_iSocketFD = -1;
struct { struct {
bool all = false; bool all = false;

View File

@@ -584,15 +584,3 @@ int CLayerSurface::popupsCount() {
MONITORID CLayerSurface::monitorID() { MONITORID CLayerSurface::monitorID() {
return monitor ? monitor->ID : MONITOR_INVALID; return monitor ? monitor->ID : MONITOR_INVALID;
} }
pid_t CLayerSurface::getPID() {
pid_t PID = -1;
if (!layerSurface || !layerSurface->surface || !layerSurface->surface->getResource() || !layerSurface->surface->getResource()->resource() ||
!layerSurface->surface->getResource()->resource()->client)
return -1;
wl_client_get_credentials(layerSurface->surface->getResource()->resource()->client, &PID, nullptr, nullptr);
return PID;
}

View File

@@ -61,8 +61,6 @@ class CLayerSurface {
std::string szNamespace = ""; std::string szNamespace = "";
UP<CPopup> popupHead; UP<CPopup> popupHead;
pid_t getPID();
void onDestroy(); void onDestroy();
void onMap(); void onMap();
void onUnmap(); void onUnmap();

View File

@@ -282,9 +282,6 @@ void CPopup::recheckTree() {
} }
void CPopup::recheckChildrenRecursive() { void CPopup::recheckChildrenRecursive() {
if (m_bInert || !m_pWLSurface)
return;
std::vector<WP<CPopup>> cpy; std::vector<WP<CPopup>> cpy;
std::ranges::for_each(m_vChildren, [&cpy](const auto& el) { cpy.emplace_back(el); }); std::ranges::for_each(m_vChildren, [&cpy](const auto& el) { cpy.emplace_back(el); });
for (auto const& c : cpy) { for (auto const& c : cpy) {
@@ -350,19 +347,18 @@ WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
continue; continue;
if (!allowsInput) { if (!allowsInput) {
const bool HASSURFACE = p->m_pResource && p->m_pResource->surface; const Vector2D offset =
p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{};
Vector2D offset = HASSURFACE ? p->m_pResource->surface->current.geometry.pos() : Vector2D{}; const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size();
Vector2D size = HASSURFACE ? p->m_pResource->surface->current.geometry.size() : p->size();
if (size == Vector2D{})
size = p->size();
const auto BOX = CBox{p->coordsGlobal() + offset, size}; const auto BOX = CBox{p->coordsGlobal() + offset, size};
if (BOX.containsPoint(globalCoords)) if (BOX.containsPoint(globalCoords))
return p; return p;
} else { } else {
const auto REGION = CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal()); const Vector2D offset =
p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{};
const auto REGION =
CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset);
if (REGION.containsPoint(globalCoords)) if (REGION.containsPoint(globalCoords))
return p; return p;
} }
@@ -370,7 +366,3 @@ WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
return {}; return {};
} }
bool CPopup::inert() const {
return m_bInert;
}

View File

@@ -34,7 +34,6 @@ class CPopup {
void recheckTree(); void recheckTree();
bool visible(); bool visible();
bool inert() const;
// will also loop over this node // will also loop over this node
void breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data); void breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data);

View File

@@ -50,6 +50,10 @@ UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, WP<CP
return subsurface; return subsurface;
} }
CSubsurface::~CSubsurface() {
;
}
void CSubsurface::initSignals() { void CSubsurface::initSignals() {
if (m_pSubsurface) { if (m_pSubsurface) {
listeners.commitSubsurface = m_pSubsurface->surface->events.commit.registerListener([this](std::any d) { onCommit(); }); listeners.commitSubsurface = m_pSubsurface->surface->events.commit.registerListener([this](std::any d) { onCommit(); });
@@ -107,7 +111,7 @@ void CSubsurface::onCommit() {
g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y);
if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface) if (m_pPopupParent)
m_pPopupParent->recheckTree(); m_pPopupParent->recheckTree();
if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this
m_pWindowParent->m_pPopupHead->recheckTree(); m_pWindowParent->m_pPopupHead->recheckTree();
@@ -124,7 +128,7 @@ void CSubsurface::onCommit() {
// g_pHyprRenderer->damageBox(box); // g_pHyprRenderer->damageBox(box);
CBox box; CBox box;
if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface) if (m_pPopupParent)
box = m_pPopupParent->m_pWLSurface->getSurfaceBoxGlobal().value_or(CBox{}); box = m_pPopupParent->m_pWLSurface->getSurfaceBoxGlobal().value_or(CBox{});
else if (m_pWindowParent) else if (m_pWindowParent)
box = m_pWindowParent->getWindowMainSurfaceBox(); box = m_pWindowParent->getWindowMainSurfaceBox();

View File

@@ -17,7 +17,7 @@ class CSubsurface {
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner); static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner);
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner); static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner);
~CSubsurface() = default; ~CSubsurface();
Vector2D coordsRelativeToParent(); Vector2D coordsRelativeToParent();
Vector2D coordsGlobal(); Vector2D coordsGlobal();

View File

@@ -98,7 +98,7 @@ CRegion CWLSurface::computeDamage() const {
if (!m_pResource->current.texture) if (!m_pResource->current.texture)
return {}; return {};
CRegion damage = m_pResource->current.accumulateBufferDamage(); CRegion damage = m_pResource->accumulateCurrentBufferDamage();
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y); damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y);
const auto BUFSIZE = m_pResource->current.bufferSize; const auto BUFSIZE = m_pResource->current.bufferSize;

View File

@@ -13,10 +13,8 @@
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../managers/TokenManager.hpp" #include "../managers/TokenManager.hpp"
#include "../managers/AnimationManager.hpp" #include "../managers/AnimationManager.hpp"
#include "../managers/ANRManager.hpp"
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/ContentType.hpp"
#include "../xwayland/XWayland.hpp" #include "../xwayland/XWayland.hpp"
#include "../helpers/Color.hpp" #include "../helpers/Color.hpp"
#include "../events/Events.hpp" #include "../events/Events.hpp"
@@ -31,7 +29,6 @@
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::Animation; using namespace Hyprutils::Animation;
using enum NContentType::eContentType;
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));
@@ -49,7 +46,6 @@ PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow)); pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow)); pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
@@ -73,7 +69,6 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow)); pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow)); pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
@@ -102,7 +97,7 @@ CWindow::CWindow(SP<CXWaylandSurface> surface) : m_pXWaylandSurface(surface) {
listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); });
listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); }); listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); });
listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); }); listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); });
listeners.configureRequest = m_pXWaylandSurface->events.configureRequest.registerListener([this](std::any d) { onX11ConfigureRequest(std::any_cast<CBox>(d)); }); listeners.configure = m_pXWaylandSurface->events.configure.registerListener([this](std::any d) { onX11Configure(std::any_cast<CBox>(d)); });
listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); }); listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); });
listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); }); listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); });
listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); }); listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); });
@@ -113,7 +108,7 @@ CWindow::CWindow(SP<CXWaylandSurface> surface) : m_pXWaylandSurface(surface) {
} }
CWindow::~CWindow() { CWindow::~CWindow() {
if (g_pCompositor->m_pLastWindow == m_pSelf) { if (g_pCompositor->m_pLastWindow.lock().get() == this) {
g_pCompositor->m_pLastFocus.reset(); g_pCompositor->m_pLastFocus.reset();
g_pCompositor->m_pLastWindow.reset(); g_pCompositor->m_pLastWindow.reset();
} }
@@ -124,7 +119,7 @@ CWindow::~CWindow() {
return; return;
g_pHyprRenderer->makeEGLCurrent(); g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.get() == this; }); std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return !other.first.lock() || other.first.lock().get() == this; });
} }
SBoxExtents CWindow::getFullWindowExtents() { SBoxExtents CWindow::getFullWindowExtents() {
@@ -415,7 +410,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
if (*PINITIALWSTRACKING == 2) { if (*PINITIALWSTRACKING == 2) {
// persistent // persistent
SInitialWorkspaceToken token = std::any_cast<SInitialWorkspaceToken>(TOKEN->data); SInitialWorkspaceToken token = std::any_cast<SInitialWorkspaceToken>(TOKEN->data);
if (token.primaryOwner == m_pSelf) { if (token.primaryOwner.lock().get() == this) {
token.workspace = pWorkspace->getConfigName(); token.workspace = pWorkspace->getConfigName();
TOKEN->data = token; TOKEN->data = token;
} }
@@ -455,11 +450,12 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
} }
if (const auto SWALLOWED = m_pSwallowed.lock()) { if (const auto SWALLOWED = m_pSwallowed.lock()) {
if (SWALLOWED->m_bCurrentlySwallowed) {
SWALLOWED->moveToWorkspace(pWorkspace); SWALLOWED->moveToWorkspace(pWorkspace);
SWALLOWED->m_pMonitor = m_pMonitor; SWALLOWED->m_pMonitor = m_pMonitor;
} }
}
// update xwayland coords
sendWindowSize(m_vRealSize->goal());
if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) {
if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR)
@@ -505,7 +501,7 @@ void CWindow::onUnmap() {
if (*PINITIALWSTRACKING == 2) { if (*PINITIALWSTRACKING == 2) {
// persistent token, but the first window got removed so the token is gone // persistent token, but the first window got removed so the token is gone
SInitialWorkspaceToken token = std::any_cast<SInitialWorkspaceToken>(TOKEN->data); SInitialWorkspaceToken token = std::any_cast<SInitialWorkspaceToken>(TOKEN->data);
if (token.primaryOwner == m_pSelf) if (token.primaryOwner.lock().get() == this)
g_pTokenManager->removeToken(TOKEN); g_pTokenManager->removeToken(TOKEN);
} }
} }
@@ -513,7 +509,7 @@ void CWindow::onUnmap() {
m_iLastWorkspace = m_pWorkspace->m_iID; m_iLastWorkspace = m_pWorkspace->m_iID;
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [this](const auto& other) { return other.expired() || other == m_pSelf; }); 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 && m_pWorkspace && m_pWorkspace->getWindows() == 0 && onSpecialWorkspace()) {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_pMonitor.lock();
@@ -523,7 +519,7 @@ void CWindow::onUnmap() {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR && PMONITOR->solitaryClient == m_pSelf) if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this)
PMONITOR->solitaryClient.reset(); PMONITOR->solitaryClient.reset();
if (m_pWorkspace) { if (m_pWorkspace) {
@@ -563,15 +559,6 @@ void CWindow::onMap() {
*m_fBorderAngleAnimationProgress = 1.f; *m_fBorderAngleAnimationProgress = 1.f;
} }
m_vRealSize->setCallbackOnBegin(
[this](auto) {
if (!m_bIsMapped || isX11OverrideRedirect())
return;
sendWindowSize();
},
false);
m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F);
g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf); g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf);
@@ -609,8 +596,9 @@ void CWindow::onBorderAngleAnimEnd(WP<CBaseAnimatedVariable> pav) {
void CWindow::setHidden(bool hidden) { void CWindow::setHidden(bool hidden) {
m_bHidden = hidden; m_bHidden = hidden;
if (hidden && g_pCompositor->m_pLastWindow == m_pSelf) if (hidden && g_pCompositor->m_pLastWindow.lock().get() == this) {
g_pCompositor->m_pLastWindow.reset(); g_pCompositor->m_pLastWindow.reset();
}
setSuspended(hidden); setSuspended(hidden);
} }
@@ -776,25 +764,21 @@ void CWindow::applyDynamicRule(const SP<CWindowRule>& r) {
} }
case CWindowRule::RULE_PROP: { case CWindowRule::RULE_PROP: {
const CVarList VARS(r->szRule, 0, ' '); const CVarList VARS(r->szRule, 0, ' ');
if (auto search = NWindowProperties::intWindowProperties.find(VARS[1]); search != NWindowProperties::intWindowProperties.end()) { if (auto search = g_pConfigManager->miWindowProperties.find(VARS[1]); search != g_pConfigManager->miWindowProperties.end()) {
try { try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[2]), priority); *(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()); } } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = NWindowProperties::floatWindowProperties.find(VARS[1]); search != NWindowProperties::floatWindowProperties.end()) { } else if (auto search = g_pConfigManager->mfWindowProperties.find(VARS[1]); search != g_pConfigManager->mfWindowProperties.end()) {
try { try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stof(VARS[2]), priority); *(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()); } } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = NWindowProperties::boolWindowProperties.find(VARS[1]); search != NWindowProperties::boolWindowProperties.end()) { } else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[1]); search != g_pConfigManager->mbWindowProperties.end()) {
try { try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(VARS[2].empty() ? true : (bool)std::stoi(VARS[2]), priority); *(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()); } } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} }
break; break;
} }
case CWindowRule::RULE_PERSISTENTSIZE: {
m_sWindowData.persistentSize = CWindowOverridableVar(true, PRIORITY_WINDOW_RULE);
break;
}
default: break; default: break;
} }
} }
@@ -904,7 +888,7 @@ void CWindow::createGroup() {
} }
void CWindow::destroyGroup() { void CWindow::destroyGroup() {
if (m_sGroupData.pNextWindow == m_pSelf) { if (m_sGroupData.pNextWindow.lock().get() == this) {
if (m_eGroupRules & GROUP_SET_ALWAYS) { if (m_eGroupRules & GROUP_SET_ALWAYS) {
Debug::log(LOG, "destoryGroup: window:{:x},title:{} has rule [group set always], ignored", (uintptr_t)this, this->m_szTitle); Debug::log(LOG, "destoryGroup: window:{:x},title:{} has rule [group set always], ignored", (uintptr_t)this, this->m_szTitle);
return; return;
@@ -986,7 +970,7 @@ PHLWINDOW CWindow::getGroupCurrent() {
int CWindow::getGroupSize() { int CWindow::getGroupSize() {
int size = 1; int size = 1;
PHLWINDOW curr = m_pSelf.lock(); PHLWINDOW curr = m_pSelf.lock();
while (curr->m_sGroupData.pNextWindow != m_pSelf) { while (curr->m_sGroupData.pNextWindow.lock().get() != this) {
curr = curr->m_sGroupData.pNextWindow.lock(); curr = curr->m_sGroupData.pNextWindow.lock();
size++; size++;
} }
@@ -1092,7 +1076,7 @@ void CWindow::insertWindowToGroup(PHLWINDOW pWindow) {
PHLWINDOW CWindow::getGroupPrevious() { PHLWINDOW CWindow::getGroupPrevious() {
PHLWINDOW curr = m_sGroupData.pNextWindow.lock(); PHLWINDOW curr = m_sGroupData.pNextWindow.lock();
while (curr != m_pSelf && curr->m_sGroupData.pNextWindow != m_pSelf) while (curr != m_pSelf.lock() && curr->m_sGroupData.pNextWindow.lock().get() != this)
curr = curr->m_sGroupData.pNextWindow.lock(); curr = curr->m_sGroupData.pNextWindow.lock();
return curr; return curr;
@@ -1107,7 +1091,7 @@ void CWindow::switchWithWindowInGroup(PHLWINDOW pWindow) {
m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow; m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow;
pWindow->m_sGroupData.pNextWindow = m_pSelf; pWindow->m_sGroupData.pNextWindow = m_pSelf;
} else if (pWindow->m_sGroupData.pNextWindow == m_pSelf) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B } else if (pWindow->m_sGroupData.pNextWindow.lock().get() == this) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B
pWindow->getGroupPrevious()->m_sGroupData.pNextWindow = m_pSelf; pWindow->getGroupPrevious()->m_sGroupData.pNextWindow = m_pSelf;
pWindow->m_sGroupData.pNextWindow = m_sGroupData.pNextWindow; pWindow->m_sGroupData.pNextWindow = m_sGroupData.pNextWindow;
m_sGroupData.pNextWindow = pWindow; m_sGroupData.pNextWindow = pWindow;
@@ -1258,7 +1242,7 @@ void CWindow::setAnimationsToMove() {
void CWindow::onWorkspaceAnimUpdate() { void CWindow::onWorkspaceAnimUpdate() {
// clip box for animated offsets // clip box for animated offsets
if (!m_bIsFloating || m_bPinned || isFullscreen() || m_bDraggingTiled) { if (!m_bIsFloating || m_bPinned || isFullscreen()) {
m_vFloatingOffset = Vector2D(0, 0); m_vFloatingOffset = Vector2D(0, 0);
return; return;
} }
@@ -1327,6 +1311,7 @@ void CWindow::clampWindowSize(const std::optional<Vector2D> minSize, const std::
*m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0; *m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0;
*m_vRealSize = NEWSIZE; *m_vRealSize = NEWSIZE;
sendWindowSize(NEWSIZE);
} }
bool CWindow::isFullscreen() { bool CWindow::isFullscreen() {
@@ -1536,21 +1521,21 @@ void CWindow::onResourceChangeX11() {
Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface->resource().get()); Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface->resource().get());
} }
void CWindow::onX11ConfigureRequest(CBox box) { void CWindow::onX11Configure(CBox box) {
if (!m_pXWaylandSurface->surface || !m_pXWaylandSurface->mapped || !m_bIsMapped) { if (!m_pXWaylandSurface->surface || !m_pXWaylandSurface->mapped || !m_bIsMapped) {
m_pXWaylandSurface->configure(box); m_pXWaylandSurface->configure(box);
m_vPendingReportedSize = box.size(); m_vPendingReportedSize = box.size();
m_vReportedSize = box.size(); m_vReportedSize = box.size();
m_vReportedPosition = box.pos(); if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
updateX11SurfaceScale(); m_fX11SurfaceScaledBy = PMONITOR->scale;
return; return;
} }
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());
if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) { if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) {
sendWindowSize(true); sendWindowSize(m_vRealSize->goal(), true);
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());
return; return;
@@ -1561,20 +1546,27 @@ void CWindow::onX11ConfigureRequest(CBox box) {
else else
setHidden(true); setHidden(true);
m_vRealPosition->setValueAndWarp(xwaylandPositionToReal(box.pos())); const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos());
m_vRealSize->setValueAndWarp(xwaylandSizeToReal(box.size()));
m_vRealPosition->setValueAndWarp(LOGICALPOS);
m_vRealSize->setValueAndWarp(box.size());
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) {
m_vRealSize->setValueAndWarp(m_vRealSize->goal() / PMONITOR->scale);
m_fX11SurfaceScaledBy = PMONITOR->scale;
}
}
m_vPosition = m_vRealPosition->goal(); m_vPosition = m_vRealPosition->goal();
m_vSize = m_vRealSize->goal(); m_vSize = m_vRealSize->goal();
if (m_vPendingReportedSize != box.size() || m_vReportedPosition != box.pos()) { sendWindowSize(box.size(), true);
m_pXWaylandSurface->configure(box);
m_vReportedSize = box.size(); m_vPendingReportedSize = box.size();
m_vPendingReportedSize = box.size(); m_vReportedSize = box.size();
m_vReportedPosition = box.pos();
}
updateX11SurfaceScale();
updateWindowDecos(); updateWindowDecos();
if (!m_pWorkspace || !m_pWorkspace->isVisible()) if (!m_pWorkspace || !m_pWorkspace->isVisible())
@@ -1630,17 +1622,17 @@ 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 !RE2::FullMatch(other->m_szClass, *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 RE2::FullMatch(other->m_szTitle, *PSWALLOWEXREGEX); });
if (candidates.size() == 0) if (candidates.size() <= 0)
return nullptr; return nullptr;
if (candidates.size() == 1) if (candidates.size() == 1)
return candidates[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 const& w : g_pCompositor->m_vWindowFocusHistory) {
@@ -1652,17 +1644,17 @@ PHLWINDOW CWindow::getSwallower() {
} }
// if none are found (??) then just return the first one // if none are found (??) then just return the first one
return candidates[0]; return candidates.at(0);
} }
void CWindow::unsetWindowData(eOverridePriority priority) { void CWindow::unsetWindowData(eOverridePriority priority) {
for (auto const& element : NWindowProperties::boolWindowProperties) { for (auto const& element : g_pConfigManager->mbWindowProperties) {
element.second(m_pSelf.lock())->unset(priority); element.second(m_pSelf.lock())->unset(priority);
} }
for (auto const& element : NWindowProperties::intWindowProperties) { for (auto const& element : g_pConfigManager->miWindowProperties) {
element.second(m_pSelf.lock())->unset(priority); element.second(m_pSelf.lock())->unset(priority);
} }
for (auto const& element : NWindowProperties::floatWindowProperties) { for (auto const& element : g_pConfigManager->mfWindowProperties) {
element.second(m_pSelf.lock())->unset(priority); element.second(m_pSelf.lock())->unset(priority);
} }
} }
@@ -1701,108 +1693,34 @@ Vector2D CWindow::requestedMaxSize() {
return maxSize; return maxSize;
} }
Vector2D CWindow::realToReportSize() { void CWindow::sendWindowSize(Vector2D size, bool force, std::optional<Vector2D> overridePos) {
if (!m_bIsX11)
return m_vRealSize->goal().clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling"); static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
const auto REPORTSIZE = m_vRealSize->goal().clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_pMonitor.lock();
if (*PXWLFORCESCALEZERO && PMONITOR) size = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
return REPORTSIZE * PMONITOR->scale;
return REPORTSIZE;
}
Vector2D CWindow::realToReportPosition() {
if (!m_bIsX11)
return m_vRealPosition->goal();
return g_pXWaylandManager->waylandToXWaylandCoords(m_vRealPosition->goal());
}
Vector2D CWindow::xwaylandSizeToReal(Vector2D size) {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
const auto PMONITOR = m_pMonitor.lock();
const auto SIZE = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});
const auto SCALE = *PXWLFORCESCALEZERO ? PMONITOR->scale : 1.0f;
return SIZE / SCALE;
}
Vector2D CWindow::xwaylandPositionToReal(Vector2D pos) {
return g_pXWaylandManager->xwaylandToWaylandCoords(pos);
}
void CWindow::updateX11SurfaceScale() {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
m_fX11SurfaceScaledBy = 1.0f;
if (m_bIsX11 && *PXWLFORCESCALEZERO) {
if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR)
m_fX11SurfaceScaledBy = PMONITOR->scale;
}
}
void CWindow::sendWindowSize(bool force) {
const auto PMONITOR = m_pMonitor.lock();
Debug::log(TRACE, "sendWindowSize: window:{:x},title:{} with real pos {}, real size {} (force: {})", (uintptr_t)this, this->m_szTitle, m_vRealPosition->goal(),
m_vRealSize->goal(), force);
// calculate pos
// TODO: this should be decoupled from setWindowSize IMO // TODO: this should be decoupled from setWindowSize IMO
const auto REPORTPOS = realToReportPosition(); Vector2D windowPos = overridePos.value_or(m_vRealPosition->goal());
const auto REPORTSIZE = realToReportSize(); if (m_bIsX11 && PMONITOR) {
windowPos = g_pXWaylandManager->waylandToXWaylandCoords(windowPos);
if (*PXWLFORCESCALEZERO)
size *= PMONITOR->scale;
}
if (!force && m_vPendingReportedSize == REPORTSIZE && (m_vReportedPosition == REPORTPOS || !m_bIsX11)) if (!force && m_vPendingReportedSize == size && (windowPos == m_vReportedPosition || !m_bIsX11))
return; return;
m_vReportedPosition = REPORTPOS; m_vReportedPosition = windowPos;
m_vPendingReportedSize = REPORTSIZE; m_vPendingReportedSize = size;
updateX11SurfaceScale(); m_fX11SurfaceScaledBy = 1.0f;
if (*PXWLFORCESCALEZERO && m_bIsX11 && PMONITOR)
m_fX11SurfaceScaledBy = PMONITOR->scale;
if (m_bIsX11 && m_pXWaylandSurface) if (m_bIsX11 && m_pXWaylandSurface)
m_pXWaylandSurface->configure({REPORTPOS, REPORTSIZE}); m_pXWaylandSurface->configure({windowPos, size});
else if (m_pXDGSurface && m_pXDGSurface->toplevel) else if (m_pXDGSurface && m_pXDGSurface->toplevel)
m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(REPORTSIZE), REPORTPOS.floor()); m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(size), size.floor());
}
NContentType::eContentType CWindow::getContentType() {
if (!m_pWLSurface || !m_pWLSurface->resource() || !m_pWLSurface->resource()->contentType.valid())
return CONTENT_TYPE_NONE;
return m_pWLSurface->resource()->contentType->value;
}
void CWindow::setContentType(NContentType::eContentType contentType) {
if (!m_pWLSurface->resource()->contentType.valid())
m_pWLSurface->resource()->contentType = PROTO::contentType->getContentType(m_pWLSurface->resource());
// else disallow content type change if proto is used?
Debug::log(INFO, "ContentType for window {}", (int)contentType);
m_pWLSurface->resource()->contentType->value = contentType;
}
void CWindow::deactivateGroupMembers() {
auto curr = getGroupHead();
while (curr) {
if (curr != m_pSelf.lock()) {
if (curr->m_bIsX11)
curr->m_pXWaylandSurface->activate(false);
else if (curr->m_pXDGSurface && curr->m_pXDGSurface->toplevel)
curr->m_pXDGSurface->toplevel->setActive(false);
}
curr = curr->m_sGroupData.pNextWindow.lock();
if (curr == getGroupHead())
break;
}
}
bool CWindow::isNotResponding() {
return g_pANRManager->isNotResponding(m_pSelf.lock());
} }

View File

@@ -19,7 +19,6 @@
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "Workspace.hpp" #include "Workspace.hpp"
#include "WindowRule.hpp" #include "WindowRule.hpp"
#include "../protocols/types/ContentType.hpp"
class CXDGSurfaceResource; class CXDGSurfaceResource;
class CXWaylandSurface; class CXWaylandSurface;
@@ -198,8 +197,6 @@ struct SWindowData {
CWindowOverridableVar<CGradientValueData> activeBorderColor; CWindowOverridableVar<CGradientValueData> activeBorderColor;
CWindowOverridableVar<CGradientValueData> inactiveBorderColor; CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
CWindowOverridableVar<bool> persistentSize;
}; };
struct SInitialWorkspaceToken { struct SInitialWorkspaceToken {
@@ -357,7 +354,6 @@ class CWindow {
// swallowing // swallowing
PHLWINDOWREF m_pSwallowed; PHLWINDOWREF m_pSwallowed;
bool m_bCurrentlySwallowed = false;
bool m_bGroupSwallowed = false; bool m_bGroupSwallowed = false;
// focus stuff // focus stuff
@@ -390,9 +386,6 @@ class CWindow {
// window tags // window tags
CTagKeeper m_tags; CTagKeeper m_tags;
// ANR
PHLANIMVAR<float> m_notRespondingTint;
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) const { bool operator==(const CWindow& rhs) const {
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
@@ -465,7 +458,7 @@ class CWindow {
void onFocusAnimUpdate(); void onFocusAnimUpdate();
void onUpdateState(); void onUpdateState();
void onUpdateMeta(); void onUpdateMeta();
void onX11ConfigureRequest(CBox box); void onX11Configure(CBox box);
void onResourceChangeX11(); void onResourceChangeX11();
std::string fetchTitle(); std::string fetchTitle();
std::string fetchClass(); std::string fetchClass();
@@ -476,16 +469,7 @@ class CWindow {
bool isModal(); bool isModal();
Vector2D requestedMinSize(); Vector2D requestedMinSize();
Vector2D requestedMaxSize(); Vector2D requestedMaxSize();
Vector2D realToReportSize(); void sendWindowSize(Vector2D size, bool force = false, std::optional<Vector2D> overridePos = std::nullopt);
Vector2D realToReportPosition();
Vector2D xwaylandSizeToReal(Vector2D size);
Vector2D xwaylandPositionToReal(Vector2D size);
void updateX11SurfaceScale();
void sendWindowSize(bool force = false);
NContentType::eContentType getContentType();
void setContentType(NContentType::eContentType contentType);
void deactivateGroupMembers();
bool isNotResponding();
CBox getWindowMainSurfaceBox() const { CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y};
@@ -508,7 +492,7 @@ class CWindow {
CHyprSignalListener commit; CHyprSignalListener commit;
CHyprSignalListener destroy; CHyprSignalListener destroy;
CHyprSignalListener activate; CHyprSignalListener activate;
CHyprSignalListener configureRequest; CHyprSignalListener configure;
CHyprSignalListener setGeometry; CHyprSignalListener setGeometry;
CHyprSignalListener updateState; CHyprSignalListener updateState;
CHyprSignalListener updateMetadata; CHyprSignalListener updateMetadata;
@@ -542,42 +526,6 @@ inline bool validMapped(PHLWINDOWREF w) {
return w->m_bIsMapped; return w->m_bIsMapped;
} }
namespace NWindowProperties {
static const std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> boolWindowProperties = {
{"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }},
};
const std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> intWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }},
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }},
};
const std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> floatWindowProperties = {
{"roundingpower", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.roundingPower; }},
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }},
};
};
/** /**
format specification format specification
- 'x', only address, equivalent of (uintpr_t)CWindow* - 'x', only address, equivalent of (uintpr_t)CWindow*

View File

@@ -5,20 +5,19 @@
#include "../config/ConfigManager.hpp" #include "../config/ConfigManager.hpp"
static const auto RULES = std::unordered_set<std::string>{ static const auto RULES = std::unordered_set<std::string>{
"float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", "persistentsize", "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused",
}; };
static const auto RULES_PREFIX = std::unordered_set<std::string>{ static const auto RULES_PREFIX = std::unordered_set<std::string>{
"animation", "bordercolor", "bordersize", "center", "content", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity",
"monitor", "move", "opacity", "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray",
"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) { CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) {
const auto VALS = CVarList(rule, 2, ' '); const auto VALS = CVarList(rule, 2, ' ');
const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule](auto prefix) { return rule.starts_with(prefix); }) || const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule](auto prefix) { return rule.starts_with(prefix); }) ||
(NWindowProperties::boolWindowProperties.find(VALS[0]) != NWindowProperties::boolWindowProperties.end()) || (g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) ||
(NWindowProperties::intWindowProperties.find(VALS[0]) != NWindowProperties::intWindowProperties.end()) || (g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end()) ||
(NWindowProperties::floatWindowProperties.find(VALS[0]) != NWindowProperties::floatWindowProperties.end()); (g_pConfigManager->mfWindowProperties.find(VALS[0]) != g_pConfigManager->mfWindowProperties.end());
if (!VALID) if (!VALID)
return; return;
@@ -39,8 +38,6 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool
ruleType = RULE_TILE; ruleType = RULE_TILE;
else if (rule == "renderunfocused") else if (rule == "renderunfocused")
ruleType = RULE_RENDERUNFOCUSED; ruleType = RULE_RENDERUNFOCUSED;
else if (rule == "persistentsize")
ruleType = RULE_PERSISTENTSIZE;
else if (rule.starts_with("animation")) else if (rule.starts_with("animation"))
ruleType = RULE_ANIMATION; ruleType = RULE_ANIMATION;
else if (rule.starts_with("bordercolor")) else if (rule.starts_with("bordercolor"))
@@ -77,14 +74,12 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool
ruleType = RULE_WORKSPACE; ruleType = RULE_WORKSPACE;
else if (rule.starts_with("prop")) else if (rule.starts_with("prop"))
ruleType = RULE_PROP; ruleType = RULE_PROP;
else if (rule.starts_with("content"))
ruleType = RULE_CONTENT;
else { else {
// check if this is a prop. // check if this is a prop.
const CVarList VARS(rule, 0, 's', true); const CVarList VARS(rule, 0, 's', true);
if (NWindowProperties::intWindowProperties.find(VARS[0]) != NWindowProperties::intWindowProperties.end() || if (g_pConfigManager->miWindowProperties.find(VARS[0]) != g_pConfigManager->miWindowProperties.end() ||
NWindowProperties::boolWindowProperties.find(VARS[0]) != NWindowProperties::boolWindowProperties.end() || g_pConfigManager->mbWindowProperties.find(VARS[0]) != g_pConfigManager->mbWindowProperties.end() ||
NWindowProperties::floatWindowProperties.find(VARS[0]) != NWindowProperties::floatWindowProperties.end()) { g_pConfigManager->mfWindowProperties.find(VARS[0]) != g_pConfigManager->mfWindowProperties.end()) {
*const_cast<std::string*>(&szRule) = "prop " + rule; *const_cast<std::string*>(&szRule) = "prop " + rule;
ruleType = RULE_PROP; ruleType = RULE_PROP;
Debug::log(LOG, "CWindowRule: direct prop rule found, rewritten {} -> {}", rule, szRule); Debug::log(LOG, "CWindowRule: direct prop rule found, rewritten {} -> {}", rule, szRule);

View File

@@ -36,8 +36,6 @@ class CWindowRule {
RULE_TAG, RULE_TAG,
RULE_WORKSPACE, RULE_WORKSPACE,
RULE_PROP, RULE_PROP,
RULE_CONTENT,
RULE_PERSISTENTSIZE,
}; };
eRuleType ruleType = RULE_INVALID; eRuleType ruleType = RULE_INVALID;
@@ -60,7 +58,6 @@ class CWindowRule {
std::string szFullscreenState = ""; // empty means any std::string szFullscreenState = ""; // empty means any
std::string szOnWorkspace = ""; // empty means any std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any std::string szWorkspace = ""; // empty means any
std::string szContentType = ""; // empty means any
// precompiled regexes // precompiled regexes
CRuleRegexContainer rTitle; CRuleRegexContainer rTitle;

View File

@@ -261,7 +261,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
// n - named: n[true] or n[s:string] or n[e:string] // n - named: n[true] or n[s:string] or n[e:string]
// m - monitor: m[monitor_selector] // m - monitor: m[monitor_selector]
// w - windowCount: w[1-4] or w[1], optional flag t or f for tiled or floating and // w - windowCount: w[1-4] or w[1], optional flag t or f for tiled or floating and
// flag p to count only pinned windows, e.g. w[p1-2], w[pg4]
// flag g to count groups instead of windows, e.g. w[t1-2], w[fg4] // flag g to count groups instead of windows, e.g. w[t1-2], w[fg4]
// flag v will count only visible windows // flag v will count only visible windows
// f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states // f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states
@@ -371,7 +370,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
prop = prop.substr(2, prop.length() - 3); prop = prop.substr(2, prop.length() - 3);
int wantsOnlyTiled = -1; int wantsOnlyTiled = -1;
int wantsOnlyPinned = false;
bool wantsCountGroup = false; bool wantsCountGroup = false;
bool wantsCountVisible = false; bool wantsCountVisible = false;
@@ -383,9 +381,6 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
} else if (flag == 'f' && wantsOnlyTiled == -1) { } else if (flag == 'f' && wantsOnlyTiled == -1) {
wantsOnlyTiled = 0; wantsOnlyTiled = 0;
flagCount++; flagCount++;
} else if (flag == 'p' && !wantsOnlyPinned) {
wantsOnlyPinned = true;
flagCount++;
} else if (flag == 'g' && !wantsCountGroup) { } else if (flag == 'g' && !wantsCountGroup) {
wantsCountGroup = true; wantsCountGroup = true;
flagCount++; flagCount++;
@@ -416,11 +411,9 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
int count; int count;
if (wantsCountGroup) if (wantsCountGroup)
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (count != from) if (count != from)
@@ -451,12 +444,10 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
WORKSPACEID count; WORKSPACEID count;
if (wantsCountGroup) if (wantsCountGroup)
count = count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else else
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsOnlyPinned ? std::optional<bool>(wantsOnlyPinned) : std::nullopt,
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (std::clamp(count, from, to) != count) if (std::clamp(count, from, to) != count)
@@ -544,15 +535,13 @@ bool CWorkspace::isVisibleNotCovered() {
return PMONITOR->activeWorkspace->m_iID == m_iID; return PMONITOR->activeWorkspace->m_iID == m_iID;
} }
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) { int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0; int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped) if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue; continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue; continue;
if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue; continue;
no++; no++;
@@ -561,7 +550,7 @@ int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> on
return no; return no;
} }
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) { int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0; int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped) if (w->workspaceID() != m_iID || !w->m_bIsMapped)
@@ -570,8 +559,6 @@ int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onl
continue; continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue; continue;
if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue; continue;
no++; no++;
@@ -637,7 +624,7 @@ void CWorkspace::forceReportSizesToWindows() {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue; continue;
w->sendWindowSize(true); w->sendWindowSize(w->m_vRealSize->goal(), true);
} }
} }
@@ -648,12 +635,6 @@ void CWorkspace::rename(const std::string& name) {
Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name); Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name);
m_szName = name; m_szName = name;
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock());
m_bPersistent = WORKSPACERULE.isPersistent;
if (WORKSPACERULE.isPersistent)
g_pCompositor->ensurePersistentWorkspacesPresent(std::vector<SWorkspaceRule>{WORKSPACERULE}, m_pSelf.lock());
g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName}); g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName});
} }

View File

@@ -72,8 +72,8 @@ class CWorkspace {
SWorkspaceIDName getPrevWorkspaceIDName() const; SWorkspaceIDName getPrevWorkspaceIDName() const;
void updateWindowDecos(); void updateWindowDecos();
void updateWindowData(); void updateWindowData();
int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyPinned = {}, std::optional<bool> onlyVisible = {}); int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyPinned = {}, std::optional<bool> onlyVisible = {}); int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
bool hasUrgentWindow(); bool hasUrgentWindow();
PHLWINDOW getFirstWindow(); PHLWINDOW getFirstWindow();
PHLWINDOW getTopLeftWindow(); PHLWINDOW getTopLeftWindow();

View File

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

View File

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

View File

@@ -20,7 +20,6 @@ class IPointer : public IHID {
uint32_t timeMs = 0; uint32_t timeMs = 0;
Vector2D delta, unaccel; Vector2D delta, unaccel;
bool mouse = false; bool mouse = false;
SP<IPointer> device;
}; };
struct SMotionAbsoluteEvent { struct SMotionAbsoluteEvent {
@@ -110,9 +109,6 @@ class IPointer : public IHID {
bool connected = false; // means connected to the cursor bool connected = false; // means connected to the cursor
std::string boundOutput = ""; std::string boundOutput = "";
bool flipX = false; // decide to invert horizontal movement
bool flipY = false; // decide to invert vertical movement
bool isTouchpad = false;
WP<IPointer> self; WP<IPointer> self;
}; };

View File

@@ -14,11 +14,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
if (!mouse) if (!mouse)
return; return;
if (auto handle = mouse->getLibinputHandle()) {
double w = 0, h = 0;
isTouchpad = libinput_device_has_capability(handle, LIBINPUT_DEVICE_CAP_POINTER) && libinput_device_get_size(handle, &w, &h) == 0;
}
listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) { listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) {
mouse.reset(); mouse.reset();
events.destroy.emit(); events.destroy.emit();
@@ -32,7 +27,6 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.delta = E.delta, .delta = E.delta,
.unaccel = E.unaccel, .unaccel = E.unaccel,
.mouse = true, .mouse = true,
.device = self.lock(),
}); });
}); });

View File

@@ -19,11 +19,7 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
events.destroy.emit(); events.destroy.emit();
}); });
listeners.motion = pointer->events.move.registerListener([this](std::any d) { listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
auto E = std::any_cast<SMotionEvent>(d);
E.device = self.lock();
pointerEvents.motion.emit(E);
});
listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) { listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) {
// we need to unpack the event and add our device here because it's required to calculate the position correctly // we need to unpack the event and add our device here because it's required to calculate the position correctly
auto E = std::any_cast<SMotionAbsoluteEvent>(d); auto E = std::any_cast<SMotionAbsoluteEvent>(d);

View File

@@ -11,11 +11,11 @@
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/ToplevelExport.hpp" #include "../protocols/ToplevelExport.hpp"
#include "../protocols/types/ContentType.hpp"
#include "../xwayland/XSurface.hpp" #include "../xwayland/XSurface.hpp"
#include "managers/AnimationManager.hpp" #include "managers/AnimationManager.hpp"
#include "managers/PointerManager.hpp" #include "managers/PointerManager.hpp"
#include "../desktop/LayerSurface.hpp" #include "../desktop/LayerSurface.hpp"
#include "../managers/input/InputManager.hpp"
#include "../managers/LayoutManager.hpp" #include "../managers/LayoutManager.hpp"
#include "../managers/EventManager.hpp" #include "../managers/EventManager.hpp"
#include "../managers/AnimationManager.hpp" #include "../managers/AnimationManager.hpp"
@@ -307,13 +307,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
break; break;
} }
case CWindowRule::RULE_CONTENT: {
const CVarList VARS(r->szRule, 0, ' ');
try {
PWINDOW->setContentType(NContentType::fromString(VARS[1]));
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
default: break; default: break;
} }
@@ -349,7 +342,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!workspaceSilent) { if (!workspaceSilent) {
if (pWorkspace->m_bIsSpecialWorkspace) if (pWorkspace->m_bIsSpecialWorkspace)
pWorkspace->m_pMonitor->setSpecialWorkspace(pWorkspace); pWorkspace->m_pMonitor->setSpecialWorkspace(pWorkspace);
else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID && !PWINDOW->m_bNoInitialFocus) else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID)
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName); g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
PMONITOR = g_pCompositor->m_pLastMonitor.lock(); PMONITOR = g_pCompositor->m_pLastMonitor.lock();
@@ -392,8 +385,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
// Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped. // Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped.
const auto SWALLOWER = PWINDOW->getSwallower(); const auto SWALLOWER = PWINDOW->getSwallower();
PWINDOW->m_pSwallowed = SWALLOWER; PWINDOW->m_pSwallowed = SWALLOWER;
if (PWINDOW->m_pSwallowed)
PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = true;
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
@@ -688,6 +679,13 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PMONITOR && PWINDOW->isX11OverrideRedirect()) if (PMONITOR && PWINDOW->isX11OverrideRedirect())
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
// Fix some X11 popups being invisible / having incorrect size on open.
// What the ACTUAL FUCK is going on?????? I HATE X11
if (!PWINDOW->isX11OverrideRedirect() && PWINDOW->m_bIsX11 && PWINDOW->m_bIsFloating) {
PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true, PWINDOW->m_vRealPosition->goal() - Vector2D{1, 1});
PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true);
}
} }
void Events::listener_unmapWindow(void* owner, void* data) { void Events::listener_unmapWindow(void* owner, void* data) {
@@ -716,13 +714,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)}); g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
EMIT_HOOK_EVENT("closeWindow", PWINDOW); EMIT_HOOK_EVENT("closeWindow", PWINDOW);
if (PWINDOW->m_bIsFloating && !PWINDOW->m_bIsX11 &&
std::any_of(PWINDOW->m_vMatchedRules.begin(), PWINDOW->m_vMatchedRules.end(), [](const auto& r) { return r->ruleType == CWindowRule::RULE_PERSISTENTSIZE; })) {
Debug::log(LOG, "storing floating size {}x{} for window {}::{} on close", PWINDOW->m_vRealSize->value().x, PWINDOW->m_vRealSize->value().y, PWINDOW->m_szClass,
PWINDOW->m_szTitle);
g_pConfigManager->storeFloatingSize(PWINDOW, PWINDOW->m_vRealSize->value());
}
PROTO::toplevelExport->onWindowUnmap(PWINDOW); PROTO::toplevelExport->onWindowUnmap(PWINDOW);
if (PWINDOW->isFullscreen()) if (PWINDOW->isFullscreen())
@@ -733,15 +724,12 @@ void Events::listener_unmapWindow(void* owner, void* data) {
// swallowing // swallowing
if (valid(PWINDOW->m_pSwallowed)) { if (valid(PWINDOW->m_pSwallowed)) {
if (PWINDOW->m_pSwallowed->m_bCurrentlySwallowed) {
PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = false;
PWINDOW->m_pSwallowed->setHidden(false); PWINDOW->m_pSwallowed->setHidden(false);
if (PWINDOW->m_sGroupData.pNextWindow.lock()) if (PWINDOW->m_sGroupData.pNextWindow.lock())
PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false. PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false.
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock()); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock());
}
PWINDOW->m_pSwallowed->m_bGroupSwallowed = false; PWINDOW->m_pSwallowed->m_bGroupSwallowed = false;
PWINDOW->m_pSwallowed.reset(); PWINDOW->m_pSwallowed.reset();
@@ -880,7 +868,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
// tearing: if solitary, redraw it. This still might be a single surface window // tearing: if solitary, redraw it. This still might be a single surface window
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) { if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.accumulateBufferDamage()}; CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
if (!damageBox.empty()) { if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) { if (PMONITOR->tearingState.busy) {
@@ -964,7 +952,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->setHidden(true); PWINDOW->setHidden(true);
if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) { if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) {
PWINDOW->sendWindowSize(true); PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true);
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
return; return;
} }

View File

@@ -49,6 +49,97 @@ using namespace Hyprutils::OS;
#endif #endif
#endif #endif
static const float transforms[][9] = {
{
1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
0.0f,
1.0f,
0.0f,
-1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
-1.0f,
0.0f,
0.0f,
0.0f,
-1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
0.0f,
-1.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
-1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
0.0f,
1.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
1.0f,
0.0f,
0.0f,
0.0f,
-1.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
{
0.0f,
-1.0f,
0.0f,
-1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
},
};
std::string absolutePath(const std::string& rawpath, const std::string& currentPath) { std::string absolutePath(const std::string& rawpath, const std::string& currentPath) {
auto value = rawpath; auto value = rawpath;
@@ -745,48 +836,50 @@ bool envEnabled(const std::string& env) {
return std::string(ENV) == "1"; return std::string(ENV) == "1";
} }
std::pair<CFileDescriptor, std::string> openExclusiveShm() { std::pair<int, std::string> openExclusiveShm() {
// Only absolute paths can be shared across different shm_open() calls // Only absolute paths can be shared across different shm_open() calls
std::string name = "/" + g_pTokenManager->getRandomUUID(); std::string name = "/" + g_pTokenManager->getRandomUUID();
for (size_t i = 0; i < 69; ++i) { for (size_t i = 0; i < 69; ++i) {
CFileDescriptor fd{shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)}; int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd.isValid()) if (fd >= 0)
return {std::move(fd), name}; return {fd, name};
} }
return {{}, ""}; return {-1, ""};
} }
CFileDescriptor allocateSHMFile(size_t len) { int allocateSHMFile(size_t len) {
auto [fd, name] = openExclusiveShm(); auto [fd, name] = openExclusiveShm();
if (!fd.isValid()) if (fd < 0)
return {}; return -1;
shm_unlink(name.c_str()); shm_unlink(name.c_str());
int ret; int ret;
do { do {
ret = ftruncate(fd.get(), len); ret = ftruncate(fd, len);
} while (ret < 0 && errno == EINTR); } while (ret < 0 && errno == EINTR);
if (ret < 0) { if (ret < 0) {
return {}; close(fd);
return -1;
} }
return std::move(fd); return fd;
} }
bool allocateSHMFilePair(size_t size, CFileDescriptor& rw_fd_ptr, CFileDescriptor& ro_fd_ptr) { bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) {
auto [fd, name] = openExclusiveShm(); auto [fd, name] = openExclusiveShm();
if (!fd.isValid()) { if (fd < 0) {
return false; return false;
} }
// CLOEXEC is guaranteed to be set by shm_open // CLOEXEC is guaranteed to be set by shm_open
CFileDescriptor ro_fd{shm_open(name.c_str(), O_RDONLY, 0)}; int ro_fd = shm_open(name.c_str(), O_RDONLY, 0);
if (!ro_fd.isValid()) { if (ro_fd < 0) {
shm_unlink(name.c_str()); shm_unlink(name.c_str());
close(fd);
return false; return false;
} }
@@ -794,20 +887,24 @@ bool allocateSHMFilePair(size_t size, CFileDescriptor& rw_fd_ptr, CFileDescripto
// Make sure the file cannot be re-opened in read-write mode (e.g. via // Make sure the file cannot be re-opened in read-write mode (e.g. via
// "/proc/self/fd/" on Linux) // "/proc/self/fd/" on Linux)
if (fchmod(fd.get(), 0) != 0) { if (fchmod(fd, 0) != 0) {
close(fd);
close(ro_fd);
return false; return false;
} }
int ret; int ret;
do { do {
ret = ftruncate(fd.get(), size); ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR); } while (ret < 0 && errno == EINTR);
if (ret < 0) { if (ret < 0) {
close(fd);
close(ro_fd);
return false; return false;
} }
rw_fd_ptr = std::move(fd); *rw_fd_ptr = fd;
ro_fd_ptr = std::move(ro_fd); *ro_fd_ptr = ro_fd;
return true; return true;
} }

View File

@@ -5,7 +5,6 @@
#include <vector> #include <vector>
#include <format> #include <format>
#include <expected> #include <expected>
#include <hyprutils/os/FileDescriptor.hpp>
#include "../SharedDefs.hpp" #include "../SharedDefs.hpp"
#include "../macros.hpp" #include "../macros.hpp"
@@ -36,8 +35,8 @@ double normalizeAngleRad(double ang);
std::vector<SCallstackFrameInfo> getBacktrace(); std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err); void throwError(const std::string& err);
bool envEnabled(const std::string& env); bool envEnabled(const std::string& env);
Hyprutils::OS::CFileDescriptor allocateSHMFile(size_t len); int allocateSHMFile(size_t len);
bool allocateSHMFilePair(size_t size, Hyprutils::OS::CFileDescriptor& rw_fd_ptr, Hyprutils::OS::CFileDescriptor& ro_fd_ptr); bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr);
float stringToPercentage(const std::string& VALUE, const float REL); float stringToPercentage(const std::string& VALUE, const float REL);
template <typename... Args> template <typename... Args>

View File

@@ -2,7 +2,6 @@
#include "MiscFunctions.hpp" #include "MiscFunctions.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "math/Math.hpp" #include "math/Math.hpp"
#include "../protocols/ColorManagement.hpp"
#include "sync/SyncReleaser.hpp" #include "sync/SyncReleaser.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
@@ -33,8 +32,6 @@
#include <ranges> #include <ranges>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::Utils; using namespace Hyprutils::Utils;
using namespace Hyprutils::OS;
using enum NContentType::eContentType;
static int ratHandler(void* data) { static int ratHandler(void* data) {
g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock()); g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock());
@@ -58,6 +55,7 @@ void CMonitor::onConnect(bool noRule) {
if (output->supportsExplicit) { if (output->supportsExplicit) {
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
outTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
} }
listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); }); listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); });
@@ -412,8 +410,7 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
if (!force && DELTALESSTHAN(vecPixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(vecPixelSize.y, RULE->resolution.y, 1) && if (!force && DELTALESSTHAN(vecPixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(vecPixelSize.y, RULE->resolution.y, 1) &&
DELTALESSTHAN(refreshRate, RULE->refreshRate, 1) && setScale == RULE->scale && DELTALESSTHAN(refreshRate, RULE->refreshRate, 1) && setScale == RULE->scale &&
((DELTALESSTHAN(vecPosition.x, RULE->offset.x, 1) && DELTALESSTHAN(vecPosition.y, RULE->offset.y, 1)) || RULE->offset == Vector2D(-INT32_MAX, -INT32_MAX)) && ((DELTALESSTHAN(vecPosition.x, RULE->offset.x, 1) && DELTALESSTHAN(vecPosition.y, RULE->offset.y, 1)) || RULE->offset == Vector2D(-INT32_MAX, -INT32_MAX)) &&
transform == RULE->transform && RULE->enable10bit == enabled10bit && RULE->cmType == cmType && RULE->sdrSaturation == sdrSaturation && transform == RULE->transform && RULE->enable10bit == enabled10bit && !std::memcmp(&customDrmMode, &RULE->drmMode, sizeof(customDrmMode))) {
RULE->sdrBrightness == sdrBrightness && !std::memcmp(&customDrmMode, &RULE->drmMode, sizeof(customDrmMode))) {
Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", szName); Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", szName);
@@ -671,66 +668,6 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
enabled10bit = set10bit; enabled10bit = set10bit;
auto oldImageDescription = imageDescription;
cmType = RULE->cmType;
switch (cmType) {
case CM_AUTO: cmType = enabled10bit && output->parsedEDID.supportsBT2020 ? CM_WIDE : CM_SRGB; break;
case CM_EDID: cmType = output->parsedEDID.chromaticityCoords.has_value() ? CM_EDID : CM_SRGB; break;
case CM_HDR:
case CM_HDR_EDID:
cmType = output->parsedEDID.supportsBT2020 && output->parsedEDID.hdrMetadata.has_value() && output->parsedEDID.hdrMetadata->supportsPQ ? cmType : CM_SRGB;
break;
default: break;
}
switch (cmType) {
case CM_SRGB: imageDescription = {}; break; // assumes SImageDescirption defaults to sRGB
case CM_WIDE:
imageDescription = {.primariesNameSet = true,
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020)};
break;
case CM_EDID:
imageDescription = {.primariesNameSet = false,
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
.primaries = {
.red = {.x = output->parsedEDID.chromaticityCoords->red.x, .y = output->parsedEDID.chromaticityCoords->red.y},
.green = {.x = output->parsedEDID.chromaticityCoords->green.x, .y = output->parsedEDID.chromaticityCoords->green.y},
.blue = {.x = output->parsedEDID.chromaticityCoords->blue.x, .y = output->parsedEDID.chromaticityCoords->blue.y},
.white = {.x = output->parsedEDID.chromaticityCoords->white.x, .y = output->parsedEDID.chromaticityCoords->white.y},
}};
break;
case CM_HDR:
imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
.primariesNameSet = true,
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
.luminances = {.min = 0, .max = 10000, .reference = 203}};
break;
case CM_HDR_EDID:
imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
.primariesNameSet = false,
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
.primaries = output->parsedEDID.chromaticityCoords.has_value() ?
NColorManagement::SPCPRimaries{
.red = {.x = output->parsedEDID.chromaticityCoords->red.x, .y = output->parsedEDID.chromaticityCoords->red.y},
.green = {.x = output->parsedEDID.chromaticityCoords->green.x, .y = output->parsedEDID.chromaticityCoords->green.y},
.blue = {.x = output->parsedEDID.chromaticityCoords->blue.x, .y = output->parsedEDID.chromaticityCoords->blue.y},
.white = {.x = output->parsedEDID.chromaticityCoords->white.x, .y = output->parsedEDID.chromaticityCoords->white.y},
} :
NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
.luminances = {.min = output->parsedEDID.hdrMetadata->desiredContentMinLuminance,
.max = output->parsedEDID.hdrMetadata->desiredContentMaxLuminance,
.reference = output->parsedEDID.hdrMetadata->desiredMaxFrameAverageLuminance}};
break;
default: UNREACHABLE();
}
if (oldImageDescription != imageDescription)
PROTO::colorManagement->onMonitorImageDescriptionChanged(self);
sdrSaturation = RULE->sdrSaturation;
sdrBrightness = RULE->sdrBrightness;
Vector2D logicalSize = vecPixelSize / scale; Vector2D logicalSize = vecPixelSize / scale;
if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) { if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) {
// invalid scale, will produce fractional pixels. // invalid scale, will produce fractional pixels.
@@ -861,8 +798,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate"); static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate");
// skip scheduling extra frames for fullsreen apps with vrr // skip scheduling extra frames for fullsreen apps with vrr
const bool shouldSkip = activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN && bool shouldSkip =
(*PNOBREAK == 1 || (*PNOBREAK == 2 && activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && output->state->state().adaptiveSync; *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
// keep requested minimum refresh rate // keep requested minimum refresh rate
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) { if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) {
@@ -1081,15 +1018,13 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
return; return;
const auto POLDWORKSPACE = activeWorkspace; const auto POLDWORKSPACE = activeWorkspace;
if (POLDWORKSPACE)
POLDWORKSPACE->m_bVisible = false; POLDWORKSPACE->m_bVisible = false;
pWorkspace->m_bVisible = true; pWorkspace->m_bVisible = true;
activeWorkspace = pWorkspace; activeWorkspace = pWorkspace;
if (!internal) { if (!internal) {
const auto ANIMTOLEFT = POLDWORKSPACE && pWorkspace->m_iID > POLDWORKSPACE->m_iID; const auto ANIMTOLEFT = pWorkspace->m_iID > POLDWORKSPACE->m_iID;
if (POLDWORKSPACE)
POLDWORKSPACE->startAnim(false, ANIMTOLEFT); POLDWORKSPACE->startAnim(false, ANIMTOLEFT);
pWorkspace->startAnim(true, ANIMTOLEFT); pWorkspace->startAnim(true, ANIMTOLEFT);
@@ -1156,7 +1091,6 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
activeSpecialWorkspace->m_bVisible = false; activeSpecialWorkspace->m_bVisible = false;
activeSpecialWorkspace->startAnim(false, false); activeSpecialWorkspace->startAnim(false, false);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + szName}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + szName});
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", ",," + szName});
} }
activeSpecialWorkspace.reset(); activeSpecialWorkspace.reset();
@@ -1186,13 +1120,12 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
bool animate = true; bool animate = true;
//close if open elsewhere //close if open elsewhere
const auto PMONITORWORKSPACEOWNER = pWorkspace->m_pMonitor.lock(); const auto PMONITORWORKSPACEOWNER = pWorkspace->m_pMonitor.lock();
if (const auto PMWSOWNER = pWorkspace->m_pMonitor.lock(); PMWSOWNER && PMWSOWNER->activeSpecialWorkspace == pWorkspace) { if (PMONITORWORKSPACEOWNER->activeSpecialWorkspace == pWorkspace) {
PMWSOWNER->activeSpecialWorkspace.reset(); PMONITORWORKSPACEOWNER->activeSpecialWorkspace.reset();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMWSOWNER->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMWSOWNER->szName}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMONITORWORKSPACEOWNER->szName});
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", ",," + PMWSOWNER->szName});
const auto PACTIVEWORKSPACE = PMWSOWNER->activeWorkspace; const auto PACTIVEWORKSPACE = PMONITORWORKSPACEOWNER->activeWorkspace;
g_pCompositor->updateFullscreenFadeOnWorkspace(PACTIVEWORKSPACE); g_pCompositor->updateFullscreenFadeOnWorkspace(PACTIVEWORKSPACE);
animate = false; animate = false;
@@ -1239,7 +1172,6 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
} }
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", std::to_string(pWorkspace->m_iID) + "," + pWorkspace->m_szName + "," + szName});
g_pHyprRenderer->damageMonitor(self.lock()); g_pHyprRenderer->damageMonitor(self.lock());
@@ -1341,43 +1273,23 @@ bool CMonitor::attemptDirectScanout() {
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
if (!PSURFACE || !PSURFACE->current.texture || !PSURFACE->current.buffer) if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform)
return false;
if (PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform)
return false; return false;
// we can't scanout shm buffers. // we can't scanout shm buffers.
const auto params = PSURFACE->current.buffer->buffer->dmabuf(); if (!PSURFACE->current.buffer || !PSURFACE->current.buffer->buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
if (!params.success || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
return false; return false;
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt, buffer {}", (uintptr_t)PSURFACE.get(), (uintptr_t)PSURFACE->current.buffer->buffer.get()); Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get());
auto PBUFFER = PSURFACE->current.buffer->buffer;
if (PBUFFER == output->state->state().buffer) {
if (scanoutNeedsCursorUpdate) {
if (!state.test()) {
Debug::log(TRACE, "attemptDirectScanout: failed basic test");
return false;
}
if (!output->commit()) {
Debug::log(TRACE, "attemptDirectScanout: failed to commit cursor update");
lastScanout.reset();
return false;
}
scanoutNeedsCursorUpdate = false;
}
return true;
}
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats // FIXME: make sure the buffer actually follows the available scanout dmabuf formats
// and comes from the appropriate device. This may implode on multi-gpu!! // and comes from the appropriate device. This may implode on multi-gpu!!
const auto params = PSURFACE->current.buffer->buffer->dmabuf();
// scanout buffer isn't dmabuf, so no scanout
if (!params.success)
return false;
// entering into scanout, so save monitor format // entering into scanout, so save monitor format
if (lastScanout.expired()) if (lastScanout.expired())
prevDrmFormat = drmFormat; prevDrmFormat = drmFormat;
@@ -1387,7 +1299,7 @@ bool CMonitor::attemptDirectScanout() {
drmFormat = params.format; drmFormat = params.format;
} }
output->state->setBuffer(PBUFFER); output->state->setBuffer(PSURFACE->current.buffer->buffer.lock());
output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
@@ -1396,28 +1308,34 @@ bool CMonitor::attemptDirectScanout() {
return false; return false;
} }
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings();
// wait for the explicit fence if present, and if kms explicit is allowed
bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled;
int explicitWaitFD = -1;
if (DOEXPLICIT) {
explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint);
if (explicitWaitFD < 0)
Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd");
}
DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0;
auto cleanup = CScopeGuard([explicitWaitFD, this]() {
output->state->resetExplicitFences();
if (explicitWaitFD >= 0)
close(explicitWaitFD);
});
timespec now; timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
PSURFACE->presentFeedback(&now, self.lock()); PSURFACE->presentFeedback(&now, self.lock());
output->state->addDamage(PSURFACE->current.accumulateBufferDamage()); output->state->addDamage(CBox{{}, vecPixelSize});
output->state->resetExplicitFences(); output->state->resetExplicitFences();
auto cleanup = CScopeGuard([this]() { output->state->resetExplicitFences(); });
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(output);
bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->current.buffer && PSURFACE->current.buffer->acquire && explicitOptions.explicitKMSEnabled;
if (DOEXPLICIT) { if (DOEXPLICIT) {
// wait for surface's explicit fence if present Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD);
inFence = PSURFACE->current.buffer->acquire->exportAsFD(); output->state->setExplicitInFence(explicitWaitFD);
if (inFence.isValid()) {
Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", inFence.get());
output->state->setExplicitInFence(inFence.get());
} else {
Debug::log(TRACE, "attemptDirectScanout: failed to acquire an sync file fd for aq IN_FENCE");
DOEXPLICIT = false;
}
} }
bool ok = output->commit(); bool ok = output->commit();
@@ -1429,26 +1347,28 @@ bool CMonitor::attemptDirectScanout() {
ok = output->commit(); ok = output->commit();
} }
if (!ok) { if (ok) {
Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface");
lastScanout.reset();
return false;
}
if (lastScanout.expired()) { if (lastScanout.expired()) {
lastScanout = PCANDIDATE; lastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
} }
scanoutNeedsCursorUpdate = false; // delay explicit sync feedback until kms release of the buffer
if (DOEXPLICIT) {
Debug::log(TRACE, "attemptDirectScanout: Delaying explicit sync release feedback until kms release");
PSURFACE->current.buffer->releaser->drop();
if (!PBUFFER->lockedByBackend || PBUFFER->hlEvents.backendRelease) PSURFACE->current.buffer->buffer->hlEvents.backendRelease2 = PSURFACE->current.buffer->buffer->events.backendRelease.registerListener([PSURFACE](std::any d) {
return true; const bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.releaseTimeline && PSURFACE->syncobj->current.releaseTimeline->timeline;
if (DOEXPLICIT)
// lock buffer while DRM/KMS is using it, then release it when page flip happens since DRM/KMS should be done by then PSURFACE->syncobj->current.releaseTimeline->timeline->signal(PSURFACE->syncobj->current.releasePoint);
// btw buffer's syncReleaser will take care of signaling release point, so we don't do that here });
PBUFFER->lock(); }
PBUFFER->onBackendRelease([PBUFFER]() { PBUFFER->unlock(); }); } else {
Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface");
lastScanout.reset();
return false;
}
return true; return true;
} }
@@ -1521,25 +1441,11 @@ void CMonitor::onMonitorFrame() {
g_pHyprRenderer->renderMonitor(self.lock()); g_pHyprRenderer->renderMonitor(self.lock());
} }
void CMonitor::onCursorMovedOnMonitor() { CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) {
if (!tearingState.activelyTearing || !solitaryClient || !g_pHyprRenderer->shouldRenderCursor()) ;
return;
// submit a frame immediately. This will only update the cursor pos.
// output->state->setBuffer(output->state->state().buffer);
// output->state->addDamage(CRegion{});
// output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE);
// if (!output->commit())
// Debug::log(ERR, "onCursorMovedOnMonitor: tearing and wanted to update cursor, failed.");
// FIXME: try to do the above. We currently can't just render because drm is a fucking bitch
// and throws a "nO pRoP cAn Be ChAnGeD dUrInG AsYnC fLiP" on crtc_x
// this will throw too but fix it if we use sw cursors
tearingState.frameScheduledWhileBusy = true;
} }
CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) { CMonitorState::~CMonitorState() {
; ;
} }

View File

@@ -6,18 +6,17 @@
#include "../SharedDefs.hpp" #include "../SharedDefs.hpp"
#include "MiscFunctions.hpp" #include "MiscFunctions.hpp"
#include "WLClasses.hpp" #include "WLClasses.hpp"
#include <vector>
#include <array> #include <array>
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include "Timer.hpp" #include "Timer.hpp"
#include "math/Math.hpp" #include "math/Math.hpp"
#include <optional> #include <optional>
#include "../protocols/types/ColorManagement.hpp"
#include "signal/Signal.hpp" #include "signal/Signal.hpp"
#include "DamageRing.hpp" #include "DamageRing.hpp"
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
#include <aquamarine/allocator/Swapchain.hpp> #include <aquamarine/allocator/Swapchain.hpp>
#include <hyprutils/os/FileDescriptor.hpp>
// Enum for the different types of auto directions, e.g. auto-left, auto-up. // Enum for the different types of auto directions, e.g. auto-left, auto-up.
enum eAutoDirs : uint8_t { enum eAutoDirs : uint8_t {
@@ -28,15 +27,6 @@ enum eAutoDirs : uint8_t {
DIR_AUTO_RIGHT DIR_AUTO_RIGHT
}; };
enum eCMType : uint8_t {
CM_AUTO = 0, // subject to change. srgb for 8bpc, wide for 10bpc if supported
CM_SRGB, // default, sRGB primaries
CM_WIDE, // wide color gamut, BT2020 primaries
CM_EDID, // primaries from edid (known to be inaccurate)
CM_HDR, // wide color gamut and HDR PQ transfer function
CM_HDR_EDID, // same as CM_HDR with edid primaries
};
struct SMonitorRule { struct SMonitorRule {
eAutoDirs autoDir = DIR_AUTO_NONE; eAutoDirs autoDir = DIR_AUTO_NONE;
std::string name = ""; std::string name = "";
@@ -48,21 +38,17 @@ struct SMonitorRule {
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
std::string mirrorOf = ""; std::string mirrorOf = "";
bool enable10bit = false; bool enable10bit = false;
eCMType cmType = CM_SRGB;
float sdrSaturation = 1.0f; // SDR -> HDR
float sdrBrightness = 1.0f; // SDR -> HDR
drmModeModeInfo drmMode = {}; drmModeModeInfo drmMode = {};
std::optional<int> vrr; std::optional<int> vrr;
}; };
class CMonitor; class CMonitor;
class CSyncTimeline; class CSyncTimeline;
class CEGLSync;
class CMonitorState { class CMonitorState {
public: public:
CMonitorState(CMonitor* owner); CMonitorState(CMonitor* owner);
~CMonitorState() = default; ~CMonitorState();
bool commit(); bool commit();
bool test(); bool test();
@@ -121,9 +107,6 @@ class CMonitor {
bool dpmsStatus = true; bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed. bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
eCMType cmType = CM_SRGB;
float sdrSaturation = 1.0f;
float sdrBrightness = 1.0f;
bool createdByUser = false; bool createdByUser = false;
bool isUnsafeFallback = false; bool isUnsafeFallback = false;
@@ -140,9 +123,8 @@ class CMonitor {
// explicit sync // explicit sync
SP<CSyncTimeline> inTimeline; SP<CSyncTimeline> inTimeline;
Hyprutils::OS::CFileDescriptor inFence; SP<CSyncTimeline> outTimeline;
SP<CEGLSync> eglSync; uint64_t commitSeq = 0;
uint64_t inTimelinePoint = 0;
PHLMONITORREF self; PHLMONITORREF self;
@@ -159,7 +141,6 @@ class CMonitor {
// for direct scanout // for direct scanout
PHLWINDOWREF lastScanout; PHLWINDOWREF lastScanout;
bool scanoutNeedsCursorUpdate = false;
struct { struct {
bool canTear = false; bool canTear = false;
@@ -205,7 +186,6 @@ class CMonitor {
void scheduleDone(); void scheduleDone();
bool attemptDirectScanout(); bool attemptDirectScanout();
void setCTM(const Mat3x3& ctm); void setCTM(const Mat3x3& ctm);
void onCursorMovedOnMonitor();
void debugLastPresentation(const std::string& message); void debugLastPresentation(const std::string& message);
void onMonitorFrame(); void onMonitorFrame();
@@ -213,7 +193,6 @@ class CMonitor {
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false; bool m_bRenderingInitPassed = false;
WP<CWindow> m_previousFSWindow; WP<CWindow> m_previousFSWindow;
NColorManagement::SImageDescription imageDescription;
// For the list lookup // For the list lookup

View File

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

View File

@@ -1,65 +1,25 @@
#include "SyncReleaser.hpp" #include "SyncReleaser.hpp"
#include "SyncTimeline.hpp" #include "SyncTimeline.hpp"
#include "../../render/OpenGL.hpp" #include "../../render/OpenGL.hpp"
#include <sys/ioctl.h>
#if defined(__linux__) CSyncReleaser::CSyncReleaser(WP<CSyncTimeline> timeline_, uint64_t point_) : timeline(timeline_), point(point_) {
#include <linux/sync_file.h>
#else
struct sync_merge_data {
char name[32];
__s32 fd2;
__s32 fence;
__u32 flags;
__u32 pad;
};
#define SYNC_IOC_MAGIC '>'
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
#endif
using namespace Hyprutils::OS;
CSyncReleaser::CSyncReleaser(SP<CSyncTimeline> timeline, uint64_t point) : m_timeline(timeline), m_point(point) {
; ;
} }
CSyncReleaser::~CSyncReleaser() { CSyncReleaser::~CSyncReleaser() {
if (!m_timeline) { if (timeline.expired())
Debug::log(ERR, "CSyncReleaser destructing without a timeline");
return; return;
}
if (m_fd.isValid()) if (sync)
m_timeline->importFromSyncFileFD(m_point, m_fd); timeline->importFromSyncFileFD(point, sync->fd());
else else
m_timeline->signal(m_point); timeline->signal(point);
} }
CFileDescriptor CSyncReleaser::mergeSyncFds(const CFileDescriptor& fd1, const CFileDescriptor& fd2) { void CSyncReleaser::addReleaseSync(SP<CEGLSync> sync_) {
struct sync_merge_data data{ sync = sync_;
.name = "merged release fence",
.fd2 = fd2.get(),
.fence = -1,
};
int err = -1;
do {
err = ioctl(fd1.get(), SYNC_IOC_MERGE, &data);
} while (err == -1 && (errno == EINTR || errno == EAGAIN));
if (err < 0)
return CFileDescriptor{};
else
return CFileDescriptor(data.fence);
}
void CSyncReleaser::addReleaseSync(SP<CEGLSync> sync) {
if (m_fd.isValid())
m_fd = mergeSyncFds(m_fd, sync->takeFD());
else
m_fd = sync->fd().duplicate();
m_sync = sync;
} }
void CSyncReleaser::drop() { void CSyncReleaser::drop() {
m_timeline.reset(); timeline.reset();
} }

View File

@@ -4,7 +4,6 @@
#include <optional> #include <optional>
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <hyprutils/os/FileDescriptor.hpp>
#include "../memory/Memory.hpp" #include "../memory/Memory.hpp"
/* /*
@@ -16,19 +15,17 @@ class CEGLSync;
class CSyncReleaser { class CSyncReleaser {
public: public:
CSyncReleaser(SP<CSyncTimeline> timeline, uint64_t point); CSyncReleaser(WP<CSyncTimeline> timeline_, uint64_t point_);
~CSyncReleaser(); ~CSyncReleaser();
// drops the releaser, will never signal anymore // drops the releaser, will never signal anymore
void drop(); void drop();
// wait for this gpu job to finish before releasing // wait for this gpu job to finish before releasing
Hyprutils::OS::CFileDescriptor mergeSyncFds(const Hyprutils::OS::CFileDescriptor& fd1, const Hyprutils::OS::CFileDescriptor& fd2);
void addReleaseSync(SP<CEGLSync> sync); void addReleaseSync(SP<CEGLSync> sync);
private: private:
SP<CSyncTimeline> m_timeline; WP<CSyncTimeline> timeline;
uint64_t m_point = 0; uint64_t point = 0;
Hyprutils::OS::CFileDescriptor m_fd; SP<CEGLSync> sync;
SP<CEGLSync> m_sync;
}; };

View File

@@ -4,7 +4,6 @@
#include <xf86drm.h> #include <xf86drm.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
using namespace Hyprutils::OS;
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) { SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
auto timeline = SP<CSyncTimeline>(new CSyncTimeline); auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
@@ -19,13 +18,12 @@ SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
return timeline; return timeline;
} }
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, CFileDescriptor&& drmSyncobjFD) { SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, int drmSyncobjFD) {
auto timeline = SP<CSyncTimeline>(new CSyncTimeline); auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
timeline->drmFD = drmFD_; timeline->drmFD = drmFD_;
timeline->syncobjFd = std::move(drmSyncobjFD);
timeline->self = timeline; timeline->self = timeline;
if (drmSyncobjFDToHandle(drmFD_, timeline->syncobjFd.get(), &timeline->handle)) { if (drmSyncobjFDToHandle(drmFD_, drmSyncobjFD, &timeline->handle)) {
Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj from fd??"); Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj from fd??");
return nullptr; return nullptr;
} }
@@ -34,13 +32,6 @@ SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, CFileDescriptor&& drmSyncobj
} }
CSyncTimeline::~CSyncTimeline() { CSyncTimeline::~CSyncTimeline() {
for (auto& w : waiters) {
if (w->source) {
wl_event_source_remove(w->source);
w->source = nullptr;
}
}
if (handle == 0) if (handle == 0)
return; return;
@@ -94,9 +85,10 @@ bool CSyncTimeline::addWaiter(const std::function<void()>& waiter, uint64_t poin
auto w = makeShared<SWaiter>(); auto w = makeShared<SWaiter>();
w->fn = waiter; w->fn = waiter;
w->timeline = self; w->timeline = self;
w->eventFd = CFileDescriptor{eventfd(0, EFD_CLOEXEC)};
if (!w->eventFd.isValid()) { int eventFD = eventfd(0, EFD_CLOEXEC);
if (eventFD < 0) {
Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd"); Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd");
return false; return false;
} }
@@ -105,17 +97,19 @@ bool CSyncTimeline::addWaiter(const std::function<void()>& waiter, uint64_t poin
.handle = handle, .handle = handle,
.flags = flags, .flags = flags,
.point = point, .point = point,
.fd = w->eventFd.get(), .fd = eventFD,
}; };
if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) { if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) {
Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed"); Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed");
close(eventFD);
return false; return false;
} }
w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, w->eventFd.get(), WL_EVENT_READABLE, ::handleWaiterFD, w.get()); w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get());
if (!w->source) { if (!w->source) {
Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed"); Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed");
close(eventFD);
return false; return false;
} }
@@ -132,43 +126,32 @@ void CSyncTimeline::removeWaiter(SWaiter* w) {
std::erase_if(waiters, [w](const auto& e) { return e.get() == w; }); std::erase_if(waiters, [w](const auto& e) { return e.get() == w; });
} }
void CSyncTimeline::removeAllWaiters() { int CSyncTimeline::exportAsSyncFileFD(uint64_t src) {
for (auto& w : waiters) {
if (w->source) {
wl_event_source_remove(w->source);
w->source = nullptr;
}
}
waiters.clear();
}
CFileDescriptor CSyncTimeline::exportAsSyncFileFD(uint64_t src) {
int sync = -1; int sync = -1;
uint32_t syncHandle = 0; uint32_t syncHandle = 0;
if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed"); Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed");
return {}; return -1;
} }
if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) { if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) {
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed"); Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed");
drmSyncobjDestroy(drmFD, syncHandle); drmSyncobjDestroy(drmFD, syncHandle);
return {}; return -1;
} }
if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) { if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) {
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed"); Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed");
drmSyncobjDestroy(drmFD, syncHandle); drmSyncobjDestroy(drmFD, syncHandle);
return {}; return -1;
} }
drmSyncobjDestroy(drmFD, syncHandle); drmSyncobjDestroy(drmFD, syncHandle);
return CFileDescriptor{sync}; return sync;
} }
bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, CFileDescriptor& fd) { bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) {
uint32_t syncHandle = 0; uint32_t syncHandle = 0;
if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
@@ -176,7 +159,7 @@ bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, CFileDescriptor& fd) {
return false; return false;
} }
if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd.get())) { if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) {
Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed"); Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed");
drmSyncobjDestroy(drmFD, syncHandle); drmSyncobjDestroy(drmFD, syncHandle);
return false; return false;

View File

@@ -4,7 +4,6 @@
#include <optional> #include <optional>
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <hyprutils/os/FileDescriptor.hpp>
#include "../memory/Memory.hpp" #include "../memory/Memory.hpp"
/* /*
@@ -17,14 +16,13 @@ struct wl_event_source;
class CSyncTimeline { class CSyncTimeline {
public: public:
static SP<CSyncTimeline> create(int drmFD_); static SP<CSyncTimeline> create(int drmFD_);
static SP<CSyncTimeline> create(int drmFD_, Hyprutils::OS::CFileDescriptor&& drmSyncobjFD); static SP<CSyncTimeline> create(int drmFD_, int drmSyncobjFD);
~CSyncTimeline(); ~CSyncTimeline();
struct SWaiter { struct SWaiter {
std::function<void()> fn; std::function<void()> fn;
wl_event_source* source = nullptr; wl_event_source* source = nullptr;
WP<CSyncTimeline> timeline; WP<CSyncTimeline> timeline;
Hyprutils::OS::CFileDescriptor eventFd;
}; };
// check if the timeline point has been signaled // check if the timeline point has been signaled
@@ -34,14 +32,12 @@ class CSyncTimeline {
bool addWaiter(const std::function<void()>& waiter, uint64_t point, uint32_t flags); bool addWaiter(const std::function<void()>& waiter, uint64_t point, uint32_t flags);
void removeWaiter(SWaiter*); void removeWaiter(SWaiter*);
void removeAllWaiters(); int exportAsSyncFileFD(uint64_t src);
Hyprutils::OS::CFileDescriptor exportAsSyncFileFD(uint64_t src); bool importFromSyncFileFD(uint64_t dst, int fd);
bool importFromSyncFileFD(uint64_t dst, Hyprutils::OS::CFileDescriptor& fd);
bool transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint); bool transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint);
void signal(uint64_t point); void signal(uint64_t point);
int drmFD = -1; int drmFD = -1;
Hyprutils::OS::CFileDescriptor syncobjFd;
uint32_t handle = 0; uint32_t handle = 0;
WP<CSyncTimeline> self; WP<CSyncTimeline> self;

View File

@@ -32,6 +32,8 @@ CHyprError::CHyprError() {
m_pTexture = makeShared<CTexture>(); m_pTexture = makeShared<CTexture>();
} }
CHyprError::~CHyprError() = default;
void CHyprError::queueCreate(std::string message, const CHyprColor& color) { void CHyprError::queueCreate(std::string message, const CHyprColor& color) {
m_szQueued = message; m_szQueued = message;
m_cQueued = color; m_cQueued = color;

View File

@@ -9,7 +9,7 @@
class CHyprError { class CHyprError {
public: public:
CHyprError(); CHyprError();
~CHyprError() = default; ~CHyprError();
void queueCreate(std::string message, const CHyprColor& color); void queueCreate(std::string message, const CHyprColor& color);
void draw(); void draw();

View File

@@ -198,12 +198,16 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
*PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealPosition = wb.pos();
*PWINDOW->m_vRealSize = wb.size(); *PWINDOW->m_vRealSize = wb.size();
PWINDOW->sendWindowSize(wb.size());
} else { } else {
CBox wb = {calcPos, calcSize}; CBox wb = {calcPos, calcSize};
wb.round(); // avoid rounding mess wb.round(); // avoid rounding mess
*PWINDOW->m_vRealSize = wb.size(); *PWINDOW->m_vRealSize = wb.size();
*PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealPosition = wb.pos();
PWINDOW->sendWindowSize(wb.size());
} }
if (force) { if (force) {

View File

@@ -16,15 +16,7 @@
void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(pWindow); CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(pWindow);
const bool HASPERSISTENTSIZE = if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
std::any_of(pWindow->m_vMatchedRules.begin(), pWindow->m_vMatchedRules.end(), [](const auto& rule) { return rule->ruleType == CWindowRule::RULE_PERSISTENTSIZE; });
const auto STOREDSIZE = HASPERSISTENTSIZE ? g_pConfigManager->getStoredFloatingSize(pWindow) : std::nullopt;
if (STOREDSIZE.has_value()) {
Debug::log(LOG, "using stored size {}x{} for new window {}::{}", STOREDSIZE->x, STOREDSIZE->y, pWindow->m_szClass, pWindow->m_szTitle);
pWindow->m_vLastFloatingSize = STOREDSIZE.value();
} else if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
const auto PMONITOR = pWindow->m_pMonitor.lock(); const auto PMONITOR = pWindow->m_pMonitor.lock();
pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f; pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f;
} else } else
@@ -184,9 +176,11 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
pWindow->m_vRealSize->warp(); pWindow->m_vRealSize->warp();
} }
if (!pWindow->isX11OverrideRedirect()) if (!pWindow->isX11OverrideRedirect()) {
pWindow->sendWindowSize(pWindow->m_vRealSize->goal());
g_pCompositor->changeWindowZOrder(pWindow, true); g_pCompositor->changeWindowZOrder(pWindow, true);
else { } else {
pWindow->m_vPendingReportedSize = pWindow->m_vRealSize->goal(); pWindow->m_vPendingReportedSize = pWindow->m_vRealSize->goal();
pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize; pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize;
} }
@@ -313,7 +307,7 @@ void IHyprLayout::onBeginDragWindow() {
} }
if (g_pInputManager->dragMode != MBIND_RESIZE && g_pInputManager->dragMode != MBIND_RESIZE_FORCE_RATIO && g_pInputManager->dragMode != MBIND_RESIZE_BLOCK_RATIO) if (g_pInputManager->dragMode != MBIND_RESIZE && g_pInputManager->dragMode != MBIND_RESIZE_FORCE_RATIO && g_pInputManager->dragMode != MBIND_RESIZE_BLOCK_RATIO)
g_pInputManager->setCursorImageUntilUnset("grabbing"); g_pInputManager->setCursorImageUntilUnset("grab");
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
@@ -368,6 +362,9 @@ void IHyprLayout::onEndDragWindow() {
DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize;
DRAGGINGWINDOW->m_bDraggingTiled = false; DRAGGINGWINDOW->m_bDraggingTiled = false;
if (pWindow->m_bIsFloating)
DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); // match the size of the window
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current"); static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
pWindow->setGroupCurrent(DRAGGINGWINDOW); pWindow->setGroupCurrent(DRAGGINGWINDOW);
@@ -609,11 +606,10 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (*PANIMATEMOUSE) if (*PANIMATEMOUSE)
*DRAGGINGWINDOW->m_vRealPosition = wb.pos(); *DRAGGINGWINDOW->m_vRealPosition = wb.pos();
else { else
DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos());
DRAGGINGWINDOW->sendWindowSize();
}
DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal());
} else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) {
if (DRAGGINGWINDOW->m_bIsFloating) { if (DRAGGINGWINDOW->m_bIsFloating) {
@@ -683,8 +679,9 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
} else { } else {
DRAGGINGWINDOW->m_vRealSize->setValueAndWarp(wb.size()); DRAGGINGWINDOW->m_vRealSize->setValueAndWarp(wb.size());
DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos());
DRAGGINGWINDOW->sendWindowSize();
} }
DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal());
} else { } else {
resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW); resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW);
} }
@@ -790,6 +787,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
pWindow->updateToplevel(); pWindow->updateToplevel();
pWindow->sendWindowSize(pWindow->m_vRealSize->goal());
g_pHyprRenderer->damageWindow(pWindow); g_pHyprRenderer->damageWindow(pWindow);
} }
@@ -952,3 +950,5 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) {
return sizePredicted; return sizePredicted;
} }
IHyprLayout::~IHyprLayout() = default;

View File

@@ -43,7 +43,7 @@ enum eDirection : int8_t {
class IHyprLayout { class IHyprLayout {
public: public:
virtual ~IHyprLayout() = default; virtual ~IHyprLayout() = 0;
virtual void onEnable() = 0; virtual void onEnable() = 0;
virtual void onDisable() = 0; virtual void onDisable() = 0;

View File

@@ -374,22 +374,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
// compute placement of master window(s) // compute placement of master window(s)
if (WINDOWS == 1 && !centerMasterWindow) { if (WINDOWS == 1 && !centerMasterWindow) {
static auto PALWAYSKEEPPOSITION = CConfigValue<Hyprlang::INT>("master:always_keep_position");
if (*PALWAYSKEEPPOSITION) {
const float WIDTH = WSSIZE.x * PMASTERNODE->percMaster;
float nextX = 0;
if (orientation == ORIENTATION_RIGHT)
nextX = WSSIZE.x - WIDTH;
else if (orientation == ORIENTATION_CENTER)
nextX = (WSSIZE.x - WIDTH) / 2;
PMASTERNODE->size = Vector2D(WIDTH, WSSIZE.y);
PMASTERNODE->position = WSPOS + Vector2D((double)nextX, 0.0);
} else {
PMASTERNODE->size = WSSIZE; PMASTERNODE->size = WSSIZE;
PMASTERNODE->position = WSPOS; PMASTERNODE->position = WSPOS;
}
applyNodeDataToWindow(PMASTERNODE); applyNodeDataToWindow(PMASTERNODE);
return; return;
@@ -692,12 +678,16 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
*PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealPosition = wb.pos();
*PWINDOW->m_vRealSize = wb.size(); *PWINDOW->m_vRealSize = wb.size();
PWINDOW->sendWindowSize(wb.size());
} else { } else {
CBox wb = {calcPos, calcSize}; CBox wb = {calcPos, calcSize};
wb.round(); // avoid rounding mess wb.round(); // avoid rounding mess
*PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealPosition = wb.pos();
*PWINDOW->m_vRealSize = wb.size(); *PWINDOW->m_vRealSize = wb.size();
PWINDOW->sendWindowSize(wb.size());
} }
if (m_bForceWarps && !*PANIMATE) { if (m_bForceWarps && !*PANIMATE) {
@@ -1367,7 +1357,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi
int nextOrPrev = 0; int nextOrPrev = 0;
for (size_t i = 0; i < cycle.size(); ++i) { for (size_t i = 0; i < cycle.size(); ++i) {
if (PWORKSPACEDATA->orientation == cycle[i]) { if (PWORKSPACEDATA->orientation == cycle.at(i)) {
nextOrPrev = i + direction; nextOrPrev = i + direction;
break; break;
} }

View File

@@ -5,6 +5,7 @@
#include "../helpers/varlist/VarList.hpp" #include "../helpers/varlist/VarList.hpp"
#include <vector> #include <vector>
#include <list> #include <list>
#include <vector>
#include <any> #include <any>
enum eFullscreenMode : int8_t; enum eFullscreenMode : int8_t;

View File

@@ -39,7 +39,6 @@
#define DYNMULTILISTENER(name) wl_listener listen_##name #define DYNMULTILISTENER(name) wl_listener listen_##name
#define VECINRECT(vec, x1, y1, x2, y2) ((vec).x >= (x1) && (vec).x < (x2) && (vec).y >= (y1) && (vec).y < (y2)) #define VECINRECT(vec, x1, y1, x2, y2) ((vec).x >= (x1) && (vec).x < (x2) && (vec).y >= (y1) && (vec).y < (y2))
#define VECNOTINRECT(vec, x1, y1, x2, y2) ((vec).x < (x1) || (vec).x >= (x2) || (vec).y < (y1) || (vec).y >= (y2))
#define DELTALESSTHAN(a, b, delta) (abs((a) - (b)) < (delta)) #define DELTALESSTHAN(a, b, delta) (abs((a) - (b)) < (delta))
@@ -89,7 +88,6 @@
{ \ { \
Debug::log(CRIT, "\n\nMEMORY CORRUPTED: Unreachable failed! (Reached an unreachable position, memory corruption!!!)"); \ Debug::log(CRIT, "\n\nMEMORY CORRUPTED: Unreachable failed! (Reached an unreachable position, memory corruption!!!)"); \
raise(SIGABRT); \ raise(SIGABRT); \
std::unreachable(); \
} }
#else #else
#define UNREACHABLE() std::unreachable(); #define UNREACHABLE() std::unreachable();
@@ -112,7 +110,6 @@
} \ } \
} }
#define AQUAMARINE_VERSION_NUMBER (AQUAMARINE_VERSION_MAJOR * 10000 + AQUAMARINE_VERSION_MINOR * 100 + AQUAMARINE_VERSION_PATCH)
#define AQUAMARINE_FORWARD(name) \ #define AQUAMARINE_FORWARD(name) \
namespace Aquamarine { \ namespace Aquamarine { \
class name; \ class name; \

View File

@@ -43,7 +43,6 @@ int main(int argc, char** argv) {
setenv("HYPRLAND_CMD", cmd.c_str(), 1); setenv("HYPRLAND_CMD", cmd.c_str(), 1);
setenv("XDG_BACKEND", "wayland", 1); setenv("XDG_BACKEND", "wayland", 1);
setenv("XDG_SESSION_TYPE", "wayland", 1);
setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1); setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1);
setenv("MOZ_ENABLE_WAYLAND", "1", 1); setenv("MOZ_ENABLE_WAYLAND", "1", 1);

View File

@@ -1,251 +0,0 @@
#include "ANRManager.hpp"
#include "../helpers/fs/FsUtils.hpp"
#include "../debug/Log.hpp"
#include "../macros.hpp"
#include "HookSystemManager.hpp"
#include "../Compositor.hpp"
#include "../protocols/XDGShell.hpp"
#include "./eventLoop/EventLoopManager.hpp"
#include "../config/ConfigValue.hpp"
#include "../xwayland/XSurface.hpp"
using namespace Hyprutils::OS;
static constexpr auto TIMER_TIMEOUT = std::chrono::milliseconds(1500);
CANRManager::CANRManager() {
if (!NFsUtils::executableExistsInPath("hyprland-dialog")) {
Debug::log(ERR, "hyprland-dialog missing from PATH, cannot start ANRManager");
return;
}
m_timer = makeShared<CEventLoopTimer>(TIMER_TIMEOUT, [this](SP<CEventLoopTimer> self, void* data) { onTick(); }, this);
g_pEventLoopManager->addTimer(m_timer);
m_active = true;
static auto P = g_pHookSystem->hookDynamic("openWindow", [this](void* self, SCallbackInfo& info, std::any data) {
auto window = std::any_cast<PHLWINDOW>(data);
for (const auto& d : m_data) {
if (d->fitsWindow(window))
return;
}
m_data.emplace_back(makeShared<SANRData>(window));
});
m_timer->updateTimeout(TIMER_TIMEOUT);
}
void CANRManager::onTick() {
std::erase_if(m_data, [](const auto& e) { return e->isDefunct(); });
static auto PENABLEANR = CConfigValue<Hyprlang::INT>("misc:enable_anr_dialog");
if (!*PENABLEANR) {
m_timer->updateTimeout(TIMER_TIMEOUT * 10);
return;
}
for (auto& data : m_data) {
PHLWINDOW firstWindow;
int count = 0;
for (const auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped)
continue;
if (!data->fitsWindow(w))
continue;
count++;
if (!firstWindow)
firstWindow = w;
}
if (count == 0)
continue;
if (data->missedResponses > 0) {
if (!data->isThreadRunning() && !data->dialogThreadSaidWait) {
data->runDialog("Application Not Responding", firstWindow->m_szTitle, firstWindow->m_szClass, data->getPid());
for (const auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped)
continue;
if (!data->fitsWindow(w))
continue;
*w->m_notRespondingTint = 0.2F;
}
}
} else if (data->isThreadRunning())
data->killDialog();
if (data->missedResponses == 0)
data->dialogThreadSaidWait = false;
data->missedResponses++;
data->ping();
}
m_timer->updateTimeout(TIMER_TIMEOUT);
}
void CANRManager::onResponse(SP<CXDGWMBase> wmBase) {
const auto DATA = dataFor(wmBase);
if (!DATA)
return;
onResponse(DATA);
}
void CANRManager::onResponse(SP<CXWaylandSurface> pXwaylandSurface) {
const auto DATA = dataFor(pXwaylandSurface);
if (!DATA)
return;
onResponse(DATA);
}
void CANRManager::onResponse(SP<CANRManager::SANRData> data) {
data->missedResponses = 0;
if (data->isThreadRunning())
data->killDialog();
}
bool CANRManager::isNotResponding(PHLWINDOW pWindow) {
const auto DATA = dataFor(pWindow);
if (!DATA)
return false;
return isNotResponding(DATA);
}
bool CANRManager::isNotResponding(SP<CANRManager::SANRData> data) {
return data->missedResponses > 1;
}
SP<CANRManager::SANRData> CANRManager::dataFor(PHLWINDOW pWindow) {
auto it = m_data.end();
if (pWindow->m_pXWaylandSurface)
it = std::ranges::find_if(m_data, [&pWindow](const auto& data) { return data->xwaylandSurface && data->xwaylandSurface == pWindow->m_pXWaylandSurface; });
else if (pWindow->m_pXDGSurface)
it = std::ranges::find_if(m_data, [&pWindow](const auto& data) { return data->xdgBase && data->xdgBase == pWindow->m_pXDGSurface->owner; });
return it == m_data.end() ? nullptr : *it;
}
SP<CANRManager::SANRData> CANRManager::dataFor(SP<CXDGWMBase> wmBase) {
auto it = std::ranges::find_if(m_data, [&wmBase](const auto& data) { return data->xdgBase && data->xdgBase == wmBase; });
return it == m_data.end() ? nullptr : *it;
}
SP<CANRManager::SANRData> CANRManager::dataFor(SP<CXWaylandSurface> pXwaylandSurface) {
auto it = std::ranges::find_if(m_data, [&pXwaylandSurface](const auto& data) { return data->xwaylandSurface && data->xwaylandSurface == pXwaylandSurface; });
return it == m_data.end() ? nullptr : *it;
}
CANRManager::SANRData::SANRData(PHLWINDOW pWindow) :
xwaylandSurface(pWindow->m_pXWaylandSurface), xdgBase(pWindow->m_pXDGSurface ? pWindow->m_pXDGSurface->owner : WP<CXDGWMBase>{}) {
;
}
CANRManager::SANRData::~SANRData() {
if (dialogThread.joinable()) {
killDialog();
// dangerous: might lock if the above failed!!
dialogThread.join();
}
}
void CANRManager::SANRData::runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID) {
if (!dialogThreadExited)
killDialog();
// dangerous: might lock if the above failed!!
if (dialogThread.joinable())
dialogThread.join();
dialogThreadExited = false;
dialogThreadSaidWait = false;
dialogThread = std::thread([title, appName, appClass, dialogWmPID, this]() {
SP<CProcess> proc = makeShared<CProcess>("hyprland-dialog",
std::vector<std::string>{"--title", title, "--text",
std::format("Application {} with class of {} is not responding.\nWhat do you want to do with it?",
appName.empty() ? "unknown" : appName, appClass.empty() ? "unknown" : appClass),
"--buttons", "Terminate;Wait"});
dialogProc = proc;
proc->runSync();
dialogThreadExited = true;
if (proc->stdOut().empty())
return;
if (proc->stdOut().starts_with("Terminate"))
kill(dialogWmPID, SIGKILL);
if (proc->stdOut().starts_with("Wait"))
dialogThreadSaidWait = true;
});
}
bool CANRManager::SANRData::isThreadRunning() {
if (dialogThread.native_handle() == 0)
return false;
if (dialogThreadExited)
return false;
return pthread_kill(dialogThread.native_handle(), 0) != ESRCH;
}
void CANRManager::SANRData::killDialog() const {
if (!dialogProc)
return;
if (!dialogProc->pid()) {
Debug::log(ERR, "ANR: cannot kill dialogProc, as it doesn't have a pid. If you have hyprutils <= 0.6.0, you will crash soon. Otherwise, dialog failed to spawn??");
return;
}
kill(dialogProc->pid(), SIGKILL);
}
bool CANRManager::SANRData::fitsWindow(PHLWINDOW pWindow) const {
if (pWindow->m_pXWaylandSurface)
return pWindow->m_pXWaylandSurface == xwaylandSurface;
else if (pWindow->m_pXDGSurface)
return pWindow->m_pXDGSurface->owner == xdgBase && xdgBase;
return false;
}
bool CANRManager::SANRData::isDefunct() const {
return xdgBase.expired() && xwaylandSurface.expired();
}
pid_t CANRManager::SANRData::getPid() const {
if (xdgBase) {
pid_t pid = 0;
wl_client_get_credentials(xdgBase->client(), &pid, nullptr, nullptr);
return pid;
}
if (xwaylandSurface)
return xwaylandSurface->pid;
return 0;
}
void CANRManager::SANRData::ping() {
if (xdgBase) {
xdgBase->ping();
return;
}
if (xwaylandSurface)
xwaylandSurface->ping();
}

View File

@@ -1,62 +0,0 @@
#pragma once
#include "../helpers/memory/Memory.hpp"
#include "../desktop/DesktopTypes.hpp"
#include <chrono>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/os/FileDescriptor.hpp>
#include "./eventLoop/EventLoopTimer.hpp"
#include "../helpers/signal/Signal.hpp"
#include <atomic>
#include <thread>
#include <vector>
class CXDGWMBase;
class CXWaylandSurface;
class CANRManager {
public:
CANRManager();
void onResponse(SP<CXDGWMBase> wmBase);
void onResponse(SP<CXWaylandSurface> xwaylandSurface);
bool isNotResponding(PHLWINDOW pWindow);
private:
bool m_active = false;
SP<CEventLoopTimer> m_timer;
void onTick();
struct SANRData {
SANRData(PHLWINDOW pWindow);
~SANRData();
WP<CXWaylandSurface> xwaylandSurface;
WP<CXDGWMBase> xdgBase;
int missedResponses = 0;
std::thread dialogThread;
SP<Hyprutils::OS::CProcess> dialogProc;
std::atomic<bool> dialogThreadExited = false;
std::atomic<bool> dialogThreadSaidWait = false;
void runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID);
bool isThreadRunning();
void killDialog() const;
bool isDefunct() const;
bool fitsWindow(PHLWINDOW pWindow) const;
pid_t getPid() const;
void ping();
};
void onResponse(SP<SANRData> data);
bool isNotResponding(SP<SANRData> data);
SP<SANRData> dataFor(PHLWINDOW pWindow);
SP<SANRData> dataFor(SP<CXDGWMBase> wmBase);
SP<SANRData> dataFor(SP<CXWaylandSurface> pXwaylandSurface);
std::vector<SP<SANRData>> m_data;
};
inline UP<CANRManager> g_pANRManager;

View File

@@ -357,21 +357,6 @@ void CHyprAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force,
*pWindow->m_vRealPosition = posOffset; *pWindow->m_vRealPosition = posOffset;
} }
void CHyprAnimationManager::animationGnomed(PHLWINDOW pWindow, bool close) {
const auto GOALPOS = pWindow->m_vRealPosition->goal();
const auto GOALSIZE = pWindow->m_vRealSize->goal();
if (close) {
*pWindow->m_vRealPosition = GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F};
*pWindow->m_vRealSize = Vector2D{GOALSIZE.x, 0.F};
} else {
pWindow->m_vRealPosition->setValueAndWarp(GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F});
pWindow->m_vRealSize->setValueAndWarp(Vector2D{GOALSIZE.x, 0.F});
*pWindow->m_vRealPosition = GOALPOS;
*pWindow->m_vRealSize = GOALSIZE;
}
}
void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) {
if (!close) { if (!close) {
pWindow->m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); pWindow->m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn"));
@@ -402,9 +387,7 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos
if (STYLE.starts_with("slide")) { if (STYLE.starts_with("slide")) {
CVarList animList2(STYLE, 0, 's'); CVarList animList2(STYLE, 0, 's');
animationSlide(pWindow, animList2[1], close); animationSlide(pWindow, animList2[1], close);
} else if (STYLE == "gnomed" || STYLE == "gnome") } else {
animationGnomed(pWindow, close);
else {
// anim popin, fallback // anim popin, fallback
float minPerc = 0.f; float minPerc = 0.f;
@@ -422,8 +405,6 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos
} else { } else {
if (animList[0] == "slide") if (animList[0] == "slide")
animationSlide(pWindow, animList[1], close); animationSlide(pWindow, animList[1], close);
else if (animList[0] == "gnomed" || animList[0] == "gnome")
animationGnomed(pWindow, close);
else { else {
// anim popin, fallback // anim popin, fallback
@@ -444,7 +425,7 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos
std::string CHyprAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { std::string CHyprAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) {
if (config.starts_with("window")) { if (config.starts_with("window")) {
if (style.starts_with("slide") || style == "gnome" || style == "gnomed") if (style.starts_with("slide"))
return ""; return "";
else if (style.starts_with("popin")) { else if (style.starts_with("popin")) {
// try parsing // try parsing

View File

@@ -59,7 +59,6 @@ class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager {
// Anim stuff // Anim stuff
void animationPopin(PHLWINDOW, bool close = false, float minPerc = 0.f); void animationPopin(PHLWINDOW, bool close = false, float minPerc = 0.f);
void animationSlide(PHLWINDOW, std::string force = "", bool close = false); void animationSlide(PHLWINDOW, std::string force = "", bool close = false);
void animationGnomed(PHLWINDOW, bool close = false);
}; };
inline UP<CHyprAnimationManager> g_pAnimationManager; inline UP<CHyprAnimationManager> g_pAnimationManager;

View File

@@ -9,10 +9,9 @@
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include <cstring> #include <cstring>
using namespace Hyprutils::OS;
CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) { CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) {
if (!m_iSocketFD.isValid()) { if (m_iSocketFD < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work.");
return; return;
} }
@@ -26,27 +25,31 @@ CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_
strncpy(SERVERADDRESS.sun_path, PATH.c_str(), sizeof(SERVERADDRESS.sun_path) - 1); strncpy(SERVERADDRESS.sun_path, PATH.c_str(), sizeof(SERVERADDRESS.sun_path) - 1);
if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
Debug::log(ERR, "Couldn't bind the Hyprland Socket 2. (3) IPC will not work."); Debug::log(ERR, "Couldn't bind the Hyprland Socket 2. (3) IPC will not work.");
return; return;
} }
// 10 max queued. // 10 max queued.
if (listen(m_iSocketFD.get(), 10) < 0) { if (listen(m_iSocketFD, 10) < 0) {
Debug::log(ERR, "Couldn't listen on the Hyprland Socket 2. (4) IPC will not work."); Debug::log(ERR, "Couldn't listen on the Hyprland Socket 2. (4) IPC will not work.");
return; return;
} }
m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, onClientEvent, nullptr); m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, onClientEvent, nullptr);
} }
CEventManager::~CEventManager() { CEventManager::~CEventManager() {
for (const auto& client : m_vClients) { for (const auto& client : m_vClients) {
wl_event_source_remove(client.eventSource); wl_event_source_remove(client.eventSource);
close(client.fd);
} }
if (m_pEventSource != nullptr) if (m_pEventSource != nullptr)
wl_event_source_remove(m_pEventSource); wl_event_source_remove(m_pEventSource);
if (m_iSocketFD >= 0)
close(m_iSocketFD);
} }
int CEventManager::onServerEvent(int fd, uint32_t mask, void* data) { int CEventManager::onServerEvent(int fd, uint32_t mask, void* data) {
@@ -63,31 +66,33 @@ int CEventManager::onServerEvent(int fd, uint32_t mask) {
wl_event_source_remove(m_pEventSource); wl_event_source_remove(m_pEventSource);
m_pEventSource = nullptr; m_pEventSource = nullptr;
m_iSocketFD.reset(); close(fd);
m_iSocketFD = -1;
return 0; return 0;
} }
sockaddr_in clientAddress; sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress); socklen_t clientSize = sizeof(clientAddress);
CFileDescriptor ACCEPTEDCONNECTION{accept4(m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK)}; const auto ACCEPTEDCONNECTION = accept4(m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK);
if (!ACCEPTEDCONNECTION.isValid()) { if (ACCEPTEDCONNECTION < 0) {
if (errno != EAGAIN) { if (errno != EAGAIN) {
Debug::log(ERR, "Socket2 failed receiving connection, errno: {}", errno); Debug::log(ERR, "Socket2 failed receiving connection, errno: {}", errno);
wl_event_source_remove(m_pEventSource); wl_event_source_remove(m_pEventSource);
m_pEventSource = nullptr; m_pEventSource = nullptr;
m_iSocketFD.reset(); close(fd);
m_iSocketFD = -1;
} }
return 0; return 0;
} }
Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION.get()); Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION);
// add to event loop so we can close it when we need to // add to event loop so we can close it when we need to
auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION.get(), 0, onServerEvent, nullptr); auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, 0, onServerEvent, nullptr);
m_vClients.emplace_back(SClient{ m_vClients.emplace_back(SClient{
std::move(ACCEPTEDCONNECTION), ACCEPTEDCONNECTION,
{}, {},
eventSource, eventSource,
}); });
@@ -108,7 +113,7 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) {
// send all queued events // send all queued events
while (!CLIENTIT->events.empty()) { while (!CLIENTIT->events.empty()) {
const auto& event = CLIENTIT->events.front(); const auto& event = CLIENTIT->events.front();
if (write(CLIENTIT->fd.get(), event->c_str(), event->length()) < 0) if (write(CLIENTIT->fd, event->c_str(), event->length()) < 0)
break; break;
CLIENTIT->events.erase(CLIENTIT->events.begin()); CLIENTIT->events.erase(CLIENTIT->events.begin());
@@ -123,12 +128,13 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) {
} }
std::vector<CEventManager::SClient>::iterator CEventManager::findClientByFD(int fd) { std::vector<CEventManager::SClient>::iterator CEventManager::findClientByFD(int fd) {
return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd.get() == fd; }); return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd == fd; });
} }
std::vector<CEventManager::SClient>::iterator CEventManager::removeClientByFD(int fd) { std::vector<CEventManager::SClient>::iterator CEventManager::removeClientByFD(int fd) {
const auto CLIENTIT = findClientByFD(fd); const auto CLIENTIT = findClientByFD(fd);
wl_event_source_remove(CLIENTIT->eventSource); wl_event_source_remove(CLIENTIT->eventSource);
close(fd);
return m_vClients.erase(CLIENTIT); return m_vClients.erase(CLIENTIT);
} }
@@ -151,11 +157,11 @@ void CEventManager::postEvent(const SHyprIPCEvent& event) {
for (auto it = m_vClients.begin(); it != m_vClients.end();) { for (auto it = m_vClients.begin(); it != m_vClients.end();) {
// try to send the event immediately if the queue is empty // try to send the event immediately if the queue is empty
const auto QUEUESIZE = it->events.size(); const auto QUEUESIZE = it->events.size();
if (QUEUESIZE > 0 || write(it->fd.get(), sharedEvent->c_str(), sharedEvent->length()) < 0) { if (QUEUESIZE > 0 || write(it->fd, sharedEvent->c_str(), sharedEvent->length()) < 0) {
if (QUEUESIZE >= MAX_QUEUED_EVENTS) { if (QUEUESIZE >= MAX_QUEUED_EVENTS) {
// too many events queued, remove the client // too many events queued, remove the client
Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd.get()); Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd);
it = removeClientByFD(it->fd.get()); it = removeClientByFD(it->fd);
continue; continue;
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <hyprutils/os/FileDescriptor.hpp> #include <vector>
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/memory/Memory.hpp" #include "../helpers/memory/Memory.hpp"
@@ -26,7 +27,7 @@ class CEventManager {
int onClientEvent(int fd, uint32_t mask); int onClientEvent(int fd, uint32_t mask);
struct SClient { struct SClient {
Hyprutils::OS::CFileDescriptor fd; int fd = -1;
std::vector<SP<std::string>> events; std::vector<SP<std::string>> events;
wl_event_source* eventSource = nullptr; wl_event_source* eventSource = nullptr;
}; };
@@ -35,7 +36,7 @@ class CEventManager {
std::vector<SClient>::iterator removeClientByFD(int fd); std::vector<SClient>::iterator removeClientByFD(int fd);
private: private:
Hyprutils::OS::CFileDescriptor m_iSocketFD; int m_iSocketFD = -1;
wl_event_source* m_pEventSource = nullptr; wl_event_source* m_pEventSource = nullptr;
std::vector<SClient> m_vClients; std::vector<SClient> m_vClients;

View File

@@ -12,6 +12,8 @@
#include "TokenManager.hpp" #include "TokenManager.hpp"
#include "eventLoop/EventLoopManager.hpp" #include "eventLoop/EventLoopManager.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
#include "helpers/varlist/VarList.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../managers/HookSystemManager.hpp" #include "../managers/HookSystemManager.hpp"
#include "../managers/input/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../managers/LayoutManager.hpp" #include "../managers/LayoutManager.hpp"
@@ -26,9 +28,7 @@
#include <cstring> #include <cstring>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <hyprutils/os/FileDescriptor.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::OS;
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <fcntl.h> #include <fcntl.h>
@@ -113,7 +113,6 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["focuswindowbyclass"] = focusWindow; m_mDispatchers["focuswindowbyclass"] = focusWindow;
m_mDispatchers["focuswindow"] = focusWindow; m_mDispatchers["focuswindow"] = focusWindow;
m_mDispatchers["tagwindow"] = tagWindow; m_mDispatchers["tagwindow"] = tagWindow;
m_mDispatchers["toggleswallow"] = toggleSwallow;
m_mDispatchers["submap"] = setSubmap; m_mDispatchers["submap"] = setSubmap;
m_mDispatchers["pass"] = pass; m_mDispatchers["pass"] = pass;
m_mDispatchers["sendshortcut"] = sendshortcut; m_mDispatchers["sendshortcut"] = sendshortcut;
@@ -368,7 +367,7 @@ bool CKeybindManager::tryMoveFocusToMonitor(PHLMONITOR monitor) {
return true; return true;
} }
void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveFocusHistory) { void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse"); static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
static auto PNOWARPS = CConfigValue<Hyprlang::INT>("cursor:no_warps"); static auto PNOWARPS = CConfigValue<Hyprlang::INT>("cursor:no_warps");
@@ -387,7 +386,7 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveF
if (!PWINDOWTOCHANGETO->m_bPinned) if (!PWINDOWTOCHANGETO->m_bPinned)
g_pCompositor->setWindowFullscreenInternal(PLASTWINDOW, FSMODE_NONE); g_pCompositor->setWindowFullscreenInternal(PLASTWINDOW, FSMODE_NONE);
g_pCompositor->focusWindow(PWINDOWTOCHANGETO, nullptr, preserveFocusHistory); g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
if (!PWINDOWTOCHANGETO->m_bPinned) if (!PWINDOWTOCHANGETO->m_bPinned)
g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE); g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE);
@@ -397,7 +396,7 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveF
PWINDOWTOCHANGETO->m_vRealSize->warp(); PWINDOWTOCHANGETO->m_vRealSize->warp();
} else { } else {
updateRelativeCursorCoords(); updateRelativeCursorCoords();
g_pCompositor->focusWindow(PWINDOWTOCHANGETO, nullptr, preserveFocusHistory); g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
PWINDOWTOCHANGETO->warpCursor(); PWINDOWTOCHANGETO->warpCursor();
// Move mouse focus to the new window if required by current follow_mouse and warp modes // Move mouse focus to the new window if required by current follow_mouse and warp modes
@@ -855,17 +854,18 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
// vtnr is bugged for some reason. // vtnr is bugged for some reason.
unsigned int ttynum = 0; unsigned int ttynum = 0;
Hyprutils::OS::CFileDescriptor fd{open("/dev/tty", O_RDONLY | O_NOCTTY)}; int fd;
if (fd.isValid()) { if ((fd = open("/dev/tty", O_RDONLY | O_NOCTTY)) >= 0) {
#if defined(VT_GETSTATE) #if defined(VT_GETSTATE)
struct vt_stat st; struct vt_stat st;
if (!ioctl(fd.get(), VT_GETSTATE, &st)) if (!ioctl(fd, VT_GETSTATE, &st))
ttynum = st.v_active; ttynum = st.v_active;
#elif defined(VT_GETACTIVE) #elif defined(VT_GETACTIVE)
int vt; int vt;
if (!ioctl(fd.get(), VT_GETACTIVE, &vt)) if (!ioctl(fd, VT_GETACTIVE, &vt))
ttynum = vt; ttynum = vt;
#endif #endif
close(fd);
} }
if (ttynum == TTY) if (ttynum == TTY)
@@ -944,11 +944,11 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo
Debug::log(LOG, "Unable to create pipe for fork"); Debug::log(LOG, "Unable to create pipe for fork");
} }
CFileDescriptor pipeSock[2] = {CFileDescriptor{socket[0]}, CFileDescriptor{socket[1]}};
pid_t child, grandchild; pid_t child, grandchild;
child = fork(); child = fork();
if (child < 0) { if (child < 0) {
close(socket[0]);
close(socket[1]);
Debug::log(LOG, "Fail to create the first fork"); Debug::log(LOG, "Fail to create the first fork");
return 0; return 0;
} }
@@ -967,24 +967,22 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo
setenv(e.first.c_str(), e.second.c_str(), 1); setenv(e.first.c_str(), e.second.c_str(), 1);
} }
setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1);
close(socket[0]);
int devnull = open("/dev/null", O_WRONLY | O_CLOEXEC); close(socket[1]);
if (devnull != -1) {
dup2(devnull, STDOUT_FILENO);
dup2(devnull, STDERR_FILENO);
close(devnull);
}
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
// exit grandchild // exit grandchild
_exit(0); _exit(0);
} }
write(pipeSock[1].get(), &grandchild, sizeof(grandchild)); close(socket[0]);
write(socket[1], &grandchild, sizeof(grandchild));
close(socket[1]);
// exit child // exit child
_exit(0); _exit(0);
} }
// run in parent // run in parent
read(pipeSock[0].get(), &grandchild, sizeof(grandchild)); close(socket[1]);
read(socket[0], &grandchild, sizeof(grandchild));
close(socket[0]);
// clear child and leave grandchild to init // clear child and leave grandchild to init
waitpid(child, nullptr, 0); waitpid(child, nullptr, 0);
if (grandchild < 0) { if (grandchild < 0) {
@@ -1043,7 +1041,7 @@ SDispatchResult CKeybindManager::killWindow(std::string args) {
} }
SDispatchResult CKeybindManager::signalActive(std::string args) { SDispatchResult CKeybindManager::signalActive(std::string args) {
if (!isNumber(args)) if (!std::all_of(args.begin(), args.end(), ::isdigit))
return {.success = false, .error = "signalActive: signal has to be int"}; return {.success = false, .error = "signalActive: signal has to be int"};
try { try {
@@ -1482,7 +1480,7 @@ SDispatchResult CKeybindManager::moveFocusTo(std::string args) {
} }
const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ? const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ?
g_pCompositor->getWindowCycle(PLASTWINDOW, true, {}, false, arg != 'd' && arg != 'b' && arg != 'r') : (arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) :
g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
// Prioritize focus change within groups if the window is a part of it. // Prioritize focus change within groups if the window is a part of it.
@@ -1723,7 +1721,7 @@ SDispatchResult CKeybindManager::changeGroupActive(std::string args) {
// index starts from '1'; '0' means last window // index starts from '1'; '0' means last window
const int INDEX = std::stoi(args); const int INDEX = std::stoi(args);
if (INDEX > PWINDOW->getGroupSize()) if (INDEX > PWINDOW->getGroupSize())
return {.success = false, .error = "Index too big, there aren't that many windows in this group"}; return {};
if (INDEX == 0) if (INDEX == 0)
PWINDOW->setGroupCurrent(PWINDOW->getGroupTail()); PWINDOW->setGroupCurrent(PWINDOW->getGroupTail());
else else
@@ -1916,6 +1914,7 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) {
if (PWORKSPACE->m_bDefaultFloating) { if (PWORKSPACE->m_bDefaultFloating) {
w->m_vRealPosition->setValueAndWarp(SAVEDPOS); w->m_vRealPosition->setValueAndWarp(SAVEDPOS);
w->m_vRealSize->setValueAndWarp(SAVEDSIZE); w->m_vRealSize->setValueAndWarp(SAVEDSIZE);
w->sendWindowSize(SAVEDSIZE);
*w->m_vRealSize = w->m_vRealSize->value() + Vector2D(4, 4); *w->m_vRealSize = w->m_vRealSize->value() + Vector2D(4, 4);
*w->m_vRealPosition = w->m_vRealPosition->value() - Vector2D(2, 2); *w->m_vRealPosition = w->m_vRealPosition->value() - Vector2D(2, 2);
} }
@@ -1986,7 +1985,7 @@ SDispatchResult CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args)
SDispatchResult CKeybindManager::moveWorkspaceToMonitor(std::string args) { SDispatchResult CKeybindManager::moveWorkspaceToMonitor(std::string args) {
if (!args.contains(' ')) if (!args.contains(' '))
return {.success = false, .error = "Invalid arguments, expected: workspace monitor"}; return {};
std::string workspace = args.substr(0, args.find_first_of(' ')); std::string workspace = args.substr(0, args.find_first_of(' '));
std::string monitor = args.substr(args.find_first_of(' ') + 1); std::string monitor = args.substr(args.find_first_of(' ') + 1);
@@ -2129,16 +2128,13 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) {
SDispatchResult CKeybindManager::resizeActive(std::string args) { SDispatchResult CKeybindManager::resizeActive(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PLASTWINDOW) if (!PLASTWINDOW || PLASTWINDOW->isFullscreen())
return {.success = false, .error = "No window found"}; return {};
if (PLASTWINDOW->isFullscreen())
return {.success = false, .error = "Window is fullscreen"};
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize->goal()); const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize->goal());
if (SIZ.x < 1 || SIZ.y < 1) if (SIZ.x < 1 || SIZ.y < 1)
return {.success = false, .error = "Invalid size provided"}; return {};
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize->goal()); g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize->goal());
@@ -2151,11 +2147,8 @@ SDispatchResult CKeybindManager::resizeActive(std::string args) {
SDispatchResult CKeybindManager::moveActive(std::string args) { SDispatchResult CKeybindManager::moveActive(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PLASTWINDOW) if (!PLASTWINDOW || PLASTWINDOW->isFullscreen())
return {.success = false, .error = "No window found"}; return {};
if (PLASTWINDOW->isFullscreen())
return {.success = false, .error = "Window is fullscreen"};
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition->goal()); const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition->goal());
@@ -2177,7 +2170,7 @@ SDispatchResult CKeybindManager::moveWindow(std::string args) {
} }
if (PWINDOW->isFullscreen()) if (PWINDOW->isFullscreen())
return {.success = false, .error = "Window is fullscreen"}; return {};
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition->goal()); const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition->goal());
@@ -2199,12 +2192,12 @@ SDispatchResult CKeybindManager::resizeWindow(std::string args) {
} }
if (PWINDOW->isFullscreen()) if (PWINDOW->isFullscreen())
return {.success = false, .error = "Window is fullscreen"}; return {};
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize->goal()); const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize->goal());
if (SIZ.x < 1 || SIZ.y < 1) if (SIZ.x < 1 || SIZ.y < 1)
return {.success = false, .error = "Invalid size provided"}; return {};
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize->goal(), CORNER_NONE, PWINDOW); g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize->goal(), CORNER_NONE, PWINDOW);
@@ -2235,13 +2228,11 @@ SDispatchResult CKeybindManager::circleNext(std::string arg) {
floatStatus = true; floatStatus = true;
const auto VISIBLE = args.contains("visible") || args.contains("v"); const auto VISIBLE = args.contains("visible") || args.contains("v");
const auto PREV = args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l"); const auto& w = (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l")) ?
const auto NEXT = args.contains("next") || args.contains("n"); // prev is default in classic alt+tab g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE) :
const auto HIST = args.contains("hist") || args.contains("h"); g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE);
const auto& w = HIST ? g_pCompositor->getWindowCycleHist(g_pCompositor->m_pLastWindow, true, floatStatus, VISIBLE, NEXT) :
g_pCompositor->getWindowCycle(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE, PREV);
switchToWindow(w, HIST); switchToWindow(w);
return {}; return {};
} }
@@ -2250,7 +2241,7 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) {
const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp); const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp);
if (!PWINDOW) if (!PWINDOW)
return {.success = false, .error = "No such window found"}; return {};
Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle); Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle);
@@ -2310,7 +2301,7 @@ SDispatchResult CKeybindManager::tagWindow(std::string args) {
else if (vars.size() == 2) else if (vars.size() == 2)
PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
else else
return {.success = false, .error = "Invalid number of arguments, expected 1 or 2 arguments"}; return {};
if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) { if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) {
PWINDOW->updateDynamicRules(); PWINDOW->updateDynamicRules();
@@ -2320,27 +2311,6 @@ SDispatchResult CKeybindManager::tagWindow(std::string args) {
return {}; return {};
} }
SDispatchResult CKeybindManager::toggleSwallow(std::string args) {
PHLWINDOWREF pWindow = g_pCompositor->m_pLastWindow;
if (!valid(pWindow) || !valid(pWindow->m_pSwallowed))
return {};
if (pWindow->m_pSwallowed->m_bCurrentlySwallowed) {
// Unswallow
pWindow->m_pSwallowed->m_bCurrentlySwallowed = false;
pWindow->m_pSwallowed->setHidden(false);
g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow->m_pSwallowed.lock());
} else {
// Reswallow
pWindow->m_pSwallowed->m_bCurrentlySwallowed = true;
pWindow->m_pSwallowed->setHidden(true);
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow->m_pSwallowed.lock());
}
return {};
}
SDispatchResult CKeybindManager::setSubmap(std::string submap) { SDispatchResult CKeybindManager::setSubmap(std::string submap) {
if (submap == "reset" || submap == "") { if (submap == "reset" || submap == "") {
m_szCurrentSelectedSubmap = ""; m_szCurrentSelectedSubmap = "";
@@ -2657,12 +2627,18 @@ SDispatchResult CKeybindManager::swapnext(std::string arg) {
g_pCompositor->m_pLastWindow->m_pLastCycledWindow.lock() : g_pCompositor->m_pLastWindow->m_pLastCycledWindow.lock() :
nullptr; nullptr;
const bool NEED_PREV = arg == "last" || arg == "l" || arg == "prev" || arg == "p"; if (arg == "last" || arg == "l" || arg == "prev" || arg == "p")
toSwap = g_pCompositor->getWindowCycle(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true, std::nullopt, false, NEED_PREV); toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true);
else
toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true);
// sometimes we may come back to ourselves. // sometimes we may come back to ourselves.
if (toSwap == PLASTWINDOW) if (toSwap == PLASTWINDOW) {
toSwap = g_pCompositor->getWindowCycle(PLASTWINDOW, true, std::nullopt, false, NEED_PREV); if (arg == "last" || arg == "l" || arg == "prev" || arg == "p")
toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true);
else
toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true);
}
g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, toSwap); g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, toSwap);
@@ -2680,10 +2656,7 @@ SDispatchResult CKeybindManager::swapActiveWorkspaces(std::string args) {
const auto PMON1 = g_pCompositor->getMonitorFromString(MON1); const auto PMON1 = g_pCompositor->getMonitorFromString(MON1);
const auto PMON2 = g_pCompositor->getMonitorFromString(MON2); const auto PMON2 = g_pCompositor->getMonitorFromString(MON2);
if (!PMON1 || !PMON2) if (!PMON1 || !PMON2 || PMON1 == PMON2)
return {.success = false, .error = "No such monitor found"};
if (PMON1 == PMON2)
return {}; return {};
g_pCompositor->swapActiveWorkspaces(PMON1, PMON2); g_pCompositor->swapActiveWorkspaces(PMON1, PMON2);
@@ -2706,7 +2679,7 @@ SDispatchResult CKeybindManager::pinActive(std::string args) {
} }
if (!PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) if (!PWINDOW->m_bIsFloating || PWINDOW->isFullscreen())
return {.success = false, .error = "Window does not qualify to be pinned"}; return {};
PWINDOW->m_bPinned = !PWINDOW->m_bPinned; PWINDOW->m_bPinned = !PWINDOW->m_bPinned;
@@ -2827,7 +2800,6 @@ SDispatchResult CKeybindManager::lockGroups(std::string args) {
g_pKeybindManager->m_bGroupsLocked = false; g_pKeybindManager->m_bGroupsLocked = false;
g_pEventManager->postEvent(SHyprIPCEvent{"lockgroups", g_pKeybindManager->m_bGroupsLocked ? "1" : "0"}); g_pEventManager->postEvent(SHyprIPCEvent{"lockgroups", g_pKeybindManager->m_bGroupsLocked ? "1" : "0"});
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
return {}; return {};
} }
@@ -2835,11 +2807,8 @@ SDispatchResult CKeybindManager::lockGroups(std::string args) {
SDispatchResult CKeybindManager::lockActiveGroup(std::string args) { SDispatchResult CKeybindManager::lockActiveGroup(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PWINDOW) if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock())
return {.success = false, .error = "No window found"}; return {};
if (!PWINDOW->m_sGroupData.pNextWindow.lock())
return {.success = false, .error = "Not a group"};
const auto PHEAD = PWINDOW->getGroupHead(); const auto PHEAD = PWINDOW->getGroupHead();
@@ -2960,7 +2929,7 @@ SDispatchResult CKeybindManager::moveOutOfGroup(std::string args) {
static auto PIGNOREGROUPLOCK = CConfigValue<Hyprlang::INT>("binds:ignore_group_lock"); static auto PIGNOREGROUPLOCK = CConfigValue<Hyprlang::INT>("binds:ignore_group_lock");
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked)
return {.success = false, .error = "Groups locked"}; return {};
PHLWINDOW PWINDOW = nullptr; PHLWINDOW PWINDOW = nullptr;
@@ -2969,11 +2938,8 @@ SDispatchResult CKeybindManager::moveOutOfGroup(std::string args) {
else else
PWINDOW = g_pCompositor->m_pLastWindow.lock(); PWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PWINDOW) if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock())
return {.success = false, .error = "No window found"}; return {};
if (!PWINDOW->m_sGroupData.pNextWindow.lock())
return {.success = false, .error = "Window not in a group"};
moveWindowOutOfGroup(PWINDOW); moveWindowOutOfGroup(PWINDOW);
@@ -2991,10 +2957,7 @@ SDispatchResult CKeybindManager::moveWindowOrGroup(std::string args) {
} }
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PWINDOW) if (!PWINDOW || PWINDOW->isFullscreen())
return {.success = false, .error = "No window found"};
if (PWINDOW->isFullscreen())
return {}; return {};
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) { if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) {
@@ -3004,7 +2967,7 @@ SDispatchResult CKeybindManager::moveWindowOrGroup(std::string args) {
const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg);
const bool ISWINDOWGROUP = PWINDOW->m_sGroupData.pNextWindow; const bool ISWINDOWGROUP = PWINDOW->m_sGroupData.pNextWindow.lock().get();
const bool ISWINDOWGROUPLOCKED = ISWINDOWGROUP && PWINDOW->getGroupHead()->m_sGroupData.locked; const bool ISWINDOWGROUPLOCKED = ISWINDOWGROUP && PWINDOW->getGroupHead()->m_sGroupData.locked;
const bool ISWINDOWGROUPSINGLE = ISWINDOWGROUP && PWINDOW->m_sGroupData.pNextWindow.lock() == PWINDOW; const bool ISWINDOWGROUPSINGLE = ISWINDOWGROUP && PWINDOW->m_sGroupData.pNextWindow.lock() == PWINDOW;
@@ -3083,11 +3046,8 @@ SDispatchResult CKeybindManager::moveGroupWindow(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PLASTWINDOW) if (!PLASTWINDOW || !PLASTWINDOW->m_sGroupData.pNextWindow.lock())
return {.success = false, .error = "No window found"}; return {};
if (!PLASTWINDOW->m_sGroupData.pNextWindow.lock())
return {.success = false, .error = "Window not in a group"};
if ((!BACK && PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head) || (BACK && PLASTWINDOW->m_sGroupData.head)) { if ((!BACK && PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head) || (BACK && PLASTWINDOW->m_sGroupData.head)) {
std::swap(PLASTWINDOW->m_sGroupData.head, PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head); std::swap(PLASTWINDOW->m_sGroupData.head, PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head);
@@ -3178,7 +3138,7 @@ SDispatchResult CKeybindManager::setProp(std::string args) {
PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
else else
PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
} else if (auto search = NWindowProperties::boolWindowProperties.find(PROP); search != NWindowProperties::boolWindowProperties.end()) { } else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) {
auto pWindowDataElement = search->second(PWINDOW); auto pWindowDataElement = search->second(PWINDOW);
if (VAL == "toggle") if (VAL == "toggle")
*pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP); *pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP);
@@ -3186,12 +3146,12 @@ SDispatchResult CKeybindManager::setProp(std::string args) {
pWindowDataElement->unset(PRIORITY_SET_PROP); pWindowDataElement->unset(PRIORITY_SET_PROP);
else else
*pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL).value_or(0), PRIORITY_SET_PROP); *pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL).value_or(0), PRIORITY_SET_PROP);
} else if (auto search = NWindowProperties::intWindowProperties.find(PROP); search != NWindowProperties::intWindowProperties.end()) { } else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) {
if (VAL == "unset") if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP); search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else if (const auto V = configStringToInt(VAL); V) else if (const auto V = configStringToInt(VAL); V)
*(search->second(PWINDOW)) = CWindowOverridableVar((int)*V, PRIORITY_SET_PROP); *(search->second(PWINDOW)) = CWindowOverridableVar((int)*V, PRIORITY_SET_PROP);
} else if (auto search = NWindowProperties::floatWindowProperties.find(PROP); search != NWindowProperties::floatWindowProperties.end()) { } else if (auto search = g_pConfigManager->mfWindowProperties.find(PROP); search != g_pConfigManager->mfWindowProperties.end()) {
if (VAL == "unset") if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP); search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else { else {

View File

@@ -148,7 +148,7 @@ class CKeybindManager {
static bool tryMoveFocusToMonitor(PHLMONITOR monitor); static bool tryMoveFocusToMonitor(PHLMONITOR monitor);
static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = ""); static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = "");
static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection); static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection);
static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveFocusHistory = false); static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO);
static uint64_t spawnRawProc(std::string, PHLWORKSPACE pInitialWorkspace); static uint64_t spawnRawProc(std::string, PHLWORKSPACE pInitialWorkspace);
static uint64_t spawnWithRules(std::string, PHLWORKSPACE pInitialWorkspace); static uint64_t spawnWithRules(std::string, PHLWORKSPACE pInitialWorkspace);
@@ -199,7 +199,6 @@ class CKeybindManager {
static SDispatchResult circleNext(std::string); static SDispatchResult circleNext(std::string);
static SDispatchResult focusWindow(std::string); static SDispatchResult focusWindow(std::string);
static SDispatchResult tagWindow(std::string); static SDispatchResult tagWindow(std::string);
static SDispatchResult toggleSwallow(std::string);
static SDispatchResult setSubmap(std::string); static SDispatchResult setSubmap(std::string);
static SDispatchResult pass(std::string); static SDispatchResult pass(std::string);
static SDispatchResult sendshortcut(std::string); static SDispatchResult sendshortcut(std::string);

View File

@@ -17,9 +17,6 @@
#include <cstring> #include <cstring>
#include <gbm.h> #include <gbm.h>
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::Utils;
CPointerManager::CPointerManager() { CPointerManager::CPointerManager() {
hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) {
@@ -274,7 +271,7 @@ void CPointerManager::updateCursorBackend() {
continue; continue;
} }
if (state->softwareLocks > 0 || g_pConfigManager->shouldUseSoftwareCursors(m) || !attemptHardwareCursor(state)) { if (state->softwareLocks > 0 || g_pConfigManager->shouldUseSoftwareCursors() || !attemptHardwareCursor(state)) {
Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName);
state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock());
state->hardwareFailed = true; state->hardwareFailed = true;
@@ -313,18 +310,11 @@ void CPointerManager::onCursorMoved() {
recalc = true; recalc = true;
} }
if (!state->entered) if (state->hardwareFailed || !state->entered)
continue;
CScopeGuard x([m] { m->onCursorMovedOnMonitor(); });
if (state->hardwareFailed)
continue; continue;
const auto CURSORPOS = getCursorPosForMonitor(m); const auto CURSORPOS = getCursorPosForMonitor(m);
m->output->moveCursor(CURSORPOS, m->shouldSkipScheduleFrameOnMouseEvent()); m->output->moveCursor(CURSORPOS, m->shouldSkipScheduleFrameOnMouseEvent());
state->monitor->scanoutNeedsCursorUpdate = true;
} }
if (recalc) if (recalc)
@@ -384,8 +374,6 @@ bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquam
if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent()) if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent())
g_pCompositor->scheduleFrameForMonitor(state->monitor.lock(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); g_pCompositor->scheduleFrameForMonitor(state->monitor.lock(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
state->monitor->scanoutNeedsCursorUpdate = true;
return true; return true;
} }
@@ -423,9 +411,7 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
} }
} }
auto backend = state->monitor->output->getBackend(); state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(allocator, state->monitor->output->getBackend());
auto primary = backend->getPrimary();
state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(allocator, primary ? primary.lock() : backend);
} }
auto options = state->monitor->cursorSwapchain->currentOptions(); auto options = state->monitor->cursorSwapchain->currentOptions();
@@ -489,7 +475,7 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
if (flipRB) { if (flipRB) {
for (size_t i = 0; i < shmBuffer.size(); i += 4) { for (size_t i = 0; i < shmBuffer.size(); i += 4) {
std::swap(shmBuffer[i], shmBuffer[i + 2]); // little-endian!!!!!! std::swap(shmBuffer.at(i), shmBuffer.at(i + 2)); // little-endian!!!!!!
} }
} }
} else { } else {
@@ -623,9 +609,13 @@ void CPointerManager::renderSoftwareCursorsFor(PHLMONITOR pMonitor, timespec* no
CTexPassElement::SRenderData data; CTexPassElement::SRenderData data;
data.tex = texture; data.tex = texture;
data.box = box.round(); data.box = box.round();
data.syncTimeline = currentCursorImage.waitTimeline;
data.syncPoint = currentCursorImage.waitPoint;
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data)); g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
currentCursorImage.waitTimeline.reset();
currentCursorImage.waitPoint = 0;
if (currentCursorImage.surface) if (currentCursorImage.surface)
currentCursorImage.surface->resource()->frame(now); currentCursorImage.surface->resource()->frame(now);
} }
@@ -739,8 +729,7 @@ void CPointerManager::damageIfSoftware() {
if (mw->monitor.expired() || !mw->monitor->output) if (mw->monitor.expired() || !mw->monitor->output)
continue; continue;
if ((mw->softwareLocks > 0 || mw->hardwareFailed || g_pConfigManager->shouldUseSoftwareCursors(mw->monitor.lock())) && if ((mw->softwareLocks > 0 || mw->hardwareFailed || g_pConfigManager->shouldUseSoftwareCursors()) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) {
b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) {
g_pHyprRenderer->damageBox(b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent()); g_pHyprRenderer->damageBox(b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent());
break; break;
} }

View File

@@ -148,6 +148,8 @@ class CPointerManager {
CHyprSignalListener destroySurface; CHyprSignalListener destroySurface;
CHyprSignalListener commitSurface; CHyprSignalListener commitSurface;
SP<CSyncTimeline> waitTimeline = nullptr;
uint64_t waitPoint = 0;
} currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors } currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors
Vector2D pointerPos = {0, 0}; Vector2D pointerPos = {0, 0};

View File

@@ -57,23 +57,15 @@
#include "../protocols/core/Output.hpp" #include "../protocols/core/Output.hpp"
#include "../protocols/core/Shm.hpp" #include "../protocols/core/Shm.hpp"
#include "../protocols/ColorManagement.hpp" #include "../protocols/ColorManagement.hpp"
#include "../protocols/XXColorManagement.hpp"
#include "../protocols/FrogColorManagement.hpp" #include "../protocols/FrogColorManagement.hpp"
#include "../protocols/ContentType.hpp"
#include "../helpers/Monitor.hpp" #include "../helpers/Monitor.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "content-type-v1.hpp"
#include <aquamarine/buffer/Buffer.hpp> #include <aquamarine/buffer/Buffer.hpp>
#include <aquamarine/backend/Backend.hpp> #include <aquamarine/backend/Backend.hpp>
// ********************************************************************************************
// * IMPORTANT: make sure to .reset() any protocol UP's you create! (put reset in destructor) *
// * otherwise Hyprland might crash when exiting. *
// ********************************************************************************************
void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) { void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) {
const bool ISMIRROR = pMonitor->isMirror(); const bool ISMIRROR = pMonitor->isMirror();
@@ -89,18 +81,14 @@ void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) {
PROTO::outputs.emplace(pMonitor->szName, makeShared<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock())); PROTO::outputs.emplace(pMonitor->szName, makeShared<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock()));
} }
if (PROTO::colorManagement && g_pCompositor->shouldChangePreferredImageDescription()) { if (PROTO::colorManagement && g_pCompositor->shouldChangePreferredImageDescription())
Debug::log(ERR, "FIXME: color management protocol is enabled, need a preferred image description id"); PROTO::colorManagement->onImagePreferredChanged();
PROTO::colorManagement->onImagePreferredChanged(0);
}
} }
CProtocolManager::CProtocolManager() { CProtocolManager::CProtocolManager() {
static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync"); static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync");
static const auto PENABLECM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
static const auto PENABLEXXCM = CConfigValue<Hyprlang::INT>("experimental:xx_color_management_v4"); static const auto PENABLEXXCM = CConfigValue<Hyprlang::INT>("experimental:xx_color_management_v4");
static const auto PDEBUGCM = CConfigValue<Hyprlang::INT>("debug:full_cm_proto");
// Outputs are a bit dumb, we have to agree. // Outputs are a bit dumb, we have to agree.
static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) {
@@ -157,7 +145,7 @@ CProtocolManager::CProtocolManager() {
PROTO::constraints = makeUnique<CPointerConstraintsProtocol>(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); PROTO::constraints = makeUnique<CPointerConstraintsProtocol>(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints");
PROTO::outputPower = makeUnique<COutputPowerProtocol>(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); PROTO::outputPower = makeUnique<COutputPowerProtocol>(&zwlr_output_power_manager_v1_interface, 1, "OutputPower");
PROTO::activation = makeUnique<CXDGActivationProtocol>(&xdg_activation_v1_interface, 1, "XDGActivation"); PROTO::activation = makeUnique<CXDGActivationProtocol>(&xdg_activation_v1_interface, 1, "XDGActivation");
PROTO::idle = makeUnique<CIdleNotifyProtocol>(&ext_idle_notifier_v1_interface, 2, "IdleNotify"); PROTO::idle = makeUnique<CIdleNotifyProtocol>(&ext_idle_notifier_v1_interface, 1, "IdleNotify");
PROTO::lockNotify = makeUnique<CLockNotifyProtocol>(&hyprland_lock_notifier_v1_interface, 1, "IdleNotify"); PROTO::lockNotify = makeUnique<CLockNotifyProtocol>(&hyprland_lock_notifier_v1_interface, 1, "IdleNotify");
PROTO::sessionLock = makeUnique<CSessionLockProtocol>(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); PROTO::sessionLock = makeUnique<CSessionLockProtocol>(&ext_session_lock_manager_v1_interface, 1, "SessionLock");
PROTO::ime = makeUnique<CInputMethodV2Protocol>(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); PROTO::ime = makeUnique<CInputMethodV2Protocol>(&zwp_input_method_manager_v2_interface, 1, "IMEv2");
@@ -176,23 +164,17 @@ CProtocolManager::CProtocolManager() {
PROTO::screencopy = makeUnique<CScreencopyProtocol>(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); PROTO::screencopy = makeUnique<CScreencopyProtocol>(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy");
PROTO::toplevelExport = makeUnique<CToplevelExportProtocol>(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::toplevelExport = makeUnique<CToplevelExportProtocol>(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport");
PROTO::globalShortcuts = makeUnique<CGlobalShortcutsProtocol>(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); PROTO::globalShortcuts = makeUnique<CGlobalShortcutsProtocol>(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts");
PROTO::xdgDialog = makeUnique<CXDGDialogProtocol>(&xdg_wm_dialog_v1_interface, 1, "XDGDialog"); PROTO::xdgDialog = makeUnique<CXDGDialogProtocol>(&xdg_dialog_v1_interface, 1, "XDGDialog");
PROTO::singlePixel = makeUnique<CSinglePixelProtocol>(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); PROTO::singlePixel = makeUnique<CSinglePixelProtocol>(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel");
PROTO::securityContext = makeUnique<CSecurityContextProtocol>(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); PROTO::securityContext = makeUnique<CSecurityContextProtocol>(&wp_security_context_manager_v1_interface, 1, "SecurityContext");
PROTO::ctm = makeUnique<CHyprlandCTMControlProtocol>(&hyprland_ctm_control_manager_v1_interface, 2, "CTMControl"); PROTO::ctm = makeUnique<CHyprlandCTMControlProtocol>(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl");
PROTO::hyprlandSurface = makeUnique<CHyprlandSurfaceProtocol>(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface"); PROTO::hyprlandSurface = makeUnique<CHyprlandSurfaceProtocol>(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface");
PROTO::contentType = makeUnique<CContentTypeProtocol>(&wp_content_type_manager_v1_interface, 1, "ContentType");
if (*PENABLECM) if (*PENABLEXXCM) {
PROTO::colorManagement = makeUnique<CColorManagementProtocol>(&wp_color_manager_v1_interface, 1, "ColorManagement", *PDEBUGCM); PROTO::colorManagement = makeUnique<CColorManagementProtocol>(&xx_color_manager_v4_interface, 1, "ColorManagement");
if (*PENABLEXXCM && *PENABLECM) {
PROTO::xxColorManagement = makeUnique<CXXColorManagementProtocol>(&xx_color_manager_v4_interface, 1, "XXColorManagement");
PROTO::frogColorManagement = makeUnique<CFrogColorManagementProtocol>(&frog_color_management_factory_v1_interface, 1, "FrogColorManagement"); PROTO::frogColorManagement = makeUnique<CFrogColorManagementProtocol>(&frog_color_management_factory_v1_interface, 1, "FrogColorManagement");
} }
// ! please read the top of this file before adding another protocol
for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) {
if (b->type() != Aquamarine::AQ_BACKEND_DRM) if (b->type() != Aquamarine::AQ_BACKEND_DRM)
continue; continue;
@@ -267,10 +249,6 @@ CProtocolManager::~CProtocolManager() {
PROTO::securityContext.reset(); PROTO::securityContext.reset();
PROTO::ctm.reset(); PROTO::ctm.reset();
PROTO::hyprlandSurface.reset(); PROTO::hyprlandSurface.reset();
PROTO::contentType.reset();
PROTO::colorManagement.reset();
PROTO::xxColorManagement.reset();
PROTO::frogColorManagement.reset();
PROTO::lease.reset(); PROTO::lease.reset();
PROTO::sync.reset(); PROTO::sync.reset();

View File

@@ -606,11 +606,11 @@ void CSeatManager::setGrab(SP<CSeatGrab> grab) {
if (!refocus) { if (!refocus) {
surf = CWLSurface::fromResource(currentFocus); surf = CWLSurface::fromResource(currentFocus);
layer = surf ? surf->getLayer() : nullptr; layer = surf->getLayer();
} }
if (!refocus && !layer) { if (!refocus && !layer) {
auto popup = surf ? surf->getPopup() : nullptr; auto popup = surf->getPopup();
if (popup) { if (popup) {
auto parent = popup->getT1Owner(); auto parent = popup->getT1Owner();
layer = parent->getLayer(); layer = parent->getLayer();

View File

@@ -89,13 +89,6 @@ void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) {
g_pCompositor->focusSurface(nullptr); g_pCompositor->focusSurface(nullptr);
g_pSeatManager->setGrab(nullptr); g_pSeatManager->setGrab(nullptr);
// Normally the locked event is sent after each output rendered a lock screen frame.
// When there are no outputs, send it right away.
if (g_pCompositor->m_bUnsafeState) {
m_pSessionLock->lock->sendLocked();
m_pSessionLock->m_hasSentLocked = true;
}
} }
bool CSessionLockManager::isSessionLocked() { bool CSessionLockManager::isSessionLocked() {
@@ -138,7 +131,8 @@ void CSessionLockManager::onLockscreenRenderedOnMonitor(uint64_t id) {
if (!m_pSessionLock || m_pSessionLock->m_hasSentLocked) if (!m_pSessionLock || m_pSessionLock->m_hasSentLocked)
return; return;
m_pSessionLock->m_lockedMonitors.emplace(id); m_pSessionLock->m_lockedMonitors.emplace(id);
const bool LOCKED = std::ranges::all_of(g_pCompositor->m_vMonitors, [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); }); const auto MONITORS = g_pCompositor->m_vMonitors;
const bool LOCKED = std::all_of(MONITORS.begin(), MONITORS.end(), [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); });
if (LOCKED && m_pSessionLock->lock->good()) { if (LOCKED && m_pSessionLock->lock->good()) {
m_pSessionLock->lock->sendLocked(); m_pSessionLock->lock->sendLocked();
m_pSessionLock->m_hasSentLocked = true; m_pSessionLock->m_hasSentLocked = true;

View File

@@ -156,6 +156,8 @@ void CXCursorManager::loadTheme(std::string const& name, int size, float scale)
cursors.emplace_back(cursor); cursors.emplace_back(cursor);
} }
static auto SYNCGSETTINGS = CConfigValue<Hyprlang::INT>("cursor:sync_gsettings_theme");
if (*SYNCGSETTINGS)
syncGsettings(); syncGsettings();
} }
@@ -480,7 +482,7 @@ std::vector<SP<SXCursors>> CXCursorManager::loadStandardCursors(std::string cons
// load the default xcursor shapes that exist in the theme // load the default xcursor shapes that exist in the theme
for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) { for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) {
std::string shape{XCURSOR_STANDARD_NAMES[i]}; std::string shape{XCURSOR_STANDARD_NAMES.at(i)};
auto xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), size); auto xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), size);
if (!xImages) { if (!xImages) {
@@ -558,10 +560,6 @@ std::vector<SP<SXCursors>> CXCursorManager::loadAllFromDir(std::string const& pa
} }
void CXCursorManager::syncGsettings() { void CXCursorManager::syncGsettings() {
static auto SYNCGSETTINGS = CConfigValue<Hyprlang::INT>("cursor:sync_gsettings_theme");
if (!*SYNCGSETTINGS)
return;
auto checkParamExists = [](std::string const& paramName, std::string const& category) { auto checkParamExists = [](std::string const& paramName, std::string const& category) {
auto* gSettingsSchemaSource = g_settings_schema_source_get_default(); auto* gSettingsSchemaSource = g_settings_schema_source_get_default();

View File

@@ -13,8 +13,8 @@ extern "C" {
// gangsta bootleg XCursor impl. adidas balkanized // gangsta bootleg XCursor impl. adidas balkanized
struct SXCursorImage { struct SXCursorImage {
Hyprutils::Math::Vector2D size; Vector2D size;
Hyprutils::Math::Vector2D hotspot; Vector2D hotspot;
std::vector<uint32_t> pixels; // XPixel is a u32 std::vector<uint32_t> pixels; // XPixel is a u32
uint32_t delay; // animation delay to next frame (ms) uint32_t delay; // animation delay to next frame (ms)
}; };

View File

@@ -55,7 +55,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) {
if (pWindow->m_bIsX11) { if (pWindow->m_bIsX11) {
if (activate) { if (activate) {
pWindow->sendWindowSize(true); // update xwayland output pos pWindow->sendWindowSize(pWindow->m_vRealSize->value(), true); // update xwayland output pos
pWindow->m_pXWaylandSurface->setMinimized(false); pWindow->m_pXWaylandSurface->setMinimized(false);
if (!pWindow->isX11OverrideRedirect()) if (!pWindow->isX11OverrideRedirect())

View File

@@ -11,12 +11,11 @@
#include <ctime> #include <ctime>
#include <aquamarine/backend/Backend.hpp> #include <aquamarine/backend/Backend.hpp>
using namespace Hyprutils::OS;
#define TIMESPEC_NSEC_PER_SEC 1000000000L #define TIMESPEC_NSEC_PER_SEC 1000000000L
CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) { CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) {
m_sTimers.timerfd = CFileDescriptor{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC)}; m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
m_sWayland.loop = wlEventLoop; m_sWayland.loop = wlEventLoop;
m_sWayland.display = display; m_sWayland.display = display;
} }
@@ -32,6 +31,8 @@ CEventLoopManager::~CEventLoopManager() {
wl_event_source_remove(m_sIdle.eventSource); wl_event_source_remove(m_sIdle.eventSource);
if (m_configWatcherInotifySource) if (m_configWatcherInotifySource)
wl_event_source_remove(m_configWatcherInotifySource); wl_event_source_remove(m_configWatcherInotifySource);
if (m_sTimers.timerfd >= 0)
close(m_sTimers.timerfd);
} }
static int timerWrite(int fd, uint32_t mask, void* data) { static int timerWrite(int fd, uint32_t mask, void* data) {
@@ -51,10 +52,10 @@ static int configWatcherWrite(int fd, uint32_t mask, void* data) {
} }
void CEventLoopManager::enterLoop() { void CEventLoopManager::enterLoop() {
m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd.get(), WL_EVENT_READABLE, timerWrite, nullptr); m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr);
if (const auto& FD = g_pConfigWatcher->getInotifyFD(); FD.isValid()) if (const auto FD = g_pConfigWatcher->getInotifyFD(); FD >= 0)
m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD.get(), WL_EVENT_READABLE, configWatcherWrite, nullptr); m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD, WL_EVENT_READABLE, configWatcherWrite, nullptr);
syncPollFDs(); syncPollFDs();
m_sListeners.pollFDsChanged = g_pCompositor->m_pAqBackend->events.pollFDsChanged.registerListener([this](std::any d) { syncPollFDs(); }); m_sListeners.pollFDsChanged = g_pCompositor->m_pAqBackend->events.pollFDsChanged.registerListener([this](std::any d) { syncPollFDs(); });
@@ -119,7 +120,7 @@ void CEventLoopManager::nudgeTimers() {
itimerspec ts = {.it_value = now}; itimerspec ts = {.it_value = now};
timerfd_settime(m_sTimers.timerfd.get(), TFD_TIMER_ABSTIME, &ts, nullptr); timerfd_settime(m_sTimers.timerfd, TFD_TIMER_ABSTIME, &ts, nullptr);
} }
void CEventLoopManager::doLater(const std::function<void()>& fn) { void CEventLoopManager::doLater(const std::function<void()>& fn) {

View File

@@ -6,7 +6,6 @@
#include <thread> #include <thread>
#include <wayland-server.h> #include <wayland-server.h>
#include "helpers/signal/Signal.hpp" #include "helpers/signal/Signal.hpp"
#include <hyprutils/os/FileDescriptor.hpp>
#include "EventLoopTimer.hpp" #include "EventLoopTimer.hpp"
@@ -55,7 +54,7 @@ class CEventLoopManager {
struct { struct {
std::vector<SP<CEventLoopTimer>> timers; std::vector<SP<CEventLoopTimer>> timers;
Hyprutils::OS::CFileDescriptor timerfd; int timerfd = -1;
} m_sTimers; } m_sTimers;
SIdleData m_sIdle; SIdleData m_sIdle;

View File

@@ -90,30 +90,14 @@ CInputManager::~CInputManager() {
void CInputManager::onMouseMoved(IPointer::SMotionEvent e) { void CInputManager::onMouseMoved(IPointer::SMotionEvent e) {
static auto PNOACCEL = CConfigValue<Hyprlang::INT>("input:force_no_accel"); static auto PNOACCEL = CConfigValue<Hyprlang::INT>("input:force_no_accel");
Vector2D delta = e.delta; const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta;
Vector2D unaccel = e.unaccel;
if (e.device) {
if (e.device->isTouchpad) {
if (e.device->flipX) {
delta.x = -delta.x;
unaccel.x = -unaccel.x;
}
if (e.device->flipY) {
delta.y = -delta.y;
unaccel.y = -unaccel.y;
}
}
}
const auto DELTA = *PNOACCEL == 1 ? unaccel : delta;
if (g_pSeatManager->isPointerFrameSkipped) if (g_pSeatManager->isPointerFrameSkipped)
g_pPointerManager->storeMovement((uint64_t)e.timeMs, DELTA, unaccel); g_pPointerManager->storeMovement((uint64_t)e.timeMs, DELTA, e.unaccel);
else else
g_pPointerManager->setStoredMovement((uint64_t)e.timeMs, DELTA, unaccel); g_pPointerManager->setStoredMovement((uint64_t)e.timeMs, DELTA, e.unaccel);
PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, unaccel); PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel);
if (e.mouse) if (e.mouse)
recheckMouseWarpOnMouseInput(); recheckMouseWarpOnMouseInput();
@@ -178,7 +162,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) {
return; return;
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse"); static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
static auto PFOLLOWMOUSETHRESHOLD = CConfigValue<Hyprlang::FLOAT>("input:follow_mouse_threshold");
static auto PMOUSEREFOCUS = CConfigValue<Hyprlang::INT>("input:mouse_refocus"); static auto PMOUSEREFOCUS = CConfigValue<Hyprlang::INT>("input:mouse_refocus");
static auto PFOLLOWONDND = CConfigValue<Hyprlang::INT>("misc:always_follow_on_dnd"); static auto PFOLLOWONDND = CConfigValue<Hyprlang::INT>("misc:always_follow_on_dnd");
static auto PFLOATBEHAVIOR = CConfigValue<Hyprlang::INT>("input:float_switch_override_focus"); static auto PFLOATBEHAVIOR = CConfigValue<Hyprlang::INT>("input:float_switch_override_focus");
@@ -189,11 +172,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) {
const auto FOLLOWMOUSE = *PFOLLOWONDND && PROTO::data->dndActive() ? 1 : *PFOLLOWMOUSE; const auto FOLLOWMOUSE = *PFOLLOWONDND && PROTO::data->dndActive() ? 1 : *PFOLLOWMOUSE;
if (FOLLOWMOUSE == 1 && m_tmrLastCursorMovement.getSeconds() < 0.5)
m_fMousePosDelta += MOUSECOORDSFLOORED.distance(m_vLastCursorPosFloored);
else
m_fMousePosDelta = 0;
m_pFoundSurfaceToFocus.reset(); m_pFoundSurfaceToFocus.reset();
m_pFoundLSToFocus.reset(); m_pFoundLSToFocus.reset();
m_pFoundWindowToFocus.reset(); m_pFoundWindowToFocus.reset();
@@ -293,10 +271,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) {
const auto BOX = HLSurface->getSurfaceBoxGlobal(); const auto BOX = HLSurface->getSurfaceBoxGlobal();
if (BOX) { if (BOX) {
const auto PWINDOW = HLSurface->getWindow();
surfacePos = BOX->pos(); surfacePos = BOX->pos();
pFoundLayerSurface = HLSurface->getLayer(); pFoundLayerSurface = HLSurface->getLayer();
pFoundWindow = !PWINDOW || PWINDOW->isHidden() ? g_pCompositor->m_pLastWindow.lock() : PWINDOW; pFoundWindow = HLSurface->getWindow();
} else // reset foundSurface, find one normally } else // reset foundSurface, find one normally
foundSurface = nullptr; foundSurface = nullptr;
} else // reset foundSurface, find one normally } else // reset foundSurface, find one normally
@@ -536,10 +513,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) {
// TODO: this looks wrong. When over a popup, it constantly is switching. // TODO: this looks wrong. When over a popup, it constantly is switching.
// Temp fix until that's figured out. Otherwise spams windowrule lookups and other shit. // Temp fix until that's figured out. Otherwise spams windowrule lookups and other shit.
if (m_pLastMouseFocus.lock() != pFoundWindow || g_pCompositor->m_pLastWindow.lock() != pFoundWindow) { if (m_pLastMouseFocus.lock() != pFoundWindow || g_pCompositor->m_pLastWindow.lock() != pFoundWindow)
if (m_fMousePosDelta > *PFOLLOWMOUSETHRESHOLD || refocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface); g_pCompositor->focusWindow(pFoundWindow, foundSurface);
} else else
g_pCompositor->focusSurface(foundSurface, pFoundWindow); g_pCompositor->focusSurface(foundSurface, pFoundWindow);
} }
} }
@@ -1197,9 +1173,6 @@ void CInputManager::setPointerConfigs() {
const auto LIBINPUTSENS = std::clamp(g_pConfigManager->getDeviceFloat(devname, "sensitivity", "input:sensitivity"), -1.f, 1.f); const auto LIBINPUTSENS = std::clamp(g_pConfigManager->getDeviceFloat(devname, "sensitivity", "input:sensitivity"), -1.f, 1.f);
libinput_device_config_accel_set_speed(LIBINPUTDEV, LIBINPUTSENS); libinput_device_config_accel_set_speed(LIBINPUTDEV, LIBINPUTSENS);
m->flipX = g_pConfigManager->getDeviceInt(devname, "flip_x", "input:touchpad:flip_x") != 0;
m->flipY = g_pConfigManager->getDeviceInt(devname, "flip_y", "input:touchpad:flip_y") != 0;
const auto ACCELPROFILE = g_pConfigManager->getDeviceString(devname, "accel_profile", "input:accel_profile"); const auto ACCELPROFILE = g_pConfigManager->getDeviceString(devname, "accel_profile", "input:accel_profile");
const auto SCROLLPOINTS = g_pConfigManager->getDeviceString(devname, "scroll_points", "input:scroll_points"); const auto SCROLLPOINTS = g_pConfigManager->getDeviceString(devname, "scroll_points", "input:scroll_points");
@@ -1579,13 +1552,10 @@ void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
if (libinput_device_config_send_events_get_mode(LIBINPUTDEV) != mode) if (libinput_device_config_send_events_get_mode(LIBINPUTDEV) != mode)
libinput_device_config_send_events_set_mode(LIBINPUTDEV, mode); libinput_device_config_send_events_set_mode(LIBINPUTDEV, mode);
if (libinput_device_config_calibration_has_matrix(LIBINPUTDEV)) { const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->hlName, "transform", "input:touchdevice:transform"), 0, 7);
Debug::log(LOG, "Setting calibration matrix for device {}", PTOUCHDEV->hlName); Debug::log(LOG, "Setting calibration matrix for device {}", PTOUCHDEV->hlName);
// default value of transform being -1 means it's unset. if (libinput_device_config_calibration_has_matrix(LIBINPUTDEV))
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->hlName, "transform", "input:touchdevice:transform"), -1, 7);
if (ROTATION > -1)
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]); libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
}
auto output = g_pConfigManager->getDeviceString(PTOUCHDEV->hlName, "output", "input:touchdevice:output"); auto output = g_pConfigManager->getDeviceString(PTOUCHDEV->hlName, "output", "input:touchdevice:output");
bool bound = !output.empty() && output != STRVAL_EMPTY; bool bound = !output.empty() && output != STRVAL_EMPTY;
@@ -1627,9 +1597,8 @@ void CInputManager::setTabletConfigs() {
const auto RELINPUT = g_pConfigManager->getDeviceInt(NAME, "relative_input", "input:tablet:relative_input"); const auto RELINPUT = g_pConfigManager->getDeviceInt(NAME, "relative_input", "input:tablet:relative_input");
t->relativeInput = RELINPUT; t->relativeInput = RELINPUT;
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(NAME, "transform", "input:tablet:transform"), -1, 7); const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(NAME, "transform", "input:tablet:transform"), 0, 7);
Debug::log(LOG, "Setting calibration matrix for device {}", NAME); Debug::log(LOG, "Setting calibration matrix for device {}", NAME);
if (ROTATION > -1)
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]); libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
if (g_pConfigManager->getDeviceInt(NAME, "left_handed", "input:tablet:left_handed") == 0) if (g_pConfigManager->getDeviceInt(NAME, "left_handed", "input:tablet:left_handed") == 0)
@@ -1731,11 +1700,8 @@ void CInputManager::releaseAllMouseButtons() {
if (PROTO::data->dndActive()) if (PROTO::data->dndActive())
return; return;
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
for (auto const& mb : buttonsCopy) { for (auto const& mb : buttonsCopy) {
g_pSeatManager->sendPointerButton(now.tv_sec * 1000 + now.tv_nsec / 1000000, mb, WL_POINTER_BUTTON_STATE_RELEASED); g_pSeatManager->sendPointerButton(0, mb, WL_POINTER_BUTTON_STATE_RELEASED);
} }
m_lCurrentlyHeldButtons.clear(); m_lCurrentlyHeldButtons.clear();

View File

@@ -255,7 +255,6 @@ class CInputManager {
// used for warping back after non-mouse input // used for warping back after non-mouse input
Vector2D m_vLastMousePos = {}; Vector2D m_vLastMousePos = {};
double m_fMousePosDelta = 0;
bool m_bLastInputMouse = true; bool m_bLastInputMouse = true;
// for holding focus on buttons held // for holding focus on buttons held

View File

@@ -88,20 +88,6 @@ static void refocusTablet(SP<CTablet> tab, SP<CTabletTool> tool, bool motion = f
PROTO::tablet->motion(tool, local); PROTO::tablet->motion(tool, local);
} }
static Vector2D transformToActiveRegion(const Vector2D pos, const CBox activeArea) {
auto newPos = pos;
//Calculate transformations if active area is set
if (!activeArea.empty()) {
if (!std::isnan(pos.x))
newPos.x = (pos.x - activeArea.x) / (activeArea.w - activeArea.x);
if (!std::isnan(pos.y))
newPos.y = (pos.y - activeArea.y) / (activeArea.h - activeArea.y);
}
return newPos;
}
void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { void CInputManager::onTabletAxis(CTablet::SAxisEvent e) {
const auto PTAB = e.tablet; const auto PTAB = e.tablet;
const auto PTOOL = ensureTabletToolPresent(e.tool); const auto PTOOL = ensureTabletToolPresent(e.tool);
@@ -127,9 +113,16 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) {
if (PTAB->relativeInput) if (PTAB->relativeInput)
g_pPointerManager->move(delta); g_pPointerManager->move(delta);
else else {
g_pPointerManager->warpAbsolute(transformToActiveRegion({x, y}, PTAB->activeArea), PTAB); //Calculate transformations if active area is set
if (!PTAB->activeArea.empty()) {
if (!std::isnan(x))
x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x);
if (!std::isnan(y))
y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y);
}
g_pPointerManager->warpAbsolute({x, y}, PTAB);
}
break; break;
} }
} }
@@ -167,12 +160,7 @@ void CInputManager::onTabletTip(CTablet::STipEvent e) {
const auto PTAB = e.tablet; const auto PTAB = e.tablet;
const auto PTOOL = ensureTabletToolPresent(e.tool); const auto PTOOL = ensureTabletToolPresent(e.tool);
const auto POS = e.tip; const auto POS = e.tip;
g_pPointerManager->warpAbsolute(POS, PTAB);
if (PTAB->relativeInput)
g_pPointerManager->move({0, 0});
else
g_pPointerManager->warpAbsolute(transformToActiveRegion(POS, PTAB->activeArea), PTAB);
refocusTablet(PTAB, PTOOL, true); refocusTablet(PTAB, PTOOL, true);
if (e.in) if (e.in)

View File

@@ -41,7 +41,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) {
if (m_sActiveSwipe.pWorkspaceBegin) { if (m_sActiveSwipe.pWorkspaceBegin) {
return; return;
// TODO: Don't swipe if you touched a floating window. // TODO: Don't swipe if you touched a floating window.
} else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus->layer <= 1) && !g_pSessionLockManager->isSessionLocked()) { } else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus->layer <= 1)) {
const auto PWORKSPACE = PMONITOR->activeWorkspace; const auto PWORKSPACE = PMONITOR->activeWorkspace;
const auto STYLE = PWORKSPACE->m_vRenderOffset->getStyle(); const auto STYLE = PWORKSPACE->m_vRenderOffset->getStyle();
const bool VERTANIMS = STYLE == "slidevert" || STYLE.starts_with("slidefadevert"); const bool VERTANIMS = STYLE == "slidevert" || STYLE.starts_with("slidefadevert");

View File

@@ -59,13 +59,6 @@ struct SVersionInfo {
#define OPTIONAL #define OPTIONAL
#define HANDLE void* #define HANDLE void*
// C ABI is needed to prevent symbol mangling, but we don't actually need C compatibility,
// so we ignore this warning about return types that are potentially incompatible with C.
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif
class IHyprLayout; class IHyprLayout;
class CWindow; class CWindow;
class IHyprWindowDecoration; class IHyprWindowDecoration;
@@ -322,7 +315,3 @@ APICALL inline EXPORT const char* __hyprland_api_get_client_hash() {
return GIT_COMMIT_HASH; return GIT_COMMIT_HASH;
} }
// NOLINTEND // NOLINTEND
#ifdef __clang__
#pragma clang diagnostic pop
#endif

View File

@@ -15,9 +15,6 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP<CHyprlandCtmControlM
resource->setSetCtmForOutput([this](CHyprlandCtmControlManagerV1* r, wl_resource* output, wl_fixed_t mat0, wl_fixed_t mat1, wl_fixed_t mat2, wl_fixed_t mat3, wl_fixed_t mat4, resource->setSetCtmForOutput([this](CHyprlandCtmControlManagerV1* r, wl_resource* output, wl_fixed_t mat0, wl_fixed_t mat1, wl_fixed_t mat2, wl_fixed_t mat3, wl_fixed_t mat4,
wl_fixed_t mat5, wl_fixed_t mat6, wl_fixed_t mat7, wl_fixed_t mat8) { wl_fixed_t mat5, wl_fixed_t mat6, wl_fixed_t mat7, wl_fixed_t mat8) {
if (blocked)
return;
const auto OUTPUTRESOURCE = CWLOutputResource::fromResource(output); const auto OUTPUTRESOURCE = CWLOutputResource::fromResource(output);
if UNLIKELY (!OUTPUTRESOURCE) if UNLIKELY (!OUTPUTRESOURCE)
@@ -44,9 +41,6 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP<CHyprlandCtmControlM
}); });
resource->setCommit([this](CHyprlandCtmControlManagerV1* r) { resource->setCommit([this](CHyprlandCtmControlManagerV1* r) {
if (blocked)
return;
LOGM(LOG, "Committing ctms to outputs"); LOGM(LOG, "Committing ctms to outputs");
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
@@ -60,17 +54,7 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP<CHyprlandCtmControlM
}); });
} }
void CHyprlandCTMControlResource::block() {
blocked = true;
if (resource->version() >= 2)
resource->sendBlocked();
}
CHyprlandCTMControlResource::~CHyprlandCTMControlResource() { CHyprlandCTMControlResource::~CHyprlandCTMControlResource() {
if (blocked)
return;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
PROTO::ctm->setCTM(m, Mat3x3::identity()); PROTO::ctm->setCTM(m, Mat3x3::identity());
} }
@@ -85,6 +69,7 @@ CHyprlandCTMControlProtocol::CHyprlandCTMControlProtocol(const wl_interface* ifa
} }
void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CHyprlandCTMControlResource>(makeShared<CHyprlandCtmControlManagerV1>(client, ver, id))); const auto RESOURCE = m_vManagers.emplace_back(makeShared<CHyprlandCTMControlResource>(makeShared<CHyprlandCtmControlManagerV1>(client, ver, id)));
if UNLIKELY (!RESOURCE->good()) { if UNLIKELY (!RESOURCE->good()) {
@@ -93,11 +78,6 @@ void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uin
return; return;
} }
if (m_pManager)
RESOURCE->block();
else
m_pManager = RESOURCE;
LOGM(LOG, "New CTM Manager at 0x{:x}", (uintptr_t)RESOURCE.get()); LOGM(LOG, "New CTM Manager at 0x{:x}", (uintptr_t)RESOURCE.get());
} }

View File

@@ -16,13 +16,11 @@ class CHyprlandCTMControlResource {
~CHyprlandCTMControlResource(); ~CHyprlandCTMControlResource();
bool good(); bool good();
void block();
private: private:
SP<CHyprlandCtmControlManagerV1> resource; SP<CHyprlandCtmControlManagerV1> resource;
std::unordered_map<std::string, Mat3x3> ctms; std::unordered_map<std::string, Mat3x3> ctms;
bool blocked = false;
}; };
class CHyprlandCTMControlProtocol : public IWaylandProtocol { class CHyprlandCTMControlProtocol : public IWaylandProtocol {
@@ -39,7 +37,6 @@ class CHyprlandCTMControlProtocol : public IWaylandProtocol {
// //
std::vector<SP<CHyprlandCTMControlResource>> m_vManagers; std::vector<SP<CHyprlandCTMControlResource>> m_vManagers;
WP<CHyprlandCTMControlResource> m_pManager;
// //
struct SCTMData { struct SCTMData {

View File

@@ -1,90 +1,42 @@
#include "ColorManagement.hpp" #include "ColorManagement.hpp"
#include "Compositor.hpp" #include "Compositor.hpp"
#include "color-management-v1.hpp"
#include "../helpers/Monitor.hpp"
#include "core/Output.hpp"
#include "types/ColorManagement.hpp"
#include <cstdint>
using namespace NColorManagement; CColorManager::CColorManager(SP<CXxColorManagerV4> resource_) : resource(resource_) {
static uint64_t lastImageID = 0; // FIXME use for deduplication
CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resource) {
if UNLIKELY (!good()) if UNLIKELY (!good())
return; return;
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC); resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_PARAMETRIC);
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_PRIMARIES); resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_EXTENDED_TARGET_VOLUME);
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES); resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES);
resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_PRIMARIES);
resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_LUMINANCES);
if (PROTO::colorManagement->m_debug) { resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_SRGB);
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_ICC_V2_V4); // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M);
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_TF_POWER); // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL);
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES); // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_NTSC);
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_EXTENDED_TARGET_VOLUME); // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM);
m_resource->sendSupportedFeature(WP_COLOR_MANAGER_V1_FEATURE_WINDOWS_SCRGB); resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_BT2020);
} // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ);
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3);
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3);
// resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_SRGB); // resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_BT2020); resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_PAL_M); resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_PAL); // resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_NTSC);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_GENERIC_FILM);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_DCI_P3);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_DISPLAY_P3);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB);
if (PROTO::colorManagement->m_debug) { resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL);
m_resource->sendSupportedPrimariesNamed(WP_COLOR_MANAGER_V1_PRIMARIES_CIE1931_XYZ); // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE);
} // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_ABSOLUTE);
// resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE_BPC);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB); resource->setDestroy([](CXxColorManagerV4* r) { LOGM(TRACE, "Destroy xx_color_manager at {:x} (generated default)", (uintptr_t)r); });
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22); resource->setGetOutput([](CXxColorManagerV4* r, uint32_t id, wl_resource* output) {
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG);
if (PROTO::colorManagement->m_debug) {
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST240);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_100);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_316);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_XVYCC);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB);
m_resource->sendSupportedTfNamed(WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST428);
}
m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL);
if (PROTO::colorManagement->m_debug) {
m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE);
m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION);
m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE);
m_resource->sendSupportedIntent(WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE_BPC);
}
m_resource->setDestroy([](CWpColorManagerV1* r) { LOGM(TRACE, "Destroy WP_color_manager at {:x} (generated default)", (uintptr_t)r); });
m_resource->setGetOutput([](CWpColorManagerV1* r, uint32_t id, wl_resource* output) {
LOGM(TRACE, "Get output for id={}, output={}", id, (uintptr_t)output); LOGM(TRACE, "Get output for id={}, output={}", id, (uintptr_t)output);
const auto OUTPUTRESOURCE = CWLOutputResource::fromResource(output);
if UNLIKELY (!OUTPUTRESOURCE) {
r->error(-1, "Invalid output (2)");
return;
}
const auto PMONITOR = OUTPUTRESOURCE->monitor.lock();
if UNLIKELY (!PMONITOR) {
r->error(-1, "Invalid output (2)");
return;
}
const auto RESOURCE = const auto RESOURCE =
PROTO::colorManagement->m_vOutputs.emplace_back(makeShared<CColorManagementOutput>(makeShared<CWpColorManagementOutputV1>(r->client(), r->version(), id), PMONITOR)); PROTO::colorManagement->m_vOutputs.emplace_back(makeShared<CColorManagementOutput>(makeShared<CXxColorManagementOutputV4>(r->client(), r->version(), id)));
if UNLIKELY (!RESOURCE->good()) { if UNLIKELY (!RESOURCE->good()) {
r->noMemory(); r->noMemory();
@@ -94,7 +46,7 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
RESOURCE->self = RESOURCE; RESOURCE->self = RESOURCE;
}); });
m_resource->setGetSurface([](CWpColorManagerV1* r, uint32_t id, wl_resource* surface) { resource->setGetSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) {
LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface); LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface);
auto SURF = CWLSurfaceResource::fromResource(surface); auto SURF = CWLSurfaceResource::fromResource(surface);
@@ -105,12 +57,12 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
} }
if (SURF->colorManagement) { if (SURF->colorManagement) {
r->error(WP_COLOR_MANAGER_V1_ERROR_SURFACE_EXISTS, "CM Surface already exists"); r->error(XX_COLOR_MANAGER_V4_ERROR_SURFACE_EXISTS, "CM Surface already exists");
return; return;
} }
const auto RESOURCE = const auto RESOURCE =
PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared<CColorManagementSurface>(makeShared<CWpColorManagementSurfaceV1>(r->client(), r->version(), id), SURF)); PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared<CColorManagementSurface>(makeShared<CXxColorManagementSurfaceV4>(r->client(), r->version(), id), SURF));
if UNLIKELY (!RESOURCE->good()) { if UNLIKELY (!RESOURCE->good()) {
r->noMemory(); r->noMemory();
PROTO::colorManagement->m_vSurfaces.pop_back(); PROTO::colorManagement->m_vSurfaces.pop_back();
@@ -121,7 +73,7 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
SURF->colorManagement = RESOURCE; SURF->colorManagement = RESOURCE;
}); });
m_resource->setGetSurfaceFeedback([](CWpColorManagerV1* r, uint32_t id, wl_resource* surface) { resource->setGetFeedbackSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) {
LOGM(TRACE, "Get feedback surface for id={}, surface={}", id, (uintptr_t)surface); LOGM(TRACE, "Get feedback surface for id={}, surface={}", id, (uintptr_t)surface);
auto SURF = CWLSurfaceResource::fromResource(surface); auto SURF = CWLSurfaceResource::fromResource(surface);
@@ -132,7 +84,7 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
} }
const auto RESOURCE = PROTO::colorManagement->m_vFeedbackSurfaces.emplace_back( const auto RESOURCE = PROTO::colorManagement->m_vFeedbackSurfaces.emplace_back(
makeShared<CColorManagementFeedbackSurface>(makeShared<CWpColorManagementSurfaceFeedbackV1>(r->client(), r->version(), id), SURF)); makeShared<CColorManagementFeedbackSurface>(makeShared<CXxColorManagementFeedbackSurfaceV4>(r->client(), r->version(), id), SURF));
if UNLIKELY (!RESOURCE->good()) { if UNLIKELY (!RESOURCE->good()) {
r->noMemory(); r->noMemory();
@@ -142,29 +94,15 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
RESOURCE->self = RESOURCE; RESOURCE->self = RESOURCE;
}); });
m_resource->setCreateIccCreator([](CWpColorManagerV1* r, uint32_t id) { resource->setNewIccCreator([](CXxColorManagerV4* r, uint32_t id) {
LOGM(WARN, "New ICC creator for id={} (unsupported)", id); LOGM(WARN, "New ICC creator for id={} (unsupported)", id);
if (!PROTO::colorManagement->m_debug) { r->error(XX_COLOR_MANAGER_V4_ERROR_UNSUPPORTED_FEATURE, "ICC profiles are not supported");
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "ICC profiles are not supported");
return;
}
const auto RESOURCE =
PROTO::colorManagement->m_vIccCreators.emplace_back(makeShared<CColorManagementIccCreator>(makeShared<CWpImageDescriptionCreatorIccV1>(r->client(), r->version(), id)));
if UNLIKELY (!RESOURCE->good()) {
r->noMemory();
PROTO::colorManagement->m_vIccCreators.pop_back();
return;
}
RESOURCE->self = RESOURCE;
}); });
m_resource->setCreateParametricCreator([](CWpColorManagerV1* r, uint32_t id) { resource->setNewParametricCreator([](CXxColorManagerV4* r, uint32_t id) {
LOGM(TRACE, "New parametric creator for id={}", id); LOGM(TRACE, "New parametric creator for id={}", id);
const auto RESOURCE = PROTO::colorManagement->m_vParametricCreators.emplace_back( const auto RESOURCE = PROTO::colorManagement->m_vParametricCreators.emplace_back(
makeShared<CColorManagementParametricCreator>(makeShared<CWpImageDescriptionCreatorParamsV1>(r->client(), r->version(), id))); makeShared<CColorManagementParametricCreator>(makeShared<CXxImageDescriptionCreatorParamsV4>(r->client(), r->version(), id)));
if UNLIKELY (!RESOURCE->good()) { if UNLIKELY (!RESOURCE->good()) {
r->noMemory(); r->noMemory();
@@ -174,59 +112,30 @@ CColorManager::CColorManager(SP<CWpColorManagerV1> resource) : m_resource(resour
RESOURCE->self = RESOURCE; RESOURCE->self = RESOURCE;
}); });
m_resource->setCreateWindowsScrgb([](CWpColorManagerV1* r, uint32_t id) {
LOGM(WARN, "New Windows scRGB description id={} (unsupported)", id);
if (!PROTO::colorManagement->m_debug) {
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "Windows scRGB profiles are not supported");
return;
}
const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( resource->setOnDestroy([this](CXxColorManagerV4* r) { PROTO::colorManagement->destroyResource(this); });
makeShared<CColorManagementImageDescription>(makeShared<CWpImageDescriptionV1>(r->client(), r->version(), id), false));
if UNLIKELY (!RESOURCE->good()) {
r->noMemory();
PROTO::colorManagement->m_vImageDescriptions.pop_back();
return;
}
RESOURCE->self = RESOURCE;
RESOURCE->settings.id = ++lastImageID;
RESOURCE->settings.windowsScRGB = true;
RESOURCE->settings.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB;
RESOURCE->settings.primariesNameSet = true;
RESOURCE->settings.primaries = NColorPrimaries::BT709;
RESOURCE->settings.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_EXT_LINEAR;
RESOURCE->settings.luminances.reference = 203;
RESOURCE->resource()->sendReady(RESOURCE->settings.id);
});
m_resource->setOnDestroy([this](CWpColorManagerV1* r) { PROTO::colorManagement->destroyResource(this); });
m_resource->sendDone();
} }
bool CColorManager::good() { bool CColorManager::good() {
return m_resource->resource(); return resource->resource();
} }
CColorManagementOutput::CColorManagementOutput(SP<CWpColorManagementOutputV1> resource, WP<CMonitor> monitor) : m_resource(resource), m_monitor(monitor) { CColorManagementOutput::CColorManagementOutput(SP<CXxColorManagementOutputV4> resource_) : resource(resource_) {
if UNLIKELY (!good()) if UNLIKELY (!good())
return; return;
pClient = m_resource->client(); pClient = resource->client();
m_resource->setDestroy([this](CWpColorManagementOutputV1* r) { PROTO::colorManagement->destroyResource(this); }); resource->setDestroy([this](CXxColorManagementOutputV4* r) { PROTO::colorManagement->destroyResource(this); });
m_resource->setOnDestroy([this](CWpColorManagementOutputV1* r) { PROTO::colorManagement->destroyResource(this); }); resource->setOnDestroy([this](CXxColorManagementOutputV4* r) { PROTO::colorManagement->destroyResource(this); });
m_resource->setGetImageDescription([this](CWpColorManagementOutputV1* r, uint32_t id) { resource->setGetImageDescription([this](CXxColorManagementOutputV4* r, uint32_t id) {
LOGM(TRACE, "Get image description for output={}, id={}", (uintptr_t)r, id); LOGM(TRACE, "Get image description for output={}, id={}", (uintptr_t)r, id);
if (imageDescription.valid()) if (imageDescription.valid())
PROTO::colorManagement->destroyResource(imageDescription.get()); PROTO::colorManagement->destroyResource(imageDescription.get());
const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back(
makeShared<CColorManagementImageDescription>(makeShared<CWpImageDescriptionV1>(r->client(), r->version(), id), true)); makeShared<CColorManagementImageDescription>(makeShared<CXxImageDescriptionV4>(r->client(), r->version(), id)));
if UNLIKELY (!RESOURCE->good()) { if UNLIKELY (!RESOURCE->good()) {
r->noMemory(); r->noMemory();
@@ -235,19 +144,11 @@ CColorManagementOutput::CColorManagementOutput(SP<CWpColorManagementOutputV1> re
} }
RESOURCE->self = RESOURCE; RESOURCE->self = RESOURCE;
if (!m_monitor.valid())
RESOURCE->m_resource->sendFailed(WP_IMAGE_DESCRIPTION_V1_CAUSE_NO_OUTPUT, "No output");
else {
RESOURCE->settings = m_monitor->imageDescription;
if (RESOURCE->settings.id)
RESOURCE->settings.id = ++lastImageID;
RESOURCE->m_resource->sendReady(RESOURCE->settings.id); // FIXME: create correct id
}
}); });
} }
bool CColorManagementOutput::good() { bool CColorManagementOutput::good() {
return m_resource->resource(); return resource->resource();
} }
wl_client* CColorManagementOutput::client() { wl_client* CColorManagementOutput::client() {
@@ -258,45 +159,45 @@ CColorManagementSurface::CColorManagementSurface(SP<CWLSurfaceResource> surface_
// only for frog cm untill wayland cm is adopted // only for frog cm untill wayland cm is adopted
} }
CColorManagementSurface::CColorManagementSurface(SP<CWpColorManagementSurfaceV1> resource, SP<CWLSurfaceResource> surface_) : surface(surface_), m_resource(resource) { CColorManagementSurface::CColorManagementSurface(SP<CXxColorManagementSurfaceV4> resource_, SP<CWLSurfaceResource> surface_) : surface(surface_), resource(resource_) {
if UNLIKELY (!good()) if UNLIKELY (!good())
return; return;
pClient = m_resource->client(); pClient = resource->client();
m_resource->setDestroy([this](CWpColorManagementSurfaceV1* r) { resource->setDestroy([this](CXxColorManagementSurfaceV4* r) {
LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface); LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface);
PROTO::colorManagement->destroyResource(this); PROTO::colorManagement->destroyResource(this);
}); });
m_resource->setOnDestroy([this](CWpColorManagementSurfaceV1* r) { resource->setOnDestroy([this](CXxColorManagementSurfaceV4* r) {
LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface); LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface);
PROTO::colorManagement->destroyResource(this); PROTO::colorManagement->destroyResource(this);
}); });
m_resource->setSetImageDescription([this](CWpColorManagementSurfaceV1* r, wl_resource* image_description, uint32_t render_intent) { resource->setSetImageDescription([this](CXxColorManagementSurfaceV4* r, wl_resource* image_description, uint32_t render_intent) {
LOGM(TRACE, "Set image description for surface={}, desc={}, intent={}", (uintptr_t)r, (uintptr_t)image_description, render_intent); LOGM(TRACE, "Set image description for surface={}, desc={}, intent={}", (uintptr_t)r, (uintptr_t)image_description, render_intent);
const auto PO = (CWpImageDescriptionV1*)wl_resource_get_user_data(image_description); const auto PO = (CXxImageDescriptionV4*)wl_resource_get_user_data(image_description);
if (!PO) { // FIXME check validity if (!PO) { // FIXME check validity
r->error(WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_IMAGE_DESCRIPTION, "Image description creation failed"); r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION, "Image description creation failed");
return; return;
} }
if (render_intent != WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL) { if (render_intent != XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL) {
r->error(WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_RENDER_INTENT, "Unsupported render intent"); r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_RENDER_INTENT, "Unsupported render intent");
return; return;
} }
const auto imageDescription = std::find_if(PROTO::colorManagement->m_vImageDescriptions.begin(), PROTO::colorManagement->m_vImageDescriptions.end(), const auto imageDescription = std::find_if(PROTO::colorManagement->m_vImageDescriptions.begin(), PROTO::colorManagement->m_vImageDescriptions.end(),
[&](const auto& other) { return other->resource()->resource() == image_description; }); [&](const auto& other) { return other->resource()->resource() == image_description; });
if (imageDescription == PROTO::colorManagement->m_vImageDescriptions.end()) { if (imageDescription == PROTO::colorManagement->m_vImageDescriptions.end()) {
r->error(WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_IMAGE_DESCRIPTION, "Image description not found"); r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION, "Image description not found");
return; return;
} }
setHasImageDescription(true); setHasImageDescription(true);
m_imageDescription = imageDescription->get()->settings; m_imageDescription = imageDescription->get()->settings;
}); });
m_resource->setUnsetImageDescription([this](CWpColorManagementSurfaceV1* r) { resource->setUnsetImageDescription([this](CXxColorManagementSurfaceV4* r) {
LOGM(TRACE, "Unset image description for surface={}", (uintptr_t)r); LOGM(TRACE, "Unset image description for surface={}", (uintptr_t)r);
m_imageDescription = SImageDescription{}; m_imageDescription = SImageDescription{};
setHasImageDescription(false); setHasImageDescription(false);
@@ -304,7 +205,7 @@ CColorManagementSurface::CColorManagementSurface(SP<CWpColorManagementSurfaceV1>
} }
bool CColorManagementSurface::good() { bool CColorManagementSurface::good() {
return m_resource && m_resource->resource(); return resource && resource->resource();
} }
wl_client* CColorManagementSurface::client() { wl_client* CColorManagementSurface::client() {
@@ -339,34 +240,34 @@ bool CColorManagementSurface::needsHdrMetadataUpdate() {
return m_needsNewMetadata; return m_needsNewMetadata;
} }
CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP<CWpColorManagementSurfaceFeedbackV1> resource, SP<CWLSurfaceResource> surface_) : CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP<CXxColorManagementFeedbackSurfaceV4> resource_, SP<CWLSurfaceResource> surface_) :
surface(surface_), m_resource(resource) { surface(surface_), resource(resource_) {
if UNLIKELY (!good()) if UNLIKELY (!good())
return; return;
pClient = m_resource->client(); pClient = resource->client();
m_resource->setDestroy([this](CWpColorManagementSurfaceFeedbackV1* r) { resource->setDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) {
LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface);
if (m_currentPreferred.valid()) if (m_currentPreferred.valid())
PROTO::colorManagement->destroyResource(m_currentPreferred.get()); PROTO::colorManagement->destroyResource(m_currentPreferred.get());
PROTO::colorManagement->destroyResource(this); PROTO::colorManagement->destroyResource(this);
}); });
m_resource->setOnDestroy([this](CWpColorManagementSurfaceFeedbackV1* r) { resource->setOnDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) {
LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface);
if (m_currentPreferred.valid()) if (m_currentPreferred.valid())
PROTO::colorManagement->destroyResource(m_currentPreferred.get()); PROTO::colorManagement->destroyResource(m_currentPreferred.get());
PROTO::colorManagement->destroyResource(this); PROTO::colorManagement->destroyResource(this);
}); });
m_resource->setGetPreferred([this](CWpColorManagementSurfaceFeedbackV1* r, uint32_t id) { resource->setGetPreferred([this](CXxColorManagementFeedbackSurfaceV4* r, uint32_t id) {
LOGM(TRACE, "Get preferred for id {}", id); LOGM(TRACE, "Get preferred for id {}", id);
if (m_currentPreferred.valid()) if (m_currentPreferred.valid())
PROTO::colorManagement->destroyResource(m_currentPreferred.get()); PROTO::colorManagement->destroyResource(m_currentPreferred.get());
const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back(
makeShared<CColorManagementImageDescription>(makeShared<CWpImageDescriptionV1>(r->client(), r->version(), id), true)); makeShared<CColorManagementImageDescription>(makeShared<CXxImageDescriptionV4>(r->client(), r->version(), id), true));
if UNLIKELY (!RESOURCE->good()) { if UNLIKELY (!RESOURCE->good()) {
r->noMemory(); r->noMemory();
@@ -378,130 +279,44 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP<CWpColorMana
m_currentPreferred = RESOURCE; m_currentPreferred = RESOURCE;
m_currentPreferred->settings = g_pCompositor->getPreferredImageDescription(); m_currentPreferred->settings = g_pCompositor->getPreferredImageDescription();
if (!m_currentPreferred->settings.id)
m_currentPreferred->settings.id = ++lastImageID;
RESOURCE->resource()->sendReady(++lastImageID); // FIXME: create correct id RESOURCE->resource()->sendReady(id);
});
m_resource->setGetPreferredParametric([this](CWpColorManagementSurfaceFeedbackV1* r, uint32_t id) {
LOGM(TRACE, "Get preferred for id {}", id);
if (!PROTO::colorManagement->m_debug) {
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "Parametric descriptions are not supported");
return;
}
if (m_currentPreferred.valid())
PROTO::colorManagement->destroyResource(m_currentPreferred.get());
const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back(
makeShared<CColorManagementImageDescription>(makeShared<CWpImageDescriptionV1>(r->client(), r->version(), id), true));
if UNLIKELY (!RESOURCE->good()) {
r->noMemory();
PROTO::colorManagement->m_vImageDescriptions.pop_back();
return;
}
RESOURCE->self = RESOURCE;
m_currentPreferred = RESOURCE;
m_currentPreferred->settings = g_pCompositor->getPreferredImageDescription();
if (!PROTO::colorManagement->m_debug && m_currentPreferred->settings.icc.fd) {
LOGM(ERR, "FIXME: parse icc profile");
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "ICC profiles are not supported");
return;
}
RESOURCE->resource()->sendReady(++lastImageID); // FIXME: create correct id
}); });
} }
bool CColorManagementFeedbackSurface::good() { bool CColorManagementFeedbackSurface::good() {
return m_resource->resource(); return resource->resource();
} }
wl_client* CColorManagementFeedbackSurface::client() { wl_client* CColorManagementFeedbackSurface::client() {
return pClient; return pClient;
} }
CColorManagementIccCreator::CColorManagementIccCreator(SP<CWpImageDescriptionCreatorIccV1> resource) : m_resource(resource) { CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CXxImageDescriptionCreatorParamsV4> resource_) : resource(resource_) {
if UNLIKELY (!good()) if UNLIKELY (!good())
return; return;
// //
pClient = m_resource->client(); pClient = resource->client();
m_resource->setOnDestroy([this](CWpImageDescriptionCreatorIccV1* r) { PROTO::colorManagement->destroyResource(this); }); resource->setOnDestroy([this](CXxImageDescriptionCreatorParamsV4* r) { PROTO::colorManagement->destroyResource(this); });
m_resource->setCreate([this](CWpImageDescriptionCreatorIccV1* r, uint32_t id) { resource->setCreate([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t id) {
LOGM(TRACE, "Create image description from icc for id {}", id);
// FIXME actually check completeness
if (settings.icc.fd < 0 || !settings.icc.length) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INCOMPLETE_SET, "Missing required settings");
return;
}
const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back(
makeShared<CColorManagementImageDescription>(makeShared<CWpImageDescriptionV1>(r->client(), r->version(), id), false));
if UNLIKELY (!RESOURCE->good()) {
r->noMemory();
PROTO::colorManagement->m_vImageDescriptions.pop_back();
return;
}
LOGM(ERR, "FIXME: Parse icc file {}({},{}) for id {}", settings.icc.fd, settings.icc.offset, settings.icc.length, id);
// FIXME actually check support
if (settings.icc.fd < 0 || !settings.icc.length) {
RESOURCE->resource()->sendFailed(WP_IMAGE_DESCRIPTION_V1_CAUSE_UNSUPPORTED, "unsupported");
return;
}
RESOURCE->self = RESOURCE;
RESOURCE->settings = settings;
settings.id = ++lastImageID;
RESOURCE->resource()->sendReady(settings.id); // FIXME: create correct id
PROTO::colorManagement->destroyResource(this);
});
m_resource->setSetIccFile([this](CWpImageDescriptionCreatorIccV1* r, int fd, uint32_t offset, uint32_t length) {
settings.icc.fd = fd;
settings.icc.offset = offset;
settings.icc.length = length;
});
}
bool CColorManagementIccCreator::good() {
return m_resource->resource();
}
wl_client* CColorManagementIccCreator::client() {
return pClient;
}
CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CWpImageDescriptionCreatorParamsV1> resource) : m_resource(resource) {
if UNLIKELY (!good())
return;
//
pClient = m_resource->client();
m_resource->setOnDestroy([this](CWpImageDescriptionCreatorParamsV1* r) { PROTO::colorManagement->destroyResource(this); });
m_resource->setCreate([this](CWpImageDescriptionCreatorParamsV1* r, uint32_t id) {
LOGM(TRACE, "Create image description from params for id {}", id); LOGM(TRACE, "Create image description from params for id {}", id);
// FIXME actually check completeness // FIXME actually check completeness
if (!valuesSet) { if (!valuesSet) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INCOMPLETE_SET, "Missing required settings"); r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCOMPLETE_SET, "Missing required settings");
return;
}
// FIXME actually check consistency
if (!valuesSet) {
r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCONSISTENT_SET, "Set is not consistent");
return; return;
} }
const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back(
makeShared<CColorManagementImageDescription>(makeShared<CWpImageDescriptionV1>(r->client(), r->version(), id), false)); makeShared<CColorManagementImageDescription>(makeShared<CXxImageDescriptionV4>(r->client(), r->version(), id)));
if UNLIKELY (!RESOURCE->good()) { if UNLIKELY (!RESOURCE->good()) {
r->noMemory(); r->noMemory();
@@ -511,168 +326,128 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CWpImage
// FIXME actually check support // FIXME actually check support
if (!valuesSet) { if (!valuesSet) {
RESOURCE->resource()->sendFailed(WP_IMAGE_DESCRIPTION_V1_CAUSE_UNSUPPORTED, "unsupported"); RESOURCE->resource()->sendFailed(XX_IMAGE_DESCRIPTION_V4_CAUSE_UNSUPPORTED, "unsupported");
return; return;
} }
RESOURCE->self = RESOURCE; RESOURCE->self = RESOURCE;
RESOURCE->settings = settings; RESOURCE->settings = settings;
settings.id = ++lastImageID; RESOURCE->resource()->sendReady(id);
RESOURCE->resource()->sendReady(settings.id); // FIXME: create correct id
PROTO::colorManagement->destroyResource(this); PROTO::colorManagement->destroyResource(this);
}); });
m_resource->setSetTfNamed([this](CWpImageDescriptionCreatorParamsV1* r, uint32_t tf) { resource->setSetTfNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t tf) {
LOGM(TRACE, "Set image description transfer function to {}", tf); LOGM(TRACE, "Set image description transfer function to {}", tf);
if (valuesSet & PC_TF) { if (valuesSet & PC_TF) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET, "Transfer function already set"); r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function already set");
return; return;
} }
switch (tf) { switch (tf) {
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB: break; case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB: break;
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ: break; case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ: break;
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR: break; default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF, "Unsupported transfer function"); return;
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22: break;
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28: break;
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG: break;
default: r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_TF, "Unsupported transfer function"); return;
} }
settings.transferFunction = convertTransferFunction((wpColorManagerV1TransferFunction)tf); settings.transferFunction = (xxColorManagerV4TransferFunction)tf;
valuesSet |= PC_TF; valuesSet |= PC_TF;
}); });
m_resource->setSetTfPower([this](CWpImageDescriptionCreatorParamsV1* r, uint32_t eexp) { resource->setSetTfPower([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t eexp) {
LOGM(TRACE, "Set image description tf power to {}", eexp); LOGM(TRACE, "Set image description tf power to {}", eexp);
if (valuesSet & PC_TF_POWER) { if (valuesSet & PC_TF_POWER) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET, "Transfer function power already set"); r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function power already set");
return;
}
if (!PROTO::colorManagement->m_debug) {
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "TF power is not supported");
return; return;
} }
settings.transferFunctionPower = eexp / 10000.0f; settings.transferFunctionPower = eexp / 10000.0f;
if (settings.transferFunctionPower < 1.0 || settings.transferFunctionPower > 10.0) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_TF, "Power should be between 1.0 and 10.0");
return;
}
valuesSet |= PC_TF_POWER; valuesSet |= PC_TF_POWER;
}); });
m_resource->setSetPrimariesNamed([this](CWpImageDescriptionCreatorParamsV1* r, uint32_t primaries) { resource->setSetPrimariesNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t primaries) {
LOGM(TRACE, "Set image description primaries by name {}", primaries); LOGM(TRACE, "Set image description primaries by name {}", primaries);
if (valuesSet & PC_PRIMARIES) { if (valuesSet & PC_PRIMARIES) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET, "Primaries already set"); r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set");
return; return;
} }
switch (primaries) { switch (primaries) {
case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB: case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB:
case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
case WP_COLOR_MANAGER_V1_PRIMARIES_PAL_M:
case WP_COLOR_MANAGER_V1_PRIMARIES_PAL:
case WP_COLOR_MANAGER_V1_PRIMARIES_NTSC:
case WP_COLOR_MANAGER_V1_PRIMARIES_GENERIC_FILM:
case WP_COLOR_MANAGER_V1_PRIMARIES_DCI_P3:
case WP_COLOR_MANAGER_V1_PRIMARIES_DISPLAY_P3:
case WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB: break;
default:
if (!PROTO::colorManagement->m_debug) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_PRIMARIES_NAMED, "Unsupported primaries");
return;
}
}
settings.primariesNameSet = true; settings.primariesNameSet = true;
settings.primariesNamed = convertPrimaries((wpColorManagerV1Primaries)primaries); settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB;
settings.primaries = getPrimaries(settings.primariesNamed); settings.primaries = NColorPrimaries::BT709;
valuesSet |= PC_PRIMARIES; valuesSet |= PC_PRIMARIES;
break;
case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020:
settings.primariesNameSet = true;
settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_BT2020;
settings.primaries = NColorPrimaries::BT2020;
valuesSet |= PC_PRIMARIES;
break;
default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, "Unsupported primaries");
}
}); });
m_resource->setSetPrimaries( resource->setSetPrimaries(
[this](CWpImageDescriptionCreatorParamsV1* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) { [this](CXxImageDescriptionCreatorParamsV4* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) {
LOGM(TRACE, "Set image description primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); LOGM(TRACE, "Set image description primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y);
if (valuesSet & PC_PRIMARIES) { if (valuesSet & PC_PRIMARIES) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET, "Primaries already set"); r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set");
return;
}
if (!PROTO::colorManagement->m_debug) {
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "Custom primaries aren't supported");
return; return;
} }
settings.primariesNameSet = false; settings.primariesNameSet = false;
settings.primaries = SPCPRimaries{.red = {.x = r_x / 1000000.0f, .y = r_y / 1000000.0f}, settings.primaries =
.green = {.x = g_x / 1000000.0f, .y = g_y / 1000000.0f}, SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}};
.blue = {.x = b_x / 1000000.0f, .y = b_y / 1000000.0f},
.white = {.x = w_x / 1000000.0f, .y = w_y / 1000000.0f}};
valuesSet |= PC_PRIMARIES; valuesSet |= PC_PRIMARIES;
}); });
m_resource->setSetLuminances([this](CWpImageDescriptionCreatorParamsV1* r, uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum) { resource->setSetLuminances([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum) {
auto min = min_lum / 10000.0f; auto min = min_lum / 10000.0f;
LOGM(TRACE, "Set image description luminances to {} - {} ({})", min, max_lum, reference_lum); LOGM(TRACE, "Set image description luminances to {} - {} ({})", min, max_lum, reference_lum);
if (valuesSet & PC_LUMINANCES) { if (valuesSet & PC_LUMINANCES) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET, "Luminances already set"); r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Luminances already set");
return; return;
} }
if (max_lum < reference_lum || reference_lum <= min) { if (max_lum < reference_lum || reference_lum <= min) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_LUMINANCE, "Invalid luminances"); r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances");
return; return;
} }
settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum}; settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum};
valuesSet |= PC_LUMINANCES; valuesSet |= PC_LUMINANCES;
}); });
m_resource->setSetMasteringDisplayPrimaries( resource->setSetMasteringDisplayPrimaries(
[this](CWpImageDescriptionCreatorParamsV1* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) { [this](CXxImageDescriptionCreatorParamsV4* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) {
LOGM(TRACE, "Set image description mastering primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); LOGM(TRACE, "Set image description mastering primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y);
if (valuesSet & PC_MASTERING_PRIMARIES) { // if (valuesSet & PC_MASTERING_PRIMARIES) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET, "Mastering primaries already set"); // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering primaries already set");
return; // return;
} // }
if (!PROTO::colorManagement->m_debug) { settings.masteringPrimaries =
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "Mastering primaries are not supported"); SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}};
return;
}
settings.masteringPrimaries = SPCPRimaries{.red = {.x = r_x / 1000000.0f, .y = r_y / 1000000.0f},
.green = {.x = g_x / 1000000.0f, .y = g_y / 1000000.0f},
.blue = {.x = b_x / 1000000.0f, .y = b_y / 1000000.0f},
.white = {.x = w_x / 1000000.0f, .y = w_y / 1000000.0f}};
valuesSet |= PC_MASTERING_PRIMARIES; valuesSet |= PC_MASTERING_PRIMARIES;
// FIXME:
// If a compositor additionally supports target color volume exceeding the primary color volume, it must advertise wp_color_manager_v1.feature.extended_target_volume.
// If a client uses target color volume exceeding the primary color volume and the compositor does not support it, the result is implementation defined.
// Compositors are recommended to detect this case and fail the image description gracefully, but it may as well result in color artifacts.
}); });
m_resource->setSetMasteringLuminance([this](CWpImageDescriptionCreatorParamsV1* r, uint32_t min_lum, uint32_t max_lum) { resource->setSetMasteringLuminance([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum) {
auto min = min_lum / 10000.0f; auto min = min_lum / 10000.0f;
LOGM(TRACE, "Set image description mastering luminances to {} - {}", min, max_lum); LOGM(TRACE, "Set image description mastering luminances to {} - {}", min, max_lum);
// if (valuesSet & PC_MASTERING_LUMINANCES) { // if (valuesSet & PC_MASTERING_LUMINANCES) {
// r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET, "Mastering luminances already set"); // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering luminances already set");
// return; // return;
// } // }
if (min > 0 && max_lum > 0 && max_lum <= min) { if (min > 0 && max_lum > 0 && max_lum <= min) {
r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_LUMINANCE, "Invalid luminances"); r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances");
return;
}
if (!PROTO::colorManagement->m_debug) {
r->error(WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE, "Mastering luminances are not supported");
return; return;
} }
settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min, .max = max_lum}; settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min, .max = max_lum};
valuesSet |= PC_MASTERING_LUMINANCES; valuesSet |= PC_MASTERING_LUMINANCES;
}); });
m_resource->setSetMaxCll([this](CWpImageDescriptionCreatorParamsV1* r, uint32_t max_cll) { resource->setSetMaxCll([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_cll) {
LOGM(TRACE, "Set image description max content light level to {}", max_cll); LOGM(TRACE, "Set image description max content light level to {}", max_cll);
// if (valuesSet & PC_CLL) { // if (valuesSet & PC_CLL) {
// r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET, "Max CLL already set"); // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max CLL already set");
// return; // return;
// } // }
settings.maxCLL = max_cll; settings.maxCLL = max_cll;
valuesSet |= PC_CLL; valuesSet |= PC_CLL;
}); });
m_resource->setSetMaxFall([this](CWpImageDescriptionCreatorParamsV1* r, uint32_t max_fall) { resource->setSetMaxFall([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_fall) {
LOGM(TRACE, "Set image description max frame-average light level to {}", max_fall); LOGM(TRACE, "Set image description max frame-average light level to {}", max_fall);
// if (valuesSet & PC_FALL) { // if (valuesSet & PC_FALL) {
// r->error(WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET, "Max FALL already set"); // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max FALL already set");
// return; // return;
// } // }
settings.maxFALL = max_fall; settings.maxFALL = max_fall;
@@ -681,31 +456,31 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SP<CWpImage
} }
bool CColorManagementParametricCreator::good() { bool CColorManagementParametricCreator::good() {
return m_resource->resource(); return resource->resource();
} }
wl_client* CColorManagementParametricCreator::client() { wl_client* CColorManagementParametricCreator::client() {
return pClient; return pClient;
} }
CColorManagementImageDescription::CColorManagementImageDescription(SP<CWpImageDescriptionV1> resource, bool allowGetInformation) : CColorManagementImageDescription::CColorManagementImageDescription(SP<CXxImageDescriptionV4> resource_, bool allowGetInformation) :
m_resource(resource), m_allowGetInformation(allowGetInformation) { m_resource(resource_), m_allowGetInformation(allowGetInformation) {
if UNLIKELY (!good()) if UNLIKELY (!good())
return; return;
pClient = m_resource->client(); pClient = m_resource->client();
m_resource->setDestroy([this](CWpImageDescriptionV1* r) { PROTO::colorManagement->destroyResource(this); }); m_resource->setDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); });
m_resource->setOnDestroy([this](CWpImageDescriptionV1* r) { PROTO::colorManagement->destroyResource(this); }); m_resource->setOnDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); });
m_resource->setGetInformation([this](CWpImageDescriptionV1* r, uint32_t id) { m_resource->setGetInformation([this](CXxImageDescriptionV4* r, uint32_t id) {
LOGM(TRACE, "Get image information for image={}, id={}", (uintptr_t)r, id); LOGM(TRACE, "Get image information for image={}, id={}", (uintptr_t)r, id);
if (!m_allowGetInformation) { if (!m_allowGetInformation) {
r->error(WP_IMAGE_DESCRIPTION_V1_ERROR_NO_INFORMATION, "Image descriptions doesn't allow get_information request"); r->error(XX_IMAGE_DESCRIPTION_V4_ERROR_NO_INFORMATION, "Image descriptions doesn't allow get_information request");
return; return;
} }
auto RESOURCE = makeShared<CColorManagementImageDescriptionInfo>(makeShared<CWpImageDescriptionInfoV1>(r->client(), r->version(), id), settings); auto RESOURCE = makeShared<CColorManagementImageDescriptionInfo>(makeShared<CXxImageDescriptionInfoV4>(r->client(), r->version(), id), settings);
if UNLIKELY (!RESOURCE->good()) if UNLIKELY (!RESOURCE->good())
r->noMemory(); r->noMemory();
@@ -723,12 +498,12 @@ wl_client* CColorManagementImageDescription::client() {
return pClient; return pClient;
} }
SP<CWpImageDescriptionV1> CColorManagementImageDescription::resource() { SP<CXxImageDescriptionV4> CColorManagementImageDescription::resource() {
return m_resource; return m_resource;
} }
CColorManagementImageDescriptionInfo::CColorManagementImageDescriptionInfo(SP<CWpImageDescriptionInfoV1> resource, const SImageDescription& settings_) : CColorManagementImageDescriptionInfo::CColorManagementImageDescriptionInfo(SP<CXxImageDescriptionInfoV4> resource_, const SImageDescription& settings_) :
m_resource(resource), settings(settings_) { m_resource(resource_), settings(settings_) {
if UNLIKELY (!good()) if UNLIKELY (!good())
return; return;
@@ -736,8 +511,8 @@ CColorManagementImageDescriptionInfo::CColorManagementImageDescriptionInfo(SP<CW
const auto toProto = [](float value) { return int32_t(std::round(value * 10000)); }; const auto toProto = [](float value) { return int32_t(std::round(value * 10000)); };
if (settings.icc.fd >= 0) if (settings.iccFd >= 0)
m_resource->sendIccFile(settings.icc.fd, settings.icc.length); m_resource->sendIccFile(settings.iccFd, settings.iccSize);
// send preferred client paramateres // send preferred client paramateres
m_resource->sendPrimaries(toProto(settings.primaries.red.x), toProto(settings.primaries.red.y), toProto(settings.primaries.green.x), toProto(settings.primaries.green.y), m_resource->sendPrimaries(toProto(settings.primaries.red.x), toProto(settings.primaries.red.y), toProto(settings.primaries.green.x), toProto(settings.primaries.green.y),
@@ -767,13 +542,12 @@ wl_client* CColorManagementImageDescriptionInfo::client() {
return pClient; return pClient;
} }
CColorManagementProtocol::CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name, bool debug) : CColorManagementProtocol::CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
IWaylandProtocol(iface, ver, name), m_debug(debug) {
; ;
} }
void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CColorManager>(makeShared<CWpColorManagerV1>(client, ver, id))); const auto RESOURCE = m_vManagers.emplace_back(makeShared<CColorManager>(makeShared<CXxColorManagerV4>(client, ver, id)));
if UNLIKELY (!RESOURCE->good()) { if UNLIKELY (!RESOURCE->good()) {
wl_client_post_no_memory(client); wl_client_post_no_memory(client);
@@ -781,19 +555,12 @@ void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32
return; return;
} }
LOGM(TRACE, "New WP_color_manager at {:x}", (uintptr_t)RESOURCE.get()); LOGM(TRACE, "New xx_color_manager at {:x}", (uintptr_t)RESOURCE.get());
} }
void CColorManagementProtocol::onImagePreferredChanged(uint32_t preferredId) { void CColorManagementProtocol::onImagePreferredChanged() {
for (auto const& feedback : m_vFeedbackSurfaces) { for (auto const& feedback : m_vFeedbackSurfaces) {
feedback->m_resource->sendPreferredChanged(preferredId); feedback->resource->sendPreferredChanged();
}
}
void CColorManagementProtocol::onMonitorImageDescriptionChanged(WP<CMonitor> monitor) {
for (auto const& output : m_vOutputs) {
if (output->m_monitor == monitor)
output->m_resource->sendImageDescriptionChanged();
} }
} }
@@ -813,10 +580,6 @@ void CColorManagementProtocol::destroyResource(CColorManagementFeedbackSurface*
std::erase_if(m_vFeedbackSurfaces, [&](const auto& other) { return other.get() == resource; }); std::erase_if(m_vFeedbackSurfaces, [&](const auto& other) { return other.get() == resource; });
} }
void CColorManagementProtocol::destroyResource(CColorManagementIccCreator* resource) {
std::erase_if(m_vIccCreators, [&](const auto& other) { return other.get() == resource; });
}
void CColorManagementProtocol::destroyResource(CColorManagementParametricCreator* resource) { void CColorManagementProtocol::destroyResource(CColorManagementParametricCreator* resource) {
std::erase_if(m_vParametricCreators, [&](const auto& other) { return other.get() == resource; }); std::erase_if(m_vParametricCreators, [&](const auto& other) { return other.get() == resource; });
} }

View File

@@ -4,9 +4,8 @@
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include "WaylandProtocol.hpp" #include "WaylandProtocol.hpp"
#include "../helpers/Monitor.hpp" #include "protocols/core/Compositor.hpp"
#include "core/Compositor.hpp" #include "xx-color-management-v4.hpp"
#include "color-management-v1.hpp"
#include "types/ColorManagement.hpp" #include "types/ColorManagement.hpp"
class CColorManager; class CColorManager;
@@ -16,17 +15,17 @@ class CColorManagementProtocol;
class CColorManager { class CColorManager {
public: public:
CColorManager(SP<CWpColorManagerV1> resource); CColorManager(SP<CXxColorManagerV4> resource_);
bool good(); bool good();
private: private:
SP<CWpColorManagerV1> m_resource; SP<CXxColorManagerV4> resource;
}; };
class CColorManagementOutput { class CColorManagementOutput {
public: public:
CColorManagementOutput(SP<CWpColorManagementOutputV1> resource, WP<CMonitor> monitor); CColorManagementOutput(SP<CXxColorManagementOutputV4> resource_);
bool good(); bool good();
wl_client* client(); wl_client* client();
@@ -35,9 +34,8 @@ class CColorManagementOutput {
WP<CColorManagementImageDescription> imageDescription; WP<CColorManagementImageDescription> imageDescription;
private: private:
SP<CWpColorManagementOutputV1> m_resource; SP<CXxColorManagementOutputV4> resource;
wl_client* pClient = nullptr; wl_client* pClient = nullptr;
WP<CMonitor> m_monitor;
friend class CColorManagementProtocol; friend class CColorManagementProtocol;
friend class CColorManagementImageDescription; friend class CColorManagementImageDescription;
@@ -46,7 +44,7 @@ class CColorManagementOutput {
class CColorManagementSurface { class CColorManagementSurface {
public: public:
CColorManagementSurface(SP<CWLSurfaceResource> surface_); // temporary interface for frog CM CColorManagementSurface(SP<CWLSurfaceResource> surface_); // temporary interface for frog CM
CColorManagementSurface(SP<CWpColorManagementSurfaceV1> resource, SP<CWLSurfaceResource> surface_); CColorManagementSurface(SP<CXxColorManagementSurfaceV4> resource_, SP<CWLSurfaceResource> surface_);
bool good(); bool good();
wl_client* client(); wl_client* client();
@@ -54,7 +52,7 @@ class CColorManagementSurface {
WP<CColorManagementSurface> self; WP<CColorManagementSurface> self;
WP<CWLSurfaceResource> surface; WP<CWLSurfaceResource> surface;
const NColorManagement::SImageDescription& imageDescription(); const SImageDescription& imageDescription();
bool hasImageDescription(); bool hasImageDescription();
void setHasImageDescription(bool has); void setHasImageDescription(bool has);
const hdr_output_metadata& hdrMetadata(); const hdr_output_metadata& hdrMetadata();
@@ -62,20 +60,19 @@ class CColorManagementSurface {
bool needsHdrMetadataUpdate(); bool needsHdrMetadataUpdate();
private: private:
SP<CWpColorManagementSurfaceV1> m_resource; SP<CXxColorManagementSurfaceV4> resource;
wl_client* pClient = nullptr; wl_client* pClient = nullptr;
NColorManagement::SImageDescription m_imageDescription; SImageDescription m_imageDescription;
bool m_hasImageDescription = false; bool m_hasImageDescription = false;
bool m_needsNewMetadata = false; bool m_needsNewMetadata = false;
hdr_output_metadata m_hdrMetadata; hdr_output_metadata m_hdrMetadata;
friend class CXXColorManagementSurface;
friend class CFrogColorManagementSurface; friend class CFrogColorManagementSurface;
}; };
class CColorManagementFeedbackSurface { class CColorManagementFeedbackSurface {
public: public:
CColorManagementFeedbackSurface(SP<CWpColorManagementSurfaceFeedbackV1> resource, SP<CWLSurfaceResource> surface_); CColorManagementFeedbackSurface(SP<CXxColorManagementFeedbackSurfaceV4> resource_, SP<CWLSurfaceResource> surface_);
bool good(); bool good();
wl_client* client(); wl_client* client();
@@ -84,7 +81,7 @@ class CColorManagementFeedbackSurface {
WP<CWLSurfaceResource> surface; WP<CWLSurfaceResource> surface;
private: private:
SP<CWpColorManagementSurfaceFeedbackV1> m_resource; SP<CXxColorManagementFeedbackSurfaceV4> resource;
wl_client* pClient = nullptr; wl_client* pClient = nullptr;
WP<CColorManagementImageDescription> m_currentPreferred; WP<CColorManagementImageDescription> m_currentPreferred;
@@ -92,32 +89,16 @@ class CColorManagementFeedbackSurface {
friend class CColorManagementProtocol; friend class CColorManagementProtocol;
}; };
class CColorManagementIccCreator {
public:
CColorManagementIccCreator(SP<CWpImageDescriptionCreatorIccV1> resource);
bool good();
wl_client* client();
WP<CColorManagementIccCreator> self;
NColorManagement::SImageDescription settings;
private:
SP<CWpImageDescriptionCreatorIccV1> m_resource;
wl_client* pClient = nullptr;
};
class CColorManagementParametricCreator { class CColorManagementParametricCreator {
public: public:
CColorManagementParametricCreator(SP<CWpImageDescriptionCreatorParamsV1> resource); CColorManagementParametricCreator(SP<CXxImageDescriptionCreatorParamsV4> resource_);
bool good(); bool good();
wl_client* client(); wl_client* client();
WP<CColorManagementParametricCreator> self; WP<CColorManagementParametricCreator> self;
NColorManagement::SImageDescription settings; SImageDescription settings;
private: private:
enum eValuesSet : uint32_t { // NOLINT enum eValuesSet : uint32_t { // NOLINT
@@ -131,25 +112,25 @@ class CColorManagementParametricCreator {
PC_FALL = (1 << 7), PC_FALL = (1 << 7),
}; };
SP<CWpImageDescriptionCreatorParamsV1> m_resource; SP<CXxImageDescriptionCreatorParamsV4> resource;
wl_client* pClient = nullptr; wl_client* pClient = nullptr;
uint32_t valuesSet = 0; // enum eValuesSet uint32_t valuesSet = 0; // enum eValuesSet
}; };
class CColorManagementImageDescription { class CColorManagementImageDescription {
public: public:
CColorManagementImageDescription(SP<CWpImageDescriptionV1> resource, bool allowGetInformation); CColorManagementImageDescription(SP<CXxImageDescriptionV4> resource_, bool allowGetInformation = false);
bool good(); bool good();
wl_client* client(); wl_client* client();
SP<CWpImageDescriptionV1> resource(); SP<CXxImageDescriptionV4> resource();
WP<CColorManagementImageDescription> self; WP<CColorManagementImageDescription> self;
NColorManagement::SImageDescription settings; SImageDescription settings;
private: private:
SP<CWpImageDescriptionV1> m_resource; SP<CXxImageDescriptionV4> m_resource;
wl_client* pClient = nullptr; wl_client* pClient = nullptr;
bool m_allowGetInformation = false; bool m_allowGetInformation = false;
@@ -158,32 +139,30 @@ class CColorManagementImageDescription {
class CColorManagementImageDescriptionInfo { class CColorManagementImageDescriptionInfo {
public: public:
CColorManagementImageDescriptionInfo(SP<CWpImageDescriptionInfoV1> resource, const NColorManagement::SImageDescription& settings_); CColorManagementImageDescriptionInfo(SP<CXxImageDescriptionInfoV4> resource_, const SImageDescription& settings_);
bool good(); bool good();
wl_client* client(); wl_client* client();
private: private:
SP<CWpImageDescriptionInfoV1> m_resource; SP<CXxImageDescriptionInfoV4> m_resource;
wl_client* pClient = nullptr; wl_client* pClient = nullptr;
NColorManagement::SImageDescription settings; SImageDescription settings;
}; };
class CColorManagementProtocol : public IWaylandProtocol { class CColorManagementProtocol : public IWaylandProtocol {
public: public:
CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name, bool debug = false); CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name);
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
void onImagePreferredChanged(uint32_t preferredId); void onImagePreferredChanged();
void onMonitorImageDescriptionChanged(WP<CMonitor> monitor);
private: private:
void destroyResource(CColorManager* resource); void destroyResource(CColorManager* resource);
void destroyResource(CColorManagementOutput* resource); void destroyResource(CColorManagementOutput* resource);
void destroyResource(CColorManagementSurface* resource); void destroyResource(CColorManagementSurface* resource);
void destroyResource(CColorManagementFeedbackSurface* resource); void destroyResource(CColorManagementFeedbackSurface* resource);
void destroyResource(CColorManagementIccCreator* resource);
void destroyResource(CColorManagementParametricCreator* resource); void destroyResource(CColorManagementParametricCreator* resource);
void destroyResource(CColorManagementImageDescription* resource); void destroyResource(CColorManagementImageDescription* resource);
@@ -191,20 +170,16 @@ class CColorManagementProtocol : public IWaylandProtocol {
std::vector<SP<CColorManagementOutput>> m_vOutputs; std::vector<SP<CColorManagementOutput>> m_vOutputs;
std::vector<SP<CColorManagementSurface>> m_vSurfaces; std::vector<SP<CColorManagementSurface>> m_vSurfaces;
std::vector<SP<CColorManagementFeedbackSurface>> m_vFeedbackSurfaces; std::vector<SP<CColorManagementFeedbackSurface>> m_vFeedbackSurfaces;
std::vector<SP<CColorManagementIccCreator>> m_vIccCreators;
std::vector<SP<CColorManagementParametricCreator>> m_vParametricCreators; std::vector<SP<CColorManagementParametricCreator>> m_vParametricCreators;
std::vector<SP<CColorManagementImageDescription>> m_vImageDescriptions; std::vector<SP<CColorManagementImageDescription>> m_vImageDescriptions;
bool m_debug = false;
friend class CColorManager; friend class CColorManager;
friend class CColorManagementOutput; friend class CColorManagementOutput;
friend class CColorManagementSurface; friend class CColorManagementSurface;
friend class CColorManagementFeedbackSurface; friend class CColorManagementFeedbackSurface;
friend class CColorManagementIccCreator;
friend class CColorManagementParametricCreator; friend class CColorManagementParametricCreator;
friend class CColorManagementImageDescription; friend class CColorManagementImageDescription;
friend class CXXColorManagementSurface;
friend class CFrogColorManagementSurface; friend class CFrogColorManagementSurface;
}; };

View File

@@ -1,95 +0,0 @@
#include "ContentType.hpp"
#include "content-type-v1.hpp"
#include "protocols/types/ContentType.hpp"
CContentTypeManager::CContentTypeManager(SP<CWpContentTypeManagerV1> resource) : m_resource(resource) {
if UNLIKELY (!good())
return;
resource->setDestroy([](CWpContentTypeManagerV1* r) {});
resource->setOnDestroy([this](CWpContentTypeManagerV1* r) { PROTO::contentType->destroyResource(this); });
resource->setGetSurfaceContentType([](CWpContentTypeManagerV1* r, uint32_t id, wl_resource* surface) {
LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface);
auto SURF = CWLSurfaceResource::fromResource(surface);
if (!SURF) {
LOGM(ERR, "No surface for resource {}", (uintptr_t)surface);
r->error(-1, "Invalid surface (2)");
return;
}
if (SURF->colorManagement) {
r->error(WP_CONTENT_TYPE_MANAGER_V1_ERROR_ALREADY_CONSTRUCTED, "CT manager already exists");
return;
}
const auto RESOURCE = PROTO::contentType->m_vContentTypes.emplace_back(makeShared<CContentType>(makeShared<CWpContentTypeV1>(r->client(), r->version(), id)));
if UNLIKELY (!RESOURCE->good()) {
r->noMemory();
PROTO::contentType->m_vContentTypes.pop_back();
return;
}
RESOURCE->self = RESOURCE;
SURF->contentType = RESOURCE;
});
}
bool CContentTypeManager::good() {
return m_resource->resource();
}
CContentType::CContentType(WP<CWLSurfaceResource> surface) {
destroy = surface->events.destroy.registerListener([this](std::any d) { PROTO::contentType->destroyResource(this); });
}
CContentType::CContentType(SP<CWpContentTypeV1> resource) : m_resource(resource) {
if UNLIKELY (!good())
return;
m_pClient = resource->client();
resource->setDestroy([this](CWpContentTypeV1* r) { PROTO::contentType->destroyResource(this); });
resource->setOnDestroy([this](CWpContentTypeV1* r) { PROTO::contentType->destroyResource(this); });
resource->setSetContentType([this](CWpContentTypeV1* r, wpContentTypeV1Type type) { value = NContentType::fromWP(type); });
}
bool CContentType::good() {
return m_resource && m_resource->resource();
}
wl_client* CContentType::client() {
return m_pClient;
}
CContentTypeProtocol::CContentTypeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CContentTypeProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CContentTypeManager>(makeShared<CWpContentTypeManagerV1>(client, ver, id)));
if UNLIKELY (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
}
SP<CContentType> CContentTypeProtocol::getContentType(WP<CWLSurfaceResource> surface) {
if (surface->contentType.valid())
return surface->contentType.lock();
return m_vContentTypes.emplace_back(makeShared<CContentType>(surface));
}
void CContentTypeProtocol::destroyResource(CContentTypeManager* resource) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; });
}
void CContentTypeProtocol::destroyResource(CContentType* resource) {
std::erase_if(m_vContentTypes, [&](const auto& other) { return other.get() == resource; });
}

View File

@@ -1,59 +0,0 @@
#pragma once
#include "WaylandProtocol.hpp"
#include "core/Compositor.hpp"
#include "content-type-v1.hpp"
#include "types/ContentType.hpp"
class CContentTypeManager {
public:
CContentTypeManager(SP<CWpContentTypeManagerV1> resource);
bool good();
private:
SP<CWpContentTypeManagerV1> m_resource;
};
class CContentType {
public:
CContentType(SP<CWpContentTypeV1> resource);
CContentType(WP<CWLSurfaceResource> surface);
bool good();
wl_client* client();
NContentType::eContentType value = NContentType::CONTENT_TYPE_NONE;
WP<CContentType> self;
private:
SP<CWpContentTypeV1> m_resource;
wl_client* m_pClient = nullptr;
CHyprSignalListener destroy;
friend class CContentTypeProtocol;
};
class CContentTypeProtocol : public IWaylandProtocol {
public:
CContentTypeProtocol(const wl_interface* iface, const int& ver, const std::string& name);
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
SP<CContentType> getContentType(WP<CWLSurfaceResource> surface);
private:
void destroyResource(CContentTypeManager* resource);
void destroyResource(CContentType* resource);
std::vector<SP<CContentTypeManager>> m_vManagers;
std::vector<SP<CContentType>> m_vContentTypes;
friend class CContentTypeManager;
friend class CContentType;
};
namespace PROTO {
inline UP<CContentTypeProtocol> contentType;
};

View File

@@ -41,7 +41,7 @@ void CCursorShapeProtocol::createCursorShapeDevice(CWpCursorShapeManagerV1* pMgr
} }
void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t serial, wpCursorShapeDeviceV1Shape shape) { void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t serial, wpCursorShapeDeviceV1Shape shape) {
if UNLIKELY ((uint32_t)shape == 0 || (uint32_t)shape >= CURSOR_SHAPE_NAMES.size()) { if UNLIKELY ((uint32_t)shape == 0 || (uint32_t)shape > CURSOR_SHAPE_NAMES.size()) {
pMgr->error(WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE, "The shape is invalid"); pMgr->error(WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE, "The shape is invalid");
return; return;
} }

View File

@@ -4,7 +4,6 @@
#include "managers/eventLoop/EventLoopManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp"
#include <aquamarine/backend/DRM.hpp> #include <aquamarine/backend/DRM.hpp>
#include <fcntl.h> #include <fcntl.h>
using namespace Hyprutils::OS;
CDRMLeaseResource::CDRMLeaseResource(SP<CWpDrmLeaseV1> resource_, SP<CDRMLeaseRequestResource> request) : resource(resource_) { CDRMLeaseResource::CDRMLeaseResource(SP<CWpDrmLeaseV1> resource_, SP<CDRMLeaseRequestResource> request) : resource(resource_) {
if UNLIKELY (!good()) if UNLIKELY (!good())
@@ -186,14 +185,15 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP<CWpDrmLeaseDeviceV1> resourc
RESOURCE->parent = self; RESOURCE->parent = self;
}); });
CFileDescriptor fd{((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD()}; int fd = ((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD();
if (!fd.isValid()) { if (fd < 0) {
LOGM(ERR, "Failed to dup fd in lease"); LOGM(ERR, "Failed to dup fd in lease");
return; return;
} }
LOGM(LOG, "Sending DRMFD {} to new lease device", fd.get()); LOGM(LOG, "Sending DRMFD {} to new lease device", fd);
resource->sendDrmFd(fd.get()); resource->sendDrmFd(fd);
close(fd);
for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) { for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) {
if (m) if (m)
@@ -233,13 +233,14 @@ void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) {
CDRMLeaseDevice::CDRMLeaseDevice(SP<Aquamarine::CDRMBackend> drmBackend) : backend(drmBackend) { CDRMLeaseDevice::CDRMLeaseDevice(SP<Aquamarine::CDRMBackend> drmBackend) : backend(drmBackend) {
auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); auto drm = (Aquamarine::CDRMBackend*)drmBackend.get();
CFileDescriptor fd{drm->getNonMasterFD()}; auto fd = drm->getNonMasterFD();
if (!fd.isValid()) { if (fd < 0) {
LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName);
return; return;
} }
close(fd);
success = true; success = true;
name = drm->gpuName; name = drm->gpuName;
} }

View File

@@ -5,7 +5,6 @@
#include "WaylandProtocol.hpp" #include "WaylandProtocol.hpp"
#include "drm-lease-v1.hpp" #include "drm-lease-v1.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
#include <hyprutils/os/FileDescriptor.hpp>
/* /*
TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu) TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu)

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