Compare commits

..

63 Commits
nix ... v0.44.1

Author SHA1 Message Date
Vaxry
4520b30d49 version: bump to 0.44.1 2024-10-09 13:54:39 +01:00
trianta
8405aa111d output: update state even if no owner exists (#8044) 2024-10-09 13:47:52 +01:00
Vaxry
ad46257cce output/xdg-output: avoid sending events to released globals
ref #6835
2024-10-09 13:47:52 +01:00
Vaxry
0cfbe618b5 keyboard: update group state on change for the sym resolve state
fixes #8038
2024-10-09 13:47:52 +01:00
Vaxry
7d0944acdf defaultConfig: add a nofocus rule for weird X windows
ref #6543
2024-10-09 13:47:52 +01:00
Vaxry
b9990468f3 pointer: expand sw cursor damage box
fixes #8031

just a bit, rounding errors I guess
2024-10-09 13:47:52 +01:00
vaxerski
736a8735b3 keybinds: fixup xkb_states for resolve_by_sym
fixes #7750
2024-10-09 13:47:52 +01:00
Vaxry
b54eecbd79 config: give simple help for super+q not working
only on default config :P
2024-10-09 13:47:52 +01:00
Ikalco
657aeb3946 screencopy: fix screencopy frames not being cleaned up (#8017)
---------

Co-authored-by: Vaxry <vaxry@vaxry.net>
2024-10-09 13:47:52 +01:00
Aqa-Ib
6807430b18 layout: fix auto group when opening a new window in a non-focused workspace using window rules (#8006) 2024-10-09 13:47:52 +01:00
Vaxry
0c7a7e2d56 version: bump to 0.44.0 2024-10-06 12:04:13 +01:00
Vaxry
0ec6072a29 single-pixel: set buffer size to 1,1 2024-10-05 16:36:57 +01:00
Vaxry
3ca699debf opengl: use GL_CLAMP_TO_EDGE instead of GL_CLAMP
avoid error spam on select hw
2024-10-05 14:57:18 +01:00
Vaxry
52c0919621 monitor: arrange monitors on connect and disconnect 2024-10-05 14:41:44 +01:00
Vaxry
6fbfeefc71 protocolmgr: don't expose the fallback output 2024-10-05 14:40:03 +01:00
Vaxry
46bf87c8d1 monitor: use a scope guard for disconnect events 2024-10-05 14:37:12 +01:00
Vaxry
595eb89f6e renderer: Fix resize artifacts (stretching, bumps) (#7499) 2024-10-05 01:01:21 +01:00
Vaxry
a815b14bf1 monitor: cleanup and modernize scheduleDone 2024-10-05 01:01:21 +01:00
Vaxry
3a5052a714 compositor: update all xdg outputs on arrange 2024-10-05 01:01:21 +01:00
Vaxry
8e237b006f xdg-output: minor cleanups 2024-10-05 01:01:20 +01:00
Theo Paris
1ed925b69c internal: fix missing include directive (#7984)
This should fix building with clang.
2024-10-04 09:41:27 +01:00
Maximilian Seidler
aed529f695 renderer: fix uvBR calculation (#7975) 2024-10-03 23:00:44 +01:00
Aqa-Ib
de68e065fe layout: fix dragging a window into a group after e242694 (#7976) 2024-10-02 21:25:25 +01:00
Aqa-Ib
e2426942e5 layout: add auto_group to control default grouping (#7883) 2024-10-02 10:22:19 +01:00
Vaxry
5c6c300abf wayland/output: send geometry in updateState 2024-09-30 17:42:36 +01:00
Vaxry
6bd3397141 wlr-output-management: accept 0 refresh rates
fixes #7879
2024-09-30 17:40:38 +01:00
Vaxry
68fd32c810 byteoperations: add missing header 2024-09-30 17:27:10 +01:00
Vaxry
3ddb16bd5b compositor/wayland: up the max buffer size to avoid disconnects when app hangs 2024-09-30 17:25:57 +01:00
Trianta
f6387536f6 protocol: fix missing include 2024-09-30 10:06:39 +03:00
Trianta
968f6a6013 meson: fix arch build with new protocol 2024-09-30 10:06:39 +03:00
Vaxry
488efab636 single-pixel-buffer: new protocol impl
fixes #6624
2024-09-30 00:58:16 +01:00
Gliczy
6649255d54 flake.lock: update 2024-09-29 17:56:27 +03:00
Luke Chen
4b00cba319 dwindle: add movetoroot method to layout messages (#7903) 2024-09-29 14:47:59 +01:00
Mike Will
9e418671e1 config: add descriptions for dwindle and master layout options (#7933) 2024-09-29 14:42:10 +01:00
Mihai Fufezan
d73c14751a CI/Nix: git+https -> github 2024-09-28 21:53:18 +03:00
bivsk
6f313de952 core: Fix Musl builds (#7934)
Musl does not include the internal type `__time_t`.
Use `time_t` instead.
2024-09-28 13:46:31 +01:00
Mike Will
2cf6e7862a dwindle: add config option split_bias (#7920)
If `default_split_ratio` is greater than 1.0, `split_bias` will give the
bigger half to a specific window:

0 - positional (default)
1 - current window
2 - opening window
2024-09-28 01:49:40 +01:00
Mihai Fufezan
58669fef77 flake.lock: update 2024-09-27 18:35:29 +03:00
Vaxry
e20aef7d53 opengl: remove debug log 2024-09-26 22:34:33 +01:00
Mihai Fufezan
b2143a98e2 CI/Nix: no longer build with submodules 2024-09-27 00:07:52 +03:00
Mihai Fufezan
f75f8efb1b Meson: add tracy dependency 2024-09-27 00:07:52 +03:00
Mihai Fufezan
be96787ed0 CMake: use udis86 from pkg-config, fallback to subproject
Only canihavesomecoffee's fork (the one the subproject uses) provides
a .pc file, so we either find the correct version or we use the
subproject.
2024-09-27 00:07:52 +03:00
Mihai Fufezan
89d945aabe CMake: use hyprland-protocols from pkg-config, fallback to subproject
protocolnew: fix external path, which may not be in $CMAKE_SOURCE_DIR
2024-09-27 00:07:52 +03:00
Mihai Fufezan
27211c71e9 Meson: try to find udis86 through pkgconfig, fallback to subproject
Only the fork provides a .pc file, so there's no risk of linking the wrong
lib version. If pkg-config can't find it (most cases), fall back to using
the subproject through the wrap file.
2024-09-27 00:07:52 +03:00
Mihai Fufezan
14942bca60 Nix: re-add hyprland-protocols 2024-09-27 00:07:52 +03:00
Mihai Fufezan
77f2a01304 flake.lock: update nixpkgs 2024-09-26 21:17:07 +03:00
Mihai Fufezan
7b56ce6521 CI/Nix: add cross build 2024-09-26 21:17:07 +03:00
Jörg Thalheim
32a8caf7e7 Nix: also test cross build 2024-09-26 21:17:07 +03:00
Vaxry
caaa9b11e4 wlr-output-configuration: Improve output configuration (#7571) 2024-09-26 11:10:53 +01:00
Kamikadze
b1ad2d8066 dispatchers: fixup dpms toggle (#7875)
now toggles every monitor individually
2024-09-26 00:08:50 +01:00
Vaxry
22746b3046 hyprctl: use the getMonitorData helper everywhere 2024-09-25 23:38:11 +01:00
Vaxry
49713fab04 pointermgr: avoid hogging CMonitor refs 2024-09-25 23:15:41 +01:00
vaxerski
8b86ee8bf0 github: encourage usage of --systeminfo if Hyprland won't launch 2024-09-25 10:39:33 +01:00
vaxerski
2a052c69f3 core: add a --systeminfo parameter to gather systeminfo without running 2024-09-25 10:36:51 +01:00
Vaxry
2320b2241c Internal: move to Mat3x3 from hyprutils (#7902)
* Meson: require hyprutils >= 0.2.3

* flake.lock: update hyprutils

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-09-25 10:01:13 +01:00
vaxerski
8f5188269b hyprctl: add solitary field to hyprctl monitors 2024-09-25 09:59:18 +01:00
vaxerski
00c8626863 hyprctl: add submap request
fixes #7898
2024-09-24 11:25:05 +01:00
Vaxry
0a211f29f5 hyprctl: add defaultName to workspacerules
fixes #7886
2024-09-24 01:19:05 +01:00
Vaxry
d279d7c4c6 eventloop: dispatch pending in session on start
fixes #7855 #7391
2024-09-24 00:49:29 +01:00
diniamo
6c78b03bb7 flake: update xdph 2024-09-24 00:47:34 +01:00
Vaxry
f79497087b internal: nuke wlsignal and related
old semi-wrappers for wl_signal, they are no longer used
2024-09-24 00:47:34 +01:00
Artur Manuel
508bde1f61 core: add HYPRLAND_CONFIG environment variable (#7851) 2024-09-23 16:40:19 +01:00
diniamo
e5ff19ac0f flake: update xdph 2024-09-22 11:55:13 +03:00
81 changed files with 1247 additions and 791 deletions

View File

@@ -29,10 +29,10 @@ body:
attributes: attributes:
label: System Info and Version label: System Info and Version
description: | description: |
Paste the output of `hyprctl systeminfo -c` here (If you are on a Paste the output of `hyprctl systeminfo -c` here. If you can't
version that shows you help menu, omit the `-c` and attach config files launch Hyprland, paste the output of `Hyprland --systeminfo`.
to the issue). If you have configs outside of the main config shown If `Hyprland --systeminfo` errors out (added in 0.44.0), find
here, please attach. and paste the Hyprland version manually.
value: "<details> value: "<details>
<summary>System/Version info</summary> <summary>System/Version info</summary>

View File

@@ -12,6 +12,7 @@ jobs:
matrix: matrix:
package: package:
- hyprland - hyprland
- hyprland-cross
- xdg-desktop-portal-hyprland - xdg-desktop-portal-hyprland
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -24,4 +25,4 @@ jobs:
name: hyprland name: hyprland
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}&submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" - run: nix build 'github:hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"

View File

@@ -25,8 +25,18 @@ message(STATUS "Gathering git info")
execute_process(COMMAND ./scripts/generateVersion.sh execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# udis find_package(PkgConfig REQUIRED)
# Try to find canihavesomecoffee's udis86 using pkgconfig vmd/udis86 does not
# provide a .pc file and won't be detected this way
pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2)
# Fallback to subproject
if(NOT udis_dep_FOUND)
add_subdirectory("subprojects/udis86") add_subdirectory("subprojects/udis86")
include_directories("subprojects/udis86")
message(STATUS "udis86 dependency not found, falling back to subproject")
endif()
if(CMAKE_BUILD_TYPE) if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
@@ -47,8 +57,6 @@ else()
set(BUILDTYPE_LOWER "release") set(BUILDTYPE_LOWER "release")
endif() endif()
find_package(PkgConfig REQUIRED)
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
@@ -63,7 +71,8 @@ else()
message(STATUS "Configuring Hyprland in Release with CMake") message(STATUS "Configuring Hyprland in Release with CMake")
endif() endif()
include_directories(. "src/" "subprojects/udis86/" "protocols/") include_directories(. "src/" "protocols/")
set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD 26)
add_compile_options( add_compile_options(
-Wall -Wall
@@ -101,7 +110,7 @@ pkg_check_modules(
IMPORTED_TARGET IMPORTED_TARGET
xkbcommon xkbcommon
uuid uuid
wayland-server wayland-server>=1.22.90
wayland-protocols wayland-protocols
cairo cairo
pango pango
@@ -114,7 +123,7 @@ pkg_check_modules(
gio-2.0 gio-2.0
hyprlang>=0.3.2 hyprlang>=0.3.2
hyprcursor>=0.1.7 hyprcursor>=0.1.7
hyprutils>=0.2.2) hyprutils>=0.2.3)
find_package(hyprwayland-scanner 0.3.10 REQUIRED) find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -216,24 +225,26 @@ set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack) include(CPack)
if(CMAKE_DISABLE_PRECOMPILE_HEADERS)
message(STATUS "Not using precompiled headers")
else()
message(STATUS "Setting precompiled headers") message(STATUS "Setting precompiled headers")
target_precompile_headers(Hyprland PRIVATE target_precompile_headers(Hyprland PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>) $<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
endif()
message(STATUS "Setting link libraries") message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps) target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps)
if(udis_dep_FOUND)
target_link_libraries(Hyprland PkgConfig::udis_dep)
else()
target_link_libraries(Hyprland libudis86)
endif()
# used by `make installheaders`, to ensure the headers are generated # used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers) add_custom_target(generate-protocol-headers)
function(protocolnew protoPath protoName external) function(protocolnew protoPath protoName external)
if(external) if(external)
set(path ${CMAKE_SOURCE_DIR}/${protoPath}) set(path ${protoPath})
else() else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif() endif()
@@ -261,14 +272,22 @@ function(protocolWayland)
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
endfunction() endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
libudis86)
protocolnew("subprojects/hyprland-protocols/protocols" pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0)
"hyprland-global-shortcuts-v1" true) if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
else()
set(HYPRLAND_PROTOCOLS "subprojects/hyprland-protocols")
message(STATUS "hyprland-protocols subproject set to ${HYPRLAND_PROTOCOLS}")
endif()
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1"
true)
protocolnew("unstable/text-input" "text-input-unstable-v1" false) protocolnew("unstable/text-input" "text-input-unstable-v1" false)
protocolnew("subprojects/hyprland-protocols/protocols" protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1"
"hyprland-toplevel-export-v1" true) true)
protocolnew("protocols" "wlr-screencopy-unstable-v1" true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) protocolnew("protocols" "wlr-gamma-control-unstable-v1" true)
protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
@@ -279,8 +298,7 @@ protocolnew("protocols" "input-method-unstable-v2" true)
protocolnew("protocols" "wlr-output-management-unstable-v1" true) protocolnew("protocols" "wlr-output-management-unstable-v1" true)
protocolnew("protocols" "kde-server-decoration" true) protocolnew("protocols" "kde-server-decoration" true)
protocolnew("protocols" "wlr-data-control-unstable-v1" true) protocolnew("protocols" "wlr-data-control-unstable-v1" true)
protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true)
true)
protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
protocolnew("protocols" "wayland-drm" true) protocolnew("protocols" "wayland-drm" true)
protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/tearing-control" "tearing-control-v1" false)
@@ -312,6 +330,7 @@ protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
protocolnew("staging/drm-lease" "drm-lease-v1" false) protocolnew("staging/drm-lease" "drm-lease-v1" false)
protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
protocolwayland() protocolwayland()

View File

@@ -1 +1 @@
0.43.0 0.44.1

View File

@@ -255,4 +255,8 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# Example windowrule v2 # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0

62
flake.lock generated
View File

@@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726665257, "lastModified": 1727261104,
"narHash": "sha256-rEzEZtd3iyVo5RJ1OGujOlnywNf3gsrOnjAn1NLciD4=", "narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "752d0fbd141fabb5a1e7f865199b80e6e76f8d8e", "rev": "b82fdaff917582a9d568969e15e61b398c71e990",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -42,11 +42,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1722623071, "lastModified": 1727532803,
"narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=", "narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "912d56025f03d41b1ad29510c423757b4379eb1c", "rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -56,6 +56,29 @@
} }
}, },
"hyprland-protocols": { "hyprland-protocols": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1727451107,
"narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-protocols",
"type": "github"
}
},
"hyprland-protocols_2": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"xdph", "xdph",
@@ -116,11 +139,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726874949, "lastModified": 1727300645,
"narHash": "sha256-PNnIpwGqpTvMU3N2r0wMQwK1E+t4Bb5fbJwblQvr+80=", "narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "d97af4f6bd068c03a518b597675e598f57ea2291", "rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -139,11 +162,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726840673, "lastModified": 1726874836,
"narHash": "sha256-HIPEXyRRVZoqD6U+lFS1B0tsIU7p83FaB9m7KT/x6mQ=", "narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "b68dab23fc922eae99306988133ee80a40b39ca5", "rev": "500c81a9e1a76760371049a8d99e008ea77aa59e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -154,11 +177,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1726755586, "lastModified": 1727348695,
"narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=", "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e", "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -172,6 +195,7 @@
"inputs": { "inputs": {
"aquamarine": "aquamarine", "aquamarine": "aquamarine",
"hyprcursor": "hyprcursor", "hyprcursor": "hyprcursor",
"hyprland-protocols": "hyprland-protocols",
"hyprlang": "hyprlang", "hyprlang": "hyprlang",
"hyprutils": "hyprutils", "hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner", "hyprwayland-scanner": "hyprwayland-scanner",
@@ -197,7 +221,7 @@
}, },
"xdph": { "xdph": {
"inputs": { "inputs": {
"hyprland-protocols": "hyprland-protocols", "hyprland-protocols": "hyprland-protocols_2",
"hyprlang": [ "hyprlang": [
"hyprlang" "hyprlang"
], ],
@@ -215,11 +239,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726851729, "lastModified": 1727524473,
"narHash": "sha256-1z0esr5lBeUMlrPZ9gZmqZT8oTQekxJi53HAW4cH0Ms=", "narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "73b8c4f1150040644cf678aa8bbf2cec48a433cf", "rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -22,6 +22,12 @@
inputs.hyprlang.follows = "hyprlang"; inputs.hyprlang.follows = "hyprlang";
}; };
hyprland-protocols = {
url = "github:hyprwm/hyprland-protocols";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
hyprlang = { hyprlang = {
url = "github:hyprwm/hyprlang"; url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@@ -67,6 +73,15 @@
hyprland-extras hyprland-extras
]; ];
}); });
pkgsCrossFor = eachSystem (system: crossSystem:
import nixpkgs {
localSystem = system;
crossSystem = crossSystem;
overlays = with self.overlays; [
hyprland-packages
hyprland-extras
];
});
in { in {
overlays = import ./nix/overlays.nix {inherit self lib inputs;}; overlays = import ./nix/overlays.nix {inherit self lib inputs;};
@@ -92,6 +107,7 @@
xdg-desktop-portal-hyprland xdg-desktop-portal-hyprland
; ;
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
}); });
devShells = eachSystem (system: { devShells = eachSystem (system: {

View File

@@ -43,10 +43,6 @@ xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland'))
gio_dep = dependency('gio-2.0', required: true) gio_dep = dependency('gio-2.0', required: true)
cmake = import('cmake')
udis = cmake.subproject('udis86')
udis86 = udis.dependency('libudis86')
if not xcb_dep.found() if not xcb_dep.found()
add_project_arguments('-DNO_XWAYLAND', language: 'cpp') add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif endif
@@ -77,6 +73,12 @@ foreach file : headers
install_headers(file, subdir: 'hyprland', preserve_path: true) install_headers(file, subdir: 'hyprland', preserve_path: true)
endforeach endforeach
tracy = dependency('tracy', static: true, required: get_option('tracy_enable'))
if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized'
warning('Profiling builds should set -- buildtype = debugoptimized')
endif
subdir('protocols') subdir('protocols')
subdir('src') subdir('src')
subdir('hyprctl') subdir('hyprctl')

View File

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

View File

@@ -1,10 +0,0 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6fdf98db..d8424d91 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.30)
+cmake_minimum_required(VERSION 3.27)
# Get version
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)

View File

@@ -5,16 +5,17 @@
pkg-config, pkg-config,
pkgconf, pkgconf,
makeWrapper, makeWrapper,
cmake, meson,
ninja,
aquamarine, aquamarine,
binutils, binutils,
cairo, cairo,
git, git,
hyprcursor, hyprcursor,
hyprland-protocols,
hyprlang, hyprlang,
hyprutils, hyprutils,
hyprwayland-scanner, hyprwayland-scanner,
jq,
libGL, libGL,
libdrm, libdrm,
libexecinfo, libexecinfo,
@@ -24,9 +25,9 @@
mesa, mesa,
pango, pango,
pciutils, pciutils,
python3,
systemd, systemd,
tomlplusplus, tomlplusplus,
udis86-hyprland,
wayland, wayland,
wayland-protocols, wayland-protocols,
wayland-scanner, wayland-scanner,
@@ -51,7 +52,7 @@
inherit (lib.attrsets) mapAttrsToList; inherit (lib.attrsets) mapAttrsToList;
inherit (lib.lists) flatten concatLists optional optionals; inherit (lib.lists) flatten concatLists optional optionals;
inherit (lib.sources) cleanSourceWith cleanSource; inherit (lib.sources) cleanSourceWith cleanSource;
inherit (lib.strings) cmakeBool hasSuffix makeBinPath optionalString; inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable;
adapters = flatten [ adapters = flatten [
stdenvAdapters.useMoldLinker stdenvAdapters.useMoldLinker
@@ -74,14 +75,6 @@ in
src = cleanSource ../.; src = cleanSource ../.;
}; };
patches = [
# forces GCC to use -std=c++26
./stdcxx.patch
# Nix does not have CMake 3.30 yet, so override the minimum version
./cmake-version.patch
];
postPatch = '' postPatch = ''
# Fix hardcoded paths to /usr installation # Fix hardcoded paths to /usr installation
sed -i "s#/usr#$out#" src/render/OpenGL.cpp sed -i "s#/usr#$out#" src/render/OpenGL.cpp
@@ -101,12 +94,10 @@ in
nativeBuildInputs = [ nativeBuildInputs = [
hyprwayland-scanner hyprwayland-scanner
jq
makeWrapper makeWrapper
cmake meson
ninja
pkg-config pkg-config
python3 # for udis86
wayland-scanner
]; ];
outputs = [ outputs = [
@@ -121,6 +112,7 @@ in
cairo cairo
git git
hyprcursor hyprcursor
hyprland-protocols
hyprlang hyprlang
hyprutils hyprutils
libdrm libdrm
@@ -132,8 +124,10 @@ in
pango pango
pciutils pciutils
tomlplusplus tomlplusplus
udis86-hyprland
wayland wayland
wayland-protocols wayland-protocols
wayland-scanner
xorg.libXcursor xorg.libXcursor
] ]
(optionals customStdenv.hostPlatform.isMusl [libexecinfo]) (optionals customStdenv.hostPlatform.isMusl [libexecinfo])
@@ -148,20 +142,25 @@ in
(optional withSystemd systemd) (optional withSystemd systemd)
]; ];
cmakeBuildType = mesonBuildType =
if debug if debug
then "Debug" then "debugoptimized"
else "RelWithDebInfo"; else "release";
# we want as much debug info as possible # we want as much debug info as possible
dontStrip = debug; dontStrip = debug;
cmakeFlags = mapAttrsToList cmakeBool { mesonFlags = flatten [
"NO_XWAYLAND" = !enableXWayland; (mapAttrsToList mesonEnable {
"LEGACY_RENDERER" = legacyRenderer; "xwayland" = enableXWayland;
"NO_SYSTEMD" = !withSystemd; "legacy_renderer" = legacyRenderer;
"CMAKE_DISABLE_PRECOMPILE_HEADERS" = true; "systemd" = withSystemd;
}; })
(mapAttrsToList mesonBool {
"b_pch" = false;
"tracy_enable" = false;
})
];
postInstall = '' postInstall = ''
${optionalString wrapRuntimeDeps '' ${optionalString wrapRuntimeDeps ''

View File

@@ -22,9 +22,11 @@ in {
# Dependencies # Dependencies
inputs.aquamarine.overlays.default inputs.aquamarine.overlays.default
inputs.hyprcursor.overlays.default inputs.hyprcursor.overlays.default
inputs.hyprland-protocols.overlays.default
inputs.hyprlang.overlays.default inputs.hyprlang.overlays.default
inputs.hyprutils.overlays.default inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default inputs.hyprwayland-scanner.overlays.default
self.overlays.udis86
# Hyprland packages themselves # Hyprland packages themselves
(final: prev: let (final: prev: let
@@ -63,4 +65,20 @@ in {
hyprland-extras = lib.composeManyExtensions [ hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.xdg-desktop-portal-hyprland inputs.xdph.overlays.xdg-desktop-portal-hyprland
]; ];
# udis86 from nixpkgs is too old, and also does not provide a .pc file
# this version is the one used in the git submodule, and allows us to
# fetch the source without '?submodules=1'
udis86 = final: prev: {
udis86-hyprland = prev.udis86.overrideAttrs (self: super: {
src = final.fetchFromGitHub {
owner = "canihavesomecoffee";
repo = "udis86";
rev = "5336633af70f3917760a6d441ff02d93477b0c86";
hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g=";
};
patches = [];
});
};
} }

View File

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

View File

@@ -63,6 +63,7 @@ protocols = [
wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml',
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
] ]
wl_protocols = [] wl_protocols = []

View File

@@ -23,11 +23,13 @@
#include "protocols/PointerConstraints.hpp" #include "protocols/PointerConstraints.hpp"
#include "protocols/LayerShell.hpp" #include "protocols/LayerShell.hpp"
#include "protocols/XDGShell.hpp" #include "protocols/XDGShell.hpp"
#include "protocols/XDGOutput.hpp"
#include "protocols/core/Compositor.hpp" #include "protocols/core/Compositor.hpp"
#include "protocols/core/Subcompositor.hpp" #include "protocols/core/Subcompositor.hpp"
#include "desktop/LayerSurface.hpp" #include "desktop/LayerSurface.hpp"
#include "render/Renderer.hpp" #include "render/Renderer.hpp"
#include "xwayland/XWayland.hpp" #include "xwayland/XWayland.hpp"
#include "helpers/ByteOperations.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>
@@ -229,6 +231,9 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
if (envEnabled("HYPRLAND_TRACE")) if (envEnabled("HYPRLAND_TRACE"))
Debug::trace = true; Debug::trace = true;
// set the buffer size to 1MB to avoid disconnects due to an app hanging for a short while
wl_display_set_default_max_buffer_size(m_sWLDisplay, 1_MB);
Aquamarine::SBackendOptions options; Aquamarine::SBackendOptions options;
options.logFunction = aqLog; options.logFunction = aqLog;
@@ -2865,6 +2870,8 @@ void CCompositor::arrangeMonitors() {
else else
m->xwaylandScale = 1.f; m->xwaylandScale = 1.f;
} }
PROTO::xdgOutput->updateAllOutputs();
} }
void CCompositor::enterUnsafeState() { void CCompositor::enterUnsafeState() {

View File

@@ -772,6 +772,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_GRADIENT, .type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66775500"}, .data = SConfigOptionDescription::SGradientData{"0x66775500"},
}, },
SConfigOptionDescription{
.value = "group:auto_group",
.description = "automatically group new windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
/* /*
* group:groupbar: * group:groupbar:
@@ -1372,4 +1378,164 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
/*
* dwindle:
*/
SConfigOptionDescription{
.value = "dwindle:pseudotile",
.description = "enable pseudotiling. Pseudotiled windows retain their floating size when tiled.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:force_split",
.description = "0 -> split follows mouse, 1 -> always split to the left (new = left or top) 2 -> always split to the right (new = right or bottom)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "follow mouse,left or top,right or bottom"},
},
SConfigOptionDescription{
.value = "dwindle:preserve_split",
.description = "if enabled, the split (side/top) will not change regardless of what happens to the container.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:smart_split",
.description = "if enabled, allows a more precise control over the window split direction based on the cursor's position. The window is conceptually divided into four "
"triangles, and cursor's triangle determines the split direction. This feature also turns on preserve_split.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:smart_resizing",
.description =
"if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "dwindle:permanent_direction_override",
.description = "if enabled, makes the preselect direction persist until either this mode is turned off, another direction is specified, or a non-direction is specified "
"(anything other than l,r,u/t,d/b)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:special_scale_factor",
.description = "specifies the scale factor of windows on the special workspace [0 - 1]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
},
SConfigOptionDescription{
.value = "dwindle:split_width_multiplier",
.description = "specifies the auto-split width multiplier",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0.1, 3},
},
SConfigOptionDescription{
.value = "dwindle:no_gaps_when_only",
.description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"},
},
SConfigOptionDescription{
.value = "dwindle:use_active_for_splits",
.description = "whether to prefer the active window or the mouse position for splits",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "dwindle:default_split_ratio",
.description = "the default split ratio on window open. 1 means even 50/50 split. [0.1 - 1.9]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0.1, 1.9},
},
SConfigOptionDescription{
.value = "dwindle:split_bias",
.description = "specifies which window will receive the larger half of a split. positional - 0, current window - 1, opening window - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "positional,current,opening"},
},
/*
* master:
*/
SConfigOptionDescription{
.value = "master:allow_small_split",
.description = "enable adding additional master windows in a horizontal split style",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:special_scale_factor",
.description = "the scale of the special workspace windows. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
},
SConfigOptionDescription{
.value = "master:mfact",
.description =
"the size as a percentage of the master window, for example `mfact = 0.70` would mean 70% of the screen will be the master window, and 30% the slave [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.55, 0, 1},
},
SConfigOptionDescription{
.value = "master:new_status",
.description = "`master`: new window becomes master; `slave`: new windows are added to slave stack; `inherit`: inherit from focused window",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"slave"},
},
SConfigOptionDescription{
.value = "master:new_on_top",
.description = "whether a newly open window should be on the top of the stack",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:new_on_active",
.description = "`before`, `after`: place new window relative to the focused window; `none`: place new window according to the value of `new_on_top`. ",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"none"},
},
SConfigOptionDescription{
.value = "master:no_gaps_when_only",
.description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"},
},
SConfigOptionDescription{
.value = "master:orientation",
.description = "default placement of the master area, can be left, right, top, bottom or center",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"left"},
},
SConfigOptionDescription{
.value = "master:inherit_fullscreen",
.description = "inherit fullscreen status when cycling/swapping to another window (e.g. monocle layout)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:always_center_master",
.description = "when using orientation=center, keep the master window centered, even when it is the only window in the workspace.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:smart_resizing",
.description =
"if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:drop_at_cursor",
.description = "when enabled, dragging and dropping windows will put them at the cursor position. Otherwise, when dropped at the stack side, they will go to the "
"top/bottom of the stack depending on new_on_top.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
}; };

