Merge branch 'hyprwm:main' into main

This commit is contained in:
Amrit Srivastava 2024-07-27 15:04:30 +00:00 committed by GitHub
commit 750d976e06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
172 changed files with 6987 additions and 5235 deletions

View file

@ -34,6 +34,7 @@ runs:
libglvnd \ libglvnd \
libinput \ libinput \
libliftoff \ libliftoff \
libxcursor \
libxcvt \ libxcvt \
libxfont2 \ libxfont2 \
libxkbcommon \ libxkbcommon \
@ -73,6 +74,11 @@ runs:
run: | run: |
git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build
- name: Get aquamarine-git
shell: bash
run: |
git clone https://github.com/hyprwm/aquamarine && cd aquamarine && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target aquamarine && cmake --install build
- name: Get Xorg pacman pkgs - name: Get Xorg pacman pkgs
shell: bash shell: bash
if: inputs.INSTALL_XORG_PKGS == 'true' if: inputs.INSTALL_XORG_PKGS == 'true'

8
.gitignore vendored
View file

@ -7,6 +7,9 @@ cmake_install.cmake
install_manifest.txt install_manifest.txt
compile_commands.json compile_commands.json
CTestTestfile.cmake CTestTestfile.cmake
CPackConfig.cmake
CPackSourceConfig.cmake
hyprland.pc
_deps _deps
build/ build/
@ -15,6 +18,9 @@ result*
/.idea/ /.idea/
.envrc .envrc
.cache .cache
.direnv
/.cmake/
/.worktree/
*.o *.o
protocols/*.c* protocols/*.c*
@ -31,5 +37,3 @@ gmon.out
PKGBUILD PKGBUILD
src/version.h src/version.h
.direnv

4
.gitmodules vendored
View file

@ -7,7 +7,3 @@
[submodule "subprojects/tracy"] [submodule "subprojects/tracy"]
path = subprojects/tracy path = subprojects/tracy
url = https://github.com/wolfpld/tracy url = https://github.com/wolfpld/tracy
[submodule "subprojects/wlroots-hyprland"]
path = subprojects/wlroots-hyprland
url = https://github.com/hyprwm/wlroots-hyprland
ignore = dirty

View file

@ -1,17 +1,16 @@
cmake_minimum_required(VERSION 3.27) cmake_minimum_required(VERSION 3.27)
include(CheckIncludeFile) include(CheckIncludeFile)
include(ExternalProject)
include(GNUInstallDirs) include(GNUInstallDirs)
# Get version # Get version
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/props.json PROPS) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
string(JSON VER GET ${PROPS} version) string(STRIP ${VER_RAW} VER)
project(Hyprland project(
DESCRIPTION "A Modern C++ Wayland Compositor" Hyprland
VERSION ${VER} DESCRIPTION "A Modern C++ Wayland Compositor"
) VERSION ${VER})
set(HYPRLAND_VERSION ${VER}) set(HYPRLAND_VERSION ${VER})
set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(PREFIX ${CMAKE_INSTALL_PREFIX})
@ -22,49 +21,32 @@ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
message(STATUS "Gathering git info") message(STATUS "Gathering git info")
# Get git info # Get git info hash and branch
# hash and branch execute_process(COMMAND ./scripts/generateVersion.sh
execute_process( WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# udis # udis
add_subdirectory("subprojects/udis86") add_subdirectory("subprojects/udis86")
# wlroots
message(STATUS "Setting up wlroots")
if(CMAKE_BUILD_TYPE) if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
if(BUILDTYPE_LOWER STREQUAL "release") if(BUILDTYPE_LOWER STREQUAL "release")
# Pass. # Pass.
elseif(BUILDTYPE_LOWER STREQUAL "debug") elseif(BUILDTYPE_LOWER STREQUAL "debug")
# Pass. # Pass.
elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo") elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
set(BUILDTYPE_LOWER "debugoptimized") set(BUILDTYPE_LOWER "debugoptimized")
elseif(BUILDTYPE_LOWER STREQUAL "minsizerel") elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
set(BUILDTYPE_LOWER "minsize") set(BUILDTYPE_LOWER "minsize")
elseif(BUILDTYPE_LOWER STREQUAL "none") elseif(BUILDTYPE_LOWER STREQUAL "none")
set(BUILDTYPE_LOWER "plain") set(BUILDTYPE_LOWER "plain")
else() else()
set(BUILDTYPE_LOWER "release")
endif()
else()
set(BUILDTYPE_LOWER "release") set(BUILDTYPE_LOWER "release")
endif()
else()
set(BUILDTYPE_LOWER "release")
endif() endif()
ExternalProject_Add(
wlroots-hyprland
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland
CONFIGURE_COMMAND meson setup --reconfigure --clearcache build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$<IF:$<BOOL:${NO_XWAYLAND}>,disabled,enabled> -Dexamples=false -Drenderers=gles2 -Dbackends=drm,libinput $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none>
BUILD_COMMAND ninja -C build
BUILD_ALWAYS true
BUILD_IN_SOURCE true
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a
INSTALL_COMMAND echo "wlroots-hyprland: install not needed"
)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner) pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner)
@ -74,25 +56,24 @@ message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Configuring Hyprland in Debug with CMake") message(STATUS "Configuring Hyprland in Debug with CMake")
add_compile_definitions(HYPRLAND_DEBUG) add_compile_definitions(HYPRLAND_DEBUG)
else() else()
add_compile_options(-O3) add_compile_options(-O3)
message(STATUS "Configuring Hyprland in Release with CMake") message(STATUS "Configuring Hyprland in Release with CMake")
endif() endif()
include_directories( include_directories(. "src/" "subprojects/udis86/" "protocols/")
.
"src/"
"subprojects/wlroots-hyprland/include/"
"subprojects/wlroots-hyprland/build/include/"
"subprojects/udis86/"
"protocols/")
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
add_compile_definitions(WLR_USE_UNSTABLE) add_compile_options(
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wall
-Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith -Wextra
-fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) -Wno-unused-parameter
-Wno-unused-value
-Wno-missing-field-initializers
-Wno-narrowing
-Wno-pointer-arith
-fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=)
set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE) set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
@ -102,19 +83,39 @@ message(STATUS "Checking deps...")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
if(LEGACY_RENDERER) if(LEGACY_RENDERER)
set(GLES_VERSION "GLES2") set(GLES_VERSION "GLES2")
else() else()
set(GLES_VERSION "GLES3") set(GLES_VERSION "GLES3")
endif() endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(deps REQUIRED IMPORTED_TARGET pkg_check_modules(
xkbcommon uuid deps
wayland-server wayland-client wayland-cursor wayland-protocols REQUIRED
cairo pango pangocairo pixman-1 IMPORTED_TARGET
libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm aquamarine
hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.5 xkbcommon
) uuid
wayland-server
wayland-client
wayland-cursor
wayland-protocols
cairo
pango
pangocairo
pixman-1
xcursor
libdrm
libinput
hwdata
libseat
libdisplay-info
libliftoff
libudev
gbm
hyprlang>=0.3.2
hyprcursor>=0.1.7
hyprutils>=0.2.0)
find_package(hyprwayland-scanner 0.3.10 REQUIRED) find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@ -122,85 +123,97 @@ file(GLOB_RECURSE SRCFILES "src/*.cpp")
set(TRACY_CPP_FILES "") set(TRACY_CPP_FILES "")
if(USE_TRACY) if(USE_TRACY)
set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp") set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES}) message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
endif() endif()
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
add_dependencies(Hyprland wlroots-hyprland)
set(USE_GPROF ON) set(USE_GPROF ON)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Setting debug flags") message(STATUS "Setting debug flags")
if (WITH_ASAN) if(WITH_ASAN)
message(STATUS "Enabling ASan") message(STATUS "Enabling ASan")
target_link_libraries(Hyprland asan) target_link_libraries(Hyprland asan)
target_compile_options(Hyprland PUBLIC -fsanitize=address) target_compile_options(Hyprland PUBLIC -fsanitize=address)
endif()
if(USE_TRACY)
message(STATUS "Tracy is turned on")
option(TRACY_ENABLE "" ON)
option(TRACY_ON_DEMAND "" ON)
add_subdirectory(subprojects/tracy)
target_link_libraries(Hyprland Tracy::TracyClient)
if(USE_TRACY_GPU)
message(STATUS "Tracy GPU Profiling is turned on")
add_compile_definitions(USE_TRACY_GPU)
endif() endif()
endif()
if(USE_TRACY) add_compile_options(-fno-pie -fno-builtin)
message(STATUS "Tracy is turned on") add_link_options(-no-pie -fno-builtin)
if(USE_GPROF)
option( TRACY_ENABLE "" ON) add_compile_options(-pg)
option( TRACY_ON_DEMAND "" ON) add_link_options(-pg)
add_subdirectory (subprojects/tracy) endif()
target_link_libraries(Hyprland Tracy::TracyClient)
if(USE_TRACY_GPU)
message(STATUS "Tracy GPU Profiling is turned on")
add_compile_definitions(USE_TRACY_GPU)
endif()
endif()
add_compile_options(-fno-pie -fno-builtin)
add_link_options(-no-pie -fno-builtin)
if(USE_GPROF)
add_compile_options(-pg)
add_link_options(-pg)
endif()
endif() endif()
check_include_file("execinfo.h" EXECINFOH) check_include_file("execinfo.h" EXECINFOH)
if(EXECINFOH) if(EXECINFOH)
message(STATUS "Configuration supports execinfo") message(STATUS "Configuration supports execinfo")
add_compile_definitions(HAS_EXECINFO) add_compile_definitions(HAS_EXECINFO)
endif() endif()
include(CheckLibraryExists) include(CheckLibraryExists)
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO) check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
if(HAVE_LIBEXECINFO) if(HAVE_LIBEXECINFO)
target_link_libraries(Hyprland execinfo) target_link_libraries(Hyprland execinfo)
endif() endif()
check_include_file("sys/timerfd.h" HAS_TIMERFD) check_include_file("sys/timerfd.h" HAS_TIMERFD)
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim) pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
if(NOT HAS_TIMERFD AND epoll_FOUND) if(NOT HAS_TIMERFD AND epoll_FOUND)
target_link_libraries(Hyprland PkgConfig::epoll) target_link_libraries(Hyprland PkgConfig::epoll)
endif() endif()
if(LEGACY_RENDERER) if(LEGACY_RENDERER)
message(STATUS "Using the legacy GLES2 renderer!") message(STATUS "Using the legacy GLES2 renderer!")
add_compile_definitions(LEGACY_RENDERER) add_compile_definitions(LEGACY_RENDERER)
endif() endif()
if(NO_XWAYLAND) if(NO_XWAYLAND)
message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!") message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
add_compile_definitions(NO_XWAYLAND) add_compile_definitions(NO_XWAYLAND)
else() else()
message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...") 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 xcb-errors) pkg_check_modules(
target_link_libraries(Hyprland PkgConfig::xdeps) 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)
endif() endif()
if(NO_SYSTEMD) if(NO_SYSTEMD)
message(STATUS "SYSTEMD support is disabled...") message(STATUS "SYSTEMD support is disabled...")
else() else()
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
add_compile_definitions(USES_SYSTEMD) add_compile_definitions(USES_SYSTEMD)
endif() endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})
@ -209,7 +222,8 @@ include(CPack)
message(STATUS "Setting precompiled headers") message(STATUS "Setting precompiled headers")
target_precompile_headers(Hyprland PRIVATE $<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>) target_precompile_headers(Hyprland PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
message(STATUS "Setting link libraries") message(STATUS "Setting link libraries")
@ -219,103 +233,114 @@ target_link_libraries(Hyprland rt PkgConfig::deps)
add_custom_target(generate-protocol-headers) add_custom_target(generate-protocol-headers)
function(protocol protoPath protoName external) function(protocol protoPath protoName external)
if (external) if(external)
set(path ${CMAKE_SOURCE_DIR}/${protoPath}) set(path ${CMAKE_SOURCE_DIR}/${protoPath})
else() else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif() endif()
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h
COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h COMMAND ${WaylandScanner} server-header ${path}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} protocols/${protoName}-protocol.h
) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c
COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c COMMAND ${WaylandScanner} private-code ${path}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 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(
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) 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() endfunction()
function(protocolNew protoPath protoName external) function(protocolnew protoPath protoName external)
if (external) if(external)
set(path ${CMAKE_SOURCE_DIR}/${protoPath}) set(path ${CMAKE_SOURCE_DIR}/${protoPath})
else() else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif() endif()
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/ COMMAND hyprwayland-scanner ${path}/${protoName}.xml
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/protocols/
) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
target_sources(Hyprland PRIVATE protocols/${protoName}.cpp protocols/${protoName}.hpp) target_sources(Hyprland PRIVATE protocols/${protoName}.cpp
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp) protocols/${protoName}.hpp)
target_sources(generate-protocol-headers
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
endfunction() endfunction()
function(protocolWayland) function(protocolWayland)
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ COMMAND hyprwayland-scanner --wayland-enums
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) target_sources(generate-protocol-headers
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
endfunction() endfunction()
target_link_libraries(Hyprland target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads
${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a libudis86 uuid)
OpenGL::EGL
OpenGL::GL
Threads::Threads
libudis86
uuid
)
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) protocol(
protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) "subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml"
protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) "hyprland-global-shortcuts-v1" true)
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) protocol(
protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) "unstable/text-input/text-input-unstable-v1.xml"
protocolNew("protocols" "wlr-output-power-management-unstable-v1" true) "text-input-unstable-v1" false)
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() protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-toplevel-export-v1" true)
protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
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)
protocolnew("staging/drm-lease" "drm-lease-v1" false)
protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolwayland()
# tools # tools
add_subdirectory(hyprctl) add_subdirectory(hyprctl)
@ -324,12 +349,12 @@ add_subdirectory(hyprpm)
# binary and symlink # binary and symlink
install(TARGETS Hyprland) install(TARGETS Hyprland)
install(CODE "execute_process( \ install(
CODE "execute_process( \
COMMAND ${CMAKE_COMMAND} -E create_symlink \ COMMAND ${CMAKE_COMMAND} -E create_symlink \
${CMAKE_INSTALL_BINDIR}/Hyprland \ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
${CMAKE_INSTALL_BINDIR}/hyprland ${CMAKE_INSTALL_FULL_BINDIR}/hyprland
)" )")
)
# session file # session file
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
@ -337,8 +362,7 @@ install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
# wallpapers # wallpapers
file(GLOB_RECURSE WALLPAPERS "assets/wall*") file(GLOB_RECURSE WALLPAPERS "assets/wall*")
install(FILES ${WALLPAPERS} install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland)
DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland)
# default config # default config
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf
@ -350,34 +374,24 @@ install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf
# man pages # man pages
file(GLOB_RECURSE MANPAGES "docs/*.1") file(GLOB_RECURSE MANPAGES "docs/*.1")
install(FILES ${MANPAGES} install(FILES ${MANPAGES} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
# pkgconfig entry # pkgconfig entry
install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
# wlroots headers
set(HEADERS_WLR "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/include/wlr")
install(DIRECTORY ${HEADERS_WLR}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING PATTERN "*.h")
# config.h and version.h
set(HEADERS_WLR_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/build/include/wlr")
install(DIRECTORY ${HEADERS_WLR_ROOT}/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland/wlr
FILES_MATCHING PATTERN "*.h")
# protocol headers # protocol headers
set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols") set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols")
install(DIRECTORY ${HEADERS_PROTO} install(
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland DIRECTORY ${HEADERS_PROTO}
FILES_MATCHING PATTERN "*.h*") DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING
PATTERN "*.h*")
# hyprland headers # hyprland headers
set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src") set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src")
install(DIRECTORY ${HEADERS_SRC} install(
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland DIRECTORY ${HEADERS_SRC}
FILES_MATCHING PATTERN "*.h*") DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING
PATTERN "*.h*")

View file

@ -27,7 +27,6 @@ nopch:
clear: clear:
rm -rf build rm -rf build
rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp
rm -rf ./subprojects/wlroots-hyprland/build
all: all:
$(MAKE) clear $(MAKE) clear
@ -50,14 +49,11 @@ installheaders:
rm -fr ${PREFIX}/include/hyprland rm -fr ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland/protocols mkdir -p ${PREFIX}/include/hyprland/protocols
mkdir -p ${PREFIX}/include/hyprland/wlr
mkdir -p ${PREFIX}/share/pkgconfig mkdir -p ${PREFIX}/share/pkgconfig
cmake --build ./build --config Release --target generate-protocol-headers cmake --build ./build --config Release --target generate-protocol-headers
find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland 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 ../../../..
cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
@ -88,7 +84,7 @@ asan:
@pidof Hyprland > /dev/null && exit 1 || echo "" @pidof Hyprland > /dev/null && exit 1 || echo ""
rm -rf ./wayland rm -rf ./wayland
git reset --hard #git reset --hard
@echo -en "If you want to apply a patch, input its path (leave empty for none):\n" @echo -en "If you want to apply a patch, input its path (leave empty for none):\n"
@read patchvar @read patchvar

View file

@ -13,10 +13,10 @@
<br> <br>
Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks. Hyprland is a 100% independent, dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
It provides the latest Wayland features, is highly customizable, has all the eyecandy, the most powerful plugins, It provides the latest Wayland features, is highly customizable, has all the eyecandy, the most powerful plugins,
easy IPC, much more QoL stuff than other wlr-based compositors and more... easy IPC, much more QoL stuff than other compositors and more...
<br> <br>
<br> <br>
@ -37,7 +37,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
- All of the eyecandy: gradient borders, blur, animations, shadows and much more - All of the eyecandy: gradient borders, blur, animations, shadows and much more
- A lot of customization - A lot of customization
- Much more QoL stuff than other wlr-based compositors - 100% independent, no wlroots, no libweston, no kwin, no mutter.
- Custom bezier curves for the best animations - Custom bezier curves for the best animations
- Powerful plugin support - Powerful plugin support
- Built-in plugin manager - Built-in plugin manager
@ -48,7 +48,6 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
- Config reloaded instantly upon saving - Config reloaded instantly upon saving
- Fully dynamic workspaces - Fully dynamic workspaces
- Two built-in layouts and more available as plugins - Two built-in layouts and more available as plugins
- Uses forked wlroots with QoL patches
- Global keybinds passed to your apps of choice - Global keybinds passed to your apps of choice
- Tiling/pseudotiling/floating/fullscreen windows - Tiling/pseudotiling/floating/fullscreen windows
- Special workspaces (scratchpads) - Special workspaces (scratchpads)
@ -86,7 +85,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
<br> <br>
**[wlroots]** - *For their amazing library* **[wlroots]** - *For powering Hyprland in the past*
**[tinywl]** - *For showing how 2 do stuff* **[tinywl]** - *For showing how 2 do stuff*

1
VERSION Normal file
View file

@ -0,0 +1 @@
0.41.2

View file

@ -32,6 +32,12 @@ Show command usage.
.TP .TP
\f[B]-c\f[R], \f[B]--config\f[R] \f[B]-c\f[R], \f[B]--config\f[R]
Specify config file to use. Specify config file to use.
.TP
\f[B]--socket\f[R]
Sets the Wayland socket name (for Wayland socket handover)
.TP
\f[B]--wayland-fd\f[R]
Sets the Wayland socket file descriptor (for Wayland socket handover)
.SH BUGS .SH BUGS
.TP .TP
Submit bug reports and request features online at: Submit bug reports and request features online at:

View file

@ -41,6 +41,12 @@ OPTIONS
**-c**, **--config** **-c**, **--config**
Specify config file to use. Specify config file to use.
**--socket**
Sets the Wayland socket name (for Wayland socket handover)
**--wayland-fd**
Sets the Wayland socket file descriptor (for Wayland socket handover)
BUGS BUGS
==== ====

View file

@ -1,5 +1,34 @@
{ {
"nodes": { "nodes": {
"aquamarine": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"hyprwayland-scanner": [
"hyprwayland-scanner"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1721992626,
"narHash": "sha256-GFDSPWxOqEkNrbuSfyoQHGIaRhJNapn2Rv0EEmBGR9A=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "f95d1509370b7f40ef356ff69a332bd0356ab044",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "aquamarine",
"type": "github"
}
},
"hyprcursor": { "hyprcursor": {
"inputs": { "inputs": {
"hyprlang": [ "hyprlang": [
@ -13,11 +42,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1720108799, "lastModified": 1721330371,
"narHash": "sha256-AxRkTJlbB8r7aG6gvc7IaLhc2T9TO4/8uqanKRxukBQ=", "narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "a5c0d57325c5f0814c39110a70ca19c070ae9486", "rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -64,11 +93,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1720381373, "lastModified": 1721324361,
"narHash": "sha256-lyC/EZdHULsaAKVryK11lgHY9u6pXr7qR4irnxNWC7k=", "narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "5df0174fd09de4ac5475233d65ffc703e89b82eb", "rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -87,11 +116,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1720203444, "lastModified": 1721324102,
"narHash": "sha256-lq2dPPPcwMHTLsFrQ2pRp4c2LwDZWoqzSyjuPdeJCP4=", "narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "a8c3a135701a7b64db0a88ec353a392f402d2a87", "rev": "962582a090bc233c4de9d9897f46794280288989",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -110,11 +139,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1720215857, "lastModified": 1721324119,
"narHash": "sha256-JPdL+Qul+jEueAn8CARfcWP83eJgwkhMejQYfDvrgvU=", "narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "d5fa094ca27e0039be5e94c0a80ae433145af8bb", "rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -125,11 +154,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1720031269, "lastModified": 1721924956,
"narHash": "sha256-rwz8NJZV+387rnWpTYcXaRNvzUSnnF9aHONoJIYmiUQ=", "narHash": "sha256-Sb1jlyRO+N8jBXEX9Pg9Z1Qb8Bw9QyOgLDNMEpmjZ2M=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9f4128e00b0ae8ec65918efeba59db998750ead6", "rev": "5ad6a14c6bf098e98800b091668718c336effc95",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -141,6 +170,7 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"aquamarine": "aquamarine",
"hyprcursor": "hyprcursor", "hyprcursor": "hyprcursor",
"hyprlang": "hyprlang", "hyprlang": "hyprlang",
"hyprutils": "hyprutils", "hyprutils": "hyprutils",
@ -179,11 +209,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1720194466, "lastModified": 1721755049,
"narHash": "sha256-Rizg9efi6ue95zOp0MeIV2ZedNo+5U9G2l6yirgBUnA=", "narHash": "sha256-O17b38bQnmfxv7It3OnVYx7fp1seEdI7xxnw5vJFv30=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "b9b97e5ba23fe7bd5fa4df54696102e8aa863cf6", "rev": "5555f467f68ce7cdf1060991c24263073b95e9da",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -7,6 +7,14 @@
# <https://github.com/nix-systems/nix-systems> # <https://github.com/nix-systems/nix-systems>
systems.url = "github:nix-systems/default-linux"; systems.url = "github:nix-systems/default-linux";
aquamarine = {
url = "github:hyprwm/aquamarine";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
};
hyprcursor = { hyprcursor = {
url = "github:hyprwm/hyprcursor"; url = "github:hyprwm/hyprcursor";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@ -90,9 +98,13 @@
stdenv = pkgsFor.${system}.gcc13Stdenv; stdenv = pkgsFor.${system}.gcc13Stdenv;
} { } {
name = "hyprland-shell"; name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [expat libxml2]; nativeBuildInputs = with pkgsFor.${system}; [
expat
libxml2
];
hardeningDisable = ["fortify"]; hardeningDisable = ["fortify"];
inputsFrom = [pkgsFor.${system}.hyprland]; inputsFrom = [pkgsFor.${system}.hyprland];
packages = [pkgsFor.${system}.clang-tools];
}; };
}); });

View file

@ -4,4 +4,4 @@ Name: Hyprland
URL: https://github.com/hyprwm/Hyprland URL: https://github.com/hyprwm/Hyprland
Description: Hyprland header files Description: Hyprland header files
Version: @HYPRLAND_VERSION@ Version: @HYPRLAND_VERSION@
Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland -I${prefix}/hyprland/wlr Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland

View file

@ -172,6 +172,9 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n"; std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n";
return false; return false;
} }
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
} }
progress.m_iSteps = 1; progress.m_iSteps = 1;
@ -226,6 +229,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
break;
} }
} }
@ -356,7 +365,7 @@ eHeadersErrors CPluginManager::headersValid() {
else else
headers = ""; headers = "";
if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland")) if (PATH.ends_with("protocols"))
continue; continue;
verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h"; verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h";
@ -493,11 +502,6 @@ bool CPluginManager::updateHeaders(bool force) {
return false; 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)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland"); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland");
progress.m_iSteps = 4; progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";

View file

@ -1,5 +1,5 @@
project('Hyprland', 'cpp', 'c', project('Hyprland', 'cpp', 'c',
version : run_command('jq', '-r', '.version', join_paths(meson.source_root(), 'props.json'), check: true).stdout().strip(), version : run_command('cat', join_paths(meson.source_root(), 'VERSION'), check: true).stdout().strip(),
default_options : [ default_options : [
'warning_level=2', 'warning_level=2',
'default_library=static', 'default_library=static',
@ -24,8 +24,6 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif 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_dep = dependency('xcb', required: get_option('xwayland'))
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland')) xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland'))
@ -38,12 +36,7 @@ cmake = import('cmake')
udis = cmake.subproject('udis86') udis = cmake.subproject('udis86')
udis86 = udis.dependency('libudis86') udis86 = udis.dependency('libudis86')
if get_option('xwayland').enabled() and not have_xwlr if not xcb_dep.found()
error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
endif
have_xwayland = xcb_dep.found() and have_xwlr
if not have_xwayland
add_project_arguments('-DNO_XWAYLAND', language: 'cpp') add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif endif
@ -86,5 +79,5 @@ import('pkgconfig').generate(
url: 'https://github.com/hyprwm/Hyprland', url: 'https://github.com/hyprwm/Hyprland',
description: 'Hyprland header files', description: 'Hyprland header files',
install_dir: pkg_install_dir, install_dir: pkg_install_dir,
subdirs: ['', 'hyprland/protocols', 'hyprland', 'hyprland/wlr'], subdirs: ['', 'hyprland/protocols', 'hyprland'],
) )

View file

@ -6,6 +6,7 @@
makeWrapper, makeWrapper,
cmake, cmake,
ninja, ninja,
aquamarine,
binutils, binutils,
cairo, cairo,
expat, expat,
@ -30,7 +31,6 @@
libuuid, libuuid,
libxkbcommon, libxkbcommon,
mesa, mesa,
meson,
pango, pango,
pciutils, pciutils,
pcre2, pcre2,
@ -89,7 +89,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
jq jq
makeWrapper makeWrapper
cmake cmake
meson # for wlroots
ninja ninja
pkg-config pkg-config
python3 # for udis86 python3 # for udis86
@ -104,6 +103,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
buildInputs = lib.concatLists [ buildInputs = lib.concatLists [
[ [
aquamarine
cairo cairo
expat expat
fribidi fribidi
@ -112,10 +112,12 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
hyprcursor hyprcursor
hyprlang hyprlang
hyprutils hyprutils
libGL
libdrm
libdatrie libdatrie
libdisplay-info
libdrm
libGL
libinput libinput
libliftoff
libselinux libselinux
libsepol libsepol
libthai libthai
@ -125,17 +127,15 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
pango pango
pciutils pciutils
pcre2 pcre2
seatd
tomlplusplus tomlplusplus
wayland wayland
wayland-protocols wayland-protocols
# for wlroots
seatd
libdisplay-info
libliftoff
] ]
(lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo])
(lib.optionals enableXWayland [ (lib.optionals enableXWayland [
xorg.libxcb xorg.libxcb
xorg.libXcursor
xorg.libXdmcp xorg.libXdmcp
xorg.xcbutil xorg.xcbutil
xorg.xcbutilerrors xorg.xcbutilerrors

View file

@ -3,13 +3,12 @@
lib, lib,
inputs, inputs,
}: let }: let
props = builtins.fromJSON (builtins.readFile ../props.json);
mkDate = longDate: (lib.concatStringsSep "-" [ mkDate = longDate: (lib.concatStringsSep "-" [
(builtins.substring 0 4 longDate) (builtins.substring 0 4 longDate)
(builtins.substring 4 2 longDate) (builtins.substring 4 2 longDate)
(builtins.substring 6 2 longDate) (builtins.substring 6 2 longDate)
]); ]);
version = lib.removeSuffix "\n" (builtins.readFile ../VERSION);
in { in {
# Contains what a user is most likely to care about: # Contains what a user is most likely to care about:
# Hyprland itself, XDPH and the Share Picker. # Hyprland itself, XDPH and the Share Picker.
@ -21,11 +20,11 @@ in {
# Packages for variations of Hyprland, dependencies included. # Packages for variations of Hyprland, dependencies included.
hyprland-packages = lib.composeManyExtensions [ hyprland-packages = lib.composeManyExtensions [
# Dependencies # Dependencies
inputs.aquamarine.overlays.default
inputs.hyprcursor.overlays.default inputs.hyprcursor.overlays.default
inputs.hyprlang.overlays.default inputs.hyprlang.overlays.default
inputs.hyprutils.overlays.default inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default inputs.hyprwayland-scanner.overlays.default
self.overlays.xwayland
# Hyprland packages themselves # Hyprland packages themselves
(final: prev: let (final: prev: let
@ -33,7 +32,7 @@ in {
in { in {
hyprland = final.callPackage ./default.nix { hyprland = final.callPackage ./default.nix {
stdenv = final.gcc13Stdenv; stdenv = final.gcc13Stdenv;
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}"; version = "${version}+date=${date}_${self.shortRev or "dirty"}";
commit = self.rev or ""; commit = self.rev or "";
inherit date; inherit date;
}; };
@ -63,14 +62,4 @@ in {
hyprland-extras = lib.composeManyExtensions [ hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.xdg-desktop-portal-hyprland inputs.xdph.overlays.xdg-desktop-portal-hyprland
]; ];
# Patches XWayland's pkgconfig file to not include Cflags or includedir
# The above two variables trip up CMake and the build fails
xwayland = final: prev: {
xwayland = prev.xwayland.overrideAttrs (old: {
postInstall = ''
sed -i '/includedir/d' $out/lib/pkgconfig/xwayland.pc
'';
});
};
} }

View file

@ -1,17 +0,0 @@
#!/usr/bin/env -S nix shell nixpkgs#gawk nixpkgs#git nixpkgs#gnused nixpkgs#ripgrep -c bash
# get wlroots revision from submodule
SUB_REV=$(git submodule status | rg wlroots | awk '{ print substr($1,2) }')
# and from lockfile
CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }')
if [ "$SUB_REV" != "$CRT_REV" ]; then
echo "Updating wlroots..."
# update wlroots to submodule revision
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix
nix flake lock
echo "wlroots: $CRT_REV -> $SUB_REV"
else
echo "wlroots is up to date!"
fi

View file

@ -1,3 +0,0 @@
{
"version": "0.41.2"
}

View file

@ -25,8 +25,6 @@ hyprwayland_scanner = find_program(
protocols = [ protocols = [
[wl_protocol_dir, 'unstable/text-input/text-input-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'],
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'] [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml']
] ]
@ -42,6 +40,8 @@ new_protocols = [
['wlr-layer-shell-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'],
['wayland-drm.xml'], ['wayland-drm.xml'],
['wlr-data-control-unstable-v1.xml'], ['wlr-data-control-unstable-v1.xml'],
['wlr-screencopy-unstable-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'],
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
@ -66,6 +66,8 @@ new_protocols = [
[wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'],
[wl_protocol_dir, 'stable/viewporter/viewporter.xml'], [wl_protocol_dir, 'stable/viewporter/viewporter.xml'],
[wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'],
[wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'],
[wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'],
] ]
wl_protos_src = [] wl_protos_src = []
@ -113,7 +115,8 @@ foreach p : wl_server_protos
wl_server_protos_gen += custom_target( wl_server_protos_gen += custom_target(
p.underscorify(), p.underscorify(),
input: p, input: p,
install: false, install: true,
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'], command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'],
) )

View file

@ -6,7 +6,10 @@
#include "managers/PointerManager.hpp" #include "managers/PointerManager.hpp"
#include "managers/SeatManager.hpp" #include "managers/SeatManager.hpp"
#include "managers/eventLoop/EventLoopManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp"
#include <aquamarine/output/Output.hpp>
#include <random> #include <random>
#include <cstring>
#include <filesystem>
#include <unordered_set> #include <unordered_set>
#include "debug/HyprCtl.hpp" #include "debug/HyprCtl.hpp"
#include "debug/CrashReporter.hpp" #include "debug/CrashReporter.hpp"
@ -22,20 +25,25 @@
#include "protocols/core/Compositor.hpp" #include "protocols/core/Compositor.hpp"
#include "protocols/core/Subcompositor.hpp" #include "protocols/core/Subcompositor.hpp"
#include "desktop/LayerSurface.hpp" #include "desktop/LayerSurface.hpp"
#include "render/Renderer.hpp"
#include "xwayland/XWayland.hpp" #include "xwayland/XWayland.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; #include <aquamarine/input/Input.hpp>
#include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/resource.h> #include <sys/resource.h>
using namespace Hyprutils::String;
using namespace Aquamarine;
int handleCritSignal(int signo, void* data) { int handleCritSignal(int signo, void* data) {
Debug::log(LOG, "Hyprland received signal {}", signo); Debug::log(LOG, "Hyprland received signal {}", signo);
if (signo == SIGTERM || signo == SIGINT || signo == SIGKILL) if (signo == SIGTERM || signo == SIGINT || signo == SIGKILL)
g_pCompositor->cleanup(); g_pCompositor->stopCompositor();
return 0; return 0;
} }
@ -71,6 +79,23 @@ void handleUserSignal(int sig) {
} }
} }
static LogLevel aqLevelToHl(Aquamarine::eBackendLogLevel level) {
switch (level) {
case Aquamarine::eBackendLogLevel::AQ_LOG_TRACE: return TRACE;
case Aquamarine::eBackendLogLevel::AQ_LOG_DEBUG: return LOG;
case Aquamarine::eBackendLogLevel::AQ_LOG_ERROR: return ERR;
case Aquamarine::eBackendLogLevel::AQ_LOG_WARNING: return WARN;
case Aquamarine::eBackendLogLevel::AQ_LOG_CRITICAL: return CRIT;
default: break;
}
return NONE;
}
void aqLog(Aquamarine::eBackendLogLevel level, std::string msg) {
Debug::log(aqLevelToHl(level), "[AQ] {}", msg);
}
void CCompositor::bumpNofile() { void CCompositor::bumpNofile() {
if (!getrlimit(RLIMIT_NOFILE, &m_sOriginalNofile)) if (!getrlimit(RLIMIT_NOFILE, &m_sOriginalNofile))
Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", m_sOriginalNofile.rlim_cur, m_sOriginalNofile.rlim_max); Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", m_sOriginalNofile.rlim_cur, m_sOriginalNofile.rlim_max);
@ -168,7 +193,8 @@ CCompositor::CCompositor() {
} }
CCompositor::~CCompositor() { CCompositor::~CCompositor() {
cleanup(); if (!m_bIsShuttingDown)
cleanup();
} }
void CCompositor::setRandomSplash() { void CCompositor::setRandomSplash() {
@ -179,7 +205,10 @@ void CCompositor::setRandomSplash() {
m_szCurrentSplash = SPLASHES[distribution(engine)]; m_szCurrentSplash = SPLASHES[distribution(engine)];
} }
void CCompositor::initServer() { static std::vector<SP<Aquamarine::IOutput>> pendingOutputs;
//
void CCompositor::initServer(std::string socketName, int socketFd) {
m_sWLDisplay = wl_display_create(); m_sWLDisplay = wl_display_create();
@ -199,102 +228,187 @@ void CCompositor::initServer() {
if (envEnabled("HYPRLAND_TRACE")) if (envEnabled("HYPRLAND_TRACE"))
Debug::trace = true; Debug::trace = true;
wlr_log_init(WLR_INFO, NULL); Aquamarine::SBackendOptions options;
options.logFunction = aqLog;
if (envEnabled("HYPRLAND_LOG_WLR")) std::vector<Aquamarine::SBackendImplementationOptions> implementations;
wlr_log_init(WLR_DEBUG, Debug::wlrLog); Aquamarine::SBackendImplementationOptions option;
else option.backendType = Aquamarine::eBackendType::AQ_BACKEND_HEADLESS;
wlr_log_init(WLR_ERROR, Debug::wlrLog); option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_MANDATORY;
implementations.emplace_back(option);
option.backendType = Aquamarine::eBackendType::AQ_BACKEND_DRM;
option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_IF_AVAILABLE;
implementations.emplace_back(option);
option.backendType = Aquamarine::eBackendType::AQ_BACKEND_WAYLAND;
option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_FALLBACK;
implementations.emplace_back(option);
m_sWLRBackend = wlr_backend_autocreate(m_sWLEventLoop, &m_sWLRSession); m_pAqBackend = CBackend::create(implementations, options);
if (!m_sWLRBackend) { if (!m_pAqBackend) {
Debug::log(CRIT, "m_sWLRBackend was NULL! This usually means wlroots could not find a GPU or enountered some issues."); Debug::log(CRIT,
throwError("wlr_backend_autocreate() failed!"); "m_pAqBackend was null! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a Wayland "
"session, NOT an X11 one.");
throwError("CBackend::create() failed!");
} }
bool isHeadlessOnly = true; // TODO: headless only
wlr_multi_for_each_backend(
m_sWLRBackend,
[](wlr_backend* backend, void* isHeadlessOnly) {
if (!wlr_backend_is_headless(backend) && !wlr_backend_is_libinput(backend))
*(bool*)isHeadlessOnly = false;
},
&isHeadlessOnly);
if (isHeadlessOnly) { initAllSignals();
m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); // TODO: remove this, it's barely needed now.
if (!m_pAqBackend->start()) {
Debug::log(CRIT,
"m_pAqBackend couldn't start! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a "
"Wayland session, NOT an X11 one.");
throwError("CBackend::create() failed!");
}
m_bInitialized = true;
m_iDRMFD = m_pAqBackend->drmFD();
Debug::log(LOG, "Running on DRMFD: {}", m_iDRMFD);
if (!socketName.empty() && socketFd != -1) {
fcntl(socketFd, F_SETFD, FD_CLOEXEC);
const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd);
if (RETVAL >= 0) {
m_szWLDisplaySocket = socketName;
Debug::log(LOG, "wl_display_add_socket_fd for {} succeeded with {}", socketName, RETVAL);
} else
Debug::log(WARN, "wl_display_add_socket_fd for {} returned {}: skipping", socketName, RETVAL);
} else { } else {
m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend); // get socket, avoid using 0
if (m_iDRMFD < 0) { for (int candidate = 1; candidate <= 32; candidate++) {
Debug::log(CRIT, "Couldn't query the DRM FD!"); const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate));
throwError("wlr_backend_get_drm_fd() failed!"); const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str());
if (RETVAL >= 0) {
m_szWLDisplaySocket = CANDIDATESTR;
Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL);
break;
} else
Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
} }
m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD);
} }
if (!m_sWLRRenderer) { if (m_szWLDisplaySocket.empty()) {
Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues."); Debug::log(WARN, "All candidates failed, trying wl_display_add_socket_auto");
throwError("wlr_gles2_renderer_create_with_drm_fd() failed!"); const auto SOCKETSTR = wl_display_add_socket_auto(m_sWLDisplay);
if (SOCKETSTR)
m_szWLDisplaySocket = SOCKETSTR;
} }
m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer); if (m_szWLDisplaySocket.empty()) {
Debug::log(CRIT, "m_szWLDisplaySocket NULL!");
if (!m_sWLRAllocator) { throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)");
Debug::log(CRIT, "m_sWLRAllocator was NULL!");
throwError("wlr_allocator_autocreate() failed!");
} }
m_sWLREGL = wlr_gles2_renderer_get_egl(m_sWLRRenderer); setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
setenv("XDG_SESSION_TYPE", "wayland", 1);
if (!m_sWLREGL) {
Debug::log(CRIT, "m_sWLREGL was NULL!");
throwError("wlr_gles2_renderer_get_egl() failed!");
}
initManagers(STAGE_BASICINIT); initManagers(STAGE_BASICINIT);
m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend);
if (!m_sWRLDRMLeaseMgr) {
Debug::log(INFO, "Failed to create wlr_drm_lease_v1_manager");
Debug::log(INFO, "VR will not be available");
}
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop);
if (!m_sWLRHeadlessBackend) {
Debug::log(CRIT, "Couldn't create the headless backend");
throwError("wlr_headless_backend_create() failed!");
}
wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
initManagers(STAGE_LATE); initManagers(STAGE_LATE);
for (auto& o : pendingOutputs) {
onNewMonitor(o);
}
pendingOutputs.clear();
} }
void CCompositor::initAllSignals() { void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend"); m_pAqBackend->events.newOutput.registerStaticListener(
addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend"); [this](void* p, std::any data) {
addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); auto output = std::any_cast<SP<Aquamarine::IOutput>>(data);
Debug::log(LOG, "New aquamarine output with name {}", output->name);
if (m_bInitialized)
onNewMonitor(output);
else
pendingOutputs.emplace_back(output);
},
nullptr);
if (m_sWRLDRMLeaseMgr) m_pAqBackend->events.newPointer.registerStaticListener(
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM"); [](void* data, std::any d) {
auto dev = std::any_cast<SP<Aquamarine::IPointer>>(d);
Debug::log(LOG, "New aquamarine pointer with name {}", dev->getName());
g_pInputManager->newMouse(dev);
g_pInputManager->updateCapabilities();
},
nullptr);
if (m_sWLRSession) m_pAqBackend->events.newKeyboard.registerStaticListener(
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session"); [](void* data, std::any d) {
auto dev = std::any_cast<SP<Aquamarine::IKeyboard>>(d);
Debug::log(LOG, "New aquamarine keyboard with name {}", dev->getName());
g_pInputManager->newKeyboard(dev);
g_pInputManager->updateCapabilities();
},
nullptr);
m_pAqBackend->events.newTouch.registerStaticListener(
[](void* data, std::any d) {
auto dev = std::any_cast<SP<Aquamarine::ITouch>>(d);
Debug::log(LOG, "New aquamarine touch with name {}", dev->getName());
g_pInputManager->newTouchDevice(dev);
g_pInputManager->updateCapabilities();
},
nullptr);
m_pAqBackend->events.newSwitch.registerStaticListener(
[](void* data, std::any d) {
auto dev = std::any_cast<SP<Aquamarine::ISwitch>>(d);
Debug::log(LOG, "New aquamarine switch with name {}", dev->getName());
g_pInputManager->newSwitch(dev);
},
nullptr);
m_pAqBackend->events.newTablet.registerStaticListener(
[](void* data, std::any d) {
auto dev = std::any_cast<SP<Aquamarine::ITablet>>(d);
Debug::log(LOG, "New aquamarine tablet with name {}", dev->getName());
g_pInputManager->newTablet(dev);
},
nullptr);
m_pAqBackend->events.newTabletPad.registerStaticListener(
[](void* data, std::any d) {
auto dev = std::any_cast<SP<Aquamarine::ITabletPad>>(d);
Debug::log(LOG, "New aquamarine tablet pad with name {}", dev->getName());
g_pInputManager->newTabletPad(dev);
},
nullptr);
if (m_pAqBackend->hasSession()) {
m_pAqBackend->session->events.changeActive.registerStaticListener(
[this](void*, std::any) {
if (m_pAqBackend->session->active) {
Debug::log(LOG, "Session got activated!");
m_bSessionActive = true;
for (auto& m : m_vMonitors) {
scheduleFrameForMonitor(m.get());
g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true);
}
g_pConfigManager->m_bWantsMonitorReload = true;
} else {
Debug::log(LOG, "Session got deactivated!");
m_bSessionActive = false;
for (auto& m : m_vMonitors) {
m->noFrameSchedule = true;
m->framesToSkip = 1;
}
}
},
nullptr);
}
} }
void CCompositor::removeAllSignals() { void CCompositor::removeAllSignals() {
removeWLSignal(&Events::listen_newOutput); ;
removeWLSignal(&Events::listen_newInput);
removeWLSignal(&Events::listen_RendererDestroy);
if (m_sWRLDRMLeaseMgr)
removeWLSignal(&Events::listen_leaseRequest);
if (m_sWLRSession)
removeWLSignal(&Events::listen_sessionActive);
} }
void CCompositor::cleanEnvironment() { void CCompositor::cleanEnvironment() {
@ -308,7 +422,7 @@ void CCompositor::cleanEnvironment() {
unsetenv("XDG_BACKEND"); unsetenv("XDG_BACKEND");
unsetenv("XDG_CURRENT_DESKTOP"); unsetenv("XDG_CURRENT_DESKTOP");
if (m_sWLRSession) { if (m_pAqBackend->hasSession()) {
const auto CMD = const auto CMD =
#ifdef USES_SYSTEMD #ifdef USES_SYSTEMD
"systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " "systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
@ -319,8 +433,16 @@ void CCompositor::cleanEnvironment() {
} }
} }
void CCompositor::stopCompositor() {
Debug::log(LOG, "Hyprland is stopping!");
// this stops the wayland loop, wl_display_run
wl_display_terminate(m_sWLDisplay);
m_bIsShuttingDown = true;
}
void CCompositor::cleanup() { void CCompositor::cleanup() {
if (!m_sWLDisplay || m_bIsShuttingDown) if (!m_sWLDisplay)
return; return;
signal(SIGABRT, SIG_DFL); signal(SIGABRT, SIG_DFL);
@ -351,7 +473,7 @@ void CCompositor::cleanup() {
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
g_pHyprOpenGL->destroyMonitorResources(m.get()); g_pHyprOpenGL->destroyMonitorResources(m.get());
wlr_output_state_set_enabled(m->state.wlr(), false); m->output->state->setEnabled(false);
m->state.commit(); m->state.commit();
} }
@ -388,25 +510,14 @@ void CCompositor::cleanup() {
g_pHyprCtl.reset(); g_pHyprCtl.reset();
g_pEventLoopManager.reset(); g_pEventLoopManager.reset();
if (m_sWLRRenderer) if (m_pAqBackend)
wlr_renderer_destroy(m_sWLRRenderer); m_pAqBackend.reset();
if (m_sWLRAllocator)
wlr_allocator_destroy(m_sWLRAllocator);
if (m_sWLRBackend)
wlr_backend_destroy(m_sWLRBackend);
if (m_critSigSource) if (m_critSigSource)
wl_event_source_remove(m_critSigSource); wl_event_source_remove(m_critSigSource);
wl_event_loop_destroy(m_sWLEventLoop); // this frees all wayland resources, including sockets
wl_display_terminate(m_sWLDisplay); wl_display_destroy(m_sWLDisplay);
m_sWLDisplay = nullptr;
std::string waylandSocket = std::string{getenv("XDG_RUNTIME_DIR")} + "/" + m_szWLDisplaySocket;
std::filesystem::remove(waylandSocket);
std::filesystem::remove(waylandSocket + ".lock");
} }
void CCompositor::initManagers(eManagersInitStage stage) { void CCompositor::initManagers(eManagersInitStage stage) {
@ -441,6 +552,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the PointerManager!"); Debug::log(LOG, "Creating the PointerManager!");
g_pPointerManager = std::make_unique<CPointerManager>(); g_pPointerManager = std::make_unique<CPointerManager>();
Debug::log(LOG, "Creating the EventManager!");
g_pEventManager = std::make_unique<CEventManager>();
} break; } break;
case STAGE_BASICINIT: { case STAGE_BASICINIT: {
Debug::log(LOG, "Creating the CHyprOpenGLImpl!"); Debug::log(LOG, "Creating the CHyprOpenGLImpl!");
@ -471,9 +585,6 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the SessionLockManager!"); Debug::log(LOG, "Creating the SessionLockManager!");
g_pSessionLockManager = std::make_unique<CSessionLockManager>(); g_pSessionLockManager = std::make_unique<CSessionLockManager>();
Debug::log(LOG, "Creating the EventManager!");
g_pEventManager = std::make_unique<CEventManager>();
Debug::log(LOG, "Creating the HyprDebugOverlay!"); Debug::log(LOG, "Creating the HyprDebugOverlay!");
g_pDebugOverlay = std::make_unique<CHyprDebugOverlay>(); g_pDebugOverlay = std::make_unique<CHyprDebugOverlay>();
@ -516,57 +627,26 @@ void CCompositor::removeLockFile() {
void CCompositor::prepareFallbackOutput() { void CCompositor::prepareFallbackOutput() {
// create a backup monitor // create a backup monitor
wlr_backend* headless = nullptr; SP<Aquamarine::IBackendImplementation> headless;
wlr_multi_for_each_backend( for (auto& impl : m_pAqBackend->getImplementations()) {
m_sWLRBackend, if (impl->type() == Aquamarine::AQ_BACKEND_HEADLESS) {
[](wlr_backend* b, void* data) { headless = impl;
if (wlr_backend_is_headless(b))
*((wlr_backend**)data) = b;
},
&headless);
if (!headless) {
Debug::log(WARN, "Unsafe state will be ineffective, no fallback output");
return;
}
wlr_headless_add_output(headless, 1920, 1080);
}
void CCompositor::startCompositor() {
initAllSignals();
// get socket, avoid using 0
for (int candidate = 1; candidate <= 32; candidate++) {
const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate));
const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str());
if (RETVAL >= 0) {
m_szWLDisplaySocket = CANDIDATESTR;
Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL);
break; break;
} else {
Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
} }
} }
if (m_szWLDisplaySocket.empty()) { if (!headless) {
Debug::log(WARN, "All candidates failed, trying wl_display_add_socket_auto"); Debug::log(WARN, "No headless in prepareFallbackOutput?!");
const auto SOCKETSTR = wl_display_add_socket_auto(m_sWLDisplay); return;
if (SOCKETSTR)
m_szWLDisplaySocket = SOCKETSTR;
} }
if (m_szWLDisplaySocket.empty()) { headless->createOutput();
Debug::log(CRIT, "m_szWLDisplaySocket NULL!"); }
wlr_backend_destroy(m_sWLRBackend);
throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)");
}
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
void CCompositor::startCompositor() {
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */) { if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) {
const auto CMD = const auto CMD =
#ifdef USES_SYSTEMD #ifdef USES_SYSTEMD
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
@ -578,13 +658,6 @@ void CCompositor::startCompositor() {
Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket); Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket);
if (!wlr_backend_start(m_sWLRBackend)) {
Debug::log(CRIT, "Backend did not start!");
wlr_backend_destroy(m_sWLRBackend);
wl_display_destroy(m_sWLDisplay);
throwError("The backend could not start!");
}
prepareFallbackOutput(); prepareFallbackOutput();
g_pHyprRenderer->setCursorFromName("left_ptr"); g_pHyprRenderer->setCursorFromName("left_ptr");
@ -702,7 +775,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowBoxUnified(properties); const auto BB = w->getWindowBoxUnified(properties);
CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); 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 (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() &&
w != pIgnoreWindow) {
if (box.containsPoint(g_pPointerManager->position())) if (box.containsPoint(g_pPointerManager->position()))
return w; return w;
@ -731,7 +805,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
continue; continue;
CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); 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 && if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() &&
w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
// OR windows should add focus to parent // OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2) if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
@ -784,7 +858,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
continue; continue;
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) { !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) {
if (w->hasPopupAt(pos)) if (w->hasPopupAt(pos))
return w; return w;
} }
@ -796,7 +870,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize};
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow)
return w; return w;
} }
@ -871,7 +945,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo
return vec - pWindow->m_vRealPosition.goal() - std::get<1>(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) { CMonitor* CCompositor::getMonitorFromOutput(SP<Aquamarine::IOutput> out) {
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
if (m->output == out) { if (m->output == out) {
return m.get(); return m.get();
@ -881,7 +955,7 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
return nullptr; return nullptr;
} }
CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) { CMonitor* CCompositor::getRealMonitorFromOutput(SP<Aquamarine::IOutput> out) {
for (auto& m : m_vRealMonitors) { for (auto& m : m_vRealMonitors) {
if (m->output == out) { if (m->output == out) {
return m.get(); return m.get();
@ -940,7 +1014,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface
return; return;
} }
if (pWindow->m_sAdditionalConfigData.noFocus) { if (pWindow->m_sWindowData.noFocus.valueOrDefault()) {
Debug::log(LOG, "Ignoring focus to nofocus window!"); Debug::log(LOG, "Ignoring focus to nofocus window!");
return; return;
} }
@ -1030,7 +1104,7 @@ void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindo
return; return;
if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(pSurface)) { if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(pSurface)) {
Debug::log(LOG, "surface {:x} won't receive kb focus becuase grab rejected it", (uintptr_t)pSurface); Debug::log(LOG, "surface {:x} won't receive kb focus becuase grab rejected it", (uintptr_t)pSurface.get());
return; return;
} }
@ -1053,9 +1127,9 @@ void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindo
g_pSeatManager->setKeyboardFocus(pSurface); g_pSeatManager->setKeyboardFocus(pSurface);
if (pWindowOwner) if (pWindowOwner)
Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", (uintptr_t)pSurface, pWindowOwner); Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", (uintptr_t)pSurface.get(), pWindowOwner);
else else
Debug::log(LOG, "Set keyboard focus to surface {:x}", (uintptr_t)pSurface); Debug::log(LOG, "Set keyboard focus to surface {:x}", (uintptr_t)pSurface.get());
g_pXWaylandManager->activateSurface(pSurface, true); g_pXWaylandManager->activateSurface(pSurface, true);
m_pLastFocus = pSurface; m_pLastFocus = pSurface;
@ -1114,15 +1188,10 @@ SP<CWLSurfaceResource> CCompositor::vectorToLayerSurface(const Vector2D& pos, st
} }
PHLWINDOW CCompositor::getWindowFromSurface(SP<CWLSurfaceResource> pSurface) { PHLWINDOW CCompositor::getWindowFromSurface(SP<CWLSurfaceResource> pSurface) {
for (auto& w : m_vWindows) { if (!pSurface || !pSurface->hlSurface)
if (!w->m_bIsMapped || w->m_bFadingOut) return nullptr;
continue;
if (w->m_pWLSurface->resource() == pSurface) return pSurface->hlSurface->getWindow();
return w;
}
return nullptr;
} }
PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) {
@ -1579,7 +1648,7 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
if (floating.has_value() && w->m_bIsFloating != floating.value()) if (floating.has_value() && w->m_bIsFloating != floating.value())
continue; continue;
if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w; return w;
} }
@ -1587,7 +1656,7 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
if (floating.has_value() && w->m_bIsFloating != floating.value()) if (floating.has_value() && w->m_bIsFloating != floating.value())
continue; continue;
if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w; return w;
} }
@ -1608,7 +1677,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
if (floating.has_value() && w->m_bIsFloating != floating.value()) if (floating.has_value() && w->m_bIsFloating != floating.value())
continue; continue;
if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w; return w;
} }
@ -1616,7 +1685,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
if (floating.has_value() && w->m_bIsFloating != floating.value()) if (floating.has_value() && w->m_bIsFloating != floating.value())
continue; continue;
if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w; return w;
} }
@ -1804,13 +1873,11 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
if (pWindow == m_pLastWindow) { if (pWindow == m_pLastWindow) {
const auto* const ACTIVECOLOR = const auto* const ACTIVECOLOR =
!pWindow->m_sGroupData.pNextWindow.lock() ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL); !pWindow->m_sGroupData.pNextWindow.lock() ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying().m_vColors.empty() ? *ACTIVECOLOR : setBorderColor(pWindow->m_sWindowData.activeBorderColor.valueOr(*ACTIVECOLOR));
pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying());
} else { } else {
const auto* const INACTIVECOLOR = !pWindow->m_sGroupData.pNextWindow.lock() ? (!pWindow->m_sGroupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : const auto* const INACTIVECOLOR = !pWindow->m_sGroupData.pNextWindow.lock() ? (!pWindow->m_sGroupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) :
(GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL); (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying().m_vColors.empty() ? *INACTIVECOLOR : setBorderColor(pWindow->m_sWindowData.inactiveBorderColor.valueOr(*INACTIVECOLOR));
pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying());
} }
} }
@ -1821,23 +1888,16 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
// opacity // opacity
const auto PWORKSPACE = pWindow->m_pWorkspace; const auto PWORKSPACE = pWindow->m_pWorkspace;
if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() != -1 ? pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA);
(pWindow->m_sSpecialRenderData.alphaFullscreenOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() :
pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() * *PFULLSCREENALPHA) :
*PFULLSCREENALPHA;
} else { } else {
if (pWindow == m_pLastWindow) if (pWindow == m_pLastWindow)
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alpha.toUnderlying() : pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alpha.valueOrDefault().applyAlpha(*PACTIVEALPHA);
pWindow->m_sSpecialRenderData.alpha.toUnderlying() * *PACTIVEALPHA;
else else
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() != -1 ? pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaInactive.valueOrDefault().applyAlpha(*PINACTIVEALPHA);
(pWindow->m_sSpecialRenderData.alphaInactiveOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() :
pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() * *PINACTIVEALPHA) :
*PINACTIVEALPHA;
} }
// dim // dim
if (pWindow == m_pLastWindow.lock() || pWindow->m_sAdditionalConfigData.forceNoDim || !*PDIMENABLED) { if (pWindow == m_pLastWindow.lock() || pWindow->m_sWindowData.noDim.valueOrDefault() || !*PDIMENABLED) {
pWindow->m_fDimPercent = 0; pWindow->m_fDimPercent = 0;
} else { } else {
pWindow->m_fDimPercent = *PDIMSTRENGTH; pWindow->m_fDimPercent = *PDIMSTRENGTH;
@ -2195,6 +2255,8 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) {
} }
void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMode mode) { void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMode mode) {
static auto PNODIRECTSCANOUT = CConfigValue<Hyprlang::INT>("misc:no_direct_scanout");
if (!validMapped(pWindow) || g_pCompositor->m_bUnsafeState) if (!validMapped(pWindow) || g_pCompositor->m_bUnsafeState)
return; return;
@ -2238,8 +2300,14 @@ void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMod
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
// DMAbuf stuff for direct scanout // further updates require a monitor
g_pHyprRenderer->setWindowScanoutMode(pWindow); if (!PMONITOR)
return;
// send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't.
// ignore if DS is disabled.
if (!*PNODIRECTSCANOUT)
g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr);
g_pConfigManager->ensureVRR(PMONITOR); g_pConfigManager->ensureVRR(PMONITOR);
} }
@ -2268,7 +2336,7 @@ void CCompositor::updateWorkspaceWindowDecos(const int& id) {
} }
} }
void CCompositor::updateWorkspaceSpecialRenderData(const int& id) { void CCompositor::updateWorkspaceWindowData(const int& id) {
const auto PWORKSPACE = getWorkspaceByID(id); const auto PWORKSPACE = getWorkspaceByID(id);
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
@ -2276,12 +2344,12 @@ void CCompositor::updateWorkspaceSpecialRenderData(const int& id) {
if (w->workspaceID() != id) if (w->workspaceID() != id)
continue; continue;
w->updateSpecialRenderData(WORKSPACERULE); w->updateWindowData(WORKSPACERULE);
} }
} }
void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) { void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleFrameReason reason) {
if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive) if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive)
return; return;
if (!pMonitor->m_bEnabled) if (!pMonitor->m_bEnabled)
@ -2290,7 +2358,7 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
if (pMonitor->renderingActive) if (pMonitor->renderingActive)
pMonitor->pendingFrame = true; pMonitor->pendingFrame = true;
wlr_output_schedule_frame(pMonitor->output); pMonitor->output->scheduleFrame(reason);
} }
PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) {
@ -2767,7 +2835,7 @@ void CCompositor::setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, d
const auto PSURFACE = CWLSurface::fromResource(pSurface); const auto PSURFACE = CWLSurface::fromResource(pSurface);
if (!PSURFACE) { if (!PSURFACE) {
Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface); Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface.get());
return; return;
} }
@ -2780,7 +2848,7 @@ void CCompositor::setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurfac
const auto PSURFACE = CWLSurface::fromResource(pSurface); const auto PSURFACE = CWLSurface::fromResource(pSurface);
if (!PSURFACE) { if (!PSURFACE) {
Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface); Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface.get());
return; return;
} }
@ -2806,3 +2874,84 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) {
return {}; return {};
} }
static void checkDefaultCursorWarp(SP<CMonitor> PNEWMONITOR, std::string monitorName) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static auto firstMonitorAdded = std::chrono::system_clock::now();
static bool cursorDefaultDone = false;
static bool firstLaunch = true;
const auto POS = PNEWMONITOR->middle();
// by default, cursor should be set to first monitor detected
// this is needed as a default if the monitor given in config above doesn't exist
if (firstLaunch) {
firstLaunch = false;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY)
return;
// after 10s, don't set cursor to default monitor
auto timePassedSec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - firstMonitorAdded);
if (timePassedSec.count() > 10) {
cursorDefaultDone = true;
return;
}
if (*PCURSORMONITOR == monitorName) {
cursorDefaultDone = true;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
}
void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) {
// add it to real
auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>());
if (std::string("HEADLESS-1") == output->name) {
g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get();
output->name = "FALLBACK"; // we are allowed to do this :)
}
Debug::log(LOG, "New output with name {}", output->name);
PNEWMONITOR->szName = output->name;
PNEWMONITOR->output = output;
PNEWMONITOR->self = PNEWMONITOR;
const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false;
PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(output->name);
PNEWMONITOR->isUnsafeFallback = FALLBACK;
EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR);
if (!FALLBACK)
PNEWMONITOR->onConnect(false);
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
return;
// ready to process if we have a real monitor
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get();
g_pCompositor->m_bReadyToProcess = true;
g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR);
checkDefaultCursorWarp(PNEWMONITOR, output->name);
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) {
w->m_iLastSurfaceMonitorID = -1;
w->updateSurfaceScaleTransformDetails();
}
}
g_pHyprRenderer->damageMonitor(PNEWMONITOR.get());
Events::listener_monitorFrame(PNEWMONITOR.get(), nullptr);
}

View file

@ -30,6 +30,9 @@
#include "plugins/PluginSystem.hpp" #include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp" #include "helpers/Watchdog.hpp"
#include <aquamarine/backend/Backend.hpp>
#include <aquamarine/output/Output.hpp>
class CWLSurfaceResource; class CWLSurfaceResource;
enum eManagersInitStage { enum eManagersInitStage {
@ -43,22 +46,11 @@ class CCompositor {
CCompositor(); CCompositor();
~CCompositor(); ~CCompositor();
// ------------------ WLR BASICS ------------------ // wl_display* m_sWLDisplay;
wl_display* m_sWLDisplay; wl_event_loop* m_sWLEventLoop;
wl_event_loop* m_sWLEventLoop; int m_iDRMFD = -1;
wlr_backend* m_sWLRBackend; bool m_bInitialized = false;
wlr_session* m_sWLRSession; SP<Aquamarine::CBackend> m_pAqBackend;
wlr_renderer* m_sWLRRenderer;
wlr_allocator* m_sWLRAllocator;
wlr_compositor* m_sWLRCompositor;
wlr_subcompositor* m_sWLRSubCompositor;
wlr_drm* m_sWRLDRM;
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_egl* m_sWLREGL;
int m_iDRMFD;
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
wlr_backend* m_sWLRHeadlessBackend;
// ------------------------------------------------- //
std::string m_szHyprTempDataRoot = ""; std::string m_szHyprTempDataRoot = "";
@ -77,8 +69,9 @@ class CCompositor {
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap; std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;
void initServer(); void initServer(std::string socketName, int socketFd);
void startCompositor(); void startCompositor();
void stopCompositor();
void cleanup(); void cleanup();
void createLockFile(); void createLockFile();
void removeLockFile(); void removeLockFile();
@ -94,10 +87,9 @@ class CCompositor {
bool m_bReadyToProcess = false; bool m_bReadyToProcess = false;
bool m_bSessionActive = true; bool m_bSessionActive = true;
bool m_bDPMSStateON = true; bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; // because wlroots bool m_bNextIsUnsafe = false;
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bExitTriggered = false; // For exit dispatcher
bool m_bIsShuttingDown = false; bool m_bIsShuttingDown = false;
// ------------------------------------------------- // // ------------------------------------------------- //
@ -116,8 +108,8 @@ class CCompositor {
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
CMonitor* getMonitorFromOutput(wlr_output*); CMonitor* getMonitorFromOutput(SP<Aquamarine::IOutput>);
CMonitor* getRealMonitorFromOutput(wlr_output*); CMonitor* getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>); PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
PHLWINDOW getWindowFromHandle(uint32_t); PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE); bool isWorkspaceVisible(PHLWORKSPACE);
@ -127,7 +119,7 @@ class CCompositor {
PHLWORKSPACE getWorkspaceByString(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces(); void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&); void updateWorkspaceWindowDecos(const int&);
void updateWorkspaceSpecialRenderData(const int&); void updateWorkspaceWindowData(const int&);
int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {}); 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 = {}); int getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
PHLWINDOW getUrgentWindow(); PHLWINDOW getUrgentWindow();
@ -157,7 +149,7 @@ class CCompositor {
void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW); PHLWINDOW getX11Parent(PHLWINDOW);
void scheduleFrameForMonitor(CMonitor*); void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
void addToFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLLS);
void removeFromFadingOutSafe(PHLLS); void removeFromFadingOutSafe(PHLLS);
void addToFadingOutSafe(PHLWINDOW); void addToFadingOutSafe(PHLWINDOW);
@ -182,6 +174,7 @@ class CCompositor {
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform); void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates(); void updateSuspendedStates();
PHLWINDOW windowForCPointer(CWindow*); PHLWINDOW windowForCPointer(CWindow*);
void onNewMonitor(SP<Aquamarine::IOutput> output);
std::string explicitConfigPath; std::string explicitConfigPath;

View file

@ -20,11 +20,11 @@ class ICustomConfigValueData {
class CGradientValueData : public ICustomConfigValueData { class CGradientValueData : public ICustomConfigValueData {
public: public:
CGradientValueData(){}; CGradientValueData() {};
CGradientValueData(CColor col) { CGradientValueData(CColor col) {
m_vColors.push_back(col); m_vColors.push_back(col);
}; };
virtual ~CGradientValueData(){}; virtual ~CGradientValueData() {};
virtual eConfigValueDataTypes getDataType() { virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_GRADIENT; return CVD_TYPE_GRADIENT;
@ -67,11 +67,11 @@ class CGradientValueData : public ICustomConfigValueData {
class CCssGapData : public ICustomConfigValueData { class CCssGapData : public ICustomConfigValueData {
public: public:
CCssGapData() : top(0), right(0), bottom(0), left(0){}; CCssGapData() : top(0), right(0), bottom(0), left(0) {};
CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global){}; CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global) {};
CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal){}; CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal) {};
CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : top(top), right(horizontal), bottom(bottom), left(horizontal){}; CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : top(top), right(horizontal), bottom(bottom), left(horizontal) {};
CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : top(top), right(right), bottom(bottom), left(left){}; CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : top(top), right(right), bottom(bottom), left(left) {};
/* Css like directions */ /* Css like directions */
int64_t top; int64_t top;

View file

@ -8,6 +8,7 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <hyprutils/path/Path.hpp>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <sys/stat.h> #include <sys/stat.h>
@ -23,6 +24,7 @@
#include <ranges> #include <ranges>
#include <unordered_set> #include <unordered_set>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <filesystem>
using namespace Hyprutils::String; using namespace Hyprutils::String;
extern "C" char** environ; extern "C" char** environ;
@ -352,6 +354,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("misc:close_special_on_empty", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:close_special_on_empty", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:background_color", Hyprlang::INT{0xff111111}); m_pConfig->addConfigValue("misc:background_color", Hyprlang::INT{0xff111111});
m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:exit_window_retains_fullscreen", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1});
@ -472,6 +475,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("input:scroll_button_lock", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:scroll_button_lock", Hyprlang::INT{0});
m_pConfig->addConfigValue("input:scroll_factor", {1.f}); m_pConfig->addConfigValue("input:scroll_factor", {1.f});
m_pConfig->addConfigValue("input:scroll_points", {STRVAL_EMPTY}); m_pConfig->addConfigValue("input:scroll_points", {STRVAL_EMPTY});
m_pConfig->addConfigValue("input:emulate_discrete_scroll", Hyprlang::INT{1});
m_pConfig->addConfigValue("input:touchpad:natural_scroll", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:touchpad:natural_scroll", Hyprlang::INT{0});
m_pConfig->addConfigValue("input:touchpad:disable_while_typing", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:touchpad:disable_while_typing", Hyprlang::INT{1});
m_pConfig->addConfigValue("input:touchpad:clickfinger_behavior", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:touchpad:clickfinger_behavior", Hyprlang::INT{0});
@ -517,6 +521,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("gestures:workspace_swipe_forever", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_forever", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_use_r", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_use_r", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_touch", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_touch", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_touch_invert", Hyprlang::INT{0});
m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1}); m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1});
m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0}); m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0});
@ -538,6 +543,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1});
m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1});
m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0});
m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0});
@ -556,6 +562,8 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"});
m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"});
m_pConfig->addConfigValue("experimental:explicit_sync", Hyprlang::INT{0});
// devices // devices
m_pConfig->addSpecialCategory("device", {"name"}); m_pConfig->addSpecialCategory("device", {"name"});
m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F}); m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F});
@ -629,25 +637,49 @@ CConfigManager::CConfigManager() {
g_pHyprError->queueCreate(ERR.value(), CColor{1.0, 0.1, 0.1, 1.0}); g_pHyprError->queueCreate(ERR.value(), CColor{1.0, 0.1, 0.1, 1.0});
} }
std::string CConfigManager::getConfigDir() { std::optional<std::string> CConfigManager::generateConfig(std::string configPath) {
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME"); std::string parentPath = std::filesystem::path(configPath).parent_path();
if (xdgConfigHome && std::filesystem::path(xdgConfigHome).is_absolute()) if (!std::filesystem::is_directory(parentPath)) {
return xdgConfigHome; Debug::log(WARN, "Creating config home directory");
try {
std::filesystem::create_directories(parentPath);
} catch (std::exception e) { throw e; }
}
static const char* home = getenv("HOME"); Debug::log(WARN, "No config file found; attempting to generate.");
std::ofstream ofs;
ofs.open(configPath, std::ios::trunc);
ofs << AUTOCONFIG;
ofs.close();
if (!home) if (!std::filesystem::exists(configPath))
throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME is set in the environment. Cannot determine config directory."); return "Config could not be generated.";
return home + std::string("/.config"); return configPath;
} }
std::string CConfigManager::getMainConfigPath() { std::string CConfigManager::getMainConfigPath() {
if (!g_pCompositor->explicitConfigPath.empty()) if (!g_pCompositor->explicitConfigPath.empty())
return g_pCompositor->explicitConfigPath; return g_pCompositor->explicitConfigPath;
return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf"); static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland");
if (paths.first.has_value()) {
return paths.first.value();
} else if (paths.second.has_value()) {
auto configPath = Hyprutils::Path::fullConfigPath(paths.second.value(), ISDEBUG ? "hyprlandd" : "hyprland");
return generateConfig(configPath).value();
} else
throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME are set in the environment. Could not find config in XDG_CONFIG_DIRS or /etc/xdg.");
}
std::optional<std::string> CConfigManager::verifyConfigExists() {
std::string mainConfigPath = getMainConfigPath();
if (!std::filesystem::exists(mainConfigPath))
return "broken config dir?";
return {};
} }
const std::string CConfigManager::getConfigString() { const std::string CConfigManager::getConfigString() {
@ -743,32 +775,6 @@ void CConfigManager::setDefaultAnimationVars() {
CREATEANIMCFG("specialWorkspace", "workspaces"); CREATEANIMCFG("specialWorkspace", "workspaces");
} }
std::optional<std::string> CConfigManager::verifyConfigExists() {
std::string mainConfigPath = getMainConfigPath();
if (g_pCompositor->explicitConfigPath.empty() && !std::filesystem::exists(mainConfigPath)) {
std::string configPath = std::filesystem::path(mainConfigPath).parent_path();
if (!std::filesystem::is_directory(configPath)) {
Debug::log(WARN, "Creating config home directory");
try {
std::filesystem::create_directories(configPath);
} catch (...) { return "Broken config file! (Could not create config directory)"; }
}
Debug::log(WARN, "No config file found; attempting to generate.");
std::ofstream ofs;
ofs.open(mainConfigPath, std::ios::trunc);
ofs << AUTOCONFIG;
ofs.close();
}
if (!std::filesystem::exists(mainConfigPath))
return "broken config dir?";
return {};
}
std::optional<std::string> CConfigManager::resetHLConfig() { std::optional<std::string> CConfigManager::resetHLConfig() {
m_dMonitorRules.clear(); m_dMonitorRules.clear();
m_dWindowRules.clear(); m_dWindowRules.clear();
@ -846,7 +852,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
if (w->inert()) if (w->inert())
continue; continue;
g_pCompositor->updateWorkspaceWindows(w->m_iID); g_pCompositor->updateWorkspaceWindows(w->m_iID);
g_pCompositor->updateWorkspaceSpecialRenderData(w->m_iID); g_pCompositor->updateWorkspaceWindowData(w->m_iID);
} }
// Update window border colors // Update window border colors
@ -1060,14 +1066,14 @@ SWorkspaceRule CConfigManager::mergeWorkspaceRules(const SWorkspaceRule& rule1,
mergedRule.gapsOut = rule2.gapsOut; mergedRule.gapsOut = rule2.gapsOut;
if (rule2.borderSize.has_value()) if (rule2.borderSize.has_value())
mergedRule.borderSize = rule2.borderSize; mergedRule.borderSize = rule2.borderSize;
if (rule2.border.has_value()) if (rule2.noBorder.has_value())
mergedRule.border = rule2.border; mergedRule.noBorder = rule2.noBorder;
if (rule2.rounding.has_value()) if (rule2.noRounding.has_value())
mergedRule.rounding = rule2.rounding; mergedRule.noRounding = rule2.noRounding;
if (rule2.decorate.has_value()) if (rule2.decorate.has_value())
mergedRule.decorate = rule2.decorate; mergedRule.decorate = rule2.decorate;
if (rule2.shadow.has_value()) if (rule2.noShadow.has_value())
mergedRule.shadow = rule2.shadow; mergedRule.noShadow = rule2.noShadow;
if (rule2.onCreatedEmptyRunCmd.has_value()) if (rule2.onCreatedEmptyRunCmd.has_value())
mergedRule.onCreatedEmptyRunCmd = rule2.onCreatedEmptyRunCmd; mergedRule.onCreatedEmptyRunCmd = rule2.onCreatedEmptyRunCmd;
if (rule2.defaultName.has_value()) if (rule2.defaultName.has_value())
@ -1286,7 +1292,7 @@ void CConfigManager::dispatchExecOnce() {
return; return;
// update dbus env // update dbus env
if (g_pCompositor->m_sWLRSession) if (g_pCompositor->m_pAqBackend->hasSession())
handleRawExec("", handleRawExec("",
#ifdef USES_SYSTEMD #ifdef USES_SYSTEMD
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
@ -1295,12 +1301,14 @@ void CConfigManager::dispatchExecOnce() {
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"); "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS");
firstExecDispatched = true; firstExecDispatched = true;
isLaunchingExecOnce = true;
for (auto& c : firstExecRequests) { for (auto& c : firstExecRequests) {
handleRawExec("", c); handleRawExec("", c);
} }
firstExecRequests.clear(); // free some kb of memory :P firstExecRequests.clear(); // free some kb of memory :P
isLaunchingExecOnce = false;
// set input, fixes some certain issues // set input, fixes some certain issues
g_pInputManager->setKeyboardLayout(); g_pInputManager->setKeyboardLayout();
@ -1411,7 +1419,8 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
if (USEVRR == 0) { if (USEVRR == 0) {
if (m->vrrActive) { if (m->vrrActive) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
m->output->state->setAdaptiveSync(false);
if (!m->state.commit()) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
@ -1420,11 +1429,11 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
return; return;
} else if (USEVRR == 1) { } else if (USEVRR == 1) {
if (!m->vrrActive) { if (!m->vrrActive) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1); m->output->state->setAdaptiveSync(true);
if (!m->state.test()) { if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); m->output->state->setAdaptiveSync(false);
} }
if (!m->state.commit()) if (!m->state.commit())
@ -1443,19 +1452,19 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) { if (WORKSPACEFULL) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1); m->output->state->setAdaptiveSync(true);
if (!m->state.test()) { if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); m->output->state->setAdaptiveSync(false);
} }
if (!m->state.commit()) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) { } else if (!WORKSPACEFULL) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); m->output->state->setAdaptiveSync(false);
if (!m->state.commit()) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
@ -1978,6 +1987,7 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
bool ignoreMods = false; bool ignoreMods = false;
bool multiKey = false; bool multiKey = false;
bool hasDescription = false; bool hasDescription = false;
bool dontInhibit = false;
const auto BINDARGS = command.substr(4); const auto BINDARGS = command.substr(4);
for (auto& arg : BINDARGS) { for (auto& arg : BINDARGS) {
@ -1999,6 +2009,8 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
multiKey = true; multiKey = true;
} else if (arg == 'd') { } else if (arg == 'd') {
hasDescription = true; hasDescription = true;
} else if (arg == 'p') {
dontInhibit = true;
} else { } else {
return "bind: invalid flag"; return "bind: invalid flag";
} }
@ -2067,8 +2079,9 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
return "Invalid catchall, catchall keybinds are only allowed in submaps."; return "Invalid catchall, catchall keybinds are only allowed in submaps.";
} }
g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, g_pKeybindManager->addKeybind(SKeybind{
release, repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription}); parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, release,
repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription, dontInhibit});
} }
return {}; return {};
@ -2088,16 +2101,17 @@ std::optional<std::string> CConfigManager::handleUnbind(const std::string& comma
bool windowRuleValid(const std::string& RULE) { bool windowRuleValid(const std::string& RULE) {
static const auto rules = std::unordered_set<std::string>{ static const auto rules = std::unordered_set<std::string>{
"dimaround", "fakefullscreen", "float", "focusonactivate", "forceinput", "forcergbx", "fullscreen", "immediate", "fakefullscreen", "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile",
"keepaspectratio", "maximize", "nearestneighbor", "noanim", "noblur", "noborder", "nodim", "nofocus",
"noinitialfocus", "nomaxsize", "noshadow", "opaque", "pin", "stayfocused", "tile", "windowdance",
}; };
static const auto rulesPrefix = std::vector<std::string>{ static const auto rulesPrefix = std::vector<std::string>{
"animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move",
"opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray", "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); }); const auto VALS = CVarList(RULE, 2, ' ');
return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }) ||
(g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) ||
(g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end());
} }
bool layerRuleValid(const std::string& RULE) { bool layerRuleValid(const std::string& RULE) {
@ -2423,11 +2437,11 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
wsRule.borderSize = std::stoi(rule.substr(delim + 11)); wsRule.borderSize = std::stoi(rule.substr(delim + 11));
} catch (...) { return "Error parsing workspace rule bordersize: {}", rule.substr(delim + 11); } } catch (...) { return "Error parsing workspace rule bordersize: {}", rule.substr(delim + 11); }
else if ((delim = rule.find("border:")) != std::string::npos) else if ((delim = rule.find("border:")) != std::string::npos)
wsRule.border = configStringToInt(rule.substr(delim + 7)); wsRule.noBorder = !configStringToInt(rule.substr(delim + 7));
else if ((delim = rule.find("shadow:")) != std::string::npos) else if ((delim = rule.find("shadow:")) != std::string::npos)
wsRule.shadow = configStringToInt(rule.substr(delim + 7)); wsRule.noShadow = !configStringToInt(rule.substr(delim + 7));
else if ((delim = rule.find("rounding:")) != std::string::npos) else if ((delim = rule.find("rounding:")) != std::string::npos)
wsRule.rounding = configStringToInt(rule.substr(delim + 9)); wsRule.noRounding = !configStringToInt(rule.substr(delim + 9));
else if ((delim = rule.find("decorate:")) != std::string::npos) else if ((delim = rule.find("decorate:")) != std::string::npos)
wsRule.decorate = configStringToInt(rule.substr(delim + 9)); wsRule.decorate = configStringToInt(rule.substr(delim + 9));
else if ((delim = rule.find("monitor:")) != std::string::npos) else if ((delim = rule.find("monitor:")) != std::string::npos)

View file

@ -39,10 +39,10 @@ struct SWorkspaceRule {
std::optional<CCssGapData> gapsIn; std::optional<CCssGapData> gapsIn;
std::optional<CCssGapData> gapsOut; std::optional<CCssGapData> gapsOut;
std::optional<int64_t> borderSize; std::optional<int64_t> borderSize;
std::optional<int> border; std::optional<bool> decorate;
std::optional<int> rounding; std::optional<bool> noRounding;
std::optional<int> decorate; std::optional<bool> noBorder;
std::optional<int> shadow; std::optional<bool> noShadow;
std::optional<std::string> onCreatedEmptyRunCmd; std::optional<std::string> onCreatedEmptyRunCmd;
std::optional<std::string> defaultName; std::optional<std::string> defaultName;
std::map<std::string, std::string> layoutopts; std::map<std::string, std::string> layoutopts;
@ -101,7 +101,6 @@ class CConfigManager {
void* const* getConfigValuePtr(const std::string&); void* const* getConfigValuePtr(const std::string&);
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = ""); Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load); void onPluginLoadUnload(const std::string& name, bool load);
static std::string getConfigDir();
static std::string getMainConfigPath(); static std::string getMainConfigPath();
const std::string getConfigString(); const std::string getConfigString();
@ -130,9 +129,6 @@ class CConfigManager {
void performMonitorReload(); void performMonitorReload();
void appendMonitorRule(const SMonitorRule&); void appendMonitorRule(const SMonitorRule&);
bool replaceMonitorRule(const SMonitorRule&); bool replaceMonitorRule(const SMonitorRule&);
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
void ensureMonitorStatus(); void ensureMonitorStatus();
void ensureVRR(CMonitor* pMonitor = nullptr); void ensureVRR(CMonitor* pMonitor = nullptr);
@ -148,25 +144,55 @@ class CConfigManager {
std::string getErrors(); std::string getErrors();
// keywords // keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&); std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&); std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&); std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&); std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&); std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&); std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&); std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&); std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&); std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&); std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&); std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&); std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&); std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&); std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&); std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&); std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&); std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::string configCurrentPath; std::string configCurrentPath;
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(PHLWINDOW)>> mbWindowProperties = {
{"allowsinput", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(PHLWINDOW)>> miWindowProperties = {
{"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
private: private:
std::unique_ptr<Hyprlang::CConfig> m_pConfig; std::unique_ptr<Hyprlang::CConfig> m_pConfig;
@ -200,14 +226,15 @@ class CConfigManager {
std::string m_szConfigErrors = ""; std::string m_szConfigErrors = "";
// internal methods // internal methods
void setAnimForChildren(SAnimationPropertyConfig* const); void setAnimForChildren(SAnimationPropertyConfig* const);
void updateBlurredLS(const std::string&, const bool); void updateBlurredLS(const std::string&, const bool);
void setDefaultAnimationVars(); void setDefaultAnimationVars();
std::optional<std::string> resetHLConfig(); std::optional<std::string> resetHLConfig();
std::optional<std::string> verifyConfigExists(); static std::optional<std::string> generateConfig(std::string configPath);
void postConfigReload(const Hyprlang::CParseResult& result); static std::optional<std::string> verifyConfigExists();
void reload(); void postConfigReload(const Hyprlang::CParseResult& result);
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); void reload();
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);
}; };
inline std::unique_ptr<CConfigManager> g_pConfigManager; inline std::unique_ptr<CConfigManager> g_pConfigManager;

View file

@ -5,6 +5,7 @@
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <filesystem>
#include "../plugins/PluginSystem.hpp" #include "../plugins/PluginSystem.hpp"
#include "../signal-safe.hpp" #include "../signal-safe.hpp"
@ -104,7 +105,19 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += GIT_COMMIT_HASH; finalCrashReport += GIT_COMMIT_HASH;
finalCrashReport += "\nTag: "; finalCrashReport += "\nTag: ";
finalCrashReport += GIT_TAG; finalCrashReport += GIT_TAG;
finalCrashReport += "\n\n"; finalCrashReport += "\nDate: ";
finalCrashReport += GIT_COMMIT_DATE;
finalCrashReport += "\nFlags:\n";
#ifdef LEGACY_RENDERER
finalCrashReport += "legacyrenderer\n";
#endif
#ifndef ISDEBUG
finalCrashReport += "debug\n";
#endif
#ifdef NO_XWAYLAND
finalCrashReport += "no xwayland\n";
#endif
finalCrashReport += "\n";
if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) { if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) {
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n"; finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";

View file

@ -12,6 +12,8 @@
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include <sys/poll.h> #include <sys/poll.h>
#include <filesystem>
#include <ranges>
#include <sstream> #include <sstream>
#include <string> #include <string>
@ -20,6 +22,7 @@
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
#include <aquamarine/input/Input.hpp>
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
@ -53,20 +56,15 @@ static std::string formatToString(uint32_t drmFormat) {
static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) { static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) {
std::string result; std::string result;
if (!wl_list_empty(&pMonitor->output->modes)) { for (auto& m : pMonitor->output->modes) {
wlr_output_mode* mode; if (format == FORMAT_NORMAL)
result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0);
wl_list_for_each(mode, &pMonitor->output->modes, link) { else
result += std::format("\"{}x{}@{:.2f}Hz\",", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0);
if (format == FORMAT_NORMAL)
result += std::format("{}x{}@{:.2f}Hz ", mode->width, mode->height, mode->refresh / 1000.0);
else
result += std::format("\"{}x{}@{:.2f}Hz\",", mode->width, mode->height, mode->refresh / 1000.0);
}
result.pop_back();
} }
trimTrailingComma(result);
return result; return result;
} }
@ -75,8 +73,10 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
if (!m->output || m->ID == -1ull) if (!m->output || m->ID == -1ull)
return ""; return "";
result += std::format( if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
R"#({{
result += std::format(
R"#({{
"id": {}, "id": {},
"name": "{}", "name": "{}",
"description": "{}", "description": "{}",
@ -107,14 +107,27 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"currentFormat": "{}", "currentFormat": "{}",
"availableModes": [{}] "availableModes": [{}]
}},)#", }},)#",
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make ? m->output->make : ""),
escapeJSONStrings(m->output->model ? m->output->model : ""), escapeJSONStrings(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make), escapeJSONStrings(m->output->model),
m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), escapeJSONStrings(m->output->serial), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
m->activeSpecialWorkspaceID(), escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(),
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"),
(m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
} else {
result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"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->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing,
!m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
}
return result; return result;
} }
@ -144,16 +157,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
if (!m->output || m->ID == -1ull) if (!m->output || m->ID == -1ull)
continue; continue;
result += std::format( result +=
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(), m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
(!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false),
m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
} }
} }
@ -317,10 +330,10 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) : std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) :
""; "";
const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : ""; const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : "";
const std::string border = (bool)(r.border) ? std::format(",\n \"border\": {}", boolToString(r.border.value())) : ""; const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : "";
const std::string rounding = (bool)(r.rounding) ? std::format(",\n \"rounding\": {}", boolToString(r.rounding.value())) : ""; const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : "";
const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : ""; const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : "";
const std::string shadow = (bool)(r.shadow) ? std::format(",\n \"shadow\": {}", boolToString(r.shadow.value())) : ""; const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : "";
std::string result = std::format(R"#({{ std::string result = std::format(R"#({{
"workspaceString": "{}"{}{}{}{}{}{}{}{} "workspaceString": "{}"{}{}{}{}{}{}{}{}
@ -339,10 +352,10 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) : std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) :
std::format("\tgapsOut: <unset>\n"); std::format("\tgapsOut: <unset>\n");
const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>"); const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>");
const std::string border = std::format("\tborder: {}\n", (bool)(r.border) ? boolToString(r.border.value()) : "<unset>"); const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : "<unset>");
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.rounding) ? boolToString(r.rounding.value()) : "<unset>"); const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>");
const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>"); const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>");
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.shadow) ? boolToString(r.shadow.value()) : "<unset>"); const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : "<unset>");
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow); borderSize, border, rounding, decorate, shadow);
@ -552,8 +565,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
"defaultSpeed": {:.5f} "defaultSpeed": {:.5f}
}},)#", }},)#",
(uintptr_t)m.get(), escapeJSONStrings(m->hlName), (uintptr_t)m.get(), escapeJSONStrings(m->hlName),
wlr_input_device_is_libinput(&m->wlr()->base) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) : m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f);
0.f);
} }
trimTrailingComma(result); trimTrailingComma(result);
@ -611,9 +623,8 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
R"#( {{ R"#( {{
"address": "0x{:x}", "address": "0x{:x}",
"type": "tabletTool", "type": "tabletTool",
"belongsTo": "0x{:x}"
}},)#", }},)#",
(uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); (uintptr_t)d.get());
} }
trimTrailingComma(result); trimTrailingComma(result);
@ -641,7 +652,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
"address": "0x{:x}", "address": "0x{:x}",
"name": "{}" "name": "{}"
}},)#", }},)#",
(uintptr_t)&d, escapeJSONStrings(d.pWlrDevice ? d.pWlrDevice->name : "")); (uintptr_t)&d, escapeJSONStrings(d.pDevice ? d.pDevice->getName() : ""));
} }
trimTrailingComma(result); trimTrailingComma(result);
@ -654,9 +665,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
for (auto& m : g_pInputManager->m_vPointers) { for (auto& m : g_pInputManager->m_vPointers) {
result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", (uintptr_t)m.get(), m->hlName, result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", (uintptr_t)m.get(), m->hlName,
(wlr_input_device_is_libinput(&m->wlr()->base) ? (m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f));
libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) :
0.f));
} }
result += "\n\nKeyboards:\n"; result += "\n\nKeyboards:\n";
@ -675,11 +684,11 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
} }
for (auto& d : g_pInputManager->m_vTablets) { for (auto& d : g_pInputManager->m_vTablets) {
result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->wlr()->width_mm, d->wlr()->height_mm); result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->aq()->physicalSize.x, d->aq()->physicalSize.y);
} }
for (auto& d : g_pInputManager->m_vTabletTools) { for (auto& d : g_pInputManager->m_vTabletTools) {
result += std::format("\tTablet Tool at {:x} (belongs to {:x})\n", (uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); result += std::format("\tTablet Tool at {:x}\n", (uintptr_t)d.get());
} }
result += "\n\nTouch:\n"; result += "\n\nTouch:\n";
@ -691,7 +700,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
result += "\n\nSwitches:\n"; result += "\n\nSwitches:\n";
for (auto& d : g_pInputManager->m_lSwitches) { for (auto& d : g_pInputManager->m_lSwitches) {
result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pWlrDevice ? d.pWlrDevice->name : ""); result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pDevice ? d.pDevice->getName() : "");
} }
} }
@ -1125,24 +1134,22 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ
if (PKEYBOARD == g_pInputManager->m_vKeyboards.end()) if (PKEYBOARD == g_pInputManager->m_vKeyboards.end())
return "device not found"; return "device not found";
const auto PWLRKEYBOARD = (*PKEYBOARD)->wlr(); const auto KEEB = *PKEYBOARD;
const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap);
const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap);
xkb_layout_index_t activeLayout = 0; xkb_layout_index_t activeLayout = 0;
while (activeLayout < LAYOUTS) { while (activeLayout < LAYOUTS) {
if (xkb_state_layout_index_is_active(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1)
break; break;
activeLayout++; activeLayout++;
} }
if (CMD == "next") { if (CMD == "next")
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1);
activeLayout > LAYOUTS ? 0 : activeLayout + 1); else if (CMD == "prev")
} else if (CMD == "prev") { KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, else {
activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
} else {
int requestedLayout = 0; int requestedLayout = 0;
try { try {
requestedLayout = std::stoi(CMD); requestedLayout = std::stoi(CMD);
@ -1152,7 +1159,7 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ
return "layout idx out of range of " + std::to_string(LAYOUTS); return "layout idx out of range of " + std::to_string(LAYOUTS);
} }
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, requestedLayout); KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout);
} }
return "ok"; return "ok";
@ -1202,74 +1209,44 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
const auto PROP = vars[2]; const auto PROP = vars[2];
const auto VAL = vars[3]; const auto VAL = vars[3];
auto noFocus = PWINDOW->m_sAdditionalConfigData.noFocus; bool noFocus = PWINDOW->m_sWindowData.noFocus.valueOrDefault();
bool lock = false;
if (request.ends_with("lock"))
lock = true;
try { try {
if (PROP == "animationstyle") { if (PROP == "animationstyle") {
PWINDOW->m_sAdditionalConfigData.animationStyle = VAL; PWINDOW->m_sWindowData.animationStyle = CWindowOverridableVar(VAL, PRIORITY_SET_PROP);
} else if (PROP == "rounding") {
PWINDOW->m_sAdditionalConfigData.rounding.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoblur") {
PWINDOW->m_sAdditionalConfigData.forceNoBlur.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceopaque") {
PWINDOW->m_sAdditionalConfigData.forceOpaque.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceopaqueoverriden") {
PWINDOW->m_sAdditionalConfigData.forceOpaqueOverridden.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceallowsinput") {
PWINDOW->m_sAdditionalConfigData.forceAllowsInput.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoanims") {
PWINDOW->m_sAdditionalConfigData.forceNoAnims.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoborder") {
PWINDOW->m_sAdditionalConfigData.forceNoBorder.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoshadow") {
PWINDOW->m_sAdditionalConfigData.forceNoShadow.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenodim") {
PWINDOW->m_sAdditionalConfigData.forceNoDim.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nofocus") {
PWINDOW->m_sAdditionalConfigData.noFocus.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "windowdancecompat") {
PWINDOW->m_sAdditionalConfigData.windowDanceCompat.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nomaxsize") {
PWINDOW->m_sAdditionalConfigData.noMaxSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "maxsize") { } else if (PROP == "maxsize") {
PWINDOW->m_sAdditionalConfigData.maxSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock); PWINDOW->m_sWindowData.maxSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
if (lock) { PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sWindowData.maxSize.value().x, PWINDOW->m_vRealSize.goal().x),
PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x), std::min((double)PWINDOW->m_sWindowData.maxSize.value().y, PWINDOW->m_vRealSize.goal().y));
std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y)); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); PWINDOW->setHidden(false);
PWINDOW->setHidden(false);
}
} else if (PROP == "minsize") { } else if (PROP == "minsize") {
PWINDOW->m_sAdditionalConfigData.minSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock); PWINDOW->m_sWindowData.minSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
if (lock) { PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sWindowData.minSize.value().x, PWINDOW->m_vRealSize.goal().x),
PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x), std::max((double)PWINDOW->m_sWindowData.minSize.value().y, PWINDOW->m_vRealSize.goal().y));
std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y)); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); PWINDOW->setHidden(false);
PWINDOW->setHidden(false);
}
} else if (PROP == "dimaround") {
PWINDOW->m_sAdditionalConfigData.dimAround.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alphaoverride") {
PWINDOW->m_sSpecialRenderData.alphaOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alpha") { } else if (PROP == "alpha") {
PWINDOW->m_sSpecialRenderData.alpha.forceSetIgnoreLocked(std::stof(VAL), lock); PWINDOW->m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alpha.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactiveoverride") {
PWINDOW->m_sSpecialRenderData.alphaInactiveOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alphainactive") { } else if (PROP == "alphainactive") {
PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock); PWINDOW->m_sWindowData.alphaInactive =
} else if (PROP == "alphafullscreenoverride") { CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
PWINDOW->m_sSpecialRenderData.alphaFullscreenOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alphafullscreen") { } else if (PROP == "alphafullscreen") {
PWINDOW->m_sSpecialRenderData.alphaFullscreen.forceSetIgnoreLocked(std::stof(VAL), lock); PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphaoverride") {
PWINDOW->m_sWindowData.alpha =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactiveoverride") {
PWINDOW->m_sWindowData.alphaInactive =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphafullscreenoverride") {
PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") { } else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") {
CGradientValueData colorData = {}; CGradientValueData colorData = {};
if (vars.size() > 4) { if (vars.size() > 4) {
for (int i = 3; i < static_cast<int>(lock ? vars.size() - 1 : vars.size()); ++i) { for (int i = 3; i < static_cast<int>(vars.size()); ++i) {
const auto TOKEN = vars[i]; const auto TOKEN = vars[i];
if (TOKEN.ends_with("deg")) if (TOKEN.ends_with("deg"))
colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0); colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0);
@ -1280,19 +1257,22 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
colorData.m_vColors.push_back(configStringToInt(VAL)); colorData.m_vColors.push_back(configStringToInt(VAL));
if (PROP == "activebordercolor") if (PROP == "activebordercolor")
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(colorData, lock); PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
else else
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(colorData, lock); PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
} else if (PROP == "forcergbx") { } else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) {
PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock); auto pWindowDataElement = search->second(PWINDOW);
} else if (PROP == "bordersize") { if (VAL == "toggle")
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock); *pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP);
} else if (PROP == "keepaspectratio") { else if (VAL == "unset")
PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock); pWindowDataElement->unset(PRIORITY_SET_PROP);
} else if (PROP == "immediate") { else
PWINDOW->m_sAdditionalConfigData.forceTearing.forceSetIgnoreLocked(configStringToInt(VAL), lock); *pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP);
} else if (PROP == "nearestneighbor") { } else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) {
PWINDOW->m_sAdditionalConfigData.nearestNeighbor.forceSetIgnoreLocked(configStringToInt(VAL), lock); if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else
*(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP);
} else { } else {
return "prop not found"; return "prop not found";
} }
@ -1300,7 +1280,7 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!(PWINDOW->m_sAdditionalConfigData.noFocus.toUnderlying() == noFocus.toUnderlying())) { if (!(PWINDOW->m_sWindowData.noFocus.valueOrDefault() == noFocus)) {
g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->focusWindow(PLASTWINDOW); g_pCompositor->focusWindow(PLASTWINDOW);
@ -1395,43 +1375,6 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request)
return result; return result;
} }
static bool addOutput(wlr_backend* backend, const std::string& type, const std::string& name) {
wlr_output* output = nullptr;
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 (addOutput(backend, DATA->type, DATA->name))
DATA->added = true;
}
std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
@ -1440,15 +1383,36 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
const auto MODE = vars[1]; const auto MODE = vars[1];
bool added = false;
if (!vars[3].empty()) {
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->szName == vars[3])
return "Name already taken";
}
}
if (MODE == "create" || MODE == "add") { if (MODE == "create" || MODE == "add") {
if (g_pCompositor->getMonitorFromName(vars[3])) if (g_pCompositor->getMonitorFromName(vars[3]))
return "A real monitor already uses that name."; return "A real monitor already uses that name.";
outputData result{vars[2], vars[3], false}; for (auto& impl : g_pCompositor->m_pAqBackend->getImplementations() | std::views::reverse) {
auto type = impl->type();
wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result); if (type == Aquamarine::AQ_BACKEND_HEADLESS && (vars[2] == "headless" || vars[2] == "auto")) {
added = true;
impl->createOutput(vars[3]);
break;
}
if (!result.added) if (type == Aquamarine::AQ_BACKEND_WAYLAND && (vars[2] == "wayland" || vars[2] == "auto")) {
added = true;
impl->createOutput(vars[3]);
break;
}
}
if (!added)
return "no backend replied to the request"; return "no backend replied to the request";
} else if (MODE == "destroy" || MODE == "remove") { } else if (MODE == "destroy" || MODE == "remove") {
@ -1460,7 +1424,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
if (!PMONITOR->createdByUser) if (!PMONITOR->createdByUser)
return "cannot remove a real display. Use the monitor keyword."; return "cannot remove a real display. Use the monitor keyword.";
wlr_output_destroy(PMONITOR->output); PMONITOR->output->destroy();
} }
return "ok"; return "ok";
@ -1848,7 +1812,6 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
} }
void CHyprCtl::startHyprCtlSocket() { void CHyprCtl::startHyprCtlSocket() {
m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (m_iSocketFD < 0) { if (m_iSocketFD < 0) {

View file

@ -10,30 +10,6 @@ void Debug::init(const std::string& IS) {
logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
} }
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
if (level > wlr_log_get_verbosity())
return;
char* outputStr = nullptr;
vasprintf(&outputStr, fmt, args);
std::string output = std::string(outputStr);
free(outputStr);
rollingLog += output + "\n";
if (!disableLogs || !**disableLogs) {
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
ofs << "[wlr] " << output << "\n";
ofs.close();
}
if (!disableStdout)
std::cout << output << "\n";
}
void Debug::log(LogLevel level, std::string str) { void Debug::log(LogLevel level, std::string str) {
if (level == TRACE && !trace) if (level == TRACE && !trace)
return; return;

View file

@ -67,6 +67,4 @@ namespace Debug {
log(level, logMsg); log(level, logMsg);
} }
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
}; };

View file

@ -74,7 +74,7 @@ CLayerSurface::~CLayerSurface() {
} }
void CLayerSurface::onDestroy() { void CLayerSurface::onDestroy() {
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface); Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get());
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
@ -114,7 +114,7 @@ void CLayerSurface::onDestroy() {
} }
void CLayerSurface::onMap() { void CLayerSurface::onMap() {
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface); Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface.get());
mapped = true; mapped = true;
interactivity = layerSurface->current.interactivity; interactivity = layerSurface->current.interactivity;
@ -177,7 +177,7 @@ void CLayerSurface::onMap() {
} }
void CLayerSurface::onUnmap() { void CLayerSurface::onUnmap() {
Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface); Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface.get());
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace}); g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace});
EMIT_HOOK_EVENT("closeLayer", self.lock()); EMIT_HOOK_EVENT("closeLayer", self.lock());
@ -212,8 +212,11 @@ void CLayerSurface::onUnmap() {
return; return;
// refocus if needed // refocus if needed
if (WASLASTFOCUS) // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
g_pInputManager->refocusLastWindow(PMONITOR); g_pInputManager->refocusLastWindow(PMONITOR);
else if (g_pCompositor->m_pLastFocus)
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);

View file

@ -55,7 +55,7 @@ void CPopup::initAllSignals() {
} }
void CPopup::onNewPopup(SP<CXDGPopupResource> popup) { void CPopup::onNewPopup(SP<CXDGPopupResource> popup) {
const auto POPUP = m_vChildren.emplace_back(std::make_unique<CPopup>(popup, this)).get(); const auto POPUP = m_vChildren.emplace_back(makeShared<CPopup>(popup, this)).get();
Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP);
} }
@ -250,7 +250,8 @@ void CPopup::recheckTree() {
} }
void CPopup::recheckChildrenRecursive() { void CPopup::recheckChildrenRecursive() {
for (auto& c : m_vChildren) { auto cpy = m_vChildren;
for (auto& c : cpy) {
c->onCommit(true); c->onCommit(true);
c->recheckChildrenRecursive(); c->recheckChildrenRecursive();
} }

View file

@ -60,8 +60,8 @@ class CPopup {
bool m_bMapped = false; bool m_bMapped = false;
// //
std::vector<std::unique_ptr<CPopup>> m_vChildren; std::vector<SP<CPopup>> m_vChildren;
std::unique_ptr<CSubsurface> m_pSubsurfaceHead; std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
struct { struct {
CHyprSignalListener newPopup; CHyprSignalListener newPopup;

View file

@ -1,6 +1,7 @@
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/LayerShell.hpp"
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_pResource = pSurface; m_pResource = pSurface;
@ -74,6 +75,16 @@ Vector2D CWLSurface::correctSmallVec() const {
return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize.value() / O->m_vReportedSize); return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize.value() / O->m_vReportedSize);
} }
Vector2D CWLSurface::correctSmallVecBuf() const {
if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.buffer)
return {};
const auto SIZE = getViewporterCorrectedSize();
const auto BS = m_pResource->current.buffer->size;
return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY});
}
Vector2D CWLSurface::getViewporterCorrectedSize() const { Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists() || !m_pResource->current.buffer) if (!exists() || !m_pResource->current.buffer)
return {}; return {};
@ -81,16 +92,15 @@ Vector2D CWLSurface::getViewporterCorrectedSize() const {
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size; return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size;
} }
CRegion CWLSurface::logicalDamage() const { CRegion CWLSurface::computeDamage() const {
if (!m_pResource->current.buffer) if (!m_pResource->current.buffer)
return {}; return {};
CRegion damage = m_pResource->accumulateCurrentBufferDamage(); CRegion damage = m_pResource->accumulateCurrentBufferDamage();
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y); damage.transform(wlTransformToHyprutils(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 BUFSIZE = m_pResource->current.buffer->size;
const auto CORRECTVEC = correctSmallVec(); const auto CORRECTVEC = correctSmallVecBuf();
if (m_pResource->current.viewport.hasSource) if (m_pResource->current.viewport.hasSource)
damage.intersect(m_pResource->current.viewport.source); damage.intersect(m_pResource->current.viewport.source);
@ -98,9 +108,20 @@ CRegion CWLSurface::logicalDamage() const {
const auto SCALEDSRCSIZE = const auto SCALEDSRCSIZE =
m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size; 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.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
damage.translate(CORRECTVEC); damage.translate(CORRECTVEC);
// go from buffer coords in the damage to hl logical
const auto BOX = getSurfaceBoxGlobal();
const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.buffer->size :
Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */};
damage.scale(SCALE);
if (m_pWindowOwner)
damage.scale(m_pWindowOwner->m_fX11SurfaceScaledBy); // fix xwayland:force_zero_scaling stuff that will be fucked by the above a bit
return damage; return damage;
} }
@ -141,27 +162,27 @@ void CWLSurface::init() {
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this); Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
} }
PHLWINDOW CWLSurface::getWindow() { PHLWINDOW CWLSurface::getWindow() const {
return m_pWindowOwner.lock(); return m_pWindowOwner.lock();
} }
PHLLS CWLSurface::getLayer() { PHLLS CWLSurface::getLayer() const {
return m_pLayerOwner.lock(); return m_pLayerOwner.lock();
} }
CPopup* CWLSurface::getPopup() { CPopup* CWLSurface::getPopup() const {
return m_pPopupOwner; return m_pPopupOwner;
} }
CSubsurface* CWLSurface::getSubsurface() { CSubsurface* CWLSurface::getSubsurface() const {
return m_pSubsurfaceOwner; return m_pSubsurfaceOwner;
} }
bool CWLSurface::desktopComponent() { bool CWLSurface::desktopComponent() const {
return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner; return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner;
} }
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() { std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const {
if (!desktopComponent()) if (!desktopComponent())
return {}; return {};
@ -181,7 +202,7 @@ void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) {
m_pConstraint = constraint; m_pConstraint = constraint;
} }
SP<CPointerConstraint> CWLSurface::constraint() { SP<CPointerConstraint> CWLSurface::constraint() const {
return m_pConstraint.lock(); return m_pConstraint.lock();
} }
@ -202,3 +223,11 @@ SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
return nullptr; return nullptr;
return pSurface->hlSurface.lock(); return pSurface->hlSurface.lock();
} }
bool CWLSurface::keyboardFocusable() const {
if (m_pWindowOwner || m_pPopupOwner || m_pSubsurfaceOwner)
return true;
if (m_pLayerOwner)
return m_pLayerOwner->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
return false;
}

View file

@ -33,22 +33,24 @@ class CWLSurface {
SP<CWLSurfaceResource> resource() const; SP<CWLSurfaceResource> resource() const;
bool exists() const; bool exists() const;
bool small() const; // means surface is smaller than the requested size bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D correctSmallVecBuf() const; // returns a corrective vector for small() surfaces, in BL coords
Vector2D getViewporterCorrectedSize() const; Vector2D getViewporterCorrectedSize() const;
CRegion logicalDamage() const; CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned
bool visible(); bool visible();
bool keyboardFocusable() const;
// getters for owners. // getters for owners.
PHLWINDOW getWindow(); PHLWINDOW getWindow() const;
PHLLS getLayer(); PHLLS getLayer() const;
CPopup* getPopup(); CPopup* getPopup() const;
CSubsurface* getSubsurface(); CSubsurface* getSubsurface() const;
// desktop components misc utils // desktop components misc utils
std::optional<CBox> getSurfaceBoxGlobal(); std::optional<CBox> getSurfaceBoxGlobal() const;
void appendConstraint(WP<CPointerConstraint> constraint); void appendConstraint(WP<CPointerConstraint> constraint);
SP<CPointerConstraint> constraint(); SP<CPointerConstraint> constraint() const;
// allow stretching. Useful for plugins. // allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false; bool m_bFillIgnoreSmall = false;
@ -107,7 +109,7 @@ class CWLSurface {
void destroy(); void destroy();
void init(); void init();
bool desktopComponent(); bool desktopComponent() const;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;

View file

@ -110,7 +110,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
const int BORDERSIZE = getRealBorderSize(); const int BORDERSIZE = getRealBorderSize();
if (m_sAdditionalConfigData.dimAround) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
@ -170,7 +170,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
} }
CBox CWindow::getFullWindowBoundingBox() { CBox CWindow::getFullWindowBoundingBox() {
if (m_sAdditionalConfigData.dimAround) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
} }
@ -218,7 +218,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
} }
CBox CWindow::getWindowBoxUnified(uint64_t properties) { CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_sAdditionalConfigData.dimAround) { if (m_sWindowData.dimAround.valueOrDefault()) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR) if (PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
@ -411,11 +411,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
setAnimationsToMove(); setAnimationsToMove();
g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID); g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID);
g_pCompositor->updateWorkspaceSpecialRenderData(OLDWORKSPACE->m_iID); g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->m_iMonitorID);
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@ -524,7 +524,7 @@ void CWindow::onUnmap() {
PMONITOR->solitaryClient.reset(); PMONITOR->solitaryClient.reset();
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@ -607,38 +607,15 @@ bool CWindow::isHidden() {
} }
void CWindow::applyDynamicRule(const SWindowRule& r) { void CWindow::applyDynamicRule(const SWindowRule& r) {
if (r.szRule == "noblur") { const eOverridePriority priority = r.szValue == "execRule" ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
m_sAdditionalConfigData.forceNoBlur = true; const CVarList VARS(r.szRule, 0, ' ');
} else if (r.szRule == "noborder") { if (r.szRule.starts_with("tag")) {
m_sAdditionalConfigData.forceNoBorder = true;
} else if (r.szRule == "noshadow") {
m_sAdditionalConfigData.forceNoShadow = true;
} else if (r.szRule == "nodim") {
m_sAdditionalConfigData.forceNoDim = true;
} else if (r.szRule == "forcergbx") {
m_sAdditionalConfigData.forceRGBX = true;
} else if (r.szRule == "opaque") {
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule == "immediate") {
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}; CVarList vars{r.szRule, 0, 's', true};
if (vars.size() == 2 && vars[0] == "tag") if (vars.size() == 2 && vars[0] == "tag")
m_tags.applyTag(vars[1], true); m_tags.applyTag(vars[1], true);
else else
Debug::log(ERR, "Tag rule invalid: {}", r.szRule); 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));
} catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("bordersize")) {
try {
m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("opacity")) { } else if (r.szRule.starts_with("opacity")) {
try { try {
CVarList vars(r.szRule, 0, ' '); CVarList vars(r.szRule, 0, ' ');
@ -651,21 +628,18 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
if (r == "override") { if (r == "override") {
if (opacityIDX == 1) if (opacityIDX == 1)
m_sSpecialRenderData.alphaOverride = true; m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
else if (opacityIDX == 2) else if (opacityIDX == 2)
m_sSpecialRenderData.alphaInactiveOverride = true; m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority);
else if (opacityIDX == 3) else if (opacityIDX == 3)
m_sSpecialRenderData.alphaFullscreenOverride = true; m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
} else { } else {
if (opacityIDX == 0) { if (opacityIDX == 0) {
m_sSpecialRenderData.alpha = std::stof(r); m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
m_sSpecialRenderData.alphaOverride = false;
} else if (opacityIDX == 1) { } else if (opacityIDX == 1) {
m_sSpecialRenderData.alphaInactive = std::stof(r); m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
m_sSpecialRenderData.alphaInactiveOverride = false;
} else if (opacityIDX == 2) { } else if (opacityIDX == 2) {
m_sSpecialRenderData.alphaFullscreen = std::stof(r); m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
m_sSpecialRenderData.alphaFullscreenOverride = false;
} else { } else {
throw std::runtime_error("more than 3 alpha values"); throw std::runtime_error("more than 3 alpha values");
} }
@ -675,17 +649,13 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} }
if (opacityIDX == 1) { if (opacityIDX == 1) {
m_sSpecialRenderData.alphaInactiveOverride = m_sSpecialRenderData.alphaOverride; m_sWindowData.alphaInactive = m_sWindowData.alpha;
m_sSpecialRenderData.alphaInactive = m_sSpecialRenderData.alpha; m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
m_sSpecialRenderData.alphaFullscreenOverride = m_sSpecialRenderData.alphaOverride;
m_sSpecialRenderData.alphaFullscreen = m_sSpecialRenderData.alpha;
} }
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "noanim") {
m_sAdditionalConfigData.forceNoAnims = true;
} else if (r.szRule.starts_with("animation")) { } else if (r.szRule.starts_with("animation")) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sAdditionalConfigData.animationStyle = STYLE; m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
} else if (r.szRule.starts_with("bordercolor")) { } else if (r.szRule.starts_with("bordercolor")) {
try { try {
// Each vector will only get used if it has at least one color // Each vector will only get used if it has at least one color
@ -696,8 +666,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
// Basic form has only two colors, everything else can be parsed as a gradient // Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) { if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))); m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))), priority);
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))); m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))), priority);
return; return;
} }
@ -720,24 +690,24 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
else if (activeBorderGradient.m_vColors.empty()) else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule); Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
else if (inactiveBorderGradient.m_vColors.empty()) else if (inactiveBorderGradient.m_vColors.empty())
m_sSpecialRenderData.activeBorderColor = activeBorderGradient; m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else { else {
m_sSpecialRenderData.activeBorderColor = activeBorderGradient; m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient; m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
} }
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "dimaround") { } else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[0]); search != g_pConfigManager->mbWindowProperties.end()) {
m_sAdditionalConfigData.dimAround = true; if (VARS[1].empty()) {
} else if (r.szRule == "keepaspectratio") { *(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority);
m_sAdditionalConfigData.keepAspectRatio = true; } else {
} else if (r.szRule.starts_with("focusonactivate")) { try {
m_sAdditionalConfigData.focusOnActivate = true; *(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]), priority);
} else if (r.szRule.starts_with("xray")) { } catch (...) {}
CVarList vars(r.szRule, 0, ' '); }
} else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) {
try { try {
m_sAdditionalConfigData.xray = configStringToInt(vars[1]); *(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[1]), priority);
} catch (...) {} } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("idleinhibit")) { } else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
@ -761,9 +731,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
return; return;
} }
m_sAdditionalConfigData.maxSize = VEC; m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
m_vRealSize = Vector2D(std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().x, m_vRealSize.goal().x), m_vRealSize =
std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().y, m_vRealSize.goal().y)); Vector2D(std::min((double)m_sWindowData.maxSize.value().x, m_vRealSize.goal().x), std::min((double)m_sWindowData.maxSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("minsize")) { } else if (r.szRule.starts_with("minsize")) {
@ -776,9 +746,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
return; return;
} }
m_sAdditionalConfigData.minSize = VEC; m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
m_vRealSize = Vector2D(std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().x, m_vRealSize.goal().x), m_vRealSize =
std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().y, m_vRealSize.goal().y)); Vector2D(std::max((double)m_sWindowData.minSize.value().x, m_vRealSize.goal().x), std::max((double)m_sWindowData.minSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
if (m_sGroupData.pNextWindow.expired()) if (m_sGroupData.pNextWindow.expired())
setHidden(false); setHidden(false);
@ -787,30 +757,20 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} }
void CWindow::updateDynamicRules() { void CWindow::updateDynamicRules() {
m_sSpecialRenderData.activeBorderColor = CGradientValueData(); m_sWindowData.alpha.unset(PRIORITY_WINDOW_RULE);
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(); m_sWindowData.alphaInactive.unset(PRIORITY_WINDOW_RULE);
m_sSpecialRenderData.alpha = 1.f; m_sWindowData.alphaFullscreen.unset(PRIORITY_WINDOW_RULE);
m_sSpecialRenderData.alphaInactive = -1.f;
m_sAdditionalConfigData.forceNoBlur = false; unsetWindowData(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.forceNoBorder = false;
m_sAdditionalConfigData.forceNoShadow = false; m_sWindowData.animationStyle.unset(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.forceNoDim = false; m_sWindowData.maxSize.unset(PRIORITY_WINDOW_RULE);
if (!m_sAdditionalConfigData.forceOpaqueOverridden) m_sWindowData.minSize.unset(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.forceOpaque = false;
m_sAdditionalConfigData.maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max()); m_sWindowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.minSize = Vector2D(20, 20); m_sWindowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.forceNoAnims = false;
m_sAdditionalConfigData.animationStyle = std::string(""); m_eIdleInhibitMode = IDLEINHIBIT_NONE;
m_sAdditionalConfigData.rounding = -1;
m_sAdditionalConfigData.dimAround = false;
m_sAdditionalConfigData.forceRGBX = false;
m_sAdditionalConfigData.borderSize = -1;
m_sAdditionalConfigData.keepAspectRatio = false;
m_sAdditionalConfigData.focusOnActivate = false;
m_sAdditionalConfigData.xray = -1;
m_sAdditionalConfigData.forceTearing = false;
m_sAdditionalConfigData.nearestNeighbor = false;
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
m_tags.removeDynamicTags(); m_tags.removeDynamicTags();
@ -887,7 +847,7 @@ void CWindow::createGroup() {
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock())); addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock()));
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@ -905,7 +865,7 @@ void CWindow::destroyGroup() {
m_sGroupData.head = false; m_sGroupData.head = false;
updateWindowDecos(); updateWindowDecos();
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@ -941,7 +901,7 @@ void CWindow::destroyGroup() {
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@ -1159,48 +1119,44 @@ bool CWindow::opaque() {
float CWindow::rounding() { float CWindow::rounding() {
static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding"); static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding");
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying(); float rounding = m_sWindowData.rounding.valueOr(*PROUNDING);
return m_sSpecialRenderData.rounding ? rounding : 0; return m_sWindowData.noRounding.valueOrDefault() ? 0 : rounding;
} }
void CWindow::updateSpecialRenderData() { void CWindow::updateWindowData() {
const auto PWORKSPACE = m_pWorkspace; const auto PWORKSPACE = m_pWorkspace;
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
updateSpecialRenderData(WORKSPACERULE); updateWindowData(WORKSPACERULE);
} }
void CWindow::updateSpecialRenderData(const SWorkspaceRule& workspaceRule) { void CWindow::updateWindowData(const SWorkspaceRule& workspaceRule) {
static auto PNOBORDERONFLOATING = CConfigValue<Hyprlang::INT>("general:no_border_on_floating"); static auto PNOBORDERONFLOATING = CConfigValue<Hyprlang::INT>("general:no_border_on_floating");
bool border = true; if (*PNOBORDERONFLOATING)
if (m_bIsFloating && *PNOBORDERONFLOATING == 1) m_sWindowData.noBorder = CWindowOverridableVar(m_bIsFloating, PRIORITY_LAYOUT);
border = false; else
m_sWindowData.noBorder.unset(PRIORITY_LAYOUT);
m_sSpecialRenderData.border = workspaceRule.border.value_or(border); m_sWindowData.borderSize.matchOptional(workspaceRule.borderSize, PRIORITY_WORKSPACE_RULE);
m_sSpecialRenderData.borderSize = workspaceRule.borderSize.value_or(-1); m_sWindowData.decorate.matchOptional(workspaceRule.decorate, PRIORITY_WORKSPACE_RULE);
m_sSpecialRenderData.decorate = workspaceRule.decorate.value_or(true); m_sWindowData.noBorder.matchOptional(workspaceRule.noBorder, PRIORITY_WORKSPACE_RULE);
m_sSpecialRenderData.rounding = workspaceRule.rounding.value_or(true); m_sWindowData.noRounding.matchOptional(workspaceRule.noRounding, PRIORITY_WORKSPACE_RULE);
m_sSpecialRenderData.shadow = workspaceRule.shadow.value_or(true); m_sWindowData.noShadow.matchOptional(workspaceRule.noShadow, PRIORITY_WORKSPACE_RULE);
} }
int CWindow::getRealBorderSize() { int CWindow::getRealBorderSize() {
if (!m_sSpecialRenderData.border || m_sAdditionalConfigData.forceNoBorder || (m_pWorkspace && m_bIsFullscreen && (m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL))) if (m_sWindowData.noBorder.valueOrDefault() || (m_pWorkspace && m_bIsFullscreen && (m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL)))
return 0; return 0;
if (m_sAdditionalConfigData.borderSize.toUnderlying() != -1)
return m_sAdditionalConfigData.borderSize.toUnderlying();
if (m_sSpecialRenderData.borderSize.toUnderlying() != -1)
return m_sSpecialRenderData.borderSize.toUnderlying();
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size"); static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
return *PBORDERSIZE; return m_sWindowData.borderSize.valueOr(*PBORDERSIZE);
} }
bool CWindow::canBeTorn() { bool CWindow::canBeTorn() {
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint); static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING;
} }
bool CWindow::shouldSendFullscreenState() { bool CWindow::shouldSendFullscreenState() {
@ -1349,8 +1305,7 @@ void CWindow::activate(bool force) {
m_bIsUrgent = true; m_bIsUrgent = true;
if (!force && if (!force && (!m_sWindowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)))
(!(*PFOCUSONACTIVATE || m_sAdditionalConfigData.focusOnActivate) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)))
return; return;
if (m_bIsFloating) if (m_bIsFloating)
@ -1389,6 +1344,7 @@ void CWindow::onUpdateMeta() {
if (m_szTitle != NEWTITLE) { if (m_szTitle != NEWTITLE) {
m_szTitle = NEWTITLE; m_szTitle = NEWTITLE;
g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)this)}); g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)this)});
g_pEventManager->postEvent(SHyprIPCEvent{"windowtitlev2", std::format("{:x},{}", (uintptr_t)this, m_szTitle)});
EMIT_HOOK_EVENT("windowTitle", m_pSelf.lock()); EMIT_HOOK_EVENT("windowTitle", m_pSelf.lock());
if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others
@ -1526,9 +1482,6 @@ void CWindow::onX11Configure(CBox box) {
m_bCreatedOverFullscreen = true; m_bCreatedOverFullscreen = true;
if (!m_sAdditionalConfigData.windowDanceCompat)
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());
} }
@ -1597,3 +1550,12 @@ PHLWINDOW CWindow::getSwallower() {
// if none are found (??) then just return the first one // if none are found (??) then just return the first one
return candidates.at(0); return candidates.at(0);
} }
void CWindow::unsetWindowData(eOverridePriority priority) {
for (auto const& element : g_pConfigManager->mbWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
for (auto const& element : g_pConfigManager->miWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
}

View file

@ -59,13 +59,36 @@ enum eSuppressEvents {
class IWindowTransformer; class IWindowTransformer;
struct SAlphaValue {
float m_fAlpha;
bool m_bOverride;
float applyAlpha(float alpha) {
if (m_bOverride)
return m_fAlpha;
else
return m_fAlpha * alpha;
};
};
enum eOverridePriority {
PRIORITY_LAYOUT,
PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP,
};
template <typename T> template <typename T>
class CWindowOverridableVar { class CWindowOverridableVar {
public: public:
CWindowOverridableVar(T const& val) { CWindowOverridableVar(T const& value, eOverridePriority priority) {
value = val; values[priority] = value;
}
CWindowOverridableVar(T const& value) {
defaultValue = value;
} }
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default; ~CWindowOverridableVar() = default;
CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> const& other) { CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> const& other) {
@ -73,112 +96,92 @@ class CWindowOverridableVar {
if (this == &other) if (this == &other)
return *this; return *this;
// Check if the current object is locked for (auto const& value : other.values) {
if (!locked) { values[value.first] = value.second;
locked = other.locked;
value = other.value;
} }
return *this; return *this;
} }
T operator=(T& other) { void unset(eOverridePriority priority) {
if (locked) values.erase(priority);
return value;
value = other;
return other;
} }
void forceSetIgnoreLocked(T const& val, bool lock = false) { bool hasValue() {
value = val; return !values.empty();
locked = lock;
} }
T operator*(T const& other) { T value() {
return value * other; if (!values.empty())
return std::prev(values.end())->second;
else
throw std::bad_optional_access();
} }
T operator+(T const& other) { T valueOr(T const& other) {
return value + other; if (hasValue())
return value();
else
return other;
} }
bool operator==(T const& other) { T valueOrDefault() {
return other == value; return valueOr(defaultValue);
} }
bool operator>=(T const& other) { eOverridePriority getPriority() {
return value >= other; if (!values.empty())
return std::prev(values.end())->first;
else
throw std::bad_optional_access();
} }
bool operator<=(T const& other) { void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
return value <= other; if (optValue.has_value())
values[priority] = optValue.value();
else
unset(priority);
} }
bool operator>(T const& other) {
return value > other;
}
bool operator<(T const& other) {
return value < other;
}
explicit operator bool() {
return static_cast<bool>(value);
}
T toUnderlying() {
return value;
}
bool locked = false;
private: private:
T value; std::map<eOverridePriority, T> values;
T defaultValue; // used for toggling, so required for bool
}; };
struct SWindowSpecialRenderData { struct SWindowData {
CWindowOverridableVar<bool> alphaOverride = false; CWindowOverridableVar<SAlphaValue> alpha = SAlphaValue{1.f, false};
CWindowOverridableVar<float> alpha = 1.f; CWindowOverridableVar<SAlphaValue> alphaInactive = SAlphaValue{1.f, false};
CWindowOverridableVar<bool> alphaInactiveOverride = false; CWindowOverridableVar<SAlphaValue> alphaFullscreen = SAlphaValue{1.f, false};
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
CWindowOverridableVar<bool> alphaFullscreenOverride = false;
CWindowOverridableVar<float> alphaFullscreen = -1.f; // -1 means unset
CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset CWindowOverridableVar<bool> allowsInput = false;
CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset CWindowOverridableVar<bool> dimAround = false;
CWindowOverridableVar<bool> decorate = true;
CWindowOverridableVar<bool> focusOnActivate = false;
CWindowOverridableVar<bool> keepAspectRatio = false;
CWindowOverridableVar<bool> nearestNeighbor = false;
CWindowOverridableVar<bool> noAnim = false;
CWindowOverridableVar<bool> noBorder = false;
CWindowOverridableVar<bool> noBlur = false;
CWindowOverridableVar<bool> noDim = false;
CWindowOverridableVar<bool> noFocus = false;
CWindowOverridableVar<bool> noMaxSize = false;
CWindowOverridableVar<bool> noRounding = false;
CWindowOverridableVar<bool> noShadow = false;
CWindowOverridableVar<bool> noShortcutsInhibit = false;
CWindowOverridableVar<bool> opaque = false;
CWindowOverridableVar<bool> RGBX = false;
CWindowOverridableVar<bool> tearing = false;
CWindowOverridableVar<bool> xray = false;
// set by the layout CWindowOverridableVar<int> rounding;
CWindowOverridableVar<int> borderSize = -1; // -1 means unset CWindowOverridableVar<int> borderSize;
bool rounding = true;
bool border = true;
bool decorate = true;
bool shadow = true;
};
struct SWindowAdditionalConfigData { CWindowOverridableVar<std::string> animationStyle;
std::string animationStyle = std::string(""); CWindowOverridableVar<Vector2D> maxSize;
CWindowOverridableVar<int> rounding = -1; // -1 means no CWindowOverridableVar<Vector2D> minSize;
CWindowOverridableVar<bool> forceNoBlur = false;
CWindowOverridableVar<bool> forceOpaque = false; CWindowOverridableVar<CGradientValueData> activeBorderColor;
CWindowOverridableVar<bool> forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher. CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
CWindowOverridableVar<bool> forceAllowsInput = false;
CWindowOverridableVar<bool> forceNoAnims = false;
CWindowOverridableVar<bool> forceNoBorder = false;
CWindowOverridableVar<bool> forceNoShadow = false;
CWindowOverridableVar<bool> forceNoDim = false;
CWindowOverridableVar<bool> noFocus = false;
CWindowOverridableVar<bool> windowDanceCompat = false;
CWindowOverridableVar<bool> noMaxSize = false;
CWindowOverridableVar<Vector2D> maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
CWindowOverridableVar<Vector2D> minSize = Vector2D(20, 20);
CWindowOverridableVar<bool> dimAround = false;
CWindowOverridableVar<bool> forceRGBX = false;
CWindowOverridableVar<bool> keepAspectRatio = false;
CWindowOverridableVar<bool> focusOnActivate = false;
CWindowOverridableVar<int> xray = -1; // -1 means unset, takes precedence over the renderdata one
CWindowOverridableVar<int> borderSize = -1; // -1 means unset, takes precedence over the renderdata one
CWindowOverridableVar<bool> forceTearing = false;
CWindowOverridableVar<bool> nearestNeighbor = false;
}; };
struct SWindowRule { struct SWindowRule {
@ -331,8 +334,7 @@ class CWindow {
std::vector<IHyprWindowDecoration*> m_vDecosToRemove; std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
// Special render data, rules, etc // Special render data, rules, etc
SWindowSpecialRenderData m_sSpecialRenderData; SWindowData m_sWindowData;
SWindowAdditionalConfigData m_sAdditionalConfigData;
// Transformers // Transformers
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers; std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
@ -423,8 +425,8 @@ class CWindow {
int surfacesCount(); int surfacesCount();
int getRealBorderSize(); int getRealBorderSize();
void updateSpecialRenderData(); void updateWindowData();
void updateSpecialRenderData(const struct SWorkspaceRule&); void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(void* ptr); void onBorderAngleAnimEnd(void* ptr);
bool isInCurvedCorner(double x, double y); bool isInCurvedCorner(double x, double y);
@ -455,6 +457,7 @@ class CWindow {
std::string fetchClass(); std::string fetchClass();
void warpCursor(); void warpCursor();
PHLWINDOW getSwallower(); PHLWINDOW getSwallower();
void unsetWindowData(eOverridePriority priority);
// listeners // listeners
void onAck(uint32_t serial); void onAck(uint32_t serial);

View file

@ -2,7 +2,21 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/varlist/VarList.hpp" #include "../helpers/varlist/VarList.hpp"
#include "../managers/input/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../managers/SeatManager.hpp"
#include "../config/ConfigManager.hpp"
#include <sys/mman.h>
#include <aquamarine/input/Input.hpp>
#include <cstring>
#define LED_COUNT 3
constexpr static std::array<const char*, 8> MODNAMES = {
XKB_MOD_NAME_SHIFT, XKB_MOD_NAME_CAPS, XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT, XKB_MOD_NAME_NUM, "Mod3", XKB_MOD_NAME_LOGO, "Mod5",
};
constexpr static std::array<const char*, 3> LEDNAMES = {XKB_LED_NAME_NUM, XKB_LED_NAME_CAPS, XKB_LED_NAME_SCROLL};
//
uint32_t IKeyboard::getCapabilities() { uint32_t IKeyboard::getCapabilities() {
return HID_INPUT_CAPABILITY_KEYBOARD; return HID_INPUT_CAPABILITY_KEYBOARD;
} }
@ -14,27 +28,167 @@ eHIDType IKeyboard::getType() {
IKeyboard::~IKeyboard() { IKeyboard::~IKeyboard() {
events.destroy.emit(); events.destroy.emit();
if (!xkbTranslationState) clearManuallyAllocd();
return; }
xkb_state_unref(xkbTranslationState); void IKeyboard::clearManuallyAllocd() {
xkbTranslationState = nullptr; if (xkbStaticState)
xkb_state_unref(xkbStaticState);
if (xkbState)
xkb_state_unref(xkbState);
if (xkbKeymap)
xkb_keymap_unref(xkbKeymap);
if (xkbKeymapFD >= 0)
close(xkbKeymapFD);
xkbKeymap = nullptr;
xkbState = nullptr;
xkbStaticState = nullptr;
xkbKeymapFD = -1;
}
void IKeyboard::setKeymap(const SStringRuleNames& rules) {
if (keymapOverridden) {
Debug::log(LOG, "Ignoring setKeymap: keymap is overridden");
return;
}
currentRules = rules;
xkb_rule_names XKBRULES = {
.rules = rules.rules.c_str(),
.model = rules.model.c_str(),
.layout = rules.layout.c_str(),
.variant = rules.variant.c_str(),
.options = rules.options.c_str(),
};
const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!CONTEXT) {
Debug::log(ERR, "setKeymap: CONTEXT null??");
return;
}
clearManuallyAllocd();
Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model,
rules.options);
if (!xkbFilePath.empty()) {
auto path = absolutePath(xkbFilePath, g_pConfigManager->configCurrentPath);
if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE)
Debug::log(ERR, "Cannot open input:kb_file= file for reading");
else {
xkbKeymap = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
fclose(KEYMAPFILE);
}
}
if (!xkbKeymap)
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!xkbKeymap) {
g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant +
", options: " + rules.options + ", layout: " + rules.layout + " )");
Debug::log(ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model,
rules.options);
memset(&XKBRULES, 0, sizeof(XKBRULES));
currentRules.rules = "";
currentRules.model = "";
currentRules.variant = "";
currentRules.options = "";
currentRules.layout = "us";
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
updateXKBTranslationState(xkbKeymap);
const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default");
if (NUMLOCKON == 1) {
// lock numlock
const auto IDX = xkb_map_mod_get_index(xkbKeymap, XKB_MOD_NAME_NUM);
if (IDX != XKB_MOD_INVALID)
modifiersState.locked |= (uint32_t)1 << IDX;
updateModifiers(modifiersState.depressed, modifiersState.latched, modifiersState.locked, modifiersState.group);
}
for (size_t i = 0; i < LEDNAMES.size(); ++i) {
ledIndexes.at(i) = xkb_map_led_get_index(xkbKeymap, LEDNAMES.at(i));
Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES.at(i), ledIndexes.at(i));
}
for (size_t i = 0; i < MODNAMES.size(); ++i) {
modIndexes.at(i) = xkb_map_mod_get_index(xkbKeymap, MODNAMES.at(i));
Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i));
}
updateKeymapFD();
xkb_context_unref(CONTEXT);
g_pSeatManager->updateActiveKeyboardData();
}
void IKeyboard::updateKeymapFD() {
Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName);
if (xkbKeymapFD >= 0)
close(xkbKeymapFD);
xkbKeymapFD = -1;
auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
xkbKeymapString = cKeymapStr;
free(cKeymapStr);
int rw, ro;
if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro))
Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap");
else {
auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0);
close(rw);
if (keymapFDDest == MAP_FAILED) {
Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap");
close(ro);
} else {
memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length());
munmap(keymapFDDest, xkbKeymapString.length() + 1);
xkbKeymapFD = ro;
}
}
Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD);
} }
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (xkbTranslationState) if (xkbStaticState)
xkb_state_unref(xkbTranslationState); xkb_state_unref(xkbStaticState);
if (xkbState)
xkb_state_unref(xkbState);
xkbState = nullptr;
xkbStaticState = nullptr;
if (keymap) { if (keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
xkbTranslationState = xkb_state_new(keymap); xkbStaticState = xkb_state_new(keymap);
xkbState = xkb_state_new(keymap);
return; return;
} }
const auto WLRKB = wlr(); const auto KEYMAP = xkbKeymap;
const auto KEYMAP = WLRKB->keymap; const auto STATE = xkbState;
const auto STATE = WLRKB->xkb_state;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
@ -73,7 +227,8 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
} }
xkbTranslationState = xkb_state_new(KEYMAP); xkbState = xkb_state_new(KEYMAP);
xkbStaticState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP); xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
@ -94,16 +249,16 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkbTranslationState = xkb_state_new(NEWKEYMAP); xkbState = xkb_state_new(NEWKEYMAP);
xkbStaticState = xkb_state_new(NEWKEYMAP);
xkb_keymap_unref(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
} }
std::string IKeyboard::getActiveLayout() { std::string IKeyboard::getActiveLayout() {
const auto WLRKB = wlr(); const auto KEYMAP = xkbKeymap;
const auto KEYMAP = WLRKB->keymap; const auto STATE = xkbState;
const auto STATE = WLRKB->xkb_state;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) { for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
@ -120,14 +275,12 @@ std::string IKeyboard::getActiveLayout() {
} }
void IKeyboard::updateLEDs() { void IKeyboard::updateLEDs() {
auto keyboard = wlr(); if (xkbState == nullptr)
if (!keyboard || keyboard->xkb_state == nullptr)
return; return;
uint32_t leds = 0; uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) { for (uint32_t i = 0; i < LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i])) if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i)))
leds |= (1 << i); leds |= (1 << i);
} }
@ -135,13 +288,88 @@ void IKeyboard::updateLEDs() {
} }
void IKeyboard::updateLEDs(uint32_t leds) { void IKeyboard::updateLEDs(uint32_t leds) {
auto keyboard = wlr(); if (!xkbState)
if (!keyboard || keyboard->xkb_state == nullptr)
return; return;
if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock())) if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock()))
return; return;
wlr_keyboard_led_update(keyboard, leds); if (!aq())
return;
aq()->updateLEDs(leds);
}
uint32_t IKeyboard::getModifiers() {
uint32_t modMask = modifiersState.depressed | modifiersState.latched;
uint32_t mods = 0;
for (size_t i = 0; i < modIndexes.size(); ++i) {
if (modIndexes.at(i) == XKB_MOD_INVALID)
continue;
if (!(modMask & (1 << modIndexes.at(i))))
continue;
mods |= (1 << i);
}
return mods;
}
void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
if (!xkbState)
return;
xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group);
if (!updateModifiersState())
return;
updateLEDs();
}
bool IKeyboard::updateModifiersState() {
if (!xkbState)
return false;
auto depressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED);
auto latched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
auto locked = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
auto group = xkb_state_serialize_layout(xkbState, XKB_STATE_LAYOUT_EFFECTIVE);
if (depressed == modifiersState.depressed && latched == modifiersState.latched && locked == modifiersState.locked && group == modifiersState.group)
return false;
modifiersState.depressed = depressed;
modifiersState.latched = latched;
modifiersState.locked = locked;
modifiersState.group = group;
return true;
}
void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
const auto contains = std::find(pressedXKB.begin(), pressedXKB.end(), xkbKey) != pressedXKB.end();
if (contains && pressed)
return;
if (!contains && !pressed)
return;
if (contains)
std::erase(pressedXKB, xkbKey);
else
pressedXKB.emplace_back(xkbKey);
xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
if (updateModifiersState()) {
keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed,
.latched = modifiersState.latched,
.locked = modifiersState.locked,
.group = modifiersState.group,
});
}
} }

View file

@ -7,15 +7,26 @@
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
struct wlr_keyboard; AQUAMARINE_FORWARD(IKeyboard);
enum eKeyboardModifiers {
HL_MODIFIER_SHIFT = (1 << 0),
HL_MODIFIER_CAPS = (1 << 1),
HL_MODIFIER_CTRL = (1 << 2),
HL_MODIFIER_ALT = (1 << 3),
HL_MODIFIER_MOD2 = (1 << 4),
HL_MODIFIER_MOD3 = (1 << 5),
HL_MODIFIER_META = (1 << 6),
HL_MODIFIER_MOD5 = (1 << 7),
};
class IKeyboard : public IHID { class IKeyboard : public IHID {
public: public:
virtual ~IKeyboard(); virtual ~IKeyboard();
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
virtual bool isVirtual() = 0; virtual bool isVirtual() = 0;
virtual wlr_keyboard* wlr() = 0; virtual SP<Aquamarine::IKeyboard> aq() = 0;
struct SKeyEvent { struct SKeyEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;
@ -24,6 +35,17 @@ class IKeyboard : public IHID {
wl_keyboard_key_state state = WL_KEYBOARD_KEY_STATE_PRESSED; wl_keyboard_key_state state = WL_KEYBOARD_KEY_STATE_PRESSED;
}; };
struct SKeymapEvent {
xkb_keymap* keymap = nullptr;
};
struct SModifiersEvent {
uint32_t depressed = 0;
uint32_t latched = 0;
uint32_t locked = 0;
uint32_t group = 0;
};
struct { struct {
CSignal key; CSignal key;
CSignal modifiers; CSignal modifiers;
@ -39,25 +61,52 @@ class IKeyboard : public IHID {
std::string rules = ""; std::string rules = "";
}; };
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); void setKeymap(const SStringRuleNames& rules);
std::string getActiveLayout(); void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
void updateLEDs(); std::string getActiveLayout();
void updateLEDs(uint32_t leds); void updateLEDs();
void updateLEDs(uint32_t leds);
uint32_t getModifiers();
void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
bool updateModifiersState(); // rets whether changed
void updateXkbStateWithKey(uint32_t xkbKey, bool pressed);
void updateKeymapFD();
bool active = false; bool active = false;
bool enabled = true; bool enabled = true;
xkb_layout_index_t activeLayout = 0; // if the keymap is overridden by the implementation,
xkb_state* xkbTranslationState = nullptr; // don't try to set keyboard rules anymore, to avoid overwriting the requested one.
// e.g. Virtual keyboards with custom maps.
bool keymapOverridden = false;
std::string hlName = ""; xkb_layout_index_t activeLayout = 0;
std::string xkbFilePath = ""; xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr;
xkb_keymap* xkbKeymap = nullptr;
SStringRuleNames currentRules; struct {
int repeatRate = 0; uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
int repeatDelay = 0; } modifiersState;
int numlockOn = -1;
bool resolveBindsBySym = false;
WP<IKeyboard> self; std::array<xkb_led_index_t, 3> ledIndexes = {XKB_MOD_INVALID};
std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID};
uint32_t leds = 0;
std::string hlName = "";
std::string xkbFilePath = "";
std::string xkbKeymapString = "";
int xkbKeymapFD = -1;
SStringRuleNames currentRules;
int repeatRate = 0;
int repeatDelay = 0;
int numlockOn = -1;
bool resolveBindsBySym = false;
WP<IKeyboard> self;
private:
void clearManuallyAllocd();
std::vector<uint32_t> pressedXKB;
}; };

View file

@ -5,17 +5,17 @@
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
struct wlr_pointer; AQUAMARINE_FORWARD(IPointer);
/* /*
Base class for a pointer. Base class for a pointer.
*/ */
class IPointer : public IHID { class IPointer : public IHID {
public: public:
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
virtual bool isVirtual() = 0; virtual bool isVirtual() = 0;
virtual wlr_pointer* wlr() = 0; virtual SP<Aquamarine::IPointer> aq() = 0;
struct SMotionEvent { struct SMotionEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;

View file

@ -5,14 +5,14 @@
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
struct wlr_touch; AQUAMARINE_FORWARD(ITouch);
class ITouch : public IHID { class ITouch : public IHID {
public: public:
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
virtual bool isVirtual() = 0; virtual bool isVirtual() = 0;
virtual wlr_touch* wlr() = 0; virtual SP<Aquamarine::ITouch> aq() = 0;
struct SDownEvent { struct SDownEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;

View file

@ -1,7 +1,10 @@
#include "Keyboard.hpp" #include "Keyboard.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../Compositor.hpp"
SP<CKeyboard> CKeyboard::create(wlr_keyboard* keeb) { #include <aquamarine/input/Input.hpp>
SP<CKeyboard> CKeyboard::create(SP<Aquamarine::IKeyboard> keeb) {
SP<CKeyboard> pKeeb = SP<CKeyboard>(new CKeyboard(keeb)); SP<CKeyboard> pKeeb = SP<CKeyboard>(new CKeyboard(keeb));
pKeeb->self = pKeeb; pKeeb->self = pKeeb;
@ -13,52 +16,41 @@ bool CKeyboard::isVirtual() {
return false; return false;
} }
wlr_keyboard* CKeyboard::wlr() { SP<Aquamarine::IKeyboard> CKeyboard::aq() {
return keyboard; return keyboard.lock();
} }
CKeyboard::CKeyboard(wlr_keyboard* keeb) : keyboard(keeb) { CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : keyboard(keeb) {
if (!keeb) if (!keeb)
return; return;
// clang-format off listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) { keyboard.reset();
disconnectCallbacks(); events.destroy.emit();
keyboard = nullptr; });
events.destroy.emit();
}, this, "CKeyboard");
hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) { listeners.key = keeb->events.key.registerListener([this](std::any d) {
auto E = (wlr_keyboard_key_event*)data; auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
keyboardEvents.key.emit(SKeyEvent{ keyboardEvents.key.emit(SKeyEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.keycode = E->keycode, .keycode = E.key,
.updateMods = E->update_state, .state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
.state = E->state,
}); });
}, this, "CKeyboard");
hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) { updateXkbStateWithKey(E.key + 8, E.pressed);
keyboardEvents.keymap.emit(); });
}, this, "CKeyboard");
hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) { listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
keyboardEvents.modifiers.emit(); updateModifiersState();
}, this, "CKeyboard");
hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) { keyboardEvents.modifiers.emit(SModifiersEvent{
keyboardEvents.repeatInfo.emit(); .depressed = modifiersState.depressed,
}, this, "CKeyboard"); .latched = modifiersState.latched,
// clang-format on .locked = modifiersState.locked,
.group = modifiersState.group,
});
});
deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN"; deviceName = keeb->getName();
}
void CKeyboard::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_key.removeCallback();
hyprListener_keymap.removeCallback();
hyprListener_repeatInfo.removeCallback();
hyprListener_modifiers.removeCallback();
} }

View file

@ -4,21 +4,19 @@
class CKeyboard : public IKeyboard { class CKeyboard : public IKeyboard {
public: public:
static SP<CKeyboard> create(wlr_keyboard* keeb); static SP<CKeyboard> create(SP<Aquamarine::IKeyboard> keeb);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_keyboard* wlr(); virtual SP<Aquamarine::IKeyboard> aq();
private: private:
CKeyboard(wlr_keyboard* keeb); CKeyboard(SP<Aquamarine::IKeyboard> keeb);
wlr_keyboard* keyboard = nullptr; WP<Aquamarine::IKeyboard> keyboard;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener key;
DYNLISTENER(key); CHyprSignalListener modifiers;
DYNLISTENER(modifiers); } listeners;
DYNLISTENER(keymap);
DYNLISTENER(repeatInfo);
}; };

View file

@ -1,7 +1,8 @@
#include "Mouse.hpp" #include "Mouse.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include <aquamarine/input/Input.hpp>
SP<CMouse> CMouse::create(wlr_pointer* mouse) { SP<CMouse> CMouse::create(SP<Aquamarine::IPointer> mouse) {
SP<CMouse> pMouse = SP<CMouse>(new CMouse(mouse)); SP<CMouse> pMouse = SP<CMouse>(new CMouse(mouse));
pMouse->self = pMouse; pMouse->self = pMouse;
@ -9,166 +10,143 @@ SP<CMouse> CMouse::create(wlr_pointer* mouse) {
return pMouse; return pMouse;
} }
CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) { CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
if (!mouse) if (!mouse)
return; return;
// clang-format off listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) { mouse.reset();
disconnectCallbacks();
mouse = nullptr;
events.destroy.emit(); events.destroy.emit();
}, this, "CMouse"); });
hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) { listeners.motion = mouse->events.move.registerListener([this](std::any d) {
auto E = (wlr_pointer_motion_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SMoveEvent>(d);
pointerEvents.motion.emit(SMotionEvent{ pointerEvents.motion.emit(SMotionEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.delta = {E->delta_x, E->delta_y}, .delta = E.delta,
.unaccel = {E->unaccel_dx, E->unaccel_dy}, .unaccel = E.unaccel,
}); });
}, this, "CMouse"); });
hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) { listeners.motionAbsolute = mouse->events.warp.registerListener([this](std::any d) {
auto E = (wlr_pointer_motion_absolute_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SWarpEvent>(d);
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.absolute = {E->x, E->y}, .absolute = E.absolute,
.device = self.lock(), .device = self.lock(),
}); });
}, this, "CMouse"); });
hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) { listeners.button = mouse->events.button.registerListener([this](std::any d) {
auto E = (wlr_pointer_button_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SButtonEvent>(d);
pointerEvents.button.emit(SButtonEvent{ pointerEvents.button.emit(SButtonEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.button = E->button, .button = E.button,
.state = (wl_pointer_button_state)E->state, .state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
}); });
}, this, "CMouse"); });
hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) { listeners.axis = mouse->events.axis.registerListener([this](std::any d) {
auto E = (wlr_pointer_axis_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SAxisEvent>(d);
pointerEvents.axis.emit(SAxisEvent{ pointerEvents.axis.emit(SAxisEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.source = E->source, .source = (wl_pointer_axis_source)E.source,
.axis = E->orientation, .axis = (wl_pointer_axis)E.axis,
.relativeDirection = E->relative_direction, .relativeDirection = (wl_pointer_axis_relative_direction)E.direction,
.delta = E->delta, .delta = E.delta,
.deltaDiscrete = E->delta_discrete, .deltaDiscrete = E.discrete,
}); });
}, this, "CMouse"); });
hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) { listeners.frame = mouse->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
pointerEvents.frame.emit();
}, this, "CMouse");
hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) { listeners.swipeBegin = mouse->events.swipeBegin.registerListener([this](std::any d) {
auto E = (wlr_pointer_swipe_begin_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SSwipeBeginEvent>(d);
pointerEvents.swipeBegin.emit(SSwipeBeginEvent{ pointerEvents.swipeBegin.emit(SSwipeBeginEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
}); });
}, this, "CMouse"); });
hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) { listeners.swipeEnd = mouse->events.swipeEnd.registerListener([this](std::any d) {
auto E = (wlr_pointer_swipe_end_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SSwipeEndEvent>(d);
pointerEvents.swipeEnd.emit(SSwipeEndEvent{ pointerEvents.swipeEnd.emit(SSwipeEndEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.cancelled = E->cancelled, .cancelled = E.cancelled,
}); });
}, this, "CMouse"); });
hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) { listeners.swipeUpdate = mouse->events.swipeUpdate.registerListener([this](std::any d) {
auto E = (wlr_pointer_swipe_update_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SSwipeUpdateEvent>(d);
pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{ pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
.delta = {E->dx, E->dy}, .delta = E.delta,
}); });
}, this, "CMouse"); });
hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) { listeners.pinchBegin = mouse->events.pinchBegin.registerListener([this](std::any d) {
auto E = (wlr_pointer_pinch_begin_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SPinchBeginEvent>(d);
pointerEvents.pinchBegin.emit(SPinchBeginEvent{ pointerEvents.pinchBegin.emit(SPinchBeginEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
}); });
}, this, "CMouse"); });
hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) { listeners.pinchEnd = mouse->events.pinchEnd.registerListener([this](std::any d) {
auto E = (wlr_pointer_pinch_end_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SPinchEndEvent>(d);
pointerEvents.pinchEnd.emit(SPinchEndEvent{ pointerEvents.pinchEnd.emit(SPinchEndEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.cancelled = E->cancelled, .cancelled = E.cancelled,
}); });
}, this, "CMouse"); });
hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) { listeners.pinchUpdate = mouse->events.pinchUpdate.registerListener([this](std::any d) {
auto E = (wlr_pointer_pinch_update_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SPinchUpdateEvent>(d);
pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{ pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
.delta = {E->dx, E->dy}, .delta = E.delta,
.scale = E->scale, .scale = E.scale,
.rotation = E->rotation, .rotation = E.rotation,
}); });
}, this, "CMouse"); });
hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) { listeners.holdBegin = mouse->events.holdBegin.registerListener([this](std::any d) {
auto E = (wlr_pointer_hold_begin_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SHoldBeginEvent>(d);
pointerEvents.holdBegin.emit(SHoldBeginEvent{ pointerEvents.holdBegin.emit(SHoldBeginEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
}); });
}, this, "CMouse"); });
hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) { listeners.holdEnd = mouse->events.holdEnd.registerListener([this](std::any d) {
auto E = (wlr_pointer_hold_end_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SHoldEndEvent>(d);
pointerEvents.holdEnd.emit(SHoldEndEvent{ pointerEvents.holdEnd.emit(SHoldEndEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.cancelled = E->cancelled, .cancelled = E.cancelled,
}); });
}, this, "CMouse"); });
// clang-format on deviceName = mouse->getName();
deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN";
}
void CMouse::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_motion.removeCallback();
hyprListener_motionAbsolute.removeCallback();
hyprListener_button.removeCallback();
hyprListener_axis.removeCallback();
hyprListener_frame.removeCallback();
hyprListener_swipeBegin.removeCallback();
hyprListener_swipeEnd.removeCallback();
hyprListener_swipeUpdate.removeCallback();
hyprListener_pinchBegin.removeCallback();
hyprListener_pinchEnd.removeCallback();
hyprListener_pinchUpdate.removeCallback();
hyprListener_holdBegin.removeCallback();
hyprListener_holdEnd.removeCallback();
} }
bool CMouse::isVirtual() { bool CMouse::isVirtual() {
return false; return false;
} }
wlr_pointer* CMouse::wlr() { SP<Aquamarine::IPointer> CMouse::aq() {
return mouse; return mouse.lock();
} }

View file

@ -4,33 +4,34 @@
class CMouse : public IPointer { class CMouse : public IPointer {
public: public:
static SP<CMouse> create(wlr_pointer* mouse); static SP<CMouse> create(SP<Aquamarine::IPointer> mouse);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_pointer* wlr(); virtual SP<Aquamarine::IPointer> aq();
private: private:
CMouse(wlr_pointer* mouse); CMouse(SP<Aquamarine::IPointer> mouse);
wlr_pointer* mouse = nullptr; WP<Aquamarine::IPointer> mouse;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener motion;
DYNLISTENER(motion); CHyprSignalListener motionAbsolute;
DYNLISTENER(motionAbsolute); CHyprSignalListener button;
DYNLISTENER(button); CHyprSignalListener axis;
DYNLISTENER(axis); CHyprSignalListener frame;
DYNLISTENER(frame);
DYNLISTENER(swipeBegin); CHyprSignalListener swipeBegin;
DYNLISTENER(swipeEnd); CHyprSignalListener swipeEnd;
DYNLISTENER(swipeUpdate); CHyprSignalListener swipeUpdate;
DYNLISTENER(pinchBegin); CHyprSignalListener pinchBegin;
DYNLISTENER(pinchEnd); CHyprSignalListener pinchEnd;
DYNLISTENER(pinchUpdate); CHyprSignalListener pinchUpdate;
DYNLISTENER(holdBegin); CHyprSignalListener holdBegin;
DYNLISTENER(holdEnd); CHyprSignalListener holdEnd;
} listeners;
}; };

View file

@ -2,8 +2,9 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../protocols/Tablet.hpp" #include "../protocols/Tablet.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include <aquamarine/input/Input.hpp>
SP<CTablet> CTablet::create(wlr_tablet* tablet) { SP<CTablet> CTablet::create(SP<Aquamarine::ITablet> tablet) {
SP<CTablet> pTab = SP<CTablet>(new CTablet(tablet)); SP<CTablet> pTab = SP<CTablet>(new CTablet(tablet));
pTab->self = pTab; pTab->self = pTab;
@ -13,7 +14,7 @@ SP<CTablet> CTablet::create(wlr_tablet* tablet) {
return pTab; return pTab;
} }
SP<CTabletTool> CTabletTool::create(wlr_tablet_tool* tablet) { SP<CTabletTool> CTabletTool::create(SP<Aquamarine::ITabletTool> tablet) {
SP<CTabletTool> pTab = SP<CTabletTool>(new CTabletTool(tablet)); SP<CTabletTool> pTab = SP<CTabletTool>(new CTabletTool(tablet));
pTab->self = pTab; pTab->self = pTab;
@ -23,7 +24,7 @@ SP<CTabletTool> CTabletTool::create(wlr_tablet_tool* tablet) {
return pTab; return pTab;
} }
SP<CTabletPad> CTabletPad::create(wlr_tablet_pad* tablet) { SP<CTabletPad> CTabletPad::create(SP<Aquamarine::ITabletPad> tablet) {
SP<CTabletPad> pTab = SP<CTabletPad>(new CTabletPad(tablet)); SP<CTabletPad> pTab = SP<CTabletPad>(new CTabletPad(tablet));
pTab->self = pTab; pTab->self = pTab;
@ -33,33 +34,25 @@ SP<CTabletPad> CTabletPad::create(wlr_tablet_pad* tablet) {
return pTab; return pTab;
} }
SP<CTabletTool> CTabletTool::fromWlr(wlr_tablet_tool* tool) { static uint32_t aqUpdateToHl(uint32_t aq) {
return ((CTabletTool*)tool->data)->self.lock();
}
SP<CTablet> CTablet::fromWlr(wlr_tablet* tablet) {
return ((CTablet*)tablet->data)->self.lock();
}
static uint32_t wlrUpdateToHl(uint32_t wlr) {
uint32_t result = 0; uint32_t result = 0;
if (wlr & WLR_TABLET_TOOL_AXIS_X) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_X)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X;
if (wlr & WLR_TABLET_TOOL_AXIS_Y) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_Y)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y;
if (wlr & WLR_TABLET_TOOL_AXIS_DISTANCE) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_DISTANCE)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE;
if (wlr & WLR_TABLET_TOOL_AXIS_PRESSURE) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_PRESSURE)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE;
if (wlr & WLR_TABLET_TOOL_AXIS_TILT_X) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_TILT_X)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X;
if (wlr & WLR_TABLET_TOOL_AXIS_TILT_Y) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_TILT_Y)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y;
if (wlr & WLR_TABLET_TOOL_AXIS_ROTATION) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_ROTATION)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION;
if (wlr & WLR_TABLET_TOOL_AXIS_SLIDER) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_SLIDER)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER;
if (wlr & WLR_TABLET_TOOL_AXIS_WHEEL) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_WHEEL)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL;
return result; return result;
} }
@ -68,97 +61,81 @@ uint32_t CTablet::getCapabilities() {
return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET;
} }
wlr_tablet* CTablet::wlr() { SP<Aquamarine::ITablet> CTablet::aq() {
return tablet; return tablet.lock();
} }
CTablet::CTablet(wlr_tablet* tablet_) : tablet(tablet_) { CTablet::CTablet(SP<Aquamarine::ITablet> tablet_) : tablet(tablet_) {
if (!tablet) if (!tablet)
return; return;
tablet->data = this; listeners.destroy = tablet->events.destroy.registerListener([this](std::any d) {
tablet.reset();
// clang-format off
hyprListener_destroy.initCallback(&tablet->base.events.destroy, [this] (void* owner, void* data) {
tablet = nullptr;
disconnectCallbacks();
events.destroy.emit(); events.destroy.emit();
}, this, "CTablet"); });
hyprListener_axis.initCallback(&tablet->events.axis, [this] (void* owner, void* data) { listeners.axis = tablet->events.axis.registerListener([this](std::any d) {
auto E = (wlr_tablet_tool_axis_event*)data; auto E = std::any_cast<Aquamarine::ITablet::SAxisEvent>(d);
tabletEvents.axis.emit(SAxisEvent{ tabletEvents.axis.emit(SAxisEvent{
.tool = E->tool, .tool = E.tool,
.tablet = self.lock(), .tablet = self.lock(),
.timeMs = E->time_msec, .timeMs = E.timeMs,
.updatedAxes = wlrUpdateToHl(E->updated_axes), .updatedAxes = aqUpdateToHl(E.updatedAxes),
.axis = {E->x, E->y}, .axis = E.absolute,
.axisDelta = {E->dx, E->dy}, .axisDelta = E.delta,
.tilt = {E->tilt_x, E->tilt_y}, .tilt = E.tilt,
.pressure = E->pressure, .pressure = E.pressure,
.distance = E->distance, .distance = E.distance,
.rotation = E->rotation, .rotation = E.rotation,
.slider = E->slider, .slider = E.slider,
.wheelDelta = E->wheel_delta, .wheelDelta = E.wheelDelta,
}); });
}, this, "CTablet"); });
hyprListener_proximity.initCallback(&tablet->events.proximity, [this] (void* owner, void* data) { listeners.proximity = tablet->events.proximity.registerListener([this](std::any d) {
auto E = (wlr_tablet_tool_proximity_event*)data; auto E = std::any_cast<Aquamarine::ITablet::SProximityEvent>(d);
tabletEvents.proximity.emit(SProximityEvent{ tabletEvents.proximity.emit(SProximityEvent{
.tool = E->tool, .tool = E.tool,
.tablet = self.lock(), .tablet = self.lock(),
.timeMs = E->time_msec, .timeMs = E.timeMs,
.proximity = {E->x, E->y}, .proximity = E.absolute,
.in = E->state == WLR_TABLET_TOOL_PROXIMITY_IN, .in = E.in,
}); });
}, this, "CTablet"); });
hyprListener_tip.initCallback(&tablet->events.tip, [this] (void* owner, void* data) { listeners.tip = tablet->events.tip.registerListener([this](std::any d) {
auto E = (wlr_tablet_tool_tip_event*)data; auto E = std::any_cast<Aquamarine::ITablet::STipEvent>(d);
tabletEvents.tip.emit(STipEvent{ tabletEvents.tip.emit(STipEvent{
.tool = E->tool, .tool = E.tool,
.tablet = self.lock(), .tablet = self.lock(),
.timeMs = E->time_msec, .timeMs = E.timeMs,
.tip = {E->x, E->y}, .tip = E.absolute,
.in = E->state == WLR_TABLET_TOOL_TIP_DOWN, .in = E.down,
}); });
}, this, "CTablet"); });
hyprListener_button.initCallback(&tablet->events.button, [this] (void* owner, void* data) { listeners.button = tablet->events.button.registerListener([this](std::any d) {
auto E = (wlr_tablet_tool_button_event*)data; auto E = std::any_cast<Aquamarine::ITablet::SButtonEvent>(d);
tabletEvents.button.emit(SButtonEvent{ tabletEvents.button.emit(SButtonEvent{
.tool = E->tool, .tool = E.tool,
.tablet = self.lock(), .tablet = self.lock(),
.timeMs = E->time_msec, .timeMs = E.timeMs,
.button = E->button, .button = E.button,
.down = E->state == WLR_BUTTON_PRESSED, .down = E.down,
}); });
}, this, "CTablet"); });
// clang-format on
deviceName = tablet->base.name ? tablet->base.name : "UNKNOWN"; deviceName = tablet->getName();
} }
CTablet::~CTablet() { CTablet::~CTablet() {
if (tablet)
tablet->data = nullptr;
PROTO::tablet->recheckRegisteredDevices(); PROTO::tablet->recheckRegisteredDevices();
} }
void CTablet::disconnectCallbacks() {
hyprListener_axis.removeCallback();
hyprListener_button.removeCallback();
hyprListener_destroy.removeCallback();
hyprListener_proximity.removeCallback();
hyprListener_tip.removeCallback();
}
eHIDType CTablet::getType() { eHIDType CTablet::getType() {
return HID_TYPE_TABLET; return HID_TYPE_TABLET;
} }
@ -167,138 +144,111 @@ uint32_t CTabletPad::getCapabilities() {
return HID_INPUT_CAPABILITY_TABLET; return HID_INPUT_CAPABILITY_TABLET;
} }
wlr_tablet_pad* CTabletPad::wlr() { SP<Aquamarine::ITabletPad> CTabletPad::aq() {
return pad; return pad.lock();
} }
eHIDType CTabletPad::getType() { eHIDType CTabletPad::getType() {
return HID_TYPE_TABLET_PAD; return HID_TYPE_TABLET_PAD;
} }
CTabletPad::CTabletPad(wlr_tablet_pad* pad_) : pad(pad_) { CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
if (!pad) if (!pad)
return; return;
// clang-format off listeners.destroy = pad->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&pad->base.events.destroy, [this] (void* owner, void* data) { pad.reset();
pad = nullptr;
disconnectCallbacks();
events.destroy.emit(); events.destroy.emit();
}, this, "CTabletPad"); });
hyprListener_button.initCallback(&pad->events.button, [this] (void* owner, void* data) { listeners.button = pad->events.button.registerListener([this](std::any d) {
auto E = (wlr_tablet_pad_button_event*)data; auto E = std::any_cast<Aquamarine::ITabletPad::SButtonEvent>(d);
padEvents.button.emit(SButtonEvent{ padEvents.button.emit(SButtonEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.button = E->button, .button = E.button,
.down = E->state == WLR_BUTTON_PRESSED, .down = E.down,
.mode = E->mode, .mode = E.mode,
.group = E->group, .group = E.group,
}); });
}, this, "CTabletPad"); });
hyprListener_ring.initCallback(&pad->events.ring, [this] (void* owner, void* data) { listeners.ring = pad->events.ring.registerListener([this](std::any d) {
auto E = (wlr_tablet_pad_ring_event*)data; auto E = std::any_cast<Aquamarine::ITabletPad::SRingEvent>(d);
padEvents.ring.emit(SRingEvent{ padEvents.ring.emit(SRingEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.finger = E->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_RING_SOURCE_FINGER,
.ring = E->ring, .ring = E.ring,
.position = E->position, .position = E.pos,
.mode = E->mode, .mode = E.mode,
}); });
}, this, "CTabletPad"); });
hyprListener_strip.initCallback(&pad->events.strip, [this] (void* owner, void* data) { listeners.strip = pad->events.strip.registerListener([this](std::any d) {
auto E = (wlr_tablet_pad_strip_event*)data; auto E = std::any_cast<Aquamarine::ITabletPad::SStripEvent>(d);
padEvents.strip.emit(SStripEvent{ padEvents.strip.emit(SStripEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.finger = E->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_STRIP_SOURCE_FINGER,
.strip = E->strip, .strip = E.strip,
.position = E->position, .position = E.pos,
.mode = E->mode, .mode = E.mode,
}); });
}, this, "CTabletPad"); });
hyprListener_attach.initCallback(&pad->events.attach_tablet, [this] (void* owner, void* data) { listeners.attach = pad->events.attach.registerListener([this](std::any d) {
if (!data) ; // TODO: this doesn't do anything in aq atm
return; });
padEvents.attach.emit(CTabletTool::fromWlr((wlr_tablet_tool*)data));
}, this, "CTabletPad");
// clang-format on
deviceName = pad->base.name ? pad->base.name : "UNKNOWN"; deviceName = pad->getName();
} }
CTabletPad::~CTabletPad() { CTabletPad::~CTabletPad() {
PROTO::tablet->recheckRegisteredDevices(); PROTO::tablet->recheckRegisteredDevices();
} }
void CTabletPad::disconnectCallbacks() {
hyprListener_ring.removeCallback();
hyprListener_button.removeCallback();
hyprListener_destroy.removeCallback();
hyprListener_strip.removeCallback();
hyprListener_attach.removeCallback();
}
uint32_t CTabletTool::getCapabilities() { uint32_t CTabletTool::getCapabilities() {
return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET;
} }
wlr_tablet_tool* CTabletTool::wlr() { SP<Aquamarine::ITabletTool> CTabletTool::aq() {
return tool; return tool.lock();
} }
eHIDType CTabletTool::getType() { eHIDType CTabletTool::getType() {
return HID_TYPE_TABLET_TOOL; return HID_TYPE_TABLET_TOOL;
} }
CTabletTool::CTabletTool(wlr_tablet_tool* tool_) : tool(tool_) { CTabletTool::CTabletTool(SP<Aquamarine::ITabletTool> tool_) : tool(tool_) {
if (!tool) if (!tool)
return; return;
// clang-format off listeners.destroyTool = tool->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&tool->events.destroy, [this] (void* owner, void* data) { tool.reset();
tool = nullptr;
disconnectCallbacks();
events.destroy.emit(); events.destroy.emit();
}, this, "CTabletTool"); });
// clang-format on
if (tool->tilt) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_TILT)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT;
if (tool->pressure) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_PRESSURE)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE;
if (tool->distance) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_DISTANCE)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE;
if (tool->rotation) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_ROTATION)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION;
if (tool->slider) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_SLIDER)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER;
if (tool->wheel) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_WHEEL)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL;
tool->data = this; deviceName = std::format("{:x}-{:x}", tool->serial, tool->id);
deviceName = std::to_string(tool->hardware_serial) + std::to_string(tool->hardware_wacom);
} }
CTabletTool::~CTabletTool() { CTabletTool::~CTabletTool() {
if (tool)
tool->data = nullptr;
PROTO::tablet->recheckRegisteredDevices(); PROTO::tablet->recheckRegisteredDevices();
} }
void CTabletTool::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
listeners.destroySurface.reset();
}
SP<CWLSurfaceResource> CTabletTool::getSurface() { SP<CWLSurfaceResource> CTabletTool::getSurface() {
return pSurface.lock(); return pSurface.lock();
} }

View file

@ -6,9 +6,9 @@
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
struct wlr_tablet; AQUAMARINE_FORWARD(ITablet);
struct wlr_tablet_tool; AQUAMARINE_FORWARD(ITabletTool);
struct wlr_tablet_pad; AQUAMARINE_FORWARD(ITabletPad);
class CTabletTool; class CTabletTool;
class CTabletPad; class CTabletPad;
@ -21,13 +21,12 @@ class CWLSurfaceResource;
*/ */
class CTablet : public IHID { class CTablet : public IHID {
public: public:
static SP<CTablet> create(wlr_tablet* tablet); static SP<CTablet> create(SP<Aquamarine::ITablet> tablet);
static SP<CTablet> fromWlr(wlr_tablet* tablet);
~CTablet(); ~CTablet();
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
wlr_tablet* wlr(); SP<Aquamarine::ITablet> aq();
enum eTabletToolAxes { enum eTabletToolAxes {
HID_TABLET_TOOL_AXIS_X = (1 << 0), HID_TABLET_TOOL_AXIS_X = (1 << 0),
@ -42,46 +41,46 @@ class CTablet : public IHID {
}; };
struct SAxisEvent { struct SAxisEvent {
wlr_tablet_tool* tool; SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet; SP<CTablet> tablet;
uint32_t timeMs = 0; uint32_t timeMs = 0;
uint32_t updatedAxes = 0; // eTabletToolAxes uint32_t updatedAxes = 0; // eTabletToolAxes
Vector2D axis; Vector2D axis;
Vector2D axisDelta; Vector2D axisDelta;
Vector2D tilt; Vector2D tilt;
double pressure = 0; double pressure = 0;
double distance = 0; double distance = 0;
double rotation = 0; double rotation = 0;
double slider = 0; double slider = 0;
double wheelDelta = 0; double wheelDelta = 0;
}; };
struct SProximityEvent { struct SProximityEvent {
wlr_tablet_tool* tool; SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet; SP<CTablet> tablet;
uint32_t timeMs = 0; uint32_t timeMs = 0;
Vector2D proximity; Vector2D proximity;
bool in = false; bool in = false;
}; };
struct STipEvent { struct STipEvent {
wlr_tablet_tool* tool; SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet; SP<CTablet> tablet;
uint32_t timeMs = 0; uint32_t timeMs = 0;
Vector2D tip; Vector2D tip;
bool in = false; bool in = false;
}; };
struct SButtonEvent { struct SButtonEvent {
wlr_tablet_tool* tool; SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet; SP<CTablet> tablet;
uint32_t timeMs = 0; uint32_t timeMs = 0;
uint32_t button; uint32_t button;
bool down = false; bool down = false;
}; };
struct { struct {
@ -100,27 +99,27 @@ class CTablet : public IHID {
CBox boundBox; // output-local CBox boundBox; // output-local
private: private:
CTablet(wlr_tablet* tablet); CTablet(SP<Aquamarine::ITablet> tablet);
void disconnectCallbacks(); WP<Aquamarine::ITablet> tablet;
wlr_tablet* tablet = nullptr; struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener axis;
DYNLISTENER(axis); CHyprSignalListener proximity;
DYNLISTENER(proximity); CHyprSignalListener tip;
DYNLISTENER(tip); CHyprSignalListener button;
DYNLISTENER(button); } listeners;
}; };
class CTabletPad : public IHID { class CTabletPad : public IHID {
public: public:
static SP<CTabletPad> create(wlr_tablet_pad* pad); static SP<CTabletPad> create(SP<Aquamarine::ITabletPad> pad);
~CTabletPad(); ~CTabletPad();
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
wlr_tablet_pad* wlr(); SP<Aquamarine::ITabletPad> aq();
struct SButtonEvent { struct SButtonEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;
@ -159,23 +158,22 @@ class CTabletPad : public IHID {
std::string hlName; std::string hlName;
private: private:
CTabletPad(wlr_tablet_pad* pad); CTabletPad(SP<Aquamarine::ITabletPad> pad);
void disconnectCallbacks(); WP<Aquamarine::ITabletPad> pad;
wlr_tablet_pad* pad = nullptr; struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener ring;
DYNLISTENER(ring); CHyprSignalListener strip;
DYNLISTENER(strip); CHyprSignalListener button;
DYNLISTENER(button); CHyprSignalListener attach;
DYNLISTENER(attach); } listeners;
}; };
class CTabletTool : public IHID { class CTabletTool : public IHID {
public: public:
static SP<CTabletTool> create(wlr_tablet_tool* tool); static SP<CTabletTool> create(SP<Aquamarine::ITabletTool> tool);
static SP<CTabletTool> fromWlr(wlr_tablet_tool* tool);
~CTabletTool(); ~CTabletTool();
enum eTabletToolType { enum eTabletToolType {
@ -198,35 +196,31 @@ class CTabletTool : public IHID {
HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5), HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5),
}; };
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
wlr_tablet_tool* wlr(); SP<Aquamarine::ITabletTool> aq();
virtual eHIDType getType(); virtual eHIDType getType();
SP<CWLSurfaceResource> getSurface(); SP<CWLSurfaceResource> getSurface();
void setSurface(SP<CWLSurfaceResource>); void setSurface(SP<CWLSurfaceResource>);
WP<CTabletTool> self; WP<CTabletTool> self;
Vector2D tilt; Vector2D tilt;
bool active = false; // true if in proximity bool active = false; // true if in proximity
uint32_t toolCapabilities = 0; uint32_t toolCapabilities = 0;
bool isDown = false; bool isDown = false;
std::vector<uint32_t> buttonsDown; std::vector<uint32_t> buttonsDown;
Vector2D absolutePos; // last known absolute position. Vector2D absolutePos; // last known absolute position.
std::string hlName; std::string hlName;
private: private:
CTabletTool(wlr_tablet_tool* tool); CTabletTool(SP<Aquamarine::ITabletTool> tool);
void disconnectCallbacks(); WP<CWLSurfaceResource> pSurface;
WP<Aquamarine::ITabletTool> tool;
WP<CWLSurfaceResource> pSurface;
wlr_tablet_tool* tool = nullptr;
DYNLISTENER(destroy);
struct { struct {
CHyprSignalListener destroySurface; CHyprSignalListener destroySurface;
CHyprSignalListener destroyTool;
} listeners; } listeners;
}; };

View file

@ -1,7 +1,8 @@
#include "TouchDevice.hpp" #include "TouchDevice.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include <aquamarine/input/Input.hpp>
SP<CTouchDevice> CTouchDevice::create(wlr_touch* touch) { SP<CTouchDevice> CTouchDevice::create(SP<Aquamarine::ITouch> touch) {
SP<CTouchDevice> pTouch = SP<CTouchDevice>(new CTouchDevice(touch)); SP<CTouchDevice> pTouch = SP<CTouchDevice>(new CTouchDevice(touch));
pTouch->self = pTouch; pTouch->self = pTouch;
@ -9,78 +10,63 @@ SP<CTouchDevice> CTouchDevice::create(wlr_touch* touch) {
return pTouch; return pTouch;
} }
CTouchDevice::CTouchDevice(wlr_touch* touch_) : touch(touch_) { CTouchDevice::CTouchDevice(SP<Aquamarine::ITouch> touch_) : touch(touch_) {
if (!touch) if (!touch)
return; return;
// clang-format off listeners.destroy = touch->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&touch->base.events.destroy, [this] (void* owner, void* data) {
events.destroy.emit(); events.destroy.emit();
disconnectCallbacks(); touch.reset();
touch = nullptr; });
}, this, "CTouchDevice");
hyprListener_down.initCallback(&touch->events.down, [this] (void* owner, void* data) { listeners.down = touch->events.down.registerListener([this](std::any d) {
auto E = (wlr_touch_down_event*)data; auto E = std::any_cast<Aquamarine::ITouch::SDownEvent>(d);
touchEvents.down.emit(SDownEvent{ touchEvents.down.emit(SDownEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.touchID = E->touch_id, .touchID = E.touchID,
.pos = {E->x, E->y}, .pos = E.pos,
.device = self.lock(), .device = self.lock(),
}); });
}, this, "CTouchDevice"); });
hyprListener_up.initCallback(&touch->events.up, [this] (void* owner, void* data) { listeners.up = touch->events.up.registerListener([this](std::any d) {
auto E = (wlr_touch_up_event*)data; auto E = std::any_cast<Aquamarine::ITouch::SUpEvent>(d);
touchEvents.up.emit(SUpEvent{ touchEvents.up.emit(SUpEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.touchID = E->touch_id .touchID = E.touchID,
}); });
}, this, "CTouchDevice"); });
hyprListener_motion.initCallback(&touch->events.motion, [this] (void* owner, void* data) { listeners.motion = touch->events.move.registerListener([this](std::any d) {
auto E = (wlr_touch_motion_event*)data; auto E = std::any_cast<Aquamarine::ITouch::SMotionEvent>(d);
touchEvents.motion.emit(SMotionEvent{ touchEvents.motion.emit(SMotionEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.touchID = E->touch_id, .touchID = E.touchID,
.pos = {E->x, E->y}, .pos = E.pos,
}); });
}, this, "CTouchDevice"); });
hyprListener_cancel.initCallback(&touch->events.cancel, [this] (void* owner, void* data) { listeners.cancel = touch->events.cancel.registerListener([this](std::any d) {
auto E = (wlr_touch_cancel_event*)data; auto E = std::any_cast<Aquamarine::ITouch::SCancelEvent>(d);
touchEvents.cancel.emit(SCancelEvent{ touchEvents.cancel.emit(SCancelEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.touchID = E->touch_id .touchID = E.touchID,
}); });
}, this, "CTouchDevice"); });
hyprListener_frame.initCallback(&touch->events.frame, [this] (void* owner, void* data) { listeners.frame = touch->events.frame.registerListener([this](std::any d) { touchEvents.frame.emit(); });
touchEvents.frame.emit();
}, this, "CTouchDevice");
// clang-format on deviceName = touch->getName();
deviceName = touch->base.name ? touch->base.name : "UNKNOWN";
} }
bool CTouchDevice::isVirtual() { bool CTouchDevice::isVirtual() {
return false; return false;
} }
wlr_touch* CTouchDevice::wlr() { SP<Aquamarine::ITouch> CTouchDevice::aq() {
return touch; return touch.lock();
}
void CTouchDevice::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_down.removeCallback();
hyprListener_up.removeCallback();
hyprListener_motion.removeCallback();
hyprListener_cancel.removeCallback();
hyprListener_frame.removeCallback();
} }

View file

@ -4,22 +4,22 @@
class CTouchDevice : public ITouch { class CTouchDevice : public ITouch {
public: public:
static SP<CTouchDevice> create(wlr_touch* touch); static SP<CTouchDevice> create(SP<Aquamarine::ITouch> touch);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_touch* wlr(); virtual SP<Aquamarine::ITouch> aq();
private: private:
CTouchDevice(wlr_touch* touch); CTouchDevice(SP<Aquamarine::ITouch> touch);
wlr_touch* touch = nullptr; WP<Aquamarine::ITouch> touch;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener down;
DYNLISTENER(down); CHyprSignalListener up;
DYNLISTENER(up); CHyprSignalListener motion;
DYNLISTENER(motion); CHyprSignalListener cancel;
DYNLISTENER(cancel); CHyprSignalListener frame;
DYNLISTENER(frame); } listeners;
}; };

View file

@ -14,58 +14,42 @@ CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : keybo
if (!keeb_) if (!keeb_)
return; return;
auto keeb = keeb_->wlr(); listeners.destroy = keeb_->events.destroy.registerListener([this](std::any d) {
// clang-format off
hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) {
disconnectCallbacks();
keyboard.reset(); keyboard.reset();
events.destroy.emit(); events.destroy.emit();
}, this, "CVirtualKeyboard"); });
hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) { listeners.key = keeb_->events.key.registerListener([this](std::any d) { keyboardEvents.key.emit(d); });
auto E = (wlr_keyboard_key_event*)data; listeners.modifiers = keeb_->events.modifiers.registerListener([this](std::any d) {
auto E = std::any_cast<SModifiersEvent>(d);
keyboardEvents.key.emit(SKeyEvent{ updateModifiers(E.depressed, E.latched, E.locked, E.group);
.timeMs = E->time_msec, keyboardEvents.modifiers.emit(SModifiersEvent{
.keycode = E->keycode, .depressed = modifiersState.depressed,
.updateMods = E->update_state, .latched = modifiersState.latched,
.state = E->state, .locked = modifiersState.locked,
.group = modifiersState.group,
}); });
}, this, "CVirtualKeyboard"); });
listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) {
auto E = std::any_cast<SKeymapEvent>(d);
if (xkbKeymap)
xkb_keymap_unref(xkbKeymap);
xkbKeymap = xkb_keymap_ref(E.keymap);
keymapOverridden = true;
updateXKBTranslationState(xkbKeymap);
updateKeymapFD();
keyboardEvents.keymap.emit(d);
});
hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) { deviceName = keeb_->name;
keyboardEvents.keymap.emit();
}, this, "CVirtualKeyboard");
hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) {
keyboardEvents.modifiers.emit();
}, this, "CVirtualKeyboard");
hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) {
keyboardEvents.repeatInfo.emit();
}, this, "CVirtualKeyboard");
// clang-format on
deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN";
} }
bool CVirtualKeyboard::isVirtual() { bool CVirtualKeyboard::isVirtual() {
return true; return true;
} }
wlr_keyboard* CVirtualKeyboard::wlr() { SP<Aquamarine::IKeyboard> CVirtualKeyboard::aq() {
if (keyboard.expired()) return nullptr;
return nullptr;
return keyboard->wlr();
}
void CVirtualKeyboard::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_key.removeCallback();
hyprListener_keymap.removeCallback();
hyprListener_repeatInfo.removeCallback();
hyprListener_modifiers.removeCallback();
} }
wl_client* CVirtualKeyboard::getClient() { wl_client* CVirtualKeyboard::getClient() {

View file

@ -6,23 +6,22 @@ class CVirtualKeyboardV1Resource;
class CVirtualKeyboard : public IKeyboard { class CVirtualKeyboard : public IKeyboard {
public: public:
static SP<CVirtualKeyboard> create(SP<CVirtualKeyboardV1Resource> keeb); static SP<CVirtualKeyboard> create(SP<CVirtualKeyboardV1Resource> keeb);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_keyboard* wlr(); virtual SP<Aquamarine::IKeyboard> aq();
wl_client* getClient(); wl_client* getClient();
private: private:
CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb); CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb);
WP<CVirtualKeyboardV1Resource> keyboard; WP<CVirtualKeyboardV1Resource> keyboard;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener key;
DYNLISTENER(key); CHyprSignalListener modifiers;
DYNLISTENER(modifiers); CHyprSignalListener keymap;
DYNLISTENER(keymap); } listeners;
DYNLISTENER(repeatInfo);
}; };

View file

@ -1,5 +1,6 @@
#include "VirtualPointer.hpp" #include "VirtualPointer.hpp"
#include "../protocols/VirtualPointer.hpp" #include "../protocols/VirtualPointer.hpp"
#include <aquamarine/input/Input.hpp>
SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resource) { SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resource) {
SP<CVirtualPointer> pPointer = SP<CVirtualPointer>(new CVirtualPointer(resource)); SP<CVirtualPointer> pPointer = SP<CVirtualPointer>(new CVirtualPointer(resource));
@ -13,165 +14,37 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
if (!resource->good()) if (!resource->good())
return; return;
auto mouse = resource->wlr(); listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) {
pointer.reset();
// clang-format off
hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) {
disconnectCallbacks();
events.destroy.emit(); events.destroy.emit();
}, this, "CVirtualPointer"); });
hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) { listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
auto E = (wlr_pointer_motion_event*)data; listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) {
// we need to unpack the event and add our device here because it's required to calculate the position correctly
auto E = std::any_cast<SMotionAbsoluteEvent>(d);
E.device = self.lock();
pointerEvents.motionAbsolute.emit(E);
});
listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); });
listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); });
listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
listeners.swipeBegin = pointer->events.swipeBegin.registerListener([this](std::any d) { pointerEvents.swipeBegin.emit(d); });
listeners.swipeEnd = pointer->events.swipeEnd.registerListener([this](std::any d) { pointerEvents.swipeEnd.emit(d); });
listeners.swipeUpdate = pointer->events.swipeUpdate.registerListener([this](std::any d) { pointerEvents.swipeUpdate.emit(d); });
listeners.pinchBegin = pointer->events.pinchBegin.registerListener([this](std::any d) { pointerEvents.pinchBegin.emit(d); });
listeners.pinchEnd = pointer->events.pinchEnd.registerListener([this](std::any d) { pointerEvents.pinchEnd.emit(d); });
listeners.pinchUpdate = pointer->events.pinchUpdate.registerListener([this](std::any d) { pointerEvents.pinchUpdate.emit(d); });
listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); });
listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); });
pointerEvents.motion.emit(SMotionEvent{ deviceName = pointer->name;
.timeMs = E->time_msec,
.delta = {E->delta_x, E->delta_y},
.unaccel = {E->unaccel_dx, E->unaccel_dy},
});
}, this, "CVirtualPointer");
hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) {
auto E = (wlr_pointer_motion_absolute_event*)data;
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E->time_msec,
.absolute = {E->x, E->y},
.device = self.lock(),
});
}, this, "CVirtualPointer");
hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) {
auto E = (wlr_pointer_button_event*)data;
pointerEvents.button.emit(SButtonEvent{
.timeMs = E->time_msec,
.button = E->button,
.state = (wl_pointer_button_state)E->state,
});
}, this, "CVirtualPointer");
hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) {
auto E = (wlr_pointer_axis_event*)data;
pointerEvents.axis.emit(SAxisEvent{
.timeMs = E->time_msec,
.source = E->source,
.axis = E->orientation,
.relativeDirection = E->relative_direction,
.delta = E->delta,
.deltaDiscrete = E->delta_discrete,
});
}, this, "CVirtualPointer");
hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) {
pointerEvents.frame.emit();
}, this, "CVirtualPointer");
hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_begin_event*)data;
pointerEvents.swipeBegin.emit(SSwipeBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
});
}, this, "CVirtualPointer");
hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_end_event*)data;
pointerEvents.swipeEnd.emit(SSwipeEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
});
}, this, "CVirtualPointer");
hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_update_event*)data;
pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.delta = {E->dx, E->dy},
});
}, this, "CVirtualPointer");
hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_begin_event*)data;
pointerEvents.pinchBegin.emit(SPinchBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
});
}, this, "CVirtualPointer");
hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_end_event*)data;
pointerEvents.pinchEnd.emit(SPinchEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
});
}, this, "CVirtualPointer");
hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_update_event*)data;
pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.delta = {E->dx, E->dy},
.scale = E->scale,
.rotation = E->rotation,
});
}, this, "CVirtualPointer");
hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_hold_begin_event*)data;
pointerEvents.holdBegin.emit(SHoldBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
});
}, this, "CVirtualPointer");
hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_hold_end_event*)data;
pointerEvents.holdEnd.emit(SHoldEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
});
}, this, "CVirtualPointer");
// clang-format on
deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN";
} }
bool CVirtualPointer::isVirtual() { bool CVirtualPointer::isVirtual() {
return true; return true;
} }
void CVirtualPointer::disconnectCallbacks() { SP<Aquamarine::IPointer> CVirtualPointer::aq() {
hyprListener_destroy.removeCallback(); return nullptr;
hyprListener_motion.removeCallback();
hyprListener_motionAbsolute.removeCallback();
hyprListener_button.removeCallback();
hyprListener_axis.removeCallback();
hyprListener_frame.removeCallback();
hyprListener_swipeBegin.removeCallback();
hyprListener_swipeEnd.removeCallback();
hyprListener_swipeUpdate.removeCallback();
hyprListener_pinchBegin.removeCallback();
hyprListener_pinchEnd.removeCallback();
hyprListener_pinchUpdate.removeCallback();
hyprListener_holdBegin.removeCallback();
hyprListener_holdEnd.removeCallback();
}
wlr_pointer* CVirtualPointer::wlr() {
if (pointer.expired())
return nullptr;
return pointer->wlr();
} }

View file

@ -6,33 +6,34 @@ class CVirtualPointerV1Resource;
class CVirtualPointer : public IPointer { class CVirtualPointer : public IPointer {
public: public:
static SP<CVirtualPointer> create(SP<CVirtualPointerV1Resource> resource); static SP<CVirtualPointer> create(SP<CVirtualPointerV1Resource> resource);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_pointer* wlr(); virtual SP<Aquamarine::IPointer> aq();
private: private:
CVirtualPointer(SP<CVirtualPointerV1Resource>); CVirtualPointer(SP<CVirtualPointerV1Resource>);
WP<CVirtualPointerV1Resource> pointer; WP<CVirtualPointerV1Resource> pointer;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener motion;
DYNLISTENER(motion); CHyprSignalListener motionAbsolute;
DYNLISTENER(motionAbsolute); CHyprSignalListener button;
DYNLISTENER(button); CHyprSignalListener axis;
DYNLISTENER(axis); CHyprSignalListener frame;
DYNLISTENER(frame);
DYNLISTENER(swipeBegin); CHyprSignalListener swipeBegin;
DYNLISTENER(swipeEnd); CHyprSignalListener swipeEnd;
DYNLISTENER(swipeUpdate); CHyprSignalListener swipeUpdate;
DYNLISTENER(pinchBegin); CHyprSignalListener pinchBegin;
DYNLISTENER(pinchEnd); CHyprSignalListener pinchEnd;
DYNLISTENER(pinchUpdate); CHyprSignalListener pinchUpdate;
DYNLISTENER(holdBegin); CHyprSignalListener holdBegin;
DYNLISTENER(holdEnd); CHyprSignalListener holdEnd;
} listeners;
}; };

View file

@ -1,50 +0,0 @@
#include "Events.hpp"
#include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
// ---------------------------------------------------- //
// _____ ________ _______ _____ ______ _____ //
// | __ \| ____\ \ / /_ _/ ____| ____|/ ____| //
// | | | | |__ \ \ / / | || | | |__ | (___ //
// | | | | __| \ \/ / | || | | __| \___ \ //
// | |__| | |____ \ / _| || |____| |____ ____) | //
// |_____/|______| \/ |_____\_____|______|_____/ //
// //
// ---------------------------------------------------- //
void Events::listener_newInput(wl_listener* listener, void* data) {
const auto DEVICE = (wlr_input_device*)data;
switch (DEVICE->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
Debug::log(LOG, "Attached a keyboard with name {}", DEVICE->name);
g_pInputManager->newKeyboard(DEVICE);
break;
case WLR_INPUT_DEVICE_POINTER:
Debug::log(LOG, "Attached a mouse with name {}", DEVICE->name);
g_pInputManager->newMouse(DEVICE);
break;
case WLR_INPUT_DEVICE_TOUCH:
Debug::log(LOG, "Attached a touch device with name {}", DEVICE->name);
g_pInputManager->newTouchDevice(DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET:
Debug::log(LOG, "Attached a tablet with name {}", DEVICE->name);
g_pInputManager->newTablet(DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET_PAD:
Debug::log(LOG, "Attached a tablet pad with name {}", DEVICE->name);
g_pInputManager->newTabletPad(DEVICE);
break;
case WLR_INPUT_DEVICE_SWITCH:
Debug::log(LOG, "Attached a switch device with name {}", DEVICE->name);
g_pInputManager->newSwitch(DEVICE);
break;
default: Debug::log(WARN, "Unrecognized input device plugged in: {}", DEVICE->name); break;
}
g_pInputManager->updateCapabilities();
}

View file

@ -8,16 +8,6 @@
// //
namespace Events { namespace Events {
// Monitor events
LISTENER(change);
LISTENER(newOutput);
// DRM events
LISTENER(leaseRequest);
// Layer events
LISTENER(newLayerSurface);
// Window events // Window events
DYNLISTENFUNC(commitWindow); DYNLISTENFUNC(commitWindow);
DYNLISTENFUNC(mapWindow); DYNLISTENFUNC(mapWindow);
@ -35,15 +25,6 @@ namespace Events {
DYNLISTENFUNC(setOverrideRedirect); DYNLISTENFUNC(setOverrideRedirect);
DYNLISTENFUNC(ackConfigure); DYNLISTENFUNC(ackConfigure);
LISTENER(newInput);
// Virt Ptr
LISTENER(newVirtPtr);
// Various
LISTENER(requestSetSel);
LISTENER(requestSetPrimarySel);
// Monitor part 2 the sequel // Monitor part 2 the sequel
DYNLISTENFUNC(monitorFrame); DYNLISTENFUNC(monitorFrame);
DYNLISTENFUNC(monitorDestroy); DYNLISTENFUNC(monitorDestroy);
@ -52,16 +33,4 @@ namespace Events {
DYNLISTENFUNC(monitorNeedsFrame); DYNLISTENFUNC(monitorNeedsFrame);
DYNLISTENFUNC(monitorCommit); DYNLISTENFUNC(monitorCommit);
DYNLISTENFUNC(monitorBind); DYNLISTENFUNC(monitorBind);
// XWayland
LISTENER(surfaceXWayland);
// Renderer destroy
LISTENER(RendererDestroy);
// session
LISTENER(sessionActive);
// Session Lock
LISTENER(newSessionLock);
}; };

View file

@ -1,54 +0,0 @@
#include "Events.hpp"
#include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "../managers/CursorManager.hpp"
// ------------------------------ //
// __ __ _____ _____ _____ //
// | \/ |_ _|/ ____|/ ____| //
// | \ / | | | | (___ | | //
// | |\/| | | | \___ \| | //
// | | | |_| |_ ____) | |____ //
// |_| |_|_____|_____/ \_____| //
// //
// ------------------------------ //
void Events::listener_leaseRequest(wl_listener* listener, void* data) {
const auto REQUEST = (wlr_drm_lease_request_v1*)data;
struct wlr_drm_lease_v1* lease = wlr_drm_lease_request_v1_grant(REQUEST);
if (!lease) {
Debug::log(ERR, "Failed to grant lease request!");
wlr_drm_lease_request_v1_reject(REQUEST);
}
}
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
Debug::log(LOG, "!!Renderer destroyed!!");
}
void Events::listener_sessionActive(wl_listener* listener, void* data) {
if (g_pCompositor->m_sWLRSession->active) {
Debug::log(LOG, "Session got activated!");
g_pCompositor->m_bSessionActive = true;
for (auto& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m.get());
g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true);
}
g_pConfigManager->m_bWantsMonitorReload = true;
} else {
Debug::log(LOG, "Session got inactivated!");
g_pCompositor->m_bSessionActive = false;
for (auto& m : g_pCompositor->m_vMonitors) {
m->noFrameSchedule = true;
m->framesToSkip = 1;
}
}
}

View file

@ -5,6 +5,9 @@
#include "Events.hpp" #include "Events.hpp"
#include "../debug/HyprCtl.hpp" #include "../debug/HyprCtl.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../protocols/Screencopy.hpp"
#include "../protocols/ToplevelExport.hpp"
#include <aquamarine/output/Output.hpp>
// --------------------------------------------------------- // // --------------------------------------------------------- //
// __ __ ____ _ _ _____ _______ ____ _____ _____ // // __ __ ____ _ _ _____ _______ ____ _____ _____ //
@ -16,99 +19,10 @@
// // // //
// --------------------------------------------------------- // // --------------------------------------------------------- //
static void checkDefaultCursorWarp(SP<CMonitor> PNEWMONITOR, std::string monitorName) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static auto firstMonitorAdded = std::chrono::steady_clock::now();
static bool cursorDefaultDone = false;
static bool firstLaunch = true;
const auto POS = PNEWMONITOR->middle();
// by default, cursor should be set to first monitor detected
// this is needed as a default if the monitor given in config above doesn't exist
if (firstLaunch) {
firstLaunch = false;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY)
return;
// after 10s, don't set cursor to default monitor
auto timePassedSec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - firstMonitorAdded);
if (timePassedSec.count() > 10) {
cursorDefaultDone = true;
return;
}
if (*PCURSORMONITOR == monitorName) {
cursorDefaultDone = true;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
}
void Events::listener_newOutput(wl_listener* listener, void* data) {
// new monitor added, let's accommodate for that.
const auto OUTPUT = (wlr_output*)data;
if (!OUTPUT->name) {
Debug::log(ERR, "New monitor has no name?? Ignoring");
return;
}
// add it to real
auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>());
if (std::string("HEADLESS-1") == OUTPUT->name)
g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get();
PNEWMONITOR->output = OUTPUT;
PNEWMONITOR->self = PNEWMONITOR;
const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false;
PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name);
PNEWMONITOR->isUnsafeFallback = FALLBACK;
EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR);
if (!FALLBACK)
PNEWMONITOR->onConnect(false);
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
return;
// ready to process if we have a real monitor
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get();
g_pCompositor->m_bReadyToProcess = true;
g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get());
checkDefaultCursorWarp(PNEWMONITOR, OUTPUT->name);
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) {
w->m_iLastSurfaceMonitorID = -1;
w->updateSurfaceScaleTransformDetails();
}
}
}
void Events::listener_monitorFrame(void* owner, void* data) { void Events::listener_monitorFrame(void* owner, void* data) {
if (g_pCompositor->m_bExitTriggered) {
// Only signal cleanup once
g_pCompositor->m_bExitTriggered = false;
g_pCompositor->cleanup();
return;
}
CMonitor* const PMONITOR = (CMonitor*)owner; CMonitor* const PMONITOR = (CMonitor*)owner;
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!"); Debug::log(WARN, "Attempted to render frame on inactive session!");
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) { if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
@ -172,12 +86,10 @@ void Events::listener_monitorFrame(void* owner, void* data) {
} }
void Events::listener_monitorDestroy(void* owner, void* data) { void Events::listener_monitorDestroy(void* owner, void* data) {
const auto OUTPUT = (wlr_output*)data; CMonitor* pMonitor = (CMonitor*)owner;
CMonitor* pMonitor = nullptr;
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->output == OUTPUT) { if (m->output == pMonitor->output) {
pMonitor = m.get(); pMonitor = m.get();
break; break;
} }
@ -188,9 +100,6 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name); Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
if (pMonitor->output->idle_frame)
wl_event_source_remove(pMonitor->output->idle_frame);
pMonitor->onDisconnect(true); pMonitor->onDisconnect(true);
pMonitor->output = nullptr; pMonitor->output = nullptr;
@ -201,44 +110,18 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP<CMonitor>& el) { return el.get() == pMonitor; }); std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP<CMonitor>& el) { return el.get() == pMonitor; });
} }
void Events::listener_monitorStateRequest(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_request_state*)data;
if (!PMONITOR->createdByUser)
return;
const auto SIZE = E->state->mode ? Vector2D{E->state->mode->width, E->state->mode->height} : Vector2D{E->state->custom_mode.width, E->state->custom_mode.height};
PMONITOR->forceSize = SIZE;
SMonitorRule rule = PMONITOR->activeMonitorRule;
rule.resolution = SIZE;
g_pHyprRenderer->applyMonitorRule(PMONITOR, &rule);
}
void Events::listener_monitorDamage(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_damage*)data;
PMONITOR->addDamage(E->damage);
}
void Events::listener_monitorNeedsFrame(void* owner, void* data) { void Events::listener_monitorNeedsFrame(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner; const auto PMONITOR = (CMonitor*)owner;
g_pCompositor->scheduleFrameForMonitor(PMONITOR); g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME);
} }
void Events::listener_monitorCommit(void* owner, void* data) { void Events::listener_monitorCommit(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner; const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_commit*)data; if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
PROTO::screencopy->onOutputCommit(PMONITOR);
if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) { PROTO::toplevelExport->onOutputCommit(PMONITOR);
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
} }
} }

View file

@ -10,6 +10,7 @@
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/ToplevelExport.hpp"
#include "../xwayland/XSurface.hpp" #include "../xwayland/XSurface.hpp"
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
@ -196,8 +197,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bIsFloating = false; PWINDOW->m_bIsFloating = false;
} else if (r.szRule.starts_with("pseudo")) { } else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true; PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.starts_with("nofocus")) {
PWINDOW->m_sAdditionalConfigData.noFocus = true;
} else if (r.szRule.starts_with("noinitialfocus")) { } else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.starts_with("suppressevent")) { } else if (r.szRule.starts_with("suppressevent")) {
@ -219,12 +218,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
overridingNoFullscreen = true; overridingNoFullscreen = true;
} else if (r.szRule == "fakefullscreen") { } else if (r.szRule == "fakefullscreen") {
requestsFakeFullscreen = true; requestsFakeFullscreen = true;
} else if (r.szRule == "windowdance") {
PWINDOW->m_sAdditionalConfigData.windowDanceCompat = true;
} else if (r.szRule == "nomaxsize") {
PWINDOW->m_sAdditionalConfigData.noMaxSize = true;
} else if (r.szRule == "forceinput") {
PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true;
} else if (r.szRule == "pin") { } else if (r.szRule == "pin") {
PWINDOW->m_bPinned = true; PWINDOW->m_bPinned = true;
} else if (r.szRule == "maximize") { } else if (r.szRule == "maximize") {
@ -321,7 +314,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
workspaceSilent = false; workspaceSilent = false;
} }
PWINDOW->updateSpecialRenderData(); PWINDOW->updateWindowData();
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
@ -457,10 +450,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock(); const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock();
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) { if (PWINDOW->m_sWindowData.allowsInput.valueOrDefault()) { // if default value wasn't set to false getPriority() would throw an exception
PWINDOW->m_sAdditionalConfigData.noFocus = false; PWINDOW->m_sWindowData.noFocus = CWindowOverridableVar(false, PWINDOW->m_sWindowData.allowsInput.getPriority());
PWINDOW->m_bNoInitialFocus = false; PWINDOW->m_bNoInitialFocus = false;
PWINDOW->m_bX11ShouldntFocus = false; PWINDOW->m_bX11ShouldntFocus = false;
} }
// check LS focus grab // check LS focus grab
@ -473,18 +466,20 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
else if (*PNEWTAKESOVERFS == 2) else if (*PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), false, FULLSCREEN_INVALID); g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), false, FULLSCREEN_INVALID);
else if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) else if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
requestsMaximize = true; requestsMaximize = true;
else if (*PNEWTAKESOVERFS == 1)
overridingNoMaximize = true;
} else
requestsFullscreen = true; requestsFullscreen = true;
} }
if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus && if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus &&
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && (PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) &&
!g_pInputManager->isConstrained()) { !g_pInputManager->isConstrained()) {
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH); PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH);
} else { } else {
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(0); PWINDOW->m_fDimPercent.setValueAndWarp(0);
@ -586,6 +581,11 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "{:c} unmapped", PWINDOW); Debug::log(LOG, "{:c} unmapped", PWINDOW);
static auto PEXITRETAINSFS = CConfigValue<Hyprlang::INT>("misc:exit_window_retains_fullscreen");
const auto CURRENTWINDOWFSSTATE = PWINDOW->m_bIsFullscreen;
const auto CURRENTWINDOWFSMODE = PWINDOW->m_pWorkspace->m_efFullscreenMode;
if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) { if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) {
Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW); Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW);
PWINDOW->m_bFadingOut = false; PWINDOW->m_bFadingOut = false;
@ -602,7 +602,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)}); g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
EMIT_HOOK_EVENT("closeWindow", PWINDOW); EMIT_HOOK_EVENT("closeWindow", PWINDOW);
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW); PROTO::toplevelExport->onWindowUnmap(PWINDOW);
if (PWINDOW->m_bIsFullscreen) if (PWINDOW->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
@ -644,8 +644,11 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE); Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE);
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) {
g_pCompositor->focusWindow(PWINDOWCANDIDATE); g_pCompositor->focusWindow(PWINDOWCANDIDATE);
if (*PEXITRETAINSFS && CURRENTWINDOWFSSTATE)
g_pCompositor->setWindowFullscreen(PWINDOWCANDIDATE, true, CURRENTWINDOWFSMODE);
}
if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0) if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0)
g_pInputManager->refocus(); g_pInputManager->refocus();
@ -700,12 +703,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden()) if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
return; return;
if (PWINDOW->m_bIsX11) PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
else if (PWINDOW->m_pPendingSizeAck.has_value()) {
PWINDOW->m_vReportedSize = PWINDOW->m_pPendingSizeAck->second;
PWINDOW->m_pPendingSizeAck.reset();
}
if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) { if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) {
const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize;

View file

@ -0,0 +1,43 @@
#pragma once
#include <array>
// clang-format off
constexpr std::array<const char*, 35> CURSOR_SHAPE_NAMES = {
"invalid",
"default",
"context-menu",
"help",
"pointer",
"progress",
"wait",
"cell",
"crosshair",
"text",
"vertical-text",
"alias",
"copy",
"move",
"no-drop",
"not-allowed",
"grab",
"grabbing",
"e-resize",
"n-resize",
"ne-resize",
"nw-resize",
"s-resize",
"se-resize",
"sw-resize",
"w-resize",
"ew-resize",
"ns-resize",
"nesw-resize",
"nwse-resize",
"col-resize",
"row-resize",
"all-scroll",
"zoom-in",
"zoom-out",
};
// clang-format on

View file

@ -3,6 +3,8 @@
#include "../includes.hpp" #include "../includes.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include <xf86drm.h>
#include <drm_fourcc.h>
/* /*
DRM formats are LE, while OGL is BE. The two primary formats DRM formats are LE, while OGL is BE. The two primary formats
@ -309,3 +311,17 @@ uint32_t FormatUtils::glFormatToType(uint32_t gl) {
#endif #endif
GL_UNSIGNED_BYTE; GL_UNSIGNED_BYTE;
} }
std::string FormatUtils::drmFormatName(DRMFormat drm) {
auto n = drmGetFormatName(drm);
std::string name = n;
free(n);
return name;
}
std::string FormatUtils::drmModifierName(uint64_t mod) {
auto n = drmGetFormatModifierName(mod);
std::string name = n;
free(n);
return name;
}

View file

@ -1,7 +1,9 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <string>
#include "math/Math.hpp" #include "math/Math.hpp"
#include <aquamarine/backend/Misc.hpp>
typedef uint32_t DRMFormat; typedef uint32_t DRMFormat;
typedef uint32_t SHMFormat; typedef uint32_t SHMFormat;
@ -18,10 +20,7 @@ struct SPixelFormat {
Vector2D blockSize; Vector2D blockSize;
}; };
struct SDRMFormat { typedef Aquamarine::SDRMFormat SDRMFormat;
uint32_t format = 0;
std::vector<uint64_t> mods;
};
namespace FormatUtils { namespace FormatUtils {
SHMFormat drmToShm(DRMFormat drm); SHMFormat drmToShm(DRMFormat drm);
@ -34,4 +33,6 @@ namespace FormatUtils {
int minStride(const SPixelFormat* const fmt, int32_t width); int minStride(const SPixelFormat* const fmt, int32_t width);
uint32_t drmFormatToGL(DRMFormat drm); uint32_t drmFormatToGL(DRMFormat drm);
uint32_t glFormatToType(uint32_t gl); uint32_t glFormatToType(uint32_t gl);
std::string drmFormatName(DRMFormat drm);
std::string drmModifierName(uint64_t mod);
}; };

View file

@ -4,9 +4,12 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../managers/TokenManager.hpp" #include "../managers/TokenManager.hpp"
#include <optional> #include <optional>
#include <cstring>
#include <cmath>
#include <set> #include <set>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
@ -649,13 +652,9 @@ void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
int64_t getPPIDof(int64_t pid) { int64_t getPPIDof(int64_t pid) {
#if defined(KERN_PROC_PID) #if defined(KERN_PROC_PID)
int mib[] = { int mib[] = {
CTL_KERN, CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid,
KERN_PROC,
KERN_PROC_PID,
(int)pid,
#if defined(__NetBSD__) || defined(__OpenBSD__) #if defined(__NetBSD__) || defined(__OpenBSD__)
sizeof(KINFO_PROC), sizeof(KINFO_PROC), 1,
1,
#endif #endif
}; };
u_int miblen = sizeof(mib) / sizeof(mib[0]); u_int miblen = sizeof(mib) / sizeof(mib[0]);

View file

@ -3,7 +3,6 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/util/box.h>
#include "math/Math.hpp" #include "math/Math.hpp"
#include <vector> #include <vector>
#include <format> #include <format>

View file

@ -1,12 +1,18 @@
#include "Monitor.hpp" #include "Monitor.hpp"
#include "MiscFunctions.hpp" #include "MiscFunctions.hpp"
#include "math/Math.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../protocols/GammaControl.hpp" #include "../protocols/GammaControl.hpp"
#include "../devices/ITouch.hpp" #include "../devices/ITouch.hpp"
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/PresentationTime.hpp" #include "../protocols/PresentationTime.hpp"
#include "../protocols/DRMLease.hpp"
#include "../protocols/core/Output.hpp"
#include "../managers/PointerManager.hpp" #include "../managers/PointerManager.hpp"
#include "../protocols/core/Compositor.hpp"
#include "sync/SyncTimeline.hpp"
#include <aquamarine/output/Output.hpp>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
@ -21,62 +27,73 @@ CMonitor::CMonitor() : state(this) {
} }
CMonitor::~CMonitor() { CMonitor::~CMonitor() {
hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
hyprListener_monitorStateRequest.removeCallback();
hyprListener_monitorDamage.removeCallback();
hyprListener_monitorNeedsFrame.removeCallback();
hyprListener_monitorCommit.removeCallback();
hyprListener_monitorBind.removeCallback();
events.destroy.emit(); events.destroy.emit();
} }
static void onPresented(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
auto E = (wlr_output_event_present*)data;
PROTO::presentation->onPresented(PMONITOR, E->when, E->refresh, E->seq, E->flags);
}
void CMonitor::onConnect(bool noRule) { void CMonitor::onConnect(bool noRule) {
hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
hyprListener_monitorStateRequest.removeCallback();
hyprListener_monitorDamage.removeCallback();
hyprListener_monitorNeedsFrame.removeCallback();
hyprListener_monitorCommit.removeCallback();
hyprListener_monitorBind.removeCallback();
hyprListener_monitorPresented.removeCallback();
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this, "CMonitor");
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this, "CMonitor");
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this, "CMonitor");
hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this, "CMonitor");
hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this, "CMonitor");
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this, "CMonitor");
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this, "CMonitor");
hyprListener_monitorPresented.initCallback(&output->events.present, ::onPresented, this, "CMonitor");
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm if (output->supportsExplicit) {
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
outTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
}
listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); });
listeners.destroy = output->events.destroy.registerListener([this](std::any d) { Events::listener_monitorDestroy(this, nullptr); });
listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); });
listeners.needsFrame =
output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); });
listeners.presented = output->events.present.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IOutput::SPresentEvent>(d);
PROTO::presentation->onPresented(this, E.when, E.refresh, E.seq, E.flags);
});
listeners.state = output->events.state.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IOutput::SStateEvent>(d);
if (E.size == Vector2D{}) {
// an indication to re-set state
// we can't do much for createdByUser displays I think
if (createdByUser)
return;
Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName);
g_pHyprRenderer->applyMonitorRule(this, &activeMonitorRule, true);
return;
}
if (!createdByUser)
return;
const auto SIZE = E.size;
forceSize = SIZE;
SMonitorRule rule = activeMonitorRule;
rule.resolution = SIZE;
g_pHyprRenderer->applyMonitorRule(this, &rule);
});
tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
if (m_bEnabled) { if (m_bEnabled) {
wlr_output_state_set_enabled(state.wlr(), true); output->state->setEnabled(true);
state.commit(); state.commit();
return; return;
} }
szName = output->name; szName = output->name;
szDescription = output->description ? output->description : ""; szDescription = output->description;
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description // remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
std::erase(szDescription, ','); std::erase(szDescription, ',');
// field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix // field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix
szShortDescription = trim(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : "")); szShortDescription = trim(std::format("{} {} {}", output->make, output->model, output->serial));
std::erase(szShortDescription, ','); std::erase(szShortDescription, ',');
if (!wlr_backend_is_drm(output->backend)) if (output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM)
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable createdByUser = true; // should be true. WL and Headless backends should be addable / removable
// get monitor rule that matches // get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this); SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
@ -84,54 +101,23 @@ void CMonitor::onConnect(bool noRule) {
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { if (monitorRule.disabled) {
wlr_output_state_set_scale(state.wlr(), 1); output->state->setEnabled(false);
wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
auto PREFSTATE = wlr_output_preferred_mode(output);
if (!PREFSTATE) {
wlr_output_mode* mode;
wl_list_for_each(mode, &output->modes, link) {
wlr_output_state_set_mode(state.wlr(), mode);
if (!wlr_output_test_state(output, state.wlr()))
continue;
PREFSTATE = mode;
break;
}
}
if (PREFSTATE)
wlr_output_state_set_mode(state.wlr(), PREFSTATE);
else
Debug::log(WARN, "No mode found for disabled output {}", output->name);
wlr_output_state_set_enabled(state.wlr(), 0);
if (!state.commit()) if (!state.commit())
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name); Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
m_bEnabled = false; m_bEnabled = false;
hyprListener_monitorFrame.removeCallback(); listeners.frame.reset();
return; return;
} }
if (output->non_desktop) { if (output->nonDesktop) {
Debug::log(LOG, "Not configuring non-desktop output"); Debug::log(LOG, "Not configuring non-desktop output");
if (g_pCompositor->m_sWRLDRMLeaseMgr) { if (PROTO::lease)
wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output); PROTO::lease->offer(self.lock());
}
return;
}
if (!m_bRenderingInitPassed) { return;
output->allocator = nullptr;
output->renderer = nullptr;
wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
m_bRenderingInitPassed = true;
} }
SP<CMonitor>* thisWrapper = nullptr; SP<CMonitor>* thisWrapper = nullptr;
@ -151,18 +137,18 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true; m_bEnabled = true;
wlr_output_state_set_enabled(state.wlr(), 1); output->state->setEnabled(true);
// set mode, also applies // set mode, also applies
if (!noRule) if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
if (!state.commit()) if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit"); Debug::log(WARN, "state.commit() failed in CMonitor::onCommit");
damage.setSize(vecTransformedSize); damage.setSize(vecTransformedSize);
Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output); Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output.get());
setupDefaultWS(monitorRule); setupDefaultWS(monitorRule);
@ -214,7 +200,7 @@ void CMonitor::onConnect(bool noRule) {
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this); renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
g_pCompositor->scheduleFrameForMonitor(this); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR);
PROTO::gamma->applyGammaToState(this); PROTO::gamma->applyGammaToState(this);
@ -261,12 +247,10 @@ void CMonitor::onDisconnect(bool destroy) {
g_pConfigManager->m_bWantsMonitorReload = true; g_pConfigManager->m_bWantsMonitorReload = true;
} }
hyprListener_monitorFrame.removeCallback(); listeners.frame.reset();
hyprListener_monitorPresented.removeCallback(); listeners.presented.reset();
hyprListener_monitorDamage.removeCallback(); listeners.needsFrame.reset();
hyprListener_monitorNeedsFrame.removeCallback(); listeners.commit.reset();
hyprListener_monitorCommit.removeCallback();
hyprListener_monitorBind.removeCallback();
for (size_t i = 0; i < 4; ++i) { for (size_t i = 0; i < 4; ++i) {
for (auto& ls : m_aLayerSurfaceLayers[i]) { for (auto& ls : m_aLayerSurfaceLayers[i]) {
@ -316,10 +300,10 @@ void CMonitor::onDisconnect(bool destroy) {
activeWorkspace->m_bVisible = false; activeWorkspace->m_bVisible = false;
activeWorkspace.reset(); activeWorkspace.reset();
wlr_output_state_set_enabled(state.wlr(), false); output->state->setEnabled(false);
if (!state.commit()) if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect"); Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor.get() == this) if (g_pCompositor->m_pLastMonitor.get() == this)
g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput); g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput);
@ -344,9 +328,9 @@ void CMonitor::addDamage(const pixman_region32_t* rg) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor"); static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
damage.damageEntire(); damage.damageEntire();
g_pCompositor->scheduleFrameForMonitor(this); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} else if (damage.damage(rg)) } else if (damage.damage(rg))
g_pCompositor->scheduleFrameForMonitor(this); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} }
void CMonitor::addDamage(const CRegion* rg) { void CMonitor::addDamage(const CRegion* rg) {
@ -357,11 +341,11 @@ void CMonitor::addDamage(const CBox* box) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor"); static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
damage.damageEntire(); damage.damageEntire();
g_pCompositor->scheduleFrameForMonitor(this); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} }
if (damage.damage(*box)) if (damage.damage(*box))
g_pCompositor->scheduleFrameForMonitor(this); g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} }
bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
@ -369,8 +353,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate"); static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate");
// skip scheduling extra frames for fullsreen apps with vrr // skip scheduling extra frames for fullsreen apps with vrr
bool shouldSkip = *PNOBREAK && output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && bool shouldSkip =
activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL; *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
// keep requested minimum refresh rate // keep requested minimum refresh rate
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
@ -563,7 +547,7 @@ float CMonitor::getDefaultScale() {
static constexpr double MMPERINCH = 25.4; static constexpr double MMPERINCH = 25.4;
const auto DIAGONALPX = sqrt(pow(vecPixelSize.x, 2) + pow(vecPixelSize.y, 2)); const auto DIAGONALPX = sqrt(pow(vecPixelSize.x, 2) + pow(vecPixelSize.y, 2));
const auto DIAGONALIN = sqrt(pow(output->phys_width / MMPERINCH, 2) + pow(output->phys_height / MMPERINCH, 2)); const auto DIAGONALIN = sqrt(pow(output->physicalSize.x / MMPERINCH, 2) + pow(output->physicalSize.y / MMPERINCH, 2));
const auto PPI = DIAGONALPX / DIAGONALIN; const auto PPI = DIAGONALPX / DIAGONALIN;
@ -767,11 +751,11 @@ Vector2D CMonitor::middle() {
} }
void CMonitor::updateMatrix() { void CMonitor::updateMatrix() {
wlr_matrix_identity(projMatrix.data()); matrixIdentity(projMatrix.data());
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
wlr_matrix_translate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0); matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
wlr_matrix_transform(projMatrix.data(), transform); matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform));
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0); matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
} }
} }
@ -787,31 +771,124 @@ CBox CMonitor::logicalBox() {
return {vecPosition, vecSize}; return {vecPosition, vecSize};
} }
static void onDoneSource(void* data) {
auto pMonitor = (CMonitor*)data;
if (!PROTO::outputs.contains(pMonitor->szName))
return;
PROTO::outputs.at(pMonitor->szName)->sendDone();
}
void CMonitor::scheduleDone() {
if (doneSource)
return;
doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this);
}
bool CMonitor::attemptDirectScanout() {
if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked)
return false; // do not DS if this monitor is being mirrored. Will break the functionality.
if (g_pPointerManager->softwareLockedFor(self.lock()))
return false;
const auto PCANDIDATE = solitaryClient.lock();
if (!PCANDIDATE)
return false;
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != vecPixelSize || PSURFACE->current.transform != transform)
return false;
// we can't scanout shm buffers.
if (!PSURFACE->current.buffer->dmabuf().success)
return false;
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats
// and comes from the appropriate device. This may implode on multi-gpu!!
output->state->setBuffer(PSURFACE->current.buffer);
output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
if (!state.test())
return false;
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
Debug::log(TRACE, "presentFeedback for DS");
PSURFACE->presentFeedback(&now, this, true);
if (state.commit()) {
if (lastScanout.expired()) {
lastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
}
} else {
lastScanout.reset();
return false;
}
return true;
}
CMonitorState::CMonitorState(CMonitor* owner) { CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner; m_pOwner = owner;
wlr_output_state_init(&m_state);
} }
CMonitorState::~CMonitorState() { CMonitorState::~CMonitorState() {
wlr_output_state_finish(&m_state); ;
} }
wlr_output_state* CMonitorState::wlr() { void CMonitorState::ensureBufferPresent() {
return &m_state; if (!m_pOwner->output->state->state().enabled) {
} Debug::log(TRACE, "CMonitorState::ensureBufferPresent: Ignoring, monitor is not enabled");
return;
}
void CMonitorState::clear() { if (m_pOwner->output->state->state().buffer)
wlr_output_state_finish(&m_state); return;
m_state = {0};
wlr_output_state_init(&m_state); // this is required for modesetting being possible and might be missing in case of first tests in the renderer
// where we test modes and buffers
Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer, attaching one from the swapchain for modeset being possible");
m_pOwner->output->state->setBuffer(m_pOwner->output->swapchain->next(nullptr));
m_pOwner->output->swapchain->rollback(); // restore the counter, don't advance the swapchain
} }
bool CMonitorState::commit() { bool CMonitorState::commit() {
bool ret = wlr_output_commit_state(m_pOwner->output, &m_state); if (!updateSwapchain())
clear(); return false;
ensureBufferPresent();
bool ret = m_pOwner->output->commit();
return ret; return ret;
} }
bool CMonitorState::test() { bool CMonitorState::test() {
return wlr_output_test_state(m_pOwner->output, &m_state); if (!updateSwapchain())
return false;
ensureBufferPresent();
return m_pOwner->output->test();
}
bool CMonitorState::updateSwapchain() {
auto options = m_pOwner->output->swapchain->currentOptions();
const auto& STATE = m_pOwner->output->state->state();
const auto& MODE = STATE.mode ? STATE.mode : STATE.customMode;
if (!MODE) {
Debug::log(WARN, "updateSwapchain: No mode?");
return true;
}
options.format = STATE.drmFormat;
options.scanout = true;
options.length = 2;
options.size = MODE->pixelSize;
return m_pOwner->output->swapchain->reconfigure(options);
} }

View file

@ -12,6 +12,8 @@
#include <optional> #include <optional>
#include "signal/Signal.hpp" #include "signal/Signal.hpp"
#include "DamageRing.hpp" #include "DamageRing.hpp"
#include <aquamarine/output/Output.hpp>
#include <aquamarine/allocator/Swapchain.hpp>
// Enum for the different types of auto directions, e.g. auto-left, auto-up. // Enum for the different types of auto directions, e.g. auto-left, auto-up.
enum eAutoDirs { enum eAutoDirs {
@ -38,22 +40,21 @@ struct SMonitorRule {
}; };
class CMonitor; class CMonitor;
class CSyncTimeline;
// Class for wrapping the wlr state
class CMonitorState { class CMonitorState {
public: public:
CMonitorState(CMonitor* owner); CMonitorState(CMonitor* owner);
~CMonitorState(); ~CMonitorState();
wlr_output_state* wlr();
void clear();
// commit() will also clear()
bool commit(); bool commit();
bool test(); bool test();
bool updateSwapchain();
private: private:
wlr_output_state m_state = {0}; void ensureBufferPresent();
CMonitor* m_pOwner;
CMonitor* m_pOwner;
}; };
class CMonitor { class CMonitor {
@ -61,61 +62,69 @@ class CMonitor {
CMonitor(); CMonitor();
~CMonitor(); ~CMonitor();
Vector2D vecPosition = Vector2D(-1, -1); // means unset Vector2D vecPosition = Vector2D(-1, -1); // means unset
Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset
Vector2D vecSize = Vector2D(0, 0); Vector2D vecSize = Vector2D(0, 0);
Vector2D vecPixelSize = Vector2D(0, 0); Vector2D vecPixelSize = Vector2D(0, 0);
Vector2D vecTransformedSize = Vector2D(0, 0); Vector2D vecTransformedSize = Vector2D(0, 0);
bool primary = false; bool primary = false;
uint64_t ID = -1; uint64_t ID = -1;
PHLWORKSPACE activeWorkspace = nullptr; PHLWORKSPACE activeWorkspace = nullptr;
PHLWORKSPACE activeSpecialWorkspace = nullptr; PHLWORKSPACE activeSpecialWorkspace = nullptr;
float setScale = 1; // scale set by cfg float setScale = 1; // scale set by cfg
float scale = 1; // real scale float scale = 1; // real scale
std::string szName = ""; std::string szName = "";
std::string szDescription = ""; std::string szDescription = "";
std::string szShortDescription = ""; std::string szShortDescription = "";
Vector2D vecReservedTopLeft = Vector2D(0, 0); Vector2D vecReservedTopLeft = Vector2D(0, 0);
Vector2D vecReservedBottomRight = Vector2D(0, 0); Vector2D vecReservedBottomRight = Vector2D(0, 0);
drmModeModeInfo customDrmMode = {}; drmModeModeInfo customDrmMode = {};
CMonitorState state; CMonitorState state;
CDamageRing damage; CDamageRing damage;
wlr_output* output = nullptr; SP<Aquamarine::IOutput> output;
float refreshRate = 60; float refreshRate = 60;
int framesToSkip = 0; int framesToSkip = 0;
int forceFullFrames = 0; int forceFullFrames = 0;
bool noFrameSchedule = false; bool noFrameSchedule = false;
bool scheduledRecalc = false; bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float xwaylandScale = 1.f; float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0}; std::array<float, 9> projMatrix = {0};
std::optional<Vector2D> forceSize; std::optional<Vector2D> forceSize;
wlr_output_mode* currentMode = nullptr; SP<Aquamarine::SOutputMode> currentMode;
SP<Aquamarine::CSwapchain> cursorSwapchain;
bool dpmsStatus = true; bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed. bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false; bool createdByUser = false;
uint32_t drmFormat = DRM_FORMAT_INVALID; bool isUnsafeFallback = false;
bool isUnsafeFallback = false;
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false; bool renderingActive = false;
wl_event_source* renderTimer = nullptr; // for RAT wl_event_source* renderTimer = nullptr; // for RAT
bool RATScheduled = false; bool RATScheduled = false;
CTimer lastPresentationTimer; CTimer lastPresentationTimer;
SMonitorRule activeMonitorRule; bool isBeingLeased = false;
WP<CMonitor> self; SMonitorRule activeMonitorRule;
// explicit sync
SP<CSyncTimeline> inTimeline;
SP<CSyncTimeline> outTimeline;
uint64_t lastWaitPoint = 0;
uint64_t commitSeq = 0;
WP<CMonitor> self;
// mirroring // mirroring
CMonitor* pMirrorOf = nullptr; CMonitor* pMirrorOf = nullptr;
@ -124,6 +133,9 @@ class CMonitor {
// for tearing // for tearing
PHLWINDOWREF solitaryClient; PHLWINDOWREF solitaryClient;
// for direct scanout
PHLWINDOWREF lastScanout;
struct { struct {
bool canTear = false; bool canTear = false;
bool nextRenderTorn = false; bool nextRenderTorn = false;
@ -143,15 +155,6 @@ class CMonitor {
std::array<std::vector<PHLLSREF>, 4> m_aLayerSurfaceLayers; std::array<std::vector<PHLLSREF>, 4> m_aLayerSurfaceLayers;
DYNLISTENER(monitorFrame);
DYNLISTENER(monitorDestroy);
DYNLISTENER(monitorStateRequest);
DYNLISTENER(monitorDamage);
DYNLISTENER(monitorNeedsFrame);
DYNLISTENER(monitorCommit);
DYNLISTENER(monitorBind);
DYNLISTENER(monitorPresented);
// methods // methods
void onConnect(bool noRule); void onConnect(bool noRule);
void onDisconnect(bool destroy = false); void onDisconnect(bool destroy = false);
@ -173,6 +176,8 @@ class CMonitor {
int64_t activeWorkspaceID(); int64_t activeWorkspaceID();
int64_t activeSpecialWorkspaceID(); int64_t activeSpecialWorkspaceID();
CBox logicalBox(); CBox logicalBox();
void scheduleDone();
bool attemptDirectScanout();
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false; bool m_bRenderingInitPassed = false;
@ -184,6 +189,17 @@ class CMonitor {
} }
private: private:
void setupDefaultWS(const SMonitorRule&); void setupDefaultWS(const SMonitorRule&);
int findAvailableDefaultWS(); int findAvailableDefaultWS();
wl_event_source* doneSource = nullptr;
struct {
CHyprSignalListener frame;
CHyprSignalListener destroy;
CHyprSignalListener state;
CHyprSignalListener needsFrame;
CHyprSignalListener presented;
CHyprSignalListener commit;
} listeners;
}; };

View file

@ -15,6 +15,8 @@ class IPointer;
class IKeyboard; class IKeyboard;
class CWLSurfaceResource; class CWLSurfaceResource;
AQUAMARINE_FORWARD(ISwitch);
struct SRenderData { struct SRenderData {
CMonitor* pMonitor; CMonitor* pMonitor;
timespec* when; timespec* when;
@ -70,14 +72,14 @@ struct SSwipeGesture {
}; };
struct SSwitchDevice { struct SSwitchDevice {
wlr_input_device* pWlrDevice = nullptr; WP<Aquamarine::ISwitch> pDevice;
int status = -1; // uninitialized struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener fire;
DYNLISTENER(toggle); } listeners;
bool operator==(const SSwitchDevice& other) const { bool operator==(const SSwitchDevice& other) const {
return pWlrDevice == other.pWlrDevice; return pDevice == other.pDevice;
} }
}; };

View file

@ -1,7 +0,0 @@
#pragma once
inline bool wlr_backend_is_x11(void*) {
return false;
}
inline void wlr_x11_output_create(void*) {}

View file

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

View file

@ -7,5 +7,14 @@
using namespace Hyprutils::Math; using namespace Hyprutils::Math;
eTransform wlTransformToHyprutils(wl_output_transform t); eTransform wlTransformToHyprutils(wl_output_transform t);
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]); void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]);
void matrixProjection(float mat[9], int width, int height, eTransform transform);
void matrixTransform(float mat[9], eTransform transform);
void matrixRotate(float mat[9], float rad);
void matrixScale(float mat[9], float x, float y);
void matrixTranslate(float mat[9], float x, float y);
void matrixTranspose(float mat[9], const float a[9]);
void matrixMultiply(float mat[9], const float a[9], const float b[9]);
void matrixIdentity(float mat[9]);
wl_output_transform invertTransform(wl_output_transform tr);

View file

@ -0,0 +1,190 @@
#include "SyncTimeline.hpp"
#include "../../defines.hpp"
#include "../../managers/eventLoop/EventLoopManager.hpp"
#include <xf86drm.h>
#include <sys/eventfd.h>
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
timeline->drmFD = drmFD_;
timeline->self = timeline;
if (drmSyncobjCreate(drmFD_, 0, &timeline->handle)) {
Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj??");
return nullptr;
}
return timeline;
}
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, int drmSyncobjFD) {
auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
timeline->drmFD = drmFD_;
timeline->self = timeline;
if (drmSyncobjFDToHandle(drmFD_, drmSyncobjFD, &timeline->handle)) {
Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj from fd??");
return nullptr;
}
return timeline;
}
CSyncTimeline::~CSyncTimeline() {
if (handle == 0)
return;
drmSyncobjDestroy(drmFD, handle);
}
std::optional<bool> CSyncTimeline::check(uint64_t point, uint32_t flags) {
#ifdef __FreeBSD__
constexpr int ETIME_ERR = ETIMEDOUT;
#else
constexpr int ETIME_ERR = ETIME;
#endif
uint32_t signaled = 0;
int ret = drmSyncobjTimelineWait(drmFD, &handle, &point, 1, 0, flags, &signaled);
if (ret != 0 && ret != -ETIME_ERR) {
Debug::log(ERR, "CSyncTimeline::check: drmSyncobjTimelineWait failed");
return std::nullopt;
}
return ret == 0;
}
static int handleWaiterFD(int fd, uint32_t mask, void* data) {
auto waiter = (CSyncTimeline::SWaiter*)data;
if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
Debug::log(ERR, "handleWaiterFD: eventfd error");
return 0;
}
if (mask & WL_EVENT_READABLE) {
uint64_t value = 0;
if (read(fd, &value, sizeof(value)) <= 0)
Debug::log(ERR, "handleWaiterFD: failed to read from eventfd");
}
wl_event_source_remove(waiter->source);
waiter->source = nullptr;
if (waiter->fn)
waiter->fn();
if (waiter->timeline)
waiter->timeline->removeWaiter(waiter);
return 0;
}
bool CSyncTimeline::addWaiter(const std::function<void()>& waiter, uint64_t point, uint32_t flags) {
auto w = makeShared<SWaiter>();
w->fn = waiter;
w->timeline = self;
int eventFD = eventfd(0, EFD_CLOEXEC);
if (eventFD < 0) {
Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd");
return false;
}
drm_syncobj_eventfd syncobjEventFD = {
.handle = handle,
.flags = flags,
.point = point,
.fd = eventFD,
};
if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) {
Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed");
close(eventFD);
return false;
}
w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get());
if (!w->source) {
Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed");
close(eventFD);
return false;
}
waiters.emplace_back(w);
return true;
}
void CSyncTimeline::removeWaiter(SWaiter* w) {
if (w->source) {
wl_event_source_remove(w->source);
w->source = nullptr;
}
std::erase_if(waiters, [w](const auto& e) { return e.get() == w; });
}
int CSyncTimeline::exportAsSyncFileFD(uint64_t src) {
int sync = -1;
uint32_t syncHandle = 0;
if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed");
return -1;
}
if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) {
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed");
drmSyncobjDestroy(drmFD, syncHandle);
return -1;
}
if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) {
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed");
drmSyncobjDestroy(drmFD, syncHandle);
return -1;
}
drmSyncobjDestroy(drmFD, syncHandle);
return sync;
}
bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) {
uint32_t syncHandle = 0;
if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
Debug::log(ERR, "importFromSyncFileFD: drmSyncobjCreate failed");
return false;
}
if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) {
Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed");
drmSyncobjDestroy(drmFD, syncHandle);
return false;
}
if (drmSyncobjTransfer(drmFD, handle, dst, syncHandle, 0, 0)) {
Debug::log(ERR, "importFromSyncFileFD: drmSyncobjTransfer failed");
drmSyncobjDestroy(drmFD, syncHandle);
return false;
}
drmSyncobjDestroy(drmFD, syncHandle);
return true;
}
bool CSyncTimeline::transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint) {
if (drmFD != from->drmFD) {
Debug::log(ERR, "CSyncTimeline::transfer: cannot transfer timelines between gpus, {} -> {}", from->drmFD, drmFD);
return false;
}
if (drmSyncobjTransfer(drmFD, handle, toPoint, from->handle, fromPoint, 0)) {
Debug::log(ERR, "CSyncTimeline::transfer: drmSyncobjTransfer failed");
return false;
}
return true;
}

View file

@ -0,0 +1,47 @@
#pragma once
#include <cstdint>
#include <optional>
#include <vector>
#include <functional>
#include "../memory/Memory.hpp"
/*
Hyprland synchronization timelines are based on the wlroots' ones, which
are based on Vk timeline semaphores: https://www.khronos.org/blog/vulkan-timeline-semaphores
*/
struct wl_event_source;
class CSyncTimeline {
public:
static SP<CSyncTimeline> create(int drmFD_);
static SP<CSyncTimeline> create(int drmFD_, int drmSyncobjFD);
~CSyncTimeline();
struct SWaiter {
std::function<void()> fn;
wl_event_source* source = nullptr;
WP<CSyncTimeline> timeline;
};
// check if the timeline point has been signaled
// flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE
// std::nullopt on fail
std::optional<bool> check(uint64_t point, uint32_t flags);
bool addWaiter(const std::function<void()>& waiter, uint64_t point, uint32_t flags);
void removeWaiter(SWaiter*);
int exportAsSyncFileFD(uint64_t src);
bool importFromSyncFileFD(uint64_t dst, int fd);
bool transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint);
int drmFD = -1;
uint32_t handle = 0;
WP<CSyncTimeline> self;
private:
CSyncTimeline() = default;
std::vector<SP<SWaiter>> waiters;
};

View file

@ -16,78 +16,6 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <mutex>
#include <thread>
#include <filesystem>
#include <climits>
#if true
// wlroots uses dumb-ass shit that makes it not compile on C++, let's fix that.
// https://github.com/swaywm/wlroots/issues/682
// pthread first because it uses class in a C++ way and XWayland includes that...
#include <pthread.h>
#define class _class
#define namespace _namespace
#define static
#define delete delete_
extern "C" {
#include <wlr/backend.h>
#include <wlr/backend/libinput.h>
#include <wlr/backend/drm.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_drm.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include <wlr/util/edges.h>
#include <wlr/types/wlr_tablet_pad.h>
#include <wlr/types/wlr_tablet_tool.h>
#include <xkbcommon/xkbcommon.h>
#include <wlr/render/egl.h>
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_texture.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/interfaces/wlr_pointer.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_switch.h>
#include <wlr/config.h>
#include <wlr/backend/headless.h>
#include <wlr/backend/multi.h>
#include <wlr/backend/wayland.h>
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/util/box.h>
#include <wlr/util/transform.h>
#include <wlr/render/swapchain.h>
#include <wlr/render/egl.h>
#include <libdrm/drm_fourcc.h>
#if WLR_HAS_X11_BACKEND
#include <wlr/backend/x11.h>
#endif
}
#undef delete
#undef class
#undef namespace
#undef static
#endif
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
@ -99,10 +27,6 @@ extern "C" {
#include <GLES3/gl3ext.h> #include <GLES3/gl3ext.h>
#endif #endif
#if !WLR_HAS_X11_BACKEND
#include "helpers/X11Stubs.hpp"
#endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
#define XWAYLAND false #define XWAYLAND false
#else #else

View file

@ -139,7 +139,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return; return;
PWINDOW->updateSpecialRenderData(); PWINDOW->unsetWindowData(PRIORITY_LAYOUT);
PWINDOW->updateWindowData();
static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("dwindle:no_gaps_when_only"); static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("dwindle:no_gaps_when_only");
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in"); static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
@ -160,10 +161,10 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() &&
(NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { (NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2); PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true); PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT);
PWINDOW->m_sSpecialRenderData.rounding = false; PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sSpecialRenderData.shadow = false; PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
@ -496,7 +497,8 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
return; return;
} }
pWindow->updateSpecialRenderData(); pWindow->unsetWindowData(PRIORITY_LAYOUT);
pWindow->updateWindowData();
if (pWindow->m_bIsFullscreen) if (pWindow->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
@ -830,7 +832,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscre
pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition;
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
pWindow->updateSpecialRenderData(); pWindow->unsetWindowData(PRIORITY_LAYOUT);
pWindow->updateWindowData();
} }
} else { } else {
// if it now got fullscreen, make it fullscreen // if it now got fullscreen, make it fullscreen

View file

@ -386,8 +386,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
} else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) {
if (DRAGGINGWINDOW->m_bIsFloating) { if (DRAGGINGWINDOW->m_bIsFloating) {
Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sAdditionalConfigData.minSize.toUnderlying()); Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sWindowData.minSize.valueOr(Vector2D(20, 20)));
Vector2D MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, DRAGGINGWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying()); Vector2D MAXSIZE;
if (DRAGGINGWINDOW->m_sWindowData.maxSize.hasValue())
MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, DRAGGINGWINDOW->m_sWindowData.maxSize.value());
else
MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max()));
Vector2D newSize = m_vBeginDragSizeXY; Vector2D newSize = m_vBeginDragSizeXY;
Vector2D newPos = m_vBeginDragPositionXY; Vector2D newPos = m_vBeginDragPositionXY;
@ -403,7 +407,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if ((m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1) && if ((m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1) &&
(g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || (g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO ||
(!(g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) && DRAGGINGWINDOW->m_sAdditionalConfigData.keepAspectRatio))) { (!(g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) && DRAGGINGWINDOW->m_sWindowData.keepAspectRatio.valueOrDefault()))) {
const float RATIO = m_vBeginDragSizeXY.y / m_vBeginDragSizeXY.x; const float RATIO = m_vBeginDragSizeXY.y / m_vBeginDragSizeXY.x;
@ -538,7 +542,8 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
pWindow->updateSpecialRenderData(); pWindow->unsetWindowData(PRIORITY_LAYOUT);
pWindow->updateWindowData();
if (pWindow == m_pLastTiledWindow) if (pWindow == m_pLastTiledWindow)
m_pLastTiledWindow.reset(); m_pLastTiledWindow.reset();
@ -587,7 +592,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) {
// find whether there is a floating window below this one // find whether there is a floating window below this one
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w != pWindow) { !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) {
if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x,
w->m_vPosition.y + w->m_vSize.y)) { w->m_vPosition.y + w->m_vSize.y)) {
return w; return w;
@ -607,7 +612,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) {
// if not, floating window // if not, floating window
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w != pWindow) !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow)
return w; return w;
} }

View file

@ -264,7 +264,8 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
const auto MASTERSLEFT = getMastersOnWorkspace(WORKSPACEID); const auto MASTERSLEFT = getMastersOnWorkspace(WORKSPACEID);
static auto SMALLSPLIT = CConfigValue<Hyprlang::INT>("master:allow_small_split"); static auto SMALLSPLIT = CConfigValue<Hyprlang::INT>("master:allow_small_split");
pWindow->updateSpecialRenderData(); pWindow->unsetWindowData(PRIORITY_LAYOUT);
pWindow->updateWindowData();
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
@ -646,7 +647,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return; return;
PWINDOW->updateSpecialRenderData(); PWINDOW->unsetWindowData(PRIORITY_LAYOUT);
PWINDOW->updateWindowData();
static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("master:no_gaps_when_only"); static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("master:no_gaps_when_only");
static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes"); static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
@ -669,10 +671,10 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() &&
(getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2); PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true); PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT);
PWINDOW->m_sSpecialRenderData.rounding = false; PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sSpecialRenderData.shadow = false; PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
@ -922,7 +924,8 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscree
pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition;
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
pWindow->updateSpecialRenderData(); pWindow->unsetWindowData(PRIORITY_LAYOUT);
pWindow->updateWindowData();
} }
} else { } else {
// if it now got fullscreen, make it fullscreen // if it now got fullscreen, make it fullscreen

View file

@ -40,8 +40,7 @@
#define STICKS(a, b) abs((a) - (b)) < 2 #define STICKS(a, b) abs((a) - (b)) < 2
#define HYPRATOM(name) \ #define HYPRATOM(name) {name, 0}
{ name, 0 }
#define RASSERT(expr, reason, ...) \ #define RASSERT(expr, reason, ...) \
if (!(expr)) { \ if (!(expr)) { \
@ -106,3 +105,8 @@
class name; \ class name; \
} \ } \
} }
#define AQUAMARINE_FORWARD(name) \
namespace Aquamarine { \
class name; \
}

View file

@ -4,6 +4,7 @@
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "init/initHelpers.hpp" #include "init/initHelpers.hpp"
#include <fcntl.h>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
#include <vector> #include <vector>
@ -16,6 +17,8 @@ void help() {
std::cout << "\nArguments:\n"; std::cout << "\nArguments:\n";
std::cout << " --help -h - Show this message again\n"; std::cout << " --help -h - Show this message again\n";
std::cout << " --config FILE -c FILE - Specify config file to use\n"; std::cout << " --config FILE -c FILE - Specify config file to use\n";
std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n";
std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n";
std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n";
} }
@ -37,6 +40,8 @@ int main(int argc, char** argv) {
// parse some args // parse some args
std::string configPath; std::string configPath;
std::string socketName;
int socketFd = -1;
bool ignoreSudo = false; bool ignoreSudo = false;
std::vector<std::string> args{argv + 1, argv + argc}; std::vector<std::string> args{argv + 1, argv + argc};
@ -46,6 +51,36 @@ int main(int argc, char** argv) {
std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n"; std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n";
ignoreSudo = true; ignoreSudo = true;
} else if (it->compare("--socket") == 0) {
if (std::next(it) == args.end()) {
help();
return 1;
}
socketName = *std::next(it);
it++;
} else if (it->compare("--wayland-fd") == 0) {
if (std::next(it) == args.end()) {
help();
return 1;
}
try {
socketFd = std::stoi(std::next(it)->c_str());
// check if socketFd is a valid file descriptor
if (fcntl(socketFd, F_GETFD) == -1)
throw std::exception();
} catch (...) {
std::cerr << "[ ERROR ] Invalid Wayland FD!\n";
help();
return 1;
}
it++;
} else if (it->compare("-c") == 0 || it->compare("--config") == 0) { } else if (it->compare("-c") == 0 || it->compare("--config") == 0) {
if (std::next(it) == args.end()) { if (std::next(it) == args.end()) {
help(); help();
@ -93,6 +128,13 @@ int main(int argc, char** argv) {
std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n"; std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n";
} }
if (socketName.empty() ^ (socketFd == -1)) {
std::cerr << "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n";
std::cerr << " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover.\n";
return 1;
}
std::cout << "Welcome to Hyprland!\n"; std::cout << "Welcome to Hyprland!\n";
// let's init the compositor. // let's init the compositor.
@ -105,7 +147,7 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
g_pCompositor->initServer(); g_pCompositor->initServer(socketName, socketFd);
if (!envEnabled("HYPRLAND_NO_RT")) if (!envEnabled("HYPRLAND_NO_RT"))
Init::gainRealTime(); Init::gainRealTime();
@ -115,11 +157,9 @@ int main(int argc, char** argv) {
// If all's good to go, start. // If all's good to go, start.
g_pCompositor->startCompositor(); g_pCompositor->startCompositor();
g_pCompositor->m_bIsShuttingDown = true; g_pCompositor->cleanup();
// If we are here it means we got yote. Debug::log(LOG, "Hyprland has reached the end.");
Debug::log(LOG, "Hyprland reached the end.");
g_pCompositor.reset();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View file

@ -102,7 +102,7 @@ void CAnimationManager::tick() {
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (!PMONITOR) if (!PMONITOR)
continue; continue;
animationsDisabled = animationsDisabled || PWINDOW->m_sAdditionalConfigData.forceNoAnims; animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled);
} else if (PWORKSPACE) { } else if (PWORKSPACE) {
PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
if (!PMONITOR) if (!PMONITOR)
@ -259,7 +259,7 @@ void CAnimationManager::tick() {
// manually schedule a frame // manually schedule a frame
if (PMONITOR) if (PMONITOR)
g_pCompositor->scheduleFrameForMonitor(PMONITOR); g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
} }
// do it here, because if this alters the animation vars deque we would be in trouble above. // do it here, because if this alters the animation vars deque we would be in trouble above.
@ -407,18 +407,19 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) {
if (!pWindow->m_vRealPosition.m_pConfig->pValues->internalEnabled) if (!pWindow->m_vRealPosition.m_pConfig->pValues->internalEnabled)
return; return;
if (pWindow->m_sAdditionalConfigData.animationStyle != "") { if (pWindow->m_sWindowData.animationStyle.hasValue()) {
const auto STYLE = pWindow->m_sWindowData.animationStyle.value();
// the window has config'd special anim // the window has config'd special anim
if (pWindow->m_sAdditionalConfigData.animationStyle.starts_with("slide")) { if (STYLE.starts_with("slide")) {
CVarList animList2(pWindow->m_sAdditionalConfigData.animationStyle, 0, 's'); CVarList animList2(STYLE, 0, 's');
animationSlide(pWindow, animList2[1], close); animationSlide(pWindow, animList2[1], close);
} else { } else {
// anim popin, fallback // anim popin, fallback
float minPerc = 0.f; float minPerc = 0.f;
if (pWindow->m_sAdditionalConfigData.animationStyle.find("%") != std::string::npos) { if (STYLE.find("%") != std::string::npos) {
try { try {
auto percstr = pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find_last_of(' ')); auto percstr = STYLE.substr(STYLE.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) { } catch (std::exception& e) {
; // oops ; // oops

View file

@ -3,10 +3,11 @@
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "PointerManager.hpp" #include "PointerManager.hpp"
#include "../xwayland/XWayland.hpp" #include "../xwayland/XWayland.hpp"
#include <cstring>
#include "../helpers/CursorShapes.hpp"
extern "C" { extern "C" {
#include <wlr/interfaces/wlr_buffer.h> #include <X11/Xcursor/Xcursor.h>
#include <wlr/types/wlr_xcursor_manager.h>
} }
static int cursorAnimTimer(void* data) { static int cursorAnimTimer(void* data) {
@ -45,8 +46,7 @@ CCursorManager::CCursorManager() {
if (m_iSize == 0) if (m_iSize == 0)
m_iSize = 24; m_iSize = 24;
m_pWLRXCursorMgr = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"), m_iSize); xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "", m_iSize * std::ceil(m_fCursorScale));
wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0);
m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr); m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr);
@ -56,9 +56,6 @@ CCursorManager::CCursorManager() {
} }
CCursorManager::~CCursorManager() { CCursorManager::~CCursorManager() {
if (m_pWLRXCursorMgr)
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
if (m_pAnimationTimer) if (m_pAnimationTimer)
wl_event_source_remove(m_pAnimationTimer); wl_event_source_remove(m_pAnimationTimer);
} }
@ -67,54 +64,61 @@ void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) {
std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; }); std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; });
} }
static void cursorBufferDestroy(struct wlr_buffer* wlr_buffer) { CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base); surface = surf;
g_pCursorManager->dropBufferRef(buffer->parent); size = size_;
stride = cairo_image_surface_get_stride(surf);
} }
static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t flags, void** data, uint32_t* format, size_t* stride) { CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base); pixelData = pixelData_;
size = size_;
if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) stride = 4 * size_.x;
return false;
*data = buffer->pixelData ? buffer->pixelData : cairo_image_surface_get_data(buffer->surface);
*stride = buffer->stride;
*format = DRM_FORMAT_ARGB8888;
return true;
}
static void cursorBufferEndDataPtr(struct wlr_buffer* wlr_buffer) {
;
}
//
static const wlr_buffer_impl bufferImpl = {
.destroy = cursorBufferDestroy,
.begin_data_ptr_access = cursorBufferBeginDataPtr,
.end_data_ptr_access = cursorBufferEndDataPtr,
};
CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) {
wlrBuffer.surface = surf;
wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y);
wlrBuffer.parent = this;
wlrBuffer.stride = cairo_image_surface_get_stride(surf);
}
CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) {
wlrBuffer.pixelData = pixelData;
wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y);
wlrBuffer.parent = this;
wlrBuffer.stride = 4 * size_.x;
} }
CCursorManager::CCursorBuffer::~CCursorBuffer() { CCursorManager::CCursorBuffer::~CCursorBuffer() {
; // will be freed in .destroy ;
} }
wlr_buffer* CCursorManager::getCursorBuffer() { Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() {
return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr; return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
}
Aquamarine::eBufferType CCursorManager::CCursorBuffer::type() {
return Aquamarine::eBufferType::BUFFER_TYPE_SHM;
}
void CCursorManager::CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) {
;
}
bool CCursorManager::CCursorBuffer::isSynchronous() {
return true;
}
bool CCursorManager::CCursorBuffer::good() {
return true;
}
Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() {
Aquamarine::SSHMAttrs attrs;
attrs.success = true;
attrs.format = DRM_FORMAT_ARGB8888;
attrs.size = size;
attrs.stride = stride;
return attrs;
}
std::tuple<uint8_t*, uint32_t, size_t> CCursorManager::CCursorBuffer::beginDataPtr(uint32_t flags) {
return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride};
}
void CCursorManager::CCursorBuffer::endDataPtr() {
;
}
SP<Aquamarine::IBuffer> CCursorManager::getCursorBuffer() {
return !m_vCursorBuffers.empty() ? m_vCursorBuffers.back() : nullptr;
} }
void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot) { void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot) {
@ -127,34 +131,24 @@ void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotsp
} }
void CCursorManager::setXCursor(const std::string& name) { void CCursorManager::setXCursor(const std::string& name) {
if (!m_pWLRXCursorMgr) {
g_pPointerManager->resetCursorImage();
return;
}
float scale = std::ceil(m_fCursorScale); float scale = std::ceil(m_fCursorScale);
wlr_xcursor_manager_load(m_pWLRXCursorMgr, scale);
auto xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, name.c_str(), scale); if (!xcursor.themeLoaded) {
if (!xcursor) { Debug::log(ERR, "XCursor failed to find theme in setXCursor");
Debug::log(ERR, "XCursor has no shape {}, retrying with left-ptr", name);
xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left-ptr", scale);
}
if (!xcursor || !xcursor->images[0]) {
Debug::log(ERR, "XCursor is broken. F this garbage.");
g_pPointerManager->resetCursorImage(); g_pPointerManager->resetCursorImage();
return; return;
} }
auto image = xcursor->images[0]; auto& icon = xcursor.defaultCursor;
// try to get an icon we know if we have one
if (xcursor.cursors.contains(name))
icon = xcursor.cursors.at(name);
m_vCursorBuffers.emplace_back( m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot));
std::make_unique<CCursorBuffer>(image->buffer, Vector2D{(int)image->width, (int)image->height}, Vector2D{(double)image->hotspot_x, (double)image->hotspot_y}));
g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{(double)image->hotspot_x, (double)image->hotspot_y} / scale, scale); g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon->hotspot / scale, scale);
if (m_vCursorBuffers.size() > 1) if (m_vCursorBuffers.size() > 1)
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); dropBufferRef(m_vCursorBuffers.at(0).get());
m_bOurBufferConnected = true; m_bOurBufferConnected = true;
} }
@ -196,14 +190,14 @@ void CCursorManager::setCursorFromName(const std::string& name) {
} }
} }
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface, m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface,
Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale, g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale,
m_fCursorScale); m_fCursorScale);
if (m_vCursorBuffers.size() > 1) if (m_vCursorBuffers.size() > 1)
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); dropBufferRef(m_vCursorBuffers.at(0).get());
m_bOurBufferConnected = true; m_bOurBufferConnected = true;
@ -225,7 +219,7 @@ void CCursorManager::tickAnimatedCursor() {
if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size()) if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size())
m_iCurrentAnimationFrame = 0; m_iCurrentAnimationFrame = 0;
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>( m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>(
m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface,
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size}, Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size},
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY})); Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}));
@ -256,10 +250,9 @@ void CCursorManager::setXWaylandCursor() {
if (CURSOR.surface) { if (CURSOR.surface) {
g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, 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}); {CURSOR.hotspotX, CURSOR.hotspotY});
} else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) { } else if (xcursor.themeLoaded)
g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {(int)XCURSOR->images[0]->width, (int)XCURSOR->images[0]->height}, g_pXWayland->setCursor((uint8_t*)xcursor.defaultCursor->pixels.data(), xcursor.defaultCursor->size.x * 4, xcursor.defaultCursor->size, xcursor.defaultCursor->hotspot);
{(double)XCURSOR->images[0]->hotspot_x, (double)XCURSOR->images[0]->hotspot_y}); else
} else
Debug::log(ERR, "CursorManager: no valid cursor for xwayland"); Debug::log(ERR, "CursorManager: no valid cursor for xwayland");
} }
@ -284,7 +277,7 @@ void CCursorManager::updateTheme() {
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
m->forceFullFrames = 5; m->forceFullFrames = 5;
g_pCompositor->scheduleFrameForMonitor(m.get()); g_pCompositor->scheduleFrameForMonitor(m.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
} }
} }
@ -303,37 +296,163 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) {
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name); Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name);
if (m_pWLRXCursorMgr) xcursor.loadTheme(name, size);
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
m_pWLRXCursorMgr = wlr_xcursor_manager_create(name.empty() ? "" : name.c_str(), size); m_szTheme = name;
bool xSuccess = wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0) == 1; m_iSize = size;
updateTheme();
return true;
}
// this basically checks if xcursor changed used theme to default but better // Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c
bool diffTheme = false; // however modified to fit wayland cursor shape names better.
wlr_xcursor_manager_theme* theme; // _ -> -
wl_list_for_each(theme, &m_pWLRXCursorMgr->scaled_themes, link) { // clang-format off
if (std::string{theme->theme->name} != name) { static std::array<const char*, 77> XCURSOR_STANDARD_NAMES = {
diffTheme = true; "X_cursor",
break; "default", // arrow
"ns-resize", // based-arrow-down
"ns-resize", // based-arrow-up
"boat",
"bogosity",
"sw-resize", // bottom-left-corner
"se-resize", // bottom-right-corner
"s-resize", // bottom-side
"bottom-tee",
"box-spiral",
"center-ptr",
"circle",
"clock",
"coffee-mug",
"cross",
"cross-reverse",
"crosshair",
"diamond-cross",
"dot",
"dotbox",
"double-arrow",
"draft-large",
"draft-small",
"draped-box",
"exchange",
"move", // fleur
"gobbler",
"gumby",
"pointer", // hand1
"grabbing", // hand2
"heart",
"icon",
"iron-cross",
"default", // left-ptr
"w-resize", // left-side
"left-tee",
"leftbutton",
"ll-angle",
"lr-angle",
"man",
"middlebutton",
"mouse",
"pencil",
"pirate",
"plus",
"help", // question-arrow
"right-ptr",
"e-resize", // right-side
"right-tee",
"rightbutton",
"rtl-logo",
"sailboat",
"ns-resize", // sb-down-arrow
"ew-resize", // sb-h-double-arrow
"ew-resize", // sb-left-arrow
"ew-resize", // sb-right-arrow
"n-resize", // sb-up-arrow
"s-resize", // sb-v-double-arrow
"shuttle",
"sizing",
"spider",
"spraycan",
"star",
"target",
"cell", // tcross
"nw-resize", // top-left-arrow
"nw-resize", // top-left-corner
"ne-resize", // top-right-corner
"n-resize", // top-side
"top-tee",
"trek",
"ul-angle",
"umbrella",
"ur-angle",
"wait", // watch
"text", // xterm
};
// clang-format on
void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int size) {
if (lastLoadSize == size && themeName == name)
return;
lastLoadSize = size;
themeLoaded = false;
themeName = name.empty() ? "default" : name;
auto img = XcursorShapeLoadImage(2, themeName.c_str(), size);
if (!img) {
Debug::log(ERR, "XCursor failed finding theme \"{}\". Trying size 24.", themeName);
size = 24;
img = XcursorShapeLoadImage(2, themeName.c_str(), size);
if (!img) {
Debug::log(ERR, "XCursor failed finding theme \"{}\".", themeName);
return;
} }
} }
if (xSuccess && !diffTheme) { defaultCursor = makeShared<SXCursor>();
m_szTheme = name; defaultCursor->size = {(int)img->width, (int)img->height};
m_iSize = size; defaultCursor->hotspot = {(int)img->xhot, (int)img->yhot};
updateTheme();
return true; defaultCursor->pixels.resize(img->width * img->height);
std::memcpy(defaultCursor->pixels.data(), img->pixels, img->width * img->height * sizeof(uint32_t));
themeLoaded = true;
XcursorImageDestroy(img);
// gather as many shapes as we can find.
cursors.clear();
for (auto& shape : CURSOR_SHAPE_NAMES) {
int id = -1;
for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) {
if (XCURSOR_STANDARD_NAMES.at(i) == std::string{shape}) {
id = i;
break;
}
}
if (id < 0) {
Debug::log(LOG, "XCursor has no shape {}, skipping", shape);
continue;
}
auto xImage = XcursorShapeLoadImage(id << 1 /* wtf xcursor? */, themeName.c_str(), size);
if (!xImage) {
Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape);
continue;
}
auto xcursor = makeShared<SXCursor>();
xcursor->size = {(int)xImage->width, (int)xImage->height};
xcursor->hotspot = {(int)xImage->xhot, (int)xImage->yhot};
xcursor->pixels.resize(xImage->width * xImage->height);
std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t));
cursors.emplace(std::string{shape}, xcursor);
XcursorImageDestroy(xImage);
} }
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

@ -6,47 +6,51 @@
#include "../includes.hpp" #include "../includes.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/memory/Memory.hpp" #include "../helpers/memory/Memory.hpp"
#include "../macros.hpp"
#include <aquamarine/buffer/Buffer.hpp>
struct wlr_buffer;
struct wlr_xcursor_manager;
class CWLSurface; class CWLSurface;
AQUAMARINE_FORWARD(IBuffer);
class CCursorManager { class CCursorManager {
public: public:
CCursorManager(); CCursorManager();
~CCursorManager(); ~CCursorManager();
wlr_buffer* getCursorBuffer(); SP<Aquamarine::IBuffer> getCursorBuffer();
void setCursorFromName(const std::string& name); void setCursorFromName(const std::string& name);
void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot); void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot);
void setXCursor(const std::string& name); void setXCursor(const std::string& name);
bool changeTheme(const std::string& name, const int size); bool changeTheme(const std::string& name, const int size);
void updateTheme(); void updateTheme();
SCursorImageData dataFor(const std::string& name); // for xwayland SCursorImageData dataFor(const std::string& name); // for xwayland
void setXWaylandCursor(); void setXWaylandCursor();
void tickAnimatedCursor(); void tickAnimatedCursor();
class CCursorBuffer { class CCursorBuffer : public Aquamarine::IBuffer {
public: public:
CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot); CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot);
CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot); CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot);
~CCursorBuffer(); ~CCursorBuffer();
struct SCursorWlrBuffer { virtual Aquamarine::eBufferCapability caps();
wlr_buffer base; virtual Aquamarine::eBufferType type();
cairo_surface_t* surface = nullptr; virtual void update(const Hyprutils::Math::CRegion& damage);
bool dropped = false; virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu
CCursorBuffer* parent = nullptr; virtual bool good();
uint8_t* pixelData = nullptr; virtual Aquamarine::SSHMAttrs shm();
size_t stride = 0; virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
} wlrBuffer; virtual void endDataPtr();
private: private:
Vector2D size; Vector2D hotspot;
Vector2D hotspot; cairo_surface_t* surface = nullptr;
uint8_t* pixelData = nullptr;
size_t stride = 0;
friend class CCursorManager; friend class CCursorManager;
}; };
@ -56,7 +60,7 @@ class CCursorManager {
bool m_bOurBufferConnected = false; bool m_bOurBufferConnected = false;
private: private:
std::vector<std::unique_ptr<CCursorBuffer>> m_vCursorBuffers; std::vector<SP<CCursorBuffer>> m_vCursorBuffers;
std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor; std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor;
@ -70,8 +74,24 @@ class CCursorManager {
int m_iCurrentAnimationFrame = 0; int m_iCurrentAnimationFrame = 0;
Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData; Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData;
// xcursor fallback // gangsta bootleg XCursor impl. Whenever Hyprland has to use
wlr_xcursor_manager* m_pWLRXCursorMgr = nullptr; // an xcursor, just use the pointer.
struct SXCursor {
Vector2D size;
Vector2D hotspot;
std::vector<uint32_t> pixels; // XPixel is a u32
};
struct SXCursorManager {
void loadTheme(const std::string& name, int size);
int lastLoadSize = 0;
bool themeLoaded = false;
std::string themeName = "";
SP<SXCursor> defaultCursor;
std::unordered_map<std::string, SP<SXCursor>> cursors;
} xcursor;
}; };
inline std::unique_ptr<CCursorManager> g_pCursorManager; inline std::unique_ptr<CCursorManager> g_pCursorManager;

View file

@ -4,10 +4,12 @@
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/ShortcutsInhibit.hpp" #include "../protocols/ShortcutsInhibit.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../devices/IKeyboard.hpp"
#include "KeybindManager.hpp" #include "KeybindManager.hpp"
#include "PointerManager.hpp" #include "PointerManager.hpp"
#include "Compositor.hpp" #include "Compositor.hpp"
#include "TokenManager.hpp" #include "TokenManager.hpp"
#include "eventLoop/EventLoopManager.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
#include "helpers/varlist/VarList.hpp" #include "helpers/varlist/VarList.hpp"
@ -15,6 +17,7 @@
#include <iterator> #include <iterator>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <cstring>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
@ -33,7 +36,7 @@ using namespace Hyprutils::String;
static std::vector<std::pair<std::string, std::string>> getHyprlandLaunchEnv() { static std::vector<std::pair<std::string, std::string>> getHyprlandLaunchEnv() {
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking"); static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
if (!*PINITIALWSTRACKING) if (!*PINITIALWSTRACKING || g_pConfigManager->isLaunchingExecOnce)
return {}; return {};
const auto PMONITOR = g_pCompositor->m_pLastMonitor; const auto PMONITOR = g_pCompositor->m_pLastMonitor;
@ -98,7 +101,6 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["pass"] = pass; m_mDispatchers["pass"] = pass;
m_mDispatchers["sendshortcut"] = sendshortcut; m_mDispatchers["sendshortcut"] = sendshortcut;
m_mDispatchers["layoutmsg"] = layoutmsg; m_mDispatchers["layoutmsg"] = layoutmsg;
m_mDispatchers["toggleopaque"] = toggleOpaque;
m_mDispatchers["dpms"] = dpms; m_mDispatchers["dpms"] = dpms;
m_mDispatchers["movewindowpixel"] = moveWindow; m_mDispatchers["movewindowpixel"] = moveWindow;
m_mDispatchers["resizewindowpixel"] = resizeWindow; m_mDispatchers["resizewindowpixel"] = resizeWindow;
@ -157,37 +159,37 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
uint32_t modMask = 0; uint32_t modMask = 0;
std::transform(mods.begin(), mods.end(), mods.begin(), ::toupper); std::transform(mods.begin(), mods.end(), mods.begin(), ::toupper);
if (mods.contains("SHIFT")) if (mods.contains("SHIFT"))
modMask |= WLR_MODIFIER_SHIFT; modMask |= HL_MODIFIER_SHIFT;
if (mods.contains("CAPS")) if (mods.contains("CAPS"))
modMask |= WLR_MODIFIER_CAPS; modMask |= HL_MODIFIER_CAPS;
if (mods.contains("CTRL") || mods.contains("CONTROL")) if (mods.contains("CTRL") || mods.contains("CONTROL"))
modMask |= WLR_MODIFIER_CTRL; modMask |= HL_MODIFIER_CTRL;
if (mods.contains("ALT") || mods.contains("MOD1")) if (mods.contains("ALT") || mods.contains("MOD1"))
modMask |= WLR_MODIFIER_ALT; modMask |= HL_MODIFIER_ALT;
if (mods.contains("MOD2")) if (mods.contains("MOD2"))
modMask |= WLR_MODIFIER_MOD2; modMask |= HL_MODIFIER_MOD2;
if (mods.contains("MOD3")) if (mods.contains("MOD3"))
modMask |= WLR_MODIFIER_MOD3; modMask |= HL_MODIFIER_MOD3;
if (mods.contains("SUPER") || mods.contains("WIN") || mods.contains("LOGO") || mods.contains("MOD4")) if (mods.contains("SUPER") || mods.contains("WIN") || mods.contains("LOGO") || mods.contains("MOD4") || mods.contains("META"))
modMask |= WLR_MODIFIER_LOGO; modMask |= HL_MODIFIER_META;
if (mods.contains("MOD5")) if (mods.contains("MOD5"))
modMask |= WLR_MODIFIER_MOD5; modMask |= HL_MODIFIER_MOD5;
return modMask; return modMask;
} }
uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) { uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) {
switch (keycode - 8) { switch (keycode - 8) {
case KEY_LEFTMETA: return WLR_MODIFIER_LOGO; case KEY_LEFTMETA: return HL_MODIFIER_META;
case KEY_RIGHTMETA: return WLR_MODIFIER_LOGO; case KEY_RIGHTMETA: return HL_MODIFIER_META;
case KEY_LEFTSHIFT: return WLR_MODIFIER_SHIFT; case KEY_LEFTSHIFT: return HL_MODIFIER_SHIFT;
case KEY_RIGHTSHIFT: return WLR_MODIFIER_SHIFT; case KEY_RIGHTSHIFT: return HL_MODIFIER_SHIFT;
case KEY_LEFTCTRL: return WLR_MODIFIER_CTRL; case KEY_LEFTCTRL: return HL_MODIFIER_CTRL;
case KEY_RIGHTCTRL: return WLR_MODIFIER_CTRL; case KEY_RIGHTCTRL: return HL_MODIFIER_CTRL;
case KEY_LEFTALT: return WLR_MODIFIER_ALT; case KEY_LEFTALT: return HL_MODIFIER_ALT;
case KEY_RIGHTALT: return WLR_MODIFIER_ALT; case KEY_RIGHTALT: return HL_MODIFIER_ALT;
case KEY_CAPSLOCK: return WLR_MODIFIER_CAPS; case KEY_CAPSLOCK: return HL_MODIFIER_CAPS;
case KEY_NUMLOCK: return WLR_MODIFIER_MOD2; case KEY_NUMLOCK: return HL_MODIFIER_MOD2;
default: return 0; default: return 0;
} }
} }
@ -252,7 +254,7 @@ bool CKeybindManager::ensureMouseBindState() {
g_pInputManager->dragMode = MBIND_INVALID; g_pInputManager->dragMode = MBIND_INVALID;
g_pCompositor->updateWorkspaceWindows(lastDraggedWindow->workspaceID()); g_pCompositor->updateWorkspaceWindows(lastDraggedWindow->workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(lastDraggedWindow->workspaceID()); g_pCompositor->updateWorkspaceWindowData(lastDraggedWindow->workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(lastDraggedWindow->m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(lastDraggedWindow->m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@ -279,13 +281,18 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
return false; return false;
const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get(); const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get();
if (!LASTMONITOR)
return false;
if (LASTMONITOR == monitor) { if (LASTMONITOR == monitor) {
Debug::log(LOG, "Tried to move to active monitor"); Debug::log(LOG, "Tried to move to active monitor");
return false; return false;
} }
const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
const auto PNEWMAINWORKSPACE = monitor->activeWorkspace; static auto PNOWARPS = CConfigValue<Hyprlang::INT>("cursor:no_warps");
const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
const auto PNEWMAINWORKSPACE = monitor->activeWorkspace;
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
PNEWMAINWORKSPACE->rememberPrevWorkspace(PWORKSPACE); PNEWMAINWORKSPACE->rememberPrevWorkspace(PWORKSPACE);
@ -298,9 +305,11 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
g_pCompositor->focusWindow(PNEWWINDOW); g_pCompositor->focusWindow(PNEWWINDOW);
PNEWWINDOW->warpCursor(); PNEWWINDOW->warpCursor();
g_pInputManager->m_pForcedFocus = PNEWWINDOW; if (*PNOWARPS == 0 || *PFOLLOWMOUSE < 2) {
g_pInputManager->simulateMouseMovement(); g_pInputManager->m_pForcedFocus = PNEWWINDOW;
g_pInputManager->m_pForcedFocus.reset(); g_pInputManager->simulateMouseMovement();
g_pInputManager->m_pForcedFocus.reset();
}
} else { } else {
g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(nullptr);
g_pCompositor->warpCursorTo(monitor->middle()); g_pCompositor->warpCursorTo(monitor->middle());
@ -311,7 +320,10 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
} }
void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
static auto PNOWARPS = CConfigValue<Hyprlang::INT>("cursor:no_warps");
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (PWINDOWTOCHANGETO == PLASTWINDOW || !PWINDOWTOCHANGETO) if (PWINDOWTOCHANGETO == PLASTWINDOW || !PWINDOWTOCHANGETO)
return; return;
@ -335,9 +347,12 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
g_pCompositor->focusWindow(PWINDOWTOCHANGETO); g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
PWINDOWTOCHANGETO->warpCursor(); PWINDOWTOCHANGETO->warpCursor();
g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO; // Move mouse focus to the new window if required by current follow_mouse and warp modes
g_pInputManager->simulateMouseMovement(); if (*PNOWARPS == 0 || *PFOLLOWMOUSE < 2) {
g_pInputManager->m_pForcedFocus.reset(); g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO;
g_pInputManager->simulateMouseMovement();
g_pInputManager->m_pForcedFocus.reset();
}
if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) { if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) {
// event // event
@ -366,8 +381,8 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbTranslationState : m_pXKBTranslationState, KEYCODE); const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbStaticState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->wlr()->xkb_state, KEYCODE); const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE);
if (handleInternalKeybinds(internalKeysym)) if (handleInternalKeybinds(internalKeysym))
return true; return true;
@ -554,7 +569,7 @@ int repeatKeyHandler(void* data) {
Debug::log(LOG, "Keybind repeat triggered, calling dispatcher."); Debug::log(LOG, "Keybind repeat triggered, calling dispatcher.");
DISPATCHER->second((*ppActiveKeybind)->arg); DISPATCHER->second((*ppActiveKeybind)->arg);
wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->wlr()->repeat_info.rate); wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->repeatRate);
return 0; return 0;
} }
@ -604,10 +619,8 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing"); static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
if (!*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) { if (!*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited())
Debug::log(LOG, "Keybind handling is disabled due to an inhibitor"); Debug::log(LOG, "Keybind handling is disabled due to an inhibitor");
return false;
}
for (auto& k : m_lKeybinds) { for (auto& k : m_lKeybinds) {
const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse"; const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse";
@ -616,6 +629,9 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
const bool IGNORECONDITIONS = const bool IGNORECONDITIONS =
SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released. SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released.
if (!k.dontInhibit && !*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited())
continue;
if (!k.locked && g_pSessionLockManager->isSessionLocked()) if (!k.locked && g_pSessionLockManager->isSessionLocked())
continue; continue;
@ -786,7 +802,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
// beyond this point, return true to not handle anything else. // beyond this point, return true to not handle anything else.
// we'll avoid printing shit to active windows. // we'll avoid printing shit to active windows.
if (g_pCompositor->m_sWLRSession) { if (g_pCompositor->m_pAqBackend->hasSession()) {
const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
// vtnr is bugged for some reason. // vtnr is bugged for some reason.
@ -810,8 +826,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
Debug::log(LOG, "Switching from VT {} to VT {}", ttynum, TTY); Debug::log(LOG, "Switching from VT {} to VT {}", ttynum, TTY);
wlr_session_change_vt(g_pCompositor->m_sWLRSession, TTY); g_pCompositor->m_pAqBackend->session->switchVT(TTY);
return true;
} }
return true; return true;
@ -893,6 +908,7 @@ uint64_t CKeybindManager::spawnRaw(std::string args) {
for (auto& e : HLENV) { for (auto& e : HLENV) {
setenv(e.first.c_str(), e.second.c_str(), 1); setenv(e.first.c_str(), e.second.c_str(), 1);
} }
setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1);
close(socket[0]); close(socket[0]);
close(socket[1]); close(socket[1]);
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
@ -974,7 +990,7 @@ static void toggleActiveFloatingCore(std::string args, std::optional<bool> float
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW); g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW);
} }
g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID()); g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(PWINDOW->workspaceID()); g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
} }
@ -1659,7 +1675,7 @@ void CKeybindManager::renameWorkspace(std::string args) {
} }
void CKeybindManager::exitHyprland(std::string argz) { void CKeybindManager::exitHyprland(std::string argz) {
g_pCompositor->m_bExitTriggered = true; g_pCompositor->stopCompositor();
} }
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
@ -2121,8 +2137,8 @@ void CKeybindManager::sendshortcut(std::string args) {
const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY); const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY);
if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) { if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) {
xkb_keymap* km = KB->wlr()->keymap; xkb_keymap* km = KB->xkbKeymap;
xkb_state* ks = KB->xkbTranslationState; xkb_state* ks = KB->xkbState;
xkb_keycode_t keycode_min, keycode_max; xkb_keycode_t keycode_min, keycode_max;
keycode_min = xkb_keymap_min_keycode(km); keycode_min = xkb_keymap_min_keycode(km);
@ -2233,18 +2249,6 @@ void CKeybindManager::layoutmsg(std::string msg) {
g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg); g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg);
} }
void CKeybindManager::toggleOpaque(std::string unused) {
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PWINDOW)
return;
PWINDOW->m_sAdditionalConfigData.forceOpaque = !PWINDOW->m_sAdditionalConfigData.forceOpaque;
PWINDOW->m_sAdditionalConfigData.forceOpaqueOverridden = true;
g_pHyprRenderer->damageWindow(PWINDOW);
}
void CKeybindManager::dpms(std::string arg) { void CKeybindManager::dpms(std::string arg) {
bool enable = arg.starts_with("on"); bool enable = arg.starts_with("on");
std::string port = ""; std::string port = "";
@ -2260,7 +2264,7 @@ void CKeybindManager::dpms(std::string arg) {
if (!port.empty() && m->szName != port) if (!port.empty() && m->szName != port)
continue; continue;
wlr_output_state_set_enabled(m->state.wlr(), enable); m->output->state->setEnabled(enable);
m->dpmsStatus = enable; m->dpmsStatus = enable;
@ -2362,7 +2366,7 @@ void CKeybindManager::mouse(std::string args) {
const auto PRESSED = args[0] == '1'; const auto PRESSED = args[0] == '1';
if (ARGS[0] == "movewindow") { if (ARGS[0] == "movewindow") {
if (PRESSED) { if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) {
g_pKeybindManager->m_bIsMouseBindActive = true; g_pKeybindManager->m_bIsMouseBindActive = true;
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal(); const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
@ -2376,7 +2380,7 @@ void CKeybindManager::mouse(std::string args) {
g_pInputManager->dragMode = MBIND_MOVE; g_pInputManager->dragMode = MBIND_MOVE;
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
} else { } else if (!PRESSED && g_pInputManager->dragMode == MBIND_MOVE) {
g_pKeybindManager->m_bIsMouseBindActive = false; g_pKeybindManager->m_bIsMouseBindActive = false;
if (!g_pInputManager->currentlyDraggedWindow.expired()) { if (!g_pInputManager->currentlyDraggedWindow.expired()) {
@ -2386,7 +2390,7 @@ void CKeybindManager::mouse(std::string args) {
} }
} }
} else if (ARGS[0] == "resizewindow") { } else if (ARGS[0] == "resizewindow") {
if (PRESSED) { if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) {
g_pKeybindManager->m_bIsMouseBindActive = true; g_pKeybindManager->m_bIsMouseBindActive = true;
g_pInputManager->currentlyDraggedWindow = g_pInputManager->currentlyDraggedWindow =
@ -2400,7 +2404,8 @@ void CKeybindManager::mouse(std::string args) {
} }
} catch (std::exception& e) { g_pInputManager->dragMode = MBIND_RESIZE; } } catch (std::exception& e) { g_pInputManager->dragMode = MBIND_RESIZE; }
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
} else { } else if (!PRESSED &&
(g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO || g_pInputManager->dragMode == MBIND_RESIZE)) {
g_pKeybindManager->m_bIsMouseBindActive = false; g_pKeybindManager->m_bIsMouseBindActive = false;
if (!g_pInputManager->currentlyDraggedWindow.expired()) { if (!g_pInputManager->currentlyDraggedWindow.expired()) {
@ -2487,6 +2492,11 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property! g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property!
if (pWindow->m_iMonitorID != pWindowInDirection->m_iMonitorID) {
pWindow->moveToWorkspace(pWindowInDirection->m_pWorkspace);
pWindow->m_iMonitorID = pWindowInDirection->m_iMonitorID;
}
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current"); static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail(); pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail();

View file

@ -6,6 +6,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include <unordered_map> #include <unordered_map>
#include <functional> #include <functional>
#include <xkbcommon/xkbcommon.h>
#include "../devices/IPointer.hpp" #include "../devices/IPointer.hpp"
class CInputManager; class CInputManager;
@ -33,6 +34,7 @@ struct SKeybind {
bool ignoreMods = false; bool ignoreMods = false;
bool multiKey = false; bool multiKey = false;
bool hasDescription = false; bool hasDescription = false;
bool dontInhibit = false;
// DO NOT INITIALIZE // DO NOT INITIALIZE
bool shadowed = false; bool shadowed = false;
@ -188,7 +190,6 @@ class CKeybindManager {
static void pass(std::string); static void pass(std::string);
static void sendshortcut(std::string); static void sendshortcut(std::string);
static void layoutmsg(std::string); static void layoutmsg(std::string);
static void toggleOpaque(std::string);
static void dpms(std::string); static void dpms(std::string);
static void swapnext(std::string); static void swapnext(std::string);
static void swapActiveWorkspaces(std::string); static void swapActiveWorkspaces(std::string);

View file

@ -6,133 +6,8 @@
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "eventLoop/EventLoopManager.hpp" #include "eventLoop/EventLoopManager.hpp"
#include "SeatManager.hpp" #include "SeatManager.hpp"
#include <wlr/interfaces/wlr_output.h> #include <cstring>
#include <wlr/render/interface.h> #include <gbm.h>
#include <wlr/render/wlr_renderer.h>
// TODO: make nicer
// this will come with the eventual rewrite of wlr_drm, etc...
static bool wlr_drm_format_intersect(wlr_drm_format* dst, const wlr_drm_format* a, const wlr_drm_format* b) {
ASSERT(a->format == b->format);
size_t capacity = a->len < b->len ? a->len : b->len;
uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * capacity);
if (!modifiers)
return false;
struct wlr_drm_format fmt = {
.format = a->format,
.len = 0,
.capacity = capacity,
.modifiers = modifiers,
};
for (size_t i = 0; i < a->len; i++) {
for (size_t j = 0; j < b->len; j++) {
if (a->modifiers[i] == b->modifiers[j]) {
ASSERT(fmt.len < fmt.capacity);
fmt.modifiers[fmt.len++] = a->modifiers[i];
break;
}
}
}
wlr_drm_format_finish(dst);
*dst = fmt;
return true;
}
static bool wlr_drm_format_copy(wlr_drm_format* dst, const wlr_drm_format* src) {
ASSERT(src->len <= src->capacity);
uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * src->len);
if (!modifiers)
return false;
memcpy(modifiers, src->modifiers, sizeof(*modifiers) * src->len);
wlr_drm_format_finish(dst);
dst->capacity = src->len;
dst->len = src->len;
dst->format = src->format;
dst->modifiers = modifiers;
return true;
}
static const wlr_drm_format_set* wlr_renderer_get_render_formats(wlr_renderer* r) {
if (!r->impl->get_render_formats)
return nullptr;
return r->impl->get_render_formats(r);
}
static bool output_pick_format(wlr_output* output, const wlr_drm_format_set* display_formats, wlr_drm_format* format, uint32_t fmt) {
const wlr_drm_format_set* render_formats = wlr_renderer_get_render_formats(g_pCompositor->m_sWLRRenderer);
if (render_formats == NULL) {
wlr_log(WLR_ERROR, "Failed to get render formats");
return false;
}
const wlr_drm_format* render_format = wlr_drm_format_set_get(render_formats, fmt);
if (render_format == NULL) {
wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%" PRIX32, fmt);
return false;
}
if (display_formats != NULL) {
const wlr_drm_format* display_format = wlr_drm_format_set_get(display_formats, fmt);
if (display_format == NULL) {
wlr_log(WLR_DEBUG, "Output doesn't support format 0x%" PRIX32, fmt);
return false;
}
if (!wlr_drm_format_intersect(format, display_format, render_format)) {
wlr_log(WLR_DEBUG,
"Failed to intersect display and render "
"modifiers for format 0x%" PRIX32 " on output %s",
fmt, output->name);
return false;
}
} else {
// The output can display any format
if (!wlr_drm_format_copy(format, render_format))
return false;
}
if (format->len == 0) {
wlr_drm_format_finish(format);
wlr_log(WLR_DEBUG, "Failed to pick output format");
return false;
}
return true;
}
static bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_format* format) {
struct wlr_allocator* allocator = output->allocator;
ASSERT(allocator != NULL);
const struct wlr_drm_format_set* display_formats = NULL;
if (output->impl->get_cursor_formats) {
display_formats = output->impl->get_cursor_formats(output, allocator->buffer_caps);
if (display_formats == NULL) {
wlr_log(WLR_DEBUG, "Failed to get cursor display formats");
return false;
}
}
// 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() { CPointerManager::CPointerManager() {
hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) { hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) {
@ -149,6 +24,14 @@ CPointerManager::CPointerManager() {
}, },
nullptr); nullptr);
}); });
hooks.monitorPreRender = g_pHookSystem->hookDynamic("preRender", [this](void* self, SCallbackInfo& info, std::any data) {
auto state = stateFor(std::any_cast<CMonitor*>(data)->self.lock());
if (!state)
return;
state->cursorRendered = false;
});
} }
void CPointerManager::lockSoftwareAll() { void CPointerManager::lockSoftwareAll() {
@ -201,6 +84,11 @@ void CPointerManager::unlockSoftwareForMonitor(SP<CMonitor> mon) {
updateCursorBackend(); updateCursorBackend();
} }
bool CPointerManager::softwareLockedFor(SP<CMonitor> mon) {
auto state = stateFor(mon);
return state->softwareLocks > 0 || state->hardwareFailed;
}
Vector2D CPointerManager::position() { Vector2D CPointerManager::position() {
return pointerPos; return pointerPos;
} }
@ -216,7 +104,7 @@ SP<CPointerManager::SMonitorPointerState> CPointerManager::stateFor(SP<CMonitor>
return *it; return *it;
} }
void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale) { void CPointerManager::setCursorBuffer(SP<Aquamarine::IBuffer> buf, const Vector2D& hotspot, const float& scale) {
damageIfSoftware(); damageIfSoftware();
if (buf == currentCursorImage.pBuffer) { if (buf == currentCursorImage.pBuffer) {
if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) { if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) {
@ -232,11 +120,8 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot,
resetCursorImage(false); resetCursorImage(false);
if (buf) { if (buf) {
currentCursorImage.size = {buf->width, buf->height}; currentCursorImage.size = buf->size;
currentCursorImage.pBuffer = wlr_buffer_lock(buf); currentCursorImage.pBuffer = buf;
currentCursorImage.hyprListener_destroyBuffer.initCallback(
&buf->events.destroy, [this](void* owner, void* data) { resetCursorImage(); }, this, "CPointerManager");
} }
currentCursorImage.hotspot = hotspot; currentCursorImage.hotspot = hotspot;
@ -318,8 +203,8 @@ void CPointerManager::recheckEnteredOutputs() {
// if we are using hw cursors, prevent // if we are using hw cursors, prevent
// the cursor from being stuck at the last point. // the cursor from being stuck at the last point.
// if we are leaving it, move it to narnia. // if we are leaving it, move it to narnia.
if (!s->hardwareFailed && s->monitor->output->impl->move_cursor) if (!s->hardwareFailed && (s->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
s->monitor->output->impl->move_cursor(s->monitor->output, -1337, -420); s->monitor->output->moveCursor({-1337, -420});
if (!currentCursorImage.surface) if (!currentCursorImage.surface)
continue; continue;
@ -340,16 +225,11 @@ void CPointerManager::resetCursorImage(bool apply) {
currentCursorImage.destroySurface.reset(); currentCursorImage.destroySurface.reset();
currentCursorImage.commitSurface.reset(); currentCursorImage.commitSurface.reset();
currentCursorImage.surface.reset(); currentCursorImage.surface.reset();
} else if (currentCursorImage.pBuffer) { } else if (currentCursorImage.pBuffer)
wlr_buffer_unlock(currentCursorImage.pBuffer);
currentCursorImage.hyprListener_destroyBuffer.removeCallback();
currentCursorImage.pBuffer = nullptr; currentCursorImage.pBuffer = nullptr;
}
if (currentCursorImage.pBufferTexture) { if (currentCursorImage.bufferTex)
wlr_texture_destroy(currentCursorImage.pBufferTexture); currentCursorImage.bufferTex = nullptr;
currentCursorImage.pBufferTexture = nullptr;
}
currentCursorImage.scale = 1.F; currentCursorImage.scale = 1.F;
currentCursorImage.hotspot = {0, 0}; currentCursorImage.hotspot = {0, 0};
@ -371,9 +251,8 @@ void CPointerManager::resetCursorImage(bool apply) {
} }
if (ms->cursorFrontBuffer) { if (ms->cursorFrontBuffer) {
if (ms->monitor->output->impl->set_cursor) if (ms->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)
ms->monitor->output->impl->set_cursor(ms->monitor->output, nullptr, 0, 0); ms->monitor->output->setCursor(nullptr, {});
wlr_buffer_unlock(ms->cursorFrontBuffer);
ms->cursorFrontBuffer = nullptr; ms->cursorFrontBuffer = nullptr;
} }
} }
@ -419,18 +298,18 @@ void CPointerManager::onCursorMoved() {
continue; continue;
const auto CURSORPOS = getCursorPosForMonitor(m); const auto CURSORPOS = getCursorPosForMonitor(m);
m->output->impl->move_cursor(m->output, CURSORPOS.x, CURSORPOS.y); m->output->moveCursor(CURSORPOS);
} }
} }
bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerState> state) { bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerState> state) {
auto output = state->monitor->output; auto output = state->monitor->output;
if (!output->impl->set_cursor) if (!(output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
return false; return false;
const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock()); const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock());
state->monitor->output->impl->move_cursor(state->monitor->output, CURSORPOS.x, CURSORPOS.y); state->monitor->output->moveCursor(CURSORPOS);
auto texture = getCurrentCursorTexture(); auto texture = getCurrentCursorTexture();
@ -460,64 +339,70 @@ bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerS
return success; return success;
} }
bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf) { bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf) {
if (!state->monitor->output->impl->set_cursor) if (!(state->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
return false; return false;
const auto HOTSPOT = transformedHotspot(state->monitor.lock()); const auto HOTSPOT = transformedHotspot(state->monitor.lock());
Debug::log(TRACE, "[pointer] hw transformed hotspot for {}: {}", state->monitor->szName, HOTSPOT); Debug::log(TRACE, "[pointer] hw transformed hotspot for {}: {}", state->monitor->szName, HOTSPOT);
if (!state->monitor->output->impl->set_cursor(state->monitor->output, buf, HOTSPOT.x, HOTSPOT.y)) if (!state->monitor->output->setCursor(buf, HOTSPOT))
return false; return false;
wlr_buffer_unlock(state->cursorFrontBuffer);
state->cursorFrontBuffer = buf; state->cursorFrontBuffer = buf;
g_pCompositor->scheduleFrameForMonitor(state->monitor.get()); g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
if (buf)
wlr_buffer_lock(buf);
return true; return true;
} }
wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) { SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
auto output = state->monitor->output; auto output = state->monitor->output;
int w = currentCursorImage.size.x, h = currentCursorImage.size.y; auto maxSize = output->cursorPlaneSize();
if (output->impl->get_cursor_size) { auto cursorSize = currentCursorImage.size;
output->impl->get_cursor_size(output, &w, &h);
if (w < currentCursorImage.size.x || h < currentCursorImage.size.y) { if (maxSize == Vector2D{})
Debug::log(TRACE, "hardware cursor too big! {} > {}x{}", currentCursorImage.size, w, h);
return nullptr;
}
}
if (w <= 0 || h <= 0) {
Debug::log(TRACE, "hw cursor for output {} failed the size checks ({}x{} is invalid)", state->monitor->szName, w, h);
return nullptr; return nullptr;
}
if (!output->cursor_swapchain || Vector2D{w, h} != Vector2D{output->cursor_swapchain->width, output->cursor_swapchain->height}) { if (maxSize != Vector2D{-1, -1}) {
wlr_drm_format fmt = {0}; if (cursorSize.x > maxSize.x || cursorSize.y > maxSize.y) {
if (!output_pick_cursor_format(output, &fmt)) { Debug::log(TRACE, "hardware cursor too big! {} > {}", currentCursorImage.size, maxSize);
Debug::log(TRACE, "Failed to pick cursor format");
return nullptr; return nullptr;
} }
} else
maxSize = cursorSize;
wlr_swapchain_destroy(output->cursor_swapchain); if (!state->monitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size) {
output->cursor_swapchain = wlr_swapchain_create(output->allocator, w, h, &fmt);
wlr_drm_format_finish(&fmt);
if (!output->cursor_swapchain) { if (!state->monitor->cursorSwapchain)
Debug::log(TRACE, "Failed to create cursor swapchain"); state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(state->monitor->output->getBackend()->preferredAllocator(), state->monitor->output->getBackend());
auto options = state->monitor->cursorSwapchain->currentOptions();
options.size = maxSize;
options.length = 2;
options.scanout = true;
options.cursor = true;
options.multigpu = state->monitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD;
// We do not set the format. If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us,
// but if it's set, we don't wanna change it.
if (!state->monitor->cursorSwapchain->reconfigure(options)) {
Debug::log(TRACE, "Failed to reconfigure cursor swapchain");
return nullptr; return nullptr;
} }
} }
wlr_buffer* buf = wlr_swapchain_acquire(output->cursor_swapchain, nullptr); // if we already rendered the cursor, revert the swapchain to avoid rendering the cursor over
// the current front buffer
// this flag will be reset in the preRender hook, so when we commit this buffer to KMS
if (state->cursorRendered)
state->monitor->cursorSwapchain->rollback();
state->cursorRendered = true;
auto buf = state->monitor->cursorSwapchain->next(nullptr);
if (!buf) { if (!buf) {
Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain"); Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain");
return nullptr; return nullptr;
@ -526,16 +411,45 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPo
CRegion damage = {0, 0, INT16_MAX, INT16_MAX}; CRegion damage = {0, 0, INT16_MAX, INT16_MAX};
g_pHyprRenderer->makeEGLCurrent(); g_pHyprRenderer->makeEGLCurrent();
g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); // has to be set cuz allocs g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get();
auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format);
if (!RBO) {
Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", buf->dmabuf().format, buf->dmabuf().modifier);
static auto PDUMB = CConfigValue<Hyprlang::INT>("cursor:allow_dumb_copy");
if (!*PDUMB)
return nullptr;
auto bufData = buf->beginDataPtr(0);
auto bufPtr = std::get<0>(bufData);
// clear buffer
memset(bufPtr, 0, std::get<2>(bufData));
auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer;
if (texBuffer) {
auto textAttrs = texBuffer->shm();
auto texData = texBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE);
auto texPtr = std::get<0>(texData);
Debug::log(TRACE, "cursor texture {}x{} {} {} {}", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, textAttrs.stride);
// copy cursor texture
for (int i = 0; i < texBuffer->shm().size.y; i++)
memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * textAttrs.stride, textAttrs.stride);
}
buf->endDataPtr();
return buf;
}
const auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, DRM_FORMAT_ARGB8888);
RBO->bind(); RBO->bind();
g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO); g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO);
g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F}); g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F});
CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()}; CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()};
Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, Vector2D{w, h}, Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, cursorSize,
currentCursorImage.scale, state->monitor->scale, xbox.size()); currentCursorImage.scale, state->monitor->scale, xbox.size());
g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F); g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F);
@ -544,9 +458,7 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPo
glFlush(); glFlush();
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
g_pHyprRenderer->onRenderbufferDestroy(RBO); g_pHyprRenderer->onRenderbufferDestroy(RBO.get());
wlr_buffer_unlock(buf);
return buf; return buf;
} }
@ -580,7 +492,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec*
box.x = std::round(box.x); box.x = std::round(box.x);
box.y = std::round(box.y); box.y = std::round(box.y);
g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F); g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F, 0, false, false, currentCursorImage.waitTimeline, currentCursorImage.waitPoint);
if (currentCursorImage.surface) if (currentCursorImage.surface)
currentCursorImage.surface->resource()->frame(now); currentCursorImage.surface->resource()->frame(now);
@ -588,17 +500,19 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec*
Vector2D CPointerManager::getCursorPosForMonitor(SP<CMonitor> pMonitor) { Vector2D CPointerManager::getCursorPosForMonitor(SP<CMonitor> pMonitor) {
return CBox{pointerPos - pMonitor->vecPosition, {0, 0}} return CBox{pointerPos - pMonitor->vecPosition, {0, 0}}
//.transform(pMonitor->transform, pMonitor->vecTransformedSize.x / pMonitor->scale, pMonitor->vecTransformedSize.y / pMonitor->scale) .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x / pMonitor->scale,
pMonitor->vecTransformedSize.y / pMonitor->scale)
.pos() * .pos() *
pMonitor->scale; pMonitor->scale;
} }
Vector2D CPointerManager::transformedHotspot(SP<CMonitor> pMonitor) { Vector2D CPointerManager::transformedHotspot(SP<CMonitor> pMonitor) {
if (!pMonitor->output->cursor_swapchain) if (!pMonitor->cursorSwapchain)
return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors
return CBox{currentCursorImage.hotspot * pMonitor->scale, {0, 0}} return CBox{currentCursorImage.hotspot * pMonitor->scale, {0, 0}}
.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->transform)), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height) .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->cursorSwapchain->currentOptions().size.x,
pMonitor->cursorSwapchain->currentOptions().size.y)
.pos(); .pos();
} }
@ -722,7 +636,7 @@ void CPointerManager::move(const Vector2D& deltaLogical) {
void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) { void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) {
SP<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor.lock(); SP<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor.lock();
if (!currentMonitor) if (!currentMonitor || !dev)
return; return;
if (!std::isnan(abs.x)) if (!std::isnan(abs.x))
@ -800,10 +714,8 @@ SP<CTexture> CPointerManager::getCurrentCursorTexture() {
return nullptr; return nullptr;
if (currentCursorImage.pBuffer) { if (currentCursorImage.pBuffer) {
if (!currentCursorImage.pBufferTexture) { if (!currentCursorImage.bufferTex)
currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer); currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBuffer);
currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBufferTexture);
}
return currentCursorImage.bufferTex; return currentCursorImage.bufferTex;
} }

View file

@ -6,13 +6,15 @@
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../desktop/WLSurface.hpp" #include "../desktop/WLSurface.hpp"
#include "../helpers/sync/SyncTimeline.hpp"
#include <tuple> #include <tuple>
class CMonitor; class CMonitor;
struct wlr_input_device;
class IHID; class IHID;
class CTexture; class CTexture;
AQUAMARINE_FORWARD(IBuffer);
/* /*
The naming here is a bit confusing. The naming here is a bit confusing.
CPointerManager manages the _position_ and _displaying_ of the cursor, CPointerManager manages the _position_ and _displaying_ of the cursor,
@ -37,7 +39,7 @@ class CPointerManager {
void move(const Vector2D& deltaLogical); void move(const Vector2D& deltaLogical);
void warpAbsolute(Vector2D abs, SP<IHID> dev); void warpAbsolute(Vector2D abs, SP<IHID> dev);
void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale); void setCursorBuffer(SP<Aquamarine::IBuffer> buf, const Vector2D& hotspot, const float& scale);
void setCursorSurface(SP<CWLSurface> buf, const Vector2D& hotspot); void setCursorSurface(SP<CWLSurface> buf, const Vector2D& hotspot);
void resetCursorImage(bool apply = true); void resetCursorImage(bool apply = true);
@ -47,6 +49,7 @@ class CPointerManager {
void unlockSoftwareForMonitor(CMonitor* pMonitor); void unlockSoftwareForMonitor(CMonitor* pMonitor);
void lockSoftwareAll(); void lockSoftwareAll();
void unlockSoftwareAll(); void unlockSoftwareAll();
bool softwareLockedFor(SP<CMonitor> pMonitor);
void renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */); void renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */);
@ -135,48 +138,47 @@ class CPointerManager {
} currentMonitorLayout; } currentMonitorLayout;
struct { struct {
wlr_buffer* pBuffer = nullptr; SP<Aquamarine::IBuffer> pBuffer;
SP<CTexture> bufferTex; SP<CTexture> bufferTex;
WP<CWLSurface> surface; WP<CWLSurface> surface;
wlr_texture* pBufferTexture = nullptr;
Vector2D hotspot; Vector2D hotspot;
Vector2D size; Vector2D size;
float scale = 1.F; float scale = 1.F;
CHyprSignalListener destroySurface; CHyprSignalListener destroySurface;
CHyprSignalListener commitSurface; CHyprSignalListener commitSurface;
DYNLISTENER(destroyBuffer); SP<CSyncTimeline> waitTimeline = nullptr;
uint64_t waitPoint = 0;
} currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors } currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors
Vector2D pointerPos = {0, 0}; Vector2D pointerPos = {0, 0};
struct SMonitorPointerState { struct SMonitorPointerState {
SMonitorPointerState(SP<CMonitor> m) : monitor(m) {} SMonitorPointerState(SP<CMonitor> m) : monitor(m) {}
~SMonitorPointerState() { ~SMonitorPointerState() {}
if (cursorFrontBuffer)
wlr_buffer_unlock(cursorFrontBuffer);
}
WP<CMonitor> monitor; WP<CMonitor> monitor;
int softwareLocks = 0; int softwareLocks = 0;
bool hardwareFailed = false; bool hardwareFailed = false;
CBox box; // logical CBox box; // logical
bool entered = false; bool entered = false;
bool hwApplied = false; bool hwApplied = false;
bool cursorRendered = false;
wlr_buffer* cursorFrontBuffer = nullptr; SP<Aquamarine::IBuffer> cursorFrontBuffer;
}; };
std::vector<SP<SMonitorPointerState>> monitorStates; std::vector<SP<SMonitorPointerState>> monitorStates;
SP<SMonitorPointerState> stateFor(SP<CMonitor> mon); SP<SMonitorPointerState> stateFor(SP<CMonitor> mon);
bool attemptHardwareCursor(SP<SMonitorPointerState> state); bool attemptHardwareCursor(SP<SMonitorPointerState> state);
wlr_buffer* renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture); SP<Aquamarine::IBuffer> renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture);
bool setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf); bool setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf);
struct { struct {
SP<HOOK_CALLBACK_FN> monitorAdded; SP<HOOK_CALLBACK_FN> monitorAdded;
SP<HOOK_CALLBACK_FN> monitorPreRender;
} hooks; } hooks;
}; };

View file

@ -1,5 +1,7 @@
#include "ProtocolManager.hpp" #include "ProtocolManager.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/TearingControl.hpp" #include "../protocols/TearingControl.hpp"
#include "../protocols/FractionalScale.hpp" #include "../protocols/FractionalScale.hpp"
#include "../protocols/XDGOutput.hpp" #include "../protocols/XDGOutput.hpp"
@ -35,6 +37,10 @@
#include "../protocols/Viewporter.hpp" #include "../protocols/Viewporter.hpp"
#include "../protocols/MesaDRM.hpp" #include "../protocols/MesaDRM.hpp"
#include "../protocols/LinuxDMABUF.hpp" #include "../protocols/LinuxDMABUF.hpp"
#include "../protocols/DRMLease.hpp"
#include "../protocols/DRMSyncobj.hpp"
#include "../protocols/Screencopy.hpp"
#include "../protocols/ToplevelExport.hpp"
#include "../protocols/core/Seat.hpp" #include "../protocols/core/Seat.hpp"
#include "../protocols/core/DataDevice.hpp" #include "../protocols/core/DataDevice.hpp"
@ -45,6 +51,10 @@
#include "../helpers/Monitor.hpp" #include "../helpers/Monitor.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
#include "../Compositor.hpp"
#include <aquamarine/buffer/Buffer.hpp>
#include <aquamarine/backend/Backend.hpp>
void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) {
const bool ISMIRROR = pMonitor->isMirror(); const bool ISMIRROR = pMonitor->isMirror();
@ -58,13 +68,14 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) {
else if (!ISMIRROR && (!PROTO::outputs.contains(pMonitor->szName) || PROTO::outputs.at(pMonitor->szName)->isDefunct())) { else if (!ISMIRROR && (!PROTO::outputs.contains(pMonitor->szName) || PROTO::outputs.at(pMonitor->szName)->isDefunct())) {
if (PROTO::outputs.contains(pMonitor->szName)) if (PROTO::outputs.contains(pMonitor->szName))
PROTO::outputs.erase(pMonitor->szName); PROTO::outputs.erase(pMonitor->szName);
PROTO::outputs.emplace(pMonitor->szName, PROTO::outputs.emplace(pMonitor->szName, makeShared<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock()));
std::make_unique<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock()));
} }
} }
CProtocolManager::CProtocolManager() { CProtocolManager::CProtocolManager() {
static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("experimental:explicit_sync");
// Outputs are a bit dumb, we have to agree. // Outputs are a bit dumb, we have to agree.
static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) {
auto M = std::any_cast<CMonitor*>(param); auto M = std::any_cast<CMonitor*>(param);
@ -76,7 +87,10 @@ CProtocolManager::CProtocolManager() {
if (PROTO::outputs.contains(M->szName)) if (PROTO::outputs.contains(M->szName))
PROTO::outputs.erase(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()));
auto ref = makeShared<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock());
PROTO::outputs.emplace(M->szName, ref);
ref->self = ref;
m_mModeChangeListeners[M->szName] = M->events.modeChanged.registerListener([M, this](std::any d) { onMonitorModeChange(M); }); m_mModeChangeListeners[M->szName] = M->events.modeChanged.registerListener([M, this](std::any d) { onMonitorModeChange(M); });
}); });
@ -130,6 +144,18 @@ CProtocolManager::CProtocolManager() {
PROTO::dataWlr = std::make_unique<CDataDeviceWLRProtocol>(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); 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::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"); PROTO::xwaylandShell = std::make_unique<CXWaylandShellProtocol>(&xwayland_shell_v1_interface, 1, "XWaylandShell");
PROTO::screencopy = std::make_unique<CScreencopyProtocol>(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy");
PROTO::toplevelExport = std::make_unique<CToplevelExportProtocol>(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport");
for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) {
if (b->type() != Aquamarine::AQ_BACKEND_DRM)
continue;
PROTO::lease = std::make_unique<CDRMLeaseProtocol>(&wp_drm_lease_device_v1_interface, 1, "DRMLease");
if (*PENABLEEXPLICIT)
PROTO::sync = std::make_unique<CDRMSyncobjProtocol>(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj");
break;
}
if (g_pHyprOpenGL->getDRMFormats().size() > 0) { if (g_pHyprOpenGL->getDRMFormats().size() > 0) {
PROTO::mesaDRM = std::make_unique<CMesaDRMProtocol>(&wl_drm_interface, 2, "MesaDRM"); PROTO::mesaDRM = std::make_unique<CMesaDRMProtocol>(&wl_drm_interface, 2, "MesaDRM");
@ -139,8 +165,62 @@ CProtocolManager::CProtocolManager() {
// Old protocol implementations. // Old protocol implementations.
// TODO: rewrite them to use hyprwayland-scanner. // TODO: rewrite them to use hyprwayland-scanner.
m_pToplevelExportProtocolManager = std::make_unique<CToplevelExportProtocolManager>();
m_pTextInputV1ProtocolManager = std::make_unique<CTextInputV1ProtocolManager>(); m_pTextInputV1ProtocolManager = std::make_unique<CTextInputV1ProtocolManager>();
m_pGlobalShortcutsProtocolManager = std::make_unique<CGlobalShortcutsProtocolManager>(); m_pGlobalShortcutsProtocolManager = std::make_unique<CGlobalShortcutsProtocolManager>();
m_pScreencopyProtocolManager = std::make_unique<CScreencopyProtocolManager>(); }
CProtocolManager::~CProtocolManager() {
// this is dumb but i don't want to replace all 600 PROTO with the right thing
// Output
PROTO::outputs.clear();
// Core
PROTO::seat.reset();
PROTO::data.reset();
PROTO::compositor.reset();
PROTO::subcompositor.reset();
PROTO::shm.reset();
// Extensions
PROTO::viewport.reset();
PROTO::tearing.reset();
PROTO::fractional.reset();
PROTO::xdgOutput.reset();
PROTO::cursorShape.reset();
PROTO::idleInhibit.reset();
PROTO::relativePointer.reset();
PROTO::xdgDecoration.reset();
PROTO::alphaModifier.reset();
PROTO::gamma.reset();
PROTO::foreignToplevel.reset();
PROTO::pointerGestures.reset();
PROTO::foreignToplevelWlr.reset();
PROTO::shortcutsInhibit.reset();
PROTO::textInputV3.reset();
PROTO::constraints.reset();
PROTO::outputPower.reset();
PROTO::activation.reset();
PROTO::idle.reset();
PROTO::sessionLock.reset();
PROTO::ime.reset();
PROTO::virtualKeyboard.reset();
PROTO::virtualPointer.reset();
PROTO::outputManagement.reset();
PROTO::serverDecorationKDE.reset();
PROTO::focusGrab.reset();
PROTO::tablet.reset();
PROTO::layerShell.reset();
PROTO::presentation.reset();
PROTO::xdgShell.reset();
PROTO::dataWlr.reset();
PROTO::primarySelection.reset();
PROTO::xwaylandShell.reset();
PROTO::screencopy.reset();
PROTO::toplevelExport.reset();
PROTO::lease.reset();
PROTO::sync.reset();
PROTO::mesaDRM.reset();
PROTO::linuxDma.reset();
} }

View file

@ -1,10 +1,9 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../protocols/ToplevelExport.hpp"
#include "../protocols/TextInputV1.hpp" #include "../protocols/TextInputV1.hpp"
#include "../protocols/GlobalShortcuts.hpp" #include "../protocols/GlobalShortcuts.hpp"
#include "../protocols/Screencopy.hpp" #include "../helpers/Monitor.hpp"
#include "../helpers/memory/Memory.hpp" #include "../helpers/memory/Memory.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
#include <unordered_map> #include <unordered_map>
@ -12,12 +11,11 @@
class CProtocolManager { class CProtocolManager {
public: public:
CProtocolManager(); CProtocolManager();
~CProtocolManager();
// TODO: rewrite to use the new protocol framework // TODO: rewrite to use the new protocol framework
std::unique_ptr<CToplevelExportProtocolManager> m_pToplevelExportProtocolManager;
std::unique_ptr<CTextInputV1ProtocolManager> m_pTextInputV1ProtocolManager; std::unique_ptr<CTextInputV1ProtocolManager> m_pTextInputV1ProtocolManager;
std::unique_ptr<CGlobalShortcutsProtocolManager> m_pGlobalShortcutsProtocolManager; std::unique_ptr<CGlobalShortcutsProtocolManager> m_pGlobalShortcutsProtocolManager;
std::unique_ptr<CScreencopyProtocolManager> m_pScreencopyProtocolManager;
private: private:
std::unordered_map<std::string, CHyprSignalListener> m_mModeChangeListeners; std::unordered_map<std::string, CHyprSignalListener> m_mModeChangeListeners;

View file

@ -94,8 +94,8 @@ void CSeatManager::setKeyboard(SP<IKeyboard> KEEB) {
} }
void CSeatManager::updateActiveKeyboardData() { void CSeatManager::updateActiveKeyboardData() {
if (keyboard && keyboard->wlr()) if (keyboard)
PROTO::seat->updateRepeatInfo(keyboard->wlr()->repeat_info.rate, keyboard->wlr()->repeat_info.delay); PROTO::seat->updateRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay);
PROTO::seat->updateKeymap(); PROTO::seat->updateKeymap();
} }
@ -103,7 +103,7 @@ void CSeatManager::setKeyboardFocus(SP<CWLSurfaceResource> surf) {
if (state.keyboardFocus == surf) if (state.keyboardFocus == surf)
return; return;
if (!keyboard || !keyboard->wlr()) { if (!keyboard) {
Debug::log(ERR, "BUG THIS: setKeyboardFocus without a valid keyboard set"); Debug::log(ERR, "BUG THIS: setKeyboardFocus without a valid keyboard set");
return; return;
} }
@ -144,7 +144,7 @@ void CSeatManager::setKeyboardFocus(SP<CWLSurfaceResource> surf) {
continue; continue;
k->sendEnter(surf); k->sendEnter(surf);
k->sendMods(keyboard->wlr()->modifiers.depressed, keyboard->wlr()->modifiers.latched, keyboard->wlr()->modifiers.locked, keyboard->wlr()->modifiers.group); k->sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group);
} }
} }
@ -196,7 +196,7 @@ void CSeatManager::setPointerFocus(SP<CWLSurfaceResource> surf, const Vector2D&
return; return;
} }
if (!mouse || !mouse->wlr()) { if (!mouse) {
Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set"); Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set");
return; return;
} }
@ -333,9 +333,7 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double
if (source == 0) { if (source == 0) {
p->sendAxisValue120(axis, value120); p->sendAxisValue120(axis, value120);
p->sendAxisDiscrete(axis, discrete); p->sendAxisDiscrete(axis, discrete);
} } else if (value == 0)
if (value == 0)
p->sendAxisStop(timeMs, axis); p->sendAxisStop(timeMs, axis);
} }
} }

View file

@ -3,6 +3,7 @@
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../protocols/FractionalScale.hpp" #include "../protocols/FractionalScale.hpp"
#include "../protocols/SessionLock.hpp" #include "../protocols/SessionLock.hpp"
#include <algorithm>
SSessionLockSurface::SSessionLockSurface(SP<CSessionLockSurface> surface_) : surface(surface_) { SSessionLockSurface::SSessionLockSurface(SP<CSessionLockSurface> surface_) : surface(surface_) {
pWlrSurface = surface->surface(); pWlrSurface = surface->surface();
@ -77,7 +78,6 @@ void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) {
g_pHyprRenderer->damageMonitor(m.get()); g_pHyprRenderer->damageMonitor(m.get());
}); });
pLock->sendLocked();
g_pCompositor->focusSurface(nullptr); g_pCompositor->focusSurface(nullptr);
} }
@ -102,7 +102,6 @@ SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64
} }
// We don't want the red screen to flash. // We don't want the red screen to flash.
// This violates the protocol a bit, but tries to handle the missing sync between a lock surface beeing created and the red screen beeing drawn.
float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) { float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) {
if (!m_pSessionLock) if (!m_pSessionLock)
return 0.F; return 0.F;
@ -118,6 +117,18 @@ float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) {
return std::clamp(NOMAPPEDSURFACETIMER->second.getSeconds() - /* delay for screencopy */ 0.5f, 0.f, 1.f); return std::clamp(NOMAPPEDSURFACETIMER->second.getSeconds() - /* delay for screencopy */ 0.5f, 0.f, 1.f);
} }
void CSessionLockManager::onLockscreenRenderedOnMonitor(uint64_t id) {
if (!m_pSessionLock || m_pSessionLock->m_hasSentLocked)
return;
m_pSessionLock->m_lockedMonitors.emplace(id);
const auto MONITORS = g_pCompositor->m_vMonitors;
const bool LOCKED = std::all_of(MONITORS.begin(), MONITORS.end(), [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); });
if (LOCKED) {
m_pSessionLock->lock->sendLocked();
m_pSessionLock->m_hasSentLocked = true;
}
}
bool CSessionLockManager::isSurfaceSessionLock(SP<CWLSurfaceResource> 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) // 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 // but can be easily fixed when I rewrite wlr_surface

View file

@ -5,6 +5,7 @@
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
#include <cstdint> #include <cstdint>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
class CSessionLockSurface; class CSessionLockSurface;
class CSessionLock; class CSessionLock;
@ -37,6 +38,9 @@ struct SSessionLock {
CHyprSignalListener unlock; CHyprSignalListener unlock;
CHyprSignalListener destroy; CHyprSignalListener destroy;
} listeners; } listeners;
bool m_hasSentLocked = false;
std::unordered_set<uint64_t> m_lockedMonitors;
}; };
class CSessionLockManager { class CSessionLockManager {
@ -54,6 +58,8 @@ class CSessionLockManager {
void removeSessionLockSurface(SSessionLockSurface*); void removeSessionLockSurface(SSessionLockSurface*);
void onLockscreenRenderedOnMonitor(uint64_t id);
private: private:
UP<SSessionLock> m_pSessionLock; UP<SSessionLock> m_pSessionLock;
@ -64,4 +70,4 @@ class CSessionLockManager {
void onNewSessionLock(SP<CSessionLock> pWlrLock); void onNewSessionLock(SP<CSessionLock> pWlrLock);
}; };
inline std::unique_ptr<CSessionLockManager> g_pSessionLockManager; inline std::unique_ptr<CSessionLockManager> g_pSessionLockManager;

View file

@ -76,13 +76,21 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) {
const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get();
if (SIZEHINTS && pWindow->m_iX11Type != 2) { if (SIZEHINTS && pWindow->m_iX11Type != 2) {
pbox->x = SIZEHINTS->x; // WM_SIZE_HINTS' x,y,w,h is deprecated it seems.
pbox->y = SIZEHINTS->y; // Source: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#wm_normal_hints_property
pbox->width = SIZEHINTS->width; pbox->x = pWindow->m_pXWaylandSurface->geometry.x;
pbox->height = SIZEHINTS->height; pbox->y = pWindow->m_pXWaylandSurface->geometry.y;
} else {
if ((SIZEHINTS->flags & 0x2 /* ICCCM USSize */) || (SIZEHINTS->flags & 0x8 /* ICCCM PSize */)) {
pbox->w = SIZEHINTS->base_width;
pbox->h = SIZEHINTS->base_height;
} else {
pbox->w = pWindow->m_pXWaylandSurface->geometry.w;
pbox->h = pWindow->m_pXWaylandSurface->geometry.h;
}
} else
*pbox = pWindow->m_pXWaylandSurface->geometry; *pbox = pWindow->m_pXWaylandSurface->geometry;
}
} else if (pWindow->m_pXDGSurface) } else if (pWindow->m_pXDGSurface)
*pbox = pWindow->m_pXDGSurface->current.geometry; *pbox = pWindow->m_pXDGSurface->current.geometry;
} }
@ -206,7 +214,8 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) {
if (!validMapped(pWindow)) if (!validMapped(pWindow))
return Vector2D(99999, 99999); return Vector2D(99999, 99999);
if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!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_sWindowData.noMaxSize.valueOrDefault())
return Vector2D(99999, 99999); return Vector2D(99999, 99999);
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) : auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) :

View file

@ -1,5 +1,6 @@
#include "EventLoopManager.hpp" #include "EventLoopManager.hpp"
#include "../../debug/Log.hpp" #include "../../debug/Log.hpp"
#include "../../Compositor.hpp"
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
@ -7,6 +8,8 @@
#include <sys/timerfd.h> #include <sys/timerfd.h>
#include <time.h> #include <time.h>
#include <aquamarine/backend/Backend.hpp>
#define TIMESPEC_NSEC_PER_SEC 1000000000L #define TIMESPEC_NSEC_PER_SEC 1000000000L
CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) { CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) {
@ -16,8 +19,14 @@ CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEvent
} }
CEventLoopManager::~CEventLoopManager() { CEventLoopManager::~CEventLoopManager() {
for (auto& eventSource : m_sWayland.aqEventSources) {
wl_event_source_remove(eventSource);
}
if (m_sWayland.eventSource) if (m_sWayland.eventSource)
wl_event_source_remove(m_sWayland.eventSource); wl_event_source_remove(m_sWayland.eventSource);
if (m_sIdle.eventSource)
wl_event_source_remove(m_sIdle.eventSource);
} }
static int timerWrite(int fd, uint32_t mask, void* data) { static int timerWrite(int fd, uint32_t mask, void* data) {
@ -25,9 +34,21 @@ static int timerWrite(int fd, uint32_t mask, void* data) {
return 1; return 1;
} }
static int aquamarineFDWrite(int fd, uint32_t mask, void* data) {
auto POLLFD = (Aquamarine::SPollFD*)data;
POLLFD->onSignal();
return 1;
}
void CEventLoopManager::enterLoop() { void CEventLoopManager::enterLoop() {
m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr);
aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs();
for (auto& fd : aqPollFDs) {
m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get()));
fd->onSignal(); // dispatch outstanding
}
wl_display_run(m_sWayland.display); wl_display_run(m_sWayland.display);
Debug::log(LOG, "Kicked off the event loop! :("); Debug::log(LOG, "Kicked off the event loop! :(");

View file

@ -7,6 +7,10 @@
#include "EventLoopTimer.hpp" #include "EventLoopTimer.hpp"
namespace Aquamarine {
struct SPollFD;
};
class CEventLoopManager { class CEventLoopManager {
public: public:
CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop); CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop);
@ -33,9 +37,10 @@ class CEventLoopManager {
private: private:
struct { struct {
wl_event_loop* loop = nullptr; wl_event_loop* loop = nullptr;
wl_display* display = nullptr; wl_display* display = nullptr;
wl_event_source* eventSource = nullptr; wl_event_source* eventSource = nullptr;
std::vector<wl_event_source*> aqEventSources;
} m_sWayland; } m_sWayland;
struct { struct {
@ -43,7 +48,10 @@ class CEventLoopManager {
int timerfd = -1; int timerfd = -1;
} m_sTimers; } m_sTimers;
SIdleData m_sIdle; SIdleData m_sIdle;
std::vector<SP<Aquamarine::SPollFD>> aqPollFDs;
friend class CSyncTimeline;
}; };
inline std::unique_ptr<CEventLoopManager> g_pEventLoopManager; inline std::unique_ptr<CEventLoopManager> g_pEventLoopManager;

View file

@ -7,7 +7,7 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) {
const auto PINHIBIT = m_vIdleInhibitors.emplace_back(std::make_unique<SIdleInhibitor>()).get(); const auto PINHIBIT = m_vIdleInhibitors.emplace_back(std::make_unique<SIdleInhibitor>()).get();
PINHIBIT->inhibitor = std::any_cast<SP<CIdleInhibitor>>(inhibitor); PINHIBIT->inhibitor = std::any_cast<SP<CIdleInhibitor>>(inhibitor);
Debug::log(LOG, "New idle inhibitor registered for surface {:x}", (uintptr_t)PINHIBIT->inhibitor->surface); Debug::log(LOG, "New idle inhibitor registered for surface {:x}", (uintptr_t)PINHIBIT->inhibitor->surface.get());
PINHIBIT->inhibitor->listeners.destroy = PINHIBIT->inhibitor->resource->events.destroy.registerListener([this, PINHIBIT](std::any data) { PINHIBIT->inhibitor->listeners.destroy = PINHIBIT->inhibitor->resource->events.destroy.registerListener([this, PINHIBIT](std::any data) {
std::erase_if(m_vIdleInhibitors, [PINHIBIT](const auto& other) { return other.get() == PINHIBIT; }); std::erase_if(m_vIdleInhibitors, [PINHIBIT](const auto& other) { return other.get() == PINHIBIT; });

View file

@ -1,6 +1,6 @@
#include "InputManager.hpp" #include "InputManager.hpp"
#include "../../Compositor.hpp" #include "../../Compositor.hpp"
#include "wlr/types/wlr_switch.h" #include <aquamarine/output/Output.hpp>
#include <cstdint> #include <cstdint>
#include <ranges> #include <ranges>
#include "../../config/ConfigValue.hpp" #include "../../config/ConfigValue.hpp"
@ -28,6 +28,8 @@
#include "../../managers/PointerManager.hpp" #include "../../managers/PointerManager.hpp"
#include "../../managers/SeatManager.hpp" #include "../../managers/SeatManager.hpp"
#include <aquamarine/input/Input.hpp>
CInputManager::CInputManager() { CInputManager::CInputManager() {
m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) { m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) {
if (!cursorImageUnlocked()) if (!cursorImageUnlocked())
@ -189,8 +191,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
bool skipFrameSchedule = PMONITOR->shouldSkipScheduleFrameOnMouseEvent(); bool skipFrameSchedule = PMONITOR->shouldSkipScheduleFrameOnMouseEvent();
if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0 && !skipFrameSchedule) if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) && !skipFrameSchedule)
g_pCompositor->scheduleFrameForMonitor(PMONITOR); g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE);
PHLWINDOW forcedFocus = m_pForcedFocus.lock(); PHLWINDOW forcedFocus = m_pForcedFocus.lock();
@ -226,7 +228,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return; return;
} else } else
Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF, (uintptr_t)CONSTRAINT.get()); Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF.get(), (uintptr_t)CONSTRAINT.get());
} }
// if we are holding a pointer button, // if we are holding a pointer button,
@ -372,8 +374,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
foundSurface = foundSurface =
g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface); g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface);
if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0 && !skipFrameSchedule) if (g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) > 0 && !skipFrameSchedule)
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get()); g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE);
// grabs // grabs
if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(foundSurface)) { if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(foundSurface)) {
@ -568,7 +570,7 @@ void CInputManager::processMouseRequest(std::any E) {
auto e = std::any_cast<CSeatManager::SSetCursorEvent>(E); auto e = std::any_cast<CSeatManager::SSetCursorEvent>(E);
Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf); Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf.get());
if (e.surf != m_sCursorSurfaceInfo.wlSurface->resource()) { if (e.surf != m_sCursorSurfaceInfo.wlSurface->resource()) {
m_sCursorSurfaceInfo.wlSurface->unassign(); m_sCursorSurfaceInfo.wlSurface->unassign();
@ -760,6 +762,7 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) {
static auto POFFWINDOWAXIS = CConfigValue<Hyprlang::INT>("input:off_window_axis_events"); static auto POFFWINDOWAXIS = CConfigValue<Hyprlang::INT>("input:off_window_axis_events");
static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor"); static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor");
static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor"); static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor");
static auto PEMULATEDISCRETE = CConfigValue<Hyprlang::INT>("input:emulate_discrete_scroll");
auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR); auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR);
@ -798,21 +801,56 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) {
} }
} }
} }
double deltaDiscrete = (e.deltaDiscrete != 0) ? (factor * e.deltaDiscrete / std::abs(e.deltaDiscrete)) : 0;
g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, deltaDiscrete > 0 ? std::ceil(deltaDiscrete) : std::floor(deltaDiscrete), double discrete = (e.deltaDiscrete != 0) ? (factor * e.deltaDiscrete / std::abs(e.deltaDiscrete)) : 0;
std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); double delta = e.delta * factor;
if (e.source == 0) {
// if an application supports v120, it should ignore discrete anyways
if ((*PEMULATEDISCRETE >= 1 && std::abs(e.deltaDiscrete) != 120) || *PEMULATEDISCRETE >= 2) {
const int interval = factor != 0 ? std::round(120 * (1 / factor)) : 120;
// reset the accumulator when timeout is reached or direction/axis has changed
if (std::signbit(e.deltaDiscrete) != m_ScrollWheelState.lastEventSign || e.axis != m_ScrollWheelState.lastEventAxis ||
e.timeMs - m_ScrollWheelState.lastEventTime > 500 /* 500ms taken from libinput default timeout */) {
m_ScrollWheelState.accumulatedScroll = 0;
// send 1 discrete on first event for responsiveness
discrete = std::copysign(1, e.deltaDiscrete);
} else
discrete = 0;
for (int ac = m_ScrollWheelState.accumulatedScroll; ac >= interval; ac -= interval) {
discrete += std::copysign(1, e.deltaDiscrete);
m_ScrollWheelState.accumulatedScroll -= interval;
}
m_ScrollWheelState.lastEventSign = std::signbit(e.deltaDiscrete);
m_ScrollWheelState.lastEventAxis = e.axis;
m_ScrollWheelState.lastEventTime = e.timeMs;
m_ScrollWheelState.accumulatedScroll += std::abs(e.deltaDiscrete);
delta = 15.0 * discrete * factor;
}
}
int32_t value120 = std::round(factor * e.deltaDiscrete);
int32_t deltaDiscrete = std::abs(discrete) != 0 && std::abs(discrete) < 1 ? std::copysign(1, discrete) : std::round(discrete);
g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, delta, deltaDiscrete, value120, e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL);
} }
Vector2D CInputManager::getMouseCoordsInternal() { Vector2D CInputManager::getMouseCoordsInternal() {
return g_pPointerManager->position(); return g_pPointerManager->position();
} }
void CInputManager::newKeyboard(wlr_input_device* keyboard) { void CInputManager::newKeyboard(SP<Aquamarine::IKeyboard> keyboard) {
const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(wlr_keyboard_from_input_device(keyboard))); const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(keyboard));
setupKeyboard(PNEWKEYBOARD); setupKeyboard(PNEWKEYBOARD);
Debug::log(LOG, "New keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard); Debug::log(LOG, "New keyboard created, pointers Hypr: {:x} and AQ: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard.get());
} }
void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard) { void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard) {
@ -820,14 +858,14 @@ void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard)
setupKeyboard(PNEWKEYBOARD); setupKeyboard(PNEWKEYBOARD);
Debug::log(LOG, "New virtual keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard->wlr()); Debug::log(LOG, "New virtual keyboard created at {:x}", (uintptr_t)PNEWKEYBOARD.get());
} }
void CInputManager::setupKeyboard(SP<IKeyboard> keeb) { void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
m_vHIDs.push_back(keeb); m_vHIDs.push_back(keeb);
try { try {
keeb->hlName = getNameForNewDevice(keeb->wlr()->base.name); keeb->hlName = getNameForNewDevice(keeb->deviceName);
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Keyboard had no name???"); // logic error Debug::log(ERR, "Keyboard had no name???"); // logic error
} }
@ -926,83 +964,12 @@ void CInputManager::applyConfigToKeyboard(SP<IKeyboard> pKeyboard) {
// we can ignore those and just apply // we can ignore those and just apply
} }
wlr_keyboard_set_repeat_info(pKeyboard->wlr(), std::max(0, REPEATRATE), std::max(0, REPEATDELAY)); pKeyboard->repeatRate = std::max(0, REPEATRATE);
pKeyboard->repeatDelay = std::max(0, REPEATDELAY);
pKeyboard->repeatDelay = REPEATDELAY;
pKeyboard->repeatRate = REPEATRATE;
pKeyboard->numlockOn = NUMLOCKON; pKeyboard->numlockOn = NUMLOCKON;
pKeyboard->xkbFilePath = FILEPATH; pKeyboard->xkbFilePath = FILEPATH;
xkb_rule_names rules = {.rules = RULES.c_str(), .model = MODEL.c_str(), .layout = LAYOUT.c_str(), .variant = VARIANT.c_str(), .options = OPTIONS.c_str()}; pKeyboard->setKeymap(IKeyboard::SStringRuleNames{LAYOUT, MODEL, VARIANT, OPTIONS, RULES});
pKeyboard->currentRules.rules = RULES;
pKeyboard->currentRules.model = MODEL;
pKeyboard->currentRules.variant = VARIANT;
pKeyboard->currentRules.options = OPTIONS;
pKeyboard->currentRules.layout = LAYOUT;
const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!CONTEXT) {
Debug::log(ERR, "applyConfigToKeyboard: CONTEXT null??");
return;
}
Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model,
rules.options);
xkb_keymap* KEYMAP = NULL;
if (!FILEPATH.empty()) {
auto path = absolutePath(FILEPATH, g_pConfigManager->configCurrentPath);
if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE)
Debug::log(ERR, "Cannot open input:kb_file= file for reading");
else {
KEYMAP = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
fclose(KEYMAPFILE);
}
}
if (!KEYMAP)
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!KEYMAP) {
g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS +
", layout: " + LAYOUT + " )");
Debug::log(ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model,
rules.options);
memset(&rules, 0, sizeof(rules));
pKeyboard->currentRules.rules = "";
pKeyboard->currentRules.model = "";
pKeyboard->currentRules.variant = "";
pKeyboard->currentRules.options = "";
pKeyboard->currentRules.layout = "us";
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
wlr_keyboard_set_keymap(pKeyboard->wlr(), KEYMAP);
pKeyboard->updateXKBTranslationState();
wlr_keyboard_modifiers wlrMods = {0};
if (NUMLOCKON == 1) {
// lock numlock
const auto IDX = xkb_map_mod_get_index(KEYMAP, XKB_MOD_NAME_NUM);
if (IDX != XKB_MOD_INVALID)
wlrMods.locked |= (uint32_t)1 << IDX;
}
if (wlrMods.locked != 0)
wlr_keyboard_notify_modifiers(pKeyboard->wlr(), 0, 0, wlrMods.locked, 0);
xkb_keymap_unref(KEYMAP);
xkb_context_unref(CONTEXT);
const auto LAYOUTSTR = pKeyboard->getActiveLayout(); const auto LAYOUTSTR = pKeyboard->getActiveLayout();
@ -1017,28 +984,28 @@ void CInputManager::newVirtualMouse(SP<CVirtualPointerV1Resource> mouse) {
setupMouse(PMOUSE); setupMouse(PMOUSE);
Debug::log(LOG, "New virtual mouse created, pointer WLR: {:x}", (uintptr_t)mouse->wlr()); Debug::log(LOG, "New virtual mouse created");
} }
void CInputManager::newMouse(wlr_input_device* mouse) { void CInputManager::newMouse(SP<Aquamarine::IPointer> mouse) {
const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(wlr_pointer_from_input_device(mouse))); const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(mouse));
setupMouse(PMOUSE); setupMouse(PMOUSE);
Debug::log(LOG, "New mouse created, pointer WLR: {:x}", (uintptr_t)mouse); Debug::log(LOG, "New mouse created, pointer AQ: {:x}", (uintptr_t)mouse.get());
} }
void CInputManager::setupMouse(SP<IPointer> mauz) { void CInputManager::setupMouse(SP<IPointer> mauz) {
m_vHIDs.push_back(mauz); m_vHIDs.push_back(mauz);
try { try {
mauz->hlName = getNameForNewDevice(mauz->wlr()->base.name); mauz->hlName = getNameForNewDevice(mauz->deviceName);
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Mouse had no name???"); // logic error Debug::log(ERR, "Mouse had no name???"); // logic error
} }
if (wlr_input_device_is_libinput(&mauz->wlr()->base)) { if (mauz->aq() && mauz->aq()->getLibinputHandle()) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&mauz->wlr()->base); const auto LIBINPUTDEV = mauz->aq()->getLibinputHandle();
Debug::log(LOG, "New mouse has libinput sens {:.2f} ({:.2f}) with accel profile {} ({})", libinput_device_config_accel_get_speed(LIBINPUTDEV), Debug::log(LOG, "New mouse has libinput sens {:.2f} ({:.2f}) with accel profile {} ({})", libinput_device_config_accel_get_speed(LIBINPUTDEV),
libinput_device_config_accel_get_default_speed(LIBINPUTDEV), (int)libinput_device_config_accel_get_profile(LIBINPUTDEV), libinput_device_config_accel_get_default_speed(LIBINPUTDEV), (int)libinput_device_config_accel_get_profile(LIBINPUTDEV),
@ -1084,8 +1051,8 @@ void CInputManager::setPointerConfigs() {
} }
} }
if (wlr_input_device_is_libinput(&m->wlr()->base)) { if (m->aq() && m->aq()->getLibinputHandle()) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base); const auto LIBINPUTDEV = m->aq()->getLibinputHandle();
double touchw = 0, touchh = 0; double touchw = 0, touchh = 0;
const auto ISTOUCHPAD = libinput_device_has_capability(LIBINPUTDEV, LIBINPUT_DEVICE_CAP_POINTER) && const auto ISTOUCHPAD = libinput_device_has_capability(LIBINPUTDEV, LIBINPUT_DEVICE_CAP_POINTER) &&
@ -1225,16 +1192,14 @@ static void removeFromHIDs(WP<IHID> hid) {
} }
void CInputManager::destroyKeyboard(SP<IKeyboard> pKeyboard) { void CInputManager::destroyKeyboard(SP<IKeyboard> pKeyboard) {
if (pKeyboard->xkbTranslationState) Debug::log(LOG, "Keyboard at {:x} removed", (uintptr_t)pKeyboard.get());
xkb_state_unref(pKeyboard->xkbTranslationState);
pKeyboard->xkbTranslationState = nullptr;
std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; }); std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; });
if (m_vKeyboards.size() > 0) { if (m_vKeyboards.size() > 0) {
bool found = false; bool found = false;
for (auto& k : m_vKeyboards | std::views::reverse) { for (auto& k : m_vKeyboards | std::views::reverse) {
if (!k->wlr()) if (!k)
continue; continue;
g_pSeatManager->setKeyboard(k); g_pSeatManager->setKeyboard(k);
@ -1251,6 +1216,8 @@ void CInputManager::destroyKeyboard(SP<IKeyboard> pKeyboard) {
} }
void CInputManager::destroyPointer(SP<IPointer> mouse) { void CInputManager::destroyPointer(SP<IPointer> mouse) {
Debug::log(LOG, "Pointer at {:x} removed", (uintptr_t)mouse.get());
std::erase_if(m_vPointers, [mouse](const auto& other) { return other == mouse; }); std::erase_if(m_vPointers, [mouse](const auto& other) { return other == mouse; });
g_pSeatManager->setMouse(m_vPointers.size() > 0 ? m_vPointers.front() : nullptr); g_pSeatManager->setMouse(m_vPointers.size() > 0 ? m_vPointers.front() : nullptr);
@ -1297,20 +1264,7 @@ void CInputManager::updateKeyboardsLeds(SP<IKeyboard> pKeyboard) {
if (!pKeyboard) if (!pKeyboard)
return; return;
auto keyboard = pKeyboard->wlr(); pKeyboard->updateLEDs();
if (!keyboard || keyboard->xkb_state == nullptr)
return;
uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i]))
leds |= (1 << i);
}
for (auto& k : m_vKeyboards) {
k->updateLEDs(leds);
}
} }
void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) { void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) {
@ -1338,7 +1292,7 @@ void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) {
const auto IME = m_sIMERelay.m_pIME.lock(); const auto IME = m_sIMERelay.m_pIME.lock();
if (IME && IME->hasGrab() && !DISALLOWACTION) { if (IME && IME->hasGrab() && !DISALLOWACTION) {
IME->setKeyboard(pKeyboard->wlr()); IME->setKeyboard(pKeyboard);
IME->sendKey(e.timeMs, e.keycode, e.state); IME->sendKey(e.timeMs, e.keycode, e.state);
} else { } else {
g_pSeatManager->setKeyboard(pKeyboard); g_pSeatManager->setKeyboard(pKeyboard);
@ -1356,15 +1310,14 @@ void CInputManager::onKeyboardMod(SP<IKeyboard> pKeyboard) {
const bool DISALLOWACTION = pKeyboard->isVirtual() && shouldIgnoreVirtualKeyboard(pKeyboard); const bool DISALLOWACTION = pKeyboard->isVirtual() && shouldIgnoreVirtualKeyboard(pKeyboard);
const auto ALLMODS = accumulateModsFromAllKBs(); const auto ALLMODS = accumulateModsFromAllKBs();
const auto PWLRKB = pKeyboard->wlr();
auto MODS = PWLRKB->modifiers; auto MODS = pKeyboard->modifiersState;
MODS.depressed = ALLMODS; MODS.depressed = ALLMODS;
const auto IME = m_sIMERelay.m_pIME.lock(); const auto IME = m_sIMERelay.m_pIME.lock();
if (IME && IME->hasGrab() && !DISALLOWACTION) { if (IME && IME->hasGrab() && !DISALLOWACTION) {
IME->setKeyboard(PWLRKB); IME->setKeyboard(pKeyboard);
IME->sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); IME->sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group);
} else { } else {
g_pSeatManager->setKeyboard(pKeyboard); g_pSeatManager->setKeyboard(pKeyboard);
@ -1373,12 +1326,12 @@ void CInputManager::onKeyboardMod(SP<IKeyboard> pKeyboard) {
updateKeyboardsLeds(pKeyboard); updateKeyboardsLeds(pKeyboard);
if (PWLRKB->modifiers.group != pKeyboard->activeLayout) { if (pKeyboard->modifiersState.group != pKeyboard->activeLayout) {
pKeyboard->activeLayout = PWLRKB->modifiers.group; pKeyboard->activeLayout = pKeyboard->modifiersState.group;
const auto LAYOUT = pKeyboard->getActiveLayout(); const auto LAYOUT = pKeyboard->getActiveLayout();
pKeyboard->updateXKBTranslationState(); Debug::log(LOG, "LAYOUT CHANGED TO {} GROUP {}", LAYOUT, MODS.group);
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->hlName + "," + LAYOUT}); g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->hlName + "," + LAYOUT});
EMIT_HOOK_EVENT("activeLayout", (std::vector<std::any>{pKeyboard, LAYOUT})); EMIT_HOOK_EVENT("activeLayout", (std::vector<std::any>{pKeyboard, LAYOUT}));
@ -1488,10 +1441,10 @@ uint32_t CInputManager::accumulateModsFromAllKBs() {
if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb)) if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb))
continue; continue;
if (!kb->enabled || !kb->wlr()) if (!kb->enabled)
continue; continue;
finalMask |= wlr_keyboard_get_modifiers(kb->wlr()); finalMask |= kb->getModifiers();
} }
return finalMask; return finalMask;
@ -1507,12 +1460,12 @@ void CInputManager::disableAllKeyboards(bool virt) {
} }
} }
void CInputManager::newTouchDevice(wlr_input_device* pDevice) { void CInputManager::newTouchDevice(SP<Aquamarine::ITouch> pDevice) {
const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(wlr_touch_from_input_device(pDevice))); const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(pDevice));
m_vHIDs.push_back(PNEWDEV); m_vHIDs.push_back(PNEWDEV);
try { try {
PNEWDEV->hlName = getNameForNewDevice(pDevice->name); PNEWDEV->hlName = getNameForNewDevice(PNEWDEV->deviceName);
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Touch Device had no name???"); // logic error Debug::log(ERR, "Touch Device had no name???"); // logic error
} }
@ -1535,9 +1488,9 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
} }
void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) { void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
auto setConfig = [&](SP<ITouch> PTOUCHDEV) -> void { auto setConfig = [](SP<ITouch> PTOUCHDEV) -> void {
if (wlr_input_device_is_libinput(&PTOUCHDEV->wlr()->base)) { if (PTOUCHDEV->aq() && PTOUCHDEV->aq()->getLibinputHandle()) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&PTOUCHDEV->wlr()->base); const auto LIBINPUTDEV = PTOUCHDEV->aq()->getLibinputHandle();
const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->hlName, "enabled", "input:touchdevice:enabled"); const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->hlName, "enabled", "input:touchdevice:enabled");
const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
@ -1553,11 +1506,12 @@ void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
bool bound = !output.empty() && output != STRVAL_EMPTY; bool bound = !output.empty() && output != STRVAL_EMPTY;
const bool AUTODETECT = output == "[[Auto]]"; const bool AUTODETECT = output == "[[Auto]]";
if (!bound && AUTODETECT) { if (!bound && AUTODETECT) {
const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name; // FIXME:
if (DEFAULTOUTPUT) { // const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name;
output = DEFAULTOUTPUT; // if (DEFAULTOUTPUT) {
bound = true; // output = DEFAULTOUTPUT;
} // bound = true;
// }
} }
PTOUCHDEV->boundOutput = bound ? output : ""; PTOUCHDEV->boundOutput = bound ? output : "";
const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr; const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr;
@ -1581,9 +1535,9 @@ void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
void CInputManager::setTabletConfigs() { void CInputManager::setTabletConfigs() {
for (auto& t : m_vTablets) { for (auto& t : m_vTablets) {
if (wlr_input_device_is_libinput(&t->wlr()->base)) { if (t->aq()->getLibinputHandle()) {
const auto NAME = t->hlName; const auto NAME = t->hlName;
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&t->wlr()->base); const auto LIBINPUTDEV = t->aq()->getLibinputHandle();
const auto RELINPUT = g_pConfigManager->getDeviceInt(NAME, "relative_input", "input:tablet:relative_input"); const auto RELINPUT = g_pConfigManager->getDeviceInt(NAME, "relative_input", "input:tablet:relative_input");
t->relativeInput = RELINPUT; t->relativeInput = RELINPUT;
@ -1611,52 +1565,37 @@ void CInputManager::setTabletConfigs() {
const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(NAME, "active_area_size", "input:tablet:active_area_size"); const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(NAME, "active_area_size", "input:tablet:active_area_size");
const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(NAME, "active_area_position", "input:tablet:active_area_position"); const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(NAME, "active_area_position", "input:tablet:active_area_position");
if (ACTIVE_AREA_SIZE.x != 0 || ACTIVE_AREA_SIZE.y != 0) { if (ACTIVE_AREA_SIZE.x != 0 || ACTIVE_AREA_SIZE.y != 0) {
t->activeArea = CBox{ACTIVE_AREA_POS.x / t->wlr()->width_mm, ACTIVE_AREA_POS.y / t->wlr()->height_mm, (ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t->wlr()->width_mm, t->activeArea = CBox{ACTIVE_AREA_POS.x / t->aq()->physicalSize.x, ACTIVE_AREA_POS.y / t->aq()->physicalSize.y,
(ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t->wlr()->height_mm}; (ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t->aq()->physicalSize.x, (ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t->aq()->physicalSize.y};
} }
} }
} }
} }
void CInputManager::newSwitch(wlr_input_device* pDevice) { void CInputManager::newSwitch(SP<Aquamarine::ISwitch> pDevice) {
const auto PNEWDEV = &m_lSwitches.emplace_back(); const auto PNEWDEV = &m_lSwitches.emplace_back();
PNEWDEV->pWlrDevice = pDevice; PNEWDEV->pDevice = pDevice;
Debug::log(LOG, "New switch with name \"{}\" added", pDevice->name); Debug::log(LOG, "New switch with name \"{}\" added", pDevice->getName());
PNEWDEV->hyprListener_destroy.initCallback( PNEWDEV->listeners.destroy = pDevice->events.destroy.registerListener([this, PNEWDEV](std::any d) { destroySwitch(PNEWDEV); });
&pDevice->events.destroy, [&](void* owner, void* data) { destroySwitch((SSwitchDevice*)owner); }, PNEWDEV, "SwitchDevice");
const auto PSWITCH = wlr_switch_from_input_device(pDevice); PNEWDEV->listeners.fire = pDevice->events.fire.registerListener([PNEWDEV](std::any d) {
const auto NAME = PNEWDEV->pDevice->getName();
const auto E = std::any_cast<Aquamarine::ISwitch::SFireEvent>(d);
PNEWDEV->hyprListener_toggle.initCallback( Debug::log(LOG, "Switch {} fired, triggering binds.", NAME);
&PSWITCH->events.toggle,
[&](void* owner, void* data) {
const auto PDEVICE = (SSwitchDevice*)owner;
const auto NAME = std::string(PDEVICE->pWlrDevice->name);
const auto E = (wlr_switch_toggle_event*)data;
if (PDEVICE->status != -1 && PDEVICE->status == E->switch_state) g_pKeybindManager->onSwitchEvent(NAME);
return;
Debug::log(LOG, "Switch {} fired, triggering binds.", NAME); if (E.enable) {
Debug::log(LOG, "Switch {} turn on, triggering binds.", NAME);
g_pKeybindManager->onSwitchEvent(NAME); g_pKeybindManager->onSwitchOnEvent(NAME);
} else {
switch (E->switch_state) { Debug::log(LOG, "Switch {} turn off, triggering binds.", NAME);
case WLR_SWITCH_STATE_ON: g_pKeybindManager->onSwitchOffEvent(NAME);
Debug::log(LOG, "Switch {} turn on, triggering binds.", NAME); }
g_pKeybindManager->onSwitchOnEvent(NAME); });
break;
case WLR_SWITCH_STATE_OFF:
Debug::log(LOG, "Switch {} turn off, triggering binds.", NAME);
g_pKeybindManager->onSwitchOffEvent(NAME);
break;
}
PDEVICE->status = E->switch_state;
},
PNEWDEV, "SwitchDevice");
} }
void CInputManager::destroySwitch(SSwitchDevice* pDevice) { void CInputManager::destroySwitch(SSwitchDevice* pDevice) {

View file

@ -18,6 +18,14 @@ class CVirtualKeyboardV1Resource;
class CVirtualPointerV1Resource; class CVirtualPointerV1Resource;
class IKeyboard; class IKeyboard;
AQUAMARINE_FORWARD(IPointer);
AQUAMARINE_FORWARD(IKeyboard);
AQUAMARINE_FORWARD(ITouch);
AQUAMARINE_FORWARD(ISwitch);
AQUAMARINE_FORWARD(ITablet);
AQUAMARINE_FORWARD(ITabletTool);
AQUAMARINE_FORWARD(ITabletPad);
enum eClickBehaviorMode { enum eClickBehaviorMode {
CLICKMODE_DEFAULT = 0, CLICKMODE_DEFAULT = 0,
CLICKMODE_KILL CLICKMODE_KILL
@ -82,15 +90,14 @@ class CInputManager {
void onKeyboardKey(std::any, SP<IKeyboard>); void onKeyboardKey(std::any, SP<IKeyboard>);
void onKeyboardMod(SP<IKeyboard>); void onKeyboardMod(SP<IKeyboard>);
void newKeyboard(wlr_input_device*); void newKeyboard(SP<Aquamarine::IKeyboard>);
void newVirtualKeyboard(SP<CVirtualKeyboardV1Resource>); void newVirtualKeyboard(SP<CVirtualKeyboardV1Resource>);
void newMouse(wlr_input_device*); void newMouse(SP<Aquamarine::IPointer>);
void newVirtualMouse(SP<CVirtualPointerV1Resource>); void newVirtualMouse(SP<CVirtualPointerV1Resource>);
void newTouchDevice(wlr_input_device*); void newTouchDevice(SP<Aquamarine::ITouch>);
void newSwitch(wlr_input_device*); void newSwitch(SP<Aquamarine::ISwitch>);
void newTabletTool(wlr_tablet_tool*); void newTabletPad(SP<Aquamarine::ITabletPad>);
void newTabletPad(wlr_input_device*); void newTablet(SP<Aquamarine::ITablet>);
void newTablet(wlr_input_device*);
void destroyTouchDevice(SP<ITouch>); void destroyTouchDevice(SP<ITouch>);
void destroyKeyboard(SP<IKeyboard>); void destroyKeyboard(SP<IKeyboard>);
void destroyPointer(SP<IPointer>); void destroyPointer(SP<IPointer>);
@ -232,7 +239,7 @@ class CInputManager {
void mouseMoveUnified(uint32_t, bool refocus = false); void mouseMoveUnified(uint32_t, bool refocus = false);
SP<CTabletTool> ensureTabletToolPresent(wlr_tablet_tool*); SP<CTabletTool> ensureTabletToolPresent(SP<Aquamarine::ITabletTool>);
void applyConfigToKeyboard(SP<IKeyboard>); void applyConfigToKeyboard(SP<IKeyboard>);
@ -278,6 +285,14 @@ class CInputManager {
void restoreCursorIconToApp(); // no-op if restored void restoreCursorIconToApp(); // no-op if restored
// discrete scrolling emulation using v120 data
struct {
bool lastEventSign = 0;
bool lastEventAxis = 0;
uint32_t lastEventTime = 0;
uint32_t accumulatedScroll = 0;
} m_ScrollWheelState;
friend class CKeybindManager; friend class CKeybindManager;
friend class CWLSurface; friend class CWLSurface;
}; };

View file

@ -62,7 +62,7 @@ static void refocusTablet(SP<CTablet> tab, SP<CTabletTool> tool, bool motion = f
if (!motion) if (!motion)
return; return;
if (LASTHLSURFACE->constraint() && tool->wlr()->type != WLR_TABLET_TOOL_TYPE_MOUSE) { if (LASTHLSURFACE->constraint() && tool->aq()->type != Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE) {
// cursor logic will completely break here as the cursor will be locked. // cursor logic will completely break here as the cursor will be locked.
// let's just "map" the desired position to the constraint area. // let's just "map" the desired position to the constraint area.
@ -102,7 +102,7 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) {
Vector2D delta = {std::isnan(dx) ? 0.0 : dx, std::isnan(dy) ? 0.0 : dy}; Vector2D delta = {std::isnan(dx) ? 0.0 : dx, std::isnan(dy) ? 0.0 : dy};
switch (e.tool->type) { switch (e.tool->type) {
case WLR_TABLET_TOOL_TYPE_MOUSE: { case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE: {
g_pPointerManager->move(delta); g_pPointerManager->move(delta);
break; break;
} }
@ -205,12 +205,12 @@ void CInputManager::onTabletProximity(CTablet::SProximityEvent e) {
PROTO::idle->onActivity(); PROTO::idle->onActivity();
} }
void CInputManager::newTablet(wlr_input_device* pDevice) { void CInputManager::newTablet(SP<Aquamarine::ITablet> pDevice) {
const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(wlr_tablet_from_input_device(pDevice))); const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(pDevice));
m_vHIDs.push_back(PNEWTABLET); m_vHIDs.push_back(PNEWTABLET);
try { try {
PNEWTABLET->hlName = deviceNameToInternalString(pDevice->name); PNEWTABLET->hlName = deviceNameToInternalString(pDevice->getName());
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Tablet had no name???"); // logic error Debug::log(ERR, "Tablet had no name???"); // logic error
} }
@ -227,28 +227,32 @@ void CInputManager::newTablet(wlr_input_device* pDevice) {
setTabletConfigs(); setTabletConfigs();
} }
SP<CTabletTool> CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) { SP<CTabletTool> CInputManager::ensureTabletToolPresent(SP<Aquamarine::ITabletTool> pTool) {
if (pTool->data == nullptr) {
const auto PTOOL = m_vTabletTools.emplace_back(CTabletTool::create(pTool));
m_vHIDs.push_back(PTOOL);
PTOOL->events.destroy.registerStaticListener( for (auto& t : m_vTabletTools) {
[this](void* owner, std::any d) { if (t->aq() == pTool)
auto TOOL = ((CTabletTool*)owner)->self; return t;
destroyTabletTool(TOOL.lock());
},
PTOOL.get());
} }
return CTabletTool::fromWlr(pTool); const auto PTOOL = m_vTabletTools.emplace_back(CTabletTool::create(pTool));
m_vHIDs.push_back(PTOOL);
PTOOL->events.destroy.registerStaticListener(
[this](void* owner, std::any d) {
auto TOOL = ((CTabletTool*)owner)->self;
destroyTabletTool(TOOL.lock());
},
PTOOL.get());
return PTOOL;
} }
void CInputManager::newTabletPad(wlr_input_device* pDevice) { void CInputManager::newTabletPad(SP<Aquamarine::ITabletPad> pDevice) {
const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(wlr_tablet_pad_from_input_device(pDevice))); const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(pDevice));
m_vHIDs.push_back(PNEWPAD); m_vHIDs.push_back(PNEWPAD);
try { try {
PNEWPAD->hlName = deviceNameToInternalString(pDevice->name); PNEWPAD->hlName = deviceNameToInternalString(pDevice->getName());
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Pad had no name???"); // logic error Debug::log(ERR, "Pad had no name???"); // logic error
} }
@ -259,7 +263,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) {
destroyTabletPad(PAD.lock()); destroyTabletPad(PAD.lock());
}, PNEWPAD.get()); }, PNEWPAD.get());
PNEWPAD->padEvents.button.registerStaticListener([this](void* owner, std::any e) { PNEWPAD->padEvents.button.registerStaticListener([](void* owner, std::any e) {
const auto E = std::any_cast<CTabletPad::SButtonEvent>(e); const auto E = std::any_cast<CTabletPad::SButtonEvent>(e);
const auto PPAD = ((CTabletPad*)owner)->self.lock(); const auto PPAD = ((CTabletPad*)owner)->self.lock();
@ -267,26 +271,25 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) {
PROTO::tablet->buttonPad(PPAD, E.button, E.timeMs, E.down); PROTO::tablet->buttonPad(PPAD, E.button, E.timeMs, E.down);
}, PNEWPAD.get()); }, PNEWPAD.get());
PNEWPAD->padEvents.strip.registerStaticListener([this](void* owner, std::any e) { PNEWPAD->padEvents.strip.registerStaticListener([](void* owner, std::any e) {
const auto E = std::any_cast<CTabletPad::SStripEvent>(e); const auto E = std::any_cast<CTabletPad::SStripEvent>(e);
const auto PPAD = ((CTabletPad*)owner)->self.lock(); const auto PPAD = ((CTabletPad*)owner)->self.lock();
PROTO::tablet->strip(PPAD, E.strip, E.position, E.finger, E.timeMs); PROTO::tablet->strip(PPAD, E.strip, E.position, E.finger, E.timeMs);
}, PNEWPAD.get()); }, PNEWPAD.get());
PNEWPAD->padEvents.ring.registerStaticListener([this](void* owner, std::any e) { PNEWPAD->padEvents.ring.registerStaticListener([](void* owner, std::any e) {
const auto E = std::any_cast<CTabletPad::SRingEvent>(e); const auto E = std::any_cast<CTabletPad::SRingEvent>(e);
const auto PPAD = ((CTabletPad*)owner)->self.lock(); const auto PPAD = ((CTabletPad*)owner)->self.lock();
PROTO::tablet->ring(PPAD, E.ring, E.position, E.finger, E.timeMs); PROTO::tablet->ring(PPAD, E.ring, E.position, E.finger, E.timeMs);
}, PNEWPAD.get()); }, PNEWPAD.get());
PNEWPAD->padEvents.attach.registerStaticListener([this](void* owner, std::any e) { PNEWPAD->padEvents.attach.registerStaticListener([](void* owner, std::any e) {
const auto PPAD = ((CTabletPad*)owner)->self.lock(); const auto PPAD = ((CTabletPad*)owner)->self.lock();
const auto TOOL = std::any_cast<SP<CTabletTool>>(e); const auto TOOL = std::any_cast<SP<CTabletTool>>(e);
PPAD->parent = TOOL; PPAD->parent = TOOL;
}, PNEWPAD.get()); }, PNEWPAD.get());
// clang-format on // clang-format on
} }

View file

@ -41,14 +41,11 @@ void CTextInput::initCallbacks() {
g_pInputManager->m_sIMERelay.removeTextInput(this); g_pInputManager->m_sIMERelay.removeTextInput(this);
}); });
} else { } else {
hyprListener_textInputEnable.initCallback( hyprListener_textInputEnable.initCallback(&pV1Input->sEnable, [this](void* owner, void* data) { onEnabled(); }, this, "textInput");
&pV1Input->sEnable, [this](void* owner, void* data) { onEnabled(); }, this, "textInput");
hyprListener_textInputCommit.initCallback( hyprListener_textInputCommit.initCallback(&pV1Input->sCommit, [this](void* owner, void* data) { onCommit(); }, this, "textInput");
&pV1Input->sCommit, [this](void* owner, void* data) { onCommit(); }, this, "textInput");
hyprListener_textInputDisable.initCallback( hyprListener_textInputDisable.initCallback(&pV1Input->sDisable, [this](void* owner, void* data) { onDisabled(); }, this, "textInput");
&pV1Input->sDisable, [this](void* owner, void* data) { onDisabled(); }, this, "textInput");
hyprListener_textInputDestroy.initCallback( hyprListener_textInputDestroy.initCallback(
&pV1Input->sDestroy, &pV1Input->sDestroy,

View file

@ -6,13 +6,15 @@
#include "../SeatManager.hpp" #include "../SeatManager.hpp"
void CInputManager::onTouchDown(ITouch::SDownEvent e) { void CInputManager::onTouchDown(ITouch::SDownEvent e) {
m_bLastInputTouch = true;
static auto PSWIPETOUCH = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch"); static auto PSWIPETOUCH = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch");
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out"); static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData();
// TODO: WORKSPACERULE.gapsOut.value_or() // TODO: WORKSPACERULE.gapsOut.value_or()
auto gapsOut = *PGAPSOUT; auto gapsOut = *PGAPSOUT;
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size"); static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_invert"); static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch_invert");
EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e); EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e);
auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : ""); auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : "");
@ -54,8 +56,6 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) {
} }
} }
m_bLastInputTouch = true;
m_sTouchData.touchFocusWindow = m_pFoundWindowToFocus; m_sTouchData.touchFocusWindow = m_pFoundWindowToFocus;
m_sTouchData.touchFocusSurface = m_pFoundSurfaceToFocus; m_sTouchData.touchFocusSurface = m_pFoundSurfaceToFocus;
m_sTouchData.touchFocusLS = m_pFoundLSToFocus; m_sTouchData.touchFocusLS = m_pFoundLSToFocus;
@ -83,6 +83,8 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) {
} }
void CInputManager::onTouchUp(ITouch::SUpEvent e) { void CInputManager::onTouchUp(ITouch::SUpEvent e) {
m_bLastInputTouch = true;
EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e); EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e);
if (m_sActiveSwipe.pWorkspaceBegin) { if (m_sActiveSwipe.pWorkspaceBegin) {
// If there was a swipe from this finger, end it. // If there was a swipe from this finger, end it.
@ -96,6 +98,8 @@ void CInputManager::onTouchUp(ITouch::SUpEvent e) {
} }
void CInputManager::onTouchMove(ITouch::SMotionEvent e) { void CInputManager::onTouchMove(ITouch::SMotionEvent e) {
m_bLastInputTouch = true;
EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e); EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e);
if (m_sActiveSwipe.pWorkspaceBegin) { if (m_sActiveSwipe.pWorkspaceBegin) {
// Do nothing if this is using a different finger. // Do nothing if this is using a different finger.
@ -103,7 +107,7 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) {
return; return;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_invert"); static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch_invert");
static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance"); static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance");
const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX);
// Handle the workspace swipe if there is one // Handle the workspace swipe if there is one

View file

@ -2,18 +2,19 @@ globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
src = globber.stdout().strip().split('\n') src = globber.stdout().strip().split('\n')
executable('Hyprland', src, executable('Hyprland', src,
cpp_args: ['-DWLR_USE_UNSTABLE'],
link_args: '-rdynamic', link_args: '-rdynamic',
cpp_pch: 'pch/pch.hpp', cpp_pch: 'pch/pch.hpp',
dependencies: [ dependencies: [
server_protos, server_protos,
dependency('aquamarine'),
dependency('gbm'),
dependency('xcursor'),
dependency('wayland-server'), dependency('wayland-server'),
dependency('wayland-client'), dependency('wayland-client'),
wlroots.get_variable('wlroots'),
dependency('cairo'), dependency('cairo'),
dependency('hyprcursor'), dependency('hyprcursor', version: '>=0.1.7'),
dependency('hyprlang', version: '>= 0.3.2'), dependency('hyprlang', version: '>= 0.3.2'),
dependency('hyprutils', version: '>= 0.1.1'), dependency('hyprutils', version: '>= 0.2.0'),
dependency('libdrm'), dependency('libdrm'),
dependency('egl'), dependency('egl'),
dependency('xkbcommon'), dependency('xkbcommon'),

View file

@ -2,6 +2,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../debug/HyprCtl.hpp" #include "../debug/HyprCtl.hpp"
#include <dlfcn.h> #include <dlfcn.h>
#include <filesystem>
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/sysctl.h> #include <sys/sysctl.h>

View file

@ -87,7 +87,7 @@ void CAlphaModifierProtocol::destroyModifier(CAlphaModifier* modifier) {
void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> 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()) { 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); LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface.get());
pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present"); pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present");
return; return;
} }
@ -100,4 +100,4 @@ void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id,
m_mAlphaModifiers.erase(surface); m_mAlphaModifiers.erase(surface);
return; return;
} }
} }

View file

@ -1,48 +1,9 @@
#include "CursorShape.hpp" #include "CursorShape.hpp"
#include <algorithm> #include <algorithm>
#include "../helpers/CursorShapes.hpp"
#define LOGM PROTO::cursorShape->protoLog #define LOGM PROTO::cursorShape->protoLog
// clang-format off
constexpr const char* SHAPE_NAMES[] = {
"invalid",
"default",
"context-menu",
"help",
"pointer",
"progress",
"wait",
"cell",
"crosshair",
"text",
"vertical-text",
"alias",
"copy",
"move",
"no-drop",
"not-allowed",
"grab",
"grabbing",
"e-resize",
"n-resize",
"ne-resize",
"nw-resize",
"s-resize",
"se-resize",
"sw-resize",
"w-resize",
"ew-resize",
"ns-resize",
"nesw-resize",
"nwse-resize",
"col-resize",
"row-resize",
"all-scroll",
"zoom-in",
"zoom-out",
};
// clang-format on
CCursorShapeProtocol::CCursorShapeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { CCursorShapeProtocol::CCursorShapeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
; ;
} }
@ -82,7 +43,7 @@ void CCursorShapeProtocol::createCursorShapeDevice(CWpCursorShapeManagerV1* pMgr
} }
void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t serial, wpCursorShapeDeviceV1Shape shape) { void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t serial, wpCursorShapeDeviceV1Shape shape) {
if ((uint32_t)shape == 0 || (uint32_t)shape > sizeof(SHAPE_NAMES)) { if ((uint32_t)shape == 0 || (uint32_t)shape > CURSOR_SHAPE_NAMES.size()) {
pMgr->error(WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE, "The shape is invalid"); pMgr->error(WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE, "The shape is invalid");
return; return;
} }
@ -90,7 +51,7 @@ void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t ser
SSetShapeEvent event; SSetShapeEvent event;
event.pMgr = pMgr; event.pMgr = pMgr;
event.shape = shape; event.shape = shape;
event.shapeName = SHAPE_NAMES[shape]; event.shapeName = CURSOR_SHAPE_NAMES.at(shape);
events.setShape.emit(event); events.setShape.emit(event);
} }

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