Merge branch 'hyprwm:main' into fix/cursor-min-padding

This commit is contained in:
drendog 2024-06-10 23:41:38 +02:00 committed by GitHub
commit 04fe914737
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
191 changed files with 9748 additions and 3452 deletions

View File

@ -9,11 +9,26 @@ body:
---
- type: dropdown
id: type
attributes:
label: Bug or Regression?
description: Is this a bug or a regression?
options:
- Bug
- Regression
validations:
required: true
- type: textarea
id: ver
attributes:
label: Hyprland Version
description: "Paste the output of `hyprctl systeminfo` here."
label: System Info and Version
description: |
Paste the output of `hyprctl systeminfo -c` here (If you are on a
version that shows you help menu, omit the `-c` and attach config files
to the issue). If you have configs outside of the main config shown
here, please attach.
value: "<details>
<summary>System/Version info</summary>
@ -29,17 +44,6 @@ body:
validations:
required: true
- type: dropdown
id: type
attributes:
label: Bug or Regression?
description: Is this a bug or a regression?
options:
- Bug
- Regression
validations:
required: true
- type: textarea
id: desc
attributes:

83
.github/labeler.yml vendored Normal file
View File

@ -0,0 +1,83 @@
assets:
- changed-files:
- any-glob-to-any-file: "assets/**"
docs:
- changed-files:
- any-glob-to-any-file: "docs/**"
hyprctl:
- changed-files:
- any-glob-to-any-file: "hyprctl/**"
hyprpm:
- changed-files:
- any-glob-to-any-file: "hyprpm/**"
nix:
- changed-files:
- any-glob-to-any-file: "nix/**"
protocols:
- changed-files:
- any-glob-to-any-file: ["protocols/**", "src/protocols/**"]
core:
- changed-files:
- any-glob-to-any-file: "src/**"
config:
- changed-files:
- any-glob-to-any-file: "src/config/**"
debug:
- changed-files:
- any-glob-to-any-file: "src/debug/**"
desktop:
- changed-files:
- any-glob-to-any-file: "src/desktop/**"
devices:
- changed-files:
- any-glob-to-any-file: "src/devices/**"
events:
- changed-files:
- any-glob-to-any-file: "src/events/**"
helpers:
- changed-files:
- any-glob-to-any-file: "src/helpers/**"
hyprerror:
- changed-files:
- any-glob-to-any-file: "src/hyprerror/**"
init:
- changed-files:
- any-glob-to-any-file: "src/init/**"
layout:
- changed-files:
- any-glob-to-any-file: "src/layout/**"
managers:
- changed-files:
- any-glob-to-any-file: "src/managers/**"
pch:
- changed-files:
- any-glob-to-any-file: "src/pch/**"
plugins:
- changed-files:
- any-glob-to-any-file: "src/plugins/**"
render:
- changed-files:
- any-glob-to-any-file: "src/render/**"
xwayland:
- changed-files:
- any-glob-to-any-file: "src/xwayland/**"

12
.github/workflows/labeler.yml vendored Normal file
View File

@ -0,0 +1,12 @@
name: "Pull Request Labeler"
on:
- pull_request_target
jobs:
labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5

View File

@ -113,9 +113,11 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET
wayland-server wayland-client wayland-cursor wayland-protocols
cairo pango pangocairo pixman-1
libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm
hyprwayland-scanner>=0.3.8 hyprlang>=0.3.2 hyprcursor>=0.1.7
hyprlang>=0.3.2 hyprcursor>=0.1.7
)
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
file(GLOB_RECURSE SRCFILES "src/*.cpp")
set(TRACY_CPP_FILES "")
@ -190,12 +192,8 @@ if(NO_XWAYLAND)
add_compile_definitions(NO_XWAYLAND)
else()
message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh)
pkg_check_modules(xcb_errors IMPORTED_TARGET xcb-errors)
pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh xcb-errors)
target_link_libraries(Hyprland PkgConfig::xdeps)
if(xcb_errors_FOUND)
target_link_libraries(Hyprland PkgConfig::xcb_errors)
endif()
endif()
if(NO_SYSTEMD)
@ -217,44 +215,54 @@ message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::deps)
# used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers)
function(protocol protoPath protoName external)
if (external)
execute_process(
COMMAND ${WaylandScanner} server-header ${protoPath} protocols/${protoName}-protocol.h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
execute_process(
COMMAND ${WaylandScanner} private-code ${protoPath} protocols/${protoName}-protocol.c
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c)
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
else()
execute_process(
COMMAND ${WaylandScanner} server-header ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
execute_process(
COMMAND ${WaylandScanner} private-code ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.c
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c)
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif()
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h
COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c
COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c)
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h)
endfunction()
function(protocolNew protoPath protoName external)
if (external)
execute_process(
COMMAND hyprwayland-scanner ${protoPath} ${CMAKE_SOURCE_DIR}/protocols/
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
target_sources(Hyprland PRIVATE protocols/${protoName}.cpp)
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
else()
execute_process(
COMMAND hyprwayland-scanner ${WAYLAND_PROTOCOLS_DIR}/${protoPath} ${CMAKE_SOURCE_DIR}/protocols/
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
target_sources(Hyprland PRIVATE protocols/${protoName}.cpp)
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif()
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
target_sources(Hyprland PRIVATE protocols/${protoName}.cpp protocols/${protoName}.hpp)
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
endfunction()
function(protocolWayland)
execute_process(
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
target_sources(Hyprland PRIVATE protocols/wayland.cpp)
target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
endfunction()
target_link_libraries(Hyprland
@ -269,40 +277,43 @@ target_link_libraries(Hyprland
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true)
protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true)
protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true)
protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false)
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
protocolNew("protocols/wlr-gamma-control-unstable-v1.xml" "wlr-gamma-control-unstable-v1" true)
protocolNew("protocols/wlr-foreign-toplevel-management-unstable-v1.xml" "wlr-foreign-toplevel-management-unstable-v1" true)
protocolNew("protocols/wlr-output-power-management-unstable-v1.xml" "wlr-output-power-management-unstable-v1" true)
protocolNew("protocols/virtual-keyboard-unstable-v1.xml" "virtual-keyboard-unstable-v1" true)
protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer-unstable-v1" true)
protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true)
protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true)
protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true)
protocolNew("protocols/wlr-data-control-unstable-v1.xml" "wlr-data-control-unstable-v1" true)
protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-v1" true)
protocolNew("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true)
protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false)
protocolNew("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
protocolNew("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false)
protocolNew("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
protocolNew("unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" "idle-inhibit-unstable-v1" false)
protocolNew("unstable/relative-pointer/relative-pointer-unstable-v1.xml" "relative-pointer-unstable-v1" false)
protocolNew("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" "xdg-decoration-unstable-v1" false)
protocolNew("staging/alpha-modifier/alpha-modifier-v1.xml" "alpha-modifier-v1" false)
protocolNew("staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml" "ext-foreign-toplevel-list-v1" false)
protocolNew("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml" "pointer-gestures-unstable-v1" false)
protocolNew("unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml" "keyboard-shortcuts-inhibit-unstable-v1" false)
protocolNew("unstable/text-input/text-input-unstable-v3.xml" "text-input-unstable-v3" false)
protocolNew("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" false)
protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" false)
protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1" false)
protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false)
protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false)
protocolNew("stable/presentation-time/presentation-time.xml" "presentation-time" false)
protocolNew("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false)
protocolNew("unstable/primary-selection/primary-selection-unstable-v1.xml" "primary-selection-unstable-v1" false)
protocolNew("protocols" "wlr-gamma-control-unstable-v1" true)
protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
protocolNew("protocols" "wlr-output-power-management-unstable-v1" true)
protocolNew("protocols" "virtual-keyboard-unstable-v1" true)
protocolNew("protocols" "wlr-virtual-pointer-unstable-v1" true)
protocolNew("protocols" "input-method-unstable-v2" true)
protocolNew("protocols" "wlr-output-management-unstable-v1" true)
protocolNew("protocols" "kde-server-decoration" true)
protocolNew("protocols" "wlr-data-control-unstable-v1" true)
protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true)
protocolNew("protocols" "wlr-layer-shell-unstable-v1" true)
protocolNew("protocols" "wayland-drm" true)
protocolNew("staging/tearing-control" "tearing-control-v1" false)
protocolNew("staging/fractional-scale" "fractional-scale-v1" false)
protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false)
protocolNew("staging/cursor-shape" "cursor-shape-v1" false)
protocolNew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false)
protocolNew("unstable/relative-pointer" "relative-pointer-unstable-v1" false)
protocolNew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false)
protocolNew("staging/alpha-modifier" "alpha-modifier-v1" false)
protocolNew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false)
protocolNew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false)
protocolNew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false)
protocolNew("unstable/text-input" "text-input-unstable-v3" false)
protocolNew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" false)
protocolNew("staging/xdg-activation" "xdg-activation-v1" false)
protocolNew("staging/ext-idle-notify" "ext-idle-notify-v1" false)
protocolNew("staging/ext-session-lock" "ext-session-lock-v1" false)
protocolNew("stable/tablet" "tablet-v2" false)
protocolNew("stable/presentation-time" "presentation-time" false)
protocolNew("stable/xdg-shell" "xdg-shell" false)
protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false)
protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false)
protocolNew("stable/viewporter" "viewporter" false)
protocolNew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
protocolWayland()

View File

@ -53,6 +53,8 @@ installheaders:
mkdir -p ${PREFIX}/include/hyprland/wlr
mkdir -p ${PREFIX}/share/pkgconfig
cmake --build ./build --config Release --target generate-protocol-headers
find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
cd subprojects/wlroots-hyprland/include/wlr && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../..
cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../..

View File

@ -13,11 +13,11 @@
]
},
"locked": {
"lastModified": 1715791817,
"narHash": "sha256-J069Uhv/gCMFLX1dSh2f+9ZTM09r1Nv3oUfocCnWKow=",
"lastModified": 1717181720,
"narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "7c3aa03dffb53921e583ade3d4ae3f487e390e7e",
"rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c",
"type": "github"
},
"original": {
@ -61,11 +61,11 @@
]
},
"locked": {
"lastModified": 1715791527,
"narHash": "sha256-HhQ4zvGHrRjR63ltySSeg+x+0jb0lepiutWdnFhLRoo=",
"lastModified": 1716473782,
"narHash": "sha256-+qLn4lsHU6iL3+HTo1gTQ1tWzet8K9h+IfVemzEQZj8=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "969cb076e5b76f2e823aeca1937a3e1f159812ee",
"rev": "87d5d984109c839482b88b4795db073eb9ed446f",
"type": "github"
},
"original": {
@ -84,11 +84,11 @@
]
},
"locked": {
"lastModified": 1716058375,
"narHash": "sha256-CwjWoVnBZE5SBpRx9dgSQGCr4Goxyfcyv3zZbOhVqzk=",
"lastModified": 1717784906,
"narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "3afed4364790aebe0426077631af1e164a9650cc",
"rev": "0f30f9eca6e404130988554accbb64d1c9ec877d",
"type": "github"
},
"original": {
@ -99,11 +99,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1716137900,
"narHash": "sha256-sowPU+tLQv8GlqtVtsXioTKeaQvlMz/pefcdwg8MvfM=",
"lastModified": 1717602782,
"narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6c0b7a92c30122196a761b440ac0d46d3d9954f1",
"rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6",
"type": "github"
},
"original": {

View File

@ -60,6 +60,7 @@ flags:
--batch Execute a batch of commands, separated by ';'
--instance (-i) use a specific instance. Can be either signature or
index in hyprctl instances (0, 1, etc)
--quiet (-q) Disable the output of hyprctl
--help:
Can be used to print command's arguments that did not fit into this page
@ -155,4 +156,4 @@ cmd:
starting from 0
flags:
See 'hyprctl --help')#";
See 'hyprctl --help')#";

View File