View File

@@ -7,6 +7,7 @@
#include "helpers/varlist/VarList.hpp" #include "helpers/varlist/VarList.hpp"
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../xwayland/XWayland.hpp" #include "../xwayland/XWayland.hpp"
#include "../protocols/OutputManagement.hpp"
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
@@ -376,6 +377,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY});
m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8});
@@ -445,6 +447,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("dwindle:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:no_gaps_when_only", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:use_active_for_splits", Hyprlang::INT{1}); m_pConfig->addConfigValue("dwindle:use_active_for_splits", Hyprlang::INT{1});
m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f}); m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f});
m_pConfig->addConfigValue("dwindle:split_bias", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:smart_split", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:smart_split", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:smart_resizing", Hyprlang::INT{1}); m_pConfig->addConfigValue("dwindle:smart_resizing", Hyprlang::INT{1});
@@ -683,6 +686,10 @@ std::string CConfigManager::getMainConfigPath() {
if (!g_pCompositor->explicitConfigPath.empty()) if (!g_pCompositor->explicitConfigPath.empty())
return g_pCompositor->explicitConfigPath; return g_pCompositor->explicitConfigPath;
if (const auto CFG_ENV = getenv("HYPRLAND_CONFIG"); CFG_ENV)
return CFG_ENV;
Debug::log(TRACE, "Seems as if HYPRLAND_CONFIG isn't set, let's see what we can do with HOME.");
static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland"); static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland");
if (paths.first.has_value()) { if (paths.first.has_value()) {
return paths.first.value(); return paths.first.value();
@@ -860,7 +867,9 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
if (result.error && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:suppress_errors"))) if (result.error && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:suppress_errors")))
g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1) else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1)
g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland", g_pHyprError->queueCreate(
"Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() +
" )\nSUPER+Q -> kitty (if it doesn't launch, make sure it's installed or choose a different terminal in the config)\nSUPER+M -> exit Hyprland",
CColor(1.0, 1.0, 70.0 / 255.0, 1.0)); CColor(1.0, 1.0, 70.0 / 255.0, 1.0));
else if (*PENABLEEXPLICIT != prevEnabledExplicit) else if (*PENABLEEXPLICIT != prevEnabledExplicit)
g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
@@ -1075,28 +1084,69 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s
return VAL; return VAL;
} }
SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { SMonitorRule CConfigManager::getMonitorRuleFor(const SP<CMonitor> PMONITOR) {
auto applyWlrOutputConfig = [PMONITOR](SMonitorRule rule) -> SMonitorRule {
const auto CONFIG = PROTO::outputManagement->getOutputStateFor(PMONITOR);
if (!CONFIG)
return rule;
Debug::log(LOG, "CConfigManager::getMonitorRuleFor: found a wlr_output_manager override for {}", PMONITOR->szName);
Debug::log(LOG, " > overriding enabled: {} -> {}", !rule.disabled, !CONFIG->enabled);
rule.disabled = !CONFIG->enabled;
if ((CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_MODE) || (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE)) {
Debug::log(LOG, " > overriding mode: {:.0f}x{:.0f}@{:.2f}Hz -> {:.0f}x{:.0f}@{:.2f}Hz", rule.resolution.x, rule.resolution.y, rule.refreshRate, CONFIG->resolution.x,
CONFIG->resolution.y, CONFIG->refresh / 1000.F);
rule.resolution = CONFIG->resolution;
rule.refreshRate = CONFIG->refresh / 1000.F;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) {
Debug::log(LOG, " > overriding offset: {:.0f}, {:.0f} -> {:.0f}, {:.0f}", rule.offset.x, rule.offset.y, CONFIG->position.x, CONFIG->position.y);
rule.offset = CONFIG->position;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) {
Debug::log(LOG, " > overriding transform: {} -> {}", (uint8_t)rule.transform, (uint8_t)CONFIG->transform);
rule.transform = CONFIG->transform;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) {
Debug::log(LOG, " > overriding scale: {} -> {}", (uint8_t)rule.scale, (uint8_t)CONFIG->scale);
rule.scale = CONFIG->scale;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
Debug::log(LOG, " > overriding vrr: {} -> {}", rule.vrr.value_or(0), CONFIG->adaptiveSync);
rule.vrr = (int)CONFIG->adaptiveSync;
}
return rule;
};
for (auto const& r : m_dMonitorRules | std::views::reverse) { for (auto const& r : m_dMonitorRules | std::views::reverse) {
if (PMONITOR.matchesStaticSelector(r.name)) { if (PMONITOR->matchesStaticSelector(r.name)) {
return r; return applyWlrOutputConfig(r);
} }
} }
Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName); Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR->szName);
for (auto const& r : m_dMonitorRules) { for (auto const& r : m_dMonitorRules) {
if (r.name.empty()) { if (r.name.empty()) {
return r; return applyWlrOutputConfig(r);
} }
} }
Debug::log(WARN, "No rules configured. Using the default hardcoded one."); Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
return SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT, return applyWlrOutputConfig(SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT,
.name = "", .name = "",
.resolution = Vector2D(0, 0), .resolution = Vector2D(0, 0),
.offset = Vector2D(-INT32_MAX, -INT32_MAX), .offset = Vector2D(-INT32_MAX, -INT32_MAX),
.scale = -1}; // 0, 0 is preferred and -1, -1 is auto .scale = -1}); // 0, 0 is preferred and -1, -1 is auto
} }
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) { SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) {
@@ -1455,7 +1505,7 @@ void CConfigManager::performMonitorReload() {
if (!m->output || m->isUnsafeFallback) if (!m->output || m->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(*m); auto rule = getMonitorRuleFor(m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
overAgain = true; overAgain = true;
@@ -1512,7 +1562,7 @@ void CConfigManager::ensureMonitorStatus() {
if (!rm->output || rm->isUnsafeFallback) if (!rm->output || rm->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(*rm); auto rule = getMonitorRuleFor(rm);
if (rule.disabled == rm->m_bEnabled) if (rule.disabled == rm->m_bEnabled)
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule); g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);

View File

@@ -169,7 +169,7 @@ class CConfigManager {
static std::string getMainConfigPath(); static std::string getMainConfigPath();
const std::string getConfigString(); const std::string getConfigString();
SMonitorRule getMonitorRuleFor(const CMonitor&); SMonitorRule getMonitorRuleFor(const SP<CMonitor>);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
std::string getDefaultWorkspaceFor(const std::string&); std::string getDefaultWorkspaceFor(const std::string&);

View File

@@ -268,5 +268,9 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# Example windowrule v2 # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
)#"; )#";

View File

@@ -103,6 +103,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"focused": {}, "focused": {},
"dpmsStatus": {}, "dpmsStatus": {},
"vrr": {}, "vrr": {},
"solitary": "{:x}",
"activelyTearing": {}, "activelyTearing": {},
"disabled": {}, "disabled": {},
"currentFormat": "{}", "currentFormat": "{}",
@@ -114,19 +115,20 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(),
escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(),
(m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat),
availableModesForOutput(m.get(), format));
} else { } else {
result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", "dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(),
!m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
} }
return result; return result;
@@ -158,16 +160,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
if (!m->output || m->ID == -1) if (!m->output || m->ID == -1)
continue; continue;
result += std::format( result += CHyprCtl::getMonitorData(m, format);
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: A {} H {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"),
(int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), m->tearingState.activelyTearing, !m->m_bEnabled,
formatToString(m->output->state->state().drmFormat), formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
} }
} }
@@ -334,11 +327,13 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : ""; const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : "";
const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : ""; const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : "";
const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : ""; const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : "";
const std::string defaultName = r.defaultName.has_value() ? std::format(",\n \"defaultName\": \"{}\"", escapeJSONStrings(r.defaultName.value())) : "";
std::string result = std::format(R"#({{ std::string result =
"workspaceString": "{}"{}{}{}{}{}{}{}{} std::format(R"#({{
"workspaceString": "{}"{}{}{}{}{}{}{}{}{}{}{}
}})#", }})#",
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow); escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow, defaultName);
return result; return result;
} else { } else {
@@ -356,9 +351,10 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>"); const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>");
const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>"); const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>");
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : "<unset>"); const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : "<unset>");
const std::string defaultName = std::format("\tdefaultName: {}\n", r.defaultName.value_or("<unset>"));
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow); borderSize, border, rounding, decorate, shadow, defaultName);
return result; return result;
} }
@@ -938,11 +934,14 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n"; result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
result += "plugins:\n"; result += "plugins:\n";
if (g_pPluginSystem) {
for (auto const& pl : g_pPluginSystem->getAllPlugins()) { for (auto const& pl : g_pPluginSystem->getAllPlugins()) {
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
} }
} else
result += "\tunknown: not runtime\n";
if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { if (g_pHyprCtl && g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) {
result += "\n======Config-Start======\n"; result += "\n======Config-Start======\n";
result += g_pConfigManager->getConfigString(); result += g_pConfigManager->getConfigString();
result += "\n======Config-End========\n"; result += "\n======Config-End========\n";
@@ -1624,6 +1623,14 @@ std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
return json; return json;
} }
std::string submapRequest(eHyprCtlOutputFormat format, std::string request) {
std::string submap = g_pKeybindManager->getCurrentSubmap();
if (submap.empty())
submap = "default";
return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n");
}
CHyprCtl::CHyprCtl() { CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
@@ -1645,6 +1652,7 @@ CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest}); registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest});
registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions}); registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
registerCommand(SHyprCtlCommand{"submap", true, submapRequest});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});