@ -2,7 +2,7 @@ _hyprctl_cmd_2 () {
hyprctl monitors | grep Monitor | awk '{ print $2 }'
}
_hyprctl_cmd_1 () {
_hyprctl_cmd_3 () {
hyprpm list | grep "Plugin" | awk '{print $4}'
}
@ -10,7 +10,7 @@ _hyprctl_cmd_0 () {
hyprctl clients | grep class | awk '{print $2}'
}
_hyprctl_cmd_3 () {
_hyprctl_cmd_1 () {
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
}
@ -23,25 +23,25 @@ _hyprctl () {
local words cword
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
declare -A literal_transitions
literal_transitions[0]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [108]=5 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [96]=5 [97]=2 [27]=2 [28]=14 [100]=2 [102]=5)"
literal_transitions[3]="([72]=18 [13]=2 [32]=18 [54]=18 [55]=18 [89]=18 [104]=2 [120]=2 [76]=1 [16]=2 [123]=18 [3]=1 [5]=2 [63]=18 [127]=2 [129]=18 [80]=18 [130]=18 [83]=18 [31]=18 [48]=2 [12]=2 [85]=18 [10]=18 [86]=18 [137]=18)"
literal_transitions[7]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [97]=2 [27]=2 [28]=14 [100]=2)"
literal_transitions[8]="([128]=2 [131]=2 [0]=2 [73]=2 [35]=2 [106]=2 [37]=2 [107]=2 [4]=2 [78]=2 [39]=2 [79]=2 [110]=2 [6]=2 [41]=2 [42]=2 [81]=2 [82]=2 [46]=2 [47]=2 [9]=2 [109]=2 [50]=2 [52]=2 [11]=2 [115]=2 [87]=2 [49]=2 [56]=2 [90]=2 [57]=2 [91]=2 [92]=2 [60]=2 [61]=2 [125]=2 [93]=2 [62]=2 [20]=2 [95]=2 [22]=2 [23]=2 [64]=2 [65]=2 [24]=2 [132]=2 [26]=2 [68]=2 [98]=2 [69]=2 [29]=2 [136]=2 [70]=2 [99]=2)"
literal_transitions[9]="([114]=15 [111]=16)"
literal_transitions[11]="([101]=2)"
literal_transitions[13]="([21]=1 [116]=1 [30]=1 [135]=1 [118]=1 [43]=1 [71]=1)"
literal_transitions[14]="([38]=2)"
literal_transitions[15]="([8]=2 [66]=2 [14]=2 [133]=2)"
literal_transitions[17]="([75]=19)"
literal_transitions[18]="([18]=2 [7]=2)"
literal_transitions[19]="([34]=5 [44]=5)"
literal_transitions[20]="([134]=2 [94]=2)"
literal_transitions[0]="([105]=1 [75]=2 [33]=3 [35]=4 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [111]=4 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [88]=4 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [98]=4 [99]=2 [27]=2 [28]=14 [102]=2 [104]=4)"
literal_transitions[3]="([73]=17 [13]=2 [32]=17 [55]=17 [56]=17 [91]=17 [106]=2 [123]=2 [77]=1 [16]=2 [126]=17 [3]=1 [5]=2 [64]=17 [131]=2 [133]=17 [81]=17 [134]=17 [84]=17 [31]=17 [49]=2 [12]=2 [86]=17 [10]=17 [87]=17 [141]=17)"
literal_transitions[7]="([105]=1 [75]=2 [33]=3 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [99]=2 [27]=2 [28]=14 [102]=2)"
literal_transitions[8]="([101]=2 [130]=2 [132]=2 [0]=2 [74]=2 [36]=2 [108]=2 [109]=2 [38]=2 [110]=2 [4]=2 [79]=2 [40]=2 [80]=2 [113]=2 [6]=2 [42]=2 [43]=2 [82]=2 [83]=2 [47]=2 [48]=2 [9]=2 [50]=2 [51]=2 [53]=2 [11]=2 [112]=2 [89]=2 [118]=2 [57]=2 [92]=2 [58]=2 [93]=2 [94]=2 [61]=2 [62]=2 [128]=2 [95]=2 [63]=2 [20]=2 [97]=2 [22]=2 [23]=2 [65]=2 [66]=2 [135]=2 [136]=2 [24]=2 [26]=2 [69]=2 [100]=2 [70]=2 [140]=2 [29]=2 [71]=2)"
literal_transitions[9]="([117]=20 [114]=16)"
literal_transitions[11]="([103]=2)"
literal_transitions[13]="([21]=1 [119]=1 [30]=1 [139]=1 [121]=1 [44]=1 [72]=1)"
literal_transitions[14]="([39]=2)"
literal_transitions[15]="([138]=2 [96]=2)"
literal_transitions[17]="([18]=2 [7]=2)"
literal_transitions[18]="([76]=19)"
literal_transitions[19]="([34]=4 [45]=4)"
literal_transitions[20]="([8]=2 [67]=2 [14]=2 [137]=2)"
declare -A match_anything_transitions
match_anything_transitions=([1]=2 [0]=7 [6]=2 [20]=2 [10]=2 [2]=17 [7]=7 [12]=2 [14]=17 [16]=2 [4]=20 [11]=17)
match_anything_transitions=([1]=2 [0]=7 [6]=2 [15]=2 [10]=2 [5]=15 [14]=18 [7]=7 [2]=18 [16]=2 [12]=2 [11]=18)
declare -A subword_transitions
local state=0
@ -108,7 +108,7 @@ _hyprctl () {
done
fi
declare -A commands
commands=([16]=2 [4]=3 [12]=1 [10]=0)
commands=([5]=1 [16]=2 [12]=3 [10]=0)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
local completions=()

View File

@ -3,7 +3,7 @@ function _hyprctl_3
hyprctl monitors | grep Monitor | awk '{ print $2 }'
end
function _hyprctl_2
function _hyprctl_4
set 1 $argv[1]
hyprpm list | grep "Plugin" | awk '{print $4}'
end
@ -13,7 +13,7 @@ function _hyprctl_1
hyprctl clients | grep class | awk '{print $2}'
end
function _hyprctl_4
function _hyprctl_2
set 1 $argv[1]
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
end
@ -29,7 +29,7 @@ function _hyprctl
set COMP_CWORD (count $COMP_WORDS)
end
set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow"
set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow"
set --local descriptions
set descriptions[1] "Focus the next window on a workspace"
@ -54,100 +54,104 @@ function _hyprctl
set descriptions[31] "CONFUSED"
set descriptions[34] "Set a property of a window"
set descriptions[35] "Specify the Hyprland instance"
set descriptions[36] "Toggle the current window's floating state"
set descriptions[37] "Get the list of defined workspace rules"
set descriptions[38] "Move the focused window to a workspace"
set descriptions[40] "Temporarily enable or disable binds:ignore_group_lock"
set descriptions[41] "List all workspaces with their properties"
set descriptions[42] "Swap the active window with the next or previous in a group"
set descriptions[43] "Close a specified window"
set descriptions[44] "WARNING"
set descriptions[45] "Specify the Hyprland instance"
set descriptions[46] "List all registered binds"
set descriptions[47] "Move the active window in a direction or to a monitor"
set descriptions[48] "Change the split ratio"
set descriptions[50] "Prohibit the active window from becoming or being inserted into group"
set descriptions[51] "Change the workspace"
set descriptions[52] "List all current config parsing errors"
set descriptions[53] "Toggle the current active window into a group"
set descriptions[54] "Get the config option status (values)"
set descriptions[57] "Close the active window"
set descriptions[58] "Pass the key to a specified window"
set descriptions[59] "List all decorations and their info"
set descriptions[60] "List all connected keyboards and mice"
set descriptions[61] "Switch focus from current to previously focused window"
set descriptions[62] "Change the current mapping group"
set descriptions[63] "Execute a Global Shortcut using the GlobalShortcuts portal"
set descriptions[65] "Force the renderer to reload all resources and outputs"
set descriptions[66] "Move a selected window"
set descriptions[68] "Print the Hyprland version: flags, commit and branch of build"
set descriptions[69] "Set all monitors' DPMS status"
set descriptions[70] "Resize the active window"
set descriptions[71] "Move the active window into a group"
set descriptions[72] "OK"
set descriptions[74] "Set the current window's floating state to true"
set descriptions[75] "Print tail of the log"
set descriptions[78] "List all layouts available (including plugin ones)"
set descriptions[79] "Move a workspace to a monitor"
set descriptions[80] "Execute a shell command"
set descriptions[82] "Modify the window stack order of the active or specified window"
set descriptions[83] "Toggle the focused window's internal fullscreen state"
set descriptions[85] "Issue a keyword to call a config keyword dynamically"
set descriptions[88] "Pin a window"
set descriptions[89] "Allows adding/removing fake outputs to a specific backend"
set descriptions[91] "Toggle a special workspace on/off"
set descriptions[92] "Toggle the focused window's fullscreen state"
set descriptions[93] "Toggle the current window to always be opaque"
set descriptions[94] "Focus the requested workspace"
set descriptions[96] "Switch to the next window in a group"
set descriptions[97] "Output in JSON format"
set descriptions[98] "List all running Hyprland instances and their info"
set descriptions[99] "Execute a raw shell command"
set descriptions[100] "Exit the compositor with no questions asked"
set descriptions[101] "List all windows with their properties"
set descriptions[103] "Execute a batch of commands separated by ;"
set descriptions[104] "Dismiss all or up to amount of notifications"
set descriptions[106] "Set the xkb layout index for a keyboard"
set descriptions[107] "Move window doesnt switch to the workspace"
set descriptions[108] "Behave as moveintogroup"
set descriptions[109] "Refresh state after issuing the command"
set descriptions[110] "Move the focus in a direction"
set descriptions[111] "Focus the urgent window or the last window"
set descriptions[113] "Get the active workspace name and its properties"
set descriptions[114] "Issue a dispatch to call a keybind dispatcher with an arg"
set descriptions[116] "Center the active window"
set descriptions[117] "HINT"
set descriptions[118] "Interact with hyprpaper if present"
set descriptions[119] "No Icon"
set descriptions[120] "Force reload the config"
set descriptions[122] "Print system info"
set descriptions[123] "Interact with a plugin"
set descriptions[125] "Get the active window name and its properties"
set descriptions[126] "Swap the active workspaces between two monitors"
set descriptions[127] "Print the current random splash"
set descriptions[129] "Lock the focused group"
set descriptions[132] "Lock the groups"
set descriptions[133] "Move the cursor to the corner of the active window"
set descriptions[136] "INFO"
set descriptions[137] "Resize a selected window"
set descriptions[36] "Disable output"
set descriptions[37] "Toggle the current window's floating state"
set descriptions[38] "Get the list of defined workspace rules"
set descriptions[39] "Move the focused window to a workspace"
set descriptions[41] "Temporarily enable or disable binds:ignore_group_lock"
set descriptions[42] "List all workspaces with their properties"
set descriptions[43] "Swap the active window with the next or previous in a group"
set descriptions[44] "Close a specified window"
set descriptions[45] "WARNING"
set descriptions[46] "Specify the Hyprland instance"
set descriptions[47] "List all registered binds"
set descriptions[48] "Move the active window in a direction or to a monitor"
set descriptions[49] "Change the split ratio"
set descriptions[51] "Prohibit the active window from becoming or being inserted into group"
set descriptions[52] "Change the workspace"
set descriptions[53] "List all current config parsing errors"
set descriptions[54] "Toggle the current active window into a group"
set descriptions[55] "Get the config option status (values)"
set descriptions[58] "Close the active window"
set descriptions[59] "Pass the key to a specified window"
set descriptions[60] "List all decorations and their info"
set descriptions[61] "List all connected keyboards and mice"
set descriptions[62] "Switch focus from current to previously focused window"
set descriptions[63] "Change the current mapping group"
set descriptions[64] "Execute a Global Shortcut using the GlobalShortcuts portal"
set descriptions[66] "Force the renderer to reload all resources and outputs"
set descriptions[67] "Move a selected window"
set descriptions[69] "Print the Hyprland version: flags, commit and branch of build"
set descriptions[70] "Set all monitors' DPMS status"
set descriptions[71] "Resize the active window"
set descriptions[72] "Move the active window into a group"
set descriptions[73] "OK"
set descriptions[75] "Set the current window's floating state to true"
set descriptions[76] "Print tail of the log"
set descriptions[79] "List all layouts available (including plugin ones)"
set descriptions[80] "Move a workspace to a monitor"
set descriptions[81] "Execute a shell command"
set descriptions[83] "Modify the window stack order of the active or specified window"
set descriptions[84] "Toggle the focused window's internal fullscreen state"
set descriptions[86] "Issue a keyword to call a config keyword dynamically"
set descriptions[89] "Disable output"
set descriptions[90] "Pin a window"
set descriptions[91] "Allows adding/removing fake outputs to a specific backend"
set descriptions[93] "Toggle a special workspace on/off"
set descriptions[94] "Toggle the focused window's fullscreen state"
set descriptions[95] "Toggle the current window to always be opaque"
set descriptions[96] "Focus the requested workspace"
set descriptions[98] "Switch to the next window in a group"
set descriptions[99] "Output in JSON format"
set descriptions[100] "List all running Hyprland instances and their info"
set descriptions[101] "Execute a raw shell command"
set descriptions[102] "Exit the compositor with no questions asked"
set descriptions[103] "List all windows with their properties"
set descriptions[105] "Execute a batch of commands separated by ;"
set descriptions[106] "Dismiss all or up to amount of notifications"
set descriptions[108] "Set the xkb layout index for a keyboard"
set descriptions[109] "Move window doesnt switch to the workspace"
set descriptions[110] "Apply a tag to the window"
set descriptions[111] "Behave as moveintogroup"
set descriptions[112] "Refresh state after issuing the command"
set descriptions[113] "Move the focus in a direction"
set descriptions[114] "Focus the urgent window or the last window"
set descriptions[116] "Get the active workspace name and its properties"
set descriptions[117] "Issue a dispatch to call a keybind dispatcher with an arg"
set descriptions[119] "Center the active window"
set descriptions[120] "HINT"
set descriptions[121] "Interact with hyprpaper if present"
set descriptions[122] "No Icon"
set descriptions[123] "Force reload the config"
set descriptions[125] "Print system info"
set descriptions[126] "Interact with a plugin"
set descriptions[128] "Get the active window name and its properties"
set descriptions[129] "Swap the active workspaces between two monitors"
set descriptions[130] "Print the current random splash"
set descriptions[131] "On shortcut X sends shortcut Y to a specified window"
set descriptions[133] "Lock the focused group"
set descriptions[136] "Lock the groups"
set descriptions[137] "Move the cursor to the corner of the active window"
set descriptions[140] "INFO"
set descriptions[141] "Resize a selected window"
set --local literal_transitions
set literal_transitions[1] "set inputs 104 75 34 2 3 78 106 37 109 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 97 98 28 29 101 103; set tos 2 3 4 3 3 3 5 3 6 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 6 3 3 15 3 6"
set literal_transitions[4] "set inputs 73 14 33 55 56 90 105 121 77 17 124 4 6 64 128 130 81 131 84 32 49 13 86 11 87 138; set tos 19 3 19 19 19 19 3 3 2 3 19 2 3 19 3 19 19 19 19 19 3 3 19 19 19 19"
set literal_transitions[8] "set inputs 104 75 34 2 3 78 106 37 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 98 28 29 101; set tos 2 3 4 3 3 3 5 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3"
set literal_transitions[9] "set inputs 129 132 1 74 36 107 38 108 5 79 40 80 111 7 42 43 82 83 47 48 10 110 51 53 12 116 88 50 57 91 58 92 93 61 62 126 94 63 21 96 23 24 65 66 25 133 27 69 99 70 30 137 71 100; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3"
set literal_transitions[10] "set inputs 115 112; set tos 16 17"
set literal_transitions[12] "set inputs 102; set tos 3"
set literal_transitions[14] "set inputs 22 117 31 136 119 44 72; set tos 2 2 2 2 2 2 2"
set literal_transitions[15] "set inputs 39; set tos 3"
set literal_transitions[16] "set inputs 9 67 15 134; set tos 3 3 3 3"
set literal_transitions[18] "set inputs 76; set tos 20"
set literal_transitions[19] "set inputs 19 8; set tos 3 3"
set literal_transitions[20] "set inputs 35 45; set tos 6 6"
set literal_transitions[21] "set inputs 135 95; set tos 3 3"
set literal_transitions[1] "set inputs 106 76 34 36 2 3 79 108 38 112 42 47 116 86 117 53 89 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 99 100 28 29 103 105; set tos 2 3 4 5 3 3 3 6 3 5 3 3 3 7 9 3 5 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 5 3 3 15 3 5"
set literal_transitions[4] "set inputs 74 14 33 56 57 92 107 124 78 17 127 4 6 65 132 134 82 135 85 32 50 13 87 11 88 142; set tos 18 3 18 18 18 18 3 3 2 3 18 2 3 18 3 18 18 18 18 18 3 3 18 18 18 18"
set literal_transitions[8] "set inputs 106 76 34 2 3 79 108 38 42 47 116 86 117 53 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 100 28 29 103; set tos 2 3 4 3 3 3 6 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3"
set literal_transitions[9] "set inputs 102 131 133 1 75 37 109 110 39 111 5 80 41 81 114 7 43 44 83 84 48 49 10 51 52 54 12 113 90 119 58 93 59 94 95 62 63 129 96 64 21 98 23 24 66 67 136 137 25 27 70 101 71 141 30 72; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3"
set literal_transitions[10] "set inputs 118 115; set tos 21 17"
set literal_transitions[12] "set inputs 104; set tos 3"
set literal_transitions[14] "set inputs 22 120 31 140 122 45 73; set tos 2 2 2 2 2 2 2"
set literal_transitions[15] "set inputs 40; set tos 3"
set literal_transitions[16] "set inputs 139 97; set tos 3 3"
set literal_transitions[18] "set inputs 19 8; set tos 3 3"
set literal_transitions[19] "set inputs 77; set tos 20"
set literal_transitions[20] "set inputs 35 46; set tos 5 5"
set literal_transitions[21] "set inputs 9 68 15 138; set tos 3 3 3 3"
set --local match_anything_transitions_from 2 1 7 21 11 3 8 13 15 17 5 12
set --local match_anything_transitions_to 3 8 3 3 3 18 8 3 18 3 21 18
set --local match_anything_transitions_from 2 1 7 16 11 6 15 8 3 17 13 12
set --local match_anything_transitions_to 3 8 3 3 3 16 19 8 19 3 3 19
set --local state 1
set --local word_index 2
@ -199,8 +203,8 @@ function _hyprctl
end
end
set command_states 17 5 13 11
set command_ids 3 4 2 1
set command_states 6 17 13 11
set command_ids 2 3 4 1
if contains $state $command_states
set --local index (contains --index $state $command_states)
set --local function_id $command_ids[$index]

View File

@ -8,6 +8,7 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (-j) "Output in JSON format"
| (-r) "Refresh state after issuing the command"
| (--batch) "Execute a batch of commands separated by ;"
| (-q | --quiet) "Disable output"
;
<WINDOWS> ::= {{{ hyprctl clients | grep class | awk '{print $2}' }}};
@ -94,6 +95,7 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
<DISPATCHERS> ::= (exec) "Execute a shell command"
| (execr) "Execute a raw shell command"
| (pass) "Pass the key to a specified window"
| (sendshortcut) "On shortcut X sends shortcut Y to a specified window"
| (killactive) "Close the active window"
| (closewindow) "Close a specified window"
| (workspace) "Change the workspace"
@ -116,6 +118,7 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (movewindowpixel) "Move a selected window"
| (cyclenext) "Focus the next window on a workspace"
| (swapnext) "Swap the focused window with the next window"
| (tagwindow) "Apply a tag to the window"
| (focuswindow) "Focus the first window matching"
| (focusmonitor) "Focus a monitor"
| (splitratio) "Change the split ratio"

View File

@ -1,10 +1,8 @@
#compdef hyprctl
_hyprctl_cmd_2 () {
hyprctl monitors | grep Monitor | awk '{ print $2 }'
}
_hyprctl_cmd_1 () {
_hyprctl_cmd_3 () {
hyprpm list | grep "Plugin" | awk '{print $4}'
}
@ -12,12 +10,12 @@ _hyprctl_cmd_0 () {
hyprctl clients | grep class | awk '{print $2}'
}
_hyprctl_cmd_3 () {
_hyprctl_cmd_1 () {
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
}
_hyprctl () {
local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
local -A descriptions
descriptions[1]="Focus the next window on a workspace"
@ -42,100 +40,104 @@ _hyprctl () {
descriptions[31]="CONFUSED"
descriptions[34]="Set a property of a window"
descriptions[35]="Specify the Hyprland instance"
descriptions[36]="Toggle the current window's floating state"
descriptions[37]="Get the list of defined workspace rules"
descriptions[38]="Move the focused window to a workspace"
descriptions[40]="Temporarily enable or disable binds:ignore_group_lock"
descriptions[41]="List all workspaces with their properties"
descriptions[42]="Swap the active window with the next or previous in a group"
descriptions[43]="Close a specified window"
descriptions[44]="WARNING"
descriptions[45]="Specify the Hyprland instance"
descriptions[46]="List all registered binds"
descriptions[47]="Move the active window in a direction or to a monitor"
descriptions[48]="Change the split ratio"
descriptions[50]="Prohibit the active window from becoming or being inserted into group"
descriptions[51]="Change the workspace"
descriptions[52]="List all current config parsing errors"
descriptions[53]="Toggle the current active window into a group"
descriptions[54]="Get the config option status (values)"
descriptions[57]="Close the active window"
descriptions[58]="Pass the key to a specified window"
descriptions[59]="List all decorations and their info"
descriptions[60]="List all connected keyboards and mice"
descriptions[61]="Switch focus from current to previously focused window"
descriptions[62]="Change the current mapping group"
descriptions[63]="Execute a Global Shortcut using the GlobalShortcuts portal"
descriptions[65]="Force the renderer to reload all resources and outputs"
descriptions[66]="Move a selected window"
descriptions[68]="Print the Hyprland version: flags, commit and branch of build"
descriptions[69]="Set all monitors' DPMS status"
descriptions[70]="Resize the active window"
descriptions[71]="Move the active window into a group"
descriptions[72]="OK"
descriptions[74]="Set the current window's floating state to true"
descriptions[75]="Print tail of the log"
descriptions[78]="List all layouts available (including plugin ones)"
descriptions[79]="Move a workspace to a monitor"
descriptions[80]="Execute a shell command"
descriptions[82]="Modify the window stack order of the active or specified window"
descriptions[83]="Toggle the focused window's internal fullscreen state"
descriptions[85]="Issue a keyword to call a config keyword dynamically"
descriptions[88]="Pin a window"
descriptions[89]="Allows adding/removing fake outputs to a specific backend"
descriptions[91]="Toggle a special workspace on/off"
descriptions[92]="Toggle the focused window's fullscreen state"
descriptions[93]="Toggle the current window to always be opaque"
descriptions[94]="Focus the requested workspace"
descriptions[96]="Switch to the next window in a group"
descriptions[97]="Output in JSON format"
descriptions[98]="List all running Hyprland instances and their info"
descriptions[99]="Execute a raw shell command"
descriptions[100]="Exit the compositor with no questions asked"
descriptions[101]="List all windows with their properties"
descriptions[103]="Execute a batch of commands separated by ;"
descriptions[104]="Dismiss all or up to amount of notifications"
descriptions[106]="Set the xkb layout index for a keyboard"
descriptions[107]="Move window doesnt switch to the workspace"
descriptions[108]="Behave as moveintogroup"
descriptions[109]="Refresh state after issuing the command"
descriptions[110]="Move the focus in a direction"
descriptions[111]="Focus the urgent window or the last window"
descriptions[113]="Get the active workspace name and its properties"
descriptions[114]="Issue a dispatch to call a keybind dispatcher with an arg"
descriptions[116]="Center the active window"
descriptions[117]="HINT"
descriptions[118]="Interact with hyprpaper if present"
descriptions[119]="No Icon"
descriptions[120]="Force reload the config"
descriptions[122]="Print system info"
descriptions[123]="Interact with a plugin"
descriptions[125]="Get the active window name and its properties"
descriptions[126]="Swap the active workspaces between two monitors"
descriptions[127]="Print the current random splash"
descriptions[129]="Lock the focused group"
descriptions[132]="Lock the groups"
descriptions[133]="Move the cursor to the corner of the active window"
descriptions[136]="INFO"
descriptions[137]="Resize a selected window"
descriptions[36]="Disable output"
descriptions[37]="Toggle the current window's floating state"
descriptions[38]="Get the list of defined workspace rules"
descriptions[39]="Move the focused window to a workspace"
descriptions[41]="Temporarily enable or disable binds:ignore_group_lock"
descriptions[42]="List all workspaces with their properties"
descriptions[43]="Swap the active window with the next or previous in a group"
descriptions[44]="Close a specified window"
descriptions[45]="WARNING"
descriptions[46]="Specify the Hyprland instance"
descriptions[47]="List all registered binds"
descriptions[48]="Move the active window in a direction or to a monitor"
descriptions[49]="Change the split ratio"
descriptions[51]="Prohibit the active window from becoming or being inserted into group"
descriptions[52]="Change the workspace"
descriptions[53]="List all current config parsing errors"
descriptions[54]="Toggle the current active window into a group"
descriptions[55]="Get the config option status (values)"
descriptions[58]="Close the active window"
descriptions[59]="Pass the key to a specified window"
descriptions[60]="List all decorations and their info"
descriptions[61]="List all connected keyboards and mice"
descriptions[62]="Switch focus from current to previously focused window"
descriptions[63]="Change the current mapping group"
descriptions[64]="Execute a Global Shortcut using the GlobalShortcuts portal"
descriptions[66]="Force the renderer to reload all resources and outputs"
descriptions[67]="Move a selected window"
descriptions[69]="Print the Hyprland version: flags, commit and branch of build"
descriptions[70]="Set all monitors' DPMS status"
descriptions[71]="Resize the active window"
descriptions[72]="Move the active window into a group"
descriptions[73]="OK"
descriptions[75]="Set the current window's floating state to true"
descriptions[76]="Print tail of the log"
descriptions[79]="List all layouts available (including plugin ones)"
descriptions[80]="Move a workspace to a monitor"
descriptions[81]="Execute a shell command"
descriptions[83]="Modify the window stack order of the active or specified window"
descriptions[84]="Toggle the focused window's internal fullscreen state"
descriptions[86]="Issue a keyword to call a config keyword dynamically"
descriptions[89]="Disable output"
descriptions[90]="Pin a window"
descriptions[91]="Allows adding/removing fake outputs to a specific backend"
descriptions[93]="Toggle a special workspace on/off"
descriptions[94]="Toggle the focused window's fullscreen state"
descriptions[95]="Toggle the current window to always be opaque"
descriptions[96]="Focus the requested workspace"
descriptions[98]="Switch to the next window in a group"
descriptions[99]="Output in JSON format"
descriptions[100]="List all running Hyprland instances and their info"
descriptions[101]="Execute a raw shell command"
descriptions[102]="Exit the compositor with no questions asked"
descriptions[103]="List all windows with their properties"
descriptions[105]="Execute a batch of commands separated by ;"
descriptions[106]="Dismiss all or up to amount of notifications"
descriptions[108]="Set the xkb layout index for a keyboard"
descriptions[109]="Move window doesnt switch to the workspace"
descriptions[110]="Apply a tag to the window"
descriptions[111]="Behave as moveintogroup"
descriptions[112]="Refresh state after issuing the command"
descriptions[113]="Move the focus in a direction"
descriptions[114]="Focus the urgent window or the last window"
descriptions[116]="Get the active workspace name and its properties"
descriptions[117]="Issue a dispatch to call a keybind dispatcher with an arg"
descriptions[119]="Center the active window"
descriptions[120]="HINT"
descriptions[121]="Interact with hyprpaper if present"
descriptions[122]="No Icon"
descriptions[123]="Force reload the config"
descriptions[125]="Print system info"
descriptions[126]="Interact with a plugin"
descriptions[128]="Get the active window name and its properties"
descriptions[129]="Swap the active workspaces between two monitors"
descriptions[130]="Print the current random splash"
descriptions[131]="On shortcut X sends shortcut Y to a specified window"
descriptions[133]="Lock the focused group"
descriptions[136]="Lock the groups"
descriptions[137]="Move the cursor to the corner of the active window"
descriptions[140]="INFO"
descriptions[141]="Resize a selected window"
local -A literal_transitions
literal_transitions[1]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [109]=6 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [97]=6 [98]=3 [28]=3 [29]=15 [101]=3 [103]=6)"
literal_transitions[4]="([73]=19 [14]=3 [33]=19 [55]=19 [56]=19 [90]=19 [105]=3 [121]=3 [77]=2 [17]=3 [124]=19 [4]=2 [6]=3 [64]=19 [128]=3 [130]=19 [81]=19 [131]=19 [84]=19 [32]=19 [49]=3 [13]=3 [86]=19 [11]=19 [87]=19 [138]=19)"
literal_transitions[8]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [98]=3 [28]=3 [29]=15 [101]=3)"
literal_transitions[9]="([129]=3 [132]=3 [1]=3 [74]=3 [36]=3 [107]=3 [38]=3 [108]=3 [5]=3 [79]=3 [40]=3 [80]=3 [111]=3 [7]=3 [42]=3 [43]=3 [82]=3 [83]=3 [47]=3 [48]=3 [10]=3 [110]=3 [51]=3 [53]=3 [12]=3 [116]=3 [88]=3 [50]=3 [57]=3 [91]=3 [58]=3 [92]=3 [93]=3 [61]=3 [62]=3 [126]=3 [94]=3 [63]=3 [21]=3 [96]=3 [23]=3 [24]=3 [65]=3 [66]=3 [25]=3 [133]=3 [27]=3 [69]=3 [99]=3 [70]=3 [30]=3 [137]=3 [71]=3 [100]=3)"
literal_transitions[10]="([115]=16 [112]=17)"
literal_transitions[12]="([102]=3)"
literal_transitions[14]="([22]=2 [117]=2 [31]=2 [136]=2 [119]=2 [44]=2 [72]=2)"
literal_transitions[15]="([39]=3)"
literal_transitions[16]="([9]=3 [67]=3 [15]=3 [134]=3)"
literal_transitions[18]="([76]=20)"
literal_transitions[19]="([19]=3 [8]=3)"
literal_transitions[20]="([35]=6 [45]=6)"
literal_transitions[21]="([135]=3 [95]=3)"
literal_transitions[1]="([106]=2 [76]=3 [34]=4 [36]=5 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [112]=5 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [89]=5 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [99]=5 [100]=3 [28]=3 [29]=15 [103]=3 [105]=5)"
literal_transitions[4]="([74]=18 [14]=3 [33]=18 [56]=18 [57]=18 [92]=18 [107]=3 [124]=3 [78]=2 [17]=3 [127]=18 [4]=2 [6]=3 [65]=18 [132]=3 [134]=18 [82]=18 [135]=18 [85]=18 [32]=18 [50]=3 [13]=3 [87]=18 [11]=18 [88]=18 [142]=18)"
literal_transitions[8]="([106]=2 [76]=3 [34]=4 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [100]=3 [28]=3 [29]=15 [103]=3)"
literal_transitions[9]="([102]=3 [131]=3 [133]=3 [1]=3 [75]=3 [37]=3 [109]=3 [110]=3 [39]=3 [111]=3 [5]=3 [80]=3 [41]=3 [81]=3 [114]=3 [7]=3 [43]=3 [44]=3 [83]=3 [84]=3 [48]=3 [49]=3 [10]=3 [51]=3 [52]=3 [54]=3 [12]=3 [113]=3 [90]=3 [119]=3 [58]=3 [93]=3 [59]=3 [94]=3 [95]=3 [62]=3 [63]=3 [129]=3 [96]=3 [64]=3 [21]=3 [98]=3 [23]=3 [24]=3 [66]=3 [67]=3 [136]=3 [137]=3 [25]=3 [27]=3 [70]=3 [101]=3 [71]=3 [141]=3 [30]=3 [72]=3)"
literal_transitions[10]="([118]=21 [115]=17)"
literal_transitions[12]="([104]=3)"
literal_transitions[14]="([22]=2 [120]=2 [31]=2 [140]=2 [122]=2 [45]=2 [73]=2)"
literal_transitions[15]="([40]=3)"
literal_transitions[16]="([139]=3 [97]=3)"
literal_transitions[18]="([19]=3 [8]=3)"
literal_transitions[19]="([77]=20)"
literal_transitions[20]="([35]=5 [46]=5)"
literal_transitions[21]="([9]=3 [68]=3 [15]=3 [138]=3)"
local -A match_anything_transitions
match_anything_transitions=([2]=3 [1]=8 [7]=3 [21]=3 [11]=3 [3]=18 [8]=8 [13]=3 [15]=18 [17]=3 [5]=21 [12]=18)
match_anything_transitions=([2]=3 [1]=8 [7]=3 [16]=3 [11]=3 [6]=16 [15]=19 [8]=8 [3]=19 [17]=3 [13]=3 [12]=19)
declare -A subword_transitions
@ -195,7 +197,7 @@ _hyprctl () {
fi
done
fi
local -A commands=([17]=2 [5]=3 [13]=1 [11]=0)
local -A commands=([6]=1 [17]=2 [13]=3 [11]=0)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}

View File

@ -30,6 +30,7 @@
#define PAD
std::string instanceSignature;
bool quiet = false;
struct SInstanceData {
std::string id;
@ -39,6 +40,13 @@ struct SInstanceData {
bool valid = true;
};
void log(std::string str) {
if (quiet)
return;
std::cout << str;
}
std::string getRuntimeDir() {
const auto XDG = getenv("XDG_RUNTIME_DIR");
@ -96,17 +104,17 @@ int request(std::string arg, int minArgs = 0) {
const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
if (ARGS < minArgs) {
std::cout << "Not enough arguments, expected at least " << minArgs;
log("Not enough arguments, expected at least " + minArgs);
return -1;
}
if (SERVERSOCKET < 0) {
std::cout << "Couldn't open a socket (1)";
log("Couldn't open a socket (1)");
return 1;
}
if (instanceSignature.empty()) {
std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)";
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
return 2;
}
@ -120,14 +128,14 @@ int request(std::string arg, int minArgs = 0) {
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
std::cout << "Couldn't connect to " << socketPath << ". (3)";
log("Couldn't connect to " + socketPath + ". (3)");
return 3;
}
auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
if (sizeWritten < 0) {
std::cout << "Couldn't write (4)";
log("Couldn't write (4)");
return 4;
}
@ -137,7 +145,7 @@ int request(std::string arg, int minArgs = 0) {
sizeWritten = read(SERVERSOCKET, buffer, 8192);
if (sizeWritten < 0) {
std::cout << "Couldn't read (5)";
log("Couldn't read (5)");
return 5;
}
@ -146,7 +154,7 @@ int request(std::string arg, int minArgs = 0) {
while (sizeWritten == 8192) {
sizeWritten = read(SERVERSOCKET, buffer, 8192);
if (sizeWritten < 0) {
std::cout << "Couldn't read (5)";
log("Couldn't read (5)");
return 5;
}
reply += std::string(buffer, sizeWritten);
@ -154,7 +162,7 @@ int request(std::string arg, int minArgs = 0) {
close(SERVERSOCKET);
std::cout << reply;
log(reply);
return 0;
}
@ -163,12 +171,12 @@ int requestHyprpaper(std::string arg) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
if (SERVERSOCKET < 0) {
std::cout << "Couldn't open a socket (1)";
log("Couldn't open a socket (1)");
return 1;
}
if (instanceSignature.empty()) {
std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)";
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
return 2;
}
@ -182,7 +190,7 @@ int requestHyprpaper(std::string arg) {
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
std::cout << "Couldn't connect to " << socketPath << ". (3)";
log("Couldn't connect to " + socketPath + ". (3)");
return 3;
}
@ -192,7 +200,7 @@ int requestHyprpaper(std::string arg) {
auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
if (sizeWritten < 0) {
std::cout << "Couldn't write (4)";
log("Couldn't write (4)");
return 4;
}
@ -201,13 +209,13 @@ int requestHyprpaper(std::string arg) {
sizeWritten = read(SERVERSOCKET, buffer, 8192);
if (sizeWritten < 0) {
std::cout << "Couldn't read (5)";
log("Couldn't read (5)");
return 5;
}
close(SERVERSOCKET);
std::cout << std::string(buffer);
log(std::string(buffer));
return 0;
}
@ -250,7 +258,7 @@ void instancesRequest(bool json) {
result += "\n]";
}
std::cout << result << "\n";
log(result + "\n");
}
std::deque<std::string> splitArgs(int argc, char** argv) {
@ -297,6 +305,8 @@ int main(int argc, char** argv) {
fullArgs += "r";
} else if (ARGS[i] == "-a" && !fullArgs.contains("a")) {
fullArgs += "a";
} else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) {
fullArgs += "c";
} else if (ARGS[i] == "--batch") {
fullRequest = "--batch ";
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
@ -308,6 +318,8 @@ int main(int argc, char** argv) {
}
overrideInstance = ARGS[i];
} else if (ARGS[i] == "-q" || ARGS[i] == "--quiet") {
quiet = true;
} else if (ARGS[i] == "--help") {
const std::string& cmd = ARGS[0];
@ -358,7 +370,7 @@ int main(int argc, char** argv) {
instanceSignature = overrideInstance;
else if (!overrideInstance.empty()) {
if (!isNumber(overrideInstance, false)) {
std::cout << "instance invalid\n";
log("instance invalid\n");
return 1;
}
@ -367,7 +379,7 @@ int main(int argc, char** argv) {
const auto INSTANCES = instances();
if (INSTANCENO < 0 || static_cast<std::size_t>(INSTANCENO) >= INSTANCES.size()) {
std::cout << "no such instance\n";
log("no such instance\n");
return 1;
}
@ -376,7 +388,7 @@ int main(int argc, char** argv) {
const auto ISIG = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!ISIG) {
std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)\n";
log("HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)\n");
return 1;
}
@ -417,6 +429,6 @@ int main(int argc, char** argv) {
exitStatus = request(fullRequest);
}
std::cout << std::endl;
std::cout << std::flush;
return exitStatus;
}

View File

@ -495,6 +495,16 @@ bool CPluginManager::updateHeaders(bool force) {
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
if (ret.contains("required packages were not found")) {
// missing deps, let the user know.
std::string missing = ret.substr(ret.find("The following required packages were not found:"));
missing = missing.substr(0, missing.find("Call Stack"));
missing = missing.substr(0, missing.find_last_of('\n'));
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" << missing << "\n";
return false;
}
// le hack. Wlroots has to generate its build/include
ret = execAndGet("cd " + WORKINGDIR + "/subprojects/wlroots-hyprland && meson setup -Drenderers=gles2 -Dexamples=false build");
if (m_bVerbose)

View File

@ -27,6 +27,12 @@ endif
wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2'])
have_xwlr = wlroots.get_variable('features').get('xwayland')
xcb_dep = dependency('xcb', required: get_option('xwayland'))
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland'))
xcb_icccm_dep = dependency('xcb-icccm', required: get_option('xwayland'))
xcb_render_dep = dependency('xcb-render', required: get_option('xwayland'))
xcb_res_dep = dependency('xcb-res', required: get_option('xwayland'))
xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland'))
cmake = import('cmake')
udis = cmake.subproject('udis86')

View File

@ -1,3 +1,3 @@
{
"version": "0.40.0"
"version": "0.41.0"
}

View File

@ -24,7 +24,6 @@ hyprwayland_scanner = find_program(
)
protocols = [
[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
['wlr-screencopy-unstable-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
@ -41,6 +40,7 @@ new_protocols = [
['wlr-output-management-unstable-v1.xml'],
['kde-server-decoration.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['wayland-drm.xml'],
['wlr-data-control-unstable-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'],
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
@ -63,6 +63,9 @@ new_protocols = [
[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'],
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
[wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'],
[wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'],
[wl_protocol_dir, 'stable/viewporter/viewporter.xml'],
[wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'],
]
wl_protos_src = []

189
protocols/wayland-drm.xml Normal file
View File

@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="drm">
<copyright>
Copyright © 2008-2011 Kristian Høgsberg
Copyright © 2010-2011 Intel Corporation
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that\n the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<!-- drm support. This object is created by the server and published
using the display's global event. -->
<interface name="wl_drm" version="2">
<enum name="error">
<entry name="authenticate_fail" value="0"/>
<entry name="invalid_format" value="1"/>
<entry name="invalid_name" value="2"/>
</enum>
<enum name="format">
<!-- The drm format codes match the #defines in drm_fourcc.h.
The formats actually supported by the compositor will be
reported by the format event. New codes must not be added,
unless directly taken from drm_fourcc.h. -->
<entry name="c8" value="0x20203843"/>
<entry name="rgb332" value="0x38424752"/>
<entry name="bgr233" value="0x38524742"/>
<entry name="xrgb4444" value="0x32315258"/>
<entry name="xbgr4444" value="0x32314258"/>
<entry name="rgbx4444" value="0x32315852"/>
<entry name="bgrx4444" value="0x32315842"/>
<entry name="argb4444" value="0x32315241"/>
<entry name="abgr4444" value="0x32314241"/>
<entry name="rgba4444" value="0x32314152"/>
<entry name="bgra4444" value="0x32314142"/>
<entry name="xrgb1555" value="0x35315258"/>
<entry name="xbgr1555" value="0x35314258"/>
<entry name="rgbx5551" value="0x35315852"/>
<entry name="bgrx5551" value="0x35315842"/>
<entry name="argb1555" value="0x35315241"/>
<entry name="abgr1555" value="0x35314241"/>
<entry name="rgba5551" value="0x35314152"/>
<entry name="bgra5551" value="0x35314142"/>
<entry name="rgb565" value="0x36314752"/>
<entry name="bgr565" value="0x36314742"/>
<entry name="rgb888" value="0x34324752"/>
<entry name="bgr888" value="0x34324742"/>
<entry name="xrgb8888" value="0x34325258"/>
<entry name="xbgr8888" value="0x34324258"/>
<entry name="rgbx8888" value="0x34325852"/>
<entry name="bgrx8888" value="0x34325842"/>
<entry name="argb8888" value="0x34325241"/>
<entry name="abgr8888" value="0x34324241"/>
<entry name="rgba8888" value="0x34324152"/>
<entry name="bgra8888" value="0x34324142"/>
<entry name="xrgb2101010" value="0x30335258"/>
<entry name="xbgr2101010" value="0x30334258"/>
<entry name="rgbx1010102" value="0x30335852"/>
<entry name="bgrx1010102" value="0x30335842"/>
<entry name="argb2101010" value="0x30335241"/>
<entry name="abgr2101010" value="0x30334241"/>
<entry name="rgba1010102" value="0x30334152"/>
<entry name="bgra1010102" value="0x30334142"/>
<entry name="yuyv" value="0x56595559"/>
<entry name="yvyu" value="0x55595659"/>
<entry name="uyvy" value="0x59565955"/>
<entry name="vyuy" value="0x59555956"/>
<entry name="ayuv" value="0x56555941"/>
<entry name="xyuv8888" value="0x56555958"/>
<entry name="nv12" value="0x3231564e"/>
<entry name="nv21" value="0x3132564e"/>
<entry name="nv16" value="0x3631564e"/>
<entry name="nv61" value="0x3136564e"/>
<entry name="yuv410" value="0x39565559"/>
<entry name="yvu410" value="0x39555659"/>
<entry name="yuv411" value="0x31315559"/>
<entry name="yvu411" value="0x31315659"/>
<entry name="yuv420" value="0x32315559"/>
<entry name="yvu420" value="0x32315659"/>
<entry name="yuv422" value="0x36315559"/>
<entry name="yvu422" value="0x36315659"/>
<entry name="yuv444" value="0x34325559"/>
<entry name="yvu444" value="0x34325659"/>
<entry name="abgr16f" value="0x48344241"/>
<entry name="xbgr16f" value="0x48344258"/>
</enum>
<!-- Call this request with the magic received from drmGetMagic().
It will be passed on to the drmAuthMagic() or
DRIAuthConnection() call. This authentication must be
completed before create_buffer could be used. -->
<request name="authenticate">
<arg name="id" type="uint"/>
</request>
<!-- Create a wayland buffer for the named DRM buffer. The DRM
surface must have a name using the flink ioctl -->
<request name="create_buffer">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="stride" type="uint"/>
<arg name="format" type="uint"/>
</request>
<!-- Create a wayland buffer for the named DRM buffer. The DRM
surface must have a name using the flink ioctl -->
<request name="create_planar_buffer">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="format" type="uint"/>
<arg name="offset0" type="int"/>
<arg name="stride0" type="int"/>
<arg name="offset1" type="int"/>
<arg name="stride1" type="int"/>
<arg name="offset2" type="int"/>
<arg name="stride2" type="int"/>
</request>
<!-- Notification of the path of the drm device which is used by
the server. The client should use this device for creating
local buffers. Only buffers created from this device should
be be passed to the server using this drm object's
create_buffer request. -->
<event name="device">
<arg name="name" type="string"/>
</event>
<event name="format">
<arg name="format" type="uint"/>
</event>
<!-- Raised if the authenticate request succeeded -->
<event name="authenticated"/>
<enum name="capability" since="2">
<description summary="wl_drm capability bitmask">
Bitmask of capabilities.
</description>
<entry name="prime" value="1" summary="wl_drm prime available"/>
</enum>
<event name="capabilities">
<arg name="value" type="uint"/>
</event>
<!-- Version 2 additions -->
<!-- Create a wayland buffer for the prime fd. Use for regular and planar
buffers. Pass 0 for offset and stride for unused planes. -->
<request name="create_prime_buffer" since="2">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="fd"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="format" type="uint"/>
<arg name="offset0" type="int"/>
<arg name="stride0" type="int"/>
<arg name="offset1" type="int"/>
<arg name="stride1" type="int"/>
<arg name="offset2" type="int"/>
<arg name="stride2" type="int"/>
</request>
</interface>
</protocol>

View File

@ -19,7 +19,10 @@
#include "protocols/PointerConstraints.hpp"
#include "protocols/LayerShell.hpp"
#include "protocols/XDGShell.hpp"
#include "protocols/core/Compositor.hpp"
#include "protocols/core/Subcompositor.hpp"
#include "desktop/LayerSurface.hpp"
#include "xwayland/XWayland.hpp"
#include <sys/types.h>
#include <sys/stat.h>
@ -146,7 +149,7 @@ void CCompositor::initServer() {
m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay);
// register crit signal handler
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
m_critSigSource = wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
if (!envEnabled("HYPRLAND_NO_CRASHREPORTER")) {
signal(SIGSEGV, handleUnrecoverableSignal);
@ -183,7 +186,7 @@ void CCompositor::initServer() {
&isHeadlessOnly);
if (isHeadlessOnly) {
m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend);
m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); // TODO: remove this, it's barely needed now.
} else {
m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend);
if (m_iDRMFD < 0) {
@ -199,15 +202,6 @@ void CCompositor::initServer() {
throwError("wlr_gles2_renderer_create_with_drm_fd() failed!");
}
wlr_renderer_init_wl_shm(m_sWLRRenderer, m_sWLDisplay);
if (wlr_renderer_get_dmabuf_texture_formats(m_sWLRRenderer)) {
if (wlr_renderer_get_drm_fd(m_sWLRRenderer) >= 0)
wlr_drm_create(m_sWLDisplay, m_sWLRRenderer);
m_sWLRLinuxDMABuf = wlr_linux_dmabuf_v1_create_with_renderer(m_sWLDisplay, 4, m_sWLRRenderer);
}
m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer);
if (!m_sWLRAllocator) {
@ -222,13 +216,7 @@ void CCompositor::initServer() {
throwError("wlr_gles2_renderer_get_egl() failed!");
}
m_sWLRCompositor = wlr_compositor_create(m_sWLDisplay, 6, m_sWLRRenderer);
m_sWLRSubCompositor = wlr_subcompositor_create(m_sWLDisplay);
// m_sWLRDataDevMgr = wlr_data_device_manager_create(m_sWLDisplay);
// wlr_data_control_manager_v1_create(m_sWLDisplay);
// wlr_primary_selection_v1_device_manager_create(m_sWLDisplay);
wlr_viewporter_create(m_sWLDisplay);
initManagers(STAGE_BASICINIT);
m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend);
if (!m_sWRLDRMLeaseMgr) {
@ -243,8 +231,6 @@ void CCompositor::initServer() {
throwError("wlr_headless_backend_create() failed!");
}
wlr_single_pixel_buffer_manager_v1_create(m_sWLDisplay);
wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
initManagers(STAGE_LATE);
@ -319,7 +305,7 @@ void CCompositor::cleanup() {
// still in a normal working state.
g_pPluginSystem->unloadAllPlugins();
m_pLastFocus = nullptr;
m_pLastFocus.reset();
m_pLastWindow.reset();
m_vWorkspaces.clear();
@ -332,12 +318,9 @@ void CCompositor::cleanup() {
m->state.commit();
}
m_vMonitors.clear();
g_pXWayland.reset();
if (g_pXWaylandManager->m_sWLRXWayland) {
wlr_xwayland_destroy(g_pXWaylandManager->m_sWLRXWayland);
g_pXWaylandManager->m_sWLRXWayland = nullptr;
}
m_vMonitors.clear();
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
removeAllSignals();
@ -375,6 +358,9 @@ void CCompositor::cleanup() {
if (m_sWLRBackend)
wlr_backend_destroy(m_sWLRBackend);
if (m_critSigSource)
wl_event_source_remove(m_critSigSource);
wl_display_terminate(m_sWLDisplay);
m_sWLDisplay = nullptr;
@ -392,12 +378,6 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the HookSystem!");
g_pHookSystem = std::make_unique<CHookSystemManager>();
Debug::log(LOG, "Creating the ProtocolManager!");
g_pProtocolManager = std::make_unique<CProtocolManager>();
Debug::log(LOG, "Creating the SeatManager!");
g_pSeatManager = std::make_unique<CSeatManager>();
Debug::log(LOG, "Creating the KeybindManager!");
g_pKeybindManager = std::make_unique<CKeybindManager>();
@ -422,6 +402,16 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the PointerManager!");
g_pPointerManager = std::make_unique<CPointerManager>();
} break;
case STAGE_BASICINIT: {
Debug::log(LOG, "Creating the CHyprOpenGLImpl!");
g_pHyprOpenGL = std::make_unique<CHyprOpenGLImpl>();
Debug::log(LOG, "Creating the ProtocolManager!");
g_pProtocolManager = std::make_unique<CProtocolManager>();
Debug::log(LOG, "Creating the SeatManager!");
g_pSeatManager = std::make_unique<CSeatManager>();
} break;
case STAGE_LATE: {
Debug::log(LOG, "Creating the ThreadManager!");
g_pThreadManager = std::make_unique<CThreadManager>();
@ -432,9 +422,6 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the InputManager!");
g_pInputManager = std::make_unique<CInputManager>();
Debug::log(LOG, "Creating the CHyprOpenGLImpl!");
g_pHyprOpenGL = std::make_unique<CHyprOpenGLImpl>();
Debug::log(LOG, "Creating the HyprRenderer!");
g_pHyprRenderer = std::make_unique<CHyprRenderer>();
@ -462,6 +449,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the CursorManager!");
g_pCursorManager = std::make_unique<CCursorManager>();
Debug::log(LOG, "Starting XWayland");
g_pXWayland = std::make_unique<CXWayland>();
} break;
default: UNREACHABLE();
}
@ -570,6 +560,8 @@ void CCompositor::startCompositor() {
createLockFile();
EMIT_HOOK_EVENT("ready", nullptr);
// This blocks until we are done.
Debug::log(LOG, "Hyprland is ready, running the event loop!");
g_pEventLoopManager->enterLoop(m_sWLDisplay, m_sWLEventLoop);
@ -669,7 +661,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (properties & ALLOW_FLOATING) {
for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowBoxUnified(properties);
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0);
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) {
if (box.containsPoint(g_pPointerManager->position()))
return w;
@ -698,7 +690,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y)
continue;
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0);
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus &&
w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
// OR windows should add focus to parent
@ -707,7 +699,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (box.containsPoint(g_pPointerManager->position())) {
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
if (w->m_bIsX11 && w->m_iX11Type == 2 && !w->m_pXWaylandSurface->wantsFocus()) {
// Override Redirect
return g_pCompositor->m_pLastWindow.lock(); // we kinda trick everything here.
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
@ -785,47 +777,32 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
return windowForWorkspace(false);
}
wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW pWindow, Vector2D& sl) {
SP<CWLSurfaceResource> CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW pWindow, Vector2D& sl) {
if (!validMapped(pWindow))
return nullptr;
RASSERT(!pWindow->m_bIsX11, "Cannot call vectorWindowToSurface on an X11 window!");
double subx, suby;
CBox geom = pWindow->m_pXDGSurface->current.geometry;
// try popups first
const auto PPOPUP = pWindow->m_pPopupHead->at(pos);
const auto PPOPUP = pWindow->m_pPopupHead->at(pos);
wlr_surface* found = PPOPUP ? PPOPUP->m_sWLSurface.wlr() : nullptr;
if (!PPOPUP)
found = wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), pos.x - pWindow->m_vRealPosition.value().x + geom.x, pos.y - pWindow->m_vRealPosition.value().y + geom.y, &subx,
&suby);
else {
if (PPOPUP) {
const auto OFF = PPOPUP->coordsRelativeToParent();
subx = pos.x - OFF.x + geom.x - pWindow->m_vRealPosition.goal().x;
suby = pos.y - OFF.y + geom.y - pWindow->m_vRealPosition.goal().y;
sl = pos - pWindow->m_vRealPosition.goal() - OFF;
return PPOPUP->m_pWLSurface->resource();
}
if (found) {
sl.x = subx;
sl.y = suby;
return found;
auto [surf, local] = pWindow->m_pWLSurface->resource()->at(pos - pWindow->m_vRealPosition.goal(), true);
if (surf) {
sl = local;
return surf;
}
sl.x = pos.x - pWindow->m_vRealPosition.value().x;
sl.y = pos.y - pWindow->m_vRealPosition.value().y;
sl.x += geom.x;
sl.y += geom.y;
return pWindow->m_pWLSurface.wlr();
return nullptr;
}
Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindow, wlr_surface* pSurface) {
Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface) {
if (!validMapped(pWindow))
return {};
@ -836,25 +813,22 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo
if (PPOPUP)
return vec - PPOPUP->coordsGlobal();
std::tuple<wlr_surface*, int, int> iterData = {pSurface, -1337, -1337};
std::tuple<SP<CWLSurfaceResource>, Vector2D> iterData = {pSurface, {-1337, -1337}};
wlr_surface_for_each_surface(
pWindow->m_pWLSurface.wlr(),
[](wlr_surface* surf, int x, int y, void* data) {
const auto PDATA = (std::tuple<wlr_surface*, int, int>*)data;
if (surf == std::get<0>(*PDATA)) {
std::get<1>(*PDATA) = x;
std::get<2>(*PDATA) = y;
}
pWindow->m_pWLSurface->resource()->breadthfirst(
[](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) {
const auto PDATA = (std::tuple<SP<CWLSurfaceResource>, Vector2D>*)data;
if (surf == std::get<0>(*PDATA))
std::get<1>(*PDATA) = offset;
},
&iterData);
CBox geom = pWindow->m_pXDGSurface->current.geometry;
if (std::get<1>(iterData) == -1337 && std::get<2>(iterData) == -1337)
if (std::get<1>(iterData) == Vector2D{-1337, -1337})
return vec - pWindow->m_vRealPosition.goal();
return vec - pWindow->m_vRealPosition.goal() - Vector2D{std::get<1>(iterData), std::get<2>(iterData)} + Vector2D{geom.x, geom.y};
return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y};
}
CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
@ -877,7 +851,7 @@ CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) {
return nullptr;
}
void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) {
void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
static auto PSPECIALFALLTHROUGH = CConfigValue<Hyprlang::INT>("input:special_fallthrough");
@ -892,7 +866,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) {
return;
}
if (pWindow && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(pWindow->m_uSurface.xwayland))
if (pWindow && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2 && !pWindow->m_pXWaylandSurface->wantsFocus())
return;
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
@ -920,7 +894,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) {
g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(nullptr);
m_pLastFocus = nullptr;
m_pLastFocus.reset();
g_pInputManager->recheckIdleInhibitorStatus();
return;
@ -972,7 +946,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) {
m_pLastWindow = PLASTWINDOW;
const auto PWINDOWSURFACE = pSurface ? pSurface : pWindow->m_pWLSurface.wlr();
const auto PWINDOWSURFACE = pSurface ? pSurface : pWindow->m_pWLSurface->resource();
focusSurface(PWINDOWSURFACE, pWindow);
@ -1007,9 +981,9 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) {
g_pInputManager->sendMotionEventsToFocused();
}
void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) {
void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindowOwner) {
if (g_pSeatManager->state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->state.keyboardFocus == pWindowOwner->m_pWLSurface.wlr()))
if (g_pSeatManager->state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->state.keyboardFocus == pWindowOwner->m_pWLSurface->resource()))
return; // Don't focus when already focused on this.
if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface))
@ -1020,18 +994,18 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) {
return;
}
const auto PLASTSURF = m_pLastFocus;
const auto PLASTSURF = m_pLastFocus.lock();
// Unfocus last surface if should
if (m_pLastFocus && !pWindowOwner)
g_pXWaylandManager->activateSurface(m_pLastFocus, false);
g_pXWaylandManager->activateSurface(m_pLastFocus.lock(), false);
if (!pSurface) {
g_pSeatManager->setKeyboardFocus(nullptr);
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""});
EMIT_HOOK_EVENT("keyboardFocus", (wlr_surface*)nullptr);
m_pLastFocus = nullptr;
EMIT_HOOK_EVENT("keyboardFocus", (SP<CWLSurfaceResource>)nullptr);
m_pLastFocus.reset();
return;
}
@ -1048,8 +1022,8 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) {
EMIT_HOOK_EVENT("keyboardFocus", pSurface);
const auto SURF = CWLSurface::surfaceFromWlr(pSurface);
const auto OLDSURF = CWLSurface::surfaceFromWlr(PLASTSURF);
const auto SURF = CWLSurface::fromResource(pSurface);
const auto OLDSURF = CWLSurface::fromResource(PLASTSURF);
if (OLDSURF && OLDSURF->constraint())
OLDSURF->constraint()->deactivate();
@ -1058,7 +1032,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) {
SURF->constraint()->activate();
}
wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) {
SP<CWLSurfaceResource> CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) {
for (auto& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) {
for (auto& ls : lsl | std::views::reverse) {
if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f)
@ -1069,7 +1043,7 @@ wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonito
if (SURFACEAT) {
*ppLayerSurfaceFound = ls.lock();
*sCoords = pos - SURFACEAT->coordsGlobal();
return SURFACEAT->m_sWLSurface.wlr();
return SURFACEAT->m_pWLSurface->resource();
}
}
}
@ -1077,31 +1051,34 @@ wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonito
return nullptr;
}
wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<PHLLSREF>* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) {
SP<CWLSurfaceResource> CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<PHLLSREF>* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) {
for (auto& ls : *layerSurfaces | std::views::reverse) {
if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f)
continue;
auto SURFACEAT = wlr_surface_surface_at(ls->layerSurface->surface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y);
auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos());
if (SURFACEAT) {
if (!pixman_region32_not_empty(&SURFACEAT->input_region))
if (surf) {
if (surf->current.input.empty())
continue;
*ppLayerSurfaceFound = ls.lock();
return SURFACEAT;
*sCoords = local;
return surf;
}
}
return nullptr;
}
PHLWINDOW CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
PHLWINDOW CCompositor::getWindowFromSurface(SP<CWLSurfaceResource> pSurface) {
for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_bFadingOut)
continue;
if (w->m_pWLSurface.wlr() == pSurface)
if (w->m_pWLSurface->resource() == pSurface)
return w;
}
@ -1240,7 +1217,7 @@ bool CCompositor::isWindowActive(PHLWINDOW pWindow) {
if (!pWindow->m_bIsMapped)
return false;
const auto PSURFACE = pWindow->m_pWLSurface.wlr();
const auto PSURFACE = pWindow->m_pWLSurface->resource();
return PSURFACE == m_pLastFocus || pWindow == m_pLastWindow.lock();
}
@ -1273,10 +1250,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
if (top)
pWindow->m_bCreatedOverFullscreen = true;
if (!pWindow->m_bIsX11) {
if (!pWindow->m_bIsX11)
moveToZ(pWindow, top);
return;
} else {
else {
// move X11 window stack
std::deque<PHLWINDOW> toMove;
@ -1288,7 +1264,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
toMove.emplace_front(pw);
for (auto& w : m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) {
x11Stack(w, top, x11Stack);
}
}
@ -1643,11 +1619,6 @@ bool CCompositor::isPointOnReservedArea(const Vector2D& point, const CMonitor* p
return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y);
}
void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) {
auto pair = (std::pair<wlr_surface*, bool>*)data;
pair->second = pair->second || pSurface == pair->first;
}
CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
return this->getMonitorInDirection(m_pLastMonitor.get(), dir);
}
@ -2226,7 +2197,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) {
if (!w->m_bIsX11)
continue;
if (w->m_uSurface.xwayland == pWindow->m_uSurface.xwayland->parent)
if (w->m_pXWaylandSurface == pWindow->m_pXWaylandSurface->parent)
return w;
}
@ -2366,8 +2337,12 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) {
static auto PNOWARPS = CConfigValue<Hyprlang::INT>("cursor:no_warps");
if (*PNOWARPS && !force)
if (*PNOWARPS && !force) {
const auto PMONITORNEW = getMonitorFromVector(pos);
if (PMONITORNEW != m_pLastMonitor.get())
setActiveMonitor(PMONITORNEW);
return;
}
g_pPointerManager->warpTo(pos);
@ -2382,24 +2357,24 @@ void CCompositor::closeWindow(PHLWINDOW pWindow) {
}
}
PHLLS CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) {
std::pair<wlr_surface*, bool> result = {pSurface, false};
PHLLS CCompositor::getLayerSurfaceFromSurface(SP<CWLSurfaceResource> pSurface) {
std::pair<SP<CWLSurfaceResource>, bool> result = {pSurface, false};
for (auto& ls : m_vLayers) {
if (ls->layerSurface && ls->layerSurface->surface == pSurface)
return ls;
static auto iter = [](wlr_surface* surf, int x, int y, void* data) -> void {
if (surf == ((std::pair<wlr_surface*, bool>*)data)->first) {
*(bool*)data = true;
return;
}
};
if (!ls->layerSurface || !ls->mapped)
continue;
wlr_surface_for_each_surface(ls->layerSurface->surface, iter, &result);
ls->layerSurface->surface->breadthfirst(
[](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) {
if (surf == ((std::pair<SP<CWLSurfaceResource>, bool>*)data)->first) {
*(bool*)data = true;
return;
}
},
&result);
if (result.second)
return ls;
@ -2666,6 +2641,7 @@ void CCompositor::arrangeMonitors() {
maxXOffsetLeft = newPosition.x;
break;
case eAutoDirs::DIR_AUTO_RIGHT:
case eAutoDirs::DIR_AUTO_NONE:
newPosition.x = maxXOffsetRight;
maxXOffsetRight += m->vecSize.x;
break;
@ -2730,13 +2706,13 @@ void CCompositor::leaveUnsafeState() {
}
}
void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) {
void CCompositor::setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, double scale) {
PROTO::fractional->sendScale(pSurface, scale);
wlr_surface_set_preferred_buffer_scale(pSurface, static_cast<int32_t>(std::ceil(scale)));
pSurface->sendPreferredScale(std::ceil(scale));
const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
const auto PSURFACE = CWLSurface::fromResource(pSurface);
if (!PSURFACE) {
Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface);
Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface);
return;
}
@ -2744,12 +2720,12 @@ void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scal
PSURFACE->m_iLastScale = static_cast<int32_t>(std::ceil(scale));
}
void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) {
wlr_surface_set_preferred_buffer_transform(pSurface, transform);
void CCompositor::setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform) {
pSurface->sendPreferredTransform(transform);
const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
const auto PSURFACE = CWLSurface::fromResource(pSurface);
if (!PSURFACE) {
Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface);
Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface);
return;
}

View File

@ -29,8 +29,11 @@
#include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp"
class CWLSurfaceResource;
enum eManagersInitStage {
STAGE_PRIORITY = 0,
STAGE_BASICINIT,
STAGE_LATE
};
@ -79,7 +82,7 @@ class CCompositor {
void createLockFile();
void removeLockFile();
wlr_surface* m_pLastFocus = nullptr;
WP<CWLSurfaceResource> m_pLastFocus;
PHLWINDOWREF m_pLastWindow;
WP<CMonitor> m_pLastMonitor;
@ -96,114 +99,97 @@ class CCompositor {
// ------------------------------------------------- //
CMonitor* getMonitorFromID(const int&);
CMonitor* getMonitorFromName(const std::string&);
CMonitor* getMonitorFromDesc(const std::string&);
CMonitor* getMonitorFromCursor();
CMonitor* getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, wlr_surface* pSurface = nullptr);
void focusSurface(wlr_surface*, PHLWINDOW pWindowOwner = nullptr);
bool monitorExists(CMonitor*);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*);
wlr_surface* vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*);
wlr_surface* vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, wlr_surface*);
CMonitor* getMonitorFromOutput(wlr_output*);
CMonitor* getRealMonitorFromOutput(wlr_output*);
PHLWINDOW getWindowFromSurface(wlr_surface*);
PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE);
PHLWORKSPACE getWorkspaceByID(const int&);
PHLWORKSPACE getWorkspaceByName(const std::string&);
PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&);
void updateWorkspaceSpecialRenderData(const int&);
int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
PHLWINDOW getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const int&);
PHLWINDOW getFirstWindowOnWorkspace(const int&);
PHLWINDOW getTopLeftWindowOnWorkspace(const int&);
PHLWINDOW getFullscreenWindowOnWorkspace(const int&);
bool isWindowActive(PHLWINDOW);
void changeWindowZOrder(PHLWINDOW, bool);
void cleanupFadingOut(const int& monid);
PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
int getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
CMonitor* getMonitorInDirection(const char&);
CMonitor* getMonitorInDirection(CMonitor*, const char&);
void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const int64_t& id);
void updateWindowAnimatedDecorationValues(PHLWINDOW);
int getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&);
void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW);
void scheduleFrameForMonitor(CMonitor*);
void addToFadingOutSafe(PHLLS);
void addToFadingOutSafe(PHLWINDOW);
PHLWINDOW getWindowByRegex(const std::string&);
void warpCursorTo(const Vector2D&, bool force = false);
PHLLS getLayerSurfaceFromSurface(wlr_surface*);
void closeWindow(PHLWINDOW);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const int&);
PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused!
void renameWorkspace(const int&, const std::string& name = "");
void setActiveMonitor(CMonitor*);
bool isWorkspaceSpecial(const int&);
int getNewSpecialID();
void performUserChecks();
void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace);
PHLWINDOW getForceFocus();
void arrangeMonitors();
void enterUnsafeState();
void leaveUnsafeState();
void setPreferredScaleForSurface(wlr_surface* pSurface, double scale);
void setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform);
void updateSuspendedStates();
PHLWINDOW windowForCPointer(CWindow*);
CMonitor* getMonitorFromID(const int&);
CMonitor* getMonitorFromName(const std::string&);
CMonitor* getMonitorFromDesc(const std::string&);
CMonitor* getMonitorFromCursor();
CMonitor* getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr);
void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr);
bool monitorExists(CMonitor*);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
CMonitor* getMonitorFromOutput(wlr_output*);
CMonitor* getRealMonitorFromOutput(wlr_output*);
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE);
PHLWORKSPACE getWorkspaceByID(const int&);
PHLWORKSPACE getWorkspaceByName(const std::string&);
PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&);
void updateWorkspaceSpecialRenderData(const int&);
int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
PHLWINDOW getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const int&);
PHLWINDOW getFirstWindowOnWorkspace(const int&);
PHLWINDOW getTopLeftWindowOnWorkspace(const int&);
PHLWINDOW getFullscreenWindowOnWorkspace(const int&);
bool isWindowActive(PHLWINDOW);
void changeWindowZOrder(PHLWINDOW, bool);
void cleanupFadingOut(const int& monid);
PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
int getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
CMonitor* getMonitorInDirection(const char&);
CMonitor* getMonitorInDirection(CMonitor*, const char&);
void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const int64_t& id);
void updateWindowAnimatedDecorationValues(PHLWINDOW);
int getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&);
void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW);
void scheduleFrameForMonitor(CMonitor*);
void addToFadingOutSafe(PHLLS);
void addToFadingOutSafe(PHLWINDOW);
PHLWINDOW getWindowByRegex(const std::string&);
void warpCursorTo(const Vector2D&, bool force = false);
PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>);
void closeWindow(PHLWINDOW);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const int&);
PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused!
void renameWorkspace(const int&, const std::string& name = "");
void setActiveMonitor(CMonitor*);
bool isWorkspaceSpecial(const int&);
int getNewSpecialID();
void performUserChecks();
void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace);
PHLWINDOW getForceFocus();
void arrangeMonitors();
void enterUnsafeState();
void leaveUnsafeState();
void setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, double scale);
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates();
PHLWINDOW windowForCPointer(CWindow*);
std::string explicitConfigPath;
std::string explicitConfigPath;
private:
void initAllSignals();
void removeAllSignals();
void cleanEnvironment();
void setRandomSplash();
void initManagers(eManagersInitStage stage);
void prepareFallbackOutput();
void initAllSignals();
void removeAllSignals();
void cleanEnvironment();
void setRandomSplash();
void initManagers(eManagersInitStage stage);
void prepareFallbackOutput();
uint64_t m_iHyprlandPID = 0;
uint64_t m_iHyprlandPID = 0;
wl_event_source* m_critSigSource = nullptr;
};
inline std::unique_ptr<CCompositor> g_pCompositor;
// For XWayland
inline std::map<std::string, xcb_atom_t> HYPRATOMS = {HYPRATOM("_NET_WM_WINDOW_TYPE"),
HYPRATOM("_NET_WM_WINDOW_TYPE_NORMAL"),
HYPRATOM("_NET_WM_WINDOW_TYPE_DOCK"),
HYPRATOM("_NET_WM_WINDOW_TYPE_DIALOG"),
HYPRATOM("_NET_WM_WINDOW_TYPE_UTILITY"),
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLBAR"),
HYPRATOM("_NET_WM_WINDOW_TYPE_SPLASH"),
HYPRATOM("_NET_WM_WINDOW_TYPE_MENU"),
HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"),
HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"),
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"),
HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION"),
HYPRATOM("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"),
HYPRATOM("_NET_SUPPORTING_WM_CHECK"),
HYPRATOM("_NET_WM_NAME"),
HYPRATOM("UTF8_STRING")};

View File

@ -19,6 +19,7 @@
#include <iostream>
#include <sstream>
#include <ranges>
#include <unordered_set>
#include <xkbcommon/xkbcommon.h>
extern "C" char** environ;
@ -499,6 +500,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("gestures:workspace_swipe", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_fingers", Hyprlang::INT{3});
m_pConfig->addConfigValue("gestures:workspace_swipe_min_fingers", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_distance", Hyprlang::INT{300});
m_pConfig->addConfigValue("gestures:workspace_swipe_invert", Hyprlang::INT{1});
m_pConfig->addConfigValue("gestures:workspace_swipe_min_speed_to_force", Hyprlang::INT{30});
@ -520,6 +522,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:default_monitor", {STRVAL_EMPTY});
m_pConfig->addConfigValue("cursor:zoom_factor", {1.f});
m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0});
@ -633,6 +636,25 @@ std::string CConfigManager::getMainConfigPath() {
return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf");
}
const std::string CConfigManager::getConfigString() {
std::string configString;
std::string currFileContent;
for (auto path : configPaths) {
std::ifstream configFile(path);
configString += ("\n\nConfig File: " + path + ": ");
if (!configFile.is_open()) {
Debug::log(LOG, "Config file not readable/found!");
configString += "Read Failed\n";
continue;
}
configString += "Read Succeeded\n";
currFileContent.assign(std::istreambuf_iterator<char>(configFile), std::istreambuf_iterator<char>());
configString.append(currFileContent);
}
return configString;
}
std::string CConfigManager::getErrors() {
return m_szConfigErrors;
}
@ -975,7 +997,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) {
Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName);
for (auto& r : m_dMonitorRules) {
if (r.name == "") {
if (r.name.empty()) {
return r;
}
}
@ -1061,12 +1083,17 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
bool hasFloating = pWindow->m_bIsFloating;
bool hasFullscreen = pWindow->m_bIsFullscreen;
// local tags for dynamic tag rule match
auto tags = pWindow->m_tags;
for (auto& rule : m_dWindowRules) {
// check if we have a matching rule
if (!rule.v2) {
try {
if (rule.szValue.starts_with("tag:") && !tags.isTagged(rule.szValue.substr(4)))
continue;
if (rule.szValue.starts_with("title:")) {
// we have a title rule.
std::regex RULECHECK(rule.szValue.substr(6));
if (!std::regex_search(title, RULECHECK))
@ -1083,28 +1110,31 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
}
} else {
try {
if (rule.szClass != "") {
if (!rule.szTag.empty() && !tags.isTagged(rule.szTag))
continue;
if (!rule.szClass.empty()) {
std::regex RULECHECK(rule.szClass);
if (!std::regex_search(appidclass, RULECHECK))
continue;
}
if (rule.szTitle != "") {
if (!rule.szTitle.empty()) {
std::regex RULECHECK(rule.szTitle);
if (!std::regex_search(title, RULECHECK))
continue;
}
if (rule.szInitialTitle != "") {
if (!rule.szInitialTitle.empty()) {
std::regex RULECHECK(rule.szInitialTitle);
if (!std::regex_search(pWindow->m_szInitialTitle, RULECHECK))
continue;
}
if (rule.szInitialClass != "") {
if (!rule.szInitialClass.empty()) {
std::regex RULECHECK(rule.szInitialClass);
if (!std::regex_search(pWindow->m_szInitialClass, RULECHECK))
@ -1173,6 +1203,13 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
returns.push_back(rule);
// apply tag with local tags
if (rule.szRule.starts_with("tag")) {
CVarList vars{rule.szRule, 0, 's', true};
if (vars.size() == 2 && vars[0] == "tag")
tags.applyTag(vars[1], true);
}
if (dynamic)
continue;
@ -1264,6 +1301,18 @@ void CConfigManager::appendMonitorRule(const SMonitorRule& r) {
m_dMonitorRules.emplace_back(r);
}
bool CConfigManager::replaceMonitorRule(const SMonitorRule& newrule) {
// Looks for an existing monitor rule (compared by name).
// If the rule exists, it is replaced with the input rule.
for (auto& r : m_dMonitorRules) {
if (r.name == newrule.name) {
r = newrule;
return true;
}
}
return false;
}
void CConfigManager::performMonitorReload() {
bool overAgain = false;
@ -1665,7 +1714,7 @@ std::optional<std::string> CConfigManager::handleMonitor(const std::string& comm
newrule.resolution = Vector2D(-1, -2);
} else if (parseModeLine(ARGS[1], newrule.drmMode)) {
newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay);
newrule.refreshRate = newrule.drmMode.vrefresh / 1000;
newrule.refreshRate = float(newrule.drmMode.vrefresh) / 1000;
} else {
if (!ARGS[1].contains("x")) {
@ -1992,7 +2041,7 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
if ((KEY != "") || multiKey) {
SParsedKey parsedKey = parseKey(KEY);
if (parsedKey.catchAll && m_szCurrentSubmap == "") {
if (parsedKey.catchAll && m_szCurrentSubmap.empty()) {
Debug::log(ERR, "Catchall not allowed outside of submap!");
return "Invalid catchall, catchall keybinds are only allowed in submaps.";
}
@ -2017,18 +2066,24 @@ std::optional<std::string> CConfigManager::handleUnbind(const std::string& comma
}
bool windowRuleValid(const std::string& RULE) {
return RULE == "float" || RULE == "tile" || RULE.starts_with("opacity") || RULE.starts_with("move") || RULE.starts_with("size") || RULE.starts_with("minsize") ||
RULE.starts_with("maxsize") || RULE.starts_with("pseudo") || RULE.starts_with("monitor") || RULE.starts_with("idleinhibit") || RULE == "nofocus" || RULE == "noblur" ||
RULE == "noshadow" || RULE == "nodim" || RULE == "noborder" || RULE == "opaque" || RULE == "forceinput" || RULE == "fullscreen" || RULE == "fakefullscreen" ||
RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" || RULE == "maximize" || RULE == "keepaspectratio" ||
RULE == "focusonactivate" || RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") || RULE.starts_with("bordercolor") ||
RULE == "forcergbx" || RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") || RULE.starts_with("center") ||
RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor" || RULE.starts_with("suppressevent") || RULE.starts_with("plugin:");
static const auto rules = std::unordered_set<std::string>{
"dimaround", "fakefullscreen", "float", "focusonactivate", "forceinput", "forcergbx", "fullscreen", "immediate",
"keepaspectratio", "maximize", "nearestneighbor", "noanim", "noblur", "noborder", "nodim", "nofocus",
"noinitialfocus", "nomaxsize", "noshadow", "opaque", "pin", "stayfocused", "tile", "windowdance",
};
static const auto rulesPrefix = std::vector<std::string>{
"animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move",
"opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray",
};
return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); });
}
bool layerRuleValid(const std::string& RULE) {
return RULE == "noanim" || RULE == "blur" || RULE == "blurpopups" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE == "dimaround" ||
RULE.starts_with("xray") || RULE.starts_with("animation");
static const auto rules = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
static const auto rulesPrefix = std::vector<std::string>{"ignorealpha", "ignorezero", "xray", "animation"};
return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); });
}
std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
@ -2036,7 +2091,7 @@ std::optional<std::string> CConfigManager::handleWindowRule(const std::string& c
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
// check rule and value
if (RULE == "" || VALUE == "")
if (RULE.empty() || VALUE.empty())
return "empty rule?";
if (RULE == "unset") {
@ -2063,7 +2118,7 @@ std::optional<std::string> CConfigManager::handleLayerRule(const std::string& co
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
// check rule and value
if (RULE == "" || VALUE == "")
if (RULE.empty() || VALUE.empty())
return "empty rule?";
if (RULE == "unset") {
@ -2101,6 +2156,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
rule.szRule = RULE;
rule.szValue = VALUE;
const auto TAGPOS = VALUE.find("tag:");
const auto TITLEPOS = VALUE.find("title:");
const auto CLASSPOS = VALUE.find("class:");
const auto INITIALTITLEPOS = VALUE.find("initialTitle:");
@ -2123,9 +2179,10 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
currentPos = VALUE.find("workspace:", currentPos + 1);
}
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && INITIALTITLEPOS == std::string::npos && INITIALCLASSPOS == std::string::npos &&
X11POS == std::string::npos && FLOATPOS == std::string::npos && FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos &&
FOCUSPOS == std::string::npos && ONWORKSPACEPOS == std::string::npos) {
const auto checkPos = std::unordered_set{
TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, FULLSCREENPOS, PINNEDPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS,
};
if (checkPos.size() == 1 && checkPos.contains(std::string::npos)) {
Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE);
return "Invalid rulev2 syntax: " + VALUE;
}
@ -2135,6 +2192,8 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
result = VALUE.substr(pos);
size_t min = 999999;
if (TAGPOS > pos && TAGPOS < min)
min = TAGPOS;
if (TITLEPOS > pos && TITLEPOS < min)
min = TITLEPOS;
if (CLASSPOS > pos && CLASSPOS < min)
@ -2168,6 +2227,9 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
return result;
};
if (TAGPOS != std::string::npos)
rule.szTag = extract(TAGPOS + 4);
if (CLASSPOS != std::string::npos)
rule.szClass = extract(CLASSPOS + 6);
@ -2206,6 +2268,9 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
if (!other.v2) {
return other.szClass == rule.szClass && !rule.szClass.empty();
} else {
if (!rule.szTag.empty() && rule.szTag != other.szTag)
return false;
if (!rule.szClass.empty() && rule.szClass != other.szClass)
return false;

View File

@ -103,6 +103,7 @@ class CConfigManager {
void onPluginLoadUnload(const std::string& name, bool load);
static std::string getConfigDir();
static std::string getMainConfigPath();
const std::string getConfigString();
SMonitorRule getMonitorRuleFor(const CMonitor&);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
@ -128,6 +129,7 @@ class CConfigManager {
void performMonitorReload();
void appendMonitorRule(const SMonitorRule&);
bool replaceMonitorRule(const SMonitorRule&);
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;

View File

@ -14,6 +14,7 @@
#include <sstream>
#include <string>
#include <typeindex>
#include <numeric>
#include "../config/ConfigDataValues.hpp"
#include "../config/ConfigValue.hpp"
@ -23,6 +24,7 @@
#include "../devices/IKeyboard.hpp"
#include "../devices/ITouch.hpp"
#include "../devices/Tablet.hpp"
#include "config/ConfigManager.hpp"
static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',')
@ -130,10 +132,9 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
continue;
result += std::format(
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
"workspace: {} ({})\n\treserved: {} "
"{} {} {}\n\tscale: {:.2f}\n\ttransform: "
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
"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: {}\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->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(),
(!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""),
@ -146,6 +147,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
return result;
}
static std::string getTagsData(PHLWINDOW w, eHyprCtlOutputFormat format) {
const auto tags = w->m_tags.getTags();
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
return std::accumulate(tags.begin(), tags.end(), std::string(),
[](const std::string& a, const std::string& b) { return a.empty() ? std::format("\"{}\"", b) : std::format("{}, \"{}\"", a, b); });
else
return std::accumulate(tags.begin(), tags.end(), std::string(), [](const std::string& a, const std::string& b) { return a.empty() ? b : a + ", " + b; });
}
static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) {
const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON;
if (w->m_sGroupData.pNextWindow.expired())
@ -204,6 +215,7 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"fullscreenMode": {},
"fakeFullscreen": {},
"grouped": [{}],
"tags": [{}],
"swallowing": "0x{:x}",
"focusHistoryID": {}
}},)#",
@ -213,18 +225,18 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(),
((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
(w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
} else {
return std::format("Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\txwayland: {}\n\tpinned: "
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass,
w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
(w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bFakeFullscreenState, getGroupedData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
}
}
@ -883,6 +895,8 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
#if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
#elif defined(__arm__) || defined(__aarch64__)
const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible");
#else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif
@ -895,6 +909,12 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
}
if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) {
result += "\n======Config-Start======\n";
result += g_pConfigManager->getConfigString();
result += "\n======Config-End========\n";
}
return result;
}
@ -1036,13 +1056,15 @@ std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
nextItem();
const std::string DELIMITER = "\n\n\n";
while (curitem != "" || request != "") {
reply += g_pHyprCtl->getReply(curitem);
reply += g_pHyprCtl->getReply(curitem) + DELIMITER;
nextItem();
}
return reply;
return reply.substr(0, std::max(static_cast<int>(reply.size() - DELIMITER.size()), 0));
}
std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
@ -1063,7 +1085,8 @@ std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request)
if (size <= 0)
return "size not positive";
g_pCursorManager->changeTheme(theme, size);
if (!g_pCursorManager->changeTheme(theme, size))
return "failed to set cursor";
return "ok";
}
@ -1351,73 +1374,64 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request)
return result;
}
void createOutputIter(wlr_backend* backend, void* data) {
const auto DATA = (std::pair<std::string, bool>*)data;
static bool addOutput(wlr_backend* backend, const std::string& type, const std::string& name) {
wlr_output* output = nullptr;
if (DATA->second)
if (type.empty() || type == "auto") {
if (wlr_backend_is_wl(backend))
output = wlr_wl_output_create(backend);
else if (wlr_backend_is_headless(backend))
output = wlr_headless_add_output(backend, 1920, 1080);
} else {
if (wlr_backend_is_wl(backend) && type == "wayland")
output = wlr_wl_output_create(backend);
else if (wlr_backend_is_headless(backend) && type == "headless")
output = wlr_headless_add_output(backend, 1920, 1080);
}
if (output && !name.empty())
g_pCompositor->getMonitorFromOutput(output)->szName = name;
return output != nullptr;
}
struct outputData {
std::string type;
std::string name;
bool added;
};
void createOutputIter(wlr_backend* backend, void* data) {
const auto DATA = static_cast<outputData*>(data);
if (DATA->added)
return;
if (DATA->first.empty() || DATA->first == "auto") {
if (wlr_backend_is_wl(backend)) {
wlr_wl_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_x11(backend)) {
wlr_x11_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_headless(backend)) {
wlr_headless_add_output(backend, 1920, 1080);
DATA->second = true;
}
} else {
if (wlr_backend_is_wl(backend) && DATA->first == "wayland") {
wlr_wl_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_x11(backend) && DATA->first == "x11") {
wlr_x11_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_headless(backend) && DATA->first == "headless") {
wlr_headless_add_output(backend, 1920, 1080);
DATA->second = true;
}
}
if (addOutput(backend, DATA->type, DATA->name))
DATA->added = true;
}
std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
std::string curitem = "";
CVarList vars(request, 0, ' ');
auto nextItem = [&]() {
auto idx = request.find_first_of(' ');
if (vars.size() < 2)
return "not enough args";
if (idx != std::string::npos) {
curitem = request.substr(0, idx);
request = request.substr(idx + 1);
} else {
curitem = request;
request = "";
}
curitem = removeBeginEndSpacesTabs(curitem);
};
nextItem();
nextItem();
const auto MODE = curitem;
nextItem();
const auto NAME = curitem;
const auto MODE = vars[1];
if (MODE == "create" || MODE == "add") {
std::pair<std::string, bool> result = {NAME, false};
if (g_pCompositor->getMonitorFromName(vars[3]))
return "A real monitor already uses that name.";
outputData result{vars[2], vars[3], false};
wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result);
if (!result.second)
if (!result.added)
return "no backend replied to the request";
} else if (MODE == "destroy" || MODE == "remove") {
const auto PMONITOR = g_pCompositor->getMonitorFromName(NAME);
const auto PMONITOR = g_pCompositor->getMonitorFromName(vars[2]);
if (!PMONITOR)
return "output not found";
@ -1602,6 +1616,11 @@ CHyprCtl::CHyprCtl() {
startHyprCtlSocket();
}
CHyprCtl::~CHyprCtl() {
if (m_eventSource)
wl_event_source_remove(m_eventSource);
}
SP<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) {
return m_vCommands.emplace_back(makeShared<SHyprCtlCommand>(cmd));
}
@ -1638,6 +1657,8 @@ std::string CHyprCtl::getReply(std::string request) {
reloadAll = true;
else if (c == 'a')
m_sCurrentRequestParams.all = true;
else if (c == 'c')
m_sCurrentRequestParams.sysInfoConfig = true;
}
if (sepIndex < request.size())
@ -1780,5 +1801,5 @@ void CHyprCtl::startHyprCtlSocket() {
Debug::log(LOG, "Hypr socket started at {}", socketPath);
wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
}

View File

@ -8,6 +8,7 @@
class CHyprCtl {
public:
CHyprCtl();
~CHyprCtl();
std::string makeDynamicCall(const std::string& input);
SP<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd);
@ -17,13 +18,15 @@ class CHyprCtl {
int m_iSocketFD = -1;
struct {
bool all = false;
bool all = false;
bool sysInfoConfig = false;
} m_sCurrentRequestParams;
private:
void startHyprCtlSocket();
std::vector<SP<SHyprCtlCommand>> m_vCommands;
wl_event_source* m_eventSource = nullptr;
};
inline std::unique_ptr<CHyprCtl> g_pHyprCtl;
inline std::unique_ptr<CHyprCtl> g_pHyprCtl;

View File

@ -3,6 +3,10 @@
#include "config/ConfigValue.hpp"
#include "../Compositor.hpp"
CHyprDebugOverlay::CHyprDebugOverlay() {
m_pTexture = makeShared<CTexture>();
}
void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
m_dLastRenderTimes.push_back(µs / 1000.f);
@ -222,8 +226,8 @@ void CHyprDebugOverlay::draw() {
// copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(m_pCairoSurface);
m_tTexture.allocate();
glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID);
m_pTexture->allocate();
glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -235,5 +239,5 @@ void CHyprDebugOverlay::draw() {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f);
}

View File

@ -31,6 +31,7 @@ class CHyprMonitorDebugOverlay {
class CHyprDebugOverlay {
public:
CHyprDebugOverlay();
void draw();
void renderData(CMonitor*, float µs);
void renderDataNoOverlay(CMonitor*, float µs);
@ -42,7 +43,7 @@ class CHyprDebugOverlay {
cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr;
CTexture m_tTexture;
SP<CTexture> m_pTexture;
friend class CHyprMonitorDebugOverlay;
friend class CHyprRenderer;

View File

@ -23,6 +23,8 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() {
g_pHyprRenderer->damageBox(&m_bLastDamage);
});
m_pTexture = makeShared<CTexture>();
}
CHyprNotificationOverlay::~CHyprNotificationOverlay() {
@ -227,8 +229,8 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
// copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(m_pCairoSurface);
m_tTexture.allocate();
glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID);
m_pTexture->allocate();
glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -240,7 +242,7 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CBox pMonBox = {0, 0, MONSIZE.x, MONSIZE.y};
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f);
}
bool CHyprNotificationOverlay::hasAny() {

View File

@ -58,7 +58,7 @@ class CHyprNotificationOverlay {
CMonitor* m_pLastMonitor = nullptr;
Vector2D m_vecLastSize = Vector2D(-1, -1);
CTexture m_tTexture;
SP<CTexture> m_pTexture;
};
inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay;

View File

@ -49,11 +49,13 @@ namespace Debug {
// print date and time to the ofs
if (disableTime && !**disableTime) {
#ifndef _LIBCPP_VERSION
logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())});
const auto zt = std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::system_clock::now()};
const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor<std::chrono::days>(zt.get_local_time())};
#else
auto c = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())};
logMsg += std::format("{:%H}:{:%M}:{:%S}", c.hours(), c.minutes(), c.subseconds());
// TODO: current clang 17 does not support `zoned_time`, remove this once clang 19 is ready
const auto hms = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())};
#endif
logMsg += std::format("[{}] ", hms);
}
// no need for try {} catch {} because std::format_string<Args...> ensures that vformat never throw std::format_error

View File

@ -2,6 +2,7 @@
#include "../Compositor.hpp"
#include "../events/Events.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp"
PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
@ -9,6 +10,8 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor);
pLS->surface->assign(resource->surface.lock(), pLS);
if (!pMonitor) {
Debug::log(ERR, "New LS has no monitor??");
return pLS;
@ -39,8 +42,6 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
pLS->alpha.setValueAndWarp(0.f);
pLS->surface.assign(resource->surface, pLS);
Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName);
return pLS;
@ -58,13 +59,16 @@ CLayerSurface::CLayerSurface(SP<CLayerShellResource> resource_) : layerSurface(r
listeners.map = layerSurface->events.map.registerListener([this](std::any d) { onMap(); });
listeners.unmap = layerSurface->events.unmap.registerListener([this](std::any d) { onUnmap(); });
listeners.destroy = layerSurface->events.destroy.registerListener([this](std::any d) { onDestroy(); });
surface = CWLSurface::create();
}
CLayerSurface::~CLayerSurface() {
if (!g_pHyprOpenGL)
return;
surface.unassign();
if (surface)
surface->unassign();
g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); });
}
@ -105,7 +109,8 @@ void CLayerSurface::onDestroy() {
readyToDelete = true;
layerSurface.reset();
surface.unassign();
if (surface)
surface->unassign();
}
void CLayerSurface::onMap() {
@ -126,7 +131,7 @@ void CLayerSurface::onMap() {
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
wlr_surface_send_enter(surface.wlr(), PMONITOR->output);
surface->resource()->enter(PMONITOR->self.lock());
if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(self);
@ -139,10 +144,10 @@ void CLayerSurface::onMap() {
// TODO: use the new superb really very cool grab
g_pSeatManager->setGrab(nullptr);
g_pInputManager->releaseAllMouseButtons();
g_pCompositor->focusSurface(surface.wlr());
g_pCompositor->focusSurface(surface->resource());
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y);
g_pSeatManager->setPointerFocus(surface.wlr(), LOCAL);
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL);
g_pInputManager->m_bEmptyFocusCursorSet = false;
}
@ -160,8 +165,8 @@ void CLayerSurface::onMap() {
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", szNamespace});
EMIT_HOOK_EVENT("openLayer", self.lock());
g_pCompositor->setPreferredScaleForSurface(surface.wlr(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(surface.wlr(), PMONITOR->transform);
g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform);
}
void CLayerSurface::onUnmap() {
@ -173,7 +178,7 @@ void CLayerSurface::onUnmap() {
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
if (!g_pInputManager->m_dExclusiveLSes.empty())
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface);
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->surface->resource());
if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
@ -197,9 +202,9 @@ void CLayerSurface::onUnmap() {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == layerSurface->surface;
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
surface = nullptr;
surface.reset();
if (!PMONITOR)
return;
@ -208,11 +213,11 @@ void CLayerSurface::onUnmap() {
if (WASLASTFOCUS) {
g_pInputManager->releaseAllMouseButtons();
Vector2D surfaceCoords;
PHLLS pFoundLayerSurface;
wlr_surface* foundSurface = nullptr;
Vector2D surfaceCoords;
PHLLS pFoundLayerSurface;
SP<CWLSurfaceResource> foundSurface = nullptr;
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastFocus.reset();
// find LS-es to focus
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
@ -236,8 +241,8 @@ void CLayerSurface::onUnmap() {
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.width,
(int)layerSurface->surface->current.height};
geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.size.x,
(int)layerSurface->surface->current.size.y};
g_pHyprRenderer->damageBox(&geomFixed);
g_pInputManager->sendMotionEventsToFocused();
@ -284,12 +289,12 @@ void CLayerSurface::onCommit() {
position = Vector2D(geometry.x, geometry.y);
// update geom if it changed
if (layerSurface->surface->current.scale == 1 && PMONITOR->scale != 1.f && layerSurface->surface->current.viewport.has_dst) {
if (layerSurface->surface->current.scale == 1 && PMONITOR->scale != 1.f && layerSurface->surface->current.viewport.hasDestination) {
// fractional scaling. Dirty hack.
geometry = {geometry.x, geometry.y, (int)(layerSurface->surface->current.viewport.dst_width), (int)(layerSurface->surface->current.viewport.dst_height)};
geometry = {geometry.pos(), layerSurface->surface->current.viewport.destination};
} else {
// this is because some apps like e.g. rofi-lbonn can't fucking use the protocol correctly.
geometry = {geometry.x, geometry.y, (int)layerSurface->surface->current.width, (int)layerSurface->surface->current.height};
geometry = {geometry.pos(), layerSurface->surface->current.size};
}
}
@ -308,10 +313,10 @@ void CLayerSurface::onCommit() {
if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained
&& !keyboardExclusive && mapped) {
g_pCompositor->focusSurface(layerSurface->surface);
g_pCompositor->focusSurface(surface->resource());
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y);
g_pSeatManager->setPointerFocus(layerSurface->surface, LOCAL);
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL);
g_pInputManager->m_bEmptyFocusCursorSet = false;
} else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) {
g_pInputManager->refocus();
@ -319,10 +324,10 @@ void CLayerSurface::onCommit() {
keyboardExclusive = layerSurface->current.interactivity;
g_pHyprRenderer->damageSurface(layerSurface->surface, position.x, position.y);
g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y);
g_pCompositor->setPreferredScaleForSurface(layerSurface->surface, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(layerSurface->surface, PMONITOR->transform);
g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform);
}
void CLayerSurface::applyRules() {

View File

@ -36,7 +36,7 @@ class CLayerSurface {
bool keyboardExclusive = false;
CWLSurface surface;
SP<CWLSurface> surface;
bool mapped = false;
uint32_t layer = 0;

View File

@ -3,6 +3,7 @@
#include "../Compositor.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include <ranges>
CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) {
@ -14,7 +15,8 @@ CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) {
}
CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner), m_pResource(popup) {
m_sWLSurface.assign(popup->surface->surface, this);
m_pWLSurface = CWLSurface::create();
m_pWLSurface->assign(popup->surface->surface.lock(), this);
m_pLayerOwner = pOwner->m_pLayerOwner;
m_pWindowOwner = pOwner->m_pWindowOwner;
@ -26,7 +28,8 @@ CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner),
}
CPopup::~CPopup() {
m_sWLSurface.unassign();
if (m_pWLSurface)
m_pWLSurface->unassign();
}
void CPopup::initAllSignals() {
@ -45,7 +48,7 @@ void CPopup::initAllSignals() {
listeners.reposition = m_pResource->events.reposition.registerListener([this](std::any d) { this->onReposition(); });
listeners.map = m_pResource->surface->events.map.registerListener([this](std::any d) { this->onMap(); });
listeners.unmap = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); });
listeners.dismissed = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); });
listeners.dismissed = m_pResource->events.dismissed.registerListener([this](std::any d) { this->onUnmap(); });
listeners.destroy = m_pResource->surface->events.destroy.registerListener([this](std::any d) { this->onDestroy(); });
listeners.commit = m_pResource->surface->events.commit.registerListener([this](std::any d) { this->onCommit(); });
listeners.newPopup = m_pResource->surface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
@ -66,13 +69,17 @@ void CPopup::onDestroy() {
}
void CPopup::onMap() {
m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height};
if (m_bMapped)
return;
m_bMapped = true;
m_vLastSize = m_pResource->surface->surface->current.size;
const auto COORDS = coordsGlobal();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
CBox box;
wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr());
box.applyFromWlr().translate(COORDS).expand(4);
CBox box = m_pWLSurface->resource()->extends();
box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(&box);
m_vLastPos = coordsRelativeToParent();
@ -83,21 +90,28 @@ void CPopup::onMap() {
//unconstrain();
sendScale();
wlr_surface_send_enter(m_pResource->surface->surface, PMONITOR->output);
m_pResource->surface->surface->enter(PMONITOR->self.lock());
if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
}
void CPopup::onUnmap() {
if (!m_pResource || !m_pResource->surface)
if (!m_bMapped)
return;
m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height};
if (!m_pResource || !m_pResource->surface) {
Debug::log(ERR, "CPopup: orphaned (no surface/resource) and unmaps??");
onDestroy();
return;
}
m_vLastSize = m_pResource->surface->surface->current.size;
const auto COORDS = coordsGlobal();
CBox box;
wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr());
box.applyFromWlr().translate(COORDS).expand(4);
CBox box = m_pWLSurface->resource()->extends();
box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(&box);
m_pSubsurfaceHead.reset();
@ -109,7 +123,7 @@ void CPopup::onUnmap() {
// damage all children
breadthfirst(
[this](CPopup* p, void* data) {
[](CPopup* p, void* data) {
if (!p->m_pResource)
return;
@ -120,13 +134,19 @@ void CPopup::onUnmap() {
}
void CPopup::onCommit(bool ignoreSiblings) {
if (!m_pResource || !m_pResource->surface) {
Debug::log(ERR, "CPopup: orphaned (no surface/resource) and commits??");
onDestroy();
return;
}
if (m_pResource->surface->initialCommit) {
m_pResource->surface->scheduleConfigure();
return;
}
if (!m_pWindowOwner.expired() && (!m_pWindowOwner->m_bIsMapped || !m_pWindowOwner->m_pWorkspace->m_bVisible)) {
m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height};
m_vLastSize = m_pResource->surface->surface->current.size;
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
if (*PLOGDAMAGE)
@ -140,11 +160,10 @@ void CPopup::onCommit(bool ignoreSiblings) {
const auto COORDS = coordsGlobal();
const auto COORDSLOCAL = coordsRelativeToParent();
if (m_vLastSize != Vector2D{m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height} || m_bRequestedReposition ||
m_vLastPos != COORDSLOCAL) {
if (m_vLastSize != m_pResource->surface->surface->current.size || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) {
CBox box = {localToGlobal(m_vLastPos), m_vLastSize};
g_pHyprRenderer->damageBox(&box);
m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height};
m_vLastSize = m_pResource->surface->surface->current.size;
box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
@ -154,7 +173,7 @@ void CPopup::onCommit(bool ignoreSiblings) {
if (!ignoreSiblings && m_pSubsurfaceHead)
m_pSubsurfaceHead->recheckDamageForSubsurfaces();
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y);
m_bRequestedReposition = false;
@ -194,7 +213,7 @@ Vector2D CPopup::coordsRelativeToParent() {
while (current->m_pParent && current->m_pResource) {
offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy};
offset += current->m_pWLSurface->resource()->current.offset;
offset += current->m_pResource->geometry.pos();
current = current->m_pParent;
@ -243,9 +262,9 @@ Vector2D CPopup::size() {
void CPopup::sendScale() {
if (!m_pWindowOwner.expired())
g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pWindowOwner->m_pWLSurface.m_fLastScale);
g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pWindowOwner->m_pWLSurface->m_fLastScale);
else if (!m_pLayerOwner.expired())
g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pLayerOwner->surface.m_fLastScale);
g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pLayerOwner->surface->m_fLastScale);
else
UNREACHABLE();
}
@ -301,9 +320,8 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
return p;
} else {
const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{};
const auto REGION = CRegion{&p->m_sWLSurface.wlr()->current.input}
.intersect(CBox{{}, {p->m_sWLSurface.wlr()->current.width, p->m_sWLSurface.wlr()->current.height}})
.translate(p->coordsGlobal() + offset);
const auto REGION =
CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset);
if (REGION.containsPoint(globalCoords))
return p;
}

View File

@ -39,7 +39,7 @@ class CPopup {
CPopup* at(const Vector2D& globalCoords, bool allowsInput = false);
//
CWLSurface m_sWLSurface;
SP<CWLSurface> m_pWLSurface;
private:
// T1 owners, each popup has to have one of these
@ -56,7 +56,8 @@ class CPopup {
bool m_bRequestedReposition = false;
bool m_bInert = false;
bool m_bInert = false;
bool m_bMapped = false;
//
std::vector<std::unique_ptr<CPopup>> m_vChildren;

View File

@ -2,29 +2,31 @@
#include "../events/Events.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
static void onNewSubsurface(void* owner, void* data);
#include "../protocols/core/Compositor.hpp"
#include "../protocols/core/Subcompositor.hpp"
CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) {
initSignals();
initExistingSubsurfaces(pOwner->m_pWLSurface.wlr());
initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
}
CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) {
initSignals();
initExistingSubsurfaces(pOwner->m_sWLSurface.wlr());
initExistingSubsurfaces(pOwner->m_pWLSurface->resource());
}
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) {
m_sWLSurface.assign(pSubsurface->surface, this);
CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) {
m_pWLSurface = CWLSurface::create();
m_pWLSurface->assign(pSubsurface->surface.lock(), this);
initSignals();
initExistingSubsurfaces(pSubsurface->surface);
initExistingSubsurfaces(pSubsurface->surface.lock());
}
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
m_sWLSurface.assign(pSubsurface->surface, this);
CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
m_pWLSurface = CWLSurface::create();
m_pWLSurface->assign(pSubsurface->surface.lock(), this);
initSignals();
initExistingSubsurfaces(pSubsurface->surface);
initExistingSubsurfaces(pSubsurface->surface.lock());
}
CSubsurface::~CSubsurface() {
@ -33,52 +35,27 @@ CSubsurface::~CSubsurface() {
if (!m_pSubsurface)
return;
m_pSubsurface->data = nullptr;
hyprListener_commitSubsurface.removeCallback();
hyprListener_destroySubsurface.removeCallback();
}
static void onNewSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onNewSubsurface((wlr_subsurface*)data);
}
static void onDestroySubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onDestroy();
}
static void onCommitSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onCommit();
}
static void onMapSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onMap();
}
static void onUnmapSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onUnmap();
}
void CSubsurface::initSignals() {
if (m_pSubsurface) {
m_pSubsurface->data = this;
hyprListener_commitSubsurface.initCallback(&m_pSubsurface->surface->events.commit, &onCommitSubsurface, this, "CSubsurface");
hyprListener_destroySubsurface.initCallback(&m_pSubsurface->events.destroy, &onDestroySubsurface, this, "CSubsurface");
hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface");
hyprListener_mapSubsurface.initCallback(&m_pSubsurface->surface->events.map, &onMapSubsurface, this, "CSubsurface");
hyprListener_unmapSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface");
listeners.commitSubsurface = m_pSubsurface->surface->events.commit.registerListener([this](std::any d) { onCommit(); });
listeners.destroySubsurface = m_pSubsurface->events.destroy.registerListener([this](std::any d) { onDestroy(); });
listeners.mapSubsurface = m_pSubsurface->surface->events.map.registerListener([this](std::any d) { onMap(); });
listeners.unmapSubsurface = m_pSubsurface->surface->events.unmap.registerListener([this](std::any d) { onUnmap(); });
listeners.newSubsurface =
m_pSubsurface->surface->events.newSubsurface.registerListener([this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); });
} else {
if (!m_pWindowParent.expired())
hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
if (m_pWindowParent)
listeners.newSubsurface = m_pWindowParent->m_pWLSurface->resource()->events.newSubsurface.registerListener(
[this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); });
else if (m_pPopupParent)
hyprListener_newSubsurface.initCallback(&m_pPopupParent->m_sWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
listeners.newSubsurface = m_pPopupParent->m_pWLSurface->resource()->events.newSubsurface.registerListener(
[this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); });
else
RASSERT(false, "CSubsurface::initSignals empty subsurface");
ASSERT(false);
}
}
@ -93,21 +70,21 @@ void CSubsurface::checkSiblingDamage() {
continue;
const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE);
g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y, SCALE);
}
}
void CSubsurface::recheckDamageForSubsurfaces() {
for (auto& n : m_vChildren) {
const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y);
g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y);
}
}
void CSubsurface::onCommit() {
// no damaging if it's not visible
if (!m_pWindowParent.expired() && (!m_pWindowParent->m_bIsMapped || !m_pWindowParent->m_pWorkspace->m_bVisible)) {
m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
m_vLastSize = m_pWLSurface->resource()->current.size;
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
if (*PLOGDAMAGE)
@ -117,7 +94,7 @@ void CSubsurface::onCommit() {
const auto COORDS = coordsGlobal();
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y);
if (m_pPopupParent)
m_pPopupParent->recheckTree();
@ -127,10 +104,10 @@ void CSubsurface::onCommit() {
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
checkSiblingDamage();
if (m_vLastSize != Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}) {
if (m_vLastSize != m_pWLSurface->resource()->current.size) {
CBox box{COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
m_vLastSize = m_pWLSurface->resource()->current.size;
box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
}
@ -149,20 +126,21 @@ void CSubsurface::onDestroy() {
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
}
void CSubsurface::onNewSubsurface(wlr_subsurface* pSubsurface) {
void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) {
CSubsurface* PSUBSURFACE = nullptr;
if (!m_pWindowParent.expired())
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pWindowParent.lock())).get();
else if (m_pPopupParent)
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pPopupParent)).get();
PSUBSURFACE->m_pParent = this;
ASSERT(PSUBSURFACE);
PSUBSURFACE->m_pParent = this;
}
void CSubsurface::onMap() {
m_vLastSize = {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
m_vLastSize = m_pWLSurface->resource()->current.size;
const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize};
@ -179,7 +157,7 @@ void CSubsurface::onUnmap() {
box.expand(4);
g_pHyprRenderer->damageBox(&box);
if (m_sWLSurface.wlr() == g_pCompositor->m_pLastFocus)
if (m_pWLSurface->resource() == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons();
g_pInputManager->simulateMouseMovement();
@ -188,19 +166,9 @@ void CSubsurface::onUnmap() {
}
Vector2D CSubsurface::coordsRelativeToParent() {
Vector2D offset;
CSubsurface* current = this;
while (current->m_pParent) {
offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy};
offset += {current->m_pSubsurface->current.x, current->m_pSubsurface->current.y};
current = current->m_pParent;
}
return offset;
if (!m_pSubsurface)
return {};
return m_pSubsurface->posRelativeToParent();
}
Vector2D CSubsurface::coordsGlobal() {
@ -214,18 +182,16 @@ Vector2D CSubsurface::coordsGlobal() {
return coords;
}
void CSubsurface::initExistingSubsurfaces(wlr_surface* pSurface) {
wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_below, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_above, current.link) {
::onNewSubsurface(this, wlrSubsurface);
void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) {
for (auto& s : pSurface->subsurfaces) {
if (!s || s->surface->hlSurface /* already assigned */)
continue;
onNewSubsurface(s.lock());
}
}
Vector2D CSubsurface::size() {
return {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
return m_pWLSurface->resource()->current.size;
}
bool CSubsurface::visible() {

View File

@ -5,6 +5,7 @@
#include "WLSurface.hpp"
class CPopup;
class CWLSubsurfaceResource;
class CSubsurface {
public:
@ -13,8 +14,8 @@ class CSubsurface {
CSubsurface(CPopup* pOwner);
// real nodes
CSubsurface(wlr_subsurface* pSubsurface, PHLWINDOW pOwner);
CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner);
CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner);
CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner);
~CSubsurface();
@ -25,7 +26,7 @@ class CSubsurface {
void onCommit();
void onDestroy();
void onNewSubsurface(wlr_subsurface* pSubsurface);
void onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface);
void onMap();
void onUnmap();
@ -37,12 +38,18 @@ class CSubsurface {
DYNLISTENER(destroySubsurface);
DYNLISTENER(commitSubsurface);
DYNLISTENER(newSubsurface);
DYNLISTENER(mapSubsurface);
DYNLISTENER(unmapSubsurface);
wlr_subsurface* m_pSubsurface = nullptr;
CWLSurface m_sWLSurface;
Vector2D m_vLastSize = {};
struct {
CHyprSignalListener destroySubsurface;
CHyprSignalListener commitSubsurface;
CHyprSignalListener mapSubsurface;
CHyprSignalListener unmapSubsurface;
CHyprSignalListener newSubsurface;
} listeners;
WP<CWLSubsurfaceResource> m_pSubsurface;
SP<CWLSurface> m_pWLSurface;
Vector2D m_vLastSize = {};
// if nullptr, means it's a dummy node
CSubsurface* m_pParent = nullptr;
@ -55,6 +62,6 @@ class CSubsurface {
bool m_bInert = false;
void initSignals();
void initExistingSubsurfaces(wlr_surface* pSurface);
void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface);
void checkSiblingDamage();
};

View File

@ -1,36 +1,37 @@
#include "WLSurface.hpp"
#include "../Compositor.hpp"
#include "../protocols/core/Compositor.hpp"
void CWLSurface::assign(wlr_surface* pSurface) {
m_pWLRSurface = pSurface;
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_pResource = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, PHLWINDOW pOwner) {
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner) {
m_pWindowOwner = pOwner;
m_pWLRSurface = pSurface;
m_pResource = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, PHLLS pOwner) {
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner) {
m_pLayerOwner = pOwner;
m_pWLRSurface = pSurface;
m_pResource = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, CSubsurface* pOwner) {
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner) {
m_pSubsurfaceOwner = pOwner;
m_pWLRSurface = pSurface;
m_pResource = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, CPopup* pOwner) {
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner) {
m_pPopupOwner = pOwner;
m_pWLRSurface = pSurface;
m_pResource = pSurface;
init();
m_bInert = false;
}
@ -44,20 +45,23 @@ CWLSurface::~CWLSurface() {
}
bool CWLSurface::exists() const {
return m_pWLRSurface;
return m_pResource;
}
wlr_surface* CWLSurface::wlr() const {
return m_pWLRSurface;
SP<CWLSurfaceResource> CWLSurface::resource() const {
return m_pResource.lock();
}
bool CWLSurface::small() const {
if (!validMapped(m_pWindowOwner) || !exists())
return false;
if (!m_pResource->current.buffer)
return false;
const auto O = m_pWindowOwner.lock();
return O->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || O->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1;
return O->m_vReportedSize.x > m_pResource->current.buffer->size.x + 1 || O->m_vReportedSize.y > m_pResource->current.buffer->size.y + 1;
}
Vector2D CWLSurface::correctSmallVec() const {
@ -71,29 +75,28 @@ Vector2D CWLSurface::correctSmallVec() const {
}
Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists())
if (!exists() || !m_pResource->current.buffer)
return {};
return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} :
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size;
}
CRegion CWLSurface::logicalDamage() const {
CRegion damage{&m_pWLRSurface->buffer_damage};
damage.transform(m_pWLRSurface->current.transform, m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height);
damage.scale(1.0 / m_pWLRSurface->current.scale);
if (!m_pResource->current.buffer)
return {};
CRegion damage = m_pResource->accumulateCurrentBufferDamage();
damage.transform(m_pResource->current.transform, m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y);
damage.scale(1.0 / m_pResource->current.scale);
const auto VPSIZE = getViewporterCorrectedSize();
const auto CORRECTVEC = correctSmallVec();
if (m_pWLRSurface->current.viewport.has_src) {
damage.intersect(CBox{std::floor(m_pWLRSurface->current.viewport.src.x), std::floor(m_pWLRSurface->current.viewport.src.y),
std::ceil(m_pWLRSurface->current.viewport.src.width), std::ceil(m_pWLRSurface->current.viewport.src.height)});
}
if (m_pResource->current.viewport.hasSource)
damage.intersect(m_pResource->current.viewport.source);
const auto SCALEDSRCSIZE = m_pWLRSurface->current.viewport.has_src ?
Vector2D{m_pWLRSurface->current.viewport.src.width, m_pWLRSurface->current.viewport.src.height} * m_pWLRSurface->current.scale :
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
const auto SCALEDSRCSIZE =
m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size;
damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y});
damage.translate(CORRECTVEC);
@ -102,48 +105,38 @@ CRegion CWLSurface::logicalDamage() const {
}
void CWLSurface::destroy() {
if (!m_pWLRSurface)
if (!m_pResource)
return;
events.destroy.emit();
m_pConstraint.reset();
hyprListener_destroy.removeCallback();
hyprListener_commit.removeCallback();
m_pWLRSurface->data = nullptr;
listeners.destroy.reset();
m_pResource->hlSurface.reset();
m_pWindowOwner.reset();
m_pLayerOwner.reset();
m_pPopupOwner = nullptr;
m_pSubsurfaceOwner = nullptr;
m_bInert = true;
if (g_pCompositor && g_pCompositor->m_pLastFocus == m_pWLRSurface)
g_pCompositor->m_pLastFocus = nullptr;
if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == this)
if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf && g_pHyprRenderer->m_sLastCursorData.surf->get() == this)
g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_pWLRSurface = nullptr;
m_pResource.reset();
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
}
static void onCommit(void* owner, void* data) {
const auto SURF = (CWLSurface*)owner;
SURF->onCommit();
}
void CWLSurface::init() {
if (!m_pWLRSurface)
if (!m_pResource)
return;
RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!");
RASSERT(!m_pResource->hlSurface, "Attempted to duplicate CWLSurface ownership!");
m_pWLRSurface->data = this;
m_pResource->hlSurface = self.lock();
hyprListener_destroy.initCallback(
&m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
hyprListener_commit.initCallback(&m_pWLRSurface->events.commit, ::onCommit, this, "CWLSurface");
listeners.destroy = m_pResource->events.destroy.registerListener([this](std::any d) { destroy(); });
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
}
@ -188,10 +181,6 @@ void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) {
m_pConstraint = constraint;
}
void CWLSurface::onCommit() {
;
}
SP<CPointerConstraint> CWLSurface::constraint() {
return m_pConstraint.lock();
}
@ -207,3 +196,9 @@ bool CWLSurface::visible() {
return m_pSubsurfaceOwner->visible();
return true; // non-desktop, we don't know much.
}
SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
if (!pSurface)
return nullptr;
return pSurface->hlSurface.lock();
}