View File

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

View File

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

View File

@@ -30,13 +30,7 @@ CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner)
} }
CSubsurface::~CSubsurface() { CSubsurface::~CSubsurface() {
hyprListener_newSubsurface.removeCallback(); ;
if (!m_pSubsurface)
return;
hyprListener_commitSubsurface.removeCallback();
hyprListener_destroySubsurface.removeCallback();
} }
void CSubsurface::initSignals() { void CSubsurface::initSignals() {

View File

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

View File

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

View File

@@ -178,13 +178,18 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (xkbState) if (xkbState)
xkb_state_unref(xkbState); xkb_state_unref(xkbState);
if (xkbSymState)
xkb_state_unref(xkbSymState);
xkbState = nullptr; xkbState = nullptr;
xkbStaticState = nullptr; xkbStaticState = nullptr;
xkbSymState = nullptr;
if (keymap) { if (keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
xkbStaticState = xkb_state_new(keymap); xkbStaticState = xkb_state_new(keymap);
xkbState = xkb_state_new(keymap); xkbState = xkb_state_new(keymap);
xkbSymState = xkb_state_new(keymap);
return; return;
} }
@@ -230,6 +235,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkbState = xkb_state_new(KEYMAP); xkbState = xkb_state_new(KEYMAP);
xkbStaticState = xkb_state_new(KEYMAP); xkbStaticState = xkb_state_new(KEYMAP);
xkbSymState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP); xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
@@ -252,6 +258,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkbState = xkb_state_new(NEWKEYMAP); xkbState = xkb_state_new(NEWKEYMAP);
xkbStaticState = xkb_state_new(NEWKEYMAP); xkbStaticState = xkb_state_new(NEWKEYMAP);
xkbSymState = xkb_state_new(NEWKEYMAP);
xkb_keymap_unref(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
@@ -332,6 +339,9 @@ void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t l
xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group); xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group);
if (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, group);
if (!updateModifiersState()) if (!updateModifiersState())
return; return;
@@ -382,6 +392,9 @@ void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
if (updateModifiersState()) { if (updateModifiersState()) {
if (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, modifiersState.group);
keyboardEvents.modifiers.emit(SModifiersEvent{ keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed, .depressed = modifiersState.depressed,
.latched = modifiersState.latched, .latched = modifiersState.latched,

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
@@ -83,7 +82,8 @@ class IKeyboard : public IHID {
bool keymapOverridden = false; bool keymapOverridden = false;
xkb_layout_index_t activeLayout = 0; xkb_layout_index_t activeLayout = 0;
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr; xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr,
*xkbSymState = nullptr /* Same as static but gets layouts */;
xkb_keymap* xkbKeymap = nullptr; xkb_keymap* xkbKeymap = nullptr;
struct { struct {

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"

View File

@@ -322,7 +322,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->updateWindowData(); PWINDOW->updateWindowData();
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
PWINDOW->m_bCreatedOverFullscreen = true; PWINDOW->m_bCreatedOverFullscreen = true;
// size and move rules // size and move rules

View File

@@ -0,0 +1,54 @@
#pragma once
#include <type_traits>
#define ULL unsigned long long
#define LD long double
constexpr ULL operator""_kB(const ULL BYTES) {
return BYTES * 1024;
}
constexpr ULL operator""_MB(const ULL BYTES) {
return BYTES * 1024 * 1024;
}
constexpr ULL operator""_GB(const ULL BYTES) {
return BYTES * 1024 * 1024 * 1024;
}
constexpr ULL operator""_TB(const ULL BYTES) {
return BYTES * 1024 * 1024 * 1024 * 1024;
}
constexpr LD operator""_kB(const LD BYTES) {
return BYTES * 1024;
}
constexpr LD operator""_MB(const LD BYTES) {
return BYTES * 1024 * 1024;
}
constexpr LD operator""_GB(const LD BYTES) {
return BYTES * 1024 * 1024 * 1024;
}
constexpr LD operator""_TB(const LD BYTES) {
return BYTES * 1024 * 1024 * 1024 * 1024;
}
template <typename T>
using __acceptable_byte_operation_type = typename std::enable_if<std::is_trivially_constructible<T, ULL>::value || std::is_trivially_constructible<T, LD>::value>::type;
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X kBtoBytes(const X kB) {
return kB * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X MBtoBytes(const X MB) {
return MB * 1024 * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X GBtoBytes(const X GB) {
return GB * 1024 * 1024 * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X TBtoBytes(const X TB) {
return TB * 1024 * 1024 * 1024 * 1024;
}
#undef ULL
#undef LD

View File

@@ -10,6 +10,7 @@ class CColor {
float r = 0, g = 0, b = 0, a = 1.f; float r = 0, g = 0, b = 0, a = 1.f;
// AR32
uint32_t getAsHex() const; uint32_t getAsHex() const;
CColor operator-(const CColor& c2) const { CColor operator-(const CColor& c2) const {

View File

@@ -628,27 +628,6 @@ void logSystemInfo() {
Debug::log(NONE, "{}", execAndGet("cat /etc/os-release")); Debug::log(NONE, "{}", execAndGet("cat /etc/os-release"));
} }
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
memset(mat, 0, sizeof(*mat) * 9);
const float* t = transforms[tr];
float x = 2.0f / w;
float y = 2.0f / h;
// Rotation + reflection
mat[0] = x * t[0];
mat[1] = x * t[1];
mat[3] = y * t[3];
mat[4] = y * t[4];
// Translation
mat[2] = -copysign(1.0f, mat[0] + mat[1]);
mat[5] = -copysign(1.0f, mat[3] + mat[4]);
// Identity
mat[8] = 1.0f;
}
int64_t getPPIDof(int64_t pid) { int64_t getPPIDof(int64_t pid) {
#if defined(KERN_PROC_PID) #if defined(KERN_PROC_PID)
int mib[] = { int mib[] = {

View File

@@ -34,7 +34,6 @@ int64_t getPPIDof(int64_t pid);
int64_t configStringToInt(const std::string&); int64_t configStringToInt(const std::string&);
Vector2D configStringToVector2D(const std::string&); Vector2D configStringToVector2D(const std::string&);
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative); std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
double normalizeAngleRad(double ang); double normalizeAngleRad(double ang);
std::vector<SCallstackFrameInfo> getBacktrace(); std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err); void throwError(const std::string& err);

View File

@@ -12,6 +12,7 @@
#include "../protocols/DRMSyncobj.hpp" #include "../protocols/DRMSyncobj.hpp"
#include "../protocols/core/Output.hpp" #include "../protocols/core/Output.hpp"
#include "../managers/PointerManager.hpp" #include "../managers/PointerManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "sync/SyncTimeline.hpp" #include "sync/SyncTimeline.hpp"
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
@@ -35,6 +36,7 @@ CMonitor::~CMonitor() {
} }
void CMonitor::onConnect(bool noRule) { void CMonitor::onConnect(bool noRule) {
CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }};
if (output->supportsExplicit) { if (output->supportsExplicit) {
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
@@ -114,7 +116,7 @@ void CMonitor::onConnect(bool noRule) {
createdByUser = true; // should be true. WL and Headless backends should be addable / removable createdByUser = true; // should be true. WL and Headless backends should be addable / removable
// get monitor rule that matches // get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this); SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(self.lock());
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { if (monitorRule.disabled) {
@@ -228,6 +230,13 @@ void CMonitor::onConnect(bool noRule) {
} }
void CMonitor::onDisconnect(bool destroy) { void CMonitor::onDisconnect(bool destroy) {
CScopeGuard x = {[this]() {
if (g_pCompositor->m_bIsShuttingDown)
return;
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", this);
g_pCompositor->arrangeMonitors();
}};
if (renderTimer) { if (renderTimer) {
wl_event_source_remove(renderTimer); wl_event_source_remove(renderTimer);
@@ -340,9 +349,6 @@ void CMonitor::onDisconnect(bool destroy) {
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
} }
std::erase_if(g_pCompositor->m_vMonitors, [&](SP<CMonitor>& el) { return el.get() == this; }); std::erase_if(g_pCompositor->m_vMonitors, [&](SP<CMonitor>& el) { return el.get() == this; });
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", this);
} }
void CMonitor::addDamage(const pixman_region32_t* rg) { void CMonitor::addDamage(const pixman_region32_t* rg) {
@@ -489,7 +495,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = nullptr; pMirrorOf = nullptr;
// set rule // set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(*this); const auto RULE = g_pConfigManager->getMonitorRuleFor(self.lock());
vecPosition = RULE.offset; vecPosition = RULE.offset;
@@ -772,12 +778,9 @@ Vector2D CMonitor::middle() {
} }
void CMonitor::updateMatrix() { void CMonitor::updateMatrix() {
matrixIdentity(projMatrix.data()); projMatrix = Mat3x3::identity();
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { if (transform != WL_OUTPUT_TRANSFORM_NORMAL)
matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0); projMatrix.translate(vecPixelSize / 2.0).transform(wlTransformToHyprutils(transform)).translate(-vecTransformedSize / 2.0);
matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform));
matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
}
} }
WORKSPACEID CMonitor::activeWorkspaceID() { WORKSPACEID CMonitor::activeWorkspaceID() {
@@ -792,20 +795,22 @@ CBox CMonitor::logicalBox() {
return {vecPosition, vecSize}; return {vecPosition, vecSize};
} }
static void onDoneSource(void* data) {
auto pMonitor = (CMonitor*)data;
if (!PROTO::outputs.contains(pMonitor->szName))
return;
PROTO::outputs.at(pMonitor->szName)->sendDone();
}
void CMonitor::scheduleDone() { void CMonitor::scheduleDone() {
if (doneSource) if (doneScheduled)
return; return;
doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this); doneScheduled = true;
g_pEventLoopManager->doLater([M = self] {
if (!M) // if M is gone, we got destroyed, doesn't matter.
return;
if (!PROTO::outputs.contains(M->szName))
return;
PROTO::outputs.at(M->szName)->sendDone();
M->doneScheduled = false;
});
} }
bool CMonitor::attemptDirectScanout() { bool CMonitor::attemptDirectScanout() {

View File

@@ -96,7 +96,7 @@ class CMonitor {
bool scheduledRecalc = false; bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float xwaylandScale = 1.f; float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0}; Mat3x3 projMatrix;
std::optional<Vector2D> forceSize; std::optional<Vector2D> forceSize;
SP<Aquamarine::SOutputMode> currentMode; SP<Aquamarine::SOutputMode> currentMode;
SP<Aquamarine::CSwapchain> cursorSwapchain; SP<Aquamarine::CSwapchain> cursorSwapchain;
@@ -193,7 +193,7 @@ class CMonitor {
void setupDefaultWS(const SMonitorRule&); void setupDefaultWS(const SMonitorRule&);
WORKSPACEID findAvailableDefaultWS(); WORKSPACEID findAvailableDefaultWS();
wl_event_source* doneSource = nullptr; bool doneScheduled = false;
struct { struct {
CHyprSignalListener frame; CHyprSignalListener frame;

View File

@@ -8,6 +8,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <cstring> #include <cstring>
namespace Systemd { namespace Systemd {

View File

@@ -1,62 +0,0 @@
#include "WLListener.hpp"
#include "MiscFunctions.hpp"
#include <string>
#include "../debug/Log.hpp"
#include "Watchdog.hpp"
void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
if (g_pWatchdog)
g_pWatchdog->startWatching();
try {
pWrap->m_pSelf->emit(data);
} catch (std::exception& e) { Debug::log(ERR, "Listener {} threw or timed out and was killed by Watchdog!!! This is bad. what(): {}", (uintptr_t)listener, e.what()); }
if (g_pWatchdog)
g_pWatchdog->endWatching();
}
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> const& callback, void* pOwner) {
initCallback(pSignal, callback, pOwner);
}
CHyprWLListener::CHyprWLListener() {
m_swWrapper.m_pSelf = this;
m_swWrapper.m_sListener.notify = &handleWrapped;
wl_list_init(&m_swWrapper.m_sListener.link);
}
CHyprWLListener::~CHyprWLListener() {
removeCallback();
}
void CHyprWLListener::removeCallback() {
if (isConnected()) {
Debug::log(LOG, "Callback {:x} -> {:x}, {} removed.", (uintptr_t)&m_pCallback, (uintptr_t)&m_pOwner, m_szAuthor);
wl_list_remove(&m_swWrapper.m_sListener.link);
wl_list_init(&m_swWrapper.m_sListener.link);
}
}
bool CHyprWLListener::isConnected() {
return !wl_list_empty(&m_swWrapper.m_sListener.link);
}
void CHyprWLListener::initCallback(wl_signal* pSignal, std::function<void(void*, void*)> const& callback, void* pOwner, std::string author) {
if (isConnected()) {
Debug::log(ERR, "Tried to connect a listener twice?!");
return;
}
m_pOwner = pOwner;
m_pCallback = callback;
m_szAuthor = author;
addWLSignal(pSignal, &m_swWrapper.m_sListener, pOwner, m_szAuthor);
}
void CHyprWLListener::emit(void* data) {
m_pCallback(m_pOwner, data);
}

View File

@@ -1,39 +0,0 @@
#pragma once
#include <string>
#include <functional>
#include <wayland-server.h>
class CHyprWLListener {
public:
CHyprWLListener(wl_signal*, std::function<void(void*, void*)> const&, void* owner);
CHyprWLListener();
~CHyprWLListener();
CHyprWLListener(const CHyprWLListener&) = delete;
CHyprWLListener(CHyprWLListener&&) = delete;
CHyprWLListener& operator=(const CHyprWLListener&) = delete;
CHyprWLListener& operator=(CHyprWLListener&&) = delete;
void initCallback(wl_signal*, std::function<void(void*, void*)> const&, void* owner, std::string author = "");
void removeCallback();
bool isConnected();
struct SWrapper {
wl_listener m_sListener;
CHyprWLListener* m_pSelf;
};
void emit(void*);
private:
SWrapper m_swWrapper;
void* m_pOwner = nullptr;
std::function<void(void*, void*)> m_pCallback = nullptr;
std::string m_szAuthor = "";
};

View File

@@ -1,6 +1,4 @@
#include "Math.hpp" #include "Math.hpp"
#include <unordered_map>
#include <cstring>
Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) {
switch (t) { switch (t) {
@@ -17,124 +15,6 @@ Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) {
return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL;
} }
void matrixIdentity(float mat[9]) {
static const float identity[9] = {
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
};
memcpy(mat, identity, sizeof(identity));
}
void matrixMultiply(float mat[9], const float a[9], const float b[9]) {
float product[9];
product[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6];
product[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7];
product[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8];
product[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6];
product[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7];
product[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8];
product[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6];
product[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7];
product[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8];
memcpy(mat, product, sizeof(product));
}
void matrixTranspose(float mat[9], const float a[9]) {
float transposition[9] = {
a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8],
};
memcpy(mat, transposition, sizeof(transposition));
}
void matrixTranslate(float mat[9], float x, float y) {
float translate[9] = {
1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f,
};
matrixMultiply(mat, mat, translate);
}
void matrixScale(float mat[9], float x, float y) {
float scale[9] = {
x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f,
};
matrixMultiply(mat, mat, scale);
}
void matrixRotate(float mat[9], float rad) {
float rotate[9] = {
cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f,
};
matrixMultiply(mat, mat, rotate);
}
const std::unordered_map<eTransform, std::array<float, 9>>& getTransforms() {
static std::unordered_map<eTransform, std::array<float, 9>> transforms = {
{HYPRUTILS_TRANSFORM_NORMAL, {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_90, {0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_180, {-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_270, {0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED, {-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED_90, {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED_180, {1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED_270, {0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
};
return transforms;
}
void matrixTransform(float mat[9], eTransform transform) {
matrixMultiply(mat, mat, getTransforms().at(transform).data());
}
void matrixProjection(float mat[9], int width, int height, eTransform transform) {
memset(mat, 0, sizeof(*mat) * 9);
const float* t = getTransforms().at(transform).data();
float x = 2.0f / width;
float y = 2.0f / height;
// Rotation + reflection
mat[0] = x * t[0];
mat[1] = x * t[1];
mat[3] = y * -t[3];
mat[4] = y * -t[4];
// Translation
mat[2] = -copysign(1.0f, mat[0] + mat[1]);
mat[5] = -copysign(1.0f, mat[3] + mat[4]);
// Identity
mat[8] = 1.0f;
}
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]) {
double x = box.x;
double y = box.y;
double width = box.width;
double height = box.height;
matrixIdentity(mat);
matrixTranslate(mat, x, y);
if (rotation != 0) {
matrixTranslate(mat, width / 2, height / 2);
matrixRotate(mat, rotation);
matrixTranslate(mat, -width / 2, -height / 2);
}
matrixScale(mat, width, height);
if (transform != HYPRUTILS_TRANSFORM_NORMAL) {
matrixTranslate(mat, 0.5, 0.5);
matrixTransform(mat, transform);
matrixTranslate(mat, -0.5, -0.5);
}
matrixMultiply(mat, projection, mat);
}
wl_output_transform invertTransform(wl_output_transform tr) { wl_output_transform invertTransform(wl_output_transform tr) {
if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED)) if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED))
tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180); tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180);

View File

@@ -4,17 +4,9 @@
// includes box and vector as well // includes box and vector as well
#include <hyprutils/math/Region.hpp> #include <hyprutils/math/Region.hpp>
#include <hyprutils/math/Mat3x3.hpp>
using namespace Hyprutils::Math; using namespace Hyprutils::Math;
eTransform wlTransformToHyprutils(wl_output_transform t); eTransform wlTransformToHyprutils(wl_output_transform t);
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]);
void matrixProjection(float mat[9], int width, int height, eTransform transform);
void matrixTransform(float mat[9], eTransform transform);
void matrixRotate(float mat[9], float rad);
void matrixScale(float mat[9], float x, float y);
void matrixTranslate(float mat[9], float x, float y);
void matrixTranspose(float mat[9], const float a[9]);
void matrixMultiply(float mat[9], const float a[9], const float b[9]);
void matrixIdentity(float mat[9]);
wl_output_transform invertTransform(wl_output_transform tr); wl_output_transform invertTransform(wl_output_transform tr);

View File

@@ -1,7 +1,7 @@
#include "DwindleLayout.hpp" #include "DwindleLayout.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) { void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) {
if (children[0]) { if (children[0]) {
@@ -340,26 +340,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
return; return;
} }
// if it's a group, add the window // get the node under our cursor
if (OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow.lock()) && !m_vOverrideFocalPoint) { // we are not moving window
m_lDwindleNodesData.remove(*PNODE);
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return;
}
// If it's not, get the node under our cursor
m_lDwindleNodesData.push_back(SDwindleNodeData()); m_lDwindleNodesData.push_back(SDwindleNodeData());
const auto NEWPARENT = &m_lDwindleNodesData.back(); const auto NEWPARENT = &m_lDwindleNodesData.back();
@@ -459,6 +440,12 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
} }
} }
// split in favor of a specific window
const auto first = NEWPARENT->children[0];
static auto PSPLITBIAS = CConfigValue<Hyprlang::INT>("dwindle:split_bias");
if ((*PSPLITBIAS == 1 && first == PNODE) || (*PSPLITBIAS == 2 && first == OPENINGON))
NEWPARENT->splitRatio = 2.f - NEWPARENT->splitRatio;
// and update the previous parent if it exists // and update the previous parent if it exists
if (OPENINGON->pParent) { if (OPENINGON->pParent) {
if (OPENINGON->pParent->children[0] == OPENINGON) { if (OPENINGON->pParent->children[0] == OPENINGON) {
@@ -992,6 +979,10 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str
toggleSplit(header.pWindow); toggleSplit(header.pWindow);
} else if (ARGS[0] == "swapsplit") { } else if (ARGS[0] == "swapsplit") {
swapSplit(header.pWindow); swapSplit(header.pWindow);
} else if (ARGS[0] == "movetoroot") {
const auto WINDOW = ARGS[1].empty() ? header.pWindow : g_pCompositor->getWindowByRegex(ARGS[1]);
const auto STABLE = ARGS[2].empty() || ARGS[2] != "unstable";
moveToRoot(WINDOW, STABLE);
} else if (ARGS[0] == "preselect") { } else if (ARGS[0] == "preselect") {
std::string direction = ARGS[1]; std::string direction = ARGS[1];
@@ -1059,6 +1050,44 @@ void CHyprDwindleLayout::swapSplit(PHLWINDOW pWindow) {
PNODE->pParent->recalcSizePosRecursive(); PNODE->pParent->recalcSizePosRecursive();
} }
// goal: maximize the chosen window within current dwindle layout
// impl: swap the selected window with the other sub-tree below root
void CHyprDwindleLayout::moveToRoot(PHLWINDOW pWindow, bool stable) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE || !PNODE->pParent)
return;
if (pWindow->isFullscreen())
return;
// already at root
if (!PNODE->pParent->pParent)
return;
auto& pNode = PNODE->pParent->children[0] == PNODE ? PNODE->pParent->children[0] : PNODE->pParent->children[1];
// instead of [getMasterNodeOnWorkspace], we walk back to root since we need
// to know which children of root is our ancestor
auto pAncestor = PNODE, pRoot = PNODE->pParent;
while (pRoot->pParent) {
pAncestor = pRoot;
pRoot = pRoot->pParent;
}
auto& pSwap = pRoot->children[0] == pAncestor ? pRoot->children[1] : pRoot->children[0];
std::swap(pNode, pSwap);
std::swap(pNode->pParent, pSwap->pParent);
// [stable] in that the focused window occupies same side of screen
if (stable)
std::swap(pRoot->children[0], pRoot->children[1]);
// if the workspace is visible, recalculate layout
if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace))
pRoot->recalcSizePosRecursive();
}
void CHyprDwindleLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) { void CHyprDwindleLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) {
const auto PNODE = getNodeFromWindow(from); const auto PNODE = getNodeFromWindow(from);

View File

@@ -87,6 +87,7 @@ class CHyprDwindleLayout : public IHyprLayout {
void toggleSplit(PHLWINDOW); void toggleSplit(PHLWINDOW);
void swapSplit(PHLWINDOW); void swapSplit(PHLWINDOW);
void moveToRoot(PHLWINDOW, bool stable = true);
eDirection overrideDirection = DIRECTION_DEFAULT; eDirection overrideDirection = DIRECTION_DEFAULT;

View File

@@ -9,24 +9,26 @@
#include "../xwayland/XSurface.hpp" #include "../xwayland/XSurface.hpp"
void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) {
onWindowCreatedFloating(pWindow);
} else {
CBox desiredGeometry = {}; CBox desiredGeometry = {};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f; pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f;
} else { } else
pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height); pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
}
pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize; pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize;
bool autoGrouped = IHyprLayout::onWindowCreatedAutoGroup(pWindow);
if (autoGrouped)
return;
if (pWindow->m_bIsFloating)
onWindowCreatedFloating(pWindow);
else
onWindowCreatedTiling(pWindow, direction); onWindowCreatedTiling(pWindow, direction);
} }
}
void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) { void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) {
if (pWindow->isFullscreen()) if (pWindow->isFullscreen())
@@ -178,6 +180,48 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
} }
} }
bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) {
static auto PAUTOGROUP = CConfigValue<Hyprlang::INT>("group:auto_group");
PHLWINDOW OPENINGON = g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ?
g_pCompositor->m_pLastWindow.lock() :
g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID());
if ((*PAUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group.
&& OPENINGON // check if OPENINGON exists.
&& OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group.
&& OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group
&& pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON
&& !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated.
switch (pWindow->m_bIsFloating) {
case false:
if (OPENINGON->m_bIsFloating)
pWindow->m_bIsFloating = true;
break;
case true:
if (!OPENINGON->m_bIsFloating)
pWindow->m_bIsFloating = false;
break;
}
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return true;
}
return false;
}
void IHyprLayout::onBeginDragWindow() { void IHyprLayout::onBeginDragWindow() {
const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock(); const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock();
@@ -509,10 +553,10 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
pWindow->m_vLastFloatingSize = PSAVEDSIZE; pWindow->m_vLastFloatingSize = PSAVEDSIZE;
// move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back. // move to narnia because we don't wanna find our own node. onWindowCreated should apply the coords back.
pWindow->m_vPosition = Vector2D(-999999, -999999); pWindow->m_vPosition = Vector2D(-999999, -999999);
onWindowCreatedTiling(pWindow); onWindowCreated(pWindow);
pWindow->m_vRealPosition.setValue(PSAVEDPOS); pWindow->m_vRealPosition.setValue(PSAVEDPOS);
pWindow->m_vRealSize.setValue(PSAVEDSIZE); pWindow->m_vRealSize.setValue(PSAVEDSIZE);

View File

@@ -47,6 +47,7 @@ class IHyprLayout {
virtual void onWindowCreated(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowCreated(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT) = 0; virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT) = 0;
virtual void onWindowCreatedFloating(PHLWINDOW); virtual void onWindowCreatedFloating(PHLWINDOW);
virtual bool onWindowCreatedAutoGroup(PHLWINDOW);
/* /*
Return tiled status Return tiled status

View File

@@ -116,26 +116,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
return; return;
} }
// if it's a group, add the window
if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow.lock())) {
m_lMasterNodesData.remove(*PNODE);
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return;
}
pWindow->applyGroupRules(); pWindow->applyGroupRules();
static auto PDROPATCURSOR = CConfigValue<Hyprlang::INT>("master:drop_at_cursor"); static auto PDROPATCURSOR = CConfigValue<Hyprlang::INT>("master:drop_at_cursor");

View File

@@ -3,6 +3,7 @@
#include "Compositor.hpp" #include "Compositor.hpp"
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "init/initHelpers.hpp" #include "init/initHelpers.hpp"
#include "debug/HyprCtl.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
@@ -133,6 +134,10 @@ int main(int argc, char** argv) {
std::cout << result; std::cout << result;
return 0; return 0;
} else if (it->compare("--systeminfo") == 0) {
const auto SYSINFO = systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "");
std::cout << SYSINFO << "\n";
return 0;
} else { } else {
std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n"; std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n";
help(); help();

View File

@@ -376,7 +376,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbState : m_pXKBTranslationState, KEYCODE); const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbSymState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE);
if (handleInternalKeybinds(internalKeysym)) if (handleInternalKeybinds(internalKeysym))
@@ -594,6 +594,10 @@ eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) {
return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys); return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys);
} }
std::string CKeybindManager::getCurrentSubmap() {
return m_szCurrentSelectedSubmap;
}
SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) {
static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing"); static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
bool found = false; bool found = false;
@@ -1939,7 +1943,7 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) {
if (!m->output) if (!m->output)
continue; continue;
auto rule = g_pConfigManager->getMonitorRuleFor(*m); auto rule = g_pConfigManager->getMonitorRuleFor(m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) { if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) {
overAgain = true; overAgain = true;
break; break;
@@ -2399,9 +2403,7 @@ SDispatchResult CKeybindManager::dpms(std::string arg) {
bool enable = arg.starts_with("on"); bool enable = arg.starts_with("on");
std::string port = ""; std::string port = "";
if (arg.starts_with("toggle")) bool isToggle = arg.starts_with("toggle");
enable = !std::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return !other->dpmsStatus; }); // enable if any is off
if (arg.find_first_of(' ') != std::string::npos) if (arg.find_first_of(' ') != std::string::npos)
port = arg.substr(arg.find_first_of(' ') + 1); port = arg.substr(arg.find_first_of(' ') + 1);
@@ -2410,6 +2412,9 @@ SDispatchResult CKeybindManager::dpms(std::string arg) {
if (!port.empty() && m->szName != port) if (!port.empty() && m->szName != port)
continue; continue;
if (isToggle)
enable = !m->dpmsStatus;
m->output->state->resetExplicitFences(); m->output->state->resetExplicitFences();
m->output->state->setEnabled(enable); m->output->state->setEnabled(enable);

View File

@@ -96,6 +96,7 @@ class CKeybindManager {
uint32_t keycodeToModifier(xkb_keycode_t); uint32_t keycodeToModifier(xkb_keycode_t);
void clearKeybinds(); void clearKeybinds();
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0); void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0);
std::string getCurrentSubmap();
std::unordered_map<std::string, std::function<SDispatchResult(std::string)>> m_mDispatchers; std::unordered_map<std::string, std::function<SDispatchResult(std::string)>> m_mDispatchers;

View File

@@ -17,10 +17,8 @@ CPointerManager::CPointerManager() {
onMonitorLayoutChange(); onMonitorLayoutChange();
PMONITOR->events.modeChanged.registerStaticListener( PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr);
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.disconnect.registerStaticListener(
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.destroy.registerStaticListener( PMONITOR->events.destroy.registerStaticListener(
[this](void* owner, std::any data) { [this](void* owner, std::any data) {
if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown)
@@ -659,7 +657,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) {
} }
void CPointerManager::damageIfSoftware() { void CPointerManager::damageIfSoftware() {
auto b = getCursorBoxGlobal(); auto b = getCursorBoxGlobal().expand(4);
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors"); static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");

View File

@@ -44,6 +44,7 @@
#include "../protocols/TextInputV1.hpp" #include "../protocols/TextInputV1.hpp"
#include "../protocols/GlobalShortcuts.hpp" #include "../protocols/GlobalShortcuts.hpp"
#include "../protocols/XDGDialog.hpp" #include "../protocols/XDGDialog.hpp"
#include "../protocols/SinglePixel.hpp"
#include "../protocols/core/Seat.hpp" #include "../protocols/core/Seat.hpp"
#include "../protocols/core/DataDevice.hpp" #include "../protocols/core/DataDevice.hpp"
@@ -85,7 +86,8 @@ CProtocolManager::CProtocolManager() {
// ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after // ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after
// this event is emitted iirc. // this event is emitted iirc.
if (M->isMirror()) // also ignore the fallback
if (M->isMirror() || M == g_pCompositor->m_pUnsafeOutput)
return; return;
if (PROTO::outputs.contains(M->szName)) if (PROTO::outputs.contains(M->szName))
@@ -152,6 +154,7 @@ CProtocolManager::CProtocolManager() {
PROTO::toplevelExport = std::make_unique<CToplevelExportProtocol>(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::toplevelExport = std::make_unique<CToplevelExportProtocol>(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport");
PROTO::globalShortcuts = std::make_unique<CGlobalShortcutsProtocol>(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); PROTO::globalShortcuts = std::make_unique<CGlobalShortcutsProtocol>(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts");
PROTO::xdgDialog = std::make_unique<CXDGDialogProtocol>(&xdg_dialog_v1_interface, 1, "XDGDialog"); PROTO::xdgDialog = std::make_unique<CXDGDialogProtocol>(&xdg_dialog_v1_interface, 1, "XDGDialog");
PROTO::singlePixel = std::make_unique<CSinglePixelProtocol>(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel");
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)

View File

@@ -2,7 +2,6 @@
#include <cstdint> #include <cstdint>
#include <wayland-server-protocol.h> #include <wayland-server-protocol.h>
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"

View File

@@ -50,6 +50,10 @@ void CEventLoopManager::enterLoop() {
m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get()));
} }
// if we have a session, dispatch it to get the pending input devices
if (g_pCompositor->m_pAqBackend->hasSession())
g_pCompositor->m_pAqBackend->session->dispatchPendingEventsAsync();
wl_display_run(m_sWayland.display); wl_display_run(m_sWayland.display);
Debug::log(LOG, "Kicked off the event loop! :("); Debug::log(LOG, "Kicked off the event loop! :(");

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include "../../helpers/WLListener.hpp"
#include "../../desktop/WLSurface.hpp" #include "../../desktop/WLSurface.hpp"
#include "../../macros.hpp" #include "../../macros.hpp"
#include "../../helpers/math/Math.hpp" #include "../../helpers/math/Math.hpp"

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include "../../helpers/WLListener.hpp"
#include "../../macros.hpp" #include "../../macros.hpp"
#include "../../helpers/math/Math.hpp" #include "../../helpers/math/Math.hpp"
#include "../../helpers/signal/Signal.hpp" #include "../../helpers/signal/Signal.hpp"

View File

@@ -16,7 +16,7 @@ executable(
dependency('cairo'), dependency('cairo'),
dependency('hyprcursor', version: '>=0.1.7'), dependency('hyprcursor', version: '>=0.1.7'),
dependency('hyprlang', version: '>= 0.3.2'), dependency('hyprlang', version: '>= 0.3.2'),
dependency('hyprutils', version: '>= 0.2.1'), dependency('hyprutils', version: '>= 0.2.3'),
dependency('libdrm'), dependency('libdrm'),
dependency('egl'), dependency('egl'),
dependency('xkbcommon'), dependency('xkbcommon'),
@@ -31,7 +31,12 @@ executable(
backtrace_dep, backtrace_dep,
epoll_dep, epoll_dep,
gio_dep, gio_dep,
udis86, tracy,
# Try to find canihavesomecoffee's udis86 using pkgconfig
# vmt/udis86 does not provide a .pc file and won't be detected this way
# Falls back to using the subproject through udis86.wrap
dependency('udis86'),
dependency('pixman-1'), dependency('pixman-1'),
dependency('gl', 'opengl'), dependency('gl', 'opengl'),

View File

@@ -53,9 +53,6 @@ class CFocusGrab {
bool m_bGrabActive = false; bool m_bGrabActive = false;
DYNLISTENER(pointerGrabStarted);
DYNLISTENER(keyboardGrabStarted);
DYNLISTENER(touchGrabStarted);
friend class CFocusGrabSurfaceState; friend class CFocusGrabSurfaceState;
}; };

View File

@@ -307,10 +307,15 @@ COutputConfiguration::COutputConfiguration(SP<CZwlrOutputConfigurationV1> resour
LOGM(LOG, "disableHead on {}", PMONITOR->szName); LOGM(LOG, "disableHead on {}", PMONITOR->szName);
PMONITOR->activeMonitorRule.disabled = true; SWlrManagerSavedOutputState newState;
if (!g_pConfigManager->replaceMonitorRule(PMONITOR->activeMonitorRule)) if (owner->monitorStates.contains(PMONITOR->szName))
g_pConfigManager->appendMonitorRule(PMONITOR->activeMonitorRule); newState = owner->monitorStates.at(PMONITOR->szName);
g_pHyprRenderer->applyMonitorRule(PMONITOR, &PMONITOR->activeMonitorRule, false);
newState.enabled = false;
g_pConfigManager->m_bWantsMonitorReload = true;
owner->monitorStates[PMONITOR->szName] = newState;
}); });
resource->setTest([this](CZwlrOutputConfigurationV1* r) { resource->setTest([this](CZwlrOutputConfigurationV1* r) {
@@ -346,6 +351,11 @@ bool COutputConfiguration::applyTestConfiguration(bool test) {
LOGM(LOG, "Applying configuration"); LOGM(LOG, "Applying configuration");
if (!owner) {
LOGM(ERR, "applyTestConfiguration: no owner?!");
return false;
}
for (auto const& headw : heads) { for (auto const& headw : heads) {
auto head = headw.lock(); auto head = headw.lock();
@@ -357,41 +367,59 @@ bool COutputConfiguration::applyTestConfiguration(bool test) {
if (!PMONITOR) if (!PMONITOR)
continue; continue;
LOGM(LOG, "Applying config for monitor {}", PMONITOR->szName); LOGM(LOG, "Saving config for monitor {}", PMONITOR->szName);
SMonitorRule newRule = PMONITOR->activeMonitorRule; SWlrManagerSavedOutputState newState;
newRule.name = PMONITOR->szName; if (owner->monitorStates.contains(PMONITOR->szName))
newRule.disabled = false; newState = owner->monitorStates.at(PMONITOR->szName);
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { newState.enabled = true;
newRule.resolution = head->state.mode->getMode()->pixelSize;
newRule.refreshRate = head->state.mode->getMode()->refreshRate / 1000.F; if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) {
} else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { newState.resolution = head->state.mode->getMode()->pixelSize;
newRule.resolution = head->state.customMode.size; newState.refresh = head->state.mode->getMode()->refreshRate;
newRule.refreshRate = head->state.customMode.refresh / 1000.F; newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE;
LOGM(LOG, " > Mode: {:.0f}x{:.0f}@{}mHz", newState.resolution.x, newState.resolution.y, newState.refresh);
} else if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) {
newState.resolution = head->state.customMode.size;
newState.refresh = head->state.customMode.refresh;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE;
LOGM(LOG, " > Custom mode: {:.0f}x{:.0f}@{}mHz", newState.resolution.x, newState.resolution.y, newState.refresh);
} }
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION) if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION) {
newRule.offset = head->state.position; newState.position = head->state.position;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION;
LOGM(LOG, " > Position: {:.0f}, {:.0f}", head->state.position.x, head->state.position.y);
}
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
newRule.vrr = head->state.adaptiveSync; newState.adaptiveSync = head->state.adaptiveSync;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC;
LOGM(LOG, " > vrr: {}", newState.adaptiveSync);
}
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE) if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE) {
newRule.scale = head->state.scale; newState.scale = head->state.scale;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE;
LOGM(LOG, " > scale: {:.2f}", newState.scale);
}
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM) if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM) {
newRule.transform = head->state.transform; newState.transform = head->state.transform;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM;
LOGM(LOG, " > transform: {}", (uint8_t)newState.transform);
}
// reset properties for next set. // reset properties for next set.
head->committedProperties = 0; head->state.committedProperties = 0;
if (!g_pConfigManager->replaceMonitorRule(newRule))
g_pConfigManager->appendMonitorRule(newRule);
g_pConfigManager->m_bWantsMonitorReload = true; g_pConfigManager->m_bWantsMonitorReload = true;
owner->monitorStates[PMONITOR->szName] = newState;
} }
LOGM(LOG, "Applied configuration"); LOGM(LOG, "Saved configuration");
return true; return true;
} }
@@ -417,12 +445,12 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return; return;
} }
if (committedProperties & OUTPUT_HEAD_COMMITTED_MODE) { if (state.committedProperties & OUTPUT_HEAD_COMMITTED_MODE) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return; return;
} }
committedProperties |= OUTPUT_HEAD_COMMITTED_MODE; state.committedProperties |= OUTPUT_HEAD_COMMITTED_MODE;
state.mode = MODE; state.mode = MODE;
LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate); LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate);
@@ -434,17 +462,22 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return; return;
} }
if (committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { if (state.committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return; return;
} }
if (w <= 0 || h <= 0 || refresh <= 100) { if (w <= 0 || h <= 0 || refresh < 0) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE, "Invalid mode"); resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE, "Invalid mode");
return; return;
} }
committedProperties |= OUTPUT_HEAD_COMMITTED_CUSTOM_MODE; if (refresh == 0) {
LOGM(LOG, " | configHead for {}: refreshRate 0, using old refresh rate of {:.2f}Hz", pMonitor->szName, pMonitor->refreshRate);
refresh = std::round(pMonitor->refreshRate * 1000.F);
}
state.committedProperties |= OUTPUT_HEAD_COMMITTED_CUSTOM_MODE;
state.customMode = {{w, h}, (uint32_t)refresh}; state.customMode = {{w, h}, (uint32_t)refresh};
LOGM(LOG, " | configHead for {}: set custom mode to {}x{}@{}", pMonitor->szName, w, h, refresh); LOGM(LOG, " | configHead for {}: set custom mode to {}x{}@{}", pMonitor->szName, w, h, refresh);
@@ -456,12 +489,12 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return; return;
} }
if (committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) { if (state.committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return; return;
} }
committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION; state.committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION;
state.position = {x, y}; state.position = {x, y};
LOGM(LOG, " | configHead for {}: set pos to {}, {}", pMonitor->szName, x, y); LOGM(LOG, " | configHead for {}: set pos to {}, {}", pMonitor->szName, x, y);
@@ -473,7 +506,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return; return;
} }
if (committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) { if (state.committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return; return;
} }
@@ -483,7 +516,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return; return;
} }
committedProperties |= OUTPUT_HEAD_COMMITTED_TRANSFORM; state.committedProperties |= OUTPUT_HEAD_COMMITTED_TRANSFORM;
state.transform = (wl_output_transform)transform; state.transform = (wl_output_transform)transform;
LOGM(LOG, " | configHead for {}: set transform to {}", pMonitor->szName, transform); LOGM(LOG, " | configHead for {}: set transform to {}", pMonitor->szName, transform);
@@ -495,7 +528,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return; return;
} }
if (committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) { if (state.committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return; return;
} }
@@ -507,7 +540,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return; return;
} }
committedProperties |= OUTPUT_HEAD_COMMITTED_SCALE; state.committedProperties |= OUTPUT_HEAD_COMMITTED_SCALE;
state.scale = scale; state.scale = scale;
LOGM(LOG, " | configHead for {}: set scale to {:.2f}", pMonitor->szName, scale); LOGM(LOG, " | configHead for {}: set scale to {:.2f}", pMonitor->szName, scale);
@@ -519,7 +552,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return; return;
} }
if (committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) { if (state.committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return; return;
} }
@@ -529,7 +562,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return; return;
} }
committedProperties |= OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC; state.committedProperties |= OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC;
state.adaptiveSync = as; state.adaptiveSync = as;
LOGM(LOG, " | configHead for {}: set adaptiveSync to {}", pMonitor->szName, as); LOGM(LOG, " | configHead for {}: set adaptiveSync to {}", pMonitor->szName, as);
@@ -601,3 +634,14 @@ SP<COutputMode> COutputManagementProtocol::modeFromResource(wl_resource* r) {
return nullptr; return nullptr;
} }
SP<SWlrManagerSavedOutputState> COutputManagementProtocol::getOutputStateFor(SP<CMonitor> pMonitor) {
for (auto const& m : m_vManagers) {
if (!m->monitorStates.contains(pMonitor->szName))
continue;
return makeShared<SWlrManagerSavedOutputState>(m->monitorStates.at(pMonitor->szName));
}
return nullptr;
}

View File

@@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include <unordered_map>
#include "WaylandProtocol.hpp" #include "WaylandProtocol.hpp"
#include "wlr-output-management-unstable-v1.hpp" #include "wlr-output-management-unstable-v1.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
@@ -13,6 +14,43 @@ class CMonitor;
class COutputHead; class COutputHead;
class COutputMode; class COutputMode;
struct SMonitorRule;
enum eWlrOutputCommittedProperties : uint32_t {
OUTPUT_HEAD_COMMITTED_MODE = (1 << 0),
OUTPUT_HEAD_COMMITTED_CUSTOM_MODE = (1 << 1),
OUTPUT_HEAD_COMMITTED_POSITION = (1 << 2),
OUTPUT_HEAD_COMMITTED_TRANSFORM = (1 << 3),
OUTPUT_HEAD_COMMITTED_SCALE = (1 << 4),
OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC = (1 << 5),
};
struct SWlrManagerOutputState {
uint32_t committedProperties = 0;
WP<COutputMode> mode;
struct {
Vector2D size;
uint32_t refresh = 0;
} customMode;
Vector2D position;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float scale = 1.F;
bool adaptiveSync = false;
bool enabled = true;
};
struct SWlrManagerSavedOutputState {
uint32_t committedProperties = 0;
Vector2D resolution;
uint32_t refresh = 0;
Vector2D position;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float scale = 1.F;
bool adaptiveSync = false;
bool enabled = true;
};
class COutputManager { class COutputManager {
public: public:
COutputManager(SP<CZwlrOutputManagerV1> resource_); COutputManager(SP<CZwlrOutputManagerV1> resource_);
@@ -21,6 +59,9 @@ class COutputManager {
void ensureMonitorSent(CMonitor* pMonitor); void ensureMonitorSent(CMonitor* pMonitor);
void sendDone(); void sendDone();
// holds the states for this manager.
std::unordered_map<std::string, SWlrManagerSavedOutputState> monitorStates;
private: private:
SP<CZwlrOutputManagerV1> resource; SP<CZwlrOutputManagerV1> resource;
bool stopped = false; bool stopped = false;
@@ -82,28 +123,7 @@ class COutputConfigurationHead {
bool good(); bool good();
enum eCommittedProperties : uint32_t { SWlrManagerOutputState state;
OUTPUT_HEAD_COMMITTED_MODE = (1 << 0),
OUTPUT_HEAD_COMMITTED_CUSTOM_MODE = (1 << 1),
OUTPUT_HEAD_COMMITTED_POSITION = (1 << 2),
OUTPUT_HEAD_COMMITTED_TRANSFORM = (1 << 3),
OUTPUT_HEAD_COMMITTED_SCALE = (1 << 4),
OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC = (1 << 5),
};
uint32_t committedProperties = 0;
struct {
WP<COutputMode> mode;
struct {
Vector2D size;
uint32_t refresh = 0;
} customMode;
Vector2D position;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float scale = 1.F;
bool adaptiveSync = false;
} state;
private: private:
SP<CZwlrOutputConfigurationHeadV1> resource; SP<CZwlrOutputConfigurationHeadV1> resource;
@@ -136,6 +156,9 @@ class COutputManagementProtocol : public IWaylandProtocol {
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);
// doesn't have to return one
SP<SWlrManagerSavedOutputState> getOutputStateFor(SP<CMonitor> pMonitor);
private: private:
void destroyResource(COutputManager* resource); void destroyResource(COutputManager* resource);
void destroyResource(COutputHead* resource); void destroyResource(COutputHead* resource);

View File

@@ -58,8 +58,8 @@ void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> data, timespe
if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION) if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION)
flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
__time_t tv_sec = 0; time_t tv_sec = 0;
if (sizeof(__time_t) > 4) if (sizeof(time_t) > 4)
tv_sec = when->tv_sec >> 32; tv_sec = when->tv_sec >> 32;
if (data->wasPresented) if (data->wasPresented)

View File

@@ -27,8 +27,6 @@ class CQueuedPresentationData {
WP<CMonitor> pMonitor; WP<CMonitor> pMonitor;
WP<CWLSurfaceResource> surface; WP<CWLSurfaceResource> surface;
DYNLISTENER(destroySurface);
friend class CPresentationFeedback; friend class CPresentationFeedback;
friend class CPresentationProtocol; friend class CPresentationProtocol;
}; };

View File

@@ -394,12 +394,12 @@ void CScreencopyProtocol::bindManager(wl_client* client, void* data, uint32_t ve
void CScreencopyProtocol::destroyResource(CScreencopyClient* client) { void CScreencopyProtocol::destroyResource(CScreencopyClient* client) {
std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; });
std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; }); std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; }); std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other->client.get() == client; });
} }
void CScreencopyProtocol::destroyResource(CScreencopyFrame* frame) { void CScreencopyProtocol::destroyResource(CScreencopyFrame* frame) {
std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; }); std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; }); std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; });
} }
void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) {
@@ -412,8 +412,11 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) {
// share frame if correct output // share frame if correct output
for (auto const& f : m_vFramesAwaitingWrite) { for (auto const& f : m_vFramesAwaitingWrite) {
if (!f)
continue;
if (!f->pMonitor || !f->buffer) { if (!f->pMonitor || !f->buffer) {
framesToRemove.push_back(f); framesToRemove.emplace_back(f);
continue; continue;
} }
@@ -425,10 +428,10 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) {
f->client->lastFrame.reset(); f->client->lastFrame.reset();
++f->client->frameCounter; ++f->client->frameCounter;
framesToRemove.push_back(f); framesToRemove.emplace_back(f);
} }
for (auto const& f : framesToRemove) { for (auto const& f : framesToRemove) {
destroyResource(f.get()); std::erase(m_vFramesAwaitingWrite, f);
} }
} }

View File

@@ -54,7 +54,7 @@ class CScreencopyFrame {
bool good(); bool good();
SP<CScreencopyFrame> self; WP<CScreencopyFrame> self;
WP<CScreencopyClient> client; WP<CScreencopyClient> client;
private: private:
@@ -92,7 +92,7 @@ class CScreencopyProtocol : public IWaylandProtocol {
private: private:
std::vector<SP<CScreencopyFrame>> m_vFrames; std::vector<SP<CScreencopyFrame>> m_vFrames;
std::vector<SP<CScreencopyFrame>> m_vFramesAwaitingWrite; std::vector<WP<CScreencopyFrame>> m_vFramesAwaitingWrite;
std::vector<SP<CScreencopyClient>> m_vClients; std::vector<SP<CScreencopyClient>> m_vClients;
SP<CEventLoopTimer> m_pSoftwareCursorTimer; SP<CEventLoopTimer> m_pSoftwareCursorTimer;

View File

@@ -0,0 +1,128 @@
#include "SinglePixel.hpp"
#include <limits>
#include "render/Renderer.hpp"
CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col_) {
LOGM(LOG, "New single-pixel buffer with color 0x{:x}", col_.getAsHex());
color = col_.getAsHex();
g_pHyprRenderer->makeEGLCurrent();
opaque = col_.a >= 1.F;
texture = makeShared<CTexture>(DRM_FORMAT_ARGB8888, (uint8_t*)&color, 4, Vector2D{1, 1});
resource = CWLBufferResource::create(makeShared<CWlBuffer>(client, 1, id));
success = texture->m_iTexID;
size = {1, 1};
if (!success)
Debug::log(ERR, "Failed creating a single pixel texture: null texture id");
}
CSinglePixelBuffer::~CSinglePixelBuffer() {
;
}
Aquamarine::eBufferCapability CSinglePixelBuffer::caps() {
return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
}
Aquamarine::eBufferType CSinglePixelBuffer::type() {
return Aquamarine::eBufferType::BUFFER_TYPE_SHM;
}
bool CSinglePixelBuffer::isSynchronous() {
return true;
}
void CSinglePixelBuffer::update(const CRegion& damage) {
;
}
Aquamarine::SDMABUFAttrs CSinglePixelBuffer::dmabuf() {
return {.success = false};
}
std::tuple<uint8_t*, uint32_t, size_t> CSinglePixelBuffer::beginDataPtr(uint32_t flags) {
return {(uint8_t*)&color, DRM_FORMAT_ARGB8888, 4};
}
void CSinglePixelBuffer::endDataPtr() {
;
}
bool CSinglePixelBuffer::good() {
return resource->good();
}
CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color) {
buffer = makeShared<CSinglePixelBuffer>(id, client, color);
if (!buffer->good())
return;
buffer->resource->buffer = buffer;
listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) {
listeners.bufferResourceDestroy.reset();
PROTO::singlePixel->destroyResource(this);
});
}
CSinglePixelBufferResource::~CSinglePixelBufferResource() {
;
}
bool CSinglePixelBufferResource::good() {
return buffer->good();
}
CSinglePixelBufferManagerResource::CSinglePixelBufferManagerResource(SP<CWpSinglePixelBufferManagerV1> resource_) : resource(resource_) {
if (!good())
return;
resource->setDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); });
resource->setOnDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); });
resource->setCreateU32RgbaBuffer([this](CWpSinglePixelBufferManagerV1* res, uint32_t id, uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
CColor color{r / (float)std::numeric_limits<uint32_t>::max(), g / (float)std::numeric_limits<uint32_t>::max(), b / (float)std::numeric_limits<uint32_t>::max(),
a / (float)std::numeric_limits<uint32_t>::max()};
const auto RESOURCE = PROTO::singlePixel->m_vBuffers.emplace_back(makeShared<CSinglePixelBufferResource>(id, resource->client(), color));
if (!RESOURCE->good()) {
res->noMemory();
PROTO::singlePixel->m_vBuffers.pop_back();
return;
}
});
}
bool CSinglePixelBufferManagerResource::good() {
return resource->resource();
}
CSinglePixelProtocol::CSinglePixelProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CSinglePixelProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CSinglePixelBufferManagerResource>(makeShared<CWpSinglePixelBufferManagerV1>(client, ver, id)));
if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
}
void CSinglePixelProtocol::destroyResource(CSinglePixelBufferManagerResource* res) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; });
}
void CSinglePixelProtocol::destroyResource(CSinglePixelBufferResource* surf) {
std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == surf; });
}

View File

@@ -0,0 +1,79 @@
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "WaylandProtocol.hpp"
#include "single-pixel-buffer-v1.hpp"
#include "types/Buffer.hpp"
class CSinglePixelBuffer : public IHLBuffer {
public:
CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col);
virtual ~CSinglePixelBuffer();
virtual Aquamarine::eBufferCapability caps();
virtual Aquamarine::eBufferType type();
virtual bool isSynchronous();
virtual void update(const CRegion& damage);
virtual Aquamarine::SDMABUFAttrs dmabuf();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
//
bool good();
bool success = false;
private:
uint32_t color = 0x00000000;
struct {
CHyprSignalListener resourceDestroy;
} listeners;
};
class CSinglePixelBufferResource {
public:
CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color);
~CSinglePixelBufferResource();
bool good();
private:
SP<CSinglePixelBuffer> buffer;
struct {
CHyprSignalListener bufferResourceDestroy;
} listeners;
};
class CSinglePixelBufferManagerResource {
public:
CSinglePixelBufferManagerResource(SP<CWpSinglePixelBufferManagerV1> resource_);
bool good();
private:
SP<CWpSinglePixelBufferManagerV1> resource;
};
class CSinglePixelProtocol : public IWaylandProtocol {
public:
CSinglePixelProtocol(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);
private:
void destroyResource(CSinglePixelBufferManagerResource* resource);
void destroyResource(CSinglePixelBufferResource* resource);
//
std::vector<SP<CSinglePixelBufferManagerResource>> m_vManagers;
std::vector<SP<CSinglePixelBufferResource>> m_vBuffers;
friend class CSinglePixelBufferManagerResource;
friend class CSinglePixelBufferResource;
};
namespace PROTO {
inline UP<CSinglePixelProtocol> singlePixel;
};

View File

@@ -354,12 +354,12 @@ void CToplevelExportProtocol::bindManager(wl_client* client, void* data, uint32_
void CToplevelExportProtocol::destroyResource(CToplevelExportClient* client) { void CToplevelExportProtocol::destroyResource(CToplevelExportClient* client) {
std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; });
std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; }); std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; }); std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other->client.get() == client; });
} }
void CToplevelExportProtocol::destroyResource(CToplevelExportFrame* frame) { void CToplevelExportProtocol::destroyResource(CToplevelExportFrame* frame) {
std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; }); std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; }); std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; });
} }
void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) {
@@ -370,11 +370,17 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) {
// share frame if correct output // share frame if correct output
for (auto const& f : m_vFramesAwaitingWrite) { for (auto const& f : m_vFramesAwaitingWrite) {
if (!f->pWindow || !validMapped(f->pWindow)) { if (!f)
framesToRemove.push_back(f); continue;
if (!validMapped(f->pWindow)) {
framesToRemove.emplace_back(f);
continue; continue;
} }
if (!f->pWindow)
continue;
const auto PWINDOW = f->pWindow; const auto PWINDOW = f->pWindow;
if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID))
@@ -394,7 +400,7 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) {
} }
for (auto const& f : framesToRemove) { for (auto const& f : framesToRemove) {
destroyResource(f.get()); std::erase(m_vFramesAwaitingWrite, f);
} }
} }

View File

@@ -45,7 +45,7 @@ class CToplevelExportFrame {
bool good(); bool good();
SP<CToplevelExportFrame> self; WP<CToplevelExportFrame> self;
WP<CToplevelExportClient> client; WP<CToplevelExportClient> client;
private: private:
@@ -85,7 +85,7 @@ class CToplevelExportProtocol : IWaylandProtocol {
private: private:
std::vector<SP<CToplevelExportClient>> m_vClients; std::vector<SP<CToplevelExportClient>> m_vClients;
std::vector<SP<CToplevelExportFrame>> m_vFrames; std::vector<SP<CToplevelExportFrame>> m_vFrames;
std::vector<SP<CToplevelExportFrame>> m_vFramesAwaitingWrite; std::vector<WP<CToplevelExportFrame>> m_vFramesAwaitingWrite;
void shareFrame(CToplevelExportFrame* frame); void shareFrame(CToplevelExportFrame* frame);
bool copyFrameDmabuf(CToplevelExportFrame* frame, timespec* now); bool copyFrameDmabuf(CToplevelExportFrame* frame, timespec* now);

View File

@@ -29,28 +29,19 @@ void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver
return; return;
} }
RESOURCE->setDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); }); RESOURCE->setDestroy([this](CZxdgOutputManagerV1* res) { onManagerResourceDestroy(res->resource()); });
RESOURCE->setOnDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); }); RESOURCE->setOnDestroy([this](CZxdgOutputManagerV1* res) { onManagerResourceDestroy(res->resource()); });
RESOURCE->setGetXdgOutput([this](CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* output) { this->onManagerGetXDGOutput(mgr, id, output); }); RESOURCE->setGetXdgOutput([this](CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* output) { onManagerGetXDGOutput(mgr, id, output); });
} }
CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); });
static auto P2 = g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); static auto P2 = g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); });
static auto P3 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) {
const auto PMONITOR = std::any_cast<CMonitor*>(param);
for (auto const& o : m_vXDGOutputs) {
if (o->monitor == PMONITOR)
o->monitor = nullptr;
}
});
} }
void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource) { void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource) {
const auto OUTPUT = CWLOutputResource::fromResource(outputResource); const auto OUTPUT = CWLOutputResource::fromResource(outputResource);
const auto PMONITOR = OUTPUT->monitor.lock();
const auto PMONITOR = OUTPUT->monitor.get();
const auto CLIENT = mgr->client(); const auto CLIENT = mgr->client();
CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique<CXDGOutput>(makeShared<CZxdgOutputV1>(CLIENT, mgr->version(), id), PMONITOR)).get(); CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique<CXDGOutput>(makeShared<CZxdgOutputV1>(CLIENT, mgr->version(), id), PMONITOR)).get();
@@ -60,14 +51,20 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32
#endif #endif
pXDGOutput->client = CLIENT; pXDGOutput->client = CLIENT;
pXDGOutput->outputProto = OUTPUT->owner;
if (!pXDGOutput->resource->resource()) { if (!pXDGOutput->resource->resource()) {
m_vXDGOutputs.pop_back(); m_vXDGOutputs.pop_back();
mgr->noMemory(); mgr->noMemory();
return; return;
} }
if (!PMONITOR) if (!PMONITOR) {
LOGM(ERR, "New xdg_output from client {:x} ({}) has no CMonitor?!", (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland");
return; return;
}
LOGM(LOG, "New xdg_output for {}: client {:x} ({})", PMONITOR->szName, (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland");
const auto XDGVER = pXDGOutput->resource->version(); const auto XDGVER = pXDGOutput->resource->version();
@@ -84,8 +81,9 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32
} }
void CXDGOutputProtocol::updateAllOutputs() { void CXDGOutputProtocol::updateAllOutputs() {
for (auto const& o : m_vXDGOutputs) { LOGM(LOG, "updating all xdg_output heads");
for (auto const& o : m_vXDGOutputs) {
if (!o->monitor) if (!o->monitor)
continue; continue;
@@ -97,7 +95,7 @@ void CXDGOutputProtocol::updateAllOutputs() {
// //
CXDGOutput::CXDGOutput(SP<CZxdgOutputV1> resource_, CMonitor* monitor_) : monitor(monitor_), resource(resource_) { CXDGOutput::CXDGOutput(SP<CZxdgOutputV1> resource_, SP<CMonitor> monitor_) : monitor(monitor_), resource(resource_) {
if (!resource->resource()) if (!resource->resource())
return; return;
@@ -108,7 +106,7 @@ CXDGOutput::CXDGOutput(SP<CZxdgOutputV1> resource_, CMonitor* monitor_) : monito
void CXDGOutput::sendDetails() { void CXDGOutput::sendDetails() {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling"); static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (!monitor) if (!monitor || !outputProto || outputProto->isDefunct())
return; return;
const auto POS = isXWayland ? monitor->vecXWaylandPosition : monitor->vecPosition; const auto POS = isXWayland ? monitor->vecXWaylandPosition : monitor->vecPosition;

View File

@@ -6,16 +6,18 @@
class CMonitor; class CMonitor;
class CXDGOutputProtocol; class CXDGOutputProtocol;
class CWLOutputProtocol;
class CXDGOutput { class CXDGOutput {
public: public:
CXDGOutput(SP<CZxdgOutputV1> resource, CMonitor* monitor_); CXDGOutput(SP<CZxdgOutputV1> resource, SP<CMonitor> monitor_);
void sendDetails(); void sendDetails();
private: private:
CMonitor* monitor = nullptr; WP<CMonitor> monitor;
SP<CZxdgOutputV1> resource; SP<CZxdgOutputV1> resource;
WP<CWLOutputProtocol> outputProto;
std::optional<Vector2D> overridePosition; std::optional<Vector2D> overridePosition;
@@ -30,12 +32,12 @@ class CXDGOutputProtocol : public IWaylandProtocol {
CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name); CXDGOutputProtocol(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 updateAllOutputs();
private: private:
void onManagerResourceDestroy(wl_resource* res); void onManagerResourceDestroy(wl_resource* res);
void onOutputResourceDestroy(wl_resource* res); void onOutputResourceDestroy(wl_resource* res);
void onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource); void onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource);
void updateAllOutputs();
// //
std::vector<UP<CZxdgOutputManagerV1>> m_vManagerResources; std::vector<UP<CZxdgOutputManagerV1>> m_vManagerResources;

View File

@@ -21,8 +21,6 @@ CWLOutputResource::CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> pMoni
PROTO::outputs.at(monitor->szName)->destroyResource(this); PROTO::outputs.at(monitor->szName)->destroyResource(this);
}); });
resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(),
monitor->output->model.c_str(), monitor->transform);
if (resource->version() >= 4) { if (resource->version() >= 4) {
resource->sendName(monitor->szName.c_str()); resource->sendName(monitor->szName.c_str());
resource->sendDescription(monitor->szDescription.c_str()); resource->sendDescription(monitor->szDescription.c_str());
@@ -57,6 +55,9 @@ void CWLOutputResource::updateState() {
resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0); resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0);
resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(),
monitor->output->model.c_str(), monitor->transform);
if (resource->version() >= 2) if (resource->version() >= 2)
resource->sendDone(); resource->sendDone();
} }
@@ -118,6 +119,9 @@ bool CWLOutputProtocol::isDefunct() {
} }
void CWLOutputProtocol::sendDone() { void CWLOutputProtocol::sendDone() {
if (defunct)
return;
for (auto const& r : m_vOutputs) { for (auto const& r : m_vOutputs) {
r->resource->sendDone(); r->resource->sendDone();
} }

View File

@@ -755,14 +755,12 @@ void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP<
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); m_RenderData.projection = Mat3x3::outputProjection(pMonitor->vecPixelSize, HYPRUTILS_TRANSFORM_NORMAL);
matrixIdentity(m_RenderData.monitorProjection.data()); m_RenderData.monitorProjection = Mat3x3::identity();
if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) { if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) {
const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize; const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize;
matrixTranslate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0); m_RenderData.monitorProjection.translate(FBO->m_vSize / 2.0).transform(wlTransformToHyprutils(pMonitor->transform)).translate(-tfmd / 2.0);
matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(pMonitor->transform));
matrixTranslate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0);
} }
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
@@ -809,7 +807,7 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); m_RenderData.projection = Mat3x3::outputProjection(pMonitor->vecPixelSize, HYPRUTILS_TRANSFORM_NORMAL);
m_RenderData.monitorProjection = pMonitor->projMatrix; m_RenderData.monitorProjection = pMonitor->projMatrix;
@@ -1289,20 +1287,17 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
box = &newBox; box = &newBox;
float matrix[9]; Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(
projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot);
m_RenderData.monitorProjection.data()); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program); glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
#else #else
matrixTranspose(glMatrix, glMatrix); glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif #endif
// premultiply the color as well as we don't work with straight alpha // premultiply the color as well as we don't work with straight alpha
@@ -1386,11 +1381,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
if (m_bEndFrame || TRANSFORMS_MATCH) if (m_bEndFrame || TRANSFORMS_MATCH)
TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform));
float matrix[9]; Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
if (waitTimeline != nullptr) { if (waitTimeline != nullptr) {
if (!waitForTimelinePoint(waitTimeline, waitPoint)) { if (!waitForTimelinePoint(waitTimeline, waitPoint)) {
@@ -1431,6 +1423,9 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(tex->m_iTarget, tex->m_iTexID); glBindTexture(tex->m_iTarget, tex->m_iTexID);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (m_RenderData.useNearestNeighbor) { if (m_RenderData.useNearestNeighbor) {
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -1442,10 +1437,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
glUseProgram(shader->program); glUseProgram(shader->program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
#else #else
matrixTranspose(glMatrix, glMatrix); glMatrix.transpose();
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif #endif
glUniform1i(shader->tex, 0); glUniform1i(shader->tex, 0);
@@ -1556,11 +1551,8 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) {
// get transform // get transform
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
float matrix[9]; Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA;
@@ -1570,10 +1562,10 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) {
glUseProgram(shader->program); glUseProgram(shader->program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
#else #else
matrixTranspose(glMatrix, glMatrix); glMatrix.transpose();
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif #endif
glUniform1i(shader->tex, 0); glUniform1i(shader->tex, 0);
@@ -1610,21 +1602,18 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuf
// get transform // get transform
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
float matrix[9]; Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE; CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE;
glUseProgram(shader->program); glUseProgram(shader->program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
#else #else
matrixTranspose(glMatrix, glMatrix); glMatrix.transpose();
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif #endif
glUniform1i(shader->tex, 0); glUniform1i(shader->tex, 0);
glUniform1i(shader->alphaMatte, 1); glUniform1i(shader->alphaMatte, 1);
@@ -1668,12 +1657,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
// get transforms for the full monitor // get transforms for the full monitor
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform));
float matrix[9];
CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
projectBox(matrix, MONITORBOX, TRANSFORM, 0, m_RenderData.monitorProjection.data()); Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(MONITORBOX, TRANSFORM);
Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
// get the config settings // get the config settings
static auto PBLURSIZE = CConfigValue<Hyprlang::INT>("decoration:blur:size"); static auto PBLURSIZE = CConfigValue<Hyprlang::INT>("decoration:blur:size");
@@ -1710,10 +1696,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
#else #else
matrixTranspose(glMatrix, glMatrix); glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif #endif
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS);
@@ -1755,10 +1741,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
// prep two shaders // prep two shaders
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
#else #else
matrixTranspose(glMatrix, glMatrix); glMatrix.transpose();
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif #endif
glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a
if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) { if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) {
@@ -1832,10 +1818,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
#else #else
matrixTranspose(glMatrix, glMatrix); glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif #endif
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS);
@@ -2165,12 +2151,9 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
round += round == 0 ? 0 : scaledBorderSize; round += round == 0 ? 0 : scaledBorderSize;
float matrix[9]; Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(
projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot);
m_RenderData.monitorProjection.data()); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
const auto BLEND = m_bBlend; const auto BLEND = m_bBlend;
blend(true); blend(true);
@@ -2178,10 +2161,10 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program); glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
#else #else
matrixTranspose(glMatrix, glMatrix); glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif #endif
static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail
@@ -2471,22 +2454,19 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
const auto col = color; const auto col = color;
float matrix[9]; Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(
projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot);
m_RenderData.monitorProjection.data()); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program); glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program);
#ifndef GLES2 #ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
#else #else
matrixTranspose(glMatrix, glMatrix); glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif #endif
glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a);
@@ -2565,11 +2545,11 @@ void CHyprOpenGLImpl::renderMirrored() {
return; return;
// replace monitor projection to undo the mirrored monitor's projection // replace monitor projection to undo the mirrored monitor's projection
matrixIdentity(m_RenderData.monitorProjection.data()); m_RenderData.monitorProjection = Mat3x3::identity()
matrixTranslate(m_RenderData.monitorProjection.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0); .translate(monitor->vecPixelSize / 2.0)
matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(monitor->transform)); .transform(wlTransformToHyprutils(monitor->transform))
matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(invertTransform(mirrored->transform))); .transform(wlTransformToHyprutils(invertTransform(mirrored->transform)))
matrixTranslate(m_RenderData.monitorProjection.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0); .translate(-monitor->vecTransformedSize / 2.0);
// clear stuff outside of mirrored area (e.g. when changing to mirrored) // clear stuff outside of mirrored area (e.g. when changing to mirrored)
clear(CColor(0, 0, 0, 0)); clear(CColor(0, 0, 0, 0));
@@ -2920,16 +2900,15 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
} }
void CHyprOpenGLImpl::saveMatrix() { void CHyprOpenGLImpl::saveMatrix() {
memcpy(m_RenderData.savedProjection, m_RenderData.projection, 9 * sizeof(float)); m_RenderData.savedProjection = m_RenderData.projection;
} }
void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) { void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) {
matrixScale(m_RenderData.projection, scale, scale); m_RenderData.projection.scale(scale).translate(translate);
matrixTranslate(m_RenderData.projection, translate.x, translate.y);
} }
void CHyprOpenGLImpl::restoreMatrix() { void CHyprOpenGLImpl::restoreMatrix() {
memcpy(m_RenderData.projection, m_RenderData.savedProjection, 9 * sizeof(float)); m_RenderData.projection = m_RenderData.savedProjection;
} }
void CHyprOpenGLImpl::bindOffMain() { void CHyprOpenGLImpl::bindOffMain() {

View File

@@ -96,9 +96,9 @@ struct SMonitorRenderData {
struct SCurrentRenderData { struct SCurrentRenderData {
CMonitor* pMonitor = nullptr; CMonitor* pMonitor = nullptr;
PHLWORKSPACE pWorkspace = nullptr; PHLWORKSPACE pWorkspace = nullptr;
float projection[9]; Mat3x3 projection;
float savedProjection[9]; Mat3x3 savedProjection;
std::array<float, 9> monitorProjection; Mat3x3 monitorProjection;
SMonitorRenderData* pCurrentMonData = nullptr; SMonitorRenderData* pCurrentMonData = nullptr;
CFramebuffer* currentFB = nullptr; // current rendering to CFramebuffer* currentFB = nullptr; // current rendering to

View File

@@ -2,7 +2,6 @@
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
#include "../helpers/memory/Memory.hpp" #include "../helpers/memory/Memory.hpp"
#include "../helpers/WLListener.hpp"
#include "Framebuffer.hpp" #include "Framebuffer.hpp"
#include <aquamarine/buffer/Buffer.hpp> #include <aquamarine/buffer/Buffer.hpp>

View File

@@ -150,7 +150,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
const auto& TEXTURE = surface->current.texture; const auto& TEXTURE = surface->current.texture;
const auto RDATA = (SRenderData*)data; const auto RDATA = (SRenderData*)data;
const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE;
// this is bad, probably has been logged elsewhere. Means the texture failed // this is bad, probably has been logged elsewhere. Means the texture failed
// uploading to the GPU. // uploading to the GPU.
@@ -180,6 +180,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
// however, if surface buffer w / h < box, we need to adjust them // however, if surface buffer w / h < box, we need to adjust them
const auto PWINDOW = PSURFACE ? PSURFACE->getWindow() : nullptr; const auto PWINDOW = PSURFACE ? PSURFACE->getWindow() : nullptr;
// center the surface if it's smaller than the viewport we assign it
if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees PWINDOW */) { if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees PWINDOW */) {
const auto CORRECT = PSURFACE->correctSmallVec(); const auto CORRECT = PSURFACE->correctSmallVec();
const auto SIZE = PSURFACE->getViewporterCorrectedSize(); const auto SIZE = PSURFACE->getViewporterCorrectedSize();
@@ -195,17 +196,6 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
} }
} }
if (!INTERACTIVERESIZEINPROGRESS && PSURFACE && PWINDOW && PWINDOW->m_vRealSize.goal().floor() > PWINDOW->m_vReportedSize && PWINDOW->m_vReportedSize > Vector2D{1, 1}) {
Vector2D size =
Vector2D{windowBox.w * (PWINDOW->m_vReportedSize.x / PWINDOW->m_vRealSize.value().x), windowBox.h * (PWINDOW->m_vReportedSize.y / PWINDOW->m_vRealSize.value().y)};
Vector2D correct = Vector2D{windowBox.w, windowBox.h} - size;
windowBox.translate(correct / 2.0);
windowBox.w = size.x;
windowBox.h = size.y;
}
} else { // here we clamp to 2, these might be some tiny specks } else { // here we clamp to 2, these might be some tiny specks
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)}; windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)};
if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) { if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) {
@@ -231,6 +221,8 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
return; // invisible return; // invisible
} }
const auto PROJSIZEUNSCALED = windowBox.size();
windowBox.scale(RDATA->pMonitor->scale); windowBox.scale(RDATA->pMonitor->scale);
windowBox.round(); windowBox.round();
@@ -239,7 +231,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ && DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ &&
(!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */;
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1); g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->pMonitor->self.lock(), RDATA->surface == surface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1);
// check for fractional scale surfaces misaligning the buffer size // check for fractional scale surfaces misaligning the buffer size
// in those cases it's better to just force nearest neighbor // in those cases it's better to just force nearest neighbor
@@ -1083,7 +1075,8 @@ void CHyprRenderer::renderSessionLockMissing(CMonitor* pMonitor) {
g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID);
} }
void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, SP<CMonitor> pMonitor, bool main, const Vector2D& projSize,
const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) {
if (!pWindow || !pWindow->m_bIsX11) { if (!pWindow || !pWindow->m_bIsX11) {
Vector2D uvTL; Vector2D uvTL;
Vector2D uvBR = Vector2D(1, 1); Vector2D uvBR = Vector2D(1, 1);
@@ -1112,6 +1105,22 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
uvBR -= MISALIGNMENT * PIXELASUV; uvBR -= MISALIGNMENT * PIXELASUV;
} }
// if the surface is smaller than our viewport, extend its edges.
// this will break if later on xdg geometry is hit, but we really try
// to let the apps know to NOT add CSD. Also if source is there.
// there is no way to fix this if that's the case
const auto MONITOR_WL_SCALE = std::ceil(pMonitor->scale);
const bool SCALE_UNAWARE = MONITOR_WL_SCALE != pSurface->current.scale && !pSurface->current.viewport.hasDestination;
const auto EXPECTED_SIZE =
((pSurface->current.viewport.hasDestination ? pSurface->current.viewport.destination : pSurface->current.bufferSize / pSurface->current.scale) * pMonitor->scale)
.round();
if (!SCALE_UNAWARE && (EXPECTED_SIZE.x < projSize.x || EXPECTED_SIZE.y < projSize.y)) {
// this will not work with shm AFAIK, idk why.
// NOTE: this math is wrong if we have a source... or geom updates later, but I don't think we can do much
const auto FIX = projSize / EXPECTED_SIZE;
uvBR = uvBR * FIX;
}
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL; g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL;
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR; g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR;
@@ -1127,18 +1136,17 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
CBox geom = pWindow->m_pXDGSurface->current.geometry; CBox geom = pWindow->m_pXDGSurface->current.geometry;
// ignore X and Y, adjust uv // ignore X and Y, adjust uv
if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) { if (geom.x != 0 || geom.y != 0 || geom.width > projSizeUnscaled.x || geom.height > projSizeUnscaled.y) {
const auto XPERC = (double)geom.x / (double)pSurface->current.size.x; const auto XPERC = (double)geom.x / (double)pSurface->current.size.x;
const auto YPERC = (double)geom.y / (double)pSurface->current.size.y; const auto YPERC = (double)geom.y / (double)pSurface->current.size.y;
const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x; const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x;
const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.size.y; const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.size.y;
const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y)); const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y));
uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y)); uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y));
uvTL = uvTL + TOADDTL; uvTL = uvTL + TOADDTL;
// TODO: make this passed to the func. Might break in the future. auto maxSize = projSizeUnscaled;
auto maxSize = pWindow->m_vRealSize.value();
if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall)
maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize(); maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize();

View File

@@ -64,7 +64,8 @@ class CHyprRenderer {
void ensureCursorRenderingMode(); void ensureCursorRenderingMode();
bool shouldRenderCursor(); bool shouldRenderCursor();
void setCursorHidden(bool hide); void setCursorHidden(bool hide);
void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, SP<CMonitor> pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {},
bool fixMisalignedFSV1 = false);
std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min
void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry); void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry);
void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace); void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace);

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include "../helpers/WLListener.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
#include "../helpers/memory/Memory.hpp" #include "../helpers/memory/Memory.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"

View File

@@ -2,7 +2,6 @@
#include "../macros.hpp" #include "../macros.hpp"
#include "XDataSource.hpp" #include "XDataSource.hpp"
#include "../helpers/WLListener.hpp"
#include "../helpers/memory/Memory.hpp" #include "../helpers/memory/Memory.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"

1
subprojects/tracy.wrap Normal file
View File

@@ -0,0 +1 @@
[wrap-file]

5
subprojects/udis86.wrap Normal file
View File

@@ -0,0 +1,5 @@
[wrap-file]
method = cmake
[provide]
udis86 = libudis86_dep