View File

@ -7,33 +7,37 @@
class CSubsurface;
class CPopup;
class CPointerConstraint;
class CWLSurfaceResource;
class CWLSurface {
public:
CWLSurface() = default;
static SP<CWLSurface> create() {
auto p = SP<CWLSurface>(new CWLSurface);
p->self = p;
return p;
}
~CWLSurface();
// anonymous surfaces are non-desktop components, e.g. a cursor surface or a DnD
void assign(wlr_surface* pSurface);
void assign(wlr_surface* pSurface, PHLWINDOW pOwner);
void assign(wlr_surface* pSurface, PHLLS pOwner);
void assign(wlr_surface* pSurface, CSubsurface* pOwner);
void assign(wlr_surface* pSurface, CPopup* pOwner);
void assign(SP<CWLSurfaceResource> pSurface);
void assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner);
void assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner);
void assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner);
void assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner);
void unassign();
CWLSurface(const CWLSurface&) = delete;
CWLSurface(CWLSurface&&) = delete;
CWLSurface& operator=(const CWLSurface&) = delete;
CWLSurface& operator=(CWLSurface&&) = delete;
CWLSurface(const CWLSurface&) = delete;
CWLSurface(CWLSurface&&) = delete;
CWLSurface& operator=(const CWLSurface&) = delete;
CWLSurface& operator=(CWLSurface&&) = delete;
wlr_surface* wlr() const;
bool exists() const;
bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D getViewporterCorrectedSize() const;
CRegion logicalDamage() const;
void onCommit();
bool visible();
SP<CWLSurfaceResource> resource() const;
bool exists() const;
bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D getViewporterCorrectedSize() const;
CRegion logicalDamage() const;
bool visible();
// getters for owners.
PHLWINDOW getWindow();
@ -55,31 +59,27 @@ class CWLSurface {
wl_output_transform m_eLastTransform = (wl_output_transform)-1;
//
CWLSurface& operator=(wlr_surface* pSurface) {
CWLSurface& operator=(SP<CWLSurfaceResource> pSurface) {
destroy();
m_pWLRSurface = pSurface;
m_pResource = pSurface;
init();
return *this;
}
bool operator==(const CWLSurface& other) const {
return other.wlr() == wlr();
return other.resource() == resource();
}
bool operator==(const wlr_surface* other) const {
return other == wlr();
bool operator==(const SP<CWLSurfaceResource> other) const {
return other == resource();
}
explicit operator bool() const {
return exists();
}
static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) {
if (!pSurface)
return nullptr;
return (CWLSurface*)pSurface->data;
}
static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface);
// used by the alpha-modifier protocol
float m_pAlphaModifier = 1.F;
@ -88,15 +88,19 @@ class CWLSurface {
CSignal destroy;
} events;
WP<CWLSurface> self;
private:
bool m_bInert = true;
CWLSurface() = default;
wlr_surface* m_pWLRSurface = nullptr;
bool m_bInert = true;
PHLWINDOWREF m_pWindowOwner;
PHLLSREF m_pLayerOwner;
CPopup* m_pPopupOwner = nullptr;
CSubsurface* m_pSubsurfaceOwner = nullptr;
WP<CWLSurfaceResource> m_pResource;
PHLWINDOWREF m_pWindowOwner;
PHLLSREF m_pLayerOwner;
CPopup* m_pPopupOwner = nullptr;
CSubsurface* m_pSubsurfaceOwner = nullptr;
//
WP<CPointerConstraint> m_pConstraint;
@ -105,8 +109,9 @@ class CWLSurface {
void init();
bool desktopComponent();
DYNLISTENER(destroy);
DYNLISTENER(commit);
struct {
CHyprSignalListener destroy;
} listeners;
friend class CPointerConstraint;
};

View File

@ -1,17 +1,23 @@
#include <any>
#include <string_view>
#include <algorithm>
#include "Window.hpp"
#include "../Compositor.hpp"
#include "../render/decorations/CHyprDropShadowDecoration.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../render/decorations/CHyprBorderDecoration.hpp"
#include "../config/ConfigValue.hpp"
#include <any>
#include "../managers/TokenManager.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../xwayland/XWayland.hpp"
PHLWINDOW CWindow::create() {
PHLWINDOW pWindow = SP<CWindow>(new CWindow);
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
pWindow->m_pSelf = pWindow;
pWindow->m_pSelf = pWindow;
pWindow->m_bIsX11 = true;
pWindow->m_iX11Type = surface->overrideRedirect ? 2 : 1;
pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
@ -46,12 +52,14 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
pWindow->m_pWLSurface.assign(pWindow->m_pXDGSurface->surface, pWindow);
pWindow->m_pWLSurface->assign(pWindow->m_pXDGSurface->surface.lock(), pWindow);
return pWindow;
}
CWindow::CWindow(SP<CXDGSurfaceResource> resource) : m_pXDGSurface(resource) {
m_pWLSurface = CWLSurface::create();
listeners.map = m_pXDGSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); });
listeners.ack = m_pXDGSurface->events.ack.registerListener([this](std::any d) { onAck(std::any_cast<uint32_t>(d)); });
listeners.unmap = m_pXDGSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); });
@ -61,13 +69,26 @@ CWindow::CWindow(SP<CXDGSurfaceResource> resource) : m_pXDGSurface(resource) {
listeners.updateMetadata = m_pXDGSurface->toplevel->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); });
}
CWindow::CWindow() {
;
CWindow::CWindow(SP<CXWaylandSurface> surface) : m_pXWaylandSurface(surface) {
m_pWLSurface = CWLSurface::create();
listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); });
listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); });
listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); });
listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); });
listeners.configure = m_pXWaylandSurface->events.configure.registerListener([this](std::any d) { onX11Configure(std::any_cast<CBox>(d)); });
listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); });
listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); });
listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); });
listeners.activate = m_pXWaylandSurface->events.activate.registerListener([this](std::any d) { Events::listener_activateX11(this, nullptr); });
if (m_pXWaylandSurface->overrideRedirect)
listeners.setGeometry = m_pXWaylandSurface->events.setGeometry.registerListener([this](std::any d) { Events::listener_unmanagedSetGeometry(this, nullptr); });
}
CWindow::~CWindow() {
if (g_pCompositor->m_pLastWindow.lock().get() == this) {
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastFocus.reset();
g_pCompositor->m_pLastWindow.reset();
}
@ -108,12 +129,12 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
if (m_pWLSurface.exists() && !m_bIsX11 && m_pPopupHead) {
if (m_pWLSurface->exists() && !m_bIsX11 && m_pPopupHead) {
CBox surfaceExtents = {0, 0, 0, 0};
// TODO: this could be better, perhaps make a getFullWindowRegion?
m_pPopupHead->breadthfirst(
[](CPopup* popup, void* data) {
if (!popup->m_sWLSurface.wlr())
if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource())
return;
CBox* pSurfaceExtents = (CBox*)data;
@ -135,11 +156,11 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
if (-surfaceExtents.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = -surfaceExtents.y;
if (surfaceExtents.x + surfaceExtents.width > m_pWLSurface.wlr()->current.width + maxExtents.bottomRight.x)
maxExtents.bottomRight.x = surfaceExtents.x + surfaceExtents.width - m_pWLSurface.wlr()->current.width;
if (surfaceExtents.x + surfaceExtents.width > m_pWLSurface->resource()->current.size.x + maxExtents.bottomRight.x)
maxExtents.bottomRight.x = surfaceExtents.x + surfaceExtents.width - m_pWLSurface->resource()->current.size.x;
if (surfaceExtents.y + surfaceExtents.height > m_pWLSurface.wlr()->current.height + maxExtents.bottomRight.y)
maxExtents.bottomRight.y = surfaceExtents.y + surfaceExtents.height - m_pWLSurface.wlr()->current.height;
if (surfaceExtents.y + surfaceExtents.height > m_pWLSurface->resource()->current.size.y + maxExtents.bottomRight.y)
maxExtents.bottomRight.y = surfaceExtents.y + surfaceExtents.height - m_pWLSurface->resource()->current.size.y;
}
return maxExtents;
@ -160,11 +181,13 @@ CBox CWindow::getFullWindowBoundingBox() {
}
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
auto POS = m_vPosition;
auto SIZE = m_vSize;
if (!PMONITOR)
return {m_vPosition, m_vSize};
auto POS = m_vPosition;
auto SIZE = m_vSize;
if (m_bIsFullscreen) {
POS = PMONITOR->vecPosition;
@ -192,10 +215,10 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
}
CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_sAdditionalConfigData.dimAround) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
if (PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
}
SWindowDecorationExtents EXTENTS = {{0, 0}, {0, 0}};
@ -300,10 +323,10 @@ pid_t CWindow::getPID() {
wl_client_get_credentials(m_pXDGSurface->owner->client(), &PID, nullptr, nullptr);
} else {
if (!m_uSurface.xwayland)
if (!m_pXWaylandSurface)
return -1;
PID = m_uSurface.xwayland->pid;
PID = m_pXWaylandSurface->pid;
}
return PID;
@ -322,17 +345,7 @@ void CWindow::updateToplevel() {
updateSurfaceScaleTransformDetails();
}
void sendEnterIter(wlr_surface* pSurface, int x, int y, void* data) {
const auto OUTPUT = (wlr_output*)data;
wlr_surface_send_enter(pSurface, OUTPUT);
}
void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
const auto OUTPUT = (wlr_output*)data;
wlr_surface_send_leave(pSurface, OUTPUT);
}
void CWindow::updateSurfaceScaleTransformDetails() {
void CWindow::updateSurfaceScaleTransformDetails(bool force) {
if (!m_bIsMapped || m_bHidden || g_pCompositor->m_bUnsafeState)
return;
@ -345,26 +358,25 @@ void CWindow::updateSurfaceScaleTransformDetails() {
if (!PNEWMONITOR)
return;
if (PNEWMONITOR != PLASTMONITOR) {
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
if (PNEWMONITOR != PLASTMONITOR || force) {
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled && PNEWMONITOR != PLASTMONITOR)
m_pWLSurface->resource()->breadthfirst([PLASTMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->leave(PLASTMONITOR->self.lock()); }, nullptr);
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr);
}
wlr_surface_for_each_surface(
m_pWLSurface.wlr(),
[](wlr_surface* surf, int x, int y, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
m_pWLSurface->resource()->breadthfirst(
[this](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto PSURFACE = CWLSurface::surfaceFromWlr(surf);
const auto PSURFACE = CWLSurface::fromResource(s);
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
return;
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
g_pCompositor->setPreferredScaleForSurface(s, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(s, PMONITOR->transform);
},
this);
nullptr);
}
void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
@ -426,22 +438,23 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
}
PHLWINDOW CWindow::X11TransientFor() {
if (!m_bIsX11)
if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent)
return nullptr;
if (!m_uSurface.xwayland->parent)
return nullptr;
auto PPARENT = g_pCompositor->getWindowFromSurface(m_uSurface.xwayland->parent->surface);
while (validMapped(PPARENT) && PPARENT->m_uSurface.xwayland->parent) {
PPARENT = g_pCompositor->getWindowFromSurface(PPARENT->m_uSurface.xwayland->parent->surface);
auto s = m_pXWaylandSurface->parent;
while (s) {
if (!s->parent)
break;
s = s->parent;
}
if (!validMapped(PPARENT))
return nullptr;
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_pXWaylandSurface != s)
continue;
return w;
}
return PPARENT;
return nullptr;
}
void CWindow::removeDecorationByType(eDecorationType type) {
@ -494,8 +507,6 @@ void CWindow::onUnmap() {
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; });
hyprListener_unmapWindow.removeCallback();
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace)
@ -548,12 +559,11 @@ void CWindow::onMap() {
g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf);
if (m_bIsX11)
hyprListener_unmapWindow.initCallback(&m_uSurface.xwayland->surface->events.unmap, &Events::listener_unmapWindow, this, "CWindow");
m_vReportedSize = m_vPendingReportedSize;
m_bAnimatingIn = true;
updateSurfaceScaleTransformDetails(true);
if (m_bIsX11)
return;
@ -609,6 +619,13 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
m_sAdditionalConfigData.forceTearing = true;
} else if (r.szRule == "nearestneighbor") {
m_sAdditionalConfigData.nearestNeighbor = true;
} else if (r.szRule.starts_with("tag")) {
CVarList vars{r.szRule, 0, 's', true};
if (vars.size() == 2 && vars[0] == "tag")
m_tags.applyTag(vars[1], true);
else
Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
} else if (r.szRule.starts_with("rounding")) {
try {
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
@ -790,6 +807,8 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.nearestNeighbor = false;
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
m_tags.removeDynamicTags();
m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock());
for (auto& r : m_vMatchedRules) {
applyDynamicRule(r);
@ -837,7 +856,7 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
CPopup* popup = m_pPopupHead->at(pos);
return popup && popup->m_sWLSurface.wlr();
return popup && popup->m_pWLSurface->resource();
}
void CWindow::applyGroupRules() {
@ -1112,23 +1131,24 @@ bool CWindow::opaque() {
const auto PWORKSPACE = m_pWorkspace;
if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall)
if (m_pWLSurface->small() && !m_pWLSurface->m_bFillIgnoreSmall)
return false;
if (PWORKSPACE->m_fAlpha.value() != 1.f)
return false;
if (m_bIsX11)
return !m_uSurface.xwayland->has_alpha;
if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.buffer)
return m_pXWaylandSurface->surface->current.buffer->opaque;
if (m_pXDGSurface->surface->opaque)
if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.buffer)
return false;
// TODO: this is wrong
const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents();
if (EXTENTS.w >= m_pXDGSurface->surface->current.buffer->size.x && EXTENTS.h >= m_pXDGSurface->surface->current.buffer->size.y)
return true;
const auto EXTENTS = pixman_region32_extents(&m_pXDGSurface->surface->opaque_region);
if (EXTENTS->x2 - EXTENTS->x1 >= m_pXDGSurface->surface->current.buffer_width && EXTENTS->y2 - EXTENTS->y1 >= m_pXDGSurface->surface->current.buffer_height)
return true;
return false;
return m_pWLSurface->resource()->current.buffer->opaque;
}
float CWindow::rounding() {
@ -1259,8 +1279,7 @@ int CWindow::surfacesCount() {
return 1;
int no = 0;
wlr_surface_for_each_surface(
m_pWLSurface.wlr(), [](wlr_surface* surf, int x, int y, void* data) { *((int*)data) += 1; }, &no);
m_pWLSurface->resource()->breadthfirst([](SP<CWLSurfaceResource> r, const Vector2D& offset, void* d) { *((int*)d) += 1; }, &no);
return no;
}
@ -1296,9 +1315,12 @@ std::unordered_map<std::string, std::string> CWindow::getEnv() {
needle += 512;
}
if (needle <= 1)
return {};
std::replace(buffer.begin(), buffer.end() - 1, '\0', '\n');
CVarList envs(std::string{buffer.data(), needle - 1}, 0, '\n', true);
CVarList envs(std::string{buffer.data(), buffer.size() - 1}, 0, '\n', true);
for (auto& e : envs) {
if (!e.contains('='))
@ -1330,33 +1352,34 @@ void CWindow::activate(bool force) {
g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true);
g_pCompositor->focusWindow(m_pSelf.lock());
g_pCompositor->warpCursorTo(middle());
warpCursor();
}
void CWindow::onUpdateState() {
if (!m_pXDGSurface)
return;
std::optional<bool> requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen;
std::optional<bool> requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize;
if (m_pXDGSurface->toplevel->state.requestsFullscreen && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
bool fs = m_pXDGSurface->toplevel->state.requestsFullscreen.value();
if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
bool fs = requestsFS.value();
if (fs != m_bIsFullscreen && m_pXDGSurface->mapped)
if (fs != m_bIsFullscreen && m_bIsMapped)
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_FULL);
if (!m_pXDGSurface->mapped)
if (!m_bIsMapped)
m_bWantsInitialFullscreen = fs;
}
if (m_pXDGSurface->toplevel->state.requestsMaximize && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) {
bool fs = m_pXDGSurface->toplevel->state.requestsMaximize.value();
if (requestsMX.has_value() && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) {
bool fs = requestsMX.value();
if (fs != m_bIsFullscreen && m_pXDGSurface->mapped)
if (fs != m_bIsFullscreen && m_bIsMapped)
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_MAXIMIZED);
}
}
void CWindow::onUpdateMeta() {
const auto NEWTITLE = fetchTitle();
bool doUpdate = false;
if (m_szTitle != NEWTITLE) {
m_szTitle = NEWTITLE;
@ -1369,11 +1392,8 @@ void CWindow::onUpdateMeta() {
EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock());
}
updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock());
updateToplevel();
Debug::log(LOG, "Window {:x} set title to {}", (uintptr_t)this, m_szTitle);
doUpdate = true;
}
const auto NEWCLASS = fetchClass();
@ -1386,11 +1406,14 @@ void CWindow::onUpdateMeta() {
EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock());
}
Debug::log(LOG, "Window {:x} set class to {}", (uintptr_t)this, m_szClass);
doUpdate = true;
}
if (doUpdate) {
updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock());
updateToplevel();
Debug::log(LOG, "Window {:x} set class to {}", (uintptr_t)this, m_szClass);
}
}
@ -1399,8 +1422,8 @@ std::string CWindow::fetchTitle() {
if (m_pXDGSurface && m_pXDGSurface->toplevel)
return m_pXDGSurface->toplevel->state.title;
} else {
if (m_uSurface.xwayland && m_uSurface.xwayland->title)
return m_uSurface.xwayland->title;
if (m_pXWaylandSurface)
return m_pXWaylandSurface->state.title;
}
return "";
@ -1411,8 +1434,8 @@ std::string CWindow::fetchClass() {
if (m_pXDGSurface && m_pXDGSurface->toplevel)
return m_pXDGSurface->toplevel->state.appid;
} else {
if (m_uSurface.xwayland && m_uSurface.xwayland->_class)
return m_uSurface.xwayland->_class;
if (m_pXWaylandSurface)
return m_pXWaylandSurface->state.appid;
}
return "";
@ -1426,4 +1449,91 @@ void CWindow::onAck(uint32_t serial) {
m_pPendingSizeAck = *SERIAL;
std::erase_if(m_vPendingSizeAcks, [&](const auto& el) { return el.first <= SERIAL->first; });
}
}
void CWindow::onResourceChangeX11() {
if (m_pXWaylandSurface->surface && !m_pWLSurface->resource())
m_pWLSurface->assign(m_pXWaylandSurface->surface.lock(), m_pSelf.lock());
else if (!m_pXWaylandSurface->surface && m_pWLSurface->resource())
m_pWLSurface->unassign();
// update metadata as well,
// could be first assoc and we need to catch the class
onUpdateMeta();
Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface->resource().get());
}
void CWindow::onX11Configure(CBox box) {
if (!m_pXWaylandSurface->surface || !m_pXWaylandSurface->mapped || !m_bIsMapped) {
m_pXWaylandSurface->configure(box);
m_vPendingReportedSize = box.size();
m_vReportedSize = box.size();
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
m_fX11SurfaceScaledBy = PMONITOR->scale;
return;
}
g_pHyprRenderer->damageWindow(m_pSelf.lock());
if (!m_bIsFloating || m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == m_pSelf) {
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true);
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock());
return;
}
if (box.size() > Vector2D{1, 1})
setHidden(false);
else
setHidden(true);
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos());
m_vRealPosition.setValueAndWarp(LOGICALPOS);
m_vRealSize.setValueAndWarp(box.size());
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) {
m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale);
m_fX11SurfaceScaledBy = PMONITOR->scale;
}
}
m_vPosition = m_vRealPosition.value();
m_vSize = m_vRealSize.value();
m_pXWaylandSurface->configure(box);
m_vPendingReportedSize = box.size();
m_vReportedSize = box.size();
updateWindowDecos();
if (!g_pCompositor->isWorkspaceVisible(m_pWorkspace))
return; // further things are only for visible windows
m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true);
m_bCreatedOverFullscreen = true;
if (!m_sAdditionalConfigData.windowDanceCompat)
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock());
}
void CWindow::warpCursor() {
static auto PERSISTENTWARPS = CConfigValue<Hyprlang::INT>("cursor:persistent_warps");
const auto coords = m_vRelativeCursorCoordsOnLastWarp;
m_vRelativeCursorCoordsOnLastWarp.x = -1; // reset m_vRelativeCursorCoordsOnLastWarp
if (*PERSISTENTWARPS && coords.x > 0 && coords.y > 0 && coords < m_vSize) // don't warp cursor outside the window
g_pCompositor->warpCursorTo(m_vPosition + coords);
else
g_pCompositor->warpCursorTo(middle());
}

View File

@ -1,20 +1,24 @@
#pragma once
#include "../defines.hpp"
#include "Subsurface.hpp"
#include "../helpers/AnimatedVariable.hpp"
#include "../render/decorations/IHyprWindowDecoration.hpp"
#include <deque>
#include <string>
#include "../config/ConfigDataValues.hpp"
#include "../defines.hpp"
#include "../helpers/AnimatedVariable.hpp"
#include "../helpers/Vector2D.hpp"
#include "WLSurface.hpp"
#include "Popup.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/TagKeeper.hpp"
#include "../macros.hpp"
#include "../managers/XWaylandManager.hpp"
#include "../render/decorations/IHyprWindowDecoration.hpp"
#include "DesktopTypes.hpp"
#include "../helpers/signal/Signal.hpp"
#include "Popup.hpp"
#include "Subsurface.hpp"
#include "WLSurface.hpp"
class CXDGSurfaceResource;
class CXWaylandSurface;
enum eIdleInhibitMode {
IDLEINHIBIT_NONE = 0,
@ -182,6 +186,7 @@ struct SWindowRule {
std::string szClass;
std::string szInitialTitle;
std::string szInitialClass;
std::string szTag;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
int bFullscreen = -1;
@ -199,48 +204,23 @@ struct SInitialWorkspaceToken {
class CWindow {
public:
static PHLWINDOW create(SP<CXDGSurfaceResource>);
// xwl
static PHLWINDOW create();
static PHLWINDOW create(SP<CXWaylandSurface>);
private:
CWindow(SP<CXDGSurfaceResource> resource);
CWindow();
CWindow(SP<CXWaylandSurface> surface);
public:
~CWindow();
DYNLISTENER(commitWindow);
DYNLISTENER(mapWindow);
DYNLISTENER(unmapWindow);
DYNLISTENER(destroyWindow);
DYNLISTENER(setTitleWindow);
DYNLISTENER(setGeometryX11U);
DYNLISTENER(fullscreenWindow);
DYNLISTENER(requestMove);
DYNLISTENER(requestMinimize);
DYNLISTENER(requestMaximize);
DYNLISTENER(requestResize);
DYNLISTENER(activateX11);
DYNLISTENER(configureX11);
DYNLISTENER(toplevelClose);
DYNLISTENER(toplevelActivate);
DYNLISTENER(toplevelFullscreen);
DYNLISTENER(setOverrideRedirect);
DYNLISTENER(associateX11);
DYNLISTENER(dissociateX11);
DYNLISTENER(ackConfigure);
// DYNLISTENER(newSubsurfaceWindow);
CWLSurface m_pWLSurface;
SP<CWLSurface> m_pWLSurface;
struct {
CSignal destroy;
} events;
union {
wlr_xwayland_surface* xwayland;
} m_uSurface;
WP<CXDGSurfaceResource> m_pXDGSurface;
WP<CXWaylandSurface> m_pXWaylandSurface;
// this is the position and size of the "bounding box"
Vector2D m_vPosition = Vector2D(0, 0);
@ -265,8 +245,11 @@ class CWindow {
Vector2D m_vFloatingOffset = Vector2D(0, 0);
// this is used for pseudotiling
bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(1280, 720);
bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(1280, 720);
// for recovering relative cursor position
Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1);
bool m_bFirstMap = false; // for layouts
bool m_bIsFloating = false;
@ -389,9 +372,12 @@ class CWindow {
// stores the currently matched window rules
std::vector<SWindowRule> m_vMatchedRules;
// window tags
CTagKeeper m_tags;
// For the list lookup
bool operator==(const CWindow& rhs) {
return m_pXDGSurface == rhs.m_pXDGSurface && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
m_bFadingOut == rhs.m_bFadingOut;
}
@ -410,7 +396,7 @@ class CWindow {
IHyprWindowDecoration* getDecorationByType(eDecorationType);
void removeDecorationByType(eDecorationType);
void updateToplevel();
void updateSurfaceScaleTransformDetails();
void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW X11TransientFor();
void onUnmap();
@ -459,8 +445,11 @@ class CWindow {
void onWorkspaceAnimUpdate();
void onUpdateState();
void onUpdateMeta();
void onX11Configure(CBox box);
void onResourceChangeX11();
std::string fetchTitle();
std::string fetchClass();
void warpCursor();
// listeners
void onAck(uint32_t serial);
@ -478,8 +467,12 @@ class CWindow {
CHyprSignalListener unmap;
CHyprSignalListener commit;
CHyprSignalListener destroy;
CHyprSignalListener activate;
CHyprSignalListener configure;
CHyprSignalListener setGeometry;
CHyprSignalListener updateState;
CHyprSignalListener updateMetadata;
CHyprSignalListener resourceChange;
} listeners;
private:

View File

@ -1,6 +1,7 @@
#include "Tablet.hpp"
#include "../defines.hpp"
#include "../protocols/Tablet.hpp"
#include "../protocols/core/Compositor.hpp"
SP<CTablet> CTablet::create(wlr_tablet* tablet) {
SP<CTablet> pTab = SP<CTablet>(new CTablet(tablet));
@ -295,32 +296,29 @@ CTabletTool::~CTabletTool() {
void CTabletTool::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_destroySurface.removeCallback();
listeners.destroySurface.reset();
}
wlr_surface* CTabletTool::getSurface() {
return pSurface;
SP<CWLSurfaceResource> CTabletTool::getSurface() {
return pSurface.lock();
}
void CTabletTool::setSurface(wlr_surface* surf) {
void CTabletTool::setSurface(SP<CWLSurfaceResource> surf) {
if (surf == pSurface)
return;
if (pSurface) {
hyprListener_destroySurface.removeCallback();
pSurface = nullptr;
listeners.destroySurface.reset();
pSurface.reset();
}
pSurface = surf;
if (surf) {
hyprListener_destroySurface.initCallback(
&surf->events.destroy,
[this](void* owner, void* data) {
PROTO::tablet->proximityOut(self.lock());
pSurface = nullptr;
hyprListener_destroySurface.removeCallback();
},
this, "CTabletTool");
listeners.destroySurface = surf->events.destroy.registerListener([this](std::any d) {
PROTO::tablet->proximityOut(self.lock());
pSurface.reset();
listeners.destroySurface.reset();
});
}
}

View File

@ -12,6 +12,7 @@ struct wlr_tablet_pad;
class CTabletTool;
class CTabletPad;
class CWLSurfaceResource;
/*
A tablet device
@ -197,32 +198,35 @@ class CTabletTool : public IHID {
HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5),
};
virtual uint32_t getCapabilities();
wlr_tablet_tool* wlr();
virtual eHIDType getType();
wlr_surface* getSurface();
void setSurface(wlr_surface*);
virtual uint32_t getCapabilities();
wlr_tablet_tool* wlr();
virtual eHIDType getType();
SP<CWLSurfaceResource> getSurface();
void setSurface(SP<CWLSurfaceResource>);
WP<CTabletTool> self;
Vector2D tilt;
bool active = false; // true if in proximity
uint32_t toolCapabilities = 0;
WP<CTabletTool> self;
Vector2D tilt;
bool active = false; // true if in proximity
uint32_t toolCapabilities = 0;
bool isDown = false;
std::vector<uint32_t> buttonsDown;
Vector2D absolutePos; // last known absolute position.
bool isDown = false;
std::vector<uint32_t> buttonsDown;
Vector2D absolutePos; // last known absolute position.
std::string hlName;
std::string hlName;
private:
CTabletTool(wlr_tablet_tool* tool);
void disconnectCallbacks();
void disconnectCallbacks();
wlr_surface* pSurface = nullptr;
WP<CWLSurfaceResource> pSurface;
wlr_tablet_tool* tool = nullptr;
wlr_tablet_tool* tool = nullptr;
DYNLISTENER(destroy);
DYNLISTENER(destroySurface);
struct {
CHyprSignalListener destroySurface;
} listeners;
};

View File

@ -33,8 +33,6 @@ namespace Events {
DYNLISTENFUNC(requestMinimize);
DYNLISTENFUNC(requestMaximize);
DYNLISTENFUNC(setOverrideRedirect);
DYNLISTENFUNC(associateX11);
DYNLISTENFUNC(dissociateX11);
DYNLISTENFUNC(ackConfigure);
LISTENER(newInput);
@ -56,7 +54,6 @@ namespace Events {
DYNLISTENFUNC(monitorBind);
// XWayland
LISTENER(readyXWayland);
LISTENER(surfaceXWayland);
// Renderer destroy

View File

@ -25,50 +25,6 @@ void Events::listener_leaseRequest(wl_listener* listener, void* data) {
}
}
void Events::listener_readyXWayland(wl_listener* listener, void* data) {
#ifndef NO_XWAYLAND
const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL);
const auto ERR = xcb_connection_has_error(XCBCONNECTION);
if (ERR) {
Debug::log(LogLevel::ERR, "XWayland -> xcb_connection_has_error failed with {}", ERR);
return;
}
for (auto& ATOM : HYPRATOMS) {
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(XCBCONNECTION, 0, ATOM.first.length(), ATOM.first.c_str());
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(XCBCONNECTION, cookie, NULL);
if (!reply) {
Debug::log(LogLevel::ERR, "XWayland -> Atom failed: {}", ATOM.first);
continue;
}
ATOM.second = reply->atom;
free(reply);
}
//wlr_xwayland_set_seat(g_pXWaylandManager->m_sWLRXWayland, g_pCompositor->m_sSeat.seat);
g_pCursorManager->setXWaylandCursor(g_pXWaylandManager->m_sWLRXWayland);
const auto ROOT = xcb_setup_roots_iterator(xcb_get_setup(XCBCONNECTION)).data->root;
auto cookie = xcb_get_property(XCBCONNECTION, 0, ROOT, HYPRATOMS["_NET_SUPPORTING_WM_CHECK"], XCB_ATOM_ANY, 0, 2048);
auto reply = xcb_get_property_reply(XCBCONNECTION, cookie, nullptr);
const auto XWMWINDOW = *(xcb_window_t*)xcb_get_property_value(reply);
const char* name = "Hyprland";
xcb_change_property(wlr_xwayland_get_xwm_connection(g_pXWaylandManager->m_sWLRXWayland), XCB_PROP_MODE_REPLACE, XWMWINDOW, HYPRATOMS["_NET_WM_NAME"], HYPRATOMS["UTF8_STRING"],
8, // format
strlen(name), name);
free(reply);
xcb_disconnect(XCBCONNECTION);
#endif
}
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
Debug::log(LOG, "!!Renderer destroyed!!");
}

View File

@ -9,6 +9,8 @@
#include "../config/ConfigValue.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../xwayland/XSurface.hpp"
// ------------------------------------------------------------ //
// __ _______ _ _ _____ ______ _______ //
@ -20,19 +22,6 @@
// //
// ------------------------------------------------------------ //
void addViewCoords(void* pWindow, int* x, int* y) {
const auto PWINDOW = (CWindow*)pWindow;
*x += PWINDOW->m_vRealPosition.goal().x;
*y += PWINDOW->m_vRealPosition.goal().y;
if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) {
Vector2D pos = PWINDOW->m_pXDGSurface->current.geometry.pos();
*x -= pos.x;
*y -= pos.y;
}
}
void setAnimToMove(void* data) {
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
@ -68,7 +57,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bReadyToDelete = false;
PWINDOW->m_bFadingOut = false;
PWINDOW->m_szTitle = PWINDOW->fetchTitle();
PWINDOW->m_iX11Type = PWINDOW->m_bIsX11 ? (PWINDOW->m_uSurface.xwayland->override_redirect ? 2 : 1) : 1;
PWINDOW->m_bFirstMap = true;
PWINDOW->m_szInitialTitle = PWINDOW->m_szTitle;
PWINDOW->m_szInitialClass = PWINDOW->fetchClass();
@ -117,7 +105,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// registers the animated vars and stuff
PWINDOW->onMap();
const auto PWINDOWSURFACE = PWINDOW->m_pWLSurface.wlr();
const auto PWINDOWSURFACE = PWINDOW->m_pWLSurface->resource();
if (!PWINDOWSURFACE) {
g_pCompositor->removeWindowFromVectorSafe(PWINDOW);
@ -129,8 +117,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bRequestsFloat = true;
}
PWINDOW->m_bX11ShouldntFocus =
PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland));
PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2 && !PWINDOW->m_pXWaylandSurface->wantsFocus());
if (PWORKSPACE->m_bDefaultFloating)
PWINDOW->m_bIsFloating = true;
@ -144,7 +131,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// window rules
PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen);
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen);
bool requestsFakeFullscreen = false;
bool requestsMaximize = false;
bool overridingNoFullscreen = false;
@ -477,24 +464,23 @@ void Events::listener_mapWindow(void* owner, void* data) {
// check LS focus grab
const auto PFORCEFOCUS = g_pCompositor->getForceFocus();
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock());
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE)
PWINDOW->m_bNoInitialFocus = true;
if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
if (*PNEWTAKESOVERFS == 0)
PWINDOW->m_bNoInitialFocus = true;
else if (*PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID);
else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), false, FULLSCREEN_INVALID);
else if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
requestsMaximize = true;
else
requestsFullscreen = true;
}
if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus &&
(PWINDOW->m_iX11Type != 2 ||
(PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->window_type_len > 0 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) &&
!workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) {
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) &&
!g_pInputManager->isConstrained()) {
g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH);
@ -503,27 +489,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_fDimPercent.setValueAndWarp(0);
}
if (PWINDOW->m_bIsX11) {
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW.get(),
"XWayland Window Late");
PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW.get(),
"XWayland Window Late");
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_title, &Events::listener_setTitleWindow, PWINDOW.get(), "XWayland Window Late");
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_minimize, &Events::listener_requestMinimize, PWINDOW.get(),
"Xwayland Window Late");
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_maximize, &Events::listener_requestMaximize, PWINDOW.get(),
"Xwayland Window Late");
if (PWINDOW->m_iX11Type == 2)
PWINDOW->hyprListener_setGeometryX11U.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_geometry, &Events::listener_unmanagedSetGeometry, PWINDOW.get(),
"XWayland Window Late");
}
if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) ||
(requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) {
// fix fullscreen on requested (basically do a switcheroo)
if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID);
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
}
@ -649,8 +619,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating)
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->transform);
if (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())
g_pInputManager->sendMotionEventsToFocused();
@ -669,7 +639,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "{:c} unmapped", PWINDOW);
if (!PWINDOW->m_pWLSurface.exists() || !PWINDOW->m_bIsMapped) {
if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) {
Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW);
PWINDOW->m_bFadingOut = false;
return;
@ -687,16 +657,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW);
if (!PWINDOW->m_bIsX11) {
Debug::log(LOG, "Unregistered late callbacks XWL");
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
PWINDOW->hyprListener_activateX11.removeCallback();
PWINDOW->hyprListener_setTitleWindow.removeCallback();
PWINDOW->hyprListener_setGeometryX11U.removeCallback();
PWINDOW->hyprListener_requestMaximize.removeCallback();
PWINDOW->hyprListener_requestMinimize.removeCallback();
}
if (PWINDOW->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
@ -715,7 +675,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) {
wasLastWindow = true;
g_pCompositor->m_pLastWindow.reset();
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastFocus.reset();
g_pInputManager->releaseAllMouseButtons();
}
@ -829,7 +789,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
if (!PWINDOW->m_pWorkspace->m_bVisible)
return;
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
if (!PWINDOW->m_bIsX11) {
@ -839,9 +799,8 @@ void Events::listener_commitWindow(void* owner, void* data) {
// tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear &&
PWINDOW->m_pWLSurface.wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
CRegion damageBox{&PWINDOW->m_pWLSurface.wlr()->buffer_damage};
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) {
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.bufferDamage};
if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) {
@ -859,24 +818,12 @@ void Events::listener_destroyWindow(void* owner, void* data) {
Debug::log(LOG, "{:c} destroyed, queueing.", PWINDOW);
if (PWINDOW->m_bIsX11)
Debug::log(LOG, "XWayland class raw: {}", PWINDOW->m_uSurface.xwayland->_class ? PWINDOW->m_uSurface.xwayland->_class : "null");
if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) {
g_pCompositor->m_pLastWindow.reset();
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastFocus.reset();
}
PWINDOW->m_pWLSurface.unassign();
PWINDOW->hyprListener_commitWindow.removeCallback();
PWINDOW->hyprListener_mapWindow.removeCallback();
PWINDOW->hyprListener_unmapWindow.removeCallback();
PWINDOW->hyprListener_destroyWindow.removeCallback();
PWINDOW->hyprListener_configureX11.removeCallback();
PWINDOW->hyprListener_setOverrideRedirect.removeCallback();
PWINDOW->hyprListener_associateX11.removeCallback();
PWINDOW->hyprListener_dissociateX11.removeCallback();
PWINDOW->m_pWLSurface->unassign();
PWINDOW->listeners = {};
@ -901,39 +848,6 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
PWINDOW->onUpdateMeta();
}
void Events::listener_fullscreenWindow(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
// x11 only
if (!PWINDOW->m_bIsMapped) {
PWINDOW->m_bWantsInitialFullscreen = true;
return;
}
if (PWINDOW->isHidden() || (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
return;
bool requestedFullState = false;
if (!PWINDOW->m_uSurface.xwayland->surface->mapped)
return;
if (!PWINDOW->m_bFakeFullscreenState)
g_pCompositor->setWindowFullscreen(PWINDOW, PWINDOW->m_uSurface.xwayland->fullscreen, FULLSCREEN_FULL);
requestedFullState = PWINDOW->m_uSurface.xwayland->fullscreen;
if (!requestedFullState && PWINDOW->m_bFakeFullscreenState) {
g_pXWaylandManager->setWindowFullscreen(PWINDOW, false); // fixes for apps expecting a de-fullscreen (e.g. ff)
g_pXWaylandManager->setWindowFullscreen(PWINDOW, true);
}
PWINDOW->updateToplevel();
Debug::log(LOG, "{} fullscreen to {}", PWINDOW, PWINDOW->m_bIsFullscreen);
}
void Events::listener_activateX11(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
@ -946,7 +860,7 @@ void Events::listener_activateX11(void* owner, void* data) {
if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID())
return;
if (!wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))
if (!PWINDOW->m_pXWaylandSurface->wantsFocus())
return;
g_pCompositor->focusWindow(PWINDOW);
@ -959,82 +873,16 @@ void Events::listener_activateX11(void* owner, void* data) {
PWINDOW->activate();
}
void Events::listener_configureX11(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
const auto E = (wlr_xwayland_surface_configure_event*)data;
if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bIsMapped) {
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
PWINDOW->m_vPendingReportedSize = {E->width, E->height};
PWINDOW->m_vReportedSize = {E->width, E->height};
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
return;
}
g_pHyprRenderer->damageWindow(PWINDOW);
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow.lock() == PWINDOW) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW);
return;
}
if (E->width > 1 && E->height > 1)
PWINDOW->setHidden(false);
else
PWINDOW->setHidden(true);
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({E->x, E->y});
PWINDOW->m_vRealPosition.setValueAndWarp(LOGICALPOS);
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height));
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
}
}
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.value();
PWINDOW->m_vSize = PWINDOW->m_vRealSize.value();
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
PWINDOW->m_vPendingReportedSize = {E->width, E->height};
PWINDOW->m_vReportedSize = {E->width, E->height};
PWINDOW->updateWindowDecos();
if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_pWorkspace))
return; // further things are only for visible windows
PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(PWINDOW, true);
PWINDOW->m_bCreatedOverFullscreen = true;
if (!PWINDOW->m_sAdditionalConfigData.windowDanceCompat)
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW);
}
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
if (!PWINDOW->m_bIsMapped)
if (!PWINDOW->m_bIsMapped || !PWINDOW->m_pXWaylandSurface || !PWINDOW->m_pXWaylandSurface->overrideRedirect)
return;
const auto POS = PWINDOW->m_vRealPosition.goal();
const auto SIZ = PWINDOW->m_vRealSize.goal();
if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1)
if (PWINDOW->m_pXWaylandSurface->geometry.size() > Vector2D{1, 1})
PWINDOW->setHidden(false);
else
PWINDOW->setHidden(true);
@ -1047,18 +895,17 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y});
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(PWINDOW->m_pXWaylandSurface->geometry.pos());
if (abs(std::floor(POS.x) - LOGICALPOS.x) > 2 || abs(std::floor(POS.y) - LOGICALPOS.y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 ||
abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) {
Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {} {}", PWINDOW, LOGICALPOS, (int)PWINDOW->m_uSurface.xwayland->width,
(int)PWINDOW->m_uSurface.xwayland->height);
if (abs(std::floor(POS.x) - LOGICALPOS.x) > 2 || abs(std::floor(POS.y) - LOGICALPOS.y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.width) > 2 ||
abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.height) > 2) {
Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {:j}", PWINDOW, LOGICALPOS, PWINDOW->m_pXWaylandSurface->geometry.size());
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y));
if (abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2)
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height));
if (abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.w) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.h) > 2)
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size());
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
@ -1079,92 +926,3 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal();
}
}
void Events::listener_setOverrideRedirect(void* owner, void* data) {
// const auto PWINDOW = (CWindow*)owner;
//if (!PWINDOW->m_bIsMapped && PWINDOW->m_uSurface.xwayland->mapped) {
// Events::listener_mapWindow(PWINDOW, nullptr);
//}
}
void Events::listener_associateX11(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW.get(), "XWayland Window");
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.commit, &Events::listener_commitWindow, PWINDOW.get(), "XWayland Window");
PWINDOW->m_pWLSurface.assign(PWINDOW->m_uSurface.xwayland->surface, PWINDOW);
}
void Events::listener_dissociateX11(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
PWINDOW->m_pWLSurface.unassign();
PWINDOW->hyprListener_mapWindow.removeCallback();
PWINDOW->hyprListener_commitWindow.removeCallback();
}
void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
const auto XWSURFACE = (wlr_xwayland_surface*)data;
Debug::log(LOG, "New XWayland Surface created (class {}).", XWSURFACE->_class ? XWSURFACE->_class : "null");
if (XWSURFACE->parent)
Debug::log(LOG, "Window parent data: {} at {:x}", XWSURFACE->parent->_class ? XWSURFACE->parent->_class : "null", (uintptr_t)XWSURFACE->parent);
const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(CWindow::create());
PNEWWINDOW->m_uSurface.xwayland = XWSURFACE;
PNEWWINDOW->m_iX11Type = XWSURFACE->override_redirect ? 2 : 1;
PNEWWINDOW->m_bIsX11 = true;
PNEWWINDOW->m_pX11Parent = g_pCompositor->getX11Parent(PNEWWINDOW);
PNEWWINDOW->hyprListener_associateX11.initCallback(&XWSURFACE->events.associate, &Events::listener_associateX11, PNEWWINDOW.get(), "XWayland Window");
PNEWWINDOW->hyprListener_dissociateX11.initCallback(&XWSURFACE->events.dissociate, &Events::listener_dissociateX11, PNEWWINDOW.get(), "XWayland Window");
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XWSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW.get(), "XWayland Window");
PNEWWINDOW->hyprListener_setOverrideRedirect.initCallback(&XWSURFACE->events.set_override_redirect, &Events::listener_setOverrideRedirect, PNEWWINDOW.get(), "XWayland Window");
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW.get(), "XWayland Window");
}
void Events::listener_requestMaximize(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)
return;
Debug::log(LOG, "Maximize request for {}", PWINDOW);
if (!PWINDOW->m_bIsX11) {
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen,
FULLSCREEN_MAXIMIZED); // this will be rejected if there already is a fullscreen window
} else {
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
return;
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED);
}
}
void Events::listener_requestMinimize(void* owner, void* data) {
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
Debug::log(LOG, "Minimize request for {}", PWINDOW);
if (PWINDOW->m_bIsX11) {
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
return;
const auto E = (wlr_xwayland_minimize_event*)data;
g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW.get(), (int)E->minimize)});
EMIT_HOOK_EVENT("minimize", (std::vector<std::any>{PWINDOW, E->minimize}));
wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow.lock() != PWINDOW); // fucking DXVK
} else {
g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW.get(), 1)});
EMIT_HOOK_EVENT("minimize", (std::vector<std::any>{PWINDOW, (int64_t)(1)}));
}
}

272
src/helpers/Format.cpp Normal file
View File

@ -0,0 +1,272 @@
#include "Format.hpp"
#include <vector>
#include "../includes.hpp"
#include "debug/Log.hpp"
/*
DRM formats are LE, while OGL is BE. The two primary formats
will be flipped, so we will set flipRB which will later use swizzle
to flip the red and blue channels.
This will not work on GLES2, but I want to drop support for it one day anyways.
*/
inline const std::vector<SPixelFormat> GLES3_FORMATS = {
{
.drmFormat = DRM_FORMAT_ARGB8888,
.flipRB = true,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = true,
.alphaStripped = DRM_FORMAT_XRGB8888,
.bytesPerBlock = 4,
},
{
.drmFormat = DRM_FORMAT_XRGB8888,
.flipRB = true,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_XRGB8888,
.bytesPerBlock = 4,
},
{
.drmFormat = DRM_FORMAT_XBGR8888,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_XBGR8888,
.bytesPerBlock = 4,
},
{
.drmFormat = DRM_FORMAT_ABGR8888,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = true,
.alphaStripped = DRM_FORMAT_XBGR8888,
.bytesPerBlock = 4,
},
{
.drmFormat = DRM_FORMAT_BGR888,
.glFormat = GL_RGB,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_BGR888,
.bytesPerBlock = 3,
},
{
.drmFormat = DRM_FORMAT_RGBX4444,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_4_4_4_4,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_RGBX4444,
.bytesPerBlock = 2,
},
{
.drmFormat = DRM_FORMAT_RGBA4444,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_4_4_4_4,
.withAlpha = true,
.alphaStripped = DRM_FORMAT_RGBX4444,
.bytesPerBlock = 2,
},
{
.drmFormat = DRM_FORMAT_RGBX5551,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_5_5_5_1,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_RGBX5551,
.bytesPerBlock = 2,
},
{
.drmFormat = DRM_FORMAT_RGBA5551,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_5_5_5_1,
.withAlpha = true,
.alphaStripped = DRM_FORMAT_RGBX5551,
.bytesPerBlock = 2,
},
{
.drmFormat = DRM_FORMAT_RGB565,
.glFormat = GL_RGB,
.glType = GL_UNSIGNED_SHORT_5_6_5,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_RGB565,
.bytesPerBlock = 2,
},
{
.drmFormat = DRM_FORMAT_XBGR2101010,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_XBGR2101010,
.bytesPerBlock = 4,
},
{
.drmFormat = DRM_FORMAT_ABGR2101010,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
.withAlpha = true,
.alphaStripped = DRM_FORMAT_XBGR2101010,
.bytesPerBlock = 4,
},
{
.drmFormat = DRM_FORMAT_XRGB2101010,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_XRGB2101010,
.bytesPerBlock = 4,
},
{
.drmFormat = DRM_FORMAT_ARGB2101010,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
.withAlpha = true,
.alphaStripped = DRM_FORMAT_XRGB2101010,
.bytesPerBlock = 4,
},
{
.drmFormat = DRM_FORMAT_XBGR16161616F,
.glFormat = GL_RGBA,
.glType = GL_HALF_FLOAT,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_XBGR16161616F,
.bytesPerBlock = 8,
},
{
.drmFormat = DRM_FORMAT_ABGR16161616F,
.glFormat = GL_RGBA,
.glType = GL_HALF_FLOAT,
.withAlpha = true,
.alphaStripped = DRM_FORMAT_XBGR16161616F,
.bytesPerBlock = 8,
},
{
.drmFormat = DRM_FORMAT_XBGR16161616,
.glInternalFormat = GL_RGBA16UI,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_XBGR16161616,
.bytesPerBlock = 8,
},
{
.drmFormat = DRM_FORMAT_ABGR16161616,
.glInternalFormat = GL_RGBA16UI,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT,
.withAlpha = true,
.alphaStripped = DRM_FORMAT_XBGR16161616,
.bytesPerBlock = 8,
},
{
.drmFormat = DRM_FORMAT_YVYU,
.bytesPerBlock = 4,
.blockSize = {2, 1},
},
{
.drmFormat = DRM_FORMAT_VYUY,
.bytesPerBlock = 4,
.blockSize = {2, 1},
},
{
.drmFormat = DRM_FORMAT_R8,
.bytesPerBlock = 1,
},
{
.drmFormat = DRM_FORMAT_GR88,
.bytesPerBlock = 2,
},
{
.drmFormat = DRM_FORMAT_RGB888,
.bytesPerBlock = 3,
},
{
.drmFormat = DRM_FORMAT_BGR888,
.bytesPerBlock = 3,
},
{
.drmFormat = DRM_FORMAT_RGBX4444,
.bytesPerBlock = 2,
},
};
SHMFormat FormatUtils::drmToShm(DRMFormat drm) {
switch (drm) {
case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888;
case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888;
default: return drm;
}
return drm;
}
DRMFormat FormatUtils::shmToDRM(SHMFormat shm) {
switch (shm) {
case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888;
case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888;
default: return shm;
}
return shm;
}
const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) {
for (auto& fmt : GLES3_FORMATS) {
if (fmt.drmFormat == drm)
return &fmt;
}
return nullptr;
}
const SPixelFormat* FormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha) {
for (auto& fmt : GLES3_FORMATS) {
if (fmt.glFormat == (int)glFormat && fmt.glType == (int)glType && fmt.withAlpha == alpha)
return &fmt;
}
return nullptr;
}
bool FormatUtils::isFormatOpaque(DRMFormat drm) {
const auto FMT = FormatUtils::getPixelFormatFromDRM(drm);
if (!FMT)
return false;
return !FMT->withAlpha;
}
int FormatUtils::pixelsPerBlock(const SPixelFormat* const fmt) {
return fmt->blockSize.x * fmt->blockSize.y > 0 ? fmt->blockSize.x * fmt->blockSize.y : 1;
}
int FormatUtils::minStride(const SPixelFormat* const fmt, int32_t width) {
return std::ceil((width * fmt->bytesPerBlock) / pixelsPerBlock(fmt));
}
uint32_t FormatUtils::drmFormatToGL(DRMFormat drm) {
switch (drm) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
#ifdef GLES2
return GL_RGB10_A2_EXT;
#else
return GL_RGB10_A2;
#endif
default: return GL_RGBA;
}
UNREACHABLE();
return GL_RGBA;
}
uint32_t FormatUtils::glFormatToType(uint32_t gl) {
return gl != GL_RGBA ?
#ifdef GLES2
GL_UNSIGNED_INT_2_10_10_10_REV_EXT :
#else
GL_UNSIGNED_INT_2_10_10_10_REV :
#endif
GL_UNSIGNED_BYTE;
}

37
src/helpers/Format.hpp Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <cstdint>
#include "Vector2D.hpp"
typedef uint32_t DRMFormat;
typedef uint32_t SHMFormat;
struct SPixelFormat {
DRMFormat drmFormat = 0; /* DRM_FORMAT_INVALID */
bool flipRB = false;
int glInternalFormat = 0;
int glFormat = 0;
int glType = 0;
bool withAlpha = true;
DRMFormat alphaStripped = 0; /* DRM_FORMAT_INVALID */
uint32_t bytesPerBlock = 0;
Vector2D blockSize;
};
struct SDRMFormat {
uint32_t format = 0;
std::vector<uint64_t> mods;
};
namespace FormatUtils {
SHMFormat drmToShm(DRMFormat drm);
DRMFormat shmToDRM(SHMFormat shm);
const SPixelFormat* getPixelFormatFromDRM(DRMFormat drm);
const SPixelFormat* getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha);
bool isFormatOpaque(DRMFormat drm);
int pixelsPerBlock(const SPixelFormat* const fmt);
int minStride(const SPixelFormat* const fmt, int32_t width);
uint32_t drmFormatToGL(DRMFormat drm);
uint32_t glFormatToType(uint32_t gl);
};

View File

@ -649,6 +649,8 @@ void logSystemInfo() {
#if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
#elif defined(__arm__) || defined(__aarch64__)
const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible");
#else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif
@ -855,33 +857,6 @@ void throwError(const std::string& err) {
throw std::runtime_error(err);
}
uint32_t drmFormatToGL(uint32_t drm) {
switch (drm) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
#ifdef GLES2
return GL_RGB10_A2_EXT;
#else
return GL_RGB10_A2;
#endif
default: return GL_RGBA;
}
UNREACHABLE();
return GL_RGBA;
}
uint32_t glFormatToType(uint32_t gl) {
return gl != GL_RGBA ?
#ifdef GLES2
GL_UNSIGNED_INT_2_10_10_10_REV_EXT :
#else
GL_UNSIGNED_INT_2_10_10_10_REV :
#endif
GL_UNSIGNED_BYTE;
}
bool envEnabled(const std::string& env) {
const auto ENV = getenv(env.c_str());
if (!ENV)
@ -920,3 +895,42 @@ int allocateSHMFile(size_t len) {
return fd;
}
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) {
auto [fd, name] = openExclusiveShm();
if (fd < 0) {
return false;
}
// CLOEXEC is guaranteed to be set by shm_open
int ro_fd = shm_open(name.c_str(), O_RDONLY, 0);
if (ro_fd < 0) {
shm_unlink(name.c_str());
close(fd);
return false;
}
shm_unlink(name.c_str());
// Make sure the file cannot be re-opened in read-write mode (e.g. via
// "/proc/self/fd/" on Linux)
if (fchmod(fd, 0) != 0) {
close(fd);
close(ro_fd);
return false;
}
int ret;
do {
ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
close(fd);
close(ro_fd);
return false;
}
*rw_fd_ptr = fd;
*ro_fd_ptr = ro_fd;
return true;
}

View File

@ -35,10 +35,9 @@ double normalizeAngleRad(double ang);
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err);
uint32_t drmFormatToGL(uint32_t drm);
uint32_t glFormatToType(uint32_t gl);
bool envEnabled(const std::string& env);
int allocateSHMFile(size_t len);
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr);
template <typename... Args>
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {

View File

@ -184,6 +184,9 @@ void CMonitor::onConnect(bool noRule) {
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
//
if (!activeMonitorRule.mirrorOf.empty())
setMirror(activeMonitorRule.mirrorOf);
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)});
EMIT_HOOK_EVENT("monitorAdded", this);
@ -216,7 +219,6 @@ void CMonitor::onConnect(bool noRule) {
PROTO::gamma->applyGammaToState(this);
events.connect.emit();
updateGlobal();
}
void CMonitor::onDisconnect(bool destroy) {
@ -284,8 +286,6 @@ void CMonitor::onDisconnect(bool destroy) {
m_bEnabled = false;
m_bRenderingInitPassed = false;
updateGlobal();
if (BACKUPMON) {
// snap cursor
g_pCompositor->warpCursorTo(BACKUPMON->vecPosition + BACKUPMON->vecTransformedSize / 2.F, true);
@ -304,7 +304,7 @@ void CMonitor::onDisconnect(bool destroy) {
w->startAnim(true, true, true);
}
} else {
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastFocus.reset();
g_pCompositor->m_pLastWindow.reset();
g_pCompositor->m_pLastMonitor.reset();
}
@ -520,6 +520,8 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
g_pCompositor->sanityCheckWorkspaces();
}
events.modeChanged.emit();
}
float CMonitor::getDefaultScale() {
@ -750,13 +752,6 @@ CBox CMonitor::logicalBox() {
return {vecPosition, vecSize};
}
void CMonitor::updateGlobal() {
if (output->width > 0 && output->height > 0 && m_bEnabled)
wlr_output_create_global(output, g_pCompositor->m_sWLDisplay);
else
wlr_output_destroy_global(output);
}
CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
wlr_output_state_init(&m_state);

View File

@ -13,7 +13,8 @@
#include "signal/Signal.hpp"
// Enum for the different types of auto directions, e.g. auto-left, auto-up.
enum class eAutoDirs {
enum eAutoDirs {
DIR_AUTO_NONE = 0, /* None will be treated as right. */
DIR_AUTO_UP,
DIR_AUTO_DOWN,
DIR_AUTO_LEFT,
@ -21,7 +22,7 @@ enum class eAutoDirs {
};
struct SMonitorRule {
eAutoDirs autoDir;
eAutoDirs autoDir = DIR_AUTO_NONE;
std::string name = "";
Vector2D resolution = Vector2D(1280, 720);
Vector2D offset = Vector2D(0, 0);
@ -171,7 +172,6 @@ class CMonitor {
int64_t activeWorkspaceID();
int64_t activeSpecialWorkspaceID();
CBox logicalBox();
void updateGlobal();
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;

View File

@ -4,6 +4,8 @@ extern "C" {
#include <wlr/util/region.h>
}
constexpr const int64_t MAX_REGION_SIDE = 10000000;
CRegion::CRegion() {
pixman_region32_init(&m_rRegion);
}
@ -103,6 +105,11 @@ CRegion& CRegion::transform(const wl_output_transform t, double w, double h) {
return *this;
}
CRegion& CRegion::rationalize() {
intersect(CBox{-MAX_REGION_SIDE, -MAX_REGION_SIDE, MAX_REGION_SIDE * 2, MAX_REGION_SIDE * 2});
return *this;
}
CRegion CRegion::copy() const {
return CRegion(*this);
}

View File

@ -50,6 +50,7 @@ class CRegion {
CRegion& invert(const CBox& box);
CRegion& scale(float scale);
CRegion& scale(const Vector2D& scale);
CRegion& rationalize();
CBox getExtents();
bool containsPoint(const Vector2D& vec) const;
bool empty() const;

View File

@ -21,8 +21,8 @@ namespace Systemd {
}
int SdNotify(int unsetEnvironment, const char* state) {
int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd == -1)
int fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
constexpr char envVar[] = "NOTIFY_SOCKET";
@ -47,12 +47,12 @@ namespace Systemd {
if (unixAddr.sun_path[0] == '@')
unixAddr.sun_path[0] = '\0';
if (!connect(fd, (const sockaddr*)&unixAddr, sizeof(struct sockaddr_un)))
return 1;
if (connect(fd, (const sockaddr*)&unixAddr, sizeof(struct sockaddr_un)) < 0)
return -errno;
// arbitrary value which seems to be enough for s-d messages
size_t stateLen = strnlen(state, 128);
if (write(fd, state, stateLen) >= 0)
ssize_t stateLen = strnlen(state, 128);
if (write(fd, state, stateLen) == stateLen)
return 1;
return -errno;

40
src/helpers/TagKeeper.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "TagKeeper.hpp"
bool CTagKeeper::isTagged(const std::string& tag, bool strict) {
return m_tags.contains(tag) || (!strict && m_tags.contains(tag + "*"));
}
bool CTagKeeper::applyTag(const std::string& tag, bool dynamic) {
std::string tagReal = tag;
if (dynamic && !tag.ends_with("*"))
tagReal += "*";
bool changed = true;
bool setTag = true;
if (tagReal.starts_with("-")) { // unset
tagReal = tagReal.substr(1);
changed = isTagged(tagReal, true);
setTag = false;
} else if (tagReal.starts_with("+")) { // set
tagReal = tagReal.substr(1);
changed = !isTagged(tagReal, true);
} else // toggle if without prefix
setTag = !isTagged(tagReal, true);
if (!changed)
return false;
if (setTag)
m_tags.emplace(tagReal);
else
m_tags.erase(tagReal);
return true;
}
bool CTagKeeper::removeDynamicTags() {
return std::erase_if(m_tags, [](const auto& tag) { return tag.ends_with("*"); });
}

18
src/helpers/TagKeeper.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <string>
#include <set>
class CTagKeeper {
public:
bool isTagged(const std::string& tag, bool strict = false);
bool applyTag(const std::string& tag, bool dynamic = false);
bool removeDynamicTags();
inline const auto& getTags() {
return m_tags;
};
private:
std::set<std::string> m_tags;
};

View File

@ -13,6 +13,7 @@
class CMonitor;
class IPointer;
class IKeyboard;
class CWLSurfaceResource;
struct SRenderData {
CMonitor* pMonitor;
@ -20,9 +21,9 @@ struct SRenderData {
double x, y;
// for iters
void* data = nullptr;
wlr_surface* surface = nullptr;
double w, h;
void* data = nullptr;
SP<CWLSurfaceResource> surface = nullptr;
double w, h;
// for rounding
bool dontRound = true;
@ -52,12 +53,6 @@ struct SRenderData {
bool popup = false;
};
struct SExtensionFindingData {
Vector2D origin;
Vector2D vec;
wlr_surface** found;
};
struct SSwipeGesture {
PHLWORKSPACE pWorkspaceBegin = nullptr;

View File

@ -1,172 +0,0 @@
#pragma once
#include <wayland-server.h>
typedef unsigned int xcb_atom_t;
struct xcb_icccm_wm_hints_t;
typedef struct {
/** User specified flags */
uint32_t flags;
/** User-specified position */
int32_t x, y;
/** User-specified size */
int32_t width, height;
/** Program-specified minimum size */
int32_t min_width, min_height;
/** Program-specified maximum size */
int32_t max_width, max_height;
/** Program-specified resize increments */
int32_t width_inc, height_inc;
/** Program-specified minimum aspect ratios */
int32_t min_aspect_num, min_aspect_den;
/** Program-specified maximum aspect ratios */
int32_t max_aspect_num, max_aspect_den;
/** Program-specified base size */
int32_t base_width, base_height;
/** Program-specified window gravity */
uint32_t win_gravity;
} xcb_size_hints_t;
typedef unsigned int xcb_window_t;
typedef enum xcb_stack_mode_t {
XCB_STACK_MODE_ABOVE = 0,
XCB_STACK_MODE_BELOW = 1,
XCB_STACK_MODE_TOP_IF = 2,
XCB_STACK_MODE_BOTTOM_IF = 3,
XCB_STACK_MODE_OPPOSITE = 4
} xcb_stack_mode_t;
struct wlr_xwayland {
struct wlr_xwayland_server* server;
struct wlr_xwm* xwm;
struct wlr_xwayland_cursor* cursor;
const char* display_name;
struct wl_display* wl_display;
struct wlr_compositor* compositor;
struct wlr_seat* seat;
void* data;
};
struct wlr_xwayland_surface {
xcb_window_t window_id;
struct wlr_xwm* xwm;
uint32_t surface_id;
struct wl_list link;
struct wl_list stack_link;
struct wl_list unpaired_link;
struct wlr_surface* surface;
int16_t x, y;
uint16_t width, height;
uint16_t saved_width, saved_height;
bool override_redirect;
bool mapped;
char* title;
char* _class;
char* instance;
char* role;
char* startup_id;
pid_t pid;
bool has_utf8_title;
struct wl_list children; // wlr_xwayland_surface::parent_link
struct wlr_xwayland_surface* parent;
struct wl_list parent_link; // wlr_xwayland_surface::children
xcb_atom_t* window_type;
size_t window_type_len;
xcb_atom_t* protocols;
size_t protocols_len;
uint32_t decorations;
xcb_icccm_wm_hints_t* hints;
xcb_size_hints_t* size_hints;
bool pinging;
struct wl_event_source* ping_timer;
// _NET_WM_STATE
bool modal;
bool fullscreen;
bool maximized_vert, maximized_horz;
bool minimized;
bool has_alpha;
struct {
struct wl_signal destroy;
struct wl_signal request_configure;
struct wl_signal request_move;
struct wl_signal request_resize;
struct wl_signal request_minimize;
struct wl_signal request_maximize;
struct wl_signal request_fullscreen;
struct wl_signal request_activate;
struct wl_signal map;
struct wl_signal unmap;
struct wl_signal associate;
struct wl_signal dissociate;
struct wl_signal set_title;
struct wl_signal set_class;
struct wl_signal set_role;
struct wl_signal set_parent;
struct wl_signal set_startup_id;
struct wl_signal set_window_type;
struct wl_signal set_hints;
struct wl_signal set_decorations;
struct wl_signal set_override_redirect;
struct wl_signal set_geometry;
struct wl_signal ping_timeout;
} events;
};
struct wlr_xwayland_surface_configure_event {
struct wlr_xwayland_surface* surface;
int16_t x, y;
uint16_t width, height;
uint16_t mask; // xcb_config_window_t
};
struct wlr_xwayland_minimize_event {
struct wlr_xwayland_surface* surface;
bool minimize;
};
inline void wlr_xwayland_destroy(wlr_xwayland*) {}
inline void wlr_xwayland_surface_configure(wlr_xwayland_surface*, int, int, int, int) {}
inline bool wlr_surface_is_xwayland_surface(void*) {
return false;
}
inline void wlr_xwayland_surface_activate(wlr_xwayland_surface*, bool) {}
inline void wlr_xwayland_surface_restack(wlr_xwayland_surface*, void*, xcb_stack_mode_t) {}
inline wlr_xwayland_surface* wlr_xwayland_surface_from_wlr_surface(void*) {
return nullptr;
}
inline void wlr_xwayland_surface_close(wlr_xwayland_surface*) {}
inline void wlr_xwayland_surface_set_fullscreen(wlr_xwayland_surface*, bool) {}
inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface*, bool) {}
inline wlr_xwayland_surface* wlr_xwayland_surface_try_from_wlr_surface(wlr_surface*) {
return nullptr;
}
inline bool wlr_xwayland_or_surface_wants_focus(const wlr_xwayland_surface*) {
return false;
}
inline void wlr_xwayland_set_cursor(wlr_xwayland* wlr_xwayland, uint8_t* pixels, uint32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) {}

View File

@ -60,7 +60,7 @@ namespace CSharedPointer_ {
bool _destroying = false;
void _destroy() {
if (!_data)
if (!_data || _destroying)
return;
// first, we destroy the data, but keep the pointer.
@ -297,6 +297,6 @@ static CSharedPointer<U> makeShared(Args&&... args) {
template <typename T>
struct std::hash<CSharedPointer<T>> {
std::size_t operator()(const CSharedPointer<T>& p) const noexcept {
return std::hash<void*>{}(p->impl_);
return std::hash<void*>{}(p.impl_);
}
};

View File

@ -185,6 +185,6 @@ class CWeakPointer {
template <typename T>
struct std::hash<CWeakPointer<T>> {
std::size_t operator()(const CWeakPointer<T>& p) const noexcept {
return std::hash<void*>{}(p->impl_);
return std::hash<void*>{}(p.impl_);
}
};

View File

@ -2,19 +2,40 @@
#include <algorithm>
void CSignal::emit(std::any data) {
bool dirty = false;
bool dirty = false;
std::vector<SP<CSignalListener>> listeners;
for (auto& l : m_vListeners) {
if (const CHyprSignalListener L = l.lock())
L->emit(data);
else
if (l.expired()) {
dirty = true;
continue;
}
listeners.emplace_back(l.lock());
}
std::vector<CStaticSignalListener*> statics;
for (auto& l : m_vStaticListeners) {
statics.emplace_back(l.get());
}
for (auto& l : listeners) {
// if there is only one lock, it means the event is only held by the listeners
// vector and was removed during our iteration
if (l.strongRef() == 1) {
dirty = true;
continue;
}
l->emit(data);
}
for (auto& l : statics) {
l->emit(data);
}
// release SPs
listeners.clear();
if (dirty)
std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); });
}

View File

@ -22,6 +22,8 @@ CHyprError::CHyprError() {
if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged)
g_pHyprRenderer->damageBox(&m_bDamageBox);
});
m_pTexture = makeShared<CTexture>();
}
CHyprError::~CHyprError() {
@ -34,9 +36,8 @@ void CHyprError::queueCreate(std::string message, const CColor& color) {
}
void CHyprError::createQueued() {
if (m_bIsCreated) {
m_tTexture.destroyTexture();
}
if (m_bIsCreated)
m_pTexture->destroyTexture();
m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
@ -136,8 +137,8 @@ void CHyprError::createQueued() {
// copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
m_tTexture.allocate();
glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID);
m_pTexture->allocate();
glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -170,7 +171,7 @@ void CHyprError::draw() {
if (!m_fFadeOpacity.isBeingAnimated()) {
if (m_fFadeOpacity.value() == 0.f) {
m_bQueuedDestroy = false;
m_tTexture.destroyTexture();
m_pTexture->destroyTexture();
m_bIsCreated = false;
m_szQueued = "";
return;
@ -193,7 +194,7 @@ void CHyprError::draw() {
m_bMonitorChanged = false;
g_pHyprOpenGL->renderTexture(m_tTexture, &monbox, m_fFadeOpacity.value(), 0);
g_pHyprOpenGL->renderTexture(m_pTexture, &monbox, m_fFadeOpacity.value(), 0);
}
void CHyprError::destroy() {

View File

@ -21,7 +21,7 @@ class CHyprError {
CColor m_cQueued;
bool m_bQueuedDestroy = false;
bool m_bIsCreated = false;
CTexture m_tTexture;
SP<CTexture> m_pTexture;
CAnimatedVariable<float> m_fFadeOpacity;
CBox m_bDamageBox = {0, 0, 0, 0};

View File

@ -82,10 +82,6 @@ extern "C" {
#if WLR_HAS_X11_BACKEND
#include <wlr/backend/x11.h>
#endif
#ifndef NO_XWAYLAND
#include <wlr/xwayland.h>
#endif
}
#undef delete
@ -110,7 +106,6 @@ extern "C" {
#ifdef NO_XWAYLAND
#define XWAYLAND false
#include "helpers/XWaylandStubs.hpp"
#else
#define XWAYLAND true
#endif

View File

@ -5,6 +5,8 @@
#include "../config/ConfigValue.hpp"
#include "../desktop/Window.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../xwayland/XSurface.hpp"
void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) {
@ -98,8 +100,8 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
}
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
const auto PWINDOWSURFACE = pWindow->m_pWLSurface.wlr();
pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height);
const auto PWINDOWSURFACE = pWindow->m_pWLSurface->resource();
pWindow->m_vRealSize = PWINDOWSURFACE->current.size;
if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 &&
pWindow->m_iX11Type == 2) { // XDG windows should be fine. TODO: check for weird atoms?
@ -111,10 +113,10 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
if (pWindow->m_vRealSize.goal().x <= 5 || pWindow->m_vRealSize.goal().y <= 5)
pWindow->m_vRealSize = PMONITOR->vecSize / 2.f;
if (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect) {
if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) {
if (pWindow->m_uSurface.xwayland->x != 0 && pWindow->m_uSurface.xwayland->y != 0)
pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords({pWindow->m_uSurface.xwayland->x, pWindow->m_uSurface.xwayland->y});
if (pWindow->m_pXWaylandSurface->geometry.x != 0 && pWindow->m_pXWaylandSurface->geometry.y != 0)
pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_pXWaylandSurface->geometry.pos());
else
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f,
PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f);
@ -146,7 +148,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
pWindow->m_vRealPosition = pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealPosition.goal() +
pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealSize.goal() / 2.F - desiredGeometry.size() / 2.F;
else
pWindow->m_vRealPosition = PMONITOR->vecPosition + desiredGeometry.size() / 2.F;
pWindow->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.F - desiredGeometry.size() / 2.F;
} else {
// if it is, we respect where it wants to put itself, but apply monitor offset if outside
// most of these are popups
@ -161,7 +163,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11)
pWindow->m_vRealSize = pWindow->m_vRealSize.goal() / PMONITOR->scale;
if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect)) {
if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2)) {
pWindow->m_vRealPosition.warp();
pWindow->m_vRealSize.warp();
}

View File

@ -89,4 +89,14 @@
}
#else
#define UNREACHABLE() std::unreachable();
#endif
#endif
#define GLCALL(__CALL__) \
{ \
__CALL__; \
auto err = glGetError(); \
if (err != GL_NO_ERROR) { \
Debug::log(ERR, "[GLES] Error in call at {}@{}: 0x{:x}", __LINE__, \
([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })(), err); \
} \
}

View File

@ -2,6 +2,7 @@
#include "Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "PointerManager.hpp"
#include "../xwayland/XWayland.hpp"
extern "C" {
#include <wlr/interfaces/wlr_buffer.h>
@ -57,6 +58,9 @@ CCursorManager::CCursorManager() {
CCursorManager::~CCursorManager() {
if (m_pWLRXCursorMgr)
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
if (m_pAnimationTimer)
wl_event_source_remove(m_pAnimationTimer);
}
void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) {
@ -113,8 +117,8 @@ wlr_buffer* CCursorManager::getCursorBuffer() {
return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr;
}
void CCursorManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) {
if (!surf || !surf->wlr())
void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot) {
if (!surf || !surf->resource())
g_pPointerManager->resetCursorImage();
else
g_pPointerManager->setCursorSurface(surf, hotspot);
@ -246,14 +250,14 @@ SCursorImageData CCursorManager::dataFor(const std::string& name) {
return IMAGES.images[0];
}
void CCursorManager::setXWaylandCursor(wlr_xwayland* xwayland) {
void CCursorManager::setXWaylandCursor() {
const auto CURSOR = dataFor("left_ptr");
if (CURSOR.surface) {
wlr_xwayland_set_cursor(xwayland, cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), CURSOR.size, CURSOR.size, CURSOR.hotspotX,
CURSOR.hotspotY);
g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size},
{CURSOR.hotspotX, CURSOR.hotspotY});
} else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) {
wlr_xwayland_set_cursor(xwayland, XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, XCURSOR->images[0]->width, XCURSOR->images[0]->height,
XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y);
g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {XCURSOR->images[0]->width, XCURSOR->images[0]->height},
{XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y});
} else
Debug::log(ERR, "CursorManager: no valid cursor for xwayland");
}
@ -266,9 +270,6 @@ void CCursorManager::updateTheme() {
highestScale = m->scale;
}
if (std::round(highestScale * m_iSize) == m_sCurrentStyleInfo.size)
return;
if (m_sCurrentStyleInfo.size && m_pHyprcursor->valid())
m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo);
@ -286,13 +287,52 @@ void CCursorManager::updateTheme() {
}
}
void CCursorManager::changeTheme(const std::string& name, const int size) {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(name.empty() ? "" : name.c_str(), hcLogger);
m_szTheme = name;
m_iSize = size;
bool CCursorManager::changeTheme(const std::string& name, const int size) {
auto options = Hyprcursor::SManagerOptions();
options.logFn = hcLogger;
options.allowDefaultFallback = false;
if (!m_pHyprcursor->valid())
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", m_szTheme);
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(name.empty() ? "" : name.c_str(), options);
if (m_pHyprcursor->valid()) {
m_szTheme = name;
m_iSize = size;
updateTheme();
return true;
}
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name);
if (m_pWLRXCursorMgr)
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
m_pWLRXCursorMgr = wlr_xcursor_manager_create(name.empty() ? "" : name.c_str(), size);
bool xSuccess = wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0) == 1;
// this basically checks if xcursor changed used theme to default but better
bool diffTheme = false;
wlr_xcursor_manager_theme* theme;
wl_list_for_each(theme, &m_pWLRXCursorMgr->scaled_themes, link) {
if (std::string{theme->theme->name} != name) {
diffTheme = true;
break;
}
}
if (xSuccess && !diffTheme) {
m_szTheme = name;
m_iSize = size;
updateTheme();
return true;
}
Debug::log(ERR, "X also failed loading theme \"{}\", falling back to previous theme.", name);
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.c_str(), hcLogger);
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
m_pWLRXCursorMgr = wlr_xcursor_manager_create(m_szTheme.c_str(), m_iSize);
wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0);
updateTheme();
return false;
}

View File

@ -8,7 +8,6 @@
struct wlr_buffer;
struct wlr_xcursor_manager;
struct wlr_xwayland;
class CWLSurface;
class CCursorManager {
@ -19,13 +18,13 @@ class CCursorManager {
wlr_buffer* getCursorBuffer();
void setCursorFromName(const std::string& name);
void setCursorSurface(CWLSurface* surf, const Vector2D& hotspot);
void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot);
void setXCursor(const std::string& name);
void changeTheme(const std::string& name, const int size);
bool changeTheme(const std::string& name, const int size);
void updateTheme();
SCursorImageData dataFor(const std::string& name); // for xwayland
void setXWaylandCursor(wlr_xwayland* xwayland);
void setXWaylandCursor();
void tickAnimatedCursor();

View File

@ -28,7 +28,7 @@ void CHookSystemManager::emit(std::vector<SCallbackFNPtr>* const callbacks, SCal
return;
std::vector<HANDLE> faultyHandles;
bool needsDeadCleanup = false;
volatile bool needsDeadCleanup = false;
for (auto& cb : *callbacks) {
@ -80,4 +80,4 @@ std::vector<SCallbackFNPtr>* CHookSystemManager::getVecForEvent(const std::strin
Debug::log(LOG, "[hookSystem] New hook event registered: {}", event);
return &m_mRegisteredHooks[event];
}
}

View File

@ -1,17 +1,17 @@
#include "KeybindManager.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "debug/Log.hpp"
#include "helpers/VarList.hpp"
#include "../config/ConfigValue.hpp"
#include "TokenManager.hpp"
#include "../protocols/ShortcutsInhibit.hpp"
#include "../devices/IKeyboard.hpp"
#include "../managers/SeatManager.hpp"
#include "../protocols/ShortcutsInhibit.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "KeybindManager.hpp"
#include "TokenManager.hpp"
#include "debug/Log.hpp"
#include "helpers/VarList.hpp"
#include <optional>
#include <regex>
#include <iterator>
#include <string>
#include <tuple>
#include <string_view>
#include <sys/ioctl.h>
#include <fcntl.h>
@ -87,8 +87,10 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["cyclenext"] = circleNext;
m_mDispatchers["focuswindowbyclass"] = focusWindow;
m_mDispatchers["focuswindow"] = focusWindow;
m_mDispatchers["tagwindow"] = tagWindow;
m_mDispatchers["submap"] = setSubmap;
m_mDispatchers["pass"] = pass;
m_mDispatchers["sendshortcut"] = sendshortcut;
m_mDispatchers["layoutmsg"] = layoutmsg;
m_mDispatchers["toggleopaque"] = toggleOpaque;
m_mDispatchers["dpms"] = dpms;
@ -255,6 +257,16 @@ bool CKeybindManager::ensureMouseBindState() {
return false;
}
void updateRelativeCursorCoords() {
static auto PNOWARPS = CConfigValue<Hyprlang::INT>("cursor:no_warps");
if (*PNOWARPS)
return;
if (g_pCompositor->m_pLastWindow)
g_pCompositor->m_pLastWindow->m_vRelativeCursorCoordsOnLastWarp = g_pInputManager->getMouseCoordsInternal() - g_pCompositor->m_pLastWindow->m_vPosition;
}
bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
if (!monitor)
return false;
@ -275,8 +287,9 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
const auto PNEWWINDOW = PNEWWORKSPACE->getLastFocusedWindow();
if (PNEWWINDOW) {
updateRelativeCursorCoords();
g_pCompositor->focusWindow(PNEWWINDOW);
g_pCompositor->warpCursorTo(PNEWWINDOW->middle());
PNEWWINDOW->warpCursor();
g_pInputManager->m_pForcedFocus = PNEWWINDOW;
g_pInputManager->simulateMouseMovement();
@ -311,8 +324,9 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
if (!PWINDOWTOCHANGETO->m_bPinned)
g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE);
} else {
updateRelativeCursorCoords();
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->middle());
PWINDOWTOCHANGETO->warpCursor();
g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO;
g_pInputManager->simulateMouseMovement();
@ -589,7 +603,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
}
for (auto& k : m_lKeybinds) {
const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "mouse";
const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse";
const bool SPECIALTRIGGERED =
std::find_if(m_vPressedSpecialBinds.begin(), m_vPressedSpecialBinds.end(), [&](const auto& other) { return other == &k; }) != m_vPressedSpecialBinds.end();
const bool IGNORECONDITIONS =
@ -1071,6 +1085,14 @@ void CKeybindManager::changeworkspace(std::string args) {
g_pCompositor->setActiveMonitor(PMONITORWORKSPACEOWNER);
if (BISWORKSPACECURRENT) {
if (*PALLOWWORKSPACECYCLES)
pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE);
else if (!EXPLICITPREVIOUS && !*PBACKANDFORTH)
pWorkspaceToChangeTo->rememberPrevWorkspace(nullptr);
} else
pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE);
PMONITORWORKSPACEOWNER->changeWorkspace(pWorkspaceToChangeTo, false, true);
if (PMONITOR != PMONITORWORKSPACEOWNER) {
@ -1083,14 +1105,6 @@ void CKeybindManager::changeworkspace(std::string args) {
g_pCompositor->warpCursorTo(middle);
}
if (BISWORKSPACECURRENT) {
if (*PALLOWWORKSPACECYCLES)
pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE);
else if (!EXPLICITPREVIOUS && !*PBACKANDFORTH)
pWorkspaceToChangeTo->rememberPrevWorkspace(nullptr);
} else
pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE);
if (!g_pInputManager->m_bLastFocusOnLS) {
if (g_pCompositor->m_pLastFocus)
g_pInputManager->sendMotionEventsToFocused();
@ -1144,6 +1158,8 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
const auto POLDWS = PWINDOW->m_pWorkspace;
static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
updateRelativeCursorCoords();
g_pHyprRenderer->damageWindow(PWINDOW);
if (pWorkspace) {
@ -1163,13 +1179,13 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
else if (POLDWS->m_bIsSpecialWorkspace)
g_pCompositor->getMonitorFromID(POLDWS->m_iMonitorID)->setSpecialWorkspace(nullptr);
if (*PALLOWWORKSPACECYCLES)
pWorkspace->rememberPrevWorkspace(POLDWS);
pMonitor->changeWorkspace(pWorkspace);
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->warpCursorTo(PWINDOW->middle());
if (*PALLOWWORKSPACECYCLES)
pWorkspace->rememberPrevWorkspace(POLDWS);
PWINDOW->warpCursor();
}
void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
@ -1301,8 +1317,9 @@ void CKeybindManager::swapActive(std::string args) {
if (!PWINDOWTOCHANGETO)
return;
updateRelativeCursorCoords();
g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, PWINDOWTOCHANGETO);
g_pCompositor->warpCursorTo(PLASTWINDOW->middle());
PLASTWINDOW->warpCursor();
}
void CKeybindManager::moveActiveTo(std::string args) {
@ -1355,9 +1372,11 @@ void CKeybindManager::moveActiveTo(std::string args) {
// If the window to change to is on the same workspace, switch them
const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
if (PWINDOWTOCHANGETO) {
updateRelativeCursorCoords();
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PLASTWINDOW, args, silent);
if (!silent)
g_pCompositor->warpCursorTo(PLASTWINDOW->middle());
PLASTWINDOW->warpCursor();
return;
}
@ -1894,6 +1913,8 @@ void CKeybindManager::focusWindow(std::string regexp) {
return;
}
updateRelativeCursorCoords();
if (g_pCompositor->m_pLastMonitor && g_pCompositor->m_pLastMonitor->activeWorkspace != PWINDOW->m_pWorkspace &&
g_pCompositor->m_pLastMonitor->activeSpecialWorkspace != PWINDOW->m_pWorkspace) {
Debug::log(LOG, "Fake executing workspace to move focus");
@ -1924,7 +1945,24 @@ void CKeybindManager::focusWindow(std::string regexp) {
} else
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->warpCursorTo(PWINDOW->middle());
PWINDOW->warpCursor();
}
void CKeybindManager::tagWindow(std::string args) {
PHLWINDOW PWINDOW = nullptr;
CVarList vars{args, 0, 's', true};
if (vars.size() == 1)
PWINDOW = g_pCompositor->m_pLastWindow.lock();
else if (vars.size() == 2)
PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
else
return;
if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) {
PWINDOW->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW->m_pSelf.lock());
}
}
void CKeybindManager::setSubmap(std::string submap) {
@ -1965,14 +2003,14 @@ void CKeybindManager::pass(std::string regexp) {
}
const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11;
const auto LASTSRF = g_pCompositor->m_pLastFocus;
const auto LASTSRF = g_pCompositor->m_pLastFocus.lock();
// pass all mf shit
if (!XWTOXW) {
if (g_pKeybindManager->m_uLastCode != 0)
g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface.wlr());
g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface->resource());
else
g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), {1, 1});
g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), {1, 1});
}
g_pSeatManager->sendKeyboardMods(g_pInputManager->accumulateModsFromAllKBs(), 0, 0, 0);
@ -2006,10 +2044,10 @@ void CKeybindManager::pass(std::string regexp) {
// please kill me
if (PWINDOW->m_bIsX11) {
if (g_pKeybindManager->m_uLastCode != 0) {
g_pSeatManager->state.keyboardFocus = nullptr;
g_pSeatManager->state.keyboardFocus.reset();
g_pSeatManager->state.keyboardFocusResource.reset();
} else {
g_pSeatManager->state.pointerFocus = nullptr;
g_pSeatManager->state.pointerFocus.reset();
g_pSeatManager->state.pointerFocusResource.reset();
}
}
@ -2019,7 +2057,158 @@ void CKeybindManager::pass(std::string regexp) {
if (g_pKeybindManager->m_uLastCode != 0)
g_pSeatManager->setKeyboardFocus(LASTSRF);
else
g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), SL);
g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), SL);
}
void CKeybindManager::sendshortcut(std::string args) {
// args=<NEW_MODKEYS><NEW_KEY>[,WINDOW_RULES]
const auto ARGS = CVarList(args, 3);
if (ARGS.size() != 3) {
Debug::log(ERR, "sendshortcut: invalid args");
return;
}
const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
const auto KEY = ARGS[1];
uint32_t keycode = 0;
bool isMouse = 0;
// similar to parseKey in ConfigManager
if (isNumber(KEY) && std::stoi(KEY) > 9)
keycode = std::stoi(KEY);
else if (KEY.compare(0, 5, "code:") == 0 && isNumber(KEY.substr(5)))
keycode = std::stoi(KEY.substr(5));
else if (KEY.compare(0, 6, "mouse:") == 0 && isNumber(KEY.substr(6))) {
keycode = std::stoi(KEY.substr(6));
isMouse = 1;
if (keycode < 272) {
Debug::log(ERR, "sendshortcut: invalid mouse button");
return;
}
} else {
// here, we need to find the keycode from the key name
// this is not possible through xkb's lib, so we need to iterate through all keycodes
// once found, we save it to the cache
const auto KEYSYM = xkb_keysym_from_name(KEY.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
keycode = 0;
const auto KB = g_pSeatManager->keyboard;
if (!KB) {
Debug::log(ERR, "sendshortcut: no kb");
return;
}
const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY);
if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) {
xkb_keymap* km = KB->wlr()->keymap;
xkb_state* ks = KB->xkbTranslationState;
xkb_keycode_t keycode_min, keycode_max;
keycode_min = xkb_keymap_min_keycode(km);
keycode_max = xkb_keymap_max_keycode(km);
for (xkb_keycode_t kc = keycode_min; kc <= keycode_max; ++kc) {
xkb_keysym_t sym = xkb_state_key_get_one_sym(ks, kc);
if (sym == KEYSYM) {
keycode = kc;
g_pKeybindManager->m_mKeyToCodeCache[KEYPAIRSTRING] = keycode;
}
}
if (!keycode) {
Debug::log(ERR, "sendshortcut: key not found");
return;
}
} else
keycode = g_pKeybindManager->m_mKeyToCodeCache[KEYPAIRSTRING];
}
if (!keycode) {
Debug::log(ERR, "sendshortcut: invalid key");
return;
}
const std::string regexp = ARGS[2];
PHLWINDOW PWINDOW = nullptr;
const auto LASTSURFACE = g_pCompositor->m_pLastFocus.lock();
//if regexp is not empty, send shortcut to current window
//else, dont change focus
if (regexp != "") {
PWINDOW = g_pCompositor->getWindowByRegex(regexp);
if (!PWINDOW) {
Debug::log(ERR, "sendshortcut: window not found");
return;
}
if (!g_pSeatManager->keyboard) {
Debug::log(ERR, "No kb in sendshortcut?");
return;
}
if (!isMouse)
g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface->resource());
else
g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), {1, 1});
}
//copied the rest from pass and modified it
// if wl -> xwl, activate destination
if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsX11)
g_pXWaylandManager->activateSurface(PWINDOW->m_pWLSurface->resource(), true);
// if xwl -> xwl, send to current. Timing issues make this not work.
if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11)
PWINDOW = nullptr;
g_pSeatManager->sendKeyboardMods(MOD, 0, 0, 0);
if (g_pKeybindManager->m_iPassPressed == 1) {
if (!isMouse)
g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_PRESSED);
else
g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_PRESSED);
} else if (g_pKeybindManager->m_iPassPressed == 0) {
if (!isMouse)
g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_RELEASED);
else
g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_RELEASED);
} else {
// dynamic call of the dispatcher
if (!isMouse) {
g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_PRESSED);
g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_RELEASED);
} else {
g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_PRESSED);
g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_RELEASED);
}
}
if (!PWINDOW)
return;
if (PWINDOW->m_bIsX11) { //xwayland hack, see pass
if (!isMouse) {
g_pSeatManager->state.keyboardFocus.reset();
g_pSeatManager->state.keyboardFocusResource.reset();
} else {
g_pSeatManager->state.pointerFocus.reset();
g_pSeatManager->state.pointerFocusResource.reset();
}
}
const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal();
if (!isMouse)
g_pSeatManager->setKeyboardFocus(LASTSURFACE);
else
g_pSeatManager->setPointerFocus(LASTSURFACE, SL);
}
void CKeybindManager::layoutmsg(std::string msg) {
@ -2275,6 +2464,8 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn
if (pWindow->m_sGroupData.deny)
return;
updateRelativeCursorCoords();
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property!
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
@ -2285,7 +2476,7 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn
pWindow->updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow);
g_pCompositor->focusWindow(pWindow);
g_pCompositor->warpCursorTo(pWindow->middle());
pWindow->warpCursor();
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
@ -2308,6 +2499,8 @@ void CKeybindManager::moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string&
default: direction = DIRECTION_DEFAULT;
}
updateRelativeCursorCoords();
if (pWindow->m_sGroupData.pNextWindow.lock() == pWindow) {
pWindow->destroyGroup();
} else {
@ -2323,10 +2516,10 @@ void CKeybindManager::moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string&
if (*BFOCUSREMOVEDWINDOW) {
g_pCompositor->focusWindow(pWindow);
g_pCompositor->warpCursorTo(pWindow->middle());
pWindow->warpCursor();
} else {
g_pCompositor->focusWindow(PWINDOWPREV);
g_pCompositor->warpCursorTo(PWINDOWPREV->middle());
PWINDOWPREV->warpCursor();
}
g_pEventManager->postEvent(SHyprIPCEvent{"moveoutofgroup", std::format("{:x}", (uintptr_t)pWindow.get())});
@ -2406,24 +2599,26 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
const bool ISWINDOWGROUPLOCKED = ISWINDOWGROUP && PWINDOW->getGroupHead()->m_sGroupData.locked;
const bool ISWINDOWGROUPSINGLE = ISWINDOWGROUP && PWINDOW->m_sGroupData.pNextWindow.lock() == PWINDOW;
updateRelativeCursorCoords();
// note: PWINDOWINDIR is not null implies !PWINDOW->m_bIsFloating
if (PWINDOWINDIR && PWINDOWINDIR->m_sGroupData.pNextWindow) { // target is group
if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || ISWINDOWGROUPLOCKED || PWINDOW->m_sGroupData.deny)) {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
g_pCompositor->warpCursorTo(PWINDOW->middle());
PWINDOW->warpCursor();
} else
moveWindowIntoGroup(PWINDOW, PWINDOWINDIR);
} else if (PWINDOWINDIR) { // target is regular window
if ((!*PIGNOREGROUPLOCK && ISWINDOWGROUPLOCKED) || !ISWINDOWGROUP || (ISWINDOWGROUPSINGLE && PWINDOW->m_eGroupRules & GROUP_SET_ALWAYS)) {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
g_pCompositor->warpCursorTo(PWINDOW->middle());
PWINDOW->warpCursor();
} else
moveWindowOutOfGroup(PWINDOW, args);
} else if ((*PIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED) && ISWINDOWGROUP) { // no target window
moveWindowOutOfGroup(PWINDOW, args);
} else if (!PWINDOWINDIR && !ISWINDOWGROUP) { // no target in dir and not in group
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
g_pCompositor->warpCursorTo(PWINDOW->middle());
PWINDOW->warpCursor();
}
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);

View File

@ -95,6 +95,12 @@ class CKeybindManager {
std::list<SKeybind> m_lKeybinds;
//since we cant find keycode through keyname in xkb:
//on sendshortcut call, we once search for keyname (e.g. "g") the correct keycode (e.g. 42)
//and cache it in this map to make sendshortcut calls faster
//we also store the keyboard pointer (in the string) to differentiate between different keyboard (layouts)
std::unordered_map<std::string, xkb_keycode_t> m_mKeyToCodeCache;
private:
std::deque<SPressedKeyWithMods> m_dPressedKeys;
@ -175,8 +181,10 @@ class CKeybindManager {
static void resizeWindow(std::string);
static void circleNext(std::string);
static void focusWindow(std::string);
static void tagWindow(std::string);
static void setSubmap(std::string);
static void pass(std::string);
static void sendshortcut(std::string);
static void layoutmsg(std::string);
static void toggleOpaque(std::string);
static void dpms(std::string);

View File

@ -3,6 +3,7 @@
#include "../config/ConfigValue.hpp"
#include "../protocols/PointerGestures.hpp"
#include "../protocols/FractionalScale.hpp"
#include "../protocols/core/Compositor.hpp"
#include "SeatManager.hpp"
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/interface.h>
@ -119,7 +120,17 @@ static bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_
}
}
return output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888);
// Note: taken from https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4596/diffs#diff-content-e3ea164da86650995728d70bd118f6aa8c386797
// If this fails to find a shared modifier try to use a linear
// modifier. This avoids a scenario where the hardware cannot render to
// linear textures but only linear textures are supported for cursors,
// as is the case with Nvidia and VmWare GPUs
if (!output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888)) {
// Clear the format as output_pick_format doesn't zero it
memset(format, 0, sizeof(*format));
return output_pick_format(output, NULL, format, DRM_FORMAT_ARGB8888);
}
return true;
}
CPointerManager::CPointerManager() {
@ -131,7 +142,11 @@ CPointerManager::CPointerManager() {
PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr);
PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr);
PMONITOR->events.destroy.registerStaticListener(
[this](void* owner, std::any data) { std::erase_if(monitorStates, [](const auto& other) { return other->monitor.expired(); }); }, nullptr);
[this](void* owner, std::any data) {
if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown)
std::erase_if(monitorStates, [](const auto& other) { return other->monitor.expired(); });
},
nullptr);
});
}
@ -198,13 +213,13 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot,
damageIfSoftware();
}
void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) {
void CPointerManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot) {
damageIfSoftware();
if (surf == currentCursorImage.surface) {
if (hotspot != currentCursorImage.hotspot || (surf && surf->wlr() ? surf->wlr()->current.scale : 1.F) != currentCursorImage.scale) {
if (hotspot != currentCursorImage.hotspot || (surf && surf->resource() ? surf->resource()->current.scale : 1.F) != currentCursorImage.scale) {
currentCursorImage.hotspot = hotspot;
currentCursorImage.scale = surf && surf->wlr() ? surf->wlr()->current.scale : 1.F;
currentCursorImage.scale = surf && surf->resource() ? surf->resource()->current.scale : 1.F;
updateCursorBackend();
damageIfSoftware();
}
@ -215,27 +230,24 @@ void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot
resetCursorImage(false);
if (surf) {
currentCursorImage.size = {surf->wlr()->current.buffer_width, surf->wlr()->current.buffer_height};
currentCursorImage.surface = surf;
currentCursorImage.scale = surf->wlr()->current.scale;
currentCursorImage.scale = surf->resource()->current.scale;
currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); });
currentCursorImage.hyprListener_commitSurface.initCallback(
&surf->wlr()->events.commit,
[this](void* owner, void* data) {
damageIfSoftware();
currentCursorImage.size = {currentCursorImage.surface->wlr()->current.buffer_width, currentCursorImage.surface->wlr()->current.buffer_height};
currentCursorImage.scale = currentCursorImage.surface && currentCursorImage.surface->wlr() ? currentCursorImage.surface->wlr()->current.scale : 1.F;
recheckEnteredOutputs();
updateCursorBackend();
damageIfSoftware();
},
nullptr, "CPointerManager");
currentCursorImage.commitSurface = surf->resource()->events.commit.registerListener([this](std::any data) {
damageIfSoftware();
currentCursorImage.size = currentCursorImage.surface->resource()->current.buffer ? currentCursorImage.surface->resource()->current.buffer->size : Vector2D{};
currentCursorImage.scale = currentCursorImage.surface ? currentCursorImage.surface->resource()->current.scale : 1.F;
recheckEnteredOutputs();
updateCursorBackend();
damageIfSoftware();
});
if (wlr_surface_has_buffer(surf->wlr())) {
if (surf->resource()->current.buffer) {
currentCursorImage.size = surf->resource()->current.buffer->size;
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_surface_send_frame_done(surf->wlr(), &now);
surf->resource()->frame(&now);
}
}
@ -264,9 +276,9 @@ void CPointerManager::recheckEnteredOutputs() {
if (!currentCursorImage.surface)
continue;
wlr_surface_send_enter(currentCursorImage.surface->wlr(), s->monitor->output);
PROTO::fractional->sendScale(currentCursorImage.surface->wlr(), s->monitor->scale);
g_pCompositor->setPreferredScaleForSurface(currentCursorImage.surface->wlr(), s->monitor->scale);
currentCursorImage.surface->resource()->enter(s->monitor.lock());
PROTO::fractional->sendScale(currentCursorImage.surface->resource(), s->monitor->scale);
g_pCompositor->setPreferredScaleForSurface(currentCursorImage.surface->resource(), s->monitor->scale);
} else if (s->entered && !overlaps) {
s->entered = false;
@ -279,7 +291,7 @@ void CPointerManager::recheckEnteredOutputs() {
if (!currentCursorImage.surface)
continue;
wlr_surface_send_leave(currentCursorImage.surface->wlr(), s->monitor->output);
currentCursorImage.surface->resource()->leave(s->monitor.lock());
}
}
}
@ -289,12 +301,12 @@ void CPointerManager::resetCursorImage(bool apply) {
if (currentCursorImage.surface) {
for (auto& m : g_pCompositor->m_vMonitors) {
wlr_surface_send_leave(currentCursorImage.surface->wlr(), m->output);
currentCursorImage.surface->resource()->leave(m);
}
currentCursorImage.destroySurface.reset();
currentCursorImage.hyprListener_commitSurface.removeCallback();
currentCursorImage.surface = nullptr;
currentCursorImage.commitSurface.reset();
currentCursorImage.surface.reset();
} else if (currentCursorImage.pBuffer) {
wlr_buffer_unlock(currentCursorImage.pBuffer);
currentCursorImage.hyprListener_destroyBuffer.removeCallback();
@ -437,7 +449,7 @@ bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buff
return true;
}
wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, wlr_texture* texture) {
wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
auto output = state->monitor->output;
int w = currentCursorImage.size.x, h = currentCursorImage.size.y;
@ -514,7 +526,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec*
if ((!state->hardwareFailed && state->softwareLocks == 0)) {
if (currentCursorImage.surface)
wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now);
currentCursorImage.surface->resource()->frame(now);
return;
}
@ -536,7 +548,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec*
g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F);
if (currentCursorImage.surface)
wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now);
currentCursorImage.surface->resource()->frame(now);
}
Vector2D CPointerManager::getCursorPosForMonitor(SP<CMonitor> pMonitor) {
@ -550,7 +562,7 @@ Vector2D CPointerManager::transformedHotspot(SP<CMonitor> pMonitor) {
if (!pMonitor->output->cursor_swapchain)
return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors
return CBox{currentCursorImage.hotspot, {0, 0}}
return CBox{currentCursorImage.hotspot * pMonitor->scale, {0, 0}}
.transform(wlr_output_transform_invert(pMonitor->transform), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height)
.pos();
}
@ -560,7 +572,7 @@ CBox CPointerManager::getCursorBoxLogicalForMonitor(SP<CMonitor> pMonitor) {
}
CBox CPointerManager::getCursorBoxGlobal() {
return CBox{pointerPos, currentCursorImage.size / currentCursorImage.scale}.translate(-currentCursorImage.hotspot / currentCursorImage.scale);
return CBox{pointerPos, currentCursorImage.size / currentCursorImage.scale}.translate(-currentCursorImage.hotspot);
}
Vector2D CPointerManager::closestValid(const Vector2D& pos) {
@ -696,8 +708,11 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) {
}
}
if (!TAB->boundBox.empty())
mappedArea = TAB->boundBox.translate(currentMonitor->vecPosition);
mappedArea.translate(TAB->boundBox.pos());
if (!TAB->boundBox.empty()) {
mappedArea.w = TAB->boundBox.w;
mappedArea.h = TAB->boundBox.h;
}
break;
}
case HID_TYPE_TOUCH: {
@ -745,17 +760,19 @@ void CPointerManager::onMonitorLayoutChange() {
damageIfSoftware();
}
wlr_texture* CPointerManager::getCurrentCursorTexture() {
if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !wlr_surface_get_texture(currentCursorImage.surface->wlr())))
SP<CTexture> CPointerManager::getCurrentCursorTexture() {
if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !currentCursorImage.surface->resource()->current.buffer))
return nullptr;
if (currentCursorImage.pBuffer) {
if (!currentCursorImage.pBufferTexture)
if (!currentCursorImage.pBufferTexture) {
currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer);
return currentCursorImage.pBufferTexture;
currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBufferTexture);
}
return currentCursorImage.bufferTex;
}
return wlr_surface_get_texture(currentCursorImage.surface->wlr());
return currentCursorImage.surface->resource()->current.buffer->texture;
}
void CPointerManager::attachPointer(SP<IPointer> pointer) {

View File

@ -11,6 +11,7 @@
class CMonitor;
struct wlr_input_device;
class IHID;
class CTexture;
/*
The naming here is a bit confusing.
@ -37,7 +38,7 @@ class CPointerManager {
void warpAbsolute(Vector2D abs, SP<IHID> dev);
void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale);
void setCursorSurface(CWLSurface* buf, const Vector2D& hotspot);
void setCursorSurface(SP<CWLSurface> buf, const Vector2D& hotspot);
void resetCursorImage(bool apply = true);
void lockSoftwareForMonitor(SP<CMonitor> pMonitor);
@ -76,7 +77,7 @@ class CPointerManager {
Vector2D transformedHotspot(SP<CMonitor> pMonitor);
wlr_texture* getCurrentCursorTexture();
SP<CTexture> getCurrentCursorTexture();
struct SPointerListener {
CHyprSignalListener destroy;
@ -129,8 +130,9 @@ class CPointerManager {
} currentMonitorLayout;
struct {
wlr_buffer* pBuffer = nullptr;
CWLSurface* surface = nullptr;
wlr_buffer* pBuffer = nullptr;
SP<CTexture> bufferTex;
WP<CWLSurface> surface;
wlr_texture* pBufferTexture = nullptr;
Vector2D hotspot;
@ -138,7 +140,7 @@ class CPointerManager {
float scale = 1.F;
CHyprSignalListener destroySurface;
DYNLISTENER(commitSurface);
CHyprSignalListener commitSurface;
DYNLISTENER(destroyBuffer);
} currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors
@ -146,6 +148,11 @@ class CPointerManager {
struct SMonitorPointerState {
SMonitorPointerState(SP<CMonitor> m) : monitor(m) {}
~SMonitorPointerState() {
if (cursorFrontBuffer)
wlr_buffer_unlock(cursorFrontBuffer);
}
WP<CMonitor> monitor;
int softwareLocks = 0;
@ -160,7 +167,7 @@ class CPointerManager {
std::vector<SP<SMonitorPointerState>> monitorStates;
SP<SMonitorPointerState> stateFor(SP<CMonitor> mon);
bool attemptHardwareCursor(SP<SMonitorPointerState> state);
wlr_buffer* renderHWCursorBuffer(SP<SMonitorPointerState> state, wlr_texture* texture);
wlr_buffer* renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture);
bool setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf);
struct {

View File

@ -31,17 +31,73 @@
#include "../protocols/XDGShell.hpp"
#include "../protocols/DataDeviceWlr.hpp"
#include "../protocols/PrimarySelection.hpp"
#include "../protocols/XWaylandShell.hpp"
#include "../protocols/Viewporter.hpp"
#include "../protocols/MesaDRM.hpp"
#include "../protocols/LinuxDMABUF.hpp"
#include "../protocols/core/Seat.hpp"
#include "../protocols/core/DataDevice.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../protocols/core/Subcompositor.hpp"
#include "../protocols/core/Output.hpp"
#include "../protocols/core/Shm.hpp"
#include "../helpers/Monitor.hpp"
#include "../render/Renderer.hpp"
void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) {
const bool ISMIRROR = pMonitor->isMirror();
// onModeChanged we check if the current mirror status matches the global.
// mirrored outputs should have their global removed, as they are not physical parts of the
// layout.
if (ISMIRROR && PROTO::outputs.contains(pMonitor->szName))
PROTO::outputs.at(pMonitor->szName)->remove();
else if (!ISMIRROR && (!PROTO::outputs.contains(pMonitor->szName) || PROTO::outputs.at(pMonitor->szName)->isDefunct())) {
if (PROTO::outputs.contains(pMonitor->szName))
PROTO::outputs.erase(pMonitor->szName);
PROTO::outputs.emplace(pMonitor->szName,
std::make_unique<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock()));
}
}
CProtocolManager::CProtocolManager() {
// Outputs are a bit dumb, we have to agree.
static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) {
auto M = std::any_cast<CMonitor*>(param);
// ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after
// this event is emitted iirc.
if (M->isMirror())
return;
if (PROTO::outputs.contains(M->szName))
PROTO::outputs.erase(M->szName);
PROTO::outputs.emplace(M->szName, std::make_unique<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock()));
m_mModeChangeListeners[M->szName] = M->events.modeChanged.registerListener([M, this](std::any d) { onMonitorModeChange(M); });
});
static auto P2 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) {
auto M = std::any_cast<CMonitor*>(param);
if (!PROTO::outputs.contains(M->szName))
return;
PROTO::outputs.at(M->szName)->remove();
m_mModeChangeListeners.erase(M->szName);
});
// Core
PROTO::seat = std::make_unique<CWLSeatProtocol>(&wl_seat_interface, 9, "WLSeat");
PROTO::data = std::make_unique<CWLDataDeviceProtocol>(&wl_data_device_manager_interface, 3, "WLDataDevice");
PROTO::seat = std::make_unique<CWLSeatProtocol>(&wl_seat_interface, 9, "WLSeat");
PROTO::data = std::make_unique<CWLDataDeviceProtocol>(&wl_data_device_manager_interface, 3, "WLDataDevice");
PROTO::compositor = std::make_unique<CWLCompositorProtocol>(&wl_compositor_interface, 6, "WLCompositor");
PROTO::subcompositor = std::make_unique<CWLSubcompositorProtocol>(&wl_subcompositor_interface, 1, "WLSubcompositor");
PROTO::shm = std::make_unique<CWLSHMProtocol>(&wl_shm_interface, 1, "WLSHM");
// Extensions
PROTO::viewport = std::make_unique<CViewporterProtocol>(&wp_viewporter_interface, 1, "Viewporter");
PROTO::tearing = std::make_unique<CTearingControlProtocol>(&wp_tearing_control_manager_v1_interface, 1, "TearingControl");
PROTO::fractional = std::make_unique<CFractionalScaleProtocol>(&wp_fractional_scale_manager_v1_interface, 1, "FractionalScale");
PROTO::xdgOutput = std::make_unique<CXDGOutputProtocol>(&zxdg_output_manager_v1_interface, 3, "XDGOutput");
@ -73,6 +129,13 @@ CProtocolManager::CProtocolManager() {
PROTO::xdgShell = std::make_unique<CXDGShellProtocol>(&xdg_wm_base_interface, 6, "XDGShell");
PROTO::dataWlr = std::make_unique<CDataDeviceWLRProtocol>(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr");
PROTO::primarySelection = std::make_unique<CPrimarySelectionProtocol>(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection");
PROTO::xwaylandShell = std::make_unique<CXWaylandShellProtocol>(&xwayland_shell_v1_interface, 1, "XWaylandShell");
if (g_pHyprOpenGL->getDRMFormats().size() > 0) {
PROTO::mesaDRM = std::make_unique<CMesaDRMProtocol>(&wl_drm_interface, 2, "MesaDRM");
PROTO::linuxDma = std::make_unique<CLinuxDMABufV1Protocol>(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF");
} else
Debug::log(WARN, "ProtocolManager: Not binding linux-dmabuf and MesaDRM: DMABUF not available");
// Old protocol implementations.
// TODO: rewrite them to use hyprwayland-scanner.

View File

@ -5,6 +5,9 @@
#include "../protocols/TextInputV1.hpp"
#include "../protocols/GlobalShortcuts.hpp"
#include "../protocols/Screencopy.hpp"
#include "../helpers/memory/WeakPtr.hpp"
#include "../helpers/signal/Listener.hpp"
#include <unordered_map>
class CProtocolManager {
public:
@ -15,6 +18,11 @@ class CProtocolManager {
std::unique_ptr<CTextInputV1ProtocolManager> m_pTextInputV1ProtocolManager;
std::unique_ptr<CGlobalShortcutsProtocolManager> m_pGlobalShortcutsProtocolManager;
std::unique_ptr<CScreencopyProtocolManager> m_pScreencopyProtocolManager;
private:
std::unordered_map<std::string, CHyprSignalListener> m_mModeChangeListeners;
void onMonitorModeChange(CMonitor* pMonitor);
};
inline std::unique_ptr<CProtocolManager> g_pProtocolManager;

View File

@ -3,6 +3,7 @@
#include "../protocols/core/DataDevice.hpp"
#include "../protocols/DataDeviceWlr.hpp"
#include "../protocols/PrimarySelection.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../Compositor.hpp"
#include "../devices/IKeyboard.hpp"
#include <algorithm>
@ -98,7 +99,7 @@ void CSeatManager::updateActiveKeyboardData() {
PROTO::seat->updateKeymap();
}
void CSeatManager::setKeyboardFocus(wlr_surface* surf) {
void CSeatManager::setKeyboardFocus(SP<CWLSurfaceResource> surf) {
if (state.keyboardFocus == surf)
return;
@ -107,15 +108,9 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) {
return;
}
hyprListener_keyboardSurfaceDestroy.removeCallback();
listeners.keyboardSurfaceDestroy.reset();
if (state.keyboardFocusResource) {
// we will iterate over all bound wl_seat
// resources here, because some idiotic apps (e.g. those based on smithay)
// tend to bind wl_seat twice.
// I can't be arsed to actually pass all events to all seat resources, so we will
// only pass enter and leave.
// If you have an issue with that, fix your app.
auto client = state.keyboardFocusResource->client();
for (auto& s : seatResources) {
if (s->resource->client() != client)
@ -138,7 +133,7 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) {
return;
}
auto client = wl_resource_get_client(surf->resource);
auto client = surf->client();
for (auto& r : seatResources | std::views::reverse) {
if (r->resource->client() != client)
continue;
@ -153,8 +148,7 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) {
}
}
hyprListener_keyboardSurfaceDestroy.initCallback(
&surf->events.destroy, [this](void* owner, void* data) { setKeyboardFocus(nullptr); }, nullptr, "CSeatManager");
listeners.keyboardSurfaceDestroy = surf->events.destroy.registerListener([this](std::any d) { setKeyboardFocus(nullptr); });
events.keyboardFocusChange.emit();
}
@ -163,11 +157,16 @@ void CSeatManager::sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_ke
if (!state.keyboardFocusResource)
return;
for (auto& k : state.keyboardFocusResource->keyboards) {
if (!k)
for (auto& s : seatResources) {
if (s->resource->client() != state.keyboardFocusResource->client())
continue;
k->sendKey(timeMs, key, state_);
for (auto& k : s->resource->keyboards) {
if (!k)
continue;
k->sendKey(timeMs, key, state_);
}
}
}
@ -175,15 +174,20 @@ void CSeatManager::sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32
if (!state.keyboardFocusResource)
return;
for (auto& k : state.keyboardFocusResource->keyboards) {
if (!k)
for (auto& s : seatResources) {
if (s->resource->client() != state.keyboardFocusResource->client())
continue;
k->sendMods(depressed, latched, locked, group);
for (auto& k : s->resource->keyboards) {
if (!k)
continue;
k->sendMods(depressed, latched, locked, group);
}
}
}
void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) {
void CSeatManager::setPointerFocus(SP<CWLSurfaceResource> surf, const Vector2D& local) {
if (state.pointerFocus == surf)
return;
@ -192,7 +196,7 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) {
return;
}
hyprListener_pointerSurfaceDestroy.removeCallback();
listeners.pointerSurfaceDestroy.reset();
if (state.pointerFocusResource) {
auto client = state.pointerFocusResource->client();
@ -220,7 +224,7 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) {
return;
}
auto client = wl_resource_get_client(surf->resource);
auto client = surf->client();
for (auto& r : seatResources | std::views::reverse) {
if (r->resource->client() != client)
continue;
@ -239,8 +243,7 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) {
sendPointerFrame();
hyprListener_pointerSurfaceDestroy.initCallback(
&surf->events.destroy, [this](void* owner, void* data) { setPointerFocus(nullptr, {}); }, nullptr, "CSeatManager");
listeners.pointerSurfaceDestroy = surf->events.destroy.registerListener([this](std::any d) { setPointerFocus(nullptr, {}); });
events.pointerFocusChange.emit();
}
@ -249,11 +252,16 @@ void CSeatManager::sendPointerMotion(uint32_t timeMs, const Vector2D& local) {
if (!state.pointerFocusResource)
return;
for (auto& p : state.pointerFocusResource->pointers) {
if (!p)
for (auto& s : seatResources) {
if (s->resource->client() != state.pointerFocusResource->client())
continue;
p->sendMotion(timeMs, local);
for (auto& p : s->resource->pointers) {
if (!p)
continue;
p->sendMotion(timeMs, local);
}
}
lastLocalCoords = local;
@ -263,11 +271,16 @@ void CSeatManager::sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_b
if (!state.pointerFocusResource)
return;
for (auto& p : state.pointerFocusResource->pointers) {
if (!p)
for (auto& s : seatResources) {
if (s->resource->client() != state.pointerFocusResource->client())
continue;
p->sendButton(timeMs, key, state_);
for (auto& p : s->resource->pointers) {
if (!p)
continue;
p->sendButton(timeMs, key, state_);
}
}
}
@ -282,40 +295,52 @@ void CSeatManager::sendPointerFrame(WP<CWLSeatResource> pResource) {
if (!pResource)
return;
for (auto& p : pResource->pointers) {
if (!p)
for (auto& s : seatResources) {
if (s->resource->client() != pResource->client())
continue;
p->sendFrame();
for (auto& p : s->resource->pointers) {
if (!p)
continue;
p->sendFrame();
}
}
}
void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, wl_pointer_axis_source source,
void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, int32_t value120, wl_pointer_axis_source source,
wl_pointer_axis_relative_direction relative) {
if (!state.pointerFocusResource)
return;
for (auto& p : state.pointerFocusResource->pointers) {
if (!p)
for (auto& s : seatResources) {
if (s->resource->client() != state.pointerFocusResource->client())
continue;
p->sendAxis(timeMs, axis, value);
p->sendAxisSource(source);
p->sendAxisRelativeDirection(axis, relative);
for (auto& p : s->resource->pointers) {
if (!p)
continue;
if (source == 0)
p->sendAxisDiscrete(axis, discrete);
p->sendAxis(timeMs, axis, value);
p->sendAxisSource(source);
p->sendAxisRelativeDirection(axis, relative);
if (value == 0)
p->sendAxisStop(timeMs, axis);
if (source == 0) {
p->sendAxisValue120(axis, value120);
p->sendAxisDiscrete(axis, discrete);
}
if (value == 0)
p->sendAxisStop(timeMs, axis);
}
}
}
void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local) {
void CSeatManager::sendTouchDown(SP<CWLSurfaceResource> surf, uint32_t timeMs, int32_t id, const Vector2D& local) {
if (state.touchFocus == surf)
return;
hyprListener_touchSurfaceDestroy.removeCallback();
listeners.touchSurfaceDestroy.reset();
if (state.touchFocusResource) {
auto client = state.touchFocusResource->client();
@ -340,7 +365,7 @@ void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id,
return;
}
auto client = wl_resource_get_client(surf->resource);
auto client = surf->client();
for (auto& r : seatResources | std::views::reverse) {
if (r->resource->client() != client)
continue;
@ -354,8 +379,7 @@ void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id,
}
}
hyprListener_touchSurfaceDestroy.initCallback(
&surf->events.destroy, [this, timeMs, id](void* owner, void* data) { sendTouchUp(timeMs + 10, id); }, nullptr, "CSeatManager");
listeners.touchSurfaceDestroy = surf->events.destroy.registerListener([this, timeMs, id](std::any d) { sendTouchUp(timeMs + 10, id); });
events.touchFocusChange.emit();
}
@ -368,11 +392,16 @@ void CSeatManager::sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D&
if (!state.touchFocusResource)
return;
for (auto& t : state.touchFocusResource->touches) {
if (!t)
for (auto& s : seatResources) {
if (s->resource->client() != state.touchFocusResource->client())
continue;
t->sendMotion(timeMs, id, local);
for (auto& t : s->resource->touches) {
if (!t)
continue;
t->sendMotion(timeMs, id, local);
}
}
}
@ -380,11 +409,16 @@ void CSeatManager::sendTouchFrame() {
if (!state.touchFocusResource)
return;
for (auto& t : state.touchFocusResource->touches) {
if (!t)
for (auto& s : seatResources) {
if (s->resource->client() != state.touchFocusResource->client())
continue;
t->sendFrame();
for (auto& t : s->resource->touches) {
if (!t)
continue;
t->sendFrame();
}
}
}
@ -392,11 +426,16 @@ void CSeatManager::sendTouchCancel() {
if (!state.touchFocusResource)
return;
for (auto& t : state.touchFocusResource->touches) {
if (!t)
for (auto& s : seatResources) {
if (s->resource->client() != state.touchFocusResource->client())
continue;
t->sendCancel();
for (auto& t : s->resource->touches) {
if (!t)
continue;
t->sendCancel();
}
}
}
@ -404,11 +443,16 @@ void CSeatManager::sendTouchShape(int32_t id, const Vector2D& shape) {
if (!state.touchFocusResource)
return;
for (auto& t : state.touchFocusResource->touches) {
if (!t)
for (auto& s : seatResources) {
if (s->resource->client() != state.touchFocusResource->client())
continue;
t->sendShape(id, shape);
for (auto& t : s->resource->touches) {
if (!t)
continue;
t->sendShape(id, shape);
}
}
}
@ -416,11 +460,16 @@ void CSeatManager::sendTouchOrientation(int32_t id, double angle) {
if (!state.touchFocusResource)
return;
for (auto& t : state.touchFocusResource->touches) {
if (!t)
for (auto& s : seatResources) {
if (s->resource->client() != state.touchFocusResource->client())
continue;
t->sendOrientation(id, angle);
for (auto& t : s->resource->touches) {
if (!t)
continue;
t->sendOrientation(id, angle);
}
}
}
@ -432,7 +481,7 @@ void CSeatManager::refocusGrab() {
// try to find a surf in focus first
const auto MOUSE = g_pInputManager->getMouseCoordsInternal();
for (auto& s : seatGrab->surfs) {
auto hlSurf = CWLSurface::surfaceFromWlr(s);
auto hlSurf = CWLSurface::fromResource(s.lock());
if (!hlSurf)
continue;
@ -444,13 +493,13 @@ void CSeatManager::refocusGrab() {
continue;
if (seatGrab->keyboard)
setKeyboardFocus(s);
setKeyboardFocus(s.lock());
if (seatGrab->pointer)
setPointerFocus(s, MOUSE - b->pos());
setPointerFocus(s.lock(), MOUSE - b->pos());
return;
}
wlr_surface* surf = seatGrab->surfs.at(0);
SP<CWLSurfaceResource> surf = seatGrab->surfs.at(0).lock();
if (seatGrab->keyboard)
setKeyboardFocus(surf);
if (seatGrab->pointer)
@ -458,7 +507,7 @@ void CSeatManager::refocusGrab() {
}
}
void CSeatManager::onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot) {
void CSeatManager::onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& hotspot) {
if (!state.pointerFocusResource || !seatResource || seatResource->client() != state.pointerFocusResource->client()) {
Debug::log(LOG, "[seatmgr] Rejecting a setCursor because the client ain't in focus");
return;
@ -498,6 +547,8 @@ void CSeatManager::setCurrentSelection(SP<IDataSource> source) {
PROTO::data->setSelection(source);
PROTO::dataWlr->setSelection(source, false);
}
events.setSelection.emit();
}
void CSeatManager::setCurrentPrimarySelection(SP<IDataSource> source) {
@ -521,6 +572,8 @@ void CSeatManager::setCurrentPrimarySelection(SP<IDataSource> source) {
PROTO::primarySelection->setSelection(source);
PROTO::dataWlr->setSelection(source, true);
}
events.setPrimarySelection.emit();
}
void CSeatManager::setGrab(SP<CSeatGrab> grab) {
@ -541,10 +594,10 @@ void CSeatManager::setGrab(SP<CSeatGrab> grab) {
}
void CSeatManager::resendEnterEvents() {
wlr_surface* kb = state.keyboardFocus;
wlr_surface* pt = state.pointerFocus;
SP<CWLSurfaceResource> kb = state.keyboardFocus.lock();
SP<CWLSurfaceResource> pt = state.pointerFocus.lock();
auto last = lastLocalCoords;
auto last = lastLocalCoords;
setKeyboardFocus(nullptr);
setPointerFocus(nullptr, {});
@ -553,15 +606,15 @@ void CSeatManager::resendEnterEvents() {
setPointerFocus(pt, last);
}
bool CSeatGrab::accepts(wlr_surface* surf) {
bool CSeatGrab::accepts(SP<CWLSurfaceResource> surf) {
return std::find(surfs.begin(), surfs.end(), surf) != surfs.end();
}
void CSeatGrab::add(wlr_surface* surf) {
void CSeatGrab::add(SP<CWLSurfaceResource> surf) {
surfs.push_back(surf);
}
void CSeatGrab::remove(wlr_surface* surf) {
void CSeatGrab::remove(SP<CWLSurfaceResource> surf) {
std::erase(surfs, surf);
if ((keyboard && g_pSeatManager->state.keyboardFocus == surf) || (pointer && g_pSeatManager->state.pointerFocus == surf))
g_pSeatManager->refocusGrab();

View File

@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <wayland-server-protocol.h>
#include "../helpers/WLListener.hpp"
#include "../macros.hpp"
@ -10,7 +11,7 @@
constexpr size_t MAX_SERIAL_STORE_LEN = 100;
struct wlr_surface;
class CWLSurfaceResource;
class CWLSeatResource;
class IPointer;
class IKeyboard;
@ -28,9 +29,9 @@ class IKeyboard;
*/
class CSeatGrab {
public:
bool accepts(wlr_surface* surf);
void add(wlr_surface* surf);
void remove(wlr_surface* surf);
bool accepts(SP<CWLSurfaceResource> surf);
void add(SP<CWLSurfaceResource> surf);
void remove(SP<CWLSurfaceResource> surf);
void setCallback(std::function<void()> onEnd_);
void clear();
@ -41,8 +42,8 @@ class CSeatGrab {
bool removeOnInput = true; // on hard input e.g. click outside, remove
private:
std::vector<wlr_surface*> surfs; // read-only
std::function<void()> onEnd;
std::vector<WP<CWLSurfaceResource>> surfs;
std::function<void()> onEnd;
friend class CSeatManager;
};
@ -56,18 +57,19 @@ class CSeatManager {
void setKeyboard(SP<IKeyboard> keeb);
void updateActiveKeyboardData(); // updates the clients with the keymap and repeat info
void setKeyboardFocus(wlr_surface* surf);
void setKeyboardFocus(SP<CWLSurfaceResource> surf);
void sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state);
void sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
void setPointerFocus(wlr_surface* surf, const Vector2D& local);
void setPointerFocus(SP<CWLSurfaceResource> surf, const Vector2D& local);
void sendPointerMotion(uint32_t timeMs, const Vector2D& local);
void sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_button_state state);
void sendPointerFrame();
void sendPointerFrame(WP<CWLSeatResource> pResource);
void sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, wl_pointer_axis_source source, wl_pointer_axis_relative_direction relative);
void sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, int32_t value120, wl_pointer_axis_source source,
wl_pointer_axis_relative_direction relative);
void sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local);
void sendTouchDown(SP<CWLSurfaceResource> surf, uint32_t timeMs, int32_t id, const Vector2D& local);
void sendTouchUp(uint32_t timeMs, int32_t id);
void sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& local);
void sendTouchFrame();
@ -81,24 +83,24 @@ class CSeatManager {
// pops the serial if it was valid, meaning it is consumed.
bool serialValid(SP<CWLSeatResource> seatResource, uint32_t serial);
void onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot);
void onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& hotspot);
SP<CWLSeatResource> seatResourceForClient(wl_client* client);
struct {
wlr_surface* keyboardFocus = nullptr;
WP<CWLSeatResource> keyboardFocusResource;
WP<CWLSurfaceResource> keyboardFocus;
WP<CWLSeatResource> keyboardFocusResource;
wlr_surface* pointerFocus = nullptr;
WP<CWLSeatResource> pointerFocusResource;
WP<CWLSurfaceResource> pointerFocus;
WP<CWLSeatResource> pointerFocusResource;
wlr_surface* touchFocus = nullptr;
WP<CWLSeatResource> touchFocusResource;
WP<CWLSurfaceResource> touchFocus;
WP<CWLSeatResource> touchFocusResource;
} state;
struct SSetCursorEvent {
wlr_surface* surf = nullptr;
Vector2D hotspot;
SP<CWLSurfaceResource> surf = nullptr;
Vector2D hotspot;
};
struct {
@ -106,6 +108,8 @@ class CSeatManager {
CSignal pointerFocusChange;
CSignal touchFocusChange;
CSignal setCursor; // SSetCursorEvent
CSignal setSelection;
CSignal setPrimarySelection;
} events;
struct {
@ -145,14 +149,13 @@ class CSeatManager {
struct {
CHyprSignalListener newSeatResource;
CHyprSignalListener keyboardSurfaceDestroy;
CHyprSignalListener pointerSurfaceDestroy;
CHyprSignalListener touchSurfaceDestroy;
} listeners;
Vector2D lastLocalCoords;
DYNLISTENER(keyboardSurfaceDestroy);
DYNLISTENER(pointerSurfaceDestroy);
DYNLISTENER(touchSurfaceDestroy);
friend struct SSeatResourceContainer;
friend class CSeatGrab;
};

View File

@ -20,7 +20,7 @@ SSessionLockSurface::SSessionLockSurface(SP<CSessionLockSurface> surface_) : sur
listeners.destroy = surface_->events.destroy.registerListener([this](std::any data) {
if (pWlrSurface == g_pCompositor->m_pLastFocus)
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastFocus.reset();
g_pSessionLockManager->removeSessionLockSurface(this);
});
@ -70,7 +70,7 @@ void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) {
g_pHyprRenderer->damageMonitor(m.get());
});
m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([this](std::any data) {
m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([](std::any data) {
g_pCompositor->focusSurface(nullptr);
for (auto& m : g_pCompositor->m_vMonitors)
@ -117,7 +117,7 @@ float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) {
return std::clamp(NOMAPPEDSURFACETIMER->second.getSeconds() - /* delay for screencopy */ 0.5f, 0.f, 1.f);
}
bool CSessionLockManager::isSurfaceSessionLock(wlr_surface* pSurface) {
bool CSessionLockManager::isSurfaceSessionLock(SP<CWLSurfaceResource> pSurface) {
// TODO: this has some edge cases when it's wrong (e.g. destroyed lock but not yet surfaces)
// but can be easily fixed when I rewrite wlr_surface

View File

@ -8,13 +8,14 @@
class CSessionLockSurface;
class CSessionLock;
class CWLSurfaceResource;
struct SSessionLockSurface {
SSessionLockSurface(SP<CSessionLockSurface> surface_);
WP<CSessionLockSurface> surface;
wlr_surface* pWlrSurface = nullptr;
uint64_t iMonitorID = -1;
WP<CWLSurfaceResource> pWlrSurface;
uint64_t iMonitorID = -1;
bool mapped = false;
@ -49,7 +50,7 @@ class CSessionLockManager {
bool isSessionLocked();
bool isSessionLockPresent();
bool isSurfaceSessionLock(wlr_surface*);
bool isSurfaceSessionLock(SP<CWLSurfaceResource>);
void removeSessionLockSurface(SSessionLockSurface*);

View File

@ -3,29 +3,15 @@
#include "../events/Events.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../xwayland/XWayland.hpp"
#define OUTPUT_MANAGER_VERSION 3
#define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3
#define OUTPUT_DESCRIPTION_MUTABLE_SINCE_VERSION 3
CHyprXWaylandManager::CHyprXWaylandManager() {
#ifndef NO_XWAYLAND
m_sWLRXWayland = wlr_xwayland_create(g_pCompositor->m_sWLDisplay, g_pCompositor->m_sWLRCompositor, 1);
if (!m_sWLRXWayland) {
Debug::log(ERR, "Couldn't start up the XWaylandManager because wlr_xwayland_create returned a nullptr!");
return;
}
addWLSignal(&m_sWLRXWayland->events.ready, &Events::listen_readyXWayland, m_sWLRXWayland, "XWayland Manager");
addWLSignal(&m_sWLRXWayland->events.new_surface, &Events::listen_surfaceXWayland, m_sWLRXWayland, "XWayland Manager");
setenv("DISPLAY", m_sWLRXWayland->display_name, 1);
Debug::log(LOG, "CHyprXWaylandManager started on display {}", m_sWLRXWayland->display_name);
#else
unsetenv("DISPLAY"); // unset DISPLAY so that X11 apps do not try to start on a different/invalid DISPLAY
#endif
;
}
CHyprXWaylandManager::~CHyprXWaylandManager() {
@ -34,32 +20,31 @@ CHyprXWaylandManager::~CHyprXWaylandManager() {
#endif
}
wlr_surface* CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) {
return pWindow->m_pWLSurface.wlr();
SP<CWLSurfaceResource> CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) {
return pWindow->m_pWLSurface->resource();
}
void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) {
void CHyprXWaylandManager::activateSurface(SP<CWLSurfaceResource> pSurface, bool activate) {
if (!pSurface)
return;
if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) {
const auto XSURF = wlr_xwayland_surface_try_from_wlr_surface(pSurface);
wlr_xwayland_surface_activate(XSURF, activate);
if (activate && !XSURF->override_redirect)
wlr_xwayland_surface_restack(XSURF, nullptr, XCB_STACK_MODE_ABOVE);
}
// TODO:
// this cannot be nicely done until we rewrite wlr_surface
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsX11 || !w->m_bIsMapped)
if (!w->m_bIsMapped)
continue;
if (w->m_pWLSurface.wlr() != pSurface)
if (w->m_pWLSurface->resource() != pSurface)
continue;
w->m_pXDGSurface->toplevel->setActive(activate);
if (w->m_bIsX11) {
if (activate) {
w->m_pXWaylandSurface->setMinimized(false);
w->m_pXWaylandSurface->restackToTop();
}
w->m_pXWaylandSurface->activate(activate);
} else
w->m_pXDGSurface->toplevel->setActive(activate);
}
}
@ -68,12 +53,12 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) {
setWindowSize(pWindow, pWindow->m_vRealSize.value()); // update xwayland output pos
if (activate) {
wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false);
if (!pWindow->m_uSurface.xwayland->override_redirect)
wlr_xwayland_surface_restack(pWindow->m_uSurface.xwayland, nullptr, XCB_STACK_MODE_ABOVE);
pWindow->m_pXWaylandSurface->setMinimized(false);
if (pWindow->m_iX11Type != 2)
pWindow->m_pXWaylandSurface->restackToTop();
}
wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate);
pWindow->m_pXWaylandSurface->activate(activate);
} else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel)
pWindow->m_pXDGSurface->toplevel->setActive(activate);
@ -88,7 +73,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) {
void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) {
if (pWindow->m_bIsX11) {
const auto SIZEHINTS = pWindow->m_uSurface.xwayland->size_hints;
const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get();
if (SIZEHINTS && pWindow->m_iX11Type != 2) {
pbox->x = SIZEHINTS->x;
@ -96,10 +81,7 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) {
pbox->width = SIZEHINTS->width;
pbox->height = SIZEHINTS->height;
} else {
pbox->x = pWindow->m_uSurface.xwayland->x;
pbox->y = pWindow->m_uSurface.xwayland->y;
pbox->width = pWindow->m_uSurface.xwayland->width;
pbox->height = pWindow->m_uSurface.xwayland->height;
*pbox = pWindow->m_pXWaylandSurface->geometry;
}
} else if (pWindow->m_pXDGSurface)
*pbox = pWindow->m_pXDGSurface->current.geometry;
@ -107,7 +89,7 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) {
void CHyprXWaylandManager::sendCloseWindow(PHLWINDOW pWindow) {
if (pWindow->m_bIsX11)
wlr_xwayland_surface_close(pWindow->m_uSurface.xwayland);
pWindow->m_pXWaylandSurface->close();
else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel)
pWindow->m_pXDGSurface->toplevel->close();
}
@ -145,56 +127,43 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool
}
if (pWindow->m_bIsX11)
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, windowPos.x, windowPos.y, size.x, size.y);
pWindow->m_pXWaylandSurface->configure({windowPos, size});
else if (pWindow->m_pXDGSurface->toplevel)
pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor()));
}
wlr_surface* CHyprXWaylandManager::surfaceAt(PHLWINDOW pWindow, const Vector2D& client, Vector2D& surface) {
return wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), client.x, client.y, &surface.x, &surface.y);
}
bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) {
if (pWindow->m_bIsX11) {
for (size_t i = 0; i < pWindow->m_uSurface.xwayland->window_type_len; i++)
if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"]) {
for (auto& a : pWindow->m_pXWaylandSurface->atoms)
if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] ||
a == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] ||
a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] ||
a == HYPRATOMS["_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"]) {
if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
pWindow->m_bX11ShouldntFocus = true;
pWindow->m_bNoInitialFocus = true;
return true;
}
if (pWindow->m_uSurface.xwayland->role) {
try {
std::string winrole = std::string(pWindow->m_uSurface.xwayland->role);
if (winrole.contains("pop-up") || winrole.contains("task_dialog")) {
return true;
}
} catch (std::exception& e) { Debug::log(ERR, "Error in shouldBeFloated, winrole threw {}", e.what()); }
}
if (pWindow->m_uSurface.xwayland->modal) {
if (pWindow->m_pXWaylandSurface->modal) {
pWindow->m_bIsModal = true;
return true;
}
if (pWindow->m_iX11Type == 2)
return true; // override_redirect
if (pWindow->m_pXWaylandSurface->transient)
return true;
const auto SIZEHINTS = pWindow->m_uSurface.xwayland->size_hints;
if (SIZEHINTS && (pWindow->m_uSurface.xwayland->parent || ((SIZEHINTS->min_width == SIZEHINTS->max_width) && (SIZEHINTS->min_height == SIZEHINTS->max_height))))
if (pWindow->m_pXWaylandSurface->role.contains("task_dialog") || pWindow->m_pXWaylandSurface->role.contains("pop-up"))
return true;
if (pWindow->m_pXWaylandSurface->overrideRedirect)
return true;
const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get();
if (pWindow->m_pXWaylandSurface->transient || pWindow->m_pXWaylandSurface->parent ||
(SIZEHINTS && (SIZEHINTS->min_width == SIZEHINTS->max_width) && (SIZEHINTS->min_height == SIZEHINTS->max_height)))
return true;
} else {
const auto PSTATE = pending ? &pWindow->m_pXDGSurface->toplevel->pending : &pWindow->m_pXDGSurface->toplevel->current;
@ -207,28 +176,14 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) {
return false;
}
void CHyprXWaylandManager::moveXWaylandWindow(PHLWINDOW pWindow, const Vector2D& pos) {
if (!validMapped(pWindow))
return;
if (!pWindow->m_bIsX11)
return;
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pos.x, pos.y, pWindow->m_vRealSize.value().x, pWindow->m_vRealSize.value().y);
}
void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) {
if (!pWindow->m_bIsX11)
return;
for (size_t i = 0; i < pWindow->m_uSurface.xwayland->window_type_len; i++) {
if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) {
for (auto& a : pWindow->m_pXWaylandSurface->atoms) {
if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
a == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] ||
a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) {
pWindow->m_bX11DoesntWantBorders = true;
return;
@ -242,7 +197,7 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) {
void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscreen) {
if (pWindow->m_bIsX11)
wlr_xwayland_surface_set_fullscreen(pWindow->m_uSurface.xwayland, fullscreen);
pWindow->m_pXWaylandSurface->setFullscreen(fullscreen);
else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel)
pWindow->m_pXDGSurface->toplevel->setFullscreen(fullscreen);
}
@ -251,10 +206,10 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) {
if (!validMapped(pWindow))
return Vector2D(99999, 99999);
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize)
if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize)
return Vector2D(99999, 99999);
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height) :
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) :
pWindow->m_pXDGSurface->toplevel->current.maxSize;
if (MAXSIZE.x < 5)
@ -269,10 +224,10 @@ Vector2D CHyprXWaylandManager::getMinSizeForWindow(PHLWINDOW pWindow) {
if (!validMapped(pWindow))
return Vector2D(0, 0);
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel))
if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel))
return Vector2D(0, 0);
auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->min_width, pWindow->m_uSurface.xwayland->size_hints->min_height) :
auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->min_width, pWindow->m_pXWaylandSurface->sizeHints->min_height) :
pWindow->m_pXDGSurface->toplevel->current.minSize;
MINSIZE = MINSIZE.clamp({1, 1});

View File

@ -5,28 +5,25 @@
class CWindow; // because clangd
typedef SP<CWindow> PHLWINDOW;
class CWLSurfaceResource;
class CHyprXWaylandManager {
public:
CHyprXWaylandManager();
~CHyprXWaylandManager();
wlr_xwayland* m_sWLRXWayland = nullptr;
wlr_surface* getWindowSurface(PHLWINDOW);
void activateSurface(wlr_surface*, bool);
void activateWindow(PHLWINDOW, bool);
void getGeometryForWindow(PHLWINDOW, CBox*);
void sendCloseWindow(PHLWINDOW);
void setWindowSize(PHLWINDOW, Vector2D, bool force = false);
void setWindowFullscreen(PHLWINDOW, bool);
wlr_surface* surfaceAt(PHLWINDOW, const Vector2D&, Vector2D&);
bool shouldBeFloated(PHLWINDOW, bool pending = false);
void moveXWaylandWindow(PHLWINDOW, const Vector2D&);
void checkBorders(PHLWINDOW);
Vector2D getMaxSizeForWindow(PHLWINDOW);
Vector2D getMinSizeForWindow(PHLWINDOW);
Vector2D xwaylandToWaylandCoords(const Vector2D&);
SP<CWLSurfaceResource> getWindowSurface(PHLWINDOW);
void activateSurface(SP<CWLSurfaceResource>, bool);
void activateWindow(PHLWINDOW, bool);
void getGeometryForWindow(PHLWINDOW, CBox*);
void sendCloseWindow(PHLWINDOW);
void setWindowSize(PHLWINDOW, Vector2D, bool force = false);
void setWindowFullscreen(PHLWINDOW, bool);
bool shouldBeFloated(PHLWINDOW, bool pending = false);
void checkBorders(PHLWINDOW);
Vector2D getMaxSizeForWindow(PHLWINDOW);
Vector2D getMinSizeForWindow(PHLWINDOW);
Vector2D xwaylandToWaylandCoords(const Vector2D&);
};
inline std::unique_ptr<CHyprXWaylandManager> g_pXWaylandManager;

View File

@ -13,6 +13,11 @@ CEventLoopManager::CEventLoopManager() {
m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
}
CEventLoopManager::~CEventLoopManager() {
if (m_sWayland.eventSource)
wl_event_source_remove(m_sWayland.eventSource);
}
static int timerWrite(int fd, uint32_t mask, void* data) {
g_pEventLoopManager->onTimerFire();
return 1;
@ -22,7 +27,7 @@ void CEventLoopManager::enterLoop(wl_display* display, wl_event_loop* wlEventLoo
m_sWayland.loop = wlEventLoop;
m_sWayland.display = display;
wl_event_loop_add_fd(wlEventLoop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr);
m_sWayland.eventSource = wl_event_loop_add_fd(wlEventLoop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr);
wl_display_run(display);

View File

@ -10,6 +10,7 @@
class CEventLoopManager {
public:
CEventLoopManager();
~CEventLoopManager();
void enterLoop(wl_display* display, wl_event_loop* wlEventLoop);
@ -24,8 +25,9 @@ class CEventLoopManager {
private:
struct {
wl_event_loop* loop = nullptr;
wl_display* display = nullptr;
wl_event_loop* loop = nullptr;
wl_display* display = nullptr;
wl_event_source* eventSource = nullptr;
} m_sWayland;
struct {

View File

@ -14,7 +14,7 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) {
recheckIdleInhibitorStatus();
});
auto WLSurface = CWLSurface::surfaceFromWlr(PINHIBIT->inhibitor->surface);
auto WLSurface = CWLSurface::fromResource(PINHIBIT->inhibitor->surface.lock());
if (!WLSurface) {
Debug::log(LOG, "Inhibitor has no HL Surface attached to it, likely meaning it's a non-desktop element. Assuming it's visible.");
@ -37,7 +37,7 @@ void CInputManager::recheckIdleInhibitorStatus() {
return;
}
auto WLSurface = CWLSurface::surfaceFromWlr(ii->inhibitor->surface);
auto WLSurface = CWLSurface::fromResource(ii->inhibitor->surface.lock());
if (!WLSurface)
continue;

View File

@ -1,6 +1,7 @@
#include "InputManager.hpp"
#include "../../Compositor.hpp"
#include "wlr/types/wlr_switch.h"
#include <cstdint>
#include <ranges>
#include "../../config/ConfigValue.hpp"
#include "../../desktop/Window.hpp"
@ -42,7 +43,7 @@ CInputManager::CInputManager() {
Debug::log(LOG, "cursorImage request: shape {} -> {}", (uint32_t)event.shape, event.shapeName);
m_sCursorSurfaceInfo.wlSurface.unassign();
m_sCursorSurfaceInfo.wlSurface->unassign();
m_sCursorSurfaceInfo.vHotspot = {};
m_sCursorSurfaceInfo.name = event.shapeName;
m_sCursorSurfaceInfo.hidden = false;
@ -51,12 +52,18 @@ CInputManager::CInputManager() {
g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name);
});
m_sListeners.newIdleInhibitor = PROTO::idleInhibit->events.newIdleInhibitor.registerListener([this](std::any data) { this->newIdleInhibitor(data); });
m_sListeners.newVirtualKeyboard =
PROTO::virtualKeyboard->events.newKeyboard.registerListener([this](std::any data) { this->newVirtualKeyboard(std::any_cast<SP<CVirtualKeyboardV1Resource>>(data)); });
m_sListeners.newVirtualMouse =
PROTO::virtualPointer->events.newPointer.registerListener([this](std::any data) { this->newVirtualMouse(std::any_cast<SP<CVirtualPointerV1Resource>>(data)); });
m_sListeners.setCursor = g_pSeatManager->events.setCursor.registerListener([this](std::any d) { this->processMouseRequest(d); });
m_sListeners.newIdleInhibitor = PROTO::idleInhibit->events.newIdleInhibitor.registerListener([this](std::any data) { this->newIdleInhibitor(data); });
m_sListeners.newVirtualKeyboard = PROTO::virtualKeyboard->events.newKeyboard.registerListener([this](std::any data) {
this->newVirtualKeyboard(std::any_cast<SP<CVirtualKeyboardV1Resource>>(data));
updateCapabilities();
});
m_sListeners.newVirtualMouse = PROTO::virtualPointer->events.newPointer.registerListener([this](std::any data) {
this->newVirtualMouse(std::any_cast<SP<CVirtualPointerV1Resource>>(data));
updateCapabilities();
});
m_sListeners.setCursor = g_pSeatManager->events.setCursor.registerListener([this](std::any d) { this->processMouseRequest(d); });
m_sCursorSurfaceInfo.wlSurface = CWLSurface::create();
}
CInputManager::~CInputManager() {
@ -114,8 +121,8 @@ void CInputManager::sendMotionEventsToFocused() {
return;
// todo: this sucks ass
const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus);
const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus.lock());
const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock());
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@ -124,7 +131,7 @@ void CInputManager::sendMotionEventsToFocused() {
m_bEmptyFocusCursorSet = false;
g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus, LOCAL);
g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus.lock(), LOCAL);
}
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
@ -140,14 +147,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
const auto FOLLOWMOUSE = *PFOLLOWONDND && PROTO::data->dndActive() ? 1 : *PFOLLOWMOUSE;
m_pFoundSurfaceToFocus = nullptr;
m_pFoundSurfaceToFocus.reset();
m_pFoundLSToFocus.reset();
m_pFoundWindowToFocus.reset();
wlr_surface* foundSurface = nullptr;
Vector2D surfaceCoords;
Vector2D surfacePos = Vector2D(-1337, -1337);
PHLWINDOW pFoundWindow;
PHLLS pFoundLayerSurface;
SP<CWLSurfaceResource> foundSurface;
Vector2D surfaceCoords;
Vector2D surfacePos = Vector2D(-1337, -1337);
PHLWINDOW pFoundWindow;
PHLLS pFoundLayerSurface;
if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState)
return;
@ -190,12 +197,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (forcedFocus) {
pFoundWindow = forcedFocus;
surfacePos = pFoundWindow->m_vRealPosition.value();
foundSurface = pFoundWindow->m_pWLSurface.wlr();
foundSurface = pFoundWindow->m_pWLSurface->resource();
}
// constraints
if (!g_pSeatManager->mouse.expired() && isConstrained()) {
const auto SURF = CWLSurface::surfaceFromWlr(g_pCompositor->m_pLastFocus);
const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock());
const auto CONSTRAINT = SURF->constraint();
if (SURF && CONSTRAINT) {
@ -222,7 +229,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// if we are holding a pointer button,
// and we're not dnd-ing, don't refocus. Keep focus on last surface.
if (!PROTO::data->dndActive() && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus && !m_bHardInput) {
foundSurface = g_pSeatManager->state.pointerFocus;
foundSurface = g_pSeatManager->state.pointerFocus.lock();
// IME popups aren't desktop-like elements
// TODO: make them.
@ -232,7 +239,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
m_bFocusHeldByButtons = true;
m_bRefocusHeldByButtons = refocus;
} else {
auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface);
auto HLSurface = CWLSurface::fromResource(foundSurface);
if (HLSurface) {
const auto BOX = HLSurface->getSurfaceBoxGlobal();
@ -274,7 +281,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!foundSurface) {
auto popup = g_pInputManager->m_sIMERelay.popupFromCoords(mouseCoords);
if (popup) {
foundSurface = popup->getWlrSurface();
foundSurface = popup->getSurface();
surfacePos = popup->globalBox().pos();
}
}
@ -305,7 +312,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
surfacePos = Vector2D(-1337, -1337);
} else {
foundSurface = pFoundWindow->m_pWLSurface.wlr();
foundSurface = pFoundWindow->m_pWLSurface->resource();
surfacePos = pFoundWindow->m_vRealPosition.value();
}
}
@ -344,7 +351,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!pFoundWindow->m_bIsX11) {
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
} else {
foundSurface = pFoundWindow->m_pWLSurface.wlr();
foundSurface = pFoundWindow->m_pWLSurface->resource();
surfacePos = pFoundWindow->m_vRealPosition.value();
}
}
@ -368,9 +375,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return; // setGrab will refocus
} else {
// we need to grab the last surface.
foundSurface = g_pSeatManager->state.pointerFocus;
foundSurface = g_pSeatManager->state.pointerFocus.lock();
auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface);
auto HLSurface = CWLSurface::fromResource(foundSurface);
if (HLSurface) {
const auto BOX = HLSurface->getSurfaceBoxGlobal();
@ -422,7 +429,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
bool allowKeyboardRefocus = true;
if (!refocus && g_pCompositor->m_pLastFocus) {
const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock());
if (PLS && PLS->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
allowKeyboardRefocus = false;
@ -440,7 +447,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return;
}
if (pFoundWindow && foundSurface == pFoundWindow->m_pWLSurface.wlr() && !m_bCursorImageOverridden) {
if (pFoundWindow && foundSurface == pFoundWindow->m_pWLSurface->resource() && !m_bCursorImageOverridden) {
const auto BOX = pFoundWindow->getWindowMainSurfaceBox();
if (!VECINRECT(mouseCoords, BOX.x, BOX.y, BOX.x + BOX.width, BOX.y + BOX.height))
setCursorImageOverride("left_ptr");
@ -554,11 +561,11 @@ void CInputManager::processMouseRequest(std::any E) {
Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf);
if (e.surf != m_sCursorSurfaceInfo.wlSurface.wlr()) {
m_sCursorSurfaceInfo.wlSurface.unassign();
if (e.surf != m_sCursorSurfaceInfo.wlSurface->resource()) {
m_sCursorSurfaceInfo.wlSurface->unassign();
if (e.surf)
m_sCursorSurfaceInfo.wlSurface.assign(e.surf);
m_sCursorSurfaceInfo.wlSurface->assign(e.surf);
}
if (e.surf) {
@ -572,7 +579,7 @@ void CInputManager::processMouseRequest(std::any E) {
m_sCursorSurfaceInfo.name = "";
m_sCursorSurfaceInfo.inUse = true;
g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, e.hotspot.x, e.hotspot.y);
g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface, e.hotspot.x, e.hotspot.y);
}
void CInputManager::restoreCursorIconToApp() {
@ -585,8 +592,8 @@ void CInputManager::restoreCursorIconToApp() {
}
if (m_sCursorSurfaceInfo.name.empty()) {
if (m_sCursorSurfaceInfo.wlSurface.exists())
g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y);
if (m_sCursorSurfaceInfo.wlSurface->exists())
g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface, m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y);
} else {
g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name);
}
@ -661,7 +668,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) {
// clicking on border triggers resize
// TODO detect click on LS properly
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED) {
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || w->m_iX11Type != 2)) {
if (w && !w->m_bIsFullscreen) {
const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y};
const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA};
@ -674,7 +681,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) {
}
switch (e.state) {
case WL_POINTER_BUTTON_STATE_PRESSED:
case WL_POINTER_BUTTON_STATE_PRESSED: {
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
break;
@ -692,10 +699,16 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) {
}
// if clicked on a floating window make it top
if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsFloating)
g_pCompositor->changeWindowZOrder(g_pCompositor->m_pLastWindow.lock(), true);
if (!g_pSeatManager->state.pointerFocus)
break;
auto HLSurf = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock());
if (HLSurf && HLSurf->getWindow())
g_pCompositor->changeWindowZOrder(HLSurf->getWindow(), true);
break;
}
case WL_POINTER_BUTTON_STATE_RELEASED: break;
}
@ -776,8 +789,9 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) {
}
}
}
g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, std::round(factor * e.deltaDiscrete / 120), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL);
double deltaDiscrete = factor * e.deltaDiscrete / std::abs(e.deltaDiscrete);
g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, deltaDiscrete > 0 ? std::ceil(deltaDiscrete) : std::floor(deltaDiscrete),
std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL);
}
Vector2D CInputManager::getMouseCoordsInternal() {
@ -842,8 +856,10 @@ void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
auto PKEEB = ((IKeyboard*)owner)->self.lock();
const auto LAYOUT = PKEEB->getActiveLayout();
if (PKEEB == g_pSeatManager->keyboard)
if (PKEEB == g_pSeatManager->keyboard) {
g_pSeatManager->updateActiveKeyboardData();
g_pKeybindManager->m_mKeyToCodeCache.clear();
}
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", PKEEB->hlName + "," + LAYOUT});
EMIT_HOOK_EVENT("activeLayout", (std::vector<std::any>{PKEEB, LAYOUT}));
@ -1389,7 +1405,7 @@ bool CInputManager::isConstrained() {
if (!C)
continue;
if (!C->isActive() || C->owner()->wlr() != g_pCompositor->m_pLastFocus)
if (!C->isActive() || C->owner()->resource() != g_pCompositor->m_pLastFocus)
continue;
return true;
@ -1675,6 +1691,10 @@ void CInputManager::setCursorIconOnBorder(PHLWINDOW w) {
return;
}
// ignore X11 OR windows, they shouldn't be touched
if (w->m_bIsX11 && w->m_iX11Type == 2)
return;
static auto PEXTENDBORDERGRAB = CConfigValue<Hyprlang::INT>("general:extend_border_grab_area");
const int BORDERSIZE = w->getRealBorderSize();
const int ROUNDING = w->rounding();

View File

@ -44,10 +44,10 @@ enum eBorderIconDirection {
};
struct STouchData {
PHLWINDOWREF touchFocusWindow;
PHLLSREF touchFocusLS;
wlr_surface* touchFocusSurface = nullptr;
Vector2D touchSurfaceOrigin;
PHLWINDOWREF touchFocusWindow;
PHLLSREF touchFocusLS;
WP<CWLSurfaceResource> touchFocusSurface;
Vector2D touchSurfaceOrigin;
};
// The third row is always 0 0 1 and is not expected by `libinput_device_config_calibration_set_matrix`
@ -236,9 +236,9 @@ class CInputManager {
void applyConfigToKeyboard(SP<IKeyboard>);
// this will be set after a refocus()
wlr_surface* m_pFoundSurfaceToFocus = nullptr;
PHLLSREF m_pFoundLSToFocus;
PHLWINDOWREF m_pFoundWindowToFocus;
WP<CWLSurfaceResource> m_pFoundSurfaceToFocus;
PHLLSREF m_pFoundLSToFocus;
PHLWINDOWREF m_pFoundWindowToFocus;
// for holding focus on buttons held
bool m_bFocusHeldByButtons = false;
@ -268,11 +268,11 @@ class CInputManager {
// cursor surface
struct cursorSI {
bool hidden = false; // null surface = hidden
CWLSurface wlSurface;
Vector2D vHotspot;
std::string name; // if not empty, means set by name.
bool inUse = false;
bool hidden = false; // null surface = hidden
SP<CWLSurface> wlSurface;
Vector2D vHotspot;
std::string name; // if not empty, means set by name.
bool inUse = false;
} m_sCursorSurfaceInfo;
void restoreCursorIconToApp(); // no-op if restored

View File

@ -3,22 +3,24 @@
#include "../../Compositor.hpp"
#include "../../protocols/FractionalScale.hpp"
#include "../../protocols/InputMethodV2.hpp"
#include "../../protocols/core/Compositor.hpp"
CInputPopup::CInputPopup(SP<CInputMethodPopupV2> popup_) : popup(popup_) {
listeners.commit = popup_->events.commit.registerListener([this](std::any d) { onCommit(); });
listeners.map = popup_->events.map.registerListener([this](std::any d) { onMap(); });
listeners.unmap = popup_->events.unmap.registerListener([this](std::any d) { onUnmap(); });
listeners.destroy = popup_->events.destroy.registerListener([this](std::any d) { onDestroy(); });
surface.assign(popup_->surface());
surface = CWLSurface::create();
surface->assign(popup_->surface());
}
CWLSurface* CInputPopup::queryOwner() {
SP<CWLSurface> CInputPopup::queryOwner() {
const auto FOCUSED = g_pInputManager->m_sIMERelay.getFocusedTextInput();
if (!FOCUSED)
return nullptr;
return CWLSurface::surfaceFromWlr(FOCUSED->focusedSurface());
return CWLSurface::fromResource(FOCUSED->focusedSurface());
}
void CInputPopup::onDestroy() {
@ -36,7 +38,7 @@ void CInputPopup::onMap() {
if (!PMONITOR)
return;
PROTO::fractional->sendScale(surface.wlr(), PMONITOR->scale);
PROTO::fractional->sendScale(surface->resource(), PMONITOR->scale);
}
void CInputPopup::onUnmap() {
@ -69,7 +71,7 @@ void CInputPopup::damageSurface() {
}
Vector2D pos = globalBox().pos();
g_pHyprRenderer->damageSurface(surface.wlr(), pos.x, pos.y);
g_pHyprRenderer->damageSurface(surface->resource(), pos.x, pos.y);
}
void CInputPopup::updateBox() {
@ -98,7 +100,7 @@ void CInputPopup::updateBox() {
cursorBoxParent = {0, 0, (int)parentBox.w, (int)parentBox.h};
}
Vector2D currentPopupSize = surface.getViewporterCorrectedSize();
Vector2D currentPopupSize = surface->getViewporterCorrectedSize();
CMonitor* pMonitor = g_pCompositor->getMonitorFromVector(parentBox.middle());
@ -127,9 +129,9 @@ void CInputPopup::updateBox() {
const auto PML = g_pCompositor->getMonitorFromID(lastMonitor);
if (PML)
wlr_surface_send_leave(surface.wlr(), PML->output);
surface->resource()->leave(PML->self.lock());
wlr_surface_send_enter(surface.wlr(), PM->output);
surface->resource()->enter(PM->self.lock());
lastMonitor = PM->ID;
}
@ -151,6 +153,6 @@ bool CInputPopup::isVecInPopup(const Vector2D& point) {
return globalBox().containsPoint(point);
}
wlr_surface* CInputPopup::getWlrSurface() {
return surface.wlr();
SP<CWLSurfaceResource> CInputPopup::getSurface() {
return surface->resource();
}

View File

@ -12,18 +12,18 @@ class CInputPopup {
public:
CInputPopup(SP<CInputMethodPopupV2> popup);
void damageEntire();
void damageSurface();
void damageEntire();
void damageSurface();
bool isVecInPopup(const Vector2D& point);
bool isVecInPopup(const Vector2D& point);
CBox globalBox();
wlr_surface* getWlrSurface();
CBox globalBox();
SP<CWLSurfaceResource> getSurface();
void onCommit();
void onCommit();
private:
CWLSurface* queryOwner();
SP<CWLSurface> queryOwner();
void updateBox();
void onDestroy();
@ -31,7 +31,7 @@ class CInputPopup {
void onUnmap();
WP<CInputMethodPopupV2> popup;
CWLSurface surface;
SP<CWLSurface> surface;
CBox lastBoxLocal;
uint64_t lastMonitor = -1;

View File

@ -3,9 +3,11 @@
#include "../../Compositor.hpp"
#include "../../protocols/TextInputV3.hpp"
#include "../../protocols/InputMethodV2.hpp"
#include "../../protocols/core/Compositor.hpp"
CInputMethodRelay::CInputMethodRelay() {
static auto P = g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast<wlr_surface*>(param)); });
static auto P =
g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast<SP<CWLSurfaceResource>>(param)); });
listeners.newTIV3 = PROTO::textInputV3->events.newTextInput.registerListener([this](std::any ti) { onNewTextInput(ti); });
listeners.newIME = PROTO::ime->events.newIME.registerListener([this](std::any ime) { onNewIME(std::any_cast<SP<CInputMethodV2>>(ime)); });
@ -54,17 +56,17 @@ void CInputMethodRelay::onNewIME(SP<CInputMethodV2> pIME) {
return;
for (auto& ti : m_vTextInputs) {
if (ti->client() != wl_resource_get_client(g_pCompositor->m_pLastFocus->resource))
if (ti->client() != g_pCompositor->m_pLastFocus->client())
continue;
if (ti->isV3())
ti->enter(g_pCompositor->m_pLastFocus);
ti->enter(g_pCompositor->m_pLastFocus.lock());
else
ti->onEnabled(g_pCompositor->m_pLastFocus);
ti->onEnabled(g_pCompositor->m_pLastFocus.lock());
}
}
void CInputMethodRelay::setIMEPopupFocus(CInputPopup* pPopup, wlr_surface* pSurface) {
void CInputMethodRelay::setIMEPopupFocus(CInputPopup* pPopup, SP<CWLSurfaceResource> pSurface) {
pPopup->onCommit();
}
@ -125,7 +127,7 @@ void CInputMethodRelay::commitIMEState(CTextInput* pInput) {
pInput->commitStateToIME(m_pIME.lock());
}
void CInputMethodRelay::onKeyboardFocus(wlr_surface* pSurface) {
void CInputMethodRelay::onKeyboardFocus(SP<CWLSurfaceResource> pSurface) {
if (m_pIME.expired())
return;
@ -145,7 +147,7 @@ void CInputMethodRelay::onKeyboardFocus(wlr_surface* pSurface) {
if (!ti->isV3())
continue;
if (ti->client() != wl_resource_get_client(pSurface->resource))
if (ti->client() != pSurface->client())
continue;
ti->enter(pSurface);
@ -161,9 +163,9 @@ CInputPopup* CInputMethodRelay::popupFromCoords(const Vector2D& point) {
return nullptr;
}
CInputPopup* CInputMethodRelay::popupFromSurface(const wlr_surface* surface) {
CInputPopup* CInputMethodRelay::popupFromSurface(const SP<CWLSurfaceResource> surface) {
for (auto& p : m_vIMEPopups) {
if (p->getWlrSurface() == surface)
if (p->getSurface() == surface)
return p.get();
}

View File

@ -26,15 +26,15 @@ class CInputMethodRelay {
void commitIMEState(CTextInput* pInput);
void removeTextInput(CTextInput* pInput);
void onKeyboardFocus(wlr_surface*);
void onKeyboardFocus(SP<CWLSurfaceResource>);
CTextInput* getFocusedTextInput();
void setIMEPopupFocus(CInputPopup*, wlr_surface*);
void setIMEPopupFocus(CInputPopup*, SP<CWLSurfaceResource>);
void removePopup(CInputPopup*);
CInputPopup* popupFromCoords(const Vector2D& point);
CInputPopup* popupFromSurface(const wlr_surface* surface);
CInputPopup* popupFromSurface(const SP<CWLSurfaceResource> surface);
void updateAllPopups();
@ -44,7 +44,7 @@ class CInputMethodRelay {
std::vector<std::unique_ptr<CTextInput>> m_vTextInputs;
std::vector<std::unique_ptr<CInputPopup>> m_vIMEPopups;
wlr_surface* m_pLastKbFocus = nullptr;
WP<CWLSurfaceResource> m_pLastKbFocus;
struct {
CHyprSignalListener newTIV3;
@ -57,6 +57,6 @@ class CInputMethodRelay {
friend class CHyprRenderer;
friend class CInputManager;
friend class CTextInputV1ProtocolManager;
friend struct CTextInput;
friend class CTextInput;
friend class CHyprRenderer;
};

View File

@ -3,13 +3,14 @@
#include "../../config/ConfigValue.hpp"
void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) {
static auto PSWIPE = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe");
static auto PSWIPEFINGERS = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_fingers");
static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new");
static auto PSWIPE = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe");
static auto PSWIPEFINGERS = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_fingers");
static auto PSWIPEMINFINGERS = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_min_fingers");
static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new");
EMIT_HOOK_EVENT_CANCELLABLE("swipeBegin", e);
if (e.fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked())
if ((!*PSWIPEMINFINGERS && e.fingers != *PSWIPEFINGERS) || (*PSWIPEMINFINGERS && e.fingers < *PSWIPEFINGERS) || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked())
return;
int onMonitor = 0;

View File

@ -20,7 +20,7 @@ static void unfocusTool(SP<CTabletTool> tool) {
PROTO::tablet->proximityOut(tool);
}
static void focusTool(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* surf) {
static void focusTool(SP<CTabletTool> tool, SP<CTablet> tablet, SP<CWLSurfaceResource> surf) {
if (tool->getSurface() == surf || !surf)
return;
@ -37,7 +37,7 @@ static void focusTool(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* sur
}
static void refocusTablet(SP<CTablet> tab, SP<CTabletTool> tool, bool motion = false) {
const auto LASTHLSURFACE = CWLSurface::surfaceFromWlr(g_pSeatManager->state.pointerFocus);
const auto LASTHLSURFACE = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock());
if (!LASTHLSURFACE || !tool->active) {
if (tool->getSurface())
@ -57,7 +57,7 @@ static void refocusTablet(SP<CTablet> tab, SP<CTabletTool> tool, bool motion = f
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
focusTool(tool, tab, g_pSeatManager->state.pointerFocus);
focusTool(tool, tab, g_pSeatManager->state.pointerFocus.lock());
if (!motion)
return;

View File

@ -5,6 +5,7 @@
#include "../../Compositor.hpp"
#include "../../protocols/TextInputV3.hpp"
#include "../../protocols/InputMethodV2.hpp"
#include "../../protocols/core/Compositor.hpp"
CTextInput::CTextInput(STextInputV1* ti) : pV1Input(ti) {
ti->pTextInput = this;
@ -56,8 +57,8 @@ void CTextInput::initCallbacks() {
hyprListener_textInputDestroy.removeCallback();
hyprListener_textInputDisable.removeCallback();
hyprListener_textInputEnable.removeCallback();
hyprListener_surfaceDestroyed.removeCallback();
hyprListener_surfaceUnmapped.removeCallback();
listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset();
g_pInputManager->m_sIMERelay.removeTextInput(this);
},
@ -65,7 +66,7 @@ void CTextInput::initCallbacks() {
}
}
void CTextInput::onEnabled(wlr_surface* surfV1) {
void CTextInput::onEnabled(SP<CWLSurfaceResource> surfV1) {
Debug::log(LOG, "TI ENABLE");
if (g_pInputManager->m_sIMERelay.m_pIME.expired()) {
@ -75,7 +76,7 @@ void CTextInput::onEnabled(wlr_surface* surfV1) {
// v1 only, map surface to PTI
if (!isV3()) {
wlr_surface* pSurface = surfV1;
SP<CWLSurfaceResource> pSurface = surfV1;
if (g_pCompositor->m_pLastFocus != pSurface || !pV1Input->active)
return;
@ -97,8 +98,8 @@ void CTextInput::onDisabled() {
if (!isV3())
leave();
hyprListener_surfaceDestroyed.removeCallback();
hyprListener_surfaceUnmapped.removeCallback();
listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset();
g_pInputManager->m_sIMERelay.deactivateIME(this);
}
@ -117,50 +118,44 @@ void CTextInput::onCommit() {
g_pInputManager->m_sIMERelay.commitIMEState(this);
}
void CTextInput::setFocusedSurface(wlr_surface* pSurface) {
void CTextInput::setFocusedSurface(SP<CWLSurfaceResource> pSurface) {
if (pSurface == pFocusedSurface)
return;
pFocusedSurface = pSurface;
hyprListener_surfaceUnmapped.removeCallback();
hyprListener_surfaceDestroyed.removeCallback();
listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset();
if (!pSurface)
return;
hyprListener_surfaceUnmapped.initCallback(
&pSurface->events.unmap,
[this](void* owner, void* data) {
Debug::log(LOG, "Unmap TI owner1");
listeners.surfaceUnmap = pSurface->events.unmap.registerListener([this](std::any d) {
Debug::log(LOG, "Unmap TI owner1");
if (enterLocks)
enterLocks--;
pFocusedSurface = nullptr;
hyprListener_surfaceUnmapped.removeCallback();
hyprListener_surfaceDestroyed.removeCallback();
},
this, "CTextInput");
if (enterLocks)
enterLocks--;
pFocusedSurface.reset();
listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset();
});
hyprListener_surfaceDestroyed.initCallback(
&pSurface->events.destroy,
[this](void* owner, void* data) {
Debug::log(LOG, "destroy TI owner1");
listeners.surfaceDestroy = pSurface->events.destroy.registerListener([this](std::any d) {
Debug::log(LOG, "Destroy TI owner1");
if (enterLocks)
enterLocks--;
pFocusedSurface = nullptr;
hyprListener_surfaceUnmapped.removeCallback();
hyprListener_surfaceDestroyed.removeCallback();
},
this, "CTextInput");
if (enterLocks)
enterLocks--;
pFocusedSurface.reset();
listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset();
});
}
bool CTextInput::isV3() {
return !pV1Input;
}
void CTextInput::enter(wlr_surface* pSurface) {
void CTextInput::enter(SP<CWLSurfaceResource> pSurface) {
if (!pSurface || !pSurface->mapped)
return;
@ -182,7 +177,7 @@ void CTextInput::enter(wlr_surface* pSurface) {
if (isV3())
pV3Input->enter(pSurface);
else {
zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->resource);
zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->getResource()->resource());
pV1Input->active = true;
}
@ -211,8 +206,8 @@ void CTextInput::leave() {
g_pInputManager->m_sIMERelay.deactivateIME(this);
}
wlr_surface* CTextInput::focusedSurface() {
return pFocusedSurface;
SP<CWLSurfaceResource> CTextInput::focusedSurface() {
return pFocusedSurface.lock();
}
wl_client* CTextInput::client() {

View File

@ -6,12 +6,12 @@
#include "../../helpers/signal/Listener.hpp"
#include <memory>
struct wlr_surface;
struct wl_client;
struct STextInputV1;
class CTextInputV3;
class CInputMethodV2;
class CWLSurfaceResource;
class CTextInput {
public:
@ -19,43 +19,43 @@ class CTextInput {
CTextInput(STextInputV1* ti);
~CTextInput();
bool isV3();
void enter(wlr_surface* pSurface);
void leave();
void tiV1Destroyed();
wl_client* client();
void commitStateToIME(SP<CInputMethodV2> ime);
void updateIMEState(SP<CInputMethodV2> ime);
bool isV3();
void enter(SP<CWLSurfaceResource> pSurface);
void leave();
void tiV1Destroyed();
wl_client* client();
void commitStateToIME(SP<CInputMethodV2> ime);
void updateIMEState(SP<CInputMethodV2> ime);
void onEnabled(wlr_surface* surfV1 = nullptr);
void onDisabled();
void onCommit();
void onEnabled(SP<CWLSurfaceResource> surfV1 = nullptr);
void onDisabled();
void onCommit();
bool hasCursorRectangle();
CBox cursorBox();
bool hasCursorRectangle();
CBox cursorBox();
wlr_surface* focusedSurface();
SP<CWLSurfaceResource> focusedSurface();
private:
void setFocusedSurface(wlr_surface* pSurface);
void initCallbacks();
void setFocusedSurface(SP<CWLSurfaceResource> pSurface);
void initCallbacks();
wlr_surface* pFocusedSurface = nullptr;
int enterLocks = 0;
WP<CTextInputV3> pV3Input;
STextInputV1* pV1Input = nullptr;
WP<CWLSurfaceResource> pFocusedSurface;
int enterLocks = 0;
WP<CTextInputV3> pV3Input;
STextInputV1* pV1Input = nullptr;
DYNLISTENER(textInputEnable);
DYNLISTENER(textInputDisable);
DYNLISTENER(textInputCommit);
DYNLISTENER(textInputDestroy);
DYNLISTENER(surfaceUnmapped);
DYNLISTENER(surfaceDestroyed);
struct {
CHyprSignalListener enable;
CHyprSignalListener disable;
CHyprSignalListener commit;
CHyprSignalListener destroy;
CHyprSignalListener surfaceUnmap;
CHyprSignalListener surfaceDestroy;
} listeners;
};

View File

@ -77,7 +77,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) {
} else
return; // oops, nothing found.
g_pSeatManager->sendTouchDown(m_sTouchData.touchFocusSurface, e.timeMs, e.touchID, local);
g_pSeatManager->sendTouchDown(m_sTouchData.touchFocusSurface.lock(), e.timeMs, e.touchID, local);
PROTO::idle->onActivity();
}

View File

@ -18,6 +18,12 @@ executable('Hyprland', src,
dependency('xkbcommon'),
dependency('libinput'),
xcb_dep,
xcb_composite_dep,
xcb_errors_dep,
xcb_icccm_dep,
xcb_render_dep,
xcb_res_dep,
xcb_xfixes_dep,
backtrace_dep,
epoll_dep,
udis86,

View File

@ -2,10 +2,11 @@
#include <algorithm>
#include "../desktop/WLSurface.hpp"
#include "../render/Renderer.hpp"
#include "core/Compositor.hpp"
#define LOGM PROTO::alphaModifier->protoLog
CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surface* surface_) : resource(resource_), pSurface(surface_) {
CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, SP<CWLSurfaceResource> surface_) : resource(resource_), pSurface(surface_) {
if (!resource->resource())
return;
@ -18,8 +19,7 @@ CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surf
setSurfaceAlpha(1.F);
});
hyprListener_surfaceDestroy.initCallback(
&surface_->events.destroy, [this](void* owner, void* data) { onSurfaceDestroy(); }, this, "CAlphaModifier");
listeners.destroySurface = pSurface->events.destroy.registerListener([this](std::any d) { onSurfaceDestroy(); });
resource->setSetMultiplier([this](CWpAlphaModifierSurfaceV1* mod, uint32_t alpha) {
if (!pSurface) {
@ -35,19 +35,19 @@ CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surf
}
CAlphaModifier::~CAlphaModifier() {
hyprListener_surfaceDestroy.removeCallback();
;
}
bool CAlphaModifier::good() {
return resource->resource();
}
wlr_surface* CAlphaModifier::getSurface() {
return pSurface;
SP<CWLSurfaceResource> CAlphaModifier::getSurface() {
return pSurface.lock();
}
void CAlphaModifier::setSurfaceAlpha(float a) {
CWLSurface* surf = CWLSurface::surfaceFromWlr(pSurface);
auto surf = CWLSurface::fromResource(pSurface.lock());
if (!surf) {
LOGM(ERR, "CAlphaModifier::setSurfaceAlpha: No CWLSurface for given surface??");
@ -62,8 +62,7 @@ void CAlphaModifier::setSurfaceAlpha(float a) {
}
void CAlphaModifier::onSurfaceDestroy() {
hyprListener_surfaceDestroy.removeCallback();
pSurface = nullptr;
pSurface.reset();
}
CAlphaModifierProtocol::CAlphaModifierProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
@ -75,7 +74,7 @@ void CAlphaModifierProtocol::bindManager(wl_client* client, void* data, uint32_t
RESOURCE->setOnDestroy([this](CWpAlphaModifierV1* p) { this->onManagerResourceDestroy(p->resource()); });
RESOURCE->setDestroy([this](CWpAlphaModifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
RESOURCE->setGetSurface([this](CWpAlphaModifierV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetSurface(pMgr, id, wlr_surface_from_resource(surface)); });
RESOURCE->setGetSurface([this](CWpAlphaModifierV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetSurface(pMgr, id, CWLSurfaceResource::fromResource(surface)); });
}
void CAlphaModifierProtocol::onManagerResourceDestroy(wl_resource* res) {
@ -83,29 +82,11 @@ void CAlphaModifierProtocol::onManagerResourceDestroy(wl_resource* res) {
}
void CAlphaModifierProtocol::destroyModifier(CAlphaModifier* modifier) {
if (modifier->getSurface())
m_mAlphaModifiers.erase(modifier->getSurface());
else {
// find it first
wlr_surface* deadptr = nullptr;
for (auto& [k, v] : m_mAlphaModifiers) {
if (v.get() == modifier) {
deadptr = k;
break;
}
}
if (!deadptr) {
LOGM(ERR, "CAlphaModifierProtocol::destroyModifier: dead resource but no deadptr???");
return;
}
m_mAlphaModifiers.erase(deadptr);
}
std::erase_if(m_mAlphaModifiers, [](const auto& e) { return e.first.expired(); });
}
void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface) {
if (m_mAlphaModifiers.contains(surface)) {
void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
if (std::find_if(m_mAlphaModifiers.begin(), m_mAlphaModifiers.end(), [surface](const auto& e) { return e.first == surface; }) != m_mAlphaModifiers.end()) {
LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface);
pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present");
return;

View File

@ -5,23 +5,28 @@
#include <unordered_map>
#include "WaylandProtocol.hpp"
#include "alpha-modifier-v1.hpp"
#include "../helpers/signal/Listener.hpp"
class CWLSurfaceResource;
class CAlphaModifier {
public:
CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surface* surface);
CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, SP<CWLSurfaceResource> surface);
~CAlphaModifier();
bool good();
wlr_surface* getSurface();
void onSurfaceDestroy();
bool good();
SP<CWLSurfaceResource> getSurface();
void onSurfaceDestroy();
private:
SP<CWpAlphaModifierSurfaceV1> resource;
wlr_surface* pSurface = nullptr;
WP<CWLSurfaceResource> pSurface;
void setSurfaceAlpha(float a);
DYNLISTENER(surfaceDestroy);
struct {
CHyprSignalListener destroySurface;
} listeners;
};
class CAlphaModifierProtocol : public IWaylandProtocol {
@ -33,15 +38,15 @@ class CAlphaModifierProtocol : public IWaylandProtocol {
private:
void onManagerResourceDestroy(wl_resource* res);
void destroyModifier(CAlphaModifier* decoration);
void onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface);
void onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface);
//
std::vector<UP<CWpAlphaModifierV1>> m_vManagers;
std::unordered_map<wlr_surface*, UP<CAlphaModifier>> m_mAlphaModifiers; // xdg_toplevel -> deco
std::vector<UP<CWpAlphaModifierV1>> m_vManagers;
std::unordered_map<WP<CWLSurfaceResource>, UP<CAlphaModifier>> m_mAlphaModifiers; // xdg_toplevel -> deco
friend class CAlphaModifier;
};
namespace PROTO {
inline UP<CAlphaModifierProtocol> alphaModifier;
};
};

View File

@ -1,21 +1,21 @@
#include "FocusGrab.hpp"
#include "Compositor.hpp"
#include "../Compositor.hpp"
#include <hyprland-focus-grab-v1.hpp>
#include "../managers/input/InputManager.hpp"
#include "../managers/SeatManager.hpp"
#include "core/Compositor.hpp"
#include <cstdint>
#include <memory>
#include <wayland-server.h>
#define LOGM PROTO::focusGrab->protoLog
CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface) {
hyprListener_surfaceDestroy.initCallback(
&surface->events.destroy, [=](void*, void*) { grab->eraseSurface(surface); }, this, "CFocusGrab");
CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SP<CWLSurfaceResource> surface) {
listeners.destroy = surface->events.destroy.registerListener([=](std::any d) { grab->eraseSurface(surface); });
}
CFocusGrabSurfaceState::~CFocusGrabSurfaceState() {
hyprListener_surfaceDestroy.removeCallback();
;
}
CFocusGrab::CFocusGrab(SP<CHyprlandFocusGrabV1> resource_) : resource(resource_) {
@ -29,8 +29,8 @@ CFocusGrab::CFocusGrab(SP<CHyprlandFocusGrabV1> resource_) : resource(resource_)
resource->setDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); });
resource->setOnDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); });
resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(wlr_surface_from_resource(surface)); });
resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(wlr_surface_from_resource(surface)); });
resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(CWLSurfaceResource::fromResource(surface)); });
resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(CWLSurfaceResource::fromResource(surface)); });
resource->setCommit([this](CHyprlandFocusGrabV1* pMgr) { commit(); });
}
@ -42,8 +42,8 @@ bool CFocusGrab::good() {
return resource->resource();
}
bool CFocusGrab::isSurfaceComitted(wlr_surface* surface) {
auto iter = m_mSurfaces.find(surface);
bool CFocusGrab::isSurfaceComitted(SP<CWLSurfaceResource> surface) {
auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& o) { return o.first == surface; });
if (iter == m_mSurfaces.end())
return false;
@ -77,14 +77,14 @@ void CFocusGrab::finish(bool sendCleared) {
}
}
void CFocusGrab::addSurface(wlr_surface* surface) {
auto iter = m_mSurfaces.find(surface);
void CFocusGrab::addSurface(SP<CWLSurfaceResource> surface) {
auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& e) { return e.first == surface; });
if (iter == m_mSurfaces.end()) {
m_mSurfaces.emplace(surface, std::make_unique<CFocusGrabSurfaceState>(this, surface));
}
}
void CFocusGrab::removeSurface(wlr_surface* surface) {
void CFocusGrab::removeSurface(SP<CWLSurfaceResource> surface) {
auto iter = m_mSurfaces.find(surface);
if (iter != m_mSurfaces.end()) {
if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) {
@ -94,20 +94,20 @@ void CFocusGrab::removeSurface(wlr_surface* surface) {
}
}
void CFocusGrab::eraseSurface(wlr_surface* surface) {
void CFocusGrab::eraseSurface(SP<CWLSurfaceResource> surface) {
removeSurface(surface);
commit(true);
}
void CFocusGrab::refocusKeyboard() {
auto keyboardSurface = g_pSeatManager->state.keyboardFocus;
if (keyboardSurface != nullptr && isSurfaceComitted(keyboardSurface))
if (keyboardSurface && isSurfaceComitted(keyboardSurface.lock()))
return;
wlr_surface* surface = nullptr;
SP<CWLSurfaceResource> surface = nullptr;
for (auto& [surf, state] : m_mSurfaces) {
if (state->state == CFocusGrabSurfaceState::Comitted) {
surface = surf;
surface = surf.lock();
break;
}
}
@ -124,14 +124,14 @@ void CFocusGrab::commit(bool removeOnly) {
for (auto iter = m_mSurfaces.begin(); iter != m_mSurfaces.end();) {
switch (iter->second->state) {
case CFocusGrabSurfaceState::PendingRemoval:
grab->remove(iter->first);
grab->remove(iter->first.lock());
iter = m_mSurfaces.erase(iter);
surfacesChanged = true;
continue;
case CFocusGrabSurfaceState::PendingAddition:
if (!removeOnly) {
iter->second->state = CFocusGrabSurfaceState::Comitted;
grab->add(iter->first);
grab->add(iter->first.lock());
surfacesChanged = true;
anyComitted = true;
}

View File

@ -6,13 +6,15 @@
#include <cstdint>
#include <unordered_map>
#include <vector>
#include "../helpers/signal/Listener.hpp"
class CFocusGrab;
class CSeatGrab;
class CWLSurfaceResource;
class CFocusGrabSurfaceState {
public:
CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface);
CFocusGrabSurfaceState(CFocusGrab* grab, SP<CWLSurfaceResource> surface);
~CFocusGrabSurfaceState();
enum State {
@ -22,7 +24,9 @@ class CFocusGrabSurfaceState {
} state = PendingAddition;
private:
DYNLISTENER(surfaceDestroy);
struct {
CHyprSignalListener destroy;
} listeners;
};
class CFocusGrab {
@ -31,23 +35,23 @@ class CFocusGrab {
~CFocusGrab();
bool good();
bool isSurfaceComitted(wlr_surface* surface);
bool isSurfaceComitted(SP<CWLSurfaceResource> surface);
void start();
void finish(bool sendCleared);
private:
void addSurface(wlr_surface* surface);
void removeSurface(wlr_surface* surface);
void eraseSurface(wlr_surface* surface);
void refocusKeyboard();
void commit(bool removeOnly = false);
void addSurface(SP<CWLSurfaceResource> surface);
void removeSurface(SP<CWLSurfaceResource> surface);
void eraseSurface(SP<CWLSurfaceResource> surface);
void refocusKeyboard();
void commit(bool removeOnly = false);
SP<CHyprlandFocusGrabV1> resource;
std::unordered_map<wlr_surface*, UP<CFocusGrabSurfaceState>> m_mSurfaces;
SP<CSeatGrab> grab;
SP<CHyprlandFocusGrabV1> resource;
std::unordered_map<WP<CWLSurfaceResource>, UP<CFocusGrabSurfaceState>> m_mSurfaces;
SP<CSeatGrab> grab;
bool m_bGrabActive = false;
bool m_bGrabActive = false;
DYNLISTENER(pointerGrabStarted);
DYNLISTENER(keyboardGrabStarted);

View File

@ -1,6 +1,8 @@
#include "ForeignToplevelWlr.hpp"
#include <algorithm>
#include "../Compositor.hpp"
#include "protocols/core/Output.hpp"
#include "render/Renderer.hpp"
#define LOGM PROTO::foreignToplevelWlr->protoLog
@ -36,7 +38,21 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP<CZwlrForeignToplevelHand
return;
}
g_pCompositor->setWindowFullscreen(PWINDOW, true);
if (output) {
const auto wpMonitor = CWLOutputResource::fromResource(output)->monitor;
if (!wpMonitor.expired()) {
const auto monitor = wpMonitor.lock();
if (PWINDOW->m_pWorkspace != monitor->activeWorkspace) {
g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, monitor->activeWorkspace);
g_pCompositor->setActiveMonitor(monitor.get());
}
}
}
g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL);
g_pHyprRenderer->damageWindow(PWINDOW);
});
resource->setUnsetFullscreen([this](CZwlrForeignToplevelHandleV1* p) {
@ -372,4 +388,4 @@ PHLWINDOW CForeignToplevelWlrProtocol::windowFromHandleResource(wl_resource* res
}
return nullptr;
}
}

View File

@ -1,13 +1,9 @@
#include "FractionalScale.hpp"
#include <algorithm>
#include "core/Compositor.hpp"
#define LOGM PROTO::fractional->protoLog
static void onWlrSurfaceDestroy(void* owner, void* data) {
const auto SURF = (wlr_surface*)owner;
PROTO::fractional->onSurfaceDestroy(SURF);
}
CFractionalScaleProtocol::CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
@ -18,7 +14,7 @@ void CFractionalScaleProtocol::bindManager(wl_client* client, void* data, uint32
RESOURCE->setDestroy([this](CWpFractionalScaleManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
RESOURCE->setGetFractionalScale(
[this](CWpFractionalScaleManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetFractionalScale(pMgr, id, wlr_surface_from_resource(surface)); });
[this](CWpFractionalScaleManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetFractionalScale(pMgr, id, CWLSurfaceResource::fromResource(surface)); });
}
void CFractionalScaleProtocol::removeAddon(CFractionalScaleAddon* addon) {
@ -29,11 +25,13 @@ void CFractionalScaleProtocol::onManagerResourceDestroy(wl_resource* res) {
std::erase_if(m_vManagers, [res](const auto& other) { return other->resource() == res; });
}
void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, wlr_surface* surface) {
if (m_mAddons.contains(surface)) {
LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface);
pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists");
return;
void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
for (auto& [k, v] : m_mAddons) {
if (k == surface) {
LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface);
pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists");
return;
}
}
const auto PADDON =
@ -48,35 +46,22 @@ void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1*
PADDON->resource->setOnDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); });
PADDON->resource->setDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); });
if (!m_mSurfaceScales.contains(surface))
m_mSurfaceScales[surface] = 1.F;
if (std::find_if(m_mSurfaceScales.begin(), m_mSurfaceScales.end(), [surface](const auto& e) { return e.first == surface; }) == m_mSurfaceScales.end())
m_mSurfaceScales.emplace(surface, 1.F);
PADDON->setScale(m_mSurfaceScales[surface]);
registerSurface(surface);
PADDON->setScale(m_mSurfaceScales.at(surface));
// clean old
std::erase_if(m_mSurfaceScales, [](const auto& e) { return e.first.expired(); });
}
void CFractionalScaleProtocol::sendScale(wlr_surface* surf, const float& scale) {
void CFractionalScaleProtocol::sendScale(SP<CWLSurfaceResource> surf, const float& scale) {
m_mSurfaceScales[surf] = scale;
if (m_mAddons.contains(surf))
m_mAddons[surf]->setScale(scale);
registerSurface(surf);
}
void CFractionalScaleProtocol::registerSurface(wlr_surface* surf) {
if (m_mSurfaceDestroyListeners.contains(surf))
return;
m_mSurfaceDestroyListeners[surf].hyprListener_surfaceDestroy.initCallback(&surf->events.destroy, ::onWlrSurfaceDestroy, surf, "FractionalScale");
}
void CFractionalScaleProtocol::onSurfaceDestroy(wlr_surface* surf) {
m_mSurfaceDestroyListeners.erase(surf);
m_mSurfaceScales.erase(surf);
if (m_mAddons.contains(surf))
m_mAddons[surf]->onSurfaceDestroy();
}
CFractionalScaleAddon::CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, wlr_surface* surf_) : resource(resource_), surface(surf_) {
CFractionalScaleAddon::CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, SP<CWLSurfaceResource> surf_) : resource(resource_), surface(surf_) {
resource->setDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); });
resource->setOnDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); });
}
@ -93,6 +78,6 @@ bool CFractionalScaleAddon::good() {
return resource->resource();
}
wlr_surface* CFractionalScaleAddon::surf() {
return surface;
SP<CWLSurfaceResource> CFractionalScaleAddon::surf() {
return surface.lock();
}

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