mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-22 16:05:58 +01:00
Merge branch 'hyprwm:main' into main
This commit is contained in:
commit
750d976e06
172 changed files with 6987 additions and 5235 deletions
6
.github/actions/setup_base/action.yml
vendored
6
.github/actions/setup_base/action.yml
vendored
|
@ -34,6 +34,7 @@ runs:
|
|||
libglvnd \
|
||||
libinput \
|
||||
libliftoff \
|
||||
libxcursor \
|
||||
libxcvt \
|
||||
libxfont2 \
|
||||
libxkbcommon \
|
||||
|
@ -73,6 +74,11 @@ runs:
|
|||
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
|
||||
|
||||
- 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
|
||||
shell: bash
|
||||
if: inputs.INSTALL_XORG_PKGS == 'true'
|
||||
|
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -7,6 +7,9 @@ cmake_install.cmake
|
|||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
CPackConfig.cmake
|
||||
CPackSourceConfig.cmake
|
||||
hyprland.pc
|
||||
_deps
|
||||
|
||||
build/
|
||||
|
@ -15,6 +18,9 @@ result*
|
|||
/.idea/
|
||||
.envrc
|
||||
.cache
|
||||
.direnv
|
||||
/.cmake/
|
||||
/.worktree/
|
||||
|
||||
*.o
|
||||
protocols/*.c*
|
||||
|
@ -31,5 +37,3 @@ gmon.out
|
|||
PKGBUILD
|
||||
|
||||
src/version.h
|
||||
|
||||
.direnv
|
||||
|
|
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -7,7 +7,3 @@
|
|||
[submodule "subprojects/tracy"]
|
||||
path = subprojects/tracy
|
||||
url = https://github.com/wolfpld/tracy
|
||||
[submodule "subprojects/wlroots-hyprland"]
|
||||
path = subprojects/wlroots-hyprland
|
||||
url = https://github.com/hyprwm/wlroots-hyprland
|
||||
ignore = dirty
|
||||
|
|
464
CMakeLists.txt
464
CMakeLists.txt
|
@ -1,17 +1,16 @@
|
|||
cmake_minimum_required(VERSION 3.27)
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(ExternalProject)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Get version
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/props.json PROPS)
|
||||
string(JSON VER GET ${PROPS} version)
|
||||
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
|
||||
string(STRIP ${VER_RAW} VER)
|
||||
|
||||
project(Hyprland
|
||||
DESCRIPTION "A Modern C++ Wayland Compositor"
|
||||
VERSION ${VER}
|
||||
)
|
||||
project(
|
||||
Hyprland
|
||||
DESCRIPTION "A Modern C++ Wayland Compositor"
|
||||
VERSION ${VER})
|
||||
|
||||
set(HYPRLAND_VERSION ${VER})
|
||||
set(PREFIX ${CMAKE_INSTALL_PREFIX})
|
||||
|
@ -22,49 +21,32 @@ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
|
|||
|
||||
message(STATUS "Gathering git info")
|
||||
|
||||
# Get git info
|
||||
# hash and branch
|
||||
execute_process(
|
||||
COMMAND ./scripts/generateVersion.sh
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
# Get git info hash and branch
|
||||
execute_process(COMMAND ./scripts/generateVersion.sh
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
|
||||
# udis
|
||||
add_subdirectory("subprojects/udis86")
|
||||
|
||||
# wlroots
|
||||
message(STATUS "Setting up wlroots")
|
||||
|
||||
if(CMAKE_BUILD_TYPE)
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
|
||||
if(BUILDTYPE_LOWER STREQUAL "release")
|
||||
# Pass.
|
||||
elseif(BUILDTYPE_LOWER STREQUAL "debug")
|
||||
# Pass.
|
||||
elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
|
||||
set(BUILDTYPE_LOWER "debugoptimized")
|
||||
elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
|
||||
set(BUILDTYPE_LOWER "minsize")
|
||||
elseif(BUILDTYPE_LOWER STREQUAL "none")
|
||||
set(BUILDTYPE_LOWER "plain")
|
||||
else()
|
||||
set(BUILDTYPE_LOWER "release")
|
||||
endif()
|
||||
else()
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
|
||||
if(BUILDTYPE_LOWER STREQUAL "release")
|
||||
# Pass.
|
||||
elseif(BUILDTYPE_LOWER STREQUAL "debug")
|
||||
# Pass.
|
||||
elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
|
||||
set(BUILDTYPE_LOWER "debugoptimized")
|
||||
elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
|
||||
set(BUILDTYPE_LOWER "minsize")
|
||||
elseif(BUILDTYPE_LOWER STREQUAL "none")
|
||||
set(BUILDTYPE_LOWER "plain")
|
||||
else()
|
||||
set(BUILDTYPE_LOWER "release")
|
||||
endif()
|
||||
else()
|
||||
set(BUILDTYPE_LOWER "release")
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
message(STATUS "Configuring Hyprland in Debug with CMake")
|
||||
add_compile_definitions(HYPRLAND_DEBUG)
|
||||
message(STATUS "Configuring Hyprland in Debug with CMake")
|
||||
add_compile_definitions(HYPRLAND_DEBUG)
|
||||
else()
|
||||
add_compile_options(-O3)
|
||||
message(STATUS "Configuring Hyprland in Release with CMake")
|
||||
add_compile_options(-O3)
|
||||
message(STATUS "Configuring Hyprland in Release with CMake")
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
.
|
||||
"src/"
|
||||
"subprojects/wlroots-hyprland/include/"
|
||||
"subprojects/wlroots-hyprland/build/include/"
|
||||
"subprojects/udis86/"
|
||||
"protocols/")
|
||||
include_directories(. "src/" "subprojects/udis86/" "protocols/")
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
add_compile_definitions(WLR_USE_UNSTABLE)
|
||||
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value
|
||||
-Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith
|
||||
-fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=)
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-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_EXPORT_COMPILE_COMMANDS TRUE)
|
||||
|
@ -102,19 +83,39 @@ message(STATUS "Checking deps...")
|
|||
find_package(Threads REQUIRED)
|
||||
|
||||
if(LEGACY_RENDERER)
|
||||
set(GLES_VERSION "GLES2")
|
||||
set(GLES_VERSION "GLES2")
|
||||
else()
|
||||
set(GLES_VERSION "GLES3")
|
||||
set(GLES_VERSION "GLES3")
|
||||
endif()
|
||||
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
||||
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET
|
||||
xkbcommon uuid
|
||||
wayland-server wayland-client wayland-cursor wayland-protocols
|
||||
cairo pango pangocairo pixman-1
|
||||
libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm
|
||||
hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.5
|
||||
)
|
||||
pkg_check_modules(
|
||||
deps
|
||||
REQUIRED
|
||||
IMPORTED_TARGET
|
||||
aquamarine
|
||||
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)
|
||||
|
||||
|
@ -122,85 +123,97 @@ file(GLOB_RECURSE SRCFILES "src/*.cpp")
|
|||
|
||||
set(TRACY_CPP_FILES "")
|
||||
if(USE_TRACY)
|
||||
set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
|
||||
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
|
||||
set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
|
||||
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
|
||||
endif()
|
||||
|
||||
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
|
||||
add_dependencies(Hyprland wlroots-hyprland)
|
||||
|
||||
set(USE_GPROF ON)
|
||||
|
||||
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)
|
||||
message(STATUS "Enabling ASan")
|
||||
if(WITH_ASAN)
|
||||
message(STATUS "Enabling ASan")
|
||||
|
||||
target_link_libraries(Hyprland asan)
|
||||
target_compile_options(Hyprland PUBLIC -fsanitize=address)
|
||||
target_link_libraries(Hyprland asan)
|
||||
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()
|
||||
|
||||
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()
|
||||
|
||||
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()
|
||||
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()
|
||||
|
||||
check_include_file("execinfo.h" EXECINFOH)
|
||||
if(EXECINFOH)
|
||||
message(STATUS "Configuration supports execinfo")
|
||||
add_compile_definitions(HAS_EXECINFO)
|
||||
message(STATUS "Configuration supports execinfo")
|
||||
add_compile_definitions(HAS_EXECINFO)
|
||||
endif()
|
||||
|
||||
include(CheckLibraryExists)
|
||||
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
|
||||
if(HAVE_LIBEXECINFO)
|
||||
target_link_libraries(Hyprland execinfo)
|
||||
target_link_libraries(Hyprland execinfo)
|
||||
endif()
|
||||
|
||||
check_include_file("sys/timerfd.h" HAS_TIMERFD)
|
||||
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
|
||||
if(NOT HAS_TIMERFD AND epoll_FOUND)
|
||||
target_link_libraries(Hyprland PkgConfig::epoll)
|
||||
target_link_libraries(Hyprland PkgConfig::epoll)
|
||||
endif()
|
||||
|
||||
if(LEGACY_RENDERER)
|
||||
message(STATUS "Using the legacy GLES2 renderer!")
|
||||
add_compile_definitions(LEGACY_RENDERER)
|
||||
message(STATUS "Using the legacy GLES2 renderer!")
|
||||
add_compile_definitions(LEGACY_RENDERER)
|
||||
endif()
|
||||
|
||||
if(NO_XWAYLAND)
|
||||
message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
|
||||
add_compile_definitions(NO_XWAYLAND)
|
||||
message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
|
||||
add_compile_definitions(NO_XWAYLAND)
|
||||
else()
|
||||
message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
|
||||
pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh xcb-errors)
|
||||
target_link_libraries(Hyprland PkgConfig::xdeps)
|
||||
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)
|
||||
target_link_libraries(Hyprland PkgConfig::xdeps)
|
||||
endif()
|
||||
|
||||
if(NO_SYSTEMD)
|
||||
message(STATUS "SYSTEMD support is disabled...")
|
||||
message(STATUS "SYSTEMD support is disabled...")
|
||||
else()
|
||||
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
|
||||
add_compile_definitions(USES_SYSTEMD)
|
||||
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
|
||||
add_compile_definitions(USES_SYSTEMD)
|
||||
endif()
|
||||
|
||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||
|
@ -209,7 +222,8 @@ include(CPack)
|
|||
|
||||
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")
|
||||
|
||||
|
@ -219,103 +233,114 @@ target_link_libraries(Hyprland rt PkgConfig::deps)
|
|||
add_custom_target(generate-protocol-headers)
|
||||
|
||||
function(protocol protoPath protoName external)
|
||||
if (external)
|
||||
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
|
||||
else()
|
||||
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
|
||||
endif()
|
||||
if(external)
|
||||
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
|
||||
else()
|
||||
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h
|
||||
COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c
|
||||
COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c)
|
||||
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h
|
||||
COMMAND ${WaylandScanner} server-header ${path}
|
||||
protocols/${protoName}-protocol.h
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c
|
||||
COMMAND ${WaylandScanner} private-code ${path}
|
||||
protocols/${protoName}-protocol.c
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(
|
||||
Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h
|
||||
${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c)
|
||||
target_sources(generate-protocol-headers
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h)
|
||||
endfunction()
|
||||
|
||||
function(protocolNew protoPath protoName external)
|
||||
if (external)
|
||||
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
|
||||
else()
|
||||
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
|
||||
${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
|
||||
COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
target_sources(Hyprland PRIVATE protocols/${protoName}.cpp protocols/${protoName}.hpp)
|
||||
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
|
||||
function(protocolnew protoPath protoName external)
|
||||
if(external)
|
||||
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
|
||||
else()
|
||||
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
|
||||
${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
|
||||
COMMAND hyprwayland-scanner ${path}/${protoName}.xml
|
||||
${CMAKE_SOURCE_DIR}/protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(Hyprland PRIVATE protocols/${protoName}.cpp
|
||||
protocols/${protoName}.hpp)
|
||||
target_sources(generate-protocol-headers
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
|
||||
endfunction()
|
||||
function(protocolWayland)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
|
||||
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
|
||||
COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
|
||||
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
|
||||
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
|
||||
COMMAND hyprwayland-scanner --wayland-enums
|
||||
${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
|
||||
target_sources(generate-protocol-headers
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
|
||||
endfunction()
|
||||
|
||||
target_link_libraries(Hyprland
|
||||
${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a
|
||||
OpenGL::EGL
|
||||
OpenGL::GL
|
||||
Threads::Threads
|
||||
libudis86
|
||||
uuid
|
||||
)
|
||||
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads
|
||||
libudis86 uuid)
|
||||
|
||||
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true)
|
||||
protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true)
|
||||
protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true)
|
||||
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
|
||||
protocol(
|
||||
"subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml"
|
||||
"hyprland-global-shortcuts-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)
|
||||
protocol(
|
||||
"unstable/text-input/text-input-unstable-v1.xml"
|
||||
"text-input-unstable-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
|
||||
add_subdirectory(hyprctl)
|
||||
|
@ -324,12 +349,12 @@ add_subdirectory(hyprpm)
|
|||
# binary and symlink
|
||||
install(TARGETS Hyprland)
|
||||
|
||||
install(CODE "execute_process( \
|
||||
install(
|
||||
CODE "execute_process( \
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink \
|
||||
${CMAKE_INSTALL_BINDIR}/Hyprland \
|
||||
${CMAKE_INSTALL_BINDIR}/hyprland
|
||||
)"
|
||||
)
|
||||
${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
|
||||
${CMAKE_INSTALL_FULL_BINDIR}/hyprland
|
||||
)")
|
||||
|
||||
# session file
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
|
||||
|
@ -337,8 +362,7 @@ install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
|
|||
|
||||
# wallpapers
|
||||
file(GLOB_RECURSE WALLPAPERS "assets/wall*")
|
||||
install(FILES ${WALLPAPERS}
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland)
|
||||
install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland)
|
||||
|
||||
# default config
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf
|
||||
|
@ -350,34 +374,24 @@ install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf
|
|||
|
||||
# man pages
|
||||
file(GLOB_RECURSE MANPAGES "docs/*.1")
|
||||
install(FILES ${MANPAGES}
|
||||
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
|
||||
install(FILES ${MANPAGES} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
|
||||
# pkgconfig entry
|
||||
install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc
|
||||
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
|
||||
set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols")
|
||||
install(DIRECTORY ${HEADERS_PROTO}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
|
||||
FILES_MATCHING PATTERN "*.h*")
|
||||
install(
|
||||
DIRECTORY ${HEADERS_PROTO}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h*")
|
||||
|
||||
# hyprland headers
|
||||
set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
install(DIRECTORY ${HEADERS_SRC}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
|
||||
FILES_MATCHING PATTERN "*.h*")
|
||||
install(
|
||||
DIRECTORY ${HEADERS_SRC}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h*")
|
||||
|
|
6
Makefile
6
Makefile
|
@ -27,7 +27,6 @@ nopch:
|
|||
clear:
|
||||
rm -rf build
|
||||
rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp
|
||||
rm -rf ./subprojects/wlroots-hyprland/build
|
||||
|
||||
all:
|
||||
$(MAKE) clear
|
||||
|
@ -50,14 +49,11 @@ installheaders:
|
|||
rm -fr ${PREFIX}/include/hyprland
|
||||
mkdir -p ${PREFIX}/include/hyprland
|
||||
mkdir -p ${PREFIX}/include/hyprland/protocols
|
||||
mkdir -p ${PREFIX}/include/hyprland/wlr
|
||||
mkdir -p ${PREFIX}/share/pkgconfig
|
||||
|
||||
cmake --build ./build --config Release --target generate-protocol-headers
|
||||
|
||||
find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
|
||||
cd subprojects/wlroots-hyprland/include/wlr && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../..
|
||||
cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../..
|
||||
cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols
|
||||
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
|
||||
|
@ -88,7 +84,7 @@ asan:
|
|||
@pidof Hyprland > /dev/null && exit 1 || echo ""
|
||||
|
||||
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"
|
||||
@read patchvar
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
|
||||
<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,
|
||||
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>
|
||||
|
||||
|
@ -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
|
||||
- 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
|
||||
- Powerful plugin support
|
||||
- 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
|
||||
- Fully dynamic workspaces
|
||||
- Two built-in layouts and more available as plugins
|
||||
- Uses forked wlroots with QoL patches
|
||||
- Global keybinds passed to your apps of choice
|
||||
- Tiling/pseudotiling/floating/fullscreen windows
|
||||
- Special workspaces (scratchpads)
|
||||
|
@ -86,7 +85,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
|
|||
|
||||
<br>
|
||||
|
||||
**[wlroots]** - *For their amazing library*
|
||||
**[wlroots]** - *For powering Hyprland in the past*
|
||||
|
||||
**[tinywl]** - *For showing how 2 do stuff*
|
||||
|
||||
|
|
1
VERSION
Normal file
1
VERSION
Normal file
|
@ -0,0 +1 @@
|
|||
0.41.2
|
|
@ -32,6 +32,12 @@ Show command usage.
|
|||
.TP
|
||||
\f[B]-c\f[R], \f[B]--config\f[R]
|
||||
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
|
||||
.TP
|
||||
Submit bug reports and request features online at:
|
||||
|
|
|
@ -41,6 +41,12 @@ OPTIONS
|
|||
**-c**, **--config**
|
||||
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
|
||||
====
|
||||
|
||||
|
|
66
flake.lock
66
flake.lock
|
@ -1,5 +1,34 @@
|
|||
{
|
||||
"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": {
|
||||
"inputs": {
|
||||
"hyprlang": [
|
||||
|
@ -13,11 +42,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1720108799,
|
||||
"narHash": "sha256-AxRkTJlbB8r7aG6gvc7IaLhc2T9TO4/8uqanKRxukBQ=",
|
||||
"lastModified": 1721330371,
|
||||
"narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprcursor",
|
||||
"rev": "a5c0d57325c5f0814c39110a70ca19c070ae9486",
|
||||
"rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -64,11 +93,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1720381373,
|
||||
"narHash": "sha256-lyC/EZdHULsaAKVryK11lgHY9u6pXr7qR4irnxNWC7k=",
|
||||
"lastModified": 1721324361,
|
||||
"narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "5df0174fd09de4ac5475233d65ffc703e89b82eb",
|
||||
"rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -87,11 +116,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1720203444,
|
||||
"narHash": "sha256-lq2dPPPcwMHTLsFrQ2pRp4c2LwDZWoqzSyjuPdeJCP4=",
|
||||
"lastModified": 1721324102,
|
||||
"narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "a8c3a135701a7b64db0a88ec353a392f402d2a87",
|
||||
"rev": "962582a090bc233c4de9d9897f46794280288989",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -110,11 +139,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1720215857,
|
||||
"narHash": "sha256-JPdL+Qul+jEueAn8CARfcWP83eJgwkhMejQYfDvrgvU=",
|
||||
"lastModified": 1721324119,
|
||||
"narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprwayland-scanner",
|
||||
"rev": "d5fa094ca27e0039be5e94c0a80ae433145af8bb",
|
||||
"rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -125,11 +154,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1720031269,
|
||||
"narHash": "sha256-rwz8NJZV+387rnWpTYcXaRNvzUSnnF9aHONoJIYmiUQ=",
|
||||
"lastModified": 1721924956,
|
||||
"narHash": "sha256-Sb1jlyRO+N8jBXEX9Pg9Z1Qb8Bw9QyOgLDNMEpmjZ2M=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9f4128e00b0ae8ec65918efeba59db998750ead6",
|
||||
"rev": "5ad6a14c6bf098e98800b091668718c336effc95",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -141,6 +170,7 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"aquamarine": "aquamarine",
|
||||
"hyprcursor": "hyprcursor",
|
||||
"hyprlang": "hyprlang",
|
||||
"hyprutils": "hyprutils",
|
||||
|
@ -179,11 +209,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1720194466,
|
||||
"narHash": "sha256-Rizg9efi6ue95zOp0MeIV2ZedNo+5U9G2l6yirgBUnA=",
|
||||
"lastModified": 1721755049,
|
||||
"narHash": "sha256-O17b38bQnmfxv7It3OnVYx7fp1seEdI7xxnw5vJFv30=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "b9b97e5ba23fe7bd5fa4df54696102e8aa863cf6",
|
||||
"rev": "5555f467f68ce7cdf1060991c24263073b95e9da",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
14
flake.nix
14
flake.nix
|
@ -7,6 +7,14 @@
|
|||
# <https://github.com/nix-systems/nix-systems>
|
||||
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 = {
|
||||
url = "github:hyprwm/hyprcursor";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
@ -90,9 +98,13 @@
|
|||
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
||||
} {
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [expat libxml2];
|
||||
nativeBuildInputs = with pkgsFor.${system}; [
|
||||
expat
|
||||
libxml2
|
||||
];
|
||||
hardeningDisable = ["fortify"];
|
||||
inputsFrom = [pkgsFor.${system}.hyprland];
|
||||
packages = [pkgsFor.${system}.clang-tools];
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -4,4 +4,4 @@ Name: Hyprland
|
|||
URL: https://github.com/hyprwm/Hyprland
|
||||
Description: Hyprland header files
|
||||
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
|
||||
|
|
|
@ -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";
|
||||
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;
|
||||
|
@ -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");
|
||||
|
||||
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
|
||||
headers = "";
|
||||
|
||||
if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland"))
|
||||
if (PATH.ends_with("protocols"))
|
||||
continue;
|
||||
|
||||
verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h";
|
||||
|
@ -493,11 +502,6 @@ bool CPluginManager::updateHeaders(bool force) {
|
|||
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.m_iSteps = 4;
|
||||
progress.m_szCurrentMessage = "Installing sources";
|
||||
|
|
13
meson.build
13
meson.build
|
@ -1,5 +1,5 @@
|
|||
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 : [
|
||||
'warning_level=2',
|
||||
'default_library=static',
|
||||
|
@ -24,8 +24,6 @@ if cpp_compiler.check_header('execinfo.h')
|
|||
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||
endif
|
||||
|
||||
wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2'])
|
||||
have_xwlr = wlroots.get_variable('features').get('xwayland')
|
||||
xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
||||
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
|
||||
xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland'))
|
||||
|
@ -38,12 +36,7 @@ cmake = import('cmake')
|
|||
udis = cmake.subproject('udis86')
|
||||
udis86 = udis.dependency('libudis86')
|
||||
|
||||
if get_option('xwayland').enabled() and not have_xwlr
|
||||
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
|
||||
if not xcb_dep.found()
|
||||
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
||||
endif
|
||||
|
||||
|
@ -86,5 +79,5 @@ import('pkgconfig').generate(
|
|||
url: 'https://github.com/hyprwm/Hyprland',
|
||||
description: 'Hyprland header files',
|
||||
install_dir: pkg_install_dir,
|
||||
subdirs: ['', 'hyprland/protocols', 'hyprland', 'hyprland/wlr'],
|
||||
subdirs: ['', 'hyprland/protocols', 'hyprland'],
|
||||
)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
makeWrapper,
|
||||
cmake,
|
||||
ninja,
|
||||
aquamarine,
|
||||
binutils,
|
||||
cairo,
|
||||
expat,
|
||||
|
@ -30,7 +31,6 @@
|
|||
libuuid,
|
||||
libxkbcommon,
|
||||
mesa,
|
||||
meson,
|
||||
pango,
|
||||
pciutils,
|
||||
pcre2,
|
||||
|
@ -89,7 +89,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
|||
jq
|
||||
makeWrapper
|
||||
cmake
|
||||
meson # for wlroots
|
||||
ninja
|
||||
pkg-config
|
||||
python3 # for udis86
|
||||
|
@ -104,6 +103,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
|||
|
||||
buildInputs = lib.concatLists [
|
||||
[
|
||||
aquamarine
|
||||
cairo
|
||||
expat
|
||||
fribidi
|
||||
|
@ -112,10 +112,12 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
|||
hyprcursor
|
||||
hyprlang
|
||||
hyprutils
|
||||
libGL
|
||||
libdrm
|
||||
libdatrie
|
||||
libdisplay-info
|
||||
libdrm
|
||||
libGL
|
||||
libinput
|
||||
libliftoff
|
||||
libselinux
|
||||
libsepol
|
||||
libthai
|
||||
|
@ -125,17 +127,15 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
|||
pango
|
||||
pciutils
|
||||
pcre2
|
||||
seatd
|
||||
tomlplusplus
|
||||
wayland
|
||||
wayland-protocols
|
||||
# for wlroots
|
||||
seatd
|
||||
libdisplay-info
|
||||
libliftoff
|
||||
]
|
||||
(lib.optionals stdenv.hostPlatform.isMusl [libexecinfo])
|
||||
(lib.optionals enableXWayland [
|
||||
xorg.libxcb
|
||||
xorg.libXcursor
|
||||
xorg.libXdmcp
|
||||
xorg.xcbutil
|
||||
xorg.xcbutilerrors
|
||||
|
|
|
@ -3,13 +3,12 @@
|
|||
lib,
|
||||
inputs,
|
||||
}: let
|
||||
props = builtins.fromJSON (builtins.readFile ../props.json);
|
||||
|
||||
mkDate = longDate: (lib.concatStringsSep "-" [
|
||||
(builtins.substring 0 4 longDate)
|
||||
(builtins.substring 4 2 longDate)
|
||||
(builtins.substring 6 2 longDate)
|
||||
]);
|
||||
version = lib.removeSuffix "\n" (builtins.readFile ../VERSION);
|
||||
in {
|
||||
# Contains what a user is most likely to care about:
|
||||
# Hyprland itself, XDPH and the Share Picker.
|
||||
|
@ -21,11 +20,11 @@ in {
|
|||
# Packages for variations of Hyprland, dependencies included.
|
||||
hyprland-packages = lib.composeManyExtensions [
|
||||
# Dependencies
|
||||
inputs.aquamarine.overlays.default
|
||||
inputs.hyprcursor.overlays.default
|
||||
inputs.hyprlang.overlays.default
|
||||
inputs.hyprutils.overlays.default
|
||||
inputs.hyprwayland-scanner.overlays.default
|
||||
self.overlays.xwayland
|
||||
|
||||
# Hyprland packages themselves
|
||||
(final: prev: let
|
||||
|
@ -33,7 +32,7 @@ in {
|
|||
in {
|
||||
hyprland = final.callPackage ./default.nix {
|
||||
stdenv = final.gcc13Stdenv;
|
||||
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
|
||||
version = "${version}+date=${date}_${self.shortRev or "dirty"}";
|
||||
commit = self.rev or "";
|
||||
inherit date;
|
||||
};
|
||||
|
@ -63,14 +62,4 @@ in {
|
|||
hyprland-extras = lib.composeManyExtensions [
|
||||
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
|
||||
'';
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"version": "0.41.2"
|
||||
}
|
|
@ -25,8 +25,6 @@ hyprwayland_scanner = find_program(
|
|||
|
||||
protocols = [
|
||||
[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']
|
||||
]
|
||||
|
||||
|
@ -42,6 +40,8 @@ new_protocols = [
|
|||
['wlr-layer-shell-unstable-v1.xml'],
|
||||
['wayland-drm.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'],
|
||||
[wl_protocol_dir, 'staging/tearing-control/tearing-control-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, 'stable/viewporter/viewporter.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 = []
|
||||
|
@ -113,7 +115,8 @@ foreach p : wl_server_protos
|
|||
wl_server_protos_gen += custom_target(
|
||||
p.underscorify(),
|
||||
input: p,
|
||||
install: false,
|
||||
install: true,
|
||||
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
|
||||
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
|
||||
command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'],
|
||||
)
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
#include "managers/PointerManager.hpp"
|
||||
#include "managers/SeatManager.hpp"
|
||||
#include "managers/eventLoop/EventLoopManager.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include <random>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <unordered_set>
|
||||
#include "debug/HyprCtl.hpp"
|
||||
#include "debug/CrashReporter.hpp"
|
||||
|
@ -22,20 +25,25 @@
|
|||
#include "protocols/core/Compositor.hpp"
|
||||
#include "protocols/core/Subcompositor.hpp"
|
||||
#include "desktop/LayerSurface.hpp"
|
||||
#include "render/Renderer.hpp"
|
||||
#include "xwayland/XWayland.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Aquamarine;
|
||||
|
||||
int handleCritSignal(int signo, void* data) {
|
||||
Debug::log(LOG, "Hyprland received signal {}", signo);
|
||||
|
||||
if (signo == SIGTERM || signo == SIGINT || signo == SIGKILL)
|
||||
g_pCompositor->cleanup();
|
||||
g_pCompositor->stopCompositor();
|
||||
|
||||
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() {
|
||||
if (!getrlimit(RLIMIT_NOFILE, &m_sOriginalNofile))
|
||||
Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", m_sOriginalNofile.rlim_cur, m_sOriginalNofile.rlim_max);
|
||||
|
@ -168,7 +193,8 @@ CCompositor::CCompositor() {
|
|||
}
|
||||
|
||||
CCompositor::~CCompositor() {
|
||||
cleanup();
|
||||
if (!m_bIsShuttingDown)
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void CCompositor::setRandomSplash() {
|
||||
|
@ -179,7 +205,10 @@ void CCompositor::setRandomSplash() {
|
|||
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();
|
||||
|
||||
|
@ -199,102 +228,187 @@ void CCompositor::initServer() {
|
|||
if (envEnabled("HYPRLAND_TRACE"))
|
||||
Debug::trace = true;
|
||||
|
||||
wlr_log_init(WLR_INFO, NULL);
|
||||
Aquamarine::SBackendOptions options;
|
||||
options.logFunction = aqLog;
|
||||
|
||||
if (envEnabled("HYPRLAND_LOG_WLR"))
|
||||
wlr_log_init(WLR_DEBUG, Debug::wlrLog);
|
||||
else
|
||||
wlr_log_init(WLR_ERROR, Debug::wlrLog);
|
||||
std::vector<Aquamarine::SBackendImplementationOptions> implementations;
|
||||
Aquamarine::SBackendImplementationOptions option;
|
||||
option.backendType = Aquamarine::eBackendType::AQ_BACKEND_HEADLESS;
|
||||
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) {
|
||||
Debug::log(CRIT, "m_sWLRBackend was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
|
||||
throwError("wlr_backend_autocreate() failed!");
|
||||
if (!m_pAqBackend) {
|
||||
Debug::log(CRIT,
|
||||
"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;
|
||||
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);
|
||||
// TODO: headless only
|
||||
|
||||
if (isHeadlessOnly) {
|
||||
m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); // TODO: remove this, it's barely needed now.
|
||||
initAllSignals();
|
||||
|
||||
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 {
|
||||
m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend);
|
||||
if (m_iDRMFD < 0) {
|
||||
Debug::log(CRIT, "Couldn't query the DRM FD!");
|
||||
throwError("wlr_backend_get_drm_fd() failed!");
|
||||
// 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;
|
||||
} 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) {
|
||||
Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
|
||||
throwError("wlr_gles2_renderer_create_with_drm_fd() failed!");
|
||||
if (m_szWLDisplaySocket.empty()) {
|
||||
Debug::log(WARN, "All candidates failed, trying wl_display_add_socket_auto");
|
||||
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_sWLRAllocator) {
|
||||
Debug::log(CRIT, "m_sWLRAllocator was NULL!");
|
||||
throwError("wlr_allocator_autocreate() failed!");
|
||||
if (m_szWLDisplaySocket.empty()) {
|
||||
Debug::log(CRIT, "m_szWLDisplaySocket NULL!");
|
||||
throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)");
|
||||
}
|
||||
|
||||
m_sWLREGL = wlr_gles2_renderer_get_egl(m_sWLRRenderer);
|
||||
|
||||
if (!m_sWLREGL) {
|
||||
Debug::log(CRIT, "m_sWLREGL was NULL!");
|
||||
throwError("wlr_gles2_renderer_get_egl() failed!");
|
||||
}
|
||||
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
|
||||
setenv("XDG_SESSION_TYPE", "wayland", 1);
|
||||
|
||||
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);
|
||||
|
||||
for (auto& o : pendingOutputs) {
|
||||
onNewMonitor(o);
|
||||
}
|
||||
pendingOutputs.clear();
|
||||
}
|
||||
|
||||
void CCompositor::initAllSignals() {
|
||||
addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend");
|
||||
addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend");
|
||||
addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer");
|
||||
m_pAqBackend->events.newOutput.registerStaticListener(
|
||||
[this](void* p, std::any data) {
|
||||
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)
|
||||
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
|
||||
m_pAqBackend->events.newPointer.registerStaticListener(
|
||||
[](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)
|
||||
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
|
||||
m_pAqBackend->events.newKeyboard.registerStaticListener(
|
||||
[](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() {
|
||||
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() {
|
||||
|
@ -308,7 +422,7 @@ void CCompositor::cleanEnvironment() {
|
|||
unsetenv("XDG_BACKEND");
|
||||
unsetenv("XDG_CURRENT_DESKTOP");
|
||||
|
||||
if (m_sWLRSession) {
|
||||
if (m_pAqBackend->hasSession()) {
|
||||
const auto CMD =
|
||||
#ifdef USES_SYSTEMD
|
||||
"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() {
|
||||
if (!m_sWLDisplay || m_bIsShuttingDown)
|
||||
if (!m_sWLDisplay)
|
||||
return;
|
||||
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
|
@ -351,7 +473,7 @@ void CCompositor::cleanup() {
|
|||
for (auto& m : m_vMonitors) {
|
||||
g_pHyprOpenGL->destroyMonitorResources(m.get());
|
||||
|
||||
wlr_output_state_set_enabled(m->state.wlr(), false);
|
||||
m->output->state->setEnabled(false);
|
||||
m->state.commit();
|
||||
}
|
||||
|
||||
|
@ -388,25 +510,14 @@ void CCompositor::cleanup() {
|
|||
g_pHyprCtl.reset();
|
||||
g_pEventLoopManager.reset();
|
||||
|
||||
if (m_sWLRRenderer)
|
||||
wlr_renderer_destroy(m_sWLRRenderer);
|
||||
|
||||
if (m_sWLRAllocator)
|
||||
wlr_allocator_destroy(m_sWLRAllocator);
|
||||
|
||||
if (m_sWLRBackend)
|
||||
wlr_backend_destroy(m_sWLRBackend);
|
||||
if (m_pAqBackend)
|
||||
m_pAqBackend.reset();
|
||||
|
||||
if (m_critSigSource)
|
||||
wl_event_source_remove(m_critSigSource);
|
||||
|
||||
wl_event_loop_destroy(m_sWLEventLoop);
|
||||
wl_display_terminate(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");
|
||||
// this frees all wayland resources, including sockets
|
||||
wl_display_destroy(m_sWLDisplay);
|
||||
}
|
||||
|
||||
void CCompositor::initManagers(eManagersInitStage stage) {
|
||||
|
@ -441,6 +552,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
|
|||
|
||||
Debug::log(LOG, "Creating the PointerManager!");
|
||||
g_pPointerManager = std::make_unique<CPointerManager>();
|
||||
|
||||
Debug::log(LOG, "Creating the EventManager!");
|
||||
g_pEventManager = std::make_unique<CEventManager>();
|
||||
} break;
|
||||
case STAGE_BASICINIT: {
|
||||
Debug::log(LOG, "Creating the CHyprOpenGLImpl!");
|
||||
|
@ -471,9 +585,6 @@ void CCompositor::initManagers(eManagersInitStage stage) {
|
|||
Debug::log(LOG, "Creating the SessionLockManager!");
|
||||
g_pSessionLockManager = std::make_unique<CSessionLockManager>();
|
||||
|
||||
Debug::log(LOG, "Creating the EventManager!");
|
||||
g_pEventManager = std::make_unique<CEventManager>();
|
||||
|
||||
Debug::log(LOG, "Creating the HyprDebugOverlay!");
|
||||
g_pDebugOverlay = std::make_unique<CHyprDebugOverlay>();
|
||||
|
||||
|
@ -516,57 +627,26 @@ void CCompositor::removeLockFile() {
|
|||
|
||||
void CCompositor::prepareFallbackOutput() {
|
||||
// create a backup monitor
|
||||
wlr_backend* headless = nullptr;
|
||||
wlr_multi_for_each_backend(
|
||||
m_sWLRBackend,
|
||||
[](wlr_backend* b, void* data) {
|
||||
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);
|
||||
SP<Aquamarine::IBackendImplementation> headless;
|
||||
for (auto& impl : m_pAqBackend->getImplementations()) {
|
||||
if (impl->type() == Aquamarine::AQ_BACKEND_HEADLESS) {
|
||||
headless = impl;
|
||||
break;
|
||||
} else {
|
||||
Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_szWLDisplaySocket.empty()) {
|
||||
Debug::log(WARN, "All candidates failed, trying wl_display_add_socket_auto");
|
||||
const auto SOCKETSTR = wl_display_add_socket_auto(m_sWLDisplay);
|
||||
if (SOCKETSTR)
|
||||
m_szWLDisplaySocket = SOCKETSTR;
|
||||
if (!headless) {
|
||||
Debug::log(WARN, "No headless in prepareFallbackOutput?!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_szWLDisplaySocket.empty()) {
|
||||
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);
|
||||
headless->createOutput();
|
||||
}
|
||||
|
||||
void CCompositor::startCompositor() {
|
||||
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 =
|
||||
#ifdef USES_SYSTEMD
|
||||
"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);
|
||||
|
||||
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();
|
||||
|
||||
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) {
|
||||
const auto BB = w->getWindowBoxUnified(properties);
|
||||
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()))
|
||||
return w;
|
||||
|
||||
|
@ -731,7 +805,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
|
|||
continue;
|
||||
|
||||
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)) {
|
||||
// OR windows should add focus to parent
|
||||
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
|
||||
|
@ -784,7 +858,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
|
|||
continue;
|
||||
|
||||
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))
|
||||
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};
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
}
|
||||
|
||||
CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
|
||||
CMonitor* CCompositor::getMonitorFromOutput(SP<Aquamarine::IOutput> out) {
|
||||
for (auto& m : m_vMonitors) {
|
||||
if (m->output == out) {
|
||||
return m.get();
|
||||
|
@ -881,7 +955,7 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) {
|
||||
CMonitor* CCompositor::getRealMonitorFromOutput(SP<Aquamarine::IOutput> out) {
|
||||
for (auto& m : m_vRealMonitors) {
|
||||
if (m->output == out) {
|
||||
return m.get();
|
||||
|
@ -940,7 +1014,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface
|
|||
return;
|
||||
}
|
||||
|
||||
if (pWindow->m_sAdditionalConfigData.noFocus) {
|
||||
if (pWindow->m_sWindowData.noFocus.valueOrDefault()) {
|
||||
Debug::log(LOG, "Ignoring focus to nofocus window!");
|
||||
return;
|
||||
}
|
||||
|
@ -1030,7 +1104,7 @@ void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindo
|
|||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1053,9 +1127,9 @@ void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindo
|
|||
g_pSeatManager->setKeyboardFocus(pSurface);
|
||||
|
||||
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
|
||||
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);
|
||||
m_pLastFocus = pSurface;
|
||||
|
@ -1114,15 +1188,10 @@ SP<CWLSurfaceResource> CCompositor::vectorToLayerSurface(const Vector2D& pos, st
|
|||
}
|
||||
|
||||
PHLWINDOW CCompositor::getWindowFromSurface(SP<CWLSurfaceResource> pSurface) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->m_bFadingOut)
|
||||
continue;
|
||||
if (!pSurface || !pSurface->hlSurface)
|
||||
return nullptr;
|
||||
|
||||
if (w->m_pWLSurface->resource() == pSurface)
|
||||
return w;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return pSurface->hlSurface->getWindow();
|
||||
}
|
||||
|
||||
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())
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1587,7 +1656,7 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
|
|||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1608,7 +1677,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
|
|||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1616,7 +1685,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
|
|||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1804,13 +1873,11 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
|
|||
if (pWindow == m_pLastWindow) {
|
||||
const auto* const ACTIVECOLOR =
|
||||
!pWindow->m_sGroupData.pNextWindow.lock() ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
|
||||
setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying().m_vColors.empty() ? *ACTIVECOLOR :
|
||||
pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying());
|
||||
setBorderColor(pWindow->m_sWindowData.activeBorderColor.valueOr(*ACTIVECOLOR));
|
||||
} else {
|
||||
const auto* const INACTIVECOLOR = !pWindow->m_sGroupData.pNextWindow.lock() ? (!pWindow->m_sGroupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) :
|
||||
(GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
|
||||
setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying().m_vColors.empty() ? *INACTIVECOLOR :
|
||||
pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying());
|
||||
setBorderColor(pWindow->m_sWindowData.inactiveBorderColor.valueOr(*INACTIVECOLOR));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1821,23 +1888,16 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
|
|||
// opacity
|
||||
const auto PWORKSPACE = pWindow->m_pWorkspace;
|
||||
if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
|
||||
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() != -1 ?
|
||||
(pWindow->m_sSpecialRenderData.alphaFullscreenOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() :
|
||||
pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() * *PFULLSCREENALPHA) :
|
||||
*PFULLSCREENALPHA;
|
||||
pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA);
|
||||
} else {
|
||||
if (pWindow == m_pLastWindow)
|
||||
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alpha.toUnderlying() :
|
||||
pWindow->m_sSpecialRenderData.alpha.toUnderlying() * *PACTIVEALPHA;
|
||||
pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alpha.valueOrDefault().applyAlpha(*PACTIVEALPHA);
|
||||
else
|
||||
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() != -1 ?
|
||||
(pWindow->m_sSpecialRenderData.alphaInactiveOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() :
|
||||
pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() * *PINACTIVEALPHA) :
|
||||
*PINACTIVEALPHA;
|
||||
pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaInactive.valueOrDefault().applyAlpha(*PINACTIVEALPHA);
|
||||
}
|
||||
|
||||
// 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;
|
||||
} else {
|
||||
pWindow->m_fDimPercent = *PDIMSTRENGTH;
|
||||
|
@ -2195,6 +2255,8 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
|
@ -2238,8 +2300,14 @@ void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMod
|
|||
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
|
||||
// DMAbuf stuff for direct scanout
|
||||
g_pHyprRenderer->setWindowScanoutMode(pWindow);
|
||||
// further updates require a monitor
|
||||
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);
|
||||
}
|
||||
|
@ -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 WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
|
||||
|
||||
|
@ -2276,12 +2344,12 @@ void CCompositor::updateWorkspaceSpecialRenderData(const int& id) {
|
|||
if (w->workspaceID() != id)
|
||||
continue;
|
||||
|
||||
w->updateSpecialRenderData(WORKSPACERULE);
|
||||
w->updateWindowData(WORKSPACERULE);
|
||||
}
|
||||
}
|
||||
|
||||
void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
|
||||
if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
|
||||
void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleFrameReason reason) {
|
||||
if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive)
|
||||
return;
|
||||
|
||||
if (!pMonitor->m_bEnabled)
|
||||
|
@ -2290,7 +2358,7 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
|
|||
if (pMonitor->renderingActive)
|
||||
pMonitor->pendingFrame = true;
|
||||
|
||||
wlr_output_schedule_frame(pMonitor->output);
|
||||
pMonitor->output->scheduleFrame(reason);
|
||||
}
|
||||
|
||||
PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) {
|
||||
|
@ -2767,7 +2835,7 @@ void CCompositor::setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, d
|
|||
|
||||
const auto PSURFACE = CWLSurface::fromResource(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;
|
||||
}
|
||||
|
||||
|
@ -2780,7 +2848,7 @@ void CCompositor::setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurfac
|
|||
|
||||
const auto PSURFACE = CWLSurface::fromResource(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;
|
||||
}
|
||||
|
||||
|
@ -2806,3 +2874,84 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) {
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#include "plugins/PluginSystem.hpp"
|
||||
#include "helpers/Watchdog.hpp"
|
||||
|
||||
#include <aquamarine/backend/Backend.hpp>
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
|
||||
class CWLSurfaceResource;
|
||||
|
||||
enum eManagersInitStage {
|
||||
|
@ -43,22 +46,11 @@ class CCompositor {
|
|||
CCompositor();
|
||||
~CCompositor();
|
||||
|
||||
// ------------------ WLR BASICS ------------------ //
|
||||
wl_display* m_sWLDisplay;
|
||||
wl_event_loop* m_sWLEventLoop;
|
||||
wlr_backend* m_sWLRBackend;
|
||||
wlr_session* m_sWLRSession;
|
||||
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;
|
||||
// ------------------------------------------------- //
|
||||
wl_display* m_sWLDisplay;
|
||||
wl_event_loop* m_sWLEventLoop;
|
||||
int m_iDRMFD = -1;
|
||||
bool m_bInitialized = false;
|
||||
SP<Aquamarine::CBackend> m_pAqBackend;
|
||||
|
||||
std::string m_szHyprTempDataRoot = "";
|
||||
|
||||
|
@ -77,8 +69,9 @@ class CCompositor {
|
|||
|
||||
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;
|
||||
|
||||
void initServer();
|
||||
void initServer(std::string socketName, int socketFd);
|
||||
void startCompositor();
|
||||
void stopCompositor();
|
||||
void cleanup();
|
||||
void createLockFile();
|
||||
void removeLockFile();
|
||||
|
@ -94,10 +87,9 @@ class CCompositor {
|
|||
bool m_bReadyToProcess = false;
|
||||
bool m_bSessionActive = true;
|
||||
bool m_bDPMSStateON = true;
|
||||
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
|
||||
bool m_bNextIsUnsafe = false; // because wlroots
|
||||
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
|
||||
bool m_bNextIsUnsafe = false;
|
||||
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
|
||||
bool m_bExitTriggered = false; // For exit dispatcher
|
||||
bool m_bIsShuttingDown = false;
|
||||
|
||||
// ------------------------------------------------- //
|
||||
|
@ -116,8 +108,8 @@ class CCompositor {
|
|||
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*);
|
||||
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
|
||||
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
|
||||
CMonitor* getMonitorFromOutput(wlr_output*);
|
||||
CMonitor* getRealMonitorFromOutput(wlr_output*);
|
||||
CMonitor* getMonitorFromOutput(SP<Aquamarine::IOutput>);
|
||||
CMonitor* getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
|
||||
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
|
||||
PHLWINDOW getWindowFromHandle(uint32_t);
|
||||
bool isWorkspaceVisible(PHLWORKSPACE);
|
||||
|
@ -127,7 +119,7 @@ class CCompositor {
|
|||
PHLWORKSPACE getWorkspaceByString(const std::string&);
|
||||
void sanityCheckWorkspaces();
|
||||
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 getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
|
||||
PHLWINDOW getUrgentWindow();
|
||||
|
@ -157,7 +149,7 @@ class CCompositor {
|
|||
void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID);
|
||||
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
|
||||
PHLWINDOW getX11Parent(PHLWINDOW);
|
||||
void scheduleFrameForMonitor(CMonitor*);
|
||||
void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
|
||||
void addToFadingOutSafe(PHLLS);
|
||||
void removeFromFadingOutSafe(PHLLS);
|
||||
void addToFadingOutSafe(PHLWINDOW);
|
||||
|
@ -182,6 +174,7 @@ class CCompositor {
|
|||
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
|
||||
void updateSuspendedStates();
|
||||
PHLWINDOW windowForCPointer(CWindow*);
|
||||
void onNewMonitor(SP<Aquamarine::IOutput> output);
|
||||
|
||||
std::string explicitConfigPath;
|
||||
|
||||
|
|
|
@ -20,11 +20,11 @@ class ICustomConfigValueData {
|
|||
|
||||
class CGradientValueData : public ICustomConfigValueData {
|
||||
public:
|
||||
CGradientValueData(){};
|
||||
CGradientValueData() {};
|
||||
CGradientValueData(CColor col) {
|
||||
m_vColors.push_back(col);
|
||||
};
|
||||
virtual ~CGradientValueData(){};
|
||||
virtual ~CGradientValueData() {};
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() {
|
||||
return CVD_TYPE_GRADIENT;
|
||||
|
@ -67,11 +67,11 @@ class CGradientValueData : public ICustomConfigValueData {
|
|||
|
||||
class CCssGapData : public ICustomConfigValueData {
|
||||
public:
|
||||
CCssGapData() : top(0), right(0), bottom(0), left(0){};
|
||||
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 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() : top(0), right(0), bottom(0), left(0) {};
|
||||
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 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) {};
|
||||
|
||||
/* Css like directions */
|
||||
int64_t top;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <hyprutils/path/Path.hpp>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
|
@ -23,6 +24,7 @@
|
|||
#include <ranges>
|
||||
#include <unordered_set>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <filesystem>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
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:background_color", Hyprlang::INT{0xff111111});
|
||||
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: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_factor", {1.f});
|
||||
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:disable_while_typing", Hyprlang::INT{1});
|
||||
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_use_r", 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: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:hide_on_key_press", Hyprlang::INT{0});
|
||||
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});
|
||||
|
||||
|
@ -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_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"});
|
||||
|
||||
m_pConfig->addConfigValue("experimental:explicit_sync", Hyprlang::INT{0});
|
||||
|
||||
// devices
|
||||
m_pConfig->addSpecialCategory("device", {"name"});
|
||||
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});
|
||||
}
|
||||
|
||||
std::string CConfigManager::getConfigDir() {
|
||||
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
|
||||
std::optional<std::string> CConfigManager::generateConfig(std::string configPath) {
|
||||
std::string parentPath = std::filesystem::path(configPath).parent_path();
|
||||
|
||||
if (xdgConfigHome && std::filesystem::path(xdgConfigHome).is_absolute())
|
||||
return xdgConfigHome;
|
||||
if (!std::filesystem::is_directory(parentPath)) {
|
||||
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)
|
||||
throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME is set in the environment. Cannot determine config directory.");
|
||||
if (!std::filesystem::exists(configPath))
|
||||
return "Config could not be generated.";
|
||||
|
||||
return home + std::string("/.config");
|
||||
return configPath;
|
||||
}
|
||||
|
||||
std::string CConfigManager::getMainConfigPath() {
|
||||
if (!g_pCompositor->explicitConfigPath.empty())
|
||||
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() {
|
||||
|
@ -743,32 +775,6 @@ void CConfigManager::setDefaultAnimationVars() {
|
|||
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() {
|
||||
m_dMonitorRules.clear();
|
||||
m_dWindowRules.clear();
|
||||
|
@ -846,7 +852,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
|
|||
if (w->inert())
|
||||
continue;
|
||||
g_pCompositor->updateWorkspaceWindows(w->m_iID);
|
||||
g_pCompositor->updateWorkspaceSpecialRenderData(w->m_iID);
|
||||
g_pCompositor->updateWorkspaceWindowData(w->m_iID);
|
||||
}
|
||||
|
||||
// Update window border colors
|
||||
|
@ -1060,14 +1066,14 @@ SWorkspaceRule CConfigManager::mergeWorkspaceRules(const SWorkspaceRule& rule1,
|
|||
mergedRule.gapsOut = rule2.gapsOut;
|
||||
if (rule2.borderSize.has_value())
|
||||
mergedRule.borderSize = rule2.borderSize;
|
||||
if (rule2.border.has_value())
|
||||
mergedRule.border = rule2.border;
|
||||
if (rule2.rounding.has_value())
|
||||
mergedRule.rounding = rule2.rounding;
|
||||
if (rule2.noBorder.has_value())
|
||||
mergedRule.noBorder = rule2.noBorder;
|
||||
if (rule2.noRounding.has_value())
|
||||
mergedRule.noRounding = rule2.noRounding;
|
||||
if (rule2.decorate.has_value())
|
||||
mergedRule.decorate = rule2.decorate;
|
||||
if (rule2.shadow.has_value())
|
||||
mergedRule.shadow = rule2.shadow;
|
||||
if (rule2.noShadow.has_value())
|
||||
mergedRule.noShadow = rule2.noShadow;
|
||||
if (rule2.onCreatedEmptyRunCmd.has_value())
|
||||
mergedRule.onCreatedEmptyRunCmd = rule2.onCreatedEmptyRunCmd;
|
||||
if (rule2.defaultName.has_value())
|
||||
|
@ -1286,7 +1292,7 @@ void CConfigManager::dispatchExecOnce() {
|
|||
return;
|
||||
|
||||
// update dbus env
|
||||
if (g_pCompositor->m_sWLRSession)
|
||||
if (g_pCompositor->m_pAqBackend->hasSession())
|
||||
handleRawExec("",
|
||||
#ifdef USES_SYSTEMD
|
||||
"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");
|
||||
|
||||
firstExecDispatched = true;
|
||||
isLaunchingExecOnce = true;
|
||||
|
||||
for (auto& c : firstExecRequests) {
|
||||
handleRawExec("", c);
|
||||
}
|
||||
|
||||
firstExecRequests.clear(); // free some kb of memory :P
|
||||
isLaunchingExecOnce = false;
|
||||
|
||||
// set input, fixes some certain issues
|
||||
g_pInputManager->setKeyboardLayout();
|
||||
|
@ -1411,7 +1419,8 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
|
|||
|
||||
if (USEVRR == 0) {
|
||||
if (m->vrrActive) {
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
|
||||
|
||||
m->output->state->setAdaptiveSync(false);
|
||||
|
||||
if (!m->state.commit())
|
||||
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
|
||||
|
@ -1420,11 +1429,11 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
|
|||
return;
|
||||
} else if (USEVRR == 1) {
|
||||
if (!m->vrrActive) {
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
|
||||
m->output->state->setAdaptiveSync(true);
|
||||
|
||||
if (!m->state.test()) {
|
||||
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())
|
||||
|
@ -1443,19 +1452,19 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
|
|||
|
||||
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
|
||||
|
||||
if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) {
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
|
||||
if (WORKSPACEFULL) {
|
||||
m->output->state->setAdaptiveSync(true);
|
||||
|
||||
if (!m->state.test()) {
|
||||
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())
|
||||
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) {
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
|
||||
} else if (!WORKSPACEFULL) {
|
||||
m->output->state->setAdaptiveSync(false);
|
||||
|
||||
if (!m->state.commit())
|
||||
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 multiKey = false;
|
||||
bool hasDescription = false;
|
||||
bool dontInhibit = false;
|
||||
const auto BINDARGS = command.substr(4);
|
||||
|
||||
for (auto& arg : BINDARGS) {
|
||||
|
@ -1999,6 +2009,8 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
|||
multiKey = true;
|
||||
} else if (arg == 'd') {
|
||||
hasDescription = true;
|
||||
} else if (arg == 'p') {
|
||||
dontInhibit = true;
|
||||
} else {
|
||||
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.";
|
||||
}
|
||||
|
||||
g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION,
|
||||
release, repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription});
|
||||
g_pKeybindManager->addKeybind(SKeybind{
|
||||
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 {};
|
||||
|
@ -2088,16 +2101,17 @@ std::optional<std::string> CConfigManager::handleUnbind(const std::string& comma
|
|||
|
||||
bool windowRuleValid(const std::string& RULE) {
|
||||
static const auto rules = std::unordered_set<std::string>{
|
||||
"dimaround", "fakefullscreen", "float", "focusonactivate", "forceinput", "forcergbx", "fullscreen", "immediate",
|
||||
"keepaspectratio", "maximize", "nearestneighbor", "noanim", "noblur", "noborder", "nodim", "nofocus",
|
||||
"noinitialfocus", "nomaxsize", "noshadow", "opaque", "pin", "stayfocused", "tile", "windowdance",
|
||||
"fakefullscreen", "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile",
|
||||
};
|
||||
static const auto rulesPrefix = std::vector<std::string>{
|
||||
"animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move",
|
||||
"opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray",
|
||||
};
|
||||
|
||||
return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); });
|
||||
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) {
|
||||
|
@ -2423,11 +2437,11 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
|
|||
wsRule.borderSize = std::stoi(rule.substr(delim + 11));
|
||||
} catch (...) { return "Error parsing workspace rule bordersize: {}", rule.substr(delim + 11); }
|
||||
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)
|
||||
wsRule.shadow = configStringToInt(rule.substr(delim + 7));
|
||||
wsRule.noShadow = !configStringToInt(rule.substr(delim + 7));
|
||||
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)
|
||||
wsRule.decorate = configStringToInt(rule.substr(delim + 9));
|
||||
else if ((delim = rule.find("monitor:")) != std::string::npos)
|
||||
|
|
|
@ -39,10 +39,10 @@ struct SWorkspaceRule {
|
|||
std::optional<CCssGapData> gapsIn;
|
||||
std::optional<CCssGapData> gapsOut;
|
||||
std::optional<int64_t> borderSize;
|
||||
std::optional<int> border;
|
||||
std::optional<int> rounding;
|
||||
std::optional<int> decorate;
|
||||
std::optional<int> shadow;
|
||||
std::optional<bool> decorate;
|
||||
std::optional<bool> noRounding;
|
||||
std::optional<bool> noBorder;
|
||||
std::optional<bool> noShadow;
|
||||
std::optional<std::string> onCreatedEmptyRunCmd;
|
||||
std::optional<std::string> defaultName;
|
||||
std::map<std::string, std::string> layoutopts;
|
||||
|
@ -101,7 +101,6 @@ class CConfigManager {
|
|||
void* const* getConfigValuePtr(const std::string&);
|
||||
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
|
||||
void onPluginLoadUnload(const std::string& name, bool load);
|
||||
static std::string getConfigDir();
|
||||
static std::string getMainConfigPath();
|
||||
const std::string getConfigString();
|
||||
|
||||
|
@ -130,9 +129,6 @@ class CConfigManager {
|
|||
void performMonitorReload();
|
||||
void appendMonitorRule(const SMonitorRule&);
|
||||
bool replaceMonitorRule(const SMonitorRule&);
|
||||
bool m_bWantsMonitorReload = false;
|
||||
bool m_bForceReload = false;
|
||||
bool m_bNoMonitorReload = false;
|
||||
void ensureMonitorStatus();
|
||||
void ensureVRR(CMonitor* pMonitor = nullptr);
|
||||
|
||||
|
@ -148,25 +144,55 @@ class CConfigManager {
|
|||
std::string getErrors();
|
||||
|
||||
// keywords
|
||||
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> handleMonitor(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> handleWindowRule(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleBezier(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> handleSubmap(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> handleEnv(const std::string&, const std::string&);
|
||||
std::optional<std::string> handlePlugin(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> handleMonitor(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> handleWindowRule(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleBezier(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> handleSubmap(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> handleEnv(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:
|
||||
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
|
||||
|
@ -200,14 +226,15 @@ class CConfigManager {
|
|||
std::string m_szConfigErrors = "";
|
||||
|
||||
// internal methods
|
||||
void setAnimForChildren(SAnimationPropertyConfig* const);
|
||||
void updateBlurredLS(const std::string&, const bool);
|
||||
void setDefaultAnimationVars();
|
||||
std::optional<std::string> resetHLConfig();
|
||||
std::optional<std::string> verifyConfigExists();
|
||||
void postConfigReload(const Hyprlang::CParseResult& result);
|
||||
void reload();
|
||||
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);
|
||||
void setAnimForChildren(SAnimationPropertyConfig* const);
|
||||
void updateBlurredLS(const std::string&, const bool);
|
||||
void setDefaultAnimationVars();
|
||||
std::optional<std::string> resetHLConfig();
|
||||
static std::optional<std::string> generateConfig(std::string configPath);
|
||||
static std::optional<std::string> verifyConfigExists();
|
||||
void postConfigReload(const Hyprlang::CParseResult& result);
|
||||
void reload();
|
||||
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CConfigManager> g_pConfigManager;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <filesystem>
|
||||
|
||||
#include "../plugins/PluginSystem.hpp"
|
||||
#include "../signal-safe.hpp"
|
||||
|
@ -104,7 +105,19 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
|||
finalCrashReport += GIT_COMMIT_HASH;
|
||||
finalCrashReport += "\nTag: ";
|
||||
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) {
|
||||
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/poll.h>
|
||||
#include <filesystem>
|
||||
#include <ranges>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
@ -20,6 +22,7 @@
|
|||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
|
||||
#include "../config/ConfigDataValues.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
@ -53,20 +56,15 @@ static std::string formatToString(uint32_t drmFormat) {
|
|||
static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) {
|
||||
std::string result;
|
||||
|
||||
if (!wl_list_empty(&pMonitor->output->modes)) {
|
||||
wlr_output_mode* mode;
|
||||
|
||||
wl_list_for_each(mode, &pMonitor->output->modes, link) {
|
||||
|
||||
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();
|
||||
for (auto& m : pMonitor->output->modes) {
|
||||
if (format == FORMAT_NORMAL)
|
||||
result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0);
|
||||
else
|
||||
result += std::format("\"{}x{}@{:.2f}Hz\",", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0);
|
||||
}
|
||||
|
||||
trimTrailingComma(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -75,8 +73,10 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
|
|||
if (!m->output || m->ID == -1ull)
|
||||
return "";
|
||||
|
||||
result += std::format(
|
||||
R"#({{
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
|
||||
result += std::format(
|
||||
R"#({{
|
||||
"id": {},
|
||||
"name": "{}",
|
||||
"description": "{}",
|
||||
|
@ -107,14 +107,27 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
|
|||
"currentFormat": "{}",
|
||||
"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->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)),
|
||||
m->activeSpecialWorkspaceID(), escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
|
||||
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
|
||||
(m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"),
|
||||
(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"),
|
||||
(m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
|
||||
|
||||
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make), escapeJSONStrings(m->output->model),
|
||||
escapeJSONStrings(m->output->serial), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
|
||||
m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(),
|
||||
escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
|
||||
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"),
|
||||
(m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"),
|
||||
(m->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;
|
||||
}
|
||||
|
||||
|
@ -144,16 +157,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
if (!m->output || m->ID == -1ull)
|
||||
continue;
|
||||
|
||||
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->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(),
|
||||
(!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""),
|
||||
(int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
|
||||
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED),
|
||||
m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
|
||||
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, (int)(m->output->state ? m->output->state->state().adaptiveSync : false),
|
||||
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) :
|
||||
"";
|
||||
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 rounding = (bool)(r.rounding) ? std::format(",\n \"rounding\": {}", boolToString(r.rounding.value())) : "";
|
||||
const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.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 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"#({{
|
||||
"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::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 border = std::format("\tborder: {}\n", (bool)(r.border) ? boolToString(r.border.value()) : "<unset>");
|
||||
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.rounding) ? boolToString(r.rounding.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.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 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,
|
||||
borderSize, border, rounding, decorate, shadow);
|
||||
|
@ -552,8 +565,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
"defaultSpeed": {:.5f}
|
||||
}},)#",
|
||||
(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)) :
|
||||
0.f);
|
||||
m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f);
|
||||
}
|
||||
|
||||
trimTrailingComma(result);
|
||||
|
@ -611,9 +623,8 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
R"#( {{
|
||||
"address": "0x{:x}",
|
||||
"type": "tabletTool",
|
||||
"belongsTo": "0x{:x}"
|
||||
}},)#",
|
||||
(uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0);
|
||||
(uintptr_t)d.get());
|
||||
}
|
||||
|
||||
trimTrailingComma(result);
|
||||
|
@ -641,7 +652,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
"address": "0x{:x}",
|
||||
"name": "{}"
|
||||
}},)#",
|
||||
(uintptr_t)&d, escapeJSONStrings(d.pWlrDevice ? d.pWlrDevice->name : ""));
|
||||
(uintptr_t)&d, escapeJSONStrings(d.pDevice ? d.pDevice->getName() : ""));
|
||||
}
|
||||
|
||||
trimTrailingComma(result);
|
||||
|
@ -654,9 +665,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
|
||||
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,
|
||||
(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)) :
|
||||
0.f));
|
||||
(m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f));
|
||||
}
|
||||
|
||||
result += "\n\nKeyboards:\n";
|
||||
|
@ -675,11 +684,11 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
}
|
||||
|
||||
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) {
|
||||
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";
|
||||
|
@ -691,7 +700,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
result += "\n\nSwitches:\n";
|
||||
|
||||
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())
|
||||
return "device not found";
|
||||
|
||||
const auto PWLRKEYBOARD = (*PKEYBOARD)->wlr();
|
||||
const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap);
|
||||
const auto KEEB = *PKEYBOARD;
|
||||
|
||||
const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap);
|
||||
xkb_layout_index_t activeLayout = 0;
|
||||
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;
|
||||
|
||||
activeLayout++;
|
||||
}
|
||||
|
||||
if (CMD == "next") {
|
||||
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked,
|
||||
activeLayout > LAYOUTS ? 0 : activeLayout + 1);
|
||||
} else if (CMD == "prev") {
|
||||
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked,
|
||||
activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
|
||||
} else {
|
||||
|
||||
if (CMD == "next")
|
||||
KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1);
|
||||
else if (CMD == "prev")
|
||||
KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
|
||||
else {
|
||||
int requestedLayout = 0;
|
||||
try {
|
||||
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);
|
||||
}
|
||||
|
||||
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";
|
||||
|
@ -1202,74 +1209,44 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
|
|||
const auto PROP = vars[2];
|
||||
const auto VAL = vars[3];
|
||||
|
||||
auto noFocus = PWINDOW->m_sAdditionalConfigData.noFocus;
|
||||
|
||||
bool lock = false;
|
||||
|
||||
if (request.ends_with("lock"))
|
||||
lock = true;
|
||||
bool noFocus = PWINDOW->m_sWindowData.noFocus.valueOrDefault();
|
||||
|
||||
try {
|
||||
if (PROP == "animationstyle") {
|
||||
PWINDOW->m_sAdditionalConfigData.animationStyle = VAL;
|
||||
} 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);
|
||||
PWINDOW->m_sWindowData.animationStyle = CWindowOverridableVar(VAL, PRIORITY_SET_PROP);
|
||||
} else if (PROP == "maxsize") {
|
||||
PWINDOW->m_sAdditionalConfigData.maxSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock);
|
||||
if (lock) {
|
||||
PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x),
|
||||
std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y));
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
|
||||
PWINDOW->setHidden(false);
|
||||
}
|
||||
PWINDOW->m_sWindowData.maxSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
|
||||
PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sWindowData.maxSize.value().x, PWINDOW->m_vRealSize.goal().x),
|
||||
std::min((double)PWINDOW->m_sWindowData.maxSize.value().y, PWINDOW->m_vRealSize.goal().y));
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
|
||||
PWINDOW->setHidden(false);
|
||||
} else if (PROP == "minsize") {
|
||||
PWINDOW->m_sAdditionalConfigData.minSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock);
|
||||
if (lock) {
|
||||
PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x),
|
||||
std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y));
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
|
||||
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);
|
||||
PWINDOW->m_sWindowData.minSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
|
||||
PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sWindowData.minSize.value().x, PWINDOW->m_vRealSize.goal().x),
|
||||
std::max((double)PWINDOW->m_sWindowData.minSize.value().y, PWINDOW->m_vRealSize.goal().y));
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
|
||||
PWINDOW->setHidden(false);
|
||||
} else if (PROP == "alpha") {
|
||||
PWINDOW->m_sSpecialRenderData.alpha.forceSetIgnoreLocked(std::stof(VAL), lock);
|
||||
} else if (PROP == "alphainactiveoverride") {
|
||||
PWINDOW->m_sSpecialRenderData.alphaInactiveOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
PWINDOW->m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alpha.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
|
||||
} else if (PROP == "alphainactive") {
|
||||
PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock);
|
||||
} else if (PROP == "alphafullscreenoverride") {
|
||||
PWINDOW->m_sSpecialRenderData.alphaFullscreenOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
PWINDOW->m_sWindowData.alphaInactive =
|
||||
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
|
||||
} 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") {
|
||||
CGradientValueData colorData = {};
|
||||
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];
|
||||
if (TOKEN.ends_with("deg"))
|
||||
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));
|
||||
|
||||
if (PROP == "activebordercolor")
|
||||
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(colorData, lock);
|
||||
PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
|
||||
else
|
||||
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(colorData, lock);
|
||||
} else if (PROP == "forcergbx") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
} else if (PROP == "bordersize") {
|
||||
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
} else if (PROP == "keepaspectratio") {
|
||||
PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
} else if (PROP == "immediate") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceTearing.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
} else if (PROP == "nearestneighbor") {
|
||||
PWINDOW->m_sAdditionalConfigData.nearestNeighbor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
|
||||
} else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) {
|
||||
auto pWindowDataElement = search->second(PWINDOW);
|
||||
if (VAL == "toggle")
|
||||
*pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP);
|
||||
else if (VAL == "unset")
|
||||
pWindowDataElement->unset(PRIORITY_SET_PROP);
|
||||
else
|
||||
*pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP);
|
||||
} else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) {
|
||||
if (VAL == "unset")
|
||||
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
|
||||
else
|
||||
*(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP);
|
||||
} else {
|
||||
return "prop not found";
|
||||
}
|
||||
|
@ -1300,7 +1280,7 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
|
|||
|
||||
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(PWINDOW);
|
||||
g_pCompositor->focusWindow(PLASTWINDOW);
|
||||
|
@ -1395,43 +1375,6 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request)
|
|||
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) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
|
@ -1440,15 +1383,36 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
|
|||
|
||||
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 (g_pCompositor->getMonitorFromName(vars[3]))
|
||||
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";
|
||||
|
||||
} else if (MODE == "destroy" || MODE == "remove") {
|
||||
|
@ -1460,7 +1424,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
|
|||
if (!PMONITOR->createdByUser)
|
||||
return "cannot remove a real display. Use the monitor keyword.";
|
||||
|
||||
wlr_output_destroy(PMONITOR->output);
|
||||
PMONITOR->output->destroy();
|
||||
}
|
||||
|
||||
return "ok";
|
||||
|
@ -1848,7 +1812,6 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
|||
}
|
||||
|
||||
void CHyprCtl::startHyprCtlSocket() {
|
||||
|
||||
m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
|
||||
if (m_iSocketFD < 0) {
|
||||
|
|
|
@ -10,30 +10,6 @@ void Debug::init(const std::string& IS) {
|
|||
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) {
|
||||
if (level == TRACE && !trace)
|
||||
return;
|
||||
|
|
|
@ -67,6 +67,4 @@ namespace Debug {
|
|||
|
||||
log(level, logMsg);
|
||||
}
|
||||
|
||||
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
|
||||
};
|
||||
|
|
|
@ -74,7 +74,7 @@ CLayerSurface::~CLayerSurface() {
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -114,7 +114,7 @@ void CLayerSurface::onDestroy() {
|
|||
}
|
||||
|
||||
void CLayerSurface::onMap() {
|
||||
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface);
|
||||
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface.get());
|
||||
|
||||
mapped = true;
|
||||
interactivity = layerSurface->current.interactivity;
|
||||
|
@ -177,7 +177,7 @@ void CLayerSurface::onMap() {
|
|||
}
|
||||
|
||||
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});
|
||||
EMIT_HOOK_EVENT("closeLayer", self.lock());
|
||||
|
@ -212,8 +212,11 @@ void CLayerSurface::onUnmap() {
|
|||
return;
|
||||
|
||||
// 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);
|
||||
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};
|
||||
g_pHyprRenderer->damageBox(&geomFixed);
|
||||
|
|
|
@ -55,7 +55,7 @@ void CPopup::initAllSignals() {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -250,7 +250,8 @@ void CPopup::recheckTree() {
|
|||
}
|
||||
|
||||
void CPopup::recheckChildrenRecursive() {
|
||||
for (auto& c : m_vChildren) {
|
||||
auto cpy = m_vChildren;
|
||||
for (auto& c : cpy) {
|
||||
c->onCommit(true);
|
||||
c->recheckChildrenRecursive();
|
||||
}
|
||||
|
|
|
@ -60,8 +60,8 @@ class CPopup {
|
|||
bool m_bMapped = false;
|
||||
|
||||
//
|
||||
std::vector<std::unique_ptr<CPopup>> m_vChildren;
|
||||
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
|
||||
std::vector<SP<CPopup>> m_vChildren;
|
||||
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener newPopup;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "WLSurface.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
|
||||
void CWLSurface::assign(SP<CWLSurfaceResource> 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);
|
||||
}
|
||||
|
||||
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 {
|
||||
if (!exists() || !m_pResource->current.buffer)
|
||||
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;
|
||||
}
|
||||
|
||||
CRegion CWLSurface::logicalDamage() const {
|
||||
CRegion CWLSurface::computeDamage() const {
|
||||
if (!m_pResource->current.buffer)
|
||||
return {};
|
||||
|
||||
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.scale(1.0 / m_pResource->current.scale);
|
||||
|
||||
const auto VPSIZE = getViewporterCorrectedSize();
|
||||
const auto CORRECTVEC = correctSmallVec();
|
||||
const auto BUFSIZE = m_pResource->current.buffer->size;
|
||||
const auto CORRECTVEC = correctSmallVecBuf();
|
||||
|
||||
if (m_pResource->current.viewport.hasSource)
|
||||
damage.intersect(m_pResource->current.viewport.source);
|
||||
|
@ -98,9 +108,20 @@ CRegion CWLSurface::logicalDamage() const {
|
|||
const auto SCALEDSRCSIZE =
|
||||
m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size;
|
||||
|
||||
damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y});
|
||||
damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -141,27 +162,27 @@ void CWLSurface::init() {
|
|||
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
|
||||
}
|
||||
|
||||
PHLWINDOW CWLSurface::getWindow() {
|
||||
PHLWINDOW CWLSurface::getWindow() const {
|
||||
return m_pWindowOwner.lock();
|
||||
}
|
||||
|
||||
PHLLS CWLSurface::getLayer() {
|
||||
PHLLS CWLSurface::getLayer() const {
|
||||
return m_pLayerOwner.lock();
|
||||
}
|
||||
|
||||
CPopup* CWLSurface::getPopup() {
|
||||
CPopup* CWLSurface::getPopup() const {
|
||||
return m_pPopupOwner;
|
||||
}
|
||||
|
||||
CSubsurface* CWLSurface::getSubsurface() {
|
||||
CSubsurface* CWLSurface::getSubsurface() const {
|
||||
return m_pSubsurfaceOwner;
|
||||
}
|
||||
|
||||
bool CWLSurface::desktopComponent() {
|
||||
bool CWLSurface::desktopComponent() const {
|
||||
return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner;
|
||||
}
|
||||
|
||||
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() {
|
||||
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const {
|
||||
if (!desktopComponent())
|
||||
return {};
|
||||
|
||||
|
@ -181,7 +202,7 @@ void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) {
|
|||
m_pConstraint = constraint;
|
||||
}
|
||||
|
||||
SP<CPointerConstraint> CWLSurface::constraint() {
|
||||
SP<CPointerConstraint> CWLSurface::constraint() const {
|
||||
return m_pConstraint.lock();
|
||||
}
|
||||
|
||||
|
@ -202,3 +223,11 @@ SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
|
|||
return nullptr;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -33,22 +33,24 @@ class CWLSurface {
|
|||
|
||||
SP<CWLSurfaceResource> resource() const;
|
||||
bool exists() const;
|
||||
bool small() const; // means surface is smaller than the requested size
|
||||
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
|
||||
bool small() const; // means surface is smaller than the requested size
|
||||
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;
|
||||
CRegion logicalDamage() const;
|
||||
CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned
|
||||
bool visible();
|
||||
bool keyboardFocusable() const;
|
||||
|
||||
// getters for owners.
|
||||
PHLWINDOW getWindow();
|
||||
PHLLS getLayer();
|
||||
CPopup* getPopup();
|
||||
CSubsurface* getSubsurface();
|
||||
PHLWINDOW getWindow() const;
|
||||
PHLLS getLayer() const;
|
||||
CPopup* getPopup() const;
|
||||
CSubsurface* getSubsurface() const;
|
||||
|
||||
// desktop components misc utils
|
||||
std::optional<CBox> getSurfaceBoxGlobal();
|
||||
std::optional<CBox> getSurfaceBoxGlobal() const;
|
||||
void appendConstraint(WP<CPointerConstraint> constraint);
|
||||
SP<CPointerConstraint> constraint();
|
||||
SP<CPointerConstraint> constraint() const;
|
||||
|
||||
// allow stretching. Useful for plugins.
|
||||
bool m_bFillIgnoreSmall = false;
|
||||
|
@ -107,7 +109,7 @@ class CWLSurface {
|
|||
|
||||
void destroy();
|
||||
void init();
|
||||
bool desktopComponent();
|
||||
bool desktopComponent() const;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener destroy;
|
||||
|
|
|
@ -110,7 +110,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
|
|||
|
||||
const int BORDERSIZE = getRealBorderSize();
|
||||
|
||||
if (m_sAdditionalConfigData.dimAround) {
|
||||
if (m_sWindowData.dimAround.valueOrDefault()) {
|
||||
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},
|
||||
{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() {
|
||||
if (m_sAdditionalConfigData.dimAround) {
|
||||
if (m_sWindowData.dimAround.valueOrDefault()) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
|
||||
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) {
|
||||
if (m_sAdditionalConfigData.dimAround) {
|
||||
if (m_sWindowData.dimAround.valueOrDefault()) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
if (PMONITOR)
|
||||
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||
|
@ -411,11 +411,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
setAnimationsToMove();
|
||||
|
||||
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_pCompositor->updateWorkspaceWindows(workspaceID());
|
||||
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
|
||||
g_pCompositor->updateWorkspaceWindowData(workspaceID());
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
|
||||
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
@ -524,7 +524,7 @@ void CWindow::onUnmap() {
|
|||
PMONITOR->solitaryClient.reset();
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(workspaceID());
|
||||
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
|
||||
g_pCompositor->updateWorkspaceWindowData(workspaceID());
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
|
@ -607,38 +607,15 @@ bool CWindow::isHidden() {
|
|||
}
|
||||
|
||||
void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
if (r.szRule == "noblur") {
|
||||
m_sAdditionalConfigData.forceNoBlur = true;
|
||||
} else if (r.szRule == "noborder") {
|
||||
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")) {
|
||||
const eOverridePriority priority = r.szValue == "execRule" ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
|
||||
const CVarList VARS(r.szRule, 0, ' ');
|
||||
if (r.szRule.starts_with("tag")) {
|
||||
CVarList vars{r.szRule, 0, 's', true};
|
||||
|
||||
if (vars.size() == 2 && vars[0] == "tag")
|
||||
m_tags.applyTag(vars[1], true);
|
||||
else
|
||||
Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
|
||||
} else if (r.szRule.starts_with("rounding")) {
|
||||
try {
|
||||
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||
} 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")) {
|
||||
try {
|
||||
CVarList vars(r.szRule, 0, ' ');
|
||||
|
@ -651,21 +628,18 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
|||
|
||||
if (r == "override") {
|
||||
if (opacityIDX == 1)
|
||||
m_sSpecialRenderData.alphaOverride = true;
|
||||
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
|
||||
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)
|
||||
m_sSpecialRenderData.alphaFullscreenOverride = true;
|
||||
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
|
||||
} else {
|
||||
if (opacityIDX == 0) {
|
||||
m_sSpecialRenderData.alpha = std::stof(r);
|
||||
m_sSpecialRenderData.alphaOverride = false;
|
||||
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
|
||||
} else if (opacityIDX == 1) {
|
||||
m_sSpecialRenderData.alphaInactive = std::stof(r);
|
||||
m_sSpecialRenderData.alphaInactiveOverride = false;
|
||||
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
|
||||
} else if (opacityIDX == 2) {
|
||||
m_sSpecialRenderData.alphaFullscreen = std::stof(r);
|
||||
m_sSpecialRenderData.alphaFullscreenOverride = false;
|
||||
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
|
||||
} else {
|
||||
throw std::runtime_error("more than 3 alpha values");
|
||||
}
|
||||
|
@ -675,17 +649,13 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
|||
}
|
||||
|
||||
if (opacityIDX == 1) {
|
||||
m_sSpecialRenderData.alphaInactiveOverride = m_sSpecialRenderData.alphaOverride;
|
||||
m_sSpecialRenderData.alphaInactive = m_sSpecialRenderData.alpha;
|
||||
m_sSpecialRenderData.alphaFullscreenOverride = m_sSpecialRenderData.alphaOverride;
|
||||
m_sSpecialRenderData.alphaFullscreen = m_sSpecialRenderData.alpha;
|
||||
m_sWindowData.alphaInactive = m_sWindowData.alpha;
|
||||
m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
|
||||
}
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||
} else if (r.szRule == "noanim") {
|
||||
m_sAdditionalConfigData.forceNoAnims = true;
|
||||
} else if (r.szRule.starts_with("animation")) {
|
||||
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
m_sAdditionalConfigData.animationStyle = STYLE;
|
||||
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
|
||||
} else if (r.szRule.starts_with("bordercolor")) {
|
||||
try {
|
||||
// Each vector will only get used if it has at least one color
|
||||
|
@ -696,8 +666,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
|||
|
||||
// Basic form has only two colors, everything else can be parsed as a gradient
|
||||
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
|
||||
m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0])));
|
||||
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1])));
|
||||
m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))), priority);
|
||||
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))), priority);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -720,24 +690,24 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
|||
else if (activeBorderGradient.m_vColors.empty())
|
||||
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
|
||||
else if (inactiveBorderGradient.m_vColors.empty())
|
||||
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
|
||||
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
|
||||
else {
|
||||
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
|
||||
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient;
|
||||
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
|
||||
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
|
||||
}
|
||||
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||
} else if (r.szRule == "dimaround") {
|
||||
m_sAdditionalConfigData.dimAround = true;
|
||||
} else if (r.szRule == "keepaspectratio") {
|
||||
m_sAdditionalConfigData.keepAspectRatio = true;
|
||||
} else if (r.szRule.starts_with("focusonactivate")) {
|
||||
m_sAdditionalConfigData.focusOnActivate = true;
|
||||
} else if (r.szRule.starts_with("xray")) {
|
||||
CVarList vars(r.szRule, 0, ' ');
|
||||
|
||||
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[0]); search != g_pConfigManager->mbWindowProperties.end()) {
|
||||
if (VARS[1].empty()) {
|
||||
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority);
|
||||
} else {
|
||||
try {
|
||||
*(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]), priority);
|
||||
} catch (...) {}
|
||||
}
|
||||
} else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) {
|
||||
try {
|
||||
m_sAdditionalConfigData.xray = configStringToInt(vars[1]);
|
||||
} catch (...) {}
|
||||
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[1]), priority);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||
} else if (r.szRule.starts_with("idleinhibit")) {
|
||||
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
|
||||
|
@ -761,9 +731,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
|||
return;
|
||||
}
|
||||
|
||||
m_sAdditionalConfigData.maxSize = VEC;
|
||||
m_vRealSize = Vector2D(std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().x, m_vRealSize.goal().x),
|
||||
std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().y, m_vRealSize.goal().y));
|
||||
m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
|
||||
m_vRealSize =
|
||||
Vector2D(std::min((double)m_sWindowData.maxSize.value().x, m_vRealSize.goal().x), std::min((double)m_sWindowData.maxSize.value().y, m_vRealSize.goal().y));
|
||||
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
|
||||
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||
} else if (r.szRule.starts_with("minsize")) {
|
||||
|
@ -776,9 +746,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
|||
return;
|
||||
}
|
||||
|
||||
m_sAdditionalConfigData.minSize = VEC;
|
||||
m_vRealSize = Vector2D(std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().x, m_vRealSize.goal().x),
|
||||
std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().y, m_vRealSize.goal().y));
|
||||
m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
|
||||
m_vRealSize =
|
||||
Vector2D(std::max((double)m_sWindowData.minSize.value().x, m_vRealSize.goal().x), std::max((double)m_sWindowData.minSize.value().y, m_vRealSize.goal().y));
|
||||
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
|
||||
if (m_sGroupData.pNextWindow.expired())
|
||||
setHidden(false);
|
||||
|
@ -787,30 +757,20 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
|||
}
|
||||
|
||||
void CWindow::updateDynamicRules() {
|
||||
m_sSpecialRenderData.activeBorderColor = CGradientValueData();
|
||||
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData();
|
||||
m_sSpecialRenderData.alpha = 1.f;
|
||||
m_sSpecialRenderData.alphaInactive = -1.f;
|
||||
m_sAdditionalConfigData.forceNoBlur = false;
|
||||
m_sAdditionalConfigData.forceNoBorder = false;
|
||||
m_sAdditionalConfigData.forceNoShadow = false;
|
||||
m_sAdditionalConfigData.forceNoDim = false;
|
||||
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
|
||||
m_sAdditionalConfigData.forceOpaque = false;
|
||||
m_sAdditionalConfigData.maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
|
||||
m_sAdditionalConfigData.minSize = Vector2D(20, 20);
|
||||
m_sAdditionalConfigData.forceNoAnims = false;
|
||||
m_sAdditionalConfigData.animationStyle = std::string("");
|
||||
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_sWindowData.alpha.unset(PRIORITY_WINDOW_RULE);
|
||||
m_sWindowData.alphaInactive.unset(PRIORITY_WINDOW_RULE);
|
||||
m_sWindowData.alphaFullscreen.unset(PRIORITY_WINDOW_RULE);
|
||||
|
||||
unsetWindowData(PRIORITY_WINDOW_RULE);
|
||||
|
||||
m_sWindowData.animationStyle.unset(PRIORITY_WINDOW_RULE);
|
||||
m_sWindowData.maxSize.unset(PRIORITY_WINDOW_RULE);
|
||||
m_sWindowData.minSize.unset(PRIORITY_WINDOW_RULE);
|
||||
|
||||
m_sWindowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE);
|
||||
m_sWindowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE);
|
||||
|
||||
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||
|
||||
m_tags.removeDynamicTags();
|
||||
|
||||
|
@ -887,7 +847,7 @@ void CWindow::createGroup() {
|
|||
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock()));
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(workspaceID());
|
||||
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
|
||||
g_pCompositor->updateWorkspaceWindowData(workspaceID());
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
|
@ -905,7 +865,7 @@ void CWindow::destroyGroup() {
|
|||
m_sGroupData.head = false;
|
||||
updateWindowDecos();
|
||||
g_pCompositor->updateWorkspaceWindows(workspaceID());
|
||||
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
|
||||
g_pCompositor->updateWorkspaceWindowData(workspaceID());
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
|
@ -941,7 +901,7 @@ void CWindow::destroyGroup() {
|
|||
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(workspaceID());
|
||||
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
|
||||
g_pCompositor->updateWorkspaceWindowData(workspaceID());
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
|
@ -1159,48 +1119,44 @@ bool CWindow::opaque() {
|
|||
float CWindow::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 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");
|
||||
|
||||
bool border = true;
|
||||
if (m_bIsFloating && *PNOBORDERONFLOATING == 1)
|
||||
border = false;
|
||||
if (*PNOBORDERONFLOATING)
|
||||
m_sWindowData.noBorder = CWindowOverridableVar(m_bIsFloating, PRIORITY_LAYOUT);
|
||||
else
|
||||
m_sWindowData.noBorder.unset(PRIORITY_LAYOUT);
|
||||
|
||||
m_sSpecialRenderData.border = workspaceRule.border.value_or(border);
|
||||
m_sSpecialRenderData.borderSize = workspaceRule.borderSize.value_or(-1);
|
||||
m_sSpecialRenderData.decorate = workspaceRule.decorate.value_or(true);
|
||||
m_sSpecialRenderData.rounding = workspaceRule.rounding.value_or(true);
|
||||
m_sSpecialRenderData.shadow = workspaceRule.shadow.value_or(true);
|
||||
m_sWindowData.borderSize.matchOptional(workspaceRule.borderSize, PRIORITY_WORKSPACE_RULE);
|
||||
m_sWindowData.decorate.matchOptional(workspaceRule.decorate, PRIORITY_WORKSPACE_RULE);
|
||||
m_sWindowData.noBorder.matchOptional(workspaceRule.noBorder, PRIORITY_WORKSPACE_RULE);
|
||||
m_sWindowData.noRounding.matchOptional(workspaceRule.noRounding, PRIORITY_WORKSPACE_RULE);
|
||||
m_sWindowData.noShadow.matchOptional(workspaceRule.noShadow, PRIORITY_WORKSPACE_RULE);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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");
|
||||
|
||||
return *PBORDERSIZE;
|
||||
return m_sWindowData.borderSize.valueOr(*PBORDERSIZE);
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -1349,8 +1305,7 @@ void CWindow::activate(bool force) {
|
|||
|
||||
m_bIsUrgent = true;
|
||||
|
||||
if (!force &&
|
||||
(!(*PFOCUSONACTIVATE || m_sAdditionalConfigData.focusOnActivate) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)))
|
||||
if (!force && (!m_sWindowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)))
|
||||
return;
|
||||
|
||||
if (m_bIsFloating)
|
||||
|
@ -1389,6 +1344,7 @@ void CWindow::onUpdateMeta() {
|
|||
if (m_szTitle != NEWTITLE) {
|
||||
m_szTitle = NEWTITLE;
|
||||
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());
|
||||
|
||||
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;
|
||||
|
||||
if (!m_sAdditionalConfigData.windowDanceCompat)
|
||||
g_pInputManager->refocus();
|
||||
|
||||
g_pHyprRenderer->damageWindow(m_pSelf.lock());
|
||||
}
|
||||
|
||||
|
@ -1597,3 +1550,12 @@ PHLWINDOW CWindow::getSwallower() {
|
|||
// if none are found (??) then just return the first one
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,13 +59,36 @@ enum eSuppressEvents {
|
|||
|
||||
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>
|
||||
class CWindowOverridableVar {
|
||||
public:
|
||||
CWindowOverridableVar(T const& val) {
|
||||
value = val;
|
||||
CWindowOverridableVar(T const& value, eOverridePriority priority) {
|
||||
values[priority] = value;
|
||||
}
|
||||
CWindowOverridableVar(T const& value) {
|
||||
defaultValue = value;
|
||||
}
|
||||
|
||||
CWindowOverridableVar() = default;
|
||||
~CWindowOverridableVar() = default;
|
||||
|
||||
CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> const& other) {
|
||||
|
@ -73,112 +96,92 @@ class CWindowOverridableVar {
|
|||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
// Check if the current object is locked
|
||||
if (!locked) {
|
||||
locked = other.locked;
|
||||
value = other.value;
|
||||
for (auto const& value : other.values) {
|
||||
values[value.first] = value.second;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
T operator=(T& other) {
|
||||
if (locked)
|
||||
return value;
|
||||
value = other;
|
||||
return other;
|
||||
void unset(eOverridePriority priority) {
|
||||
values.erase(priority);
|
||||
}
|
||||
|
||||
void forceSetIgnoreLocked(T const& val, bool lock = false) {
|
||||
value = val;
|
||||
locked = lock;
|
||||
bool hasValue() {
|
||||
return !values.empty();
|
||||
}
|
||||
|
||||
T operator*(T const& other) {
|
||||
return value * other;
|
||||
T value() {
|
||||
if (!values.empty())
|
||||
return std::prev(values.end())->second;
|
||||
else
|
||||
throw std::bad_optional_access();
|
||||
}
|
||||
|
||||
T operator+(T const& other) {
|
||||
return value + other;
|
||||
T valueOr(T const& other) {
|
||||
if (hasValue())
|
||||
return value();
|
||||
else
|
||||
return other;
|
||||
}
|
||||
|
||||
bool operator==(T const& other) {
|
||||
return other == value;
|
||||
T valueOrDefault() {
|
||||
return valueOr(defaultValue);
|
||||
}
|
||||
|
||||
bool operator>=(T const& other) {
|
||||
return value >= other;
|
||||
eOverridePriority getPriority() {
|
||||
if (!values.empty())
|
||||
return std::prev(values.end())->first;
|
||||
else
|
||||
throw std::bad_optional_access();
|
||||
}
|
||||
|
||||
bool operator<=(T const& other) {
|
||||
return value <= other;
|
||||
void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
|
||||
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:
|
||||
T value;
|
||||
std::map<eOverridePriority, T> values;
|
||||
T defaultValue; // used for toggling, so required for bool
|
||||
};
|
||||
|
||||
struct SWindowSpecialRenderData {
|
||||
CWindowOverridableVar<bool> alphaOverride = false;
|
||||
CWindowOverridableVar<float> alpha = 1.f;
|
||||
CWindowOverridableVar<bool> alphaInactiveOverride = false;
|
||||
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
|
||||
CWindowOverridableVar<bool> alphaFullscreenOverride = false;
|
||||
CWindowOverridableVar<float> alphaFullscreen = -1.f; // -1 means unset
|
||||
struct SWindowData {
|
||||
CWindowOverridableVar<SAlphaValue> alpha = SAlphaValue{1.f, false};
|
||||
CWindowOverridableVar<SAlphaValue> alphaInactive = SAlphaValue{1.f, false};
|
||||
CWindowOverridableVar<SAlphaValue> alphaFullscreen = SAlphaValue{1.f, false};
|
||||
|
||||
CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset
|
||||
CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset
|
||||
CWindowOverridableVar<bool> allowsInput = false;
|
||||
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> borderSize = -1; // -1 means unset
|
||||
bool rounding = true;
|
||||
bool border = true;
|
||||
bool decorate = true;
|
||||
bool shadow = true;
|
||||
};
|
||||
CWindowOverridableVar<int> rounding;
|
||||
CWindowOverridableVar<int> borderSize;
|
||||
|
||||
struct SWindowAdditionalConfigData {
|
||||
std::string animationStyle = std::string("");
|
||||
CWindowOverridableVar<int> rounding = -1; // -1 means no
|
||||
CWindowOverridableVar<bool> forceNoBlur = false;
|
||||
CWindowOverridableVar<bool> forceOpaque = false;
|
||||
CWindowOverridableVar<bool> forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
|
||||
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;
|
||||
CWindowOverridableVar<std::string> animationStyle;
|
||||
CWindowOverridableVar<Vector2D> maxSize;
|
||||
CWindowOverridableVar<Vector2D> minSize;
|
||||
|
||||
CWindowOverridableVar<CGradientValueData> activeBorderColor;
|
||||
CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
|
||||
};
|
||||
|
||||
struct SWindowRule {
|
||||
|
@ -331,8 +334,7 @@ class CWindow {
|
|||
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
|
||||
|
||||
// Special render data, rules, etc
|
||||
SWindowSpecialRenderData m_sSpecialRenderData;
|
||||
SWindowAdditionalConfigData m_sAdditionalConfigData;
|
||||
SWindowData m_sWindowData;
|
||||
|
||||
// Transformers
|
||||
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
|
||||
|
@ -423,8 +425,8 @@ class CWindow {
|
|||
int surfacesCount();
|
||||
|
||||
int getRealBorderSize();
|
||||
void updateSpecialRenderData();
|
||||
void updateSpecialRenderData(const struct SWorkspaceRule&);
|
||||
void updateWindowData();
|
||||
void updateWindowData(const struct SWorkspaceRule&);
|
||||
|
||||
void onBorderAngleAnimEnd(void* ptr);
|
||||
bool isInCurvedCorner(double x, double y);
|
||||
|
@ -455,6 +457,7 @@ class CWindow {
|
|||
std::string fetchClass();
|
||||
void warpCursor();
|
||||
PHLWINDOW getSwallower();
|
||||
void unsetWindowData(eOverridePriority priority);
|
||||
|
||||
// listeners
|
||||
void onAck(uint32_t serial);
|
||||
|
|
|
@ -2,7 +2,21 @@
|
|||
#include "../defines.hpp"
|
||||
#include "../helpers/varlist/VarList.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() {
|
||||
return HID_INPUT_CAPABILITY_KEYBOARD;
|
||||
}
|
||||
|
@ -14,27 +28,167 @@ eHIDType IKeyboard::getType() {
|
|||
IKeyboard::~IKeyboard() {
|
||||
events.destroy.emit();
|
||||
|
||||
if (!xkbTranslationState)
|
||||
return;
|
||||
clearManuallyAllocd();
|
||||
}
|
||||
|
||||
xkb_state_unref(xkbTranslationState);
|
||||
xkbTranslationState = nullptr;
|
||||
void IKeyboard::clearManuallyAllocd() {
|
||||
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) {
|
||||
|
||||
if (xkbTranslationState)
|
||||
xkb_state_unref(xkbTranslationState);
|
||||
if (xkbStaticState)
|
||||
xkb_state_unref(xkbStaticState);
|
||||
|
||||
if (xkbState)
|
||||
xkb_state_unref(xkbState);
|
||||
|
||||
xkbState = nullptr;
|
||||
xkbStaticState = nullptr;
|
||||
|
||||
if (keymap) {
|
||||
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;
|
||||
}
|
||||
|
||||
const auto WLRKB = wlr();
|
||||
const auto KEYMAP = WLRKB->keymap;
|
||||
const auto STATE = WLRKB->xkb_state;
|
||||
const auto KEYMAP = xkbKeymap;
|
||||
const auto STATE = xkbState;
|
||||
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
xkbTranslationState = xkb_state_new(KEYMAP);
|
||||
xkbState = xkb_state_new(KEYMAP);
|
||||
xkbStaticState = xkb_state_new(KEYMAP);
|
||||
|
||||
xkb_keymap_unref(KEYMAP);
|
||||
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);
|
||||
|
||||
xkbTranslationState = xkb_state_new(NEWKEYMAP);
|
||||
xkbState = xkb_state_new(NEWKEYMAP);
|
||||
xkbStaticState = xkb_state_new(NEWKEYMAP);
|
||||
|
||||
xkb_keymap_unref(NEWKEYMAP);
|
||||
xkb_context_unref(PCONTEXT);
|
||||
}
|
||||
|
||||
std::string IKeyboard::getActiveLayout() {
|
||||
const auto WLRKB = wlr();
|
||||
const auto KEYMAP = WLRKB->keymap;
|
||||
const auto STATE = WLRKB->xkb_state;
|
||||
const auto KEYMAP = xkbKeymap;
|
||||
const auto STATE = xkbState;
|
||||
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
|
||||
|
||||
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
|
||||
|
@ -120,14 +275,12 @@ std::string IKeyboard::getActiveLayout() {
|
|||
}
|
||||
|
||||
void IKeyboard::updateLEDs() {
|
||||
auto keyboard = wlr();
|
||||
|
||||
if (!keyboard || keyboard->xkb_state == nullptr)
|
||||
if (xkbState == 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]))
|
||||
for (uint32_t i = 0; i < LED_COUNT; ++i) {
|
||||
if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i)))
|
||||
leds |= (1 << i);
|
||||
}
|
||||
|
||||
|
@ -135,13 +288,88 @@ void IKeyboard::updateLEDs() {
|
|||
}
|
||||
|
||||
void IKeyboard::updateLEDs(uint32_t leds) {
|
||||
auto keyboard = wlr();
|
||||
|
||||
if (!keyboard || keyboard->xkb_state == nullptr)
|
||||
if (!xkbState)
|
||||
return;
|
||||
|
||||
if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock()))
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,15 +7,26 @@
|
|||
|
||||
#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 {
|
||||
public:
|
||||
virtual ~IKeyboard();
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
virtual bool isVirtual() = 0;
|
||||
virtual wlr_keyboard* wlr() = 0;
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
virtual bool isVirtual() = 0;
|
||||
virtual SP<Aquamarine::IKeyboard> aq() = 0;
|
||||
|
||||
struct SKeyEvent {
|
||||
uint32_t timeMs = 0;
|
||||
|
@ -24,6 +35,17 @@ class IKeyboard : public IHID {
|
|||
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 {
|
||||
CSignal key;
|
||||
CSignal modifiers;
|
||||
|
@ -39,25 +61,52 @@ class IKeyboard : public IHID {
|
|||
std::string rules = "";
|
||||
};
|
||||
|
||||
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
|
||||
std::string getActiveLayout();
|
||||
void updateLEDs();
|
||||
void updateLEDs(uint32_t leds);
|
||||
void setKeymap(const SStringRuleNames& rules);
|
||||
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
|
||||
std::string getActiveLayout();
|
||||
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 enabled = true;
|
||||
bool active = false;
|
||||
bool enabled = true;
|
||||
|
||||
xkb_layout_index_t activeLayout = 0;
|
||||
xkb_state* xkbTranslationState = nullptr;
|
||||
// if the keymap is overridden by the implementation,
|
||||
// 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 = "";
|
||||
std::string xkbFilePath = "";
|
||||
xkb_layout_index_t activeLayout = 0;
|
||||
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr;
|
||||
xkb_keymap* xkbKeymap = nullptr;
|
||||
|
||||
SStringRuleNames currentRules;
|
||||
int repeatRate = 0;
|
||||
int repeatDelay = 0;
|
||||
int numlockOn = -1;
|
||||
bool resolveBindsBySym = false;
|
||||
struct {
|
||||
uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
|
||||
} modifiersState;
|
||||
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
#include "../macros.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
|
||||
struct wlr_pointer;
|
||||
AQUAMARINE_FORWARD(IPointer);
|
||||
|
||||
/*
|
||||
Base class for a pointer.
|
||||
*/
|
||||
class IPointer : public IHID {
|
||||
public:
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
virtual bool isVirtual() = 0;
|
||||
virtual wlr_pointer* wlr() = 0;
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
virtual bool isVirtual() = 0;
|
||||
virtual SP<Aquamarine::IPointer> aq() = 0;
|
||||
|
||||
struct SMotionEvent {
|
||||
uint32_t timeMs = 0;
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
#include "../macros.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
|
||||
struct wlr_touch;
|
||||
AQUAMARINE_FORWARD(ITouch);
|
||||
|
||||
class ITouch : public IHID {
|
||||
public:
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
virtual bool isVirtual() = 0;
|
||||
virtual wlr_touch* wlr() = 0;
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
virtual bool isVirtual() = 0;
|
||||
virtual SP<Aquamarine::ITouch> aq() = 0;
|
||||
|
||||
struct SDownEvent {
|
||||
uint32_t timeMs = 0;
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#include "Keyboard.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));
|
||||
|
||||
pKeeb->self = pKeeb;
|
||||
|
@ -13,52 +16,41 @@ bool CKeyboard::isVirtual() {
|
|||
return false;
|
||||
}
|
||||
|
||||
wlr_keyboard* CKeyboard::wlr() {
|
||||
return keyboard;
|
||||
SP<Aquamarine::IKeyboard> CKeyboard::aq() {
|
||||
return keyboard.lock();
|
||||
}
|
||||
|
||||
CKeyboard::CKeyboard(wlr_keyboard* keeb) : keyboard(keeb) {
|
||||
CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : keyboard(keeb) {
|
||||
if (!keeb)
|
||||
return;
|
||||
|
||||
// clang-format off
|
||||
hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) {
|
||||
disconnectCallbacks();
|
||||
keyboard = nullptr;
|
||||
events.destroy.emit();
|
||||
}, this, "CKeyboard");
|
||||
listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) {
|
||||
keyboard.reset();
|
||||
events.destroy.emit();
|
||||
});
|
||||
|
||||
hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_keyboard_key_event*)data;
|
||||
listeners.key = keeb->events.key.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
|
||||
|
||||
keyboardEvents.key.emit(SKeyEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.keycode = E->keycode,
|
||||
.updateMods = E->update_state,
|
||||
.state = E->state,
|
||||
.timeMs = E.timeMs,
|
||||
.keycode = E.key,
|
||||
.state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
|
||||
});
|
||||
}, this, "CKeyboard");
|
||||
|
||||
hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) {
|
||||
keyboardEvents.keymap.emit();
|
||||
}, this, "CKeyboard");
|
||||
updateXkbStateWithKey(E.key + 8, E.pressed);
|
||||
});
|
||||
|
||||
hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) {
|
||||
keyboardEvents.modifiers.emit();
|
||||
}, this, "CKeyboard");
|
||||
listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
|
||||
updateModifiersState();
|
||||
|
||||
hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) {
|
||||
keyboardEvents.repeatInfo.emit();
|
||||
}, this, "CKeyboard");
|
||||
// clang-format on
|
||||
keyboardEvents.modifiers.emit(SModifiersEvent{
|
||||
.depressed = modifiersState.depressed,
|
||||
.latched = modifiersState.latched,
|
||||
.locked = modifiersState.locked,
|
||||
.group = modifiersState.group,
|
||||
});
|
||||
});
|
||||
|
||||
deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN";
|
||||
}
|
||||
|
||||
void CKeyboard::disconnectCallbacks() {
|
||||
hyprListener_destroy.removeCallback();
|
||||
hyprListener_key.removeCallback();
|
||||
hyprListener_keymap.removeCallback();
|
||||
hyprListener_repeatInfo.removeCallback();
|
||||
hyprListener_modifiers.removeCallback();
|
||||
deviceName = keeb->getName();
|
||||
}
|
||||
|
|
|
@ -4,21 +4,19 @@
|
|||
|
||||
class CKeyboard : public IKeyboard {
|
||||
public:
|
||||
static SP<CKeyboard> create(wlr_keyboard* keeb);
|
||||
static SP<CKeyboard> create(SP<Aquamarine::IKeyboard> keeb);
|
||||
|
||||
virtual bool isVirtual();
|
||||
virtual wlr_keyboard* wlr();
|
||||
virtual bool isVirtual();
|
||||
virtual SP<Aquamarine::IKeyboard> aq();
|
||||
|
||||
private:
|
||||
CKeyboard(wlr_keyboard* keeb);
|
||||
CKeyboard(SP<Aquamarine::IKeyboard> keeb);
|
||||
|
||||
wlr_keyboard* keyboard = nullptr;
|
||||
WP<Aquamarine::IKeyboard> keyboard;
|
||||
|
||||
void disconnectCallbacks();
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(key);
|
||||
DYNLISTENER(modifiers);
|
||||
DYNLISTENER(keymap);
|
||||
DYNLISTENER(repeatInfo);
|
||||
struct {
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener key;
|
||||
CHyprSignalListener modifiers;
|
||||
} listeners;
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
#include "Mouse.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));
|
||||
|
||||
pMouse->self = pMouse;
|
||||
|
@ -9,166 +10,143 @@ SP<CMouse> CMouse::create(wlr_pointer* mouse) {
|
|||
return pMouse;
|
||||
}
|
||||
|
||||
CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) {
|
||||
CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
|
||||
if (!mouse)
|
||||
return;
|
||||
|
||||
// clang-format off
|
||||
hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) {
|
||||
disconnectCallbacks();
|
||||
mouse = nullptr;
|
||||
listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) {
|
||||
mouse.reset();
|
||||
events.destroy.emit();
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_motion_event*)data;
|
||||
listeners.motion = mouse->events.move.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SMoveEvent>(d);
|
||||
|
||||
pointerEvents.motion.emit(SMotionEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.delta = {E->delta_x, E->delta_y},
|
||||
.unaccel = {E->unaccel_dx, E->unaccel_dy},
|
||||
.timeMs = E.timeMs,
|
||||
.delta = E.delta,
|
||||
.unaccel = E.unaccel,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_motion_absolute_event*)data;
|
||||
listeners.motionAbsolute = mouse->events.warp.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SWarpEvent>(d);
|
||||
|
||||
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.absolute = {E->x, E->y},
|
||||
.timeMs = E.timeMs,
|
||||
.absolute = E.absolute,
|
||||
.device = self.lock(),
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_button_event*)data;
|
||||
listeners.button = mouse->events.button.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SButtonEvent>(d);
|
||||
|
||||
pointerEvents.button.emit(SButtonEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.button = E->button,
|
||||
.state = (wl_pointer_button_state)E->state,
|
||||
.timeMs = E.timeMs,
|
||||
.button = E.button,
|
||||
.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) {
|
||||
auto E = (wlr_pointer_axis_event*)data;
|
||||
listeners.axis = mouse->events.axis.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SAxisEvent>(d);
|
||||
|
||||
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,
|
||||
.timeMs = E.timeMs,
|
||||
.source = (wl_pointer_axis_source)E.source,
|
||||
.axis = (wl_pointer_axis)E.axis,
|
||||
.relativeDirection = (wl_pointer_axis_relative_direction)E.direction,
|
||||
.delta = E.delta,
|
||||
.deltaDiscrete = E.discrete,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) {
|
||||
pointerEvents.frame.emit();
|
||||
}, this, "CMouse");
|
||||
listeners.frame = mouse->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
|
||||
|
||||
hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_swipe_begin_event*)data;
|
||||
listeners.swipeBegin = mouse->events.swipeBegin.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SSwipeBeginEvent>(d);
|
||||
|
||||
pointerEvents.swipeBegin.emit(SSwipeBeginEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.fingers = E->fingers,
|
||||
.timeMs = E.timeMs,
|
||||
.fingers = E.fingers,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_swipe_end_event*)data;
|
||||
listeners.swipeEnd = mouse->events.swipeEnd.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SSwipeEndEvent>(d);
|
||||
|
||||
pointerEvents.swipeEnd.emit(SSwipeEndEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.cancelled = E->cancelled,
|
||||
.timeMs = E.timeMs,
|
||||
.cancelled = E.cancelled,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_swipe_update_event*)data;
|
||||
listeners.swipeUpdate = mouse->events.swipeUpdate.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SSwipeUpdateEvent>(d);
|
||||
|
||||
pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.fingers = E->fingers,
|
||||
.delta = {E->dx, E->dy},
|
||||
.timeMs = E.timeMs,
|
||||
.fingers = E.fingers,
|
||||
.delta = E.delta,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_pinch_begin_event*)data;
|
||||
listeners.pinchBegin = mouse->events.pinchBegin.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SPinchBeginEvent>(d);
|
||||
|
||||
pointerEvents.pinchBegin.emit(SPinchBeginEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.fingers = E->fingers,
|
||||
.timeMs = E.timeMs,
|
||||
.fingers = E.fingers,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_pinch_end_event*)data;
|
||||
listeners.pinchEnd = mouse->events.pinchEnd.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SPinchEndEvent>(d);
|
||||
|
||||
pointerEvents.pinchEnd.emit(SPinchEndEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.cancelled = E->cancelled,
|
||||
.timeMs = E.timeMs,
|
||||
.cancelled = E.cancelled,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_pinch_update_event*)data;
|
||||
listeners.pinchUpdate = mouse->events.pinchUpdate.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SPinchUpdateEvent>(d);
|
||||
|
||||
pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.fingers = E->fingers,
|
||||
.delta = {E->dx, E->dy},
|
||||
.scale = E->scale,
|
||||
.rotation = E->rotation,
|
||||
.timeMs = E.timeMs,
|
||||
.fingers = E.fingers,
|
||||
.delta = E.delta,
|
||||
.scale = E.scale,
|
||||
.rotation = E.rotation,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_hold_begin_event*)data;
|
||||
listeners.holdBegin = mouse->events.holdBegin.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SHoldBeginEvent>(d);
|
||||
|
||||
pointerEvents.holdBegin.emit(SHoldBeginEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.fingers = E->fingers,
|
||||
.timeMs = E.timeMs,
|
||||
.fingers = E.fingers,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_hold_end_event*)data;
|
||||
listeners.holdEnd = mouse->events.holdEnd.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IPointer::SHoldEndEvent>(d);
|
||||
|
||||
pointerEvents.holdEnd.emit(SHoldEndEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.cancelled = E->cancelled,
|
||||
.timeMs = E.timeMs,
|
||||
.cancelled = E.cancelled,
|
||||
});
|
||||
}, this, "CMouse");
|
||||
});
|
||||
|
||||
// clang-format on
|
||||
|
||||
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();
|
||||
deviceName = mouse->getName();
|
||||
}
|
||||
|
||||
bool CMouse::isVirtual() {
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_pointer* CMouse::wlr() {
|
||||
return mouse;
|
||||
SP<Aquamarine::IPointer> CMouse::aq() {
|
||||
return mouse.lock();
|
||||
}
|
||||
|
|
|
@ -4,33 +4,34 @@
|
|||
|
||||
class CMouse : public IPointer {
|
||||
public:
|
||||
static SP<CMouse> create(wlr_pointer* mouse);
|
||||
static SP<CMouse> create(SP<Aquamarine::IPointer> mouse);
|
||||
|
||||
virtual bool isVirtual();
|
||||
virtual wlr_pointer* wlr();
|
||||
virtual bool isVirtual();
|
||||
virtual SP<Aquamarine::IPointer> aq();
|
||||
|
||||
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);
|
||||
DYNLISTENER(motion);
|
||||
DYNLISTENER(motionAbsolute);
|
||||
DYNLISTENER(button);
|
||||
DYNLISTENER(axis);
|
||||
DYNLISTENER(frame);
|
||||
CHyprSignalListener motion;
|
||||
CHyprSignalListener motionAbsolute;
|
||||
CHyprSignalListener button;
|
||||
CHyprSignalListener axis;
|
||||
CHyprSignalListener frame;
|
||||
|
||||
DYNLISTENER(swipeBegin);
|
||||
DYNLISTENER(swipeEnd);
|
||||
DYNLISTENER(swipeUpdate);
|
||||
CHyprSignalListener swipeBegin;
|
||||
CHyprSignalListener swipeEnd;
|
||||
CHyprSignalListener swipeUpdate;
|
||||
|
||||
DYNLISTENER(pinchBegin);
|
||||
DYNLISTENER(pinchEnd);
|
||||
DYNLISTENER(pinchUpdate);
|
||||
CHyprSignalListener pinchBegin;
|
||||
CHyprSignalListener pinchEnd;
|
||||
CHyprSignalListener pinchUpdate;
|
||||
|
||||
DYNLISTENER(holdBegin);
|
||||
DYNLISTENER(holdEnd);
|
||||
CHyprSignalListener holdBegin;
|
||||
CHyprSignalListener holdEnd;
|
||||
} listeners;
|
||||
};
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
#include "../defines.hpp"
|
||||
#include "../protocols/Tablet.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));
|
||||
|
||||
pTab->self = pTab;
|
||||
|
@ -13,7 +14,7 @@ SP<CTablet> CTablet::create(wlr_tablet* tablet) {
|
|||
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));
|
||||
|
||||
pTab->self = pTab;
|
||||
|
@ -23,7 +24,7 @@ SP<CTabletTool> CTabletTool::create(wlr_tablet_tool* tablet) {
|
|||
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));
|
||||
|
||||
pTab->self = pTab;
|
||||
|
@ -33,33 +34,25 @@ SP<CTabletPad> CTabletPad::create(wlr_tablet_pad* tablet) {
|
|||
return pTab;
|
||||
}
|
||||
|
||||
SP<CTabletTool> CTabletTool::fromWlr(wlr_tablet_tool* tool) {
|
||||
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) {
|
||||
static uint32_t aqUpdateToHl(uint32_t aq) {
|
||||
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;
|
||||
if (wlr & WLR_TABLET_TOOL_AXIS_Y)
|
||||
if (aq & Aquamarine::AQ_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;
|
||||
if (wlr & WLR_TABLET_TOOL_AXIS_PRESSURE)
|
||||
if (aq & Aquamarine::AQ_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;
|
||||
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;
|
||||
if (wlr & WLR_TABLET_TOOL_AXIS_ROTATION)
|
||||
if (aq & Aquamarine::AQ_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;
|
||||
if (wlr & WLR_TABLET_TOOL_AXIS_WHEEL)
|
||||
if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_WHEEL)
|
||||
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL;
|
||||
return result;
|
||||
}
|
||||
|
@ -68,97 +61,81 @@ uint32_t CTablet::getCapabilities() {
|
|||
return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET;
|
||||
}
|
||||
|
||||
wlr_tablet* CTablet::wlr() {
|
||||
return tablet;
|
||||
SP<Aquamarine::ITablet> CTablet::aq() {
|
||||
return tablet.lock();
|
||||
}
|
||||
|
||||
CTablet::CTablet(wlr_tablet* tablet_) : tablet(tablet_) {
|
||||
CTablet::CTablet(SP<Aquamarine::ITablet> tablet_) : tablet(tablet_) {
|
||||
if (!tablet)
|
||||
return;
|
||||
|
||||
tablet->data = this;
|
||||
|
||||
// clang-format off
|
||||
hyprListener_destroy.initCallback(&tablet->base.events.destroy, [this] (void* owner, void* data) {
|
||||
tablet = nullptr;
|
||||
disconnectCallbacks();
|
||||
listeners.destroy = tablet->events.destroy.registerListener([this](std::any d) {
|
||||
tablet.reset();
|
||||
events.destroy.emit();
|
||||
}, this, "CTablet");
|
||||
});
|
||||
|
||||
hyprListener_axis.initCallback(&tablet->events.axis, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_tablet_tool_axis_event*)data;
|
||||
listeners.axis = tablet->events.axis.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITablet::SAxisEvent>(d);
|
||||
|
||||
tabletEvents.axis.emit(SAxisEvent{
|
||||
.tool = E->tool,
|
||||
.tool = E.tool,
|
||||
.tablet = self.lock(),
|
||||
.timeMs = E->time_msec,
|
||||
.updatedAxes = wlrUpdateToHl(E->updated_axes),
|
||||
.axis = {E->x, E->y},
|
||||
.axisDelta = {E->dx, E->dy},
|
||||
.tilt = {E->tilt_x, E->tilt_y},
|
||||
.pressure = E->pressure,
|
||||
.distance = E->distance,
|
||||
.rotation = E->rotation,
|
||||
.slider = E->slider,
|
||||
.wheelDelta = E->wheel_delta,
|
||||
.timeMs = E.timeMs,
|
||||
.updatedAxes = aqUpdateToHl(E.updatedAxes),
|
||||
.axis = E.absolute,
|
||||
.axisDelta = E.delta,
|
||||
.tilt = E.tilt,
|
||||
.pressure = E.pressure,
|
||||
.distance = E.distance,
|
||||
.rotation = E.rotation,
|
||||
.slider = E.slider,
|
||||
.wheelDelta = E.wheelDelta,
|
||||
});
|
||||
}, this, "CTablet");
|
||||
});
|
||||
|
||||
hyprListener_proximity.initCallback(&tablet->events.proximity, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_tablet_tool_proximity_event*)data;
|
||||
listeners.proximity = tablet->events.proximity.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITablet::SProximityEvent>(d);
|
||||
|
||||
tabletEvents.proximity.emit(SProximityEvent{
|
||||
.tool = E->tool,
|
||||
.tool = E.tool,
|
||||
.tablet = self.lock(),
|
||||
.timeMs = E->time_msec,
|
||||
.proximity = {E->x, E->y},
|
||||
.in = E->state == WLR_TABLET_TOOL_PROXIMITY_IN,
|
||||
.timeMs = E.timeMs,
|
||||
.proximity = E.absolute,
|
||||
.in = E.in,
|
||||
});
|
||||
}, this, "CTablet");
|
||||
});
|
||||
|
||||
hyprListener_tip.initCallback(&tablet->events.tip, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_tablet_tool_tip_event*)data;
|
||||
listeners.tip = tablet->events.tip.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITablet::STipEvent>(d);
|
||||
|
||||
tabletEvents.tip.emit(STipEvent{
|
||||
.tool = E->tool,
|
||||
.tool = E.tool,
|
||||
.tablet = self.lock(),
|
||||
.timeMs = E->time_msec,
|
||||
.tip = {E->x, E->y},
|
||||
.in = E->state == WLR_TABLET_TOOL_TIP_DOWN,
|
||||
.timeMs = E.timeMs,
|
||||
.tip = E.absolute,
|
||||
.in = E.down,
|
||||
});
|
||||
}, this, "CTablet");
|
||||
});
|
||||
|
||||
hyprListener_button.initCallback(&tablet->events.button, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_tablet_tool_button_event*)data;
|
||||
listeners.button = tablet->events.button.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITablet::SButtonEvent>(d);
|
||||
|
||||
tabletEvents.button.emit(SButtonEvent{
|
||||
.tool = E->tool,
|
||||
.tool = E.tool,
|
||||
.tablet = self.lock(),
|
||||
.timeMs = E->time_msec,
|
||||
.button = E->button,
|
||||
.down = E->state == WLR_BUTTON_PRESSED,
|
||||
.timeMs = E.timeMs,
|
||||
.button = E.button,
|
||||
.down = E.down,
|
||||
});
|
||||
}, this, "CTablet");
|
||||
// clang-format on
|
||||
});
|
||||
|
||||
deviceName = tablet->base.name ? tablet->base.name : "UNKNOWN";
|
||||
deviceName = tablet->getName();
|
||||
}
|
||||
|
||||
CTablet::~CTablet() {
|
||||
if (tablet)
|
||||
tablet->data = nullptr;
|
||||
|
||||
PROTO::tablet->recheckRegisteredDevices();
|
||||
}
|
||||
|
||||
void CTablet::disconnectCallbacks() {
|
||||
hyprListener_axis.removeCallback();
|
||||
hyprListener_button.removeCallback();
|
||||
hyprListener_destroy.removeCallback();
|
||||
hyprListener_proximity.removeCallback();
|
||||
hyprListener_tip.removeCallback();
|
||||
}
|
||||
|
||||
eHIDType CTablet::getType() {
|
||||
return HID_TYPE_TABLET;
|
||||
}
|
||||
|
@ -167,138 +144,111 @@ uint32_t CTabletPad::getCapabilities() {
|
|||
return HID_INPUT_CAPABILITY_TABLET;
|
||||
}
|
||||
|
||||
wlr_tablet_pad* CTabletPad::wlr() {
|
||||
return pad;
|
||||
SP<Aquamarine::ITabletPad> CTabletPad::aq() {
|
||||
return pad.lock();
|
||||
}
|
||||
|
||||
eHIDType CTabletPad::getType() {
|
||||
return HID_TYPE_TABLET_PAD;
|
||||
}
|
||||
|
||||
CTabletPad::CTabletPad(wlr_tablet_pad* pad_) : pad(pad_) {
|
||||
CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
|
||||
if (!pad)
|
||||
return;
|
||||
|
||||
// clang-format off
|
||||
hyprListener_destroy.initCallback(&pad->base.events.destroy, [this] (void* owner, void* data) {
|
||||
pad = nullptr;
|
||||
disconnectCallbacks();
|
||||
listeners.destroy = pad->events.destroy.registerListener([this](std::any d) {
|
||||
pad.reset();
|
||||
events.destroy.emit();
|
||||
}, this, "CTabletPad");
|
||||
});
|
||||
|
||||
hyprListener_button.initCallback(&pad->events.button, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_tablet_pad_button_event*)data;
|
||||
listeners.button = pad->events.button.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITabletPad::SButtonEvent>(d);
|
||||
|
||||
padEvents.button.emit(SButtonEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.button = E->button,
|
||||
.down = E->state == WLR_BUTTON_PRESSED,
|
||||
.mode = E->mode,
|
||||
.group = E->group,
|
||||
.timeMs = E.timeMs,
|
||||
.button = E.button,
|
||||
.down = E.down,
|
||||
.mode = E.mode,
|
||||
.group = E.group,
|
||||
});
|
||||
}, this, "CTabletPad");
|
||||
});
|
||||
|
||||
hyprListener_ring.initCallback(&pad->events.ring, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_tablet_pad_ring_event*)data;
|
||||
listeners.ring = pad->events.ring.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITabletPad::SRingEvent>(d);
|
||||
|
||||
padEvents.ring.emit(SRingEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.finger = E->source == WLR_TABLET_PAD_RING_SOURCE_FINGER,
|
||||
.ring = E->ring,
|
||||
.position = E->position,
|
||||
.mode = E->mode,
|
||||
.timeMs = E.timeMs,
|
||||
.finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_RING_SOURCE_FINGER,
|
||||
.ring = E.ring,
|
||||
.position = E.pos,
|
||||
.mode = E.mode,
|
||||
});
|
||||
}, this, "CTabletPad");
|
||||
});
|
||||
|
||||
hyprListener_strip.initCallback(&pad->events.strip, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_tablet_pad_strip_event*)data;
|
||||
listeners.strip = pad->events.strip.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITabletPad::SStripEvent>(d);
|
||||
|
||||
padEvents.strip.emit(SStripEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.finger = E->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER,
|
||||
.strip = E->strip,
|
||||
.position = E->position,
|
||||
.mode = E->mode,
|
||||
.timeMs = E.timeMs,
|
||||
.finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_STRIP_SOURCE_FINGER,
|
||||
.strip = E.strip,
|
||||
.position = E.pos,
|
||||
.mode = E.mode,
|
||||
});
|
||||
}, this, "CTabletPad");
|
||||
});
|
||||
|
||||
hyprListener_attach.initCallback(&pad->events.attach_tablet, [this] (void* owner, void* data) {
|
||||
if (!data)
|
||||
return;
|
||||
listeners.attach = pad->events.attach.registerListener([this](std::any d) {
|
||||
; // TODO: this doesn't do anything in aq atm
|
||||
});
|
||||
|
||||
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() {
|
||||
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() {
|
||||
return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET;
|
||||
}
|
||||
|
||||
wlr_tablet_tool* CTabletTool::wlr() {
|
||||
return tool;
|
||||
SP<Aquamarine::ITabletTool> CTabletTool::aq() {
|
||||
return tool.lock();
|
||||
}
|
||||
|
||||
eHIDType CTabletTool::getType() {
|
||||
return HID_TYPE_TABLET_TOOL;
|
||||
}
|
||||
|
||||
CTabletTool::CTabletTool(wlr_tablet_tool* tool_) : tool(tool_) {
|
||||
CTabletTool::CTabletTool(SP<Aquamarine::ITabletTool> tool_) : tool(tool_) {
|
||||
if (!tool)
|
||||
return;
|
||||
|
||||
// clang-format off
|
||||
hyprListener_destroy.initCallback(&tool->events.destroy, [this] (void* owner, void* data) {
|
||||
tool = nullptr;
|
||||
disconnectCallbacks();
|
||||
listeners.destroyTool = tool->events.destroy.registerListener([this](std::any d) {
|
||||
tool.reset();
|
||||
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;
|
||||
if (tool->pressure)
|
||||
if (tool->capabilities & Aquamarine::ITabletTool::AQ_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;
|
||||
if (tool->rotation)
|
||||
if (tool->capabilities & Aquamarine::ITabletTool::AQ_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;
|
||||
if (tool->wheel)
|
||||
if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_WHEEL)
|
||||
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL;
|
||||
|
||||
tool->data = this;
|
||||
|
||||
deviceName = std::to_string(tool->hardware_serial) + std::to_string(tool->hardware_wacom);
|
||||
deviceName = std::format("{:x}-{:x}", tool->serial, tool->id);
|
||||
}
|
||||
|
||||
CTabletTool::~CTabletTool() {
|
||||
if (tool)
|
||||
tool->data = nullptr;
|
||||
|
||||
PROTO::tablet->recheckRegisteredDevices();
|
||||
}
|
||||
|
||||
void CTabletTool::disconnectCallbacks() {
|
||||
hyprListener_destroy.removeCallback();
|
||||
listeners.destroySurface.reset();
|
||||
}
|
||||
|
||||
SP<CWLSurfaceResource> CTabletTool::getSurface() {
|
||||
return pSurface.lock();
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
#include "../helpers/math/Math.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
|
||||
struct wlr_tablet;
|
||||
struct wlr_tablet_tool;
|
||||
struct wlr_tablet_pad;
|
||||
AQUAMARINE_FORWARD(ITablet);
|
||||
AQUAMARINE_FORWARD(ITabletTool);
|
||||
AQUAMARINE_FORWARD(ITabletPad);
|
||||
|
||||
class CTabletTool;
|
||||
class CTabletPad;
|
||||
|
@ -21,13 +21,12 @@ class CWLSurfaceResource;
|
|||
*/
|
||||
class CTablet : public IHID {
|
||||
public:
|
||||
static SP<CTablet> create(wlr_tablet* tablet);
|
||||
static SP<CTablet> fromWlr(wlr_tablet* tablet);
|
||||
static SP<CTablet> create(SP<Aquamarine::ITablet> tablet);
|
||||
~CTablet();
|
||||
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
wlr_tablet* wlr();
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
SP<Aquamarine::ITablet> aq();
|
||||
|
||||
enum eTabletToolAxes {
|
||||
HID_TABLET_TOOL_AXIS_X = (1 << 0),
|
||||
|
@ -42,46 +41,46 @@ class CTablet : public IHID {
|
|||
};
|
||||
|
||||
struct SAxisEvent {
|
||||
wlr_tablet_tool* tool;
|
||||
SP<CTablet> tablet;
|
||||
SP<Aquamarine::ITabletTool> tool;
|
||||
SP<CTablet> tablet;
|
||||
|
||||
uint32_t timeMs = 0;
|
||||
uint32_t updatedAxes = 0; // eTabletToolAxes
|
||||
Vector2D axis;
|
||||
Vector2D axisDelta;
|
||||
Vector2D tilt;
|
||||
double pressure = 0;
|
||||
double distance = 0;
|
||||
double rotation = 0;
|
||||
double slider = 0;
|
||||
double wheelDelta = 0;
|
||||
uint32_t timeMs = 0;
|
||||
uint32_t updatedAxes = 0; // eTabletToolAxes
|
||||
Vector2D axis;
|
||||
Vector2D axisDelta;
|
||||
Vector2D tilt;
|
||||
double pressure = 0;
|
||||
double distance = 0;
|
||||
double rotation = 0;
|
||||
double slider = 0;
|
||||
double wheelDelta = 0;
|
||||
};
|
||||
|
||||
struct SProximityEvent {
|
||||
wlr_tablet_tool* tool;
|
||||
SP<CTablet> tablet;
|
||||
SP<Aquamarine::ITabletTool> tool;
|
||||
SP<CTablet> tablet;
|
||||
|
||||
uint32_t timeMs = 0;
|
||||
Vector2D proximity;
|
||||
bool in = false;
|
||||
uint32_t timeMs = 0;
|
||||
Vector2D proximity;
|
||||
bool in = false;
|
||||
};
|
||||
|
||||
struct STipEvent {
|
||||
wlr_tablet_tool* tool;
|
||||
SP<CTablet> tablet;
|
||||
SP<Aquamarine::ITabletTool> tool;
|
||||
SP<CTablet> tablet;
|
||||
|
||||
uint32_t timeMs = 0;
|
||||
Vector2D tip;
|
||||
bool in = false;
|
||||
uint32_t timeMs = 0;
|
||||
Vector2D tip;
|
||||
bool in = false;
|
||||
};
|
||||
|
||||
struct SButtonEvent {
|
||||
wlr_tablet_tool* tool;
|
||||
SP<CTablet> tablet;
|
||||
SP<Aquamarine::ITabletTool> tool;
|
||||
SP<CTablet> tablet;
|
||||
|
||||
uint32_t timeMs = 0;
|
||||
uint32_t button;
|
||||
bool down = false;
|
||||
uint32_t timeMs = 0;
|
||||
uint32_t button;
|
||||
bool down = false;
|
||||
};
|
||||
|
||||
struct {
|
||||
|
@ -100,27 +99,27 @@ class CTablet : public IHID {
|
|||
CBox boundBox; // output-local
|
||||
|
||||
private:
|
||||
CTablet(wlr_tablet* tablet);
|
||||
CTablet(SP<Aquamarine::ITablet> tablet);
|
||||
|
||||
void disconnectCallbacks();
|
||||
WP<Aquamarine::ITablet> tablet;
|
||||
|
||||
wlr_tablet* tablet = nullptr;
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(axis);
|
||||
DYNLISTENER(proximity);
|
||||
DYNLISTENER(tip);
|
||||
DYNLISTENER(button);
|
||||
struct {
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener axis;
|
||||
CHyprSignalListener proximity;
|
||||
CHyprSignalListener tip;
|
||||
CHyprSignalListener button;
|
||||
} listeners;
|
||||
};
|
||||
|
||||
class CTabletPad : public IHID {
|
||||
public:
|
||||
static SP<CTabletPad> create(wlr_tablet_pad* pad);
|
||||
static SP<CTabletPad> create(SP<Aquamarine::ITabletPad> pad);
|
||||
~CTabletPad();
|
||||
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
wlr_tablet_pad* wlr();
|
||||
virtual uint32_t getCapabilities();
|
||||
virtual eHIDType getType();
|
||||
SP<Aquamarine::ITabletPad> aq();
|
||||
|
||||
struct SButtonEvent {
|
||||
uint32_t timeMs = 0;
|
||||
|
@ -159,23 +158,22 @@ class CTabletPad : public IHID {
|
|||
std::string hlName;
|
||||
|
||||
private:
|
||||
CTabletPad(wlr_tablet_pad* pad);
|
||||
CTabletPad(SP<Aquamarine::ITabletPad> pad);
|
||||
|
||||
void disconnectCallbacks();
|
||||
WP<Aquamarine::ITabletPad> pad;
|
||||
|
||||
wlr_tablet_pad* pad = nullptr;
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(ring);
|
||||
DYNLISTENER(strip);
|
||||
DYNLISTENER(button);
|
||||
DYNLISTENER(attach);
|
||||
struct {
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener ring;
|
||||
CHyprSignalListener strip;
|
||||
CHyprSignalListener button;
|
||||
CHyprSignalListener attach;
|
||||
} listeners;
|
||||
};
|
||||
|
||||
class CTabletTool : public IHID {
|
||||
public:
|
||||
static SP<CTabletTool> create(wlr_tablet_tool* tool);
|
||||
static SP<CTabletTool> fromWlr(wlr_tablet_tool* tool);
|
||||
static SP<CTabletTool> create(SP<Aquamarine::ITabletTool> tool);
|
||||
~CTabletTool();
|
||||
|
||||
enum eTabletToolType {
|
||||
|
@ -198,35 +196,31 @@ class CTabletTool : public IHID {
|
|||
HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5),
|
||||
};
|
||||
|
||||
virtual uint32_t getCapabilities();
|
||||
wlr_tablet_tool* wlr();
|
||||
virtual eHIDType getType();
|
||||
SP<CWLSurfaceResource> getSurface();
|
||||
void setSurface(SP<CWLSurfaceResource>);
|
||||
virtual uint32_t getCapabilities();
|
||||
SP<Aquamarine::ITabletTool> aq();
|
||||
virtual eHIDType getType();
|
||||
SP<CWLSurfaceResource> getSurface();
|
||||
void setSurface(SP<CWLSurfaceResource>);
|
||||
|
||||
WP<CTabletTool> self;
|
||||
Vector2D tilt;
|
||||
bool active = false; // true if in proximity
|
||||
uint32_t toolCapabilities = 0;
|
||||
WP<CTabletTool> self;
|
||||
Vector2D tilt;
|
||||
bool active = false; // true if in proximity
|
||||
uint32_t toolCapabilities = 0;
|
||||
|
||||
bool isDown = false;
|
||||
std::vector<uint32_t> buttonsDown;
|
||||
Vector2D absolutePos; // last known absolute position.
|
||||
bool isDown = false;
|
||||
std::vector<uint32_t> buttonsDown;
|
||||
Vector2D absolutePos; // last known absolute position.
|
||||
|
||||
std::string hlName;
|
||||
std::string hlName;
|
||||
|
||||
private:
|
||||
CTabletTool(wlr_tablet_tool* tool);
|
||||
CTabletTool(SP<Aquamarine::ITabletTool> tool);
|
||||
|
||||
void disconnectCallbacks();
|
||||
|
||||
WP<CWLSurfaceResource> pSurface;
|
||||
|
||||
wlr_tablet_tool* tool = nullptr;
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
WP<CWLSurfaceResource> pSurface;
|
||||
WP<Aquamarine::ITabletTool> tool;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener destroySurface;
|
||||
CHyprSignalListener destroyTool;
|
||||
} listeners;
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
#include "TouchDevice.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));
|
||||
|
||||
pTouch->self = pTouch;
|
||||
|
@ -9,78 +10,63 @@ SP<CTouchDevice> CTouchDevice::create(wlr_touch* touch) {
|
|||
return pTouch;
|
||||
}
|
||||
|
||||
CTouchDevice::CTouchDevice(wlr_touch* touch_) : touch(touch_) {
|
||||
CTouchDevice::CTouchDevice(SP<Aquamarine::ITouch> touch_) : touch(touch_) {
|
||||
if (!touch)
|
||||
return;
|
||||
|
||||
// clang-format off
|
||||
hyprListener_destroy.initCallback(&touch->base.events.destroy, [this] (void* owner, void* data) {
|
||||
listeners.destroy = touch->events.destroy.registerListener([this](std::any d) {
|
||||
events.destroy.emit();
|
||||
disconnectCallbacks();
|
||||
touch = nullptr;
|
||||
}, this, "CTouchDevice");
|
||||
touch.reset();
|
||||
});
|
||||
|
||||
hyprListener_down.initCallback(&touch->events.down, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_touch_down_event*)data;
|
||||
listeners.down = touch->events.down.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITouch::SDownEvent>(d);
|
||||
|
||||
touchEvents.down.emit(SDownEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.touchID = E->touch_id,
|
||||
.pos = {E->x, E->y},
|
||||
.timeMs = E.timeMs,
|
||||
.touchID = E.touchID,
|
||||
.pos = E.pos,
|
||||
.device = self.lock(),
|
||||
});
|
||||
}, this, "CTouchDevice");
|
||||
});
|
||||
|
||||
hyprListener_up.initCallback(&touch->events.up, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_touch_up_event*)data;
|
||||
listeners.up = touch->events.up.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITouch::SUpEvent>(d);
|
||||
|
||||
touchEvents.up.emit(SUpEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.touchID = E->touch_id
|
||||
.timeMs = E.timeMs,
|
||||
.touchID = E.touchID,
|
||||
});
|
||||
}, this, "CTouchDevice");
|
||||
});
|
||||
|
||||
hyprListener_motion.initCallback(&touch->events.motion, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_touch_motion_event*)data;
|
||||
listeners.motion = touch->events.move.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITouch::SMotionEvent>(d);
|
||||
|
||||
touchEvents.motion.emit(SMotionEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.touchID = E->touch_id,
|
||||
.pos = {E->x, E->y},
|
||||
.timeMs = E.timeMs,
|
||||
.touchID = E.touchID,
|
||||
.pos = E.pos,
|
||||
});
|
||||
}, this, "CTouchDevice");
|
||||
});
|
||||
|
||||
hyprListener_cancel.initCallback(&touch->events.cancel, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_touch_cancel_event*)data;
|
||||
listeners.cancel = touch->events.cancel.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::ITouch::SCancelEvent>(d);
|
||||
|
||||
touchEvents.cancel.emit(SCancelEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.touchID = E->touch_id
|
||||
.timeMs = E.timeMs,
|
||||
.touchID = E.touchID,
|
||||
});
|
||||
}, this, "CTouchDevice");
|
||||
});
|
||||
|
||||
hyprListener_frame.initCallback(&touch->events.frame, [this] (void* owner, void* data) {
|
||||
touchEvents.frame.emit();
|
||||
}, this, "CTouchDevice");
|
||||
listeners.frame = touch->events.frame.registerListener([this](std::any d) { touchEvents.frame.emit(); });
|
||||
|
||||
// clang-format on
|
||||
|
||||
deviceName = touch->base.name ? touch->base.name : "UNKNOWN";
|
||||
deviceName = touch->getName();
|
||||
}
|
||||
|
||||
bool CTouchDevice::isVirtual() {
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_touch* CTouchDevice::wlr() {
|
||||
return touch;
|
||||
}
|
||||
|
||||
void CTouchDevice::disconnectCallbacks() {
|
||||
hyprListener_destroy.removeCallback();
|
||||
hyprListener_down.removeCallback();
|
||||
hyprListener_up.removeCallback();
|
||||
hyprListener_motion.removeCallback();
|
||||
hyprListener_cancel.removeCallback();
|
||||
hyprListener_frame.removeCallback();
|
||||
SP<Aquamarine::ITouch> CTouchDevice::aq() {
|
||||
return touch.lock();
|
||||
}
|
||||
|
|
|
@ -4,22 +4,22 @@
|
|||
|
||||
class CTouchDevice : public ITouch {
|
||||
public:
|
||||
static SP<CTouchDevice> create(wlr_touch* touch);
|
||||
static SP<CTouchDevice> create(SP<Aquamarine::ITouch> touch);
|
||||
|
||||
virtual bool isVirtual();
|
||||
virtual wlr_touch* wlr();
|
||||
virtual bool isVirtual();
|
||||
virtual SP<Aquamarine::ITouch> aq();
|
||||
|
||||
private:
|
||||
CTouchDevice(wlr_touch* touch);
|
||||
CTouchDevice(SP<Aquamarine::ITouch> touch);
|
||||
|
||||
wlr_touch* touch = nullptr;
|
||||
WP<Aquamarine::ITouch> touch;
|
||||
|
||||
void disconnectCallbacks();
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(down);
|
||||
DYNLISTENER(up);
|
||||
DYNLISTENER(motion);
|
||||
DYNLISTENER(cancel);
|
||||
DYNLISTENER(frame);
|
||||
struct {
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener down;
|
||||
CHyprSignalListener up;
|
||||
CHyprSignalListener motion;
|
||||
CHyprSignalListener cancel;
|
||||
CHyprSignalListener frame;
|
||||
} listeners;
|
||||
};
|
|
@ -14,58 +14,42 @@ CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : keybo
|
|||
if (!keeb_)
|
||||
return;
|
||||
|
||||
auto keeb = keeb_->wlr();
|
||||
|
||||
// clang-format off
|
||||
hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) {
|
||||
disconnectCallbacks();
|
||||
listeners.destroy = keeb_->events.destroy.registerListener([this](std::any d) {
|
||||
keyboard.reset();
|
||||
events.destroy.emit();
|
||||
}, this, "CVirtualKeyboard");
|
||||
events.destroy.emit();
|
||||
});
|
||||
|
||||
hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_keyboard_key_event*)data;
|
||||
|
||||
keyboardEvents.key.emit(SKeyEvent{
|
||||
.timeMs = E->time_msec,
|
||||
.keycode = E->keycode,
|
||||
.updateMods = E->update_state,
|
||||
.state = E->state,
|
||||
listeners.key = keeb_->events.key.registerListener([this](std::any d) { keyboardEvents.key.emit(d); });
|
||||
listeners.modifiers = keeb_->events.modifiers.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<SModifiersEvent>(d);
|
||||
updateModifiers(E.depressed, E.latched, E.locked, E.group);
|
||||
keyboardEvents.modifiers.emit(SModifiersEvent{
|
||||
.depressed = modifiersState.depressed,
|
||||
.latched = modifiersState.latched,
|
||||
.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) {
|
||||
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";
|
||||
deviceName = keeb_->name;
|
||||
}
|
||||
|
||||
bool CVirtualKeyboard::isVirtual() {
|
||||
return true;
|
||||
}
|
||||
|
||||
wlr_keyboard* CVirtualKeyboard::wlr() {
|
||||
if (keyboard.expired())
|
||||
return nullptr;
|
||||
return keyboard->wlr();
|
||||
}
|
||||
|
||||
void CVirtualKeyboard::disconnectCallbacks() {
|
||||
hyprListener_destroy.removeCallback();
|
||||
hyprListener_key.removeCallback();
|
||||
hyprListener_keymap.removeCallback();
|
||||
hyprListener_repeatInfo.removeCallback();
|
||||
hyprListener_modifiers.removeCallback();
|
||||
SP<Aquamarine::IKeyboard> CVirtualKeyboard::aq() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wl_client* CVirtualKeyboard::getClient() {
|
||||
|
|
|
@ -6,23 +6,22 @@ class CVirtualKeyboardV1Resource;
|
|||
|
||||
class CVirtualKeyboard : public IKeyboard {
|
||||
public:
|
||||
static SP<CVirtualKeyboard> create(SP<CVirtualKeyboardV1Resource> keeb);
|
||||
static SP<CVirtualKeyboard> create(SP<CVirtualKeyboardV1Resource> keeb);
|
||||
|
||||
virtual bool isVirtual();
|
||||
virtual wlr_keyboard* wlr();
|
||||
virtual bool isVirtual();
|
||||
virtual SP<Aquamarine::IKeyboard> aq();
|
||||
|
||||
wl_client* getClient();
|
||||
wl_client* getClient();
|
||||
|
||||
private:
|
||||
CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb);
|
||||
|
||||
WP<CVirtualKeyboardV1Resource> keyboard;
|
||||
|
||||
void disconnectCallbacks();
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(key);
|
||||
DYNLISTENER(modifiers);
|
||||
DYNLISTENER(keymap);
|
||||
DYNLISTENER(repeatInfo);
|
||||
struct {
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener key;
|
||||
CHyprSignalListener modifiers;
|
||||
CHyprSignalListener keymap;
|
||||
} listeners;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "VirtualPointer.hpp"
|
||||
#include "../protocols/VirtualPointer.hpp"
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
|
||||
SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resource) {
|
||||
SP<CVirtualPointer> pPointer = SP<CVirtualPointer>(new CVirtualPointer(resource));
|
||||
|
@ -13,165 +14,37 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
|
|||
if (!resource->good())
|
||||
return;
|
||||
|
||||
auto mouse = resource->wlr();
|
||||
|
||||
// clang-format off
|
||||
hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) {
|
||||
disconnectCallbacks();
|
||||
listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) {
|
||||
pointer.reset();
|
||||
events.destroy.emit();
|
||||
}, this, "CVirtualPointer");
|
||||
});
|
||||
|
||||
hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) {
|
||||
auto E = (wlr_pointer_motion_event*)data;
|
||||
listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
|
||||
listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) {
|
||||
// we need to unpack the event and add our device here because it's required to calculate the position correctly
|
||||
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{
|
||||
.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";
|
||||
deviceName = pointer->name;
|
||||
}
|
||||
|
||||
bool CVirtualPointer::isVirtual() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void CVirtualPointer::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();
|
||||
}
|
||||
|
||||
wlr_pointer* CVirtualPointer::wlr() {
|
||||
if (pointer.expired())
|
||||
return nullptr;
|
||||
return pointer->wlr();
|
||||
SP<Aquamarine::IPointer> CVirtualPointer::aq() {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -6,33 +6,34 @@ class CVirtualPointerV1Resource;
|
|||
|
||||
class CVirtualPointer : public IPointer {
|
||||
public:
|
||||
static SP<CVirtualPointer> create(SP<CVirtualPointerV1Resource> resource);
|
||||
static SP<CVirtualPointer> create(SP<CVirtualPointerV1Resource> resource);
|
||||
|
||||
virtual bool isVirtual();
|
||||
virtual wlr_pointer* wlr();
|
||||
virtual bool isVirtual();
|
||||
virtual SP<Aquamarine::IPointer> aq();
|
||||
|
||||
private:
|
||||
CVirtualPointer(SP<CVirtualPointerV1Resource>);
|
||||
|
||||
WP<CVirtualPointerV1Resource> pointer;
|
||||
|
||||
void disconnectCallbacks();
|
||||
struct {
|
||||
CHyprSignalListener destroy;
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(motion);
|
||||
DYNLISTENER(motionAbsolute);
|
||||
DYNLISTENER(button);
|
||||
DYNLISTENER(axis);
|
||||
DYNLISTENER(frame);
|
||||
CHyprSignalListener motion;
|
||||
CHyprSignalListener motionAbsolute;
|
||||
CHyprSignalListener button;
|
||||
CHyprSignalListener axis;
|
||||
CHyprSignalListener frame;
|
||||
|
||||
DYNLISTENER(swipeBegin);
|
||||
DYNLISTENER(swipeEnd);
|
||||
DYNLISTENER(swipeUpdate);
|
||||
CHyprSignalListener swipeBegin;
|
||||
CHyprSignalListener swipeEnd;
|
||||
CHyprSignalListener swipeUpdate;
|
||||
|
||||
DYNLISTENER(pinchBegin);
|
||||
DYNLISTENER(pinchEnd);
|
||||
DYNLISTENER(pinchUpdate);
|
||||
CHyprSignalListener pinchBegin;
|
||||
CHyprSignalListener pinchEnd;
|
||||
CHyprSignalListener pinchUpdate;
|
||||
|
||||
DYNLISTENER(holdBegin);
|
||||
DYNLISTENER(holdEnd);
|
||||
CHyprSignalListener holdBegin;
|
||||
CHyprSignalListener holdEnd;
|
||||
} listeners;
|
||||
};
|
|
@ -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();
|
||||
}
|
|
@ -8,16 +8,6 @@
|
|||
//
|
||||
|
||||
namespace Events {
|
||||
// Monitor events
|
||||
LISTENER(change);
|
||||
LISTENER(newOutput);
|
||||
|
||||
// DRM events
|
||||
LISTENER(leaseRequest);
|
||||
|
||||
// Layer events
|
||||
LISTENER(newLayerSurface);
|
||||
|
||||
// Window events
|
||||
DYNLISTENFUNC(commitWindow);
|
||||
DYNLISTENFUNC(mapWindow);
|
||||
|
@ -35,15 +25,6 @@ namespace Events {
|
|||
DYNLISTENFUNC(setOverrideRedirect);
|
||||
DYNLISTENFUNC(ackConfigure);
|
||||
|
||||
LISTENER(newInput);
|
||||
|
||||
// Virt Ptr
|
||||
LISTENER(newVirtPtr);
|
||||
|
||||
// Various
|
||||
LISTENER(requestSetSel);
|
||||
LISTENER(requestSetPrimarySel);
|
||||
|
||||
// Monitor part 2 the sequel
|
||||
DYNLISTENFUNC(monitorFrame);
|
||||
DYNLISTENFUNC(monitorDestroy);
|
||||
|
@ -52,16 +33,4 @@ namespace Events {
|
|||
DYNLISTENFUNC(monitorNeedsFrame);
|
||||
DYNLISTENFUNC(monitorCommit);
|
||||
DYNLISTENFUNC(monitorBind);
|
||||
|
||||
// XWayland
|
||||
LISTENER(surfaceXWayland);
|
||||
|
||||
// Renderer destroy
|
||||
LISTENER(RendererDestroy);
|
||||
|
||||
// session
|
||||
LISTENER(sessionActive);
|
||||
|
||||
// Session Lock
|
||||
LISTENER(newSessionLock);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,9 @@
|
|||
#include "Events.hpp"
|
||||
#include "../debug/HyprCtl.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) {
|
||||
if (g_pCompositor->m_bExitTriggered) {
|
||||
// Only signal cleanup once
|
||||
g_pCompositor->m_bExitTriggered = false;
|
||||
g_pCompositor->cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
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!");
|
||||
|
||||
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) {
|
||||
const auto OUTPUT = (wlr_output*)data;
|
||||
|
||||
CMonitor* pMonitor = nullptr;
|
||||
CMonitor* pMonitor = (CMonitor*)owner;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
if (m->output == OUTPUT) {
|
||||
if (m->output == pMonitor->output) {
|
||||
pMonitor = m.get();
|
||||
break;
|
||||
}
|
||||
|
@ -188,9 +100,6 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
|||
|
||||
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->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; });
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
const auto PMONITOR = (CMonitor*)owner;
|
||||
|
||||
const auto E = (wlr_output_event_commit*)data;
|
||||
|
||||
if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
|
||||
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
|
||||
PROTO::screencopy->onOutputCommit(PMONITOR);
|
||||
PROTO::toplevelExport->onOutputCommit(PMONITOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../protocols/ToplevelExport.hpp"
|
||||
#include "../xwayland/XSurface.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
|
@ -196,8 +197,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
PWINDOW->m_bIsFloating = false;
|
||||
} else if (r.szRule.starts_with("pseudo")) {
|
||||
PWINDOW->m_bIsPseudotiled = true;
|
||||
} else if (r.szRule.starts_with("nofocus")) {
|
||||
PWINDOW->m_sAdditionalConfigData.noFocus = true;
|
||||
} else if (r.szRule.starts_with("noinitialfocus")) {
|
||||
PWINDOW->m_bNoInitialFocus = true;
|
||||
} else if (r.szRule.starts_with("suppressevent")) {
|
||||
|
@ -219,12 +218,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
overridingNoFullscreen = true;
|
||||
} else if (r.szRule == "fakefullscreen") {
|
||||
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") {
|
||||
PWINDOW->m_bPinned = true;
|
||||
} else if (r.szRule == "maximize") {
|
||||
|
@ -321,7 +314,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
workspaceSilent = false;
|
||||
}
|
||||
|
||||
PWINDOW->updateSpecialRenderData();
|
||||
PWINDOW->updateWindowData();
|
||||
|
||||
if (PWINDOW->m_bIsFloating) {
|
||||
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();
|
||||
|
||||
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) {
|
||||
PWINDOW->m_sAdditionalConfigData.noFocus = false;
|
||||
PWINDOW->m_bNoInitialFocus = false;
|
||||
PWINDOW->m_bX11ShouldntFocus = false;
|
||||
if (PWINDOW->m_sWindowData.allowsInput.valueOrDefault()) { // if default value wasn't set to false getPriority() would throw an exception
|
||||
PWINDOW->m_sWindowData.noFocus = CWindowOverridableVar(false, PWINDOW->m_sWindowData.allowsInput.getPriority());
|
||||
PWINDOW->m_bNoInitialFocus = false;
|
||||
PWINDOW->m_bX11ShouldntFocus = false;
|
||||
}
|
||||
|
||||
// check LS focus grab
|
||||
|
@ -473,18 +466,20 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
PWINDOW->m_bNoInitialFocus = true;
|
||||
else if (*PNEWTAKESOVERFS == 2)
|
||||
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;
|
||||
else
|
||||
if (*PNEWTAKESOVERFS == 1)
|
||||
overridingNoMaximize = true;
|
||||
} else
|
||||
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) &&
|
||||
!g_pInputManager->isConstrained()) {
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
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 {
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(0);
|
||||
|
@ -586,6 +581,11 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
|||
|
||||
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) {
|
||||
Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW);
|
||||
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)});
|
||||
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW);
|
||||
PROTO::toplevelExport->onWindowUnmap(PWINDOW);
|
||||
|
||||
if (PWINDOW->m_bIsFullscreen)
|
||||
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);
|
||||
|
||||
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE)
|
||||
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) {
|
||||
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
|
||||
if (*PEXITRETAINSFS && CURRENTWINDOWFSSTATE)
|
||||
g_pCompositor->setWindowFullscreen(PWINDOWCANDIDATE, true, CURRENTWINDOWFSMODE);
|
||||
}
|
||||
|
||||
if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0)
|
||||
g_pInputManager->refocus();
|
||||
|
@ -700,12 +703,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
|||
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_bIsX11)
|
||||
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();
|
||||
}
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
|
||||
|
||||
if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) {
|
||||
const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize;
|
||||
|
|
43
src/helpers/CursorShapes.hpp
Normal file
43
src/helpers/CursorShapes.hpp
Normal 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
|
|
@ -3,6 +3,8 @@
|
|||
#include "../includes.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include <xf86drm.h>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
/*
|
||||
DRM formats are LE, while OGL is BE. The two primary formats
|
||||
|
@ -309,3 +311,17 @@ uint32_t FormatUtils::glFormatToType(uint32_t gl) {
|
|||
#endif
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "math/Math.hpp"
|
||||
#include <aquamarine/backend/Misc.hpp>
|
||||
|
||||
typedef uint32_t DRMFormat;
|
||||
typedef uint32_t SHMFormat;
|
||||
|
@ -18,10 +20,7 @@ struct SPixelFormat {
|
|||
Vector2D blockSize;
|
||||
};
|
||||
|
||||
struct SDRMFormat {
|
||||
uint32_t format = 0;
|
||||
std::vector<uint64_t> mods;
|
||||
};
|
||||
typedef Aquamarine::SDRMFormat SDRMFormat;
|
||||
|
||||
namespace FormatUtils {
|
||||
SHMFormat drmToShm(DRMFormat drm);
|
||||
|
@ -34,4 +33,6 @@ namespace FormatUtils {
|
|||
int minStride(const SPixelFormat* const fmt, int32_t width);
|
||||
uint32_t drmFormatToGL(DRMFormat drm);
|
||||
uint32_t glFormatToType(uint32_t gl);
|
||||
std::string drmFormatName(DRMFormat drm);
|
||||
std::string drmModifierName(uint64_t mod);
|
||||
};
|
||||
|
|
|
@ -4,9 +4,12 @@
|
|||
#include "../Compositor.hpp"
|
||||
#include "../managers/TokenManager.hpp"
|
||||
#include <optional>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <iomanip>
|
||||
#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) {
|
||||
#if defined(KERN_PROC_PID)
|
||||
int mib[] = {
|
||||
CTL_KERN,
|
||||
KERN_PROC,
|
||||
KERN_PROC_PID,
|
||||
(int)pid,
|
||||
CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid,
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
sizeof(KINFO_PROC),
|
||||
1,
|
||||
sizeof(KINFO_PROC), 1,
|
||||
#endif
|
||||
};
|
||||
u_int miblen = sizeof(mib) / sizeof(mib[0]);
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include <optional>
|
||||
#include <string>
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include "math/Math.hpp"
|
||||
#include <vector>
|
||||
#include <format>
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
#include "Monitor.hpp"
|
||||
#include "MiscFunctions.hpp"
|
||||
#include "math/Math.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../protocols/GammaControl.hpp"
|
||||
#include "../devices/ITouch.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/PresentationTime.hpp"
|
||||
#include "../protocols/DRMLease.hpp"
|
||||
#include "../protocols/core/Output.hpp"
|
||||
#include "../managers/PointerManager.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "sync/SyncTimeline.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
|
@ -21,62 +27,73 @@ CMonitor::CMonitor() : state(this) {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
wlr_output_state_set_enabled(state.wlr(), true);
|
||||
output->state->setEnabled(true);
|
||||
state.commit();
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
std::erase(szDescription, ',');
|
||||
|
||||
// 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, ',');
|
||||
|
||||
if (!wlr_backend_is_drm(output->backend))
|
||||
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
|
||||
if (output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM)
|
||||
createdByUser = true; // should be true. WL and Headless backends should be addable / removable
|
||||
|
||||
// get monitor rule that matches
|
||||
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
|
||||
|
@ -84,54 +101,23 @@ void CMonitor::onConnect(bool noRule) {
|
|||
// if it's disabled, disable and ignore
|
||||
if (monitorRule.disabled) {
|
||||
|
||||
wlr_output_state_set_scale(state.wlr(), 1);
|
||||
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);
|
||||
output->state->setEnabled(false);
|
||||
|
||||
if (!state.commit())
|
||||
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
|
||||
|
||||
m_bEnabled = false;
|
||||
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
listeners.frame.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (output->non_desktop) {
|
||||
if (output->nonDesktop) {
|
||||
Debug::log(LOG, "Not configuring non-desktop output");
|
||||
if (g_pCompositor->m_sWRLDRMLeaseMgr) {
|
||||
wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (PROTO::lease)
|
||||
PROTO::lease->offer(self.lock());
|
||||
|
||||
if (!m_bRenderingInitPassed) {
|
||||
output->allocator = nullptr;
|
||||
output->renderer = nullptr;
|
||||
wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
|
||||
m_bRenderingInitPassed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
SP<CMonitor>* thisWrapper = nullptr;
|
||||
|
@ -151,18 +137,18 @@ void CMonitor::onConnect(bool noRule) {
|
|||
|
||||
m_bEnabled = true;
|
||||
|
||||
wlr_output_state_set_enabled(state.wlr(), 1);
|
||||
output->state->setEnabled(true);
|
||||
|
||||
// set mode, also applies
|
||||
if (!noRule)
|
||||
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -214,7 +200,7 @@ void CMonitor::onConnect(bool noRule) {
|
|||
|
||||
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);
|
||||
|
||||
|
@ -261,12 +247,10 @@ void CMonitor::onDisconnect(bool destroy) {
|
|||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
}
|
||||
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
hyprListener_monitorPresented.removeCallback();
|
||||
hyprListener_monitorDamage.removeCallback();
|
||||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
listeners.frame.reset();
|
||||
listeners.presented.reset();
|
||||
listeners.needsFrame.reset();
|
||||
listeners.commit.reset();
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
for (auto& ls : m_aLayerSurfaceLayers[i]) {
|
||||
|
@ -316,10 +300,10 @@ void CMonitor::onDisconnect(bool destroy) {
|
|||
activeWorkspace->m_bVisible = false;
|
||||
activeWorkspace.reset();
|
||||
|
||||
wlr_output_state_set_enabled(state.wlr(), false);
|
||||
output->state->setEnabled(false);
|
||||
|
||||
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)
|
||||
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");
|
||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
|
||||
damage.damageEntire();
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
} else if (damage.damage(rg))
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
}
|
||||
|
||||
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");
|
||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
|
||||
damage.damageEntire();
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
}
|
||||
|
||||
if (damage.damage(*box))
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
}
|
||||
|
||||
bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
|
||||
|
@ -369,8 +353,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
|
|||
static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate");
|
||||
|
||||
// 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 &&
|
||||
activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
|
||||
bool shouldSkip =
|
||||
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
|
||||
|
||||
// keep requested minimum refresh rate
|
||||
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
|
||||
|
@ -563,7 +547,7 @@ float CMonitor::getDefaultScale() {
|
|||
static constexpr double MMPERINCH = 25.4;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -767,11 +751,11 @@ Vector2D CMonitor::middle() {
|
|||
}
|
||||
|
||||
void CMonitor::updateMatrix() {
|
||||
wlr_matrix_identity(projMatrix.data());
|
||||
matrixIdentity(projMatrix.data());
|
||||
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
|
||||
wlr_matrix_translate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
|
||||
wlr_matrix_transform(projMatrix.data(), transform);
|
||||
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
|
||||
matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
|
||||
matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform));
|
||||
matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -787,31 +771,124 @@ CBox CMonitor::logicalBox() {
|
|||
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) {
|
||||
m_pOwner = owner;
|
||||
wlr_output_state_init(&m_state);
|
||||
}
|
||||
|
||||
CMonitorState::~CMonitorState() {
|
||||
wlr_output_state_finish(&m_state);
|
||||
;
|
||||
}
|
||||
|
||||
wlr_output_state* CMonitorState::wlr() {
|
||||
return &m_state;
|
||||
}
|
||||
void CMonitorState::ensureBufferPresent() {
|
||||
if (!m_pOwner->output->state->state().enabled) {
|
||||
Debug::log(TRACE, "CMonitorState::ensureBufferPresent: Ignoring, monitor is not enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
void CMonitorState::clear() {
|
||||
wlr_output_state_finish(&m_state);
|
||||
m_state = {0};
|
||||
wlr_output_state_init(&m_state);
|
||||
if (m_pOwner->output->state->state().buffer)
|
||||
return;
|
||||
|
||||
// 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 ret = wlr_output_commit_state(m_pOwner->output, &m_state);
|
||||
clear();
|
||||
if (!updateSwapchain())
|
||||
return false;
|
||||
|
||||
ensureBufferPresent();
|
||||
|
||||
bool ret = m_pOwner->output->commit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <optional>
|
||||
#include "signal/Signal.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 eAutoDirs {
|
||||
|
@ -38,22 +40,21 @@ struct SMonitorRule {
|
|||
};
|
||||
|
||||
class CMonitor;
|
||||
class CSyncTimeline;
|
||||
|
||||
// Class for wrapping the wlr state
|
||||
class CMonitorState {
|
||||
public:
|
||||
CMonitorState(CMonitor* owner);
|
||||
~CMonitorState();
|
||||
|
||||
wlr_output_state* wlr();
|
||||
void clear();
|
||||
// commit() will also clear()
|
||||
bool commit();
|
||||
bool test();
|
||||
bool updateSwapchain();
|
||||
|
||||
private:
|
||||
wlr_output_state m_state = {0};
|
||||
CMonitor* m_pOwner;
|
||||
void ensureBufferPresent();
|
||||
|
||||
CMonitor* m_pOwner;
|
||||
};
|
||||
|
||||
class CMonitor {
|
||||
|
@ -61,61 +62,69 @@ class CMonitor {
|
|||
CMonitor();
|
||||
~CMonitor();
|
||||
|
||||
Vector2D vecPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecSize = Vector2D(0, 0);
|
||||
Vector2D vecPixelSize = Vector2D(0, 0);
|
||||
Vector2D vecTransformedSize = Vector2D(0, 0);
|
||||
Vector2D vecPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecSize = Vector2D(0, 0);
|
||||
Vector2D vecPixelSize = Vector2D(0, 0);
|
||||
Vector2D vecTransformedSize = Vector2D(0, 0);
|
||||
|
||||
bool primary = false;
|
||||
bool primary = false;
|
||||
|
||||
uint64_t ID = -1;
|
||||
PHLWORKSPACE activeWorkspace = nullptr;
|
||||
PHLWORKSPACE activeSpecialWorkspace = nullptr;
|
||||
float setScale = 1; // scale set by cfg
|
||||
float scale = 1; // real scale
|
||||
uint64_t ID = -1;
|
||||
PHLWORKSPACE activeWorkspace = nullptr;
|
||||
PHLWORKSPACE activeSpecialWorkspace = nullptr;
|
||||
float setScale = 1; // scale set by cfg
|
||||
float scale = 1; // real scale
|
||||
|
||||
std::string szName = "";
|
||||
std::string szDescription = "";
|
||||
std::string szShortDescription = "";
|
||||
std::string szName = "";
|
||||
std::string szDescription = "";
|
||||
std::string szShortDescription = "";
|
||||
|
||||
Vector2D vecReservedTopLeft = Vector2D(0, 0);
|
||||
Vector2D vecReservedBottomRight = Vector2D(0, 0);
|
||||
Vector2D vecReservedTopLeft = Vector2D(0, 0);
|
||||
Vector2D vecReservedBottomRight = Vector2D(0, 0);
|
||||
|
||||
drmModeModeInfo customDrmMode = {};
|
||||
drmModeModeInfo customDrmMode = {};
|
||||
|
||||
CMonitorState state;
|
||||
CDamageRing damage;
|
||||
CMonitorState state;
|
||||
CDamageRing damage;
|
||||
|
||||
wlr_output* output = nullptr;
|
||||
float refreshRate = 60;
|
||||
int framesToSkip = 0;
|
||||
int forceFullFrames = 0;
|
||||
bool noFrameSchedule = false;
|
||||
bool scheduledRecalc = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
float xwaylandScale = 1.f;
|
||||
std::array<float, 9> projMatrix = {0};
|
||||
std::optional<Vector2D> forceSize;
|
||||
wlr_output_mode* currentMode = nullptr;
|
||||
SP<Aquamarine::IOutput> output;
|
||||
float refreshRate = 60;
|
||||
int framesToSkip = 0;
|
||||
int forceFullFrames = 0;
|
||||
bool noFrameSchedule = false;
|
||||
bool scheduledRecalc = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
float xwaylandScale = 1.f;
|
||||
std::array<float, 9> projMatrix = {0};
|
||||
std::optional<Vector2D> forceSize;
|
||||
SP<Aquamarine::SOutputMode> currentMode;
|
||||
SP<Aquamarine::CSwapchain> cursorSwapchain;
|
||||
|
||||
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 enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
bool createdByUser = false;
|
||||
uint32_t drmFormat = DRM_FORMAT_INVALID;
|
||||
bool isUnsafeFallback = false;
|
||||
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 enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
bool createdByUser = false;
|
||||
bool isUnsafeFallback = false;
|
||||
|
||||
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||
bool renderingActive = false;
|
||||
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||
bool renderingActive = false;
|
||||
|
||||
wl_event_source* renderTimer = nullptr; // for RAT
|
||||
bool RATScheduled = false;
|
||||
CTimer lastPresentationTimer;
|
||||
wl_event_source* renderTimer = nullptr; // for RAT
|
||||
bool RATScheduled = false;
|
||||
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
|
||||
CMonitor* pMirrorOf = nullptr;
|
||||
|
@ -124,6 +133,9 @@ class CMonitor {
|
|||
// for tearing
|
||||
PHLWINDOWREF solitaryClient;
|
||||
|
||||
// for direct scanout
|
||||
PHLWINDOWREF lastScanout;
|
||||
|
||||
struct {
|
||||
bool canTear = false;
|
||||
bool nextRenderTorn = false;
|
||||
|
@ -143,15 +155,6 @@ class CMonitor {
|
|||
|
||||
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
|
||||
void onConnect(bool noRule);
|
||||
void onDisconnect(bool destroy = false);
|
||||
|
@ -173,6 +176,8 @@ class CMonitor {
|
|||
int64_t activeWorkspaceID();
|
||||
int64_t activeSpecialWorkspaceID();
|
||||
CBox logicalBox();
|
||||
void scheduleDone();
|
||||
bool attemptDirectScanout();
|
||||
|
||||
bool m_bEnabled = false;
|
||||
bool m_bRenderingInitPassed = false;
|
||||
|
@ -184,6 +189,17 @@ class CMonitor {
|
|||
}
|
||||
|
||||
private:
|
||||
void setupDefaultWS(const SMonitorRule&);
|
||||
int findAvailableDefaultWS();
|
||||
void setupDefaultWS(const SMonitorRule&);
|
||||
int findAvailableDefaultWS();
|
||||
|
||||
wl_event_source* doneSource = nullptr;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener frame;
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener state;
|
||||
CHyprSignalListener needsFrame;
|
||||
CHyprSignalListener presented;
|
||||
CHyprSignalListener commit;
|
||||
} listeners;
|
||||
};
|
||||
|
|
|
@ -15,6 +15,8 @@ class IPointer;
|
|||
class IKeyboard;
|
||||
class CWLSurfaceResource;
|
||||
|
||||
AQUAMARINE_FORWARD(ISwitch);
|
||||
|
||||
struct SRenderData {
|
||||
CMonitor* pMonitor;
|
||||
timespec* when;
|
||||
|
@ -70,14 +72,14 @@ struct SSwipeGesture {
|
|||
};
|
||||
|
||||
struct SSwitchDevice {
|
||||
wlr_input_device* pWlrDevice = nullptr;
|
||||
WP<Aquamarine::ISwitch> pDevice;
|
||||
|
||||
int status = -1; // uninitialized
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(toggle);
|
||||
struct {
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener fire;
|
||||
} listeners;
|
||||
|
||||
bool operator==(const SSwitchDevice& other) const {
|
||||
return pWlrDevice == other.pWlrDevice;
|
||||
return pDevice == other.pDevice;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
inline bool wlr_backend_is_x11(void*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void wlr_x11_output_create(void*) {}
|
|
@ -17,14 +17,14 @@ Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) {
|
|||
return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL;
|
||||
}
|
||||
|
||||
static void matrixIdentity(float mat[9]) {
|
||||
void matrixIdentity(float mat[9]) {
|
||||
static const float identity[9] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
memcpy(mat, identity, sizeof(identity));
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void matrixTranspose(float mat[9], const float a[9]) {
|
||||
void matrixTranspose(float mat[9], const float a[9]) {
|
||||
float transposition[9] = {
|
||||
a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8],
|
||||
};
|
||||
memcpy(mat, transposition, sizeof(transposition));
|
||||
}
|
||||
|
||||
static void matrixTranslate(float mat[9], float x, float y) {
|
||||
void matrixTranslate(float mat[9], float x, float y) {
|
||||
float translate[9] = {
|
||||
1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
matrixMultiply(mat, mat, translate);
|
||||
}
|
||||
|
||||
static void matrixScale(float mat[9], float x, float y) {
|
||||
void matrixScale(float mat[9], float x, float y) {
|
||||
float scale[9] = {
|
||||
x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
matrixMultiply(mat, mat, scale);
|
||||
}
|
||||
|
||||
static void matrixRotate(float mat[9], float rad) {
|
||||
void matrixRotate(float mat[9], float rad) {
|
||||
float rotate[9] = {
|
||||
cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
matrixMultiply(mat, mat, rotate);
|
||||
}
|
||||
|
||||
static std::unordered_map<eTransform, std::array<float, 9>> transforms = {
|
||||
{HYPRUTILS_TRANSFORM_NORMAL,
|
||||
{
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_90,
|
||||
{
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_180,
|
||||
{
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_270,
|
||||
{
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED,
|
||||
{
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_90,
|
||||
{
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_180,
|
||||
{
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_270,
|
||||
{
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
};
|
||||
|
||||
static void matrixTransform(float mat[9], eTransform transform) {
|
||||
matrixMultiply(mat, mat, transforms.at(transform).data());
|
||||
const std::unordered_map<eTransform, std::array<float, 9>>& getTransforms() {
|
||||
static std::unordered_map<eTransform, std::array<float, 9>> transforms = {
|
||||
{HYPRUTILS_TRANSFORM_NORMAL, {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_90, {0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_180, {-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_270, {0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED, {-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_90, {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_180, {1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_270, {0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
};
|
||||
return transforms;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
const float* t = transforms.at(transform).data();
|
||||
const float* t = getTransforms().at(transform).data();
|
||||
float x = 2.0f / width;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -7,5 +7,14 @@
|
|||
|
||||
using namespace Hyprutils::Math;
|
||||
|
||||
eTransform wlTransformToHyprutils(wl_output_transform t);
|
||||
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]);
|
||||
eTransform wlTransformToHyprutils(wl_output_transform t);
|
||||
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]);
|
||||
void matrixProjection(float mat[9], int width, int height, eTransform transform);
|
||||
void matrixTransform(float mat[9], eTransform transform);
|
||||
void matrixRotate(float mat[9], float rad);
|
||||
void matrixScale(float mat[9], float x, float y);
|
||||
void matrixTranslate(float mat[9], float x, float y);
|
||||
void matrixTranspose(float mat[9], const float a[9]);
|
||||
void matrixMultiply(float mat[9], const float a[9], const float b[9]);
|
||||
void matrixIdentity(float mat[9]);
|
||||
wl_output_transform invertTransform(wl_output_transform tr);
|
||||
|
|
190
src/helpers/sync/SyncTimeline.cpp
Normal file
190
src/helpers/sync/SyncTimeline.cpp
Normal 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;
|
||||
}
|
47
src/helpers/sync/SyncTimeline.hpp
Normal file
47
src/helpers/sync/SyncTimeline.hpp
Normal 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;
|
||||
};
|
|
@ -16,78 +16,6 @@
|
|||
#include <time.h>
|
||||
#include <unistd.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
|
||||
#include <GLES2/gl2.h>
|
||||
|
@ -99,10 +27,6 @@ extern "C" {
|
|||
#include <GLES3/gl3ext.h>
|
||||
#endif
|
||||
|
||||
#if !WLR_HAS_X11_BACKEND
|
||||
#include "helpers/X11Stubs.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef NO_XWAYLAND
|
||||
#define XWAYLAND false
|
||||
#else
|
||||
|
|
|
@ -139,7 +139,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
|||
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
|
||||
return;
|
||||
|
||||
PWINDOW->updateSpecialRenderData();
|
||||
PWINDOW->unsetWindowData(PRIORITY_LAYOUT);
|
||||
PWINDOW->updateWindowData();
|
||||
|
||||
static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("dwindle:no_gaps_when_only");
|
||||
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
|
||||
|
@ -160,10 +161,10 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
|||
if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() &&
|
||||
(NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
|
||||
|
||||
PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2);
|
||||
PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true);
|
||||
PWINDOW->m_sSpecialRenderData.rounding = false;
|
||||
PWINDOW->m_sSpecialRenderData.shadow = false;
|
||||
PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT);
|
||||
PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT);
|
||||
PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT);
|
||||
PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
|
@ -496,7 +497,8 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
|
|||
return;
|
||||
}
|
||||
|
||||
pWindow->updateSpecialRenderData();
|
||||
pWindow->unsetWindowData(PRIORITY_LAYOUT);
|
||||
pWindow->updateWindowData();
|
||||
|
||||
if (pWindow->m_bIsFullscreen)
|
||||
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_vRealSize = pWindow->m_vLastFloatingSize;
|
||||
|
||||
pWindow->updateSpecialRenderData();
|
||||
pWindow->unsetWindowData(PRIORITY_LAYOUT);
|
||||
pWindow->updateWindowData();
|
||||
}
|
||||
} else {
|
||||
// if it now got fullscreen, make it fullscreen
|
||||
|
|
|
@ -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) {
|
||||
if (DRAGGINGWINDOW->m_bIsFloating) {
|
||||
|
||||
Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sAdditionalConfigData.minSize.toUnderlying());
|
||||
Vector2D MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, DRAGGINGWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying());
|
||||
Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sWindowData.minSize.valueOr(Vector2D(20, 20)));
|
||||
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 newPos = m_vBeginDragPositionXY;
|
||||
|
@ -403,7 +407,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
|
|||
|
||||
if ((m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1) &&
|
||||
(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;
|
||||
|
||||
|
@ -538,7 +542,8 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
|
|||
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
|
||||
|
||||
pWindow->updateSpecialRenderData();
|
||||
pWindow->unsetWindowData(PRIORITY_LAYOUT);
|
||||
pWindow->updateWindowData();
|
||||
|
||||
if (pWindow == m_pLastTiledWindow)
|
||||
m_pLastTiledWindow.reset();
|
||||
|
@ -587,7 +592,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) {
|
|||
// find whether there is a floating window below this one
|
||||
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 &&
|
||||
!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,
|
||||
w->m_vPosition.y + w->m_vSize.y)) {
|
||||
return w;
|
||||
|
@ -607,7 +612,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) {
|
|||
// if not, floating window
|
||||
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 &&
|
||||
!w->m_sAdditionalConfigData.noFocus && w != pWindow)
|
||||
!w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow)
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
@ -264,7 +264,8 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
|
|||
const auto MASTERSLEFT = getMastersOnWorkspace(WORKSPACEID);
|
||||
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);
|
||||
|
||||
|
@ -646,7 +647,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
|||
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
|
||||
return;
|
||||
|
||||
PWINDOW->updateSpecialRenderData();
|
||||
PWINDOW->unsetWindowData(PRIORITY_LAYOUT);
|
||||
PWINDOW->updateWindowData();
|
||||
|
||||
static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("master:no_gaps_when_only");
|
||||
static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
|
||||
|
@ -669,10 +671,10 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
|||
if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() &&
|
||||
(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_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true);
|
||||
PWINDOW->m_sSpecialRenderData.rounding = false;
|
||||
PWINDOW->m_sSpecialRenderData.shadow = false;
|
||||
PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT);
|
||||
PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT);
|
||||
PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT);
|
||||
PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
|
@ -922,7 +924,8 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscree
|
|||
pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition;
|
||||
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
|
||||
|
||||
pWindow->updateSpecialRenderData();
|
||||
pWindow->unsetWindowData(PRIORITY_LAYOUT);
|
||||
pWindow->updateWindowData();
|
||||
}
|
||||
} else {
|
||||
// if it now got fullscreen, make it fullscreen
|
||||
|
|
|
@ -40,8 +40,7 @@
|
|||
|
||||
#define STICKS(a, b) abs((a) - (b)) < 2
|
||||
|
||||
#define HYPRATOM(name) \
|
||||
{ name, 0 }
|
||||
#define HYPRATOM(name) {name, 0}
|
||||
|
||||
#define RASSERT(expr, reason, ...) \
|
||||
if (!(expr)) { \
|
||||
|
@ -106,3 +105,8 @@
|
|||
class name; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AQUAMARINE_FORWARD(name) \
|
||||
namespace Aquamarine { \
|
||||
class name; \
|
||||
}
|
||||
|
|
50
src/main.cpp
50
src/main.cpp
|
@ -4,6 +4,7 @@
|
|||
#include "config/ConfigManager.hpp"
|
||||
#include "init/initHelpers.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
@ -16,6 +17,8 @@ void help() {
|
|||
std::cout << "\nArguments:\n";
|
||||
std::cout << " --help -h - Show this message again\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";
|
||||
}
|
||||
|
||||
|
@ -37,6 +40,8 @@ int main(int argc, char** argv) {
|
|||
|
||||
// parse some args
|
||||
std::string configPath;
|
||||
std::string socketName;
|
||||
int socketFd = -1;
|
||||
bool ignoreSudo = false;
|
||||
|
||||
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";
|
||||
|
||||
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) {
|
||||
if (std::next(it) == args.end()) {
|
||||
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";
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
// let's init the compositor.
|
||||
|
@ -105,7 +147,7 @@ int main(int argc, char** argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
g_pCompositor->initServer();
|
||||
g_pCompositor->initServer(socketName, socketFd);
|
||||
|
||||
if (!envEnabled("HYPRLAND_NO_RT"))
|
||||
Init::gainRealTime();
|
||||
|
@ -115,11 +157,9 @@ int main(int argc, char** argv) {
|
|||
// If all's good to go, start.
|
||||
g_pCompositor->startCompositor();
|
||||
|
||||
g_pCompositor->m_bIsShuttingDown = true;
|
||||
g_pCompositor->cleanup();
|
||||
|
||||
// If we are here it means we got yote.
|
||||
Debug::log(LOG, "Hyprland reached the end.");
|
||||
g_pCompositor.reset();
|
||||
Debug::log(LOG, "Hyprland has reached the end.");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ void CAnimationManager::tick() {
|
|||
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
if (!PMONITOR)
|
||||
continue;
|
||||
animationsDisabled = animationsDisabled || PWINDOW->m_sAdditionalConfigData.forceNoAnims;
|
||||
animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled);
|
||||
} else if (PWORKSPACE) {
|
||||
PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
|
||||
if (!PMONITOR)
|
||||
|
@ -259,7 +259,7 @@ void CAnimationManager::tick() {
|
|||
|
||||
// manually schedule a frame
|
||||
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.
|
||||
|
@ -407,18 +407,19 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) {
|
|||
if (!pWindow->m_vRealPosition.m_pConfig->pValues->internalEnabled)
|
||||
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
|
||||
if (pWindow->m_sAdditionalConfigData.animationStyle.starts_with("slide")) {
|
||||
CVarList animList2(pWindow->m_sAdditionalConfigData.animationStyle, 0, 's');
|
||||
if (STYLE.starts_with("slide")) {
|
||||
CVarList animList2(STYLE, 0, 's');
|
||||
animationSlide(pWindow, animList2[1], close);
|
||||
} else {
|
||||
// anim popin, fallback
|
||||
|
||||
float minPerc = 0.f;
|
||||
if (pWindow->m_sAdditionalConfigData.animationStyle.find("%") != std::string::npos) {
|
||||
if (STYLE.find("%") != std::string::npos) {
|
||||
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));
|
||||
} catch (std::exception& e) {
|
||||
; // oops
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
#include "../config/ConfigValue.hpp"
|
||||
#include "PointerManager.hpp"
|
||||
#include "../xwayland/XWayland.hpp"
|
||||
#include <cstring>
|
||||
#include "../helpers/CursorShapes.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
}
|
||||
|
||||
static int cursorAnimTimer(void* data) {
|
||||
|
@ -45,8 +46,7 @@ CCursorManager::CCursorManager() {
|
|||
if (m_iSize == 0)
|
||||
m_iSize = 24;
|
||||
|
||||
m_pWLRXCursorMgr = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"), m_iSize);
|
||||
wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0);
|
||||
xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "", m_iSize * std::ceil(m_fCursorScale));
|
||||
|
||||
m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr);
|
||||
|
||||
|
@ -56,9 +56,6 @@ CCursorManager::CCursorManager() {
|
|||
}
|
||||
|
||||
CCursorManager::~CCursorManager() {
|
||||
if (m_pWLRXCursorMgr)
|
||||
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
|
||||
|
||||
if (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; });
|
||||
}
|
||||
|
||||
static void cursorBufferDestroy(struct wlr_buffer* wlr_buffer) {
|
||||
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
|
||||
g_pCursorManager->dropBufferRef(buffer->parent);
|
||||
CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
|
||||
surface = surf;
|
||||
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::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
|
||||
|
||||
if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE)
|
||||
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(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
|
||||
pixelData = pixelData_;
|
||||
size = size_;
|
||||
stride = 4 * size_.x;
|
||||
}
|
||||
|
||||
CCursorManager::CCursorBuffer::~CCursorBuffer() {
|
||||
; // will be freed in .destroy
|
||||
;
|
||||
}
|
||||
|
||||
wlr_buffer* CCursorManager::getCursorBuffer() {
|
||||
return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr;
|
||||
Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() {
|
||||
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) {
|
||||
|
@ -127,34 +131,24 @@ void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotsp
|
|||
}
|
||||
|
||||
void CCursorManager::setXCursor(const std::string& name) {
|
||||
if (!m_pWLRXCursorMgr) {
|
||||
g_pPointerManager->resetCursorImage();
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
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.");
|
||||
if (!xcursor.themeLoaded) {
|
||||
Debug::log(ERR, "XCursor failed to find theme in setXCursor");
|
||||
g_pPointerManager->resetCursorImage();
|
||||
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(
|
||||
std::make_unique<CCursorBuffer>(image->buffer, Vector2D{(int)image->width, (int)image->height}, Vector2D{(double)image->hotspot_x, (double)image->hotspot_y}));
|
||||
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot));
|
||||
|
||||
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)
|
||||
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
|
||||
dropBufferRef(m_vCursorBuffers.at(0).get());
|
||||
|
||||
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,
|
||||
Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
|
||||
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
|
||||
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].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
|
||||
|
||||
g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale,
|
||||
m_fCursorScale);
|
||||
if (m_vCursorBuffers.size() > 1)
|
||||
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
|
||||
dropBufferRef(m_vCursorBuffers.at(0).get());
|
||||
|
||||
m_bOurBufferConnected = true;
|
||||
|
||||
|
@ -225,7 +219,7 @@ void CCursorManager::tickAnimatedCursor() {
|
|||
if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size())
|
||||
m_iCurrentAnimationFrame = 0;
|
||||
|
||||
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(
|
||||
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>(
|
||||
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].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}));
|
||||
|
@ -256,10 +250,9 @@ void CCursorManager::setXWaylandCursor() {
|
|||
if (CURSOR.surface) {
|
||||
g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size},
|
||||
{CURSOR.hotspotX, CURSOR.hotspotY});
|
||||
} else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) {
|
||||
g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {(int)XCURSOR->images[0]->width, (int)XCURSOR->images[0]->height},
|
||||
{(double)XCURSOR->images[0]->hotspot_x, (double)XCURSOR->images[0]->hotspot_y});
|
||||
} else
|
||||
} else if (xcursor.themeLoaded)
|
||||
g_pXWayland->setCursor((uint8_t*)xcursor.defaultCursor->pixels.data(), xcursor.defaultCursor->size.x * 4, xcursor.defaultCursor->size, xcursor.defaultCursor->hotspot);
|
||||
else
|
||||
Debug::log(ERR, "CursorManager: no valid cursor for xwayland");
|
||||
}
|
||||
|
||||
|
@ -284,7 +277,7 @@ void CCursorManager::updateTheme() {
|
|||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
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);
|
||||
|
||||
if (m_pWLRXCursorMgr)
|
||||
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
|
||||
xcursor.loadTheme(name, size);
|
||||
|
||||
m_pWLRXCursorMgr = wlr_xcursor_manager_create(name.empty() ? "" : name.c_str(), size);
|
||||
bool xSuccess = wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0) == 1;
|
||||
m_szTheme = name;
|
||||
m_iSize = size;
|
||||
updateTheme();
|
||||
return true;
|
||||
}
|
||||
|
||||
// this basically checks if xcursor changed used theme to default but better
|
||||
bool diffTheme = false;
|
||||
wlr_xcursor_manager_theme* theme;
|
||||
wl_list_for_each(theme, &m_pWLRXCursorMgr->scaled_themes, link) {
|
||||
if (std::string{theme->theme->name} != name) {
|
||||
diffTheme = true;
|
||||
break;
|
||||
// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c
|
||||
// however modified to fit wayland cursor shape names better.
|
||||
// _ -> -
|
||||
// clang-format off
|
||||
static std::array<const char*, 77> XCURSOR_STANDARD_NAMES = {
|
||||
"X_cursor",
|
||||
"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) {
|
||||
m_szTheme = name;
|
||||
m_iSize = size;
|
||||
updateTheme();
|
||||
return true;
|
||||
defaultCursor = makeShared<SXCursor>();
|
||||
defaultCursor->size = {(int)img->width, (int)img->height};
|
||||
defaultCursor->hotspot = {(int)img->xhot, (int)img->yhot};
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -6,47 +6,51 @@
|
|||
#include "../includes.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include <aquamarine/buffer/Buffer.hpp>
|
||||
|
||||
struct wlr_buffer;
|
||||
struct wlr_xcursor_manager;
|
||||
class CWLSurface;
|
||||
|
||||
AQUAMARINE_FORWARD(IBuffer);
|
||||
|
||||
class CCursorManager {
|
||||
public:
|
||||
CCursorManager();
|
||||
~CCursorManager();
|
||||
|
||||
wlr_buffer* getCursorBuffer();
|
||||
SP<Aquamarine::IBuffer> getCursorBuffer();
|
||||
|
||||
void setCursorFromName(const std::string& name);
|
||||
void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot);
|
||||
void setXCursor(const std::string& name);
|
||||
void setCursorFromName(const std::string& name);
|
||||
void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot);
|
||||
void setXCursor(const std::string& name);
|
||||
|
||||
bool changeTheme(const std::string& name, const int size);
|
||||
void updateTheme();
|
||||
SCursorImageData dataFor(const std::string& name); // for xwayland
|
||||
void setXWaylandCursor();
|
||||
bool changeTheme(const std::string& name, const int size);
|
||||
void updateTheme();
|
||||
SCursorImageData dataFor(const std::string& name); // for xwayland
|
||||
void setXWaylandCursor();
|
||||
|
||||
void tickAnimatedCursor();
|
||||
void tickAnimatedCursor();
|
||||
|
||||
class CCursorBuffer {
|
||||
class CCursorBuffer : public Aquamarine::IBuffer {
|
||||
public:
|
||||
CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot);
|
||||
CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot);
|
||||
~CCursorBuffer();
|
||||
|
||||
struct SCursorWlrBuffer {
|
||||
wlr_buffer base;
|
||||
cairo_surface_t* surface = nullptr;
|
||||
bool dropped = false;
|
||||
CCursorBuffer* parent = nullptr;
|
||||
uint8_t* pixelData = nullptr;
|
||||
size_t stride = 0;
|
||||
} wlrBuffer;
|
||||
virtual Aquamarine::eBufferCapability caps();
|
||||
virtual Aquamarine::eBufferType type();
|
||||
virtual void update(const Hyprutils::Math::CRegion& damage);
|
||||
virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu
|
||||
virtual bool good();
|
||||
virtual Aquamarine::SSHMAttrs shm();
|
||||
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
|
||||
virtual void endDataPtr();
|
||||
|
||||
private:
|
||||
Vector2D size;
|
||||
Vector2D hotspot;
|
||||
Vector2D hotspot;
|
||||
cairo_surface_t* surface = nullptr;
|
||||
uint8_t* pixelData = nullptr;
|
||||
size_t stride = 0;
|
||||
|
||||
friend class CCursorManager;
|
||||
};
|
||||
|
@ -56,7 +60,7 @@ class CCursorManager {
|
|||
bool m_bOurBufferConnected = false;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<CCursorBuffer>> m_vCursorBuffers;
|
||||
std::vector<SP<CCursorBuffer>> m_vCursorBuffers;
|
||||
|
||||
std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor;
|
||||
|
||||
|
@ -70,8 +74,24 @@ class CCursorManager {
|
|||
int m_iCurrentAnimationFrame = 0;
|
||||
Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData;
|
||||
|
||||
// xcursor fallback
|
||||
wlr_xcursor_manager* m_pWLRXCursorMgr = nullptr;
|
||||
// gangsta bootleg XCursor impl. Whenever Hyprland has to use
|
||||
// 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;
|
|
@ -4,10 +4,12 @@
|
|||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/ShortcutsInhibit.hpp"
|
||||
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
#include "../devices/IKeyboard.hpp"
|
||||
#include "KeybindManager.hpp"
|
||||
#include "PointerManager.hpp"
|
||||
#include "Compositor.hpp"
|
||||
#include "TokenManager.hpp"
|
||||
#include "eventLoop/EventLoopManager.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "helpers/varlist/VarList.hpp"
|
||||
|
||||
|
@ -15,6 +17,7 @@
|
|||
#include <iterator>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <cstring>
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
@ -33,7 +36,7 @@ using namespace Hyprutils::String;
|
|||
static std::vector<std::pair<std::string, std::string>> getHyprlandLaunchEnv() {
|
||||
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
|
||||
|
||||
if (!*PINITIALWSTRACKING)
|
||||
if (!*PINITIALWSTRACKING || g_pConfigManager->isLaunchingExecOnce)
|
||||
return {};
|
||||
|
||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
|
@ -98,7 +101,6 @@ CKeybindManager::CKeybindManager() {
|
|||
m_mDispatchers["pass"] = pass;
|
||||
m_mDispatchers["sendshortcut"] = sendshortcut;
|
||||
m_mDispatchers["layoutmsg"] = layoutmsg;
|
||||
m_mDispatchers["toggleopaque"] = toggleOpaque;
|
||||
m_mDispatchers["dpms"] = dpms;
|
||||
m_mDispatchers["movewindowpixel"] = moveWindow;
|
||||
m_mDispatchers["resizewindowpixel"] = resizeWindow;
|
||||
|
@ -157,37 +159,37 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
|
|||
uint32_t modMask = 0;
|
||||
std::transform(mods.begin(), mods.end(), mods.begin(), ::toupper);
|
||||
if (mods.contains("SHIFT"))
|
||||
modMask |= WLR_MODIFIER_SHIFT;
|
||||
modMask |= HL_MODIFIER_SHIFT;
|
||||
if (mods.contains("CAPS"))
|
||||
modMask |= WLR_MODIFIER_CAPS;
|
||||
modMask |= HL_MODIFIER_CAPS;
|
||||
if (mods.contains("CTRL") || mods.contains("CONTROL"))
|
||||
modMask |= WLR_MODIFIER_CTRL;
|
||||
modMask |= HL_MODIFIER_CTRL;
|
||||
if (mods.contains("ALT") || mods.contains("MOD1"))
|
||||
modMask |= WLR_MODIFIER_ALT;
|
||||
modMask |= HL_MODIFIER_ALT;
|
||||
if (mods.contains("MOD2"))
|
||||
modMask |= WLR_MODIFIER_MOD2;
|
||||
modMask |= HL_MODIFIER_MOD2;
|
||||
if (mods.contains("MOD3"))
|
||||
modMask |= WLR_MODIFIER_MOD3;
|
||||
if (mods.contains("SUPER") || mods.contains("WIN") || mods.contains("LOGO") || mods.contains("MOD4"))
|
||||
modMask |= WLR_MODIFIER_LOGO;
|
||||
modMask |= HL_MODIFIER_MOD3;
|
||||
if (mods.contains("SUPER") || mods.contains("WIN") || mods.contains("LOGO") || mods.contains("MOD4") || mods.contains("META"))
|
||||
modMask |= HL_MODIFIER_META;
|
||||
if (mods.contains("MOD5"))
|
||||
modMask |= WLR_MODIFIER_MOD5;
|
||||
modMask |= HL_MODIFIER_MOD5;
|
||||
|
||||
return modMask;
|
||||
}
|
||||
|
||||
uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) {
|
||||
switch (keycode - 8) {
|
||||
case KEY_LEFTMETA: return WLR_MODIFIER_LOGO;
|
||||
case KEY_RIGHTMETA: return WLR_MODIFIER_LOGO;
|
||||
case KEY_LEFTSHIFT: return WLR_MODIFIER_SHIFT;
|
||||
case KEY_RIGHTSHIFT: return WLR_MODIFIER_SHIFT;
|
||||
case KEY_LEFTCTRL: return WLR_MODIFIER_CTRL;
|
||||
case KEY_RIGHTCTRL: return WLR_MODIFIER_CTRL;
|
||||
case KEY_LEFTALT: return WLR_MODIFIER_ALT;
|
||||
case KEY_RIGHTALT: return WLR_MODIFIER_ALT;
|
||||
case KEY_CAPSLOCK: return WLR_MODIFIER_CAPS;
|
||||
case KEY_NUMLOCK: return WLR_MODIFIER_MOD2;
|
||||
case KEY_LEFTMETA: return HL_MODIFIER_META;
|
||||
case KEY_RIGHTMETA: return HL_MODIFIER_META;
|
||||
case KEY_LEFTSHIFT: return HL_MODIFIER_SHIFT;
|
||||
case KEY_RIGHTSHIFT: return HL_MODIFIER_SHIFT;
|
||||
case KEY_LEFTCTRL: return HL_MODIFIER_CTRL;
|
||||
case KEY_RIGHTCTRL: return HL_MODIFIER_CTRL;
|
||||
case KEY_LEFTALT: return HL_MODIFIER_ALT;
|
||||
case KEY_RIGHTALT: return HL_MODIFIER_ALT;
|
||||
case KEY_CAPSLOCK: return HL_MODIFIER_CAPS;
|
||||
case KEY_NUMLOCK: return HL_MODIFIER_MOD2;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
@ -252,7 +254,7 @@ bool CKeybindManager::ensureMouseBindState() {
|
|||
g_pInputManager->dragMode = MBIND_INVALID;
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(lastDraggedWindow->workspaceID());
|
||||
g_pCompositor->updateWorkspaceSpecialRenderData(lastDraggedWindow->workspaceID());
|
||||
g_pCompositor->updateWorkspaceWindowData(lastDraggedWindow->workspaceID());
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(lastDraggedWindow->m_iMonitorID);
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
|
@ -279,13 +281,18 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
|
|||
return false;
|
||||
|
||||
const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get();
|
||||
if (!LASTMONITOR)
|
||||
return false;
|
||||
if (LASTMONITOR == monitor) {
|
||||
Debug::log(LOG, "Tried to move to active monitor");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
const auto PNEWMAINWORKSPACE = monitor->activeWorkspace;
|
||||
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
|
||||
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();
|
||||
PNEWMAINWORKSPACE->rememberPrevWorkspace(PWORKSPACE);
|
||||
|
@ -298,9 +305,11 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
|
|||
g_pCompositor->focusWindow(PNEWWINDOW);
|
||||
PNEWWINDOW->warpCursor();
|
||||
|
||||
g_pInputManager->m_pForcedFocus = PNEWWINDOW;
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->m_pForcedFocus.reset();
|
||||
if (*PNOWARPS == 0 || *PFOLLOWMOUSE < 2) {
|
||||
g_pInputManager->m_pForcedFocus = PNEWWINDOW;
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->m_pForcedFocus.reset();
|
||||
}
|
||||
} else {
|
||||
g_pCompositor->focusWindow(nullptr);
|
||||
g_pCompositor->warpCursorTo(monitor->middle());
|
||||
|
@ -311,7 +320,10 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
|
|||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
@ -335,9 +347,12 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
|
|||
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
|
||||
PWINDOWTOCHANGETO->warpCursor();
|
||||
|
||||
g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO;
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->m_pForcedFocus.reset();
|
||||
// Move mouse focus to the new window if required by current follow_mouse and warp modes
|
||||
if (*PNOWARPS == 0 || *PFOLLOWMOUSE < 2) {
|
||||
g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO;
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->m_pForcedFocus.reset();
|
||||
}
|
||||
|
||||
if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) {
|
||||
// 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 xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbTranslationState : m_pXKBTranslationState, KEYCODE);
|
||||
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->wlr()->xkb_state, 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->xkbState, KEYCODE);
|
||||
|
||||
if (handleInternalKeybinds(internalKeysym))
|
||||
return true;
|
||||
|
@ -554,7 +569,7 @@ int repeatKeyHandler(void* data) {
|
|||
Debug::log(LOG, "Keybind repeat triggered, calling dispatcher.");
|
||||
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;
|
||||
}
|
||||
|
@ -604,10 +619,8 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
|
|||
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& k : m_lKeybinds) {
|
||||
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 =
|
||||
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())
|
||||
continue;
|
||||
|
||||
|
@ -786,7 +802,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
|
|||
// beyond this point, return true to not handle anything else.
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
|
||||
wlr_session_change_vt(g_pCompositor->m_sWLRSession, TTY);
|
||||
return true;
|
||||
g_pCompositor->m_pAqBackend->session->switchVT(TTY);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -893,6 +908,7 @@ uint64_t CKeybindManager::spawnRaw(std::string args) {
|
|||
for (auto& e : HLENV) {
|
||||
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[1]);
|
||||
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_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID());
|
||||
g_pCompositor->updateWorkspaceSpecialRenderData(PWINDOW->workspaceID());
|
||||
g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID());
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
}
|
||||
|
@ -1659,7 +1675,7 @@ void CKeybindManager::renameWorkspace(std::string args) {
|
|||
}
|
||||
|
||||
void CKeybindManager::exitHyprland(std::string argz) {
|
||||
g_pCompositor->m_bExitTriggered = true;
|
||||
g_pCompositor->stopCompositor();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) {
|
||||
xkb_keymap* km = KB->wlr()->keymap;
|
||||
xkb_state* ks = KB->xkbTranslationState;
|
||||
xkb_keymap* km = KB->xkbKeymap;
|
||||
xkb_state* ks = KB->xkbState;
|
||||
|
||||
xkb_keycode_t keycode_min, keycode_max;
|
||||
keycode_min = xkb_keymap_min_keycode(km);
|
||||
|
@ -2233,18 +2249,6 @@ void CKeybindManager::layoutmsg(std::string 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) {
|
||||
bool enable = arg.starts_with("on");
|
||||
std::string port = "";
|
||||
|
@ -2260,7 +2264,7 @@ void CKeybindManager::dpms(std::string arg) {
|
|||
if (!port.empty() && m->szName != port)
|
||||
continue;
|
||||
|
||||
wlr_output_state_set_enabled(m->state.wlr(), enable);
|
||||
m->output->state->setEnabled(enable);
|
||||
|
||||
m->dpmsStatus = enable;
|
||||
|
||||
|
@ -2362,7 +2366,7 @@ void CKeybindManager::mouse(std::string args) {
|
|||
const auto PRESSED = args[0] == '1';
|
||||
|
||||
if (ARGS[0] == "movewindow") {
|
||||
if (PRESSED) {
|
||||
if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) {
|
||||
g_pKeybindManager->m_bIsMouseBindActive = true;
|
||||
|
||||
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
|
||||
|
@ -2376,7 +2380,7 @@ void CKeybindManager::mouse(std::string args) {
|
|||
|
||||
g_pInputManager->dragMode = MBIND_MOVE;
|
||||
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
|
||||
} else {
|
||||
} else if (!PRESSED && g_pInputManager->dragMode == MBIND_MOVE) {
|
||||
g_pKeybindManager->m_bIsMouseBindActive = false;
|
||||
|
||||
if (!g_pInputManager->currentlyDraggedWindow.expired()) {
|
||||
|
@ -2386,7 +2390,7 @@ void CKeybindManager::mouse(std::string args) {
|
|||
}
|
||||
}
|
||||
} else if (ARGS[0] == "resizewindow") {
|
||||
if (PRESSED) {
|
||||
if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) {
|
||||
g_pKeybindManager->m_bIsMouseBindActive = true;
|
||||
|
||||
g_pInputManager->currentlyDraggedWindow =
|
||||
|
@ -2400,7 +2404,8 @@ void CKeybindManager::mouse(std::string args) {
|
|||
}
|
||||
} catch (std::exception& e) { g_pInputManager->dragMode = MBIND_RESIZE; }
|
||||
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;
|
||||
|
||||
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!
|
||||
|
||||
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");
|
||||
pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail();
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "../Compositor.hpp"
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "../devices/IPointer.hpp"
|
||||
|
||||
class CInputManager;
|
||||
|
@ -33,6 +34,7 @@ struct SKeybind {
|
|||
bool ignoreMods = false;
|
||||
bool multiKey = false;
|
||||
bool hasDescription = false;
|
||||
bool dontInhibit = false;
|
||||
|
||||
// DO NOT INITIALIZE
|
||||
bool shadowed = false;
|
||||
|
@ -188,7 +190,6 @@ class CKeybindManager {
|
|||
static void pass(std::string);
|
||||
static void sendshortcut(std::string);
|
||||
static void layoutmsg(std::string);
|
||||
static void toggleOpaque(std::string);
|
||||
static void dpms(std::string);
|
||||
static void swapnext(std::string);
|
||||
static void swapActiveWorkspaces(std::string);
|
||||
|
|
|
@ -6,133 +6,8 @@
|
|||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "eventLoop/EventLoopManager.hpp"
|
||||
#include "SeatManager.hpp"
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/render/interface.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;
|
||||
}
|
||||
#include <cstring>
|
||||
#include <gbm.h>
|
||||
|
||||
CPointerManager::CPointerManager() {
|
||||
hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) {
|
||||
|
@ -149,6 +24,14 @@ CPointerManager::CPointerManager() {
|
|||
},
|
||||
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() {
|
||||
|
@ -201,6 +84,11 @@ void CPointerManager::unlockSoftwareForMonitor(SP<CMonitor> mon) {
|
|||
updateCursorBackend();
|
||||
}
|
||||
|
||||
bool CPointerManager::softwareLockedFor(SP<CMonitor> mon) {
|
||||
auto state = stateFor(mon);
|
||||
return state->softwareLocks > 0 || state->hardwareFailed;
|
||||
}
|
||||
|
||||
Vector2D CPointerManager::position() {
|
||||
return pointerPos;
|
||||
}
|
||||
|
@ -216,7 +104,7 @@ SP<CPointerManager::SMonitorPointerState> CPointerManager::stateFor(SP<CMonitor>
|
|||
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();
|
||||
if (buf == currentCursorImage.pBuffer) {
|
||||
if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) {
|
||||
|
@ -232,11 +120,8 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot,
|
|||
resetCursorImage(false);
|
||||
|
||||
if (buf) {
|
||||
currentCursorImage.size = {buf->width, buf->height};
|
||||
currentCursorImage.pBuffer = wlr_buffer_lock(buf);
|
||||
|
||||
currentCursorImage.hyprListener_destroyBuffer.initCallback(
|
||||
&buf->events.destroy, [this](void* owner, void* data) { resetCursorImage(); }, this, "CPointerManager");
|
||||
currentCursorImage.size = buf->size;
|
||||
currentCursorImage.pBuffer = buf;
|
||||
}
|
||||
|
||||
currentCursorImage.hotspot = hotspot;
|
||||
|
@ -318,8 +203,8 @@ void CPointerManager::recheckEnteredOutputs() {
|
|||
// if we are using hw cursors, prevent
|
||||
// the cursor from being stuck at the last point.
|
||||
// if we are leaving it, move it to narnia.
|
||||
if (!s->hardwareFailed && s->monitor->output->impl->move_cursor)
|
||||
s->monitor->output->impl->move_cursor(s->monitor->output, -1337, -420);
|
||||
if (!s->hardwareFailed && (s->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
|
||||
s->monitor->output->moveCursor({-1337, -420});
|
||||
|
||||
if (!currentCursorImage.surface)
|
||||
continue;
|
||||
|
@ -340,16 +225,11 @@ void CPointerManager::resetCursorImage(bool apply) {
|
|||
currentCursorImage.destroySurface.reset();
|
||||
currentCursorImage.commitSurface.reset();
|
||||
currentCursorImage.surface.reset();
|
||||
} else if (currentCursorImage.pBuffer) {
|
||||
wlr_buffer_unlock(currentCursorImage.pBuffer);
|
||||
currentCursorImage.hyprListener_destroyBuffer.removeCallback();
|
||||
} else if (currentCursorImage.pBuffer)
|
||||
currentCursorImage.pBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (currentCursorImage.pBufferTexture) {
|
||||
wlr_texture_destroy(currentCursorImage.pBufferTexture);
|
||||
currentCursorImage.pBufferTexture = nullptr;
|
||||
}
|
||||
if (currentCursorImage.bufferTex)
|
||||
currentCursorImage.bufferTex = nullptr;
|
||||
|
||||
currentCursorImage.scale = 1.F;
|
||||
currentCursorImage.hotspot = {0, 0};
|
||||
|
@ -371,9 +251,8 @@ void CPointerManager::resetCursorImage(bool apply) {
|
|||
}
|
||||
|
||||
if (ms->cursorFrontBuffer) {
|
||||
if (ms->monitor->output->impl->set_cursor)
|
||||
ms->monitor->output->impl->set_cursor(ms->monitor->output, nullptr, 0, 0);
|
||||
wlr_buffer_unlock(ms->cursorFrontBuffer);
|
||||
if (ms->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)
|
||||
ms->monitor->output->setCursor(nullptr, {});
|
||||
ms->cursorFrontBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -419,18 +298,18 @@ void CPointerManager::onCursorMoved() {
|
|||
continue;
|
||||
|
||||
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) {
|
||||
auto output = state->monitor->output;
|
||||
|
||||
if (!output->impl->set_cursor)
|
||||
if (!(output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
|
||||
return false;
|
||||
|
||||
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();
|
||||
|
||||
|
@ -460,64 +339,70 @@ bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerS
|
|||
return success;
|
||||
}
|
||||
|
||||
bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf) {
|
||||
if (!state->monitor->output->impl->set_cursor)
|
||||
bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf) {
|
||||
if (!(state->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
|
||||
return false;
|
||||
|
||||
const auto HOTSPOT = transformedHotspot(state->monitor.lock());
|
||||
|
||||
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;
|
||||
|
||||
wlr_buffer_unlock(state->cursorFrontBuffer);
|
||||
state->cursorFrontBuffer = buf;
|
||||
|
||||
g_pCompositor->scheduleFrameForMonitor(state->monitor.get());
|
||||
|
||||
if (buf)
|
||||
wlr_buffer_lock(buf);
|
||||
g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
|
||||
|
||||
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;
|
||||
|
||||
int w = currentCursorImage.size.x, h = currentCursorImage.size.y;
|
||||
if (output->impl->get_cursor_size) {
|
||||
output->impl->get_cursor_size(output, &w, &h);
|
||||
auto maxSize = output->cursorPlaneSize();
|
||||
auto cursorSize = currentCursorImage.size;
|
||||
|
||||
if (w < currentCursorImage.size.x || h < currentCursorImage.size.y) {
|
||||
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);
|
||||
if (maxSize == Vector2D{})
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!output->cursor_swapchain || Vector2D{w, h} != Vector2D{output->cursor_swapchain->width, output->cursor_swapchain->height}) {
|
||||
wlr_drm_format fmt = {0};
|
||||
if (!output_pick_cursor_format(output, &fmt)) {
|
||||
Debug::log(TRACE, "Failed to pick cursor format");
|
||||
if (maxSize != Vector2D{-1, -1}) {
|
||||
if (cursorSize.x > maxSize.x || cursorSize.y > maxSize.y) {
|
||||
Debug::log(TRACE, "hardware cursor too big! {} > {}", currentCursorImage.size, maxSize);
|
||||
return nullptr;
|
||||
}
|
||||
} else
|
||||
maxSize = cursorSize;
|
||||
|
||||
wlr_swapchain_destroy(output->cursor_swapchain);
|
||||
output->cursor_swapchain = wlr_swapchain_create(output->allocator, w, h, &fmt);
|
||||
wlr_drm_format_finish(&fmt);
|
||||
if (!state->monitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size) {
|
||||
|
||||
if (!output->cursor_swapchain) {
|
||||
Debug::log(TRACE, "Failed to create cursor swapchain");
|
||||
if (!state->monitor->cursorSwapchain)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain");
|
||||
return nullptr;
|
||||
|
@ -526,16 +411,45 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPo
|
|||
CRegion damage = {0, 0, INT16_MAX, INT16_MAX};
|
||||
|
||||
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();
|
||||
|
||||
g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO);
|
||||
g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F});
|
||||
|
||||
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());
|
||||
|
||||
g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F);
|
||||
|
@ -544,9 +458,7 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPo
|
|||
glFlush();
|
||||
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
|
||||
|
||||
g_pHyprRenderer->onRenderbufferDestroy(RBO);
|
||||
|
||||
wlr_buffer_unlock(buf);
|
||||
g_pHyprRenderer->onRenderbufferDestroy(RBO.get());
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
@ -580,7 +492,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec*
|
|||
box.x = std::round(box.x);
|
||||
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)
|
||||
currentCursorImage.surface->resource()->frame(now);
|
||||
|
@ -588,17 +500,19 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec*
|
|||
|
||||
Vector2D CPointerManager::getCursorPosForMonitor(SP<CMonitor> pMonitor) {
|
||||
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() *
|
||||
pMonitor->scale;
|
||||
}
|
||||
|
||||
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 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();
|
||||
}
|
||||
|
||||
|
@ -722,7 +636,7 @@ void CPointerManager::move(const Vector2D& deltaLogical) {
|
|||
void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) {
|
||||
|
||||
SP<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor.lock();
|
||||
if (!currentMonitor)
|
||||
if (!currentMonitor || !dev)
|
||||
return;
|
||||
|
||||
if (!std::isnan(abs.x))
|
||||
|
@ -800,10 +714,8 @@ SP<CTexture> CPointerManager::getCurrentCursorTexture() {
|
|||
return nullptr;
|
||||
|
||||
if (currentCursorImage.pBuffer) {
|
||||
if (!currentCursorImage.pBufferTexture) {
|
||||
currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer);
|
||||
currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBufferTexture);
|
||||
}
|
||||
if (!currentCursorImage.bufferTex)
|
||||
currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBuffer);
|
||||
return currentCursorImage.bufferTex;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,15 @@
|
|||
#include "../helpers/math/Math.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
#include "../desktop/WLSurface.hpp"
|
||||
#include "../helpers/sync/SyncTimeline.hpp"
|
||||
#include <tuple>
|
||||
|
||||
class CMonitor;
|
||||
struct wlr_input_device;
|
||||
class IHID;
|
||||
class CTexture;
|
||||
|
||||
AQUAMARINE_FORWARD(IBuffer);
|
||||
|
||||
/*
|
||||
The naming here is a bit confusing.
|
||||
CPointerManager manages the _position_ and _displaying_ of the cursor,
|
||||
|
@ -37,7 +39,7 @@ class CPointerManager {
|
|||
void move(const Vector2D& deltaLogical);
|
||||
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 resetCursorImage(bool apply = true);
|
||||
|
||||
|
@ -47,6 +49,7 @@ class CPointerManager {
|
|||
void unlockSoftwareForMonitor(CMonitor* pMonitor);
|
||||
void lockSoftwareAll();
|
||||
void unlockSoftwareAll();
|
||||
bool softwareLockedFor(SP<CMonitor> pMonitor);
|
||||
|
||||
void renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */);
|
||||
|
||||
|
@ -135,48 +138,47 @@ class CPointerManager {
|
|||
} currentMonitorLayout;
|
||||
|
||||
struct {
|
||||
wlr_buffer* pBuffer = nullptr;
|
||||
SP<CTexture> bufferTex;
|
||||
WP<CWLSurface> surface;
|
||||
wlr_texture* pBufferTexture = nullptr;
|
||||
SP<Aquamarine::IBuffer> pBuffer;
|
||||
SP<CTexture> bufferTex;
|
||||
WP<CWLSurface> surface;
|
||||
|
||||
Vector2D hotspot;
|
||||
Vector2D size;
|
||||
float scale = 1.F;
|
||||
Vector2D hotspot;
|
||||
Vector2D size;
|
||||
float scale = 1.F;
|
||||
|
||||
CHyprSignalListener destroySurface;
|
||||
CHyprSignalListener commitSurface;
|
||||
DYNLISTENER(destroyBuffer);
|
||||
CHyprSignalListener destroySurface;
|
||||
CHyprSignalListener commitSurface;
|
||||
SP<CSyncTimeline> waitTimeline = nullptr;
|
||||
uint64_t waitPoint = 0;
|
||||
} currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors
|
||||
|
||||
Vector2D pointerPos = {0, 0};
|
||||
|
||||
struct SMonitorPointerState {
|
||||
SMonitorPointerState(SP<CMonitor> m) : monitor(m) {}
|
||||
~SMonitorPointerState() {
|
||||
if (cursorFrontBuffer)
|
||||
wlr_buffer_unlock(cursorFrontBuffer);
|
||||
}
|
||||
~SMonitorPointerState() {}
|
||||
|
||||
WP<CMonitor> monitor;
|
||||
WP<CMonitor> monitor;
|
||||
|
||||
int softwareLocks = 0;
|
||||
bool hardwareFailed = false;
|
||||
CBox box; // logical
|
||||
bool entered = false;
|
||||
bool hwApplied = false;
|
||||
int softwareLocks = 0;
|
||||
bool hardwareFailed = false;
|
||||
CBox box; // logical
|
||||
bool entered = false;
|
||||
bool hwApplied = false;
|
||||
bool cursorRendered = false;
|
||||
|
||||
wlr_buffer* cursorFrontBuffer = nullptr;
|
||||
SP<Aquamarine::IBuffer> cursorFrontBuffer;
|
||||
};
|
||||
|
||||
std::vector<SP<SMonitorPointerState>> monitorStates;
|
||||
SP<SMonitorPointerState> stateFor(SP<CMonitor> mon);
|
||||
bool attemptHardwareCursor(SP<SMonitorPointerState> state);
|
||||
wlr_buffer* renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture);
|
||||
bool setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf);
|
||||
SP<Aquamarine::IBuffer> renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture);
|
||||
bool setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf);
|
||||
|
||||
struct {
|
||||
SP<HOOK_CALLBACK_FN> monitorAdded;
|
||||
SP<HOOK_CALLBACK_FN> monitorPreRender;
|
||||
} hooks;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "ProtocolManager.hpp"
|
||||
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
#include "../protocols/TearingControl.hpp"
|
||||
#include "../protocols/FractionalScale.hpp"
|
||||
#include "../protocols/XDGOutput.hpp"
|
||||
|
@ -35,6 +37,10 @@
|
|||
#include "../protocols/Viewporter.hpp"
|
||||
#include "../protocols/MesaDRM.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/DataDevice.hpp"
|
||||
|
@ -45,6 +51,10 @@
|
|||
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
#include <aquamarine/buffer/Buffer.hpp>
|
||||
#include <aquamarine/backend/Backend.hpp>
|
||||
|
||||
void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) {
|
||||
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())) {
|
||||
if (PROTO::outputs.contains(pMonitor->szName))
|
||||
PROTO::outputs.erase(pMonitor->szName);
|
||||
PROTO::outputs.emplace(pMonitor->szName,
|
||||
std::make_unique<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock()));
|
||||
PROTO::outputs.emplace(pMonitor->szName, makeShared<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock()));
|
||||
}
|
||||
}
|
||||
|
||||
CProtocolManager::CProtocolManager() {
|
||||
|
||||
static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("experimental:explicit_sync");
|
||||
|
||||
// Outputs are a bit dumb, we have to agree.
|
||||
static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) {
|
||||
auto M = std::any_cast<CMonitor*>(param);
|
||||
|
@ -76,7 +87,10 @@ CProtocolManager::CProtocolManager() {
|
|||
|
||||
if (PROTO::outputs.contains(M->szName))
|
||||
PROTO::outputs.erase(M->szName);
|
||||
PROTO::outputs.emplace(M->szName, std::make_unique<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock()));
|
||||
|
||||
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); });
|
||||
});
|
||||
|
@ -130,6 +144,18 @@ CProtocolManager::CProtocolManager() {
|
|||
PROTO::dataWlr = std::make_unique<CDataDeviceWLRProtocol>(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr");
|
||||
PROTO::primarySelection = std::make_unique<CPrimarySelectionProtocol>(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection");
|
||||
PROTO::xwaylandShell = std::make_unique<CXWaylandShellProtocol>(&xwayland_shell_v1_interface, 1, "XWaylandShell");
|
||||
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) {
|
||||
PROTO::mesaDRM = std::make_unique<CMesaDRMProtocol>(&wl_drm_interface, 2, "MesaDRM");
|
||||
|
@ -139,8 +165,62 @@ CProtocolManager::CProtocolManager() {
|
|||
|
||||
// Old protocol implementations.
|
||||
// TODO: rewrite them to use hyprwayland-scanner.
|
||||
m_pToplevelExportProtocolManager = std::make_unique<CToplevelExportProtocolManager>();
|
||||
m_pTextInputV1ProtocolManager = std::make_unique<CTextInputV1ProtocolManager>();
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../protocols/ToplevelExport.hpp"
|
||||
#include "../protocols/TextInputV1.hpp"
|
||||
#include "../protocols/GlobalShortcuts.hpp"
|
||||
#include "../protocols/Screencopy.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include <unordered_map>
|
||||
|
@ -12,12 +11,11 @@
|
|||
class CProtocolManager {
|
||||
public:
|
||||
CProtocolManager();
|
||||
~CProtocolManager();
|
||||
|
||||
// TODO: rewrite to use the new protocol framework
|
||||
std::unique_ptr<CToplevelExportProtocolManager> m_pToplevelExportProtocolManager;
|
||||
std::unique_ptr<CTextInputV1ProtocolManager> m_pTextInputV1ProtocolManager;
|
||||
std::unique_ptr<CGlobalShortcutsProtocolManager> m_pGlobalShortcutsProtocolManager;
|
||||
std::unique_ptr<CScreencopyProtocolManager> m_pScreencopyProtocolManager;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, CHyprSignalListener> m_mModeChangeListeners;
|
||||
|
|
|
@ -94,8 +94,8 @@ void CSeatManager::setKeyboard(SP<IKeyboard> KEEB) {
|
|||
}
|
||||
|
||||
void CSeatManager::updateActiveKeyboardData() {
|
||||
if (keyboard && keyboard->wlr())
|
||||
PROTO::seat->updateRepeatInfo(keyboard->wlr()->repeat_info.rate, keyboard->wlr()->repeat_info.delay);
|
||||
if (keyboard)
|
||||
PROTO::seat->updateRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay);
|
||||
PROTO::seat->updateKeymap();
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ void CSeatManager::setKeyboardFocus(SP<CWLSurfaceResource> surf) {
|
|||
if (state.keyboardFocus == surf)
|
||||
return;
|
||||
|
||||
if (!keyboard || !keyboard->wlr()) {
|
||||
if (!keyboard) {
|
||||
Debug::log(ERR, "BUG THIS: setKeyboardFocus without a valid keyboard set");
|
||||
return;
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ void CSeatManager::setKeyboardFocus(SP<CWLSurfaceResource> surf) {
|
|||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!mouse || !mouse->wlr()) {
|
||||
if (!mouse) {
|
||||
Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set");
|
||||
return;
|
||||
}
|
||||
|
@ -333,9 +333,7 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double
|
|||
if (source == 0) {
|
||||
p->sendAxisValue120(axis, value120);
|
||||
p->sendAxisDiscrete(axis, discrete);
|
||||
}
|
||||
|
||||
if (value == 0)
|
||||
} else if (value == 0)
|
||||
p->sendAxisStop(timeMs, axis);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "../config/ConfigValue.hpp"
|
||||
#include "../protocols/FractionalScale.hpp"
|
||||
#include "../protocols/SessionLock.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
SSessionLockSurface::SSessionLockSurface(SP<CSessionLockSurface> surface_) : surface(surface_) {
|
||||
pWlrSurface = surface->surface();
|
||||
|
@ -77,7 +78,6 @@ void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) {
|
|||
g_pHyprRenderer->damageMonitor(m.get());
|
||||
});
|
||||
|
||||
pLock->sendLocked();
|
||||
g_pCompositor->focusSurface(nullptr);
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,6 @@ SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64
|
|||
}
|
||||
|
||||
// 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) {
|
||||
if (!m_pSessionLock)
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../helpers/signal/Signal.hpp"
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
class CSessionLockSurface;
|
||||
class CSessionLock;
|
||||
|
@ -37,6 +38,9 @@ struct SSessionLock {
|
|||
CHyprSignalListener unlock;
|
||||
CHyprSignalListener destroy;
|
||||
} listeners;
|
||||
|
||||
bool m_hasSentLocked = false;
|
||||
std::unordered_set<uint64_t> m_lockedMonitors;
|
||||
};
|
||||
|
||||
class CSessionLockManager {
|
||||
|
@ -54,6 +58,8 @@ class CSessionLockManager {
|
|||
|
||||
void removeSessionLockSurface(SSessionLockSurface*);
|
||||
|
||||
void onLockscreenRenderedOnMonitor(uint64_t id);
|
||||
|
||||
private:
|
||||
UP<SSessionLock> m_pSessionLock;
|
||||
|
||||
|
|
|
@ -76,13 +76,21 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) {
|
|||
const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get();
|
||||
|
||||
if (SIZEHINTS && pWindow->m_iX11Type != 2) {
|
||||
pbox->x = SIZEHINTS->x;
|
||||
pbox->y = SIZEHINTS->y;
|
||||
pbox->width = SIZEHINTS->width;
|
||||
pbox->height = SIZEHINTS->height;
|
||||
} else {
|
||||
// WM_SIZE_HINTS' x,y,w,h is deprecated it seems.
|
||||
// Source: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#wm_normal_hints_property
|
||||
pbox->x = pWindow->m_pXWaylandSurface->geometry.x;
|
||||
pbox->y = pWindow->m_pXWaylandSurface->geometry.y;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} else if (pWindow->m_pXDGSurface)
|
||||
*pbox = pWindow->m_pXDGSurface->current.geometry;
|
||||
}
|
||||
|
@ -206,7 +214,8 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) {
|
|||
if (!validMapped(pWindow))
|
||||
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);
|
||||
|
||||
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) :
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "EventLoopManager.hpp"
|
||||
#include "../../debug/Log.hpp"
|
||||
#include "../../Compositor.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
@ -7,6 +8,8 @@
|
|||
#include <sys/timerfd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <aquamarine/backend/Backend.hpp>
|
||||
|
||||
#define TIMESPEC_NSEC_PER_SEC 1000000000L
|
||||
|
||||
CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) {
|
||||
|
@ -16,8 +19,14 @@ CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEvent
|
|||
}
|
||||
|
||||
CEventLoopManager::~CEventLoopManager() {
|
||||
for (auto& eventSource : m_sWayland.aqEventSources) {
|
||||
wl_event_source_remove(eventSource);
|
||||
}
|
||||
|
||||
if (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) {
|
||||
|
@ -25,9 +34,21 @@ static int timerWrite(int fd, uint32_t mask, void* data) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int aquamarineFDWrite(int fd, uint32_t mask, void* data) {
|
||||
auto POLLFD = (Aquamarine::SPollFD*)data;
|
||||
POLLFD->onSignal();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CEventLoopManager::enterLoop() {
|
||||
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);
|
||||
|
||||
Debug::log(LOG, "Kicked off the event loop! :(");
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
#include "EventLoopTimer.hpp"
|
||||
|
||||
namespace Aquamarine {
|
||||
struct SPollFD;
|
||||
};
|
||||
|
||||
class CEventLoopManager {
|
||||
public:
|
||||
CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop);
|
||||
|
@ -33,9 +37,10 @@ class CEventLoopManager {
|
|||
|
||||
private:
|
||||
struct {
|
||||
wl_event_loop* loop = nullptr;
|
||||
wl_display* display = nullptr;
|
||||
wl_event_source* eventSource = nullptr;
|
||||
wl_event_loop* loop = nullptr;
|
||||
wl_display* display = nullptr;
|
||||
wl_event_source* eventSource = nullptr;
|
||||
std::vector<wl_event_source*> aqEventSources;
|
||||
} m_sWayland;
|
||||
|
||||
struct {
|
||||
|
@ -43,7 +48,10 @@ class CEventLoopManager {
|
|||
int timerfd = -1;
|
||||
} m_sTimers;
|
||||
|
||||
SIdleData m_sIdle;
|
||||
SIdleData m_sIdle;
|
||||
std::vector<SP<Aquamarine::SPollFD>> aqPollFDs;
|
||||
|
||||
friend class CSyncTimeline;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CEventLoopManager> g_pEventLoopManager;
|
|
@ -7,7 +7,7 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) {
|
|||
const auto PINHIBIT = m_vIdleInhibitors.emplace_back(std::make_unique<SIdleInhibitor>()).get();
|
||||
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) {
|
||||
std::erase_if(m_vIdleInhibitors, [PINHIBIT](const auto& other) { return other.get() == PINHIBIT; });
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "InputManager.hpp"
|
||||
#include "../../Compositor.hpp"
|
||||
#include "wlr/types/wlr_switch.h"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include <cstdint>
|
||||
#include <ranges>
|
||||
#include "../../config/ConfigValue.hpp"
|
||||
|
@ -28,6 +28,8 @@
|
|||
#include "../../managers/PointerManager.hpp"
|
||||
#include "../../managers/SeatManager.hpp"
|
||||
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
|
||||
CInputManager::CInputManager() {
|
||||
m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) {
|
||||
if (!cursorImageUnlocked())
|
||||
|
@ -189,8 +191,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
|
||||
bool skipFrameSchedule = PMONITOR->shouldSkipScheduleFrameOnMouseEvent();
|
||||
|
||||
if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0 && !skipFrameSchedule)
|
||||
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
||||
if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) && !skipFrameSchedule)
|
||||
g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE);
|
||||
|
||||
PHLWINDOW forcedFocus = m_pForcedFocus.lock();
|
||||
|
||||
|
@ -226,7 +228,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
return;
|
||||
|
||||
} 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,
|
||||
|
@ -372,8 +374,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
foundSurface =
|
||||
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)
|
||||
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get());
|
||||
if (g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) > 0 && !skipFrameSchedule)
|
||||
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE);
|
||||
|
||||
// grabs
|
||||
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);
|
||||
|
||||
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()) {
|
||||
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 PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input: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);
|
||||
|
||||
|
@ -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),
|
||||
std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL);
|
||||
|
||||
double discrete = (e.deltaDiscrete != 0) ? (factor * e.deltaDiscrete / std::abs(e.deltaDiscrete)) : 0;
|
||||
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() {
|
||||
return g_pPointerManager->position();
|
||||
}
|
||||
|
||||
void CInputManager::newKeyboard(wlr_input_device* keyboard) {
|
||||
const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(wlr_keyboard_from_input_device(keyboard)));
|
||||
void CInputManager::newKeyboard(SP<Aquamarine::IKeyboard> keyboard) {
|
||||
const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(keyboard));
|
||||
|
||||
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) {
|
||||
|
@ -820,14 +858,14 @@ void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard)
|
|||
|
||||
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) {
|
||||
m_vHIDs.push_back(keeb);
|
||||
|
||||
try {
|
||||
keeb->hlName = getNameForNewDevice(keeb->wlr()->base.name);
|
||||
keeb->hlName = getNameForNewDevice(keeb->deviceName);
|
||||
} catch (std::exception& e) {
|
||||
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
|
||||
}
|
||||
|
||||
wlr_keyboard_set_repeat_info(pKeyboard->wlr(), std::max(0, REPEATRATE), std::max(0, REPEATDELAY));
|
||||
|
||||
pKeyboard->repeatDelay = REPEATDELAY;
|
||||
pKeyboard->repeatRate = REPEATRATE;
|
||||
pKeyboard->repeatRate = std::max(0, REPEATRATE);
|
||||
pKeyboard->repeatDelay = std::max(0, REPEATDELAY);
|
||||
pKeyboard->numlockOn = NUMLOCKON;
|
||||
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->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);
|
||||
pKeyboard->setKeymap(IKeyboard::SStringRuleNames{LAYOUT, MODEL, VARIANT, OPTIONS, RULES});
|
||||
|
||||
const auto LAYOUTSTR = pKeyboard->getActiveLayout();
|
||||
|
||||
|
@ -1017,28 +984,28 @@ void CInputManager::newVirtualMouse(SP<CVirtualPointerV1Resource> mouse) {
|
|||
|
||||
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) {
|
||||
const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(wlr_pointer_from_input_device(mouse)));
|
||||
void CInputManager::newMouse(SP<Aquamarine::IPointer> mouse) {
|
||||
const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(mouse));
|
||||
|
||||
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) {
|
||||
m_vHIDs.push_back(mauz);
|
||||
|
||||
try {
|
||||
mauz->hlName = getNameForNewDevice(mauz->wlr()->base.name);
|
||||
mauz->hlName = getNameForNewDevice(mauz->deviceName);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Mouse had no name???"); // logic error
|
||||
}
|
||||
|
||||
if (wlr_input_device_is_libinput(&mauz->wlr()->base)) {
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&mauz->wlr()->base);
|
||||
if (mauz->aq() && mauz->aq()->getLibinputHandle()) {
|
||||
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),
|
||||
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)) {
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base);
|
||||
if (m->aq() && m->aq()->getLibinputHandle()) {
|
||||
const auto LIBINPUTDEV = m->aq()->getLibinputHandle();
|
||||
|
||||
double touchw = 0, touchh = 0;
|
||||
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) {
|
||||
if (pKeyboard->xkbTranslationState)
|
||||
xkb_state_unref(pKeyboard->xkbTranslationState);
|
||||
pKeyboard->xkbTranslationState = nullptr;
|
||||
Debug::log(LOG, "Keyboard at {:x} removed", (uintptr_t)pKeyboard.get());
|
||||
|
||||
std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; });
|
||||
|
||||
if (m_vKeyboards.size() > 0) {
|
||||
bool found = false;
|
||||
for (auto& k : m_vKeyboards | std::views::reverse) {
|
||||
if (!k->wlr())
|
||||
if (!k)
|
||||
continue;
|
||||
|
||||
g_pSeatManager->setKeyboard(k);
|
||||
|
@ -1251,6 +1216,8 @@ void CInputManager::destroyKeyboard(SP<IKeyboard> pKeyboard) {
|
|||
}
|
||||
|
||||
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; });
|
||||
|
||||
g_pSeatManager->setMouse(m_vPointers.size() > 0 ? m_vPointers.front() : nullptr);
|
||||
|
@ -1297,20 +1264,7 @@ void CInputManager::updateKeyboardsLeds(SP<IKeyboard> pKeyboard) {
|
|||
if (!pKeyboard)
|
||||
return;
|
||||
|
||||
auto keyboard = pKeyboard->wlr();
|
||||
|
||||
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);
|
||||
}
|
||||
pKeyboard->updateLEDs();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (IME && IME->hasGrab() && !DISALLOWACTION) {
|
||||
IME->setKeyboard(pKeyboard->wlr());
|
||||
IME->setKeyboard(pKeyboard);
|
||||
IME->sendKey(e.timeMs, e.keycode, e.state);
|
||||
} else {
|
||||
g_pSeatManager->setKeyboard(pKeyboard);
|
||||
|
@ -1356,15 +1310,14 @@ void CInputManager::onKeyboardMod(SP<IKeyboard> pKeyboard) {
|
|||
const bool DISALLOWACTION = pKeyboard->isVirtual() && shouldIgnoreVirtualKeyboard(pKeyboard);
|
||||
|
||||
const auto ALLMODS = accumulateModsFromAllKBs();
|
||||
const auto PWLRKB = pKeyboard->wlr();
|
||||
|
||||
auto MODS = PWLRKB->modifiers;
|
||||
auto MODS = pKeyboard->modifiersState;
|
||||
MODS.depressed = ALLMODS;
|
||||
|
||||
const auto IME = m_sIMERelay.m_pIME.lock();
|
||||
|
||||
if (IME && IME->hasGrab() && !DISALLOWACTION) {
|
||||
IME->setKeyboard(PWLRKB);
|
||||
IME->setKeyboard(pKeyboard);
|
||||
IME->sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group);
|
||||
} else {
|
||||
g_pSeatManager->setKeyboard(pKeyboard);
|
||||
|
@ -1373,12 +1326,12 @@ void CInputManager::onKeyboardMod(SP<IKeyboard> pKeyboard) {
|
|||
|
||||
updateKeyboardsLeds(pKeyboard);
|
||||
|
||||
if (PWLRKB->modifiers.group != pKeyboard->activeLayout) {
|
||||
pKeyboard->activeLayout = PWLRKB->modifiers.group;
|
||||
if (pKeyboard->modifiersState.group != pKeyboard->activeLayout) {
|
||||
pKeyboard->activeLayout = pKeyboard->modifiersState.group;
|
||||
|
||||
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});
|
||||
EMIT_HOOK_EVENT("activeLayout", (std::vector<std::any>{pKeyboard, LAYOUT}));
|
||||
|
@ -1488,10 +1441,10 @@ uint32_t CInputManager::accumulateModsFromAllKBs() {
|
|||
if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb))
|
||||
continue;
|
||||
|
||||
if (!kb->enabled || !kb->wlr())
|
||||
if (!kb->enabled)
|
||||
continue;
|
||||
|
||||
finalMask |= wlr_keyboard_get_modifiers(kb->wlr());
|
||||
finalMask |= kb->getModifiers();
|
||||
}
|
||||
|
||||
return finalMask;
|
||||
|
@ -1507,12 +1460,12 @@ void CInputManager::disableAllKeyboards(bool virt) {
|
|||
}
|
||||
}
|
||||
|
||||
void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
|
||||
const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(wlr_touch_from_input_device(pDevice)));
|
||||
void CInputManager::newTouchDevice(SP<Aquamarine::ITouch> pDevice) {
|
||||
const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(pDevice));
|
||||
m_vHIDs.push_back(PNEWDEV);
|
||||
|
||||
try {
|
||||
PNEWDEV->hlName = getNameForNewDevice(pDevice->name);
|
||||
PNEWDEV->hlName = getNameForNewDevice(PNEWDEV->deviceName);
|
||||
} catch (std::exception& e) {
|
||||
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) {
|
||||
auto setConfig = [&](SP<ITouch> PTOUCHDEV) -> void {
|
||||
if (wlr_input_device_is_libinput(&PTOUCHDEV->wlr()->base)) {
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&PTOUCHDEV->wlr()->base);
|
||||
auto setConfig = [](SP<ITouch> PTOUCHDEV) -> void {
|
||||
if (PTOUCHDEV->aq() && PTOUCHDEV->aq()->getLibinputHandle()) {
|
||||
const auto LIBINPUTDEV = PTOUCHDEV->aq()->getLibinputHandle();
|
||||
|
||||
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;
|
||||
|
@ -1553,11 +1506,12 @@ void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
|
|||
bool bound = !output.empty() && output != STRVAL_EMPTY;
|
||||
const bool AUTODETECT = output == "[[Auto]]";
|
||||
if (!bound && AUTODETECT) {
|
||||
const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name;
|
||||
if (DEFAULTOUTPUT) {
|
||||
output = DEFAULTOUTPUT;
|
||||
bound = true;
|
||||
}
|
||||
// FIXME:
|
||||
// const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name;
|
||||
// if (DEFAULTOUTPUT) {
|
||||
// output = DEFAULTOUTPUT;
|
||||
// bound = true;
|
||||
// }
|
||||
}
|
||||
PTOUCHDEV->boundOutput = bound ? output : "";
|
||||
const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr;
|
||||
|
@ -1581,9 +1535,9 @@ void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
|
|||
|
||||
void CInputManager::setTabletConfigs() {
|
||||
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 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");
|
||||
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_POS = g_pConfigManager->getDeviceVec(NAME, "active_area_position", "input:tablet:active_area_position");
|
||||
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,
|
||||
(ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t->wlr()->height_mm};
|
||||
t->activeArea = CBox{ACTIVE_AREA_POS.x / t->aq()->physicalSize.x, ACTIVE_AREA_POS.y / t->aq()->physicalSize.y,
|
||||
(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) {
|
||||
const auto PNEWDEV = &m_lSwitches.emplace_back();
|
||||
PNEWDEV->pWlrDevice = pDevice;
|
||||
void CInputManager::newSwitch(SP<Aquamarine::ISwitch> pDevice) {
|
||||
const auto PNEWDEV = &m_lSwitches.emplace_back();
|
||||
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(
|
||||
&pDevice->events.destroy, [&](void* owner, void* data) { destroySwitch((SSwitchDevice*)owner); }, PNEWDEV, "SwitchDevice");
|
||||
PNEWDEV->listeners.destroy = pDevice->events.destroy.registerListener([this, PNEWDEV](std::any d) { destroySwitch(PNEWDEV); });
|
||||
|
||||
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(
|
||||
&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;
|
||||
Debug::log(LOG, "Switch {} fired, triggering binds.", NAME);
|
||||
|
||||
if (PDEVICE->status != -1 && PDEVICE->status == E->switch_state)
|
||||
return;
|
||||
g_pKeybindManager->onSwitchEvent(NAME);
|
||||
|
||||
Debug::log(LOG, "Switch {} fired, triggering binds.", NAME);
|
||||
|
||||
g_pKeybindManager->onSwitchEvent(NAME);
|
||||
|
||||
switch (E->switch_state) {
|
||||
case WLR_SWITCH_STATE_ON:
|
||||
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");
|
||||
if (E.enable) {
|
||||
Debug::log(LOG, "Switch {} turn on, triggering binds.", NAME);
|
||||
g_pKeybindManager->onSwitchOnEvent(NAME);
|
||||
} else {
|
||||
Debug::log(LOG, "Switch {} turn off, triggering binds.", NAME);
|
||||
g_pKeybindManager->onSwitchOffEvent(NAME);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
|
||||
|
|
|
@ -18,6 +18,14 @@ class CVirtualKeyboardV1Resource;
|
|||
class CVirtualPointerV1Resource;
|
||||
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 {
|
||||
CLICKMODE_DEFAULT = 0,
|
||||
CLICKMODE_KILL
|
||||
|
@ -82,15 +90,14 @@ class CInputManager {
|
|||
void onKeyboardKey(std::any, SP<IKeyboard>);
|
||||
void onKeyboardMod(SP<IKeyboard>);
|
||||
|
||||
void newKeyboard(wlr_input_device*);
|
||||
void newKeyboard(SP<Aquamarine::IKeyboard>);
|
||||
void newVirtualKeyboard(SP<CVirtualKeyboardV1Resource>);
|
||||
void newMouse(wlr_input_device*);
|
||||
void newMouse(SP<Aquamarine::IPointer>);
|
||||
void newVirtualMouse(SP<CVirtualPointerV1Resource>);
|
||||
void newTouchDevice(wlr_input_device*);
|
||||
void newSwitch(wlr_input_device*);
|
||||
void newTabletTool(wlr_tablet_tool*);
|
||||
void newTabletPad(wlr_input_device*);
|
||||
void newTablet(wlr_input_device*);
|
||||
void newTouchDevice(SP<Aquamarine::ITouch>);
|
||||
void newSwitch(SP<Aquamarine::ISwitch>);
|
||||
void newTabletPad(SP<Aquamarine::ITabletPad>);
|
||||
void newTablet(SP<Aquamarine::ITablet>);
|
||||
void destroyTouchDevice(SP<ITouch>);
|
||||
void destroyKeyboard(SP<IKeyboard>);
|
||||
void destroyPointer(SP<IPointer>);
|
||||
|
@ -232,7 +239,7 @@ class CInputManager {
|
|||
|
||||
void mouseMoveUnified(uint32_t, bool refocus = false);
|
||||
|
||||
SP<CTabletTool> ensureTabletToolPresent(wlr_tablet_tool*);
|
||||
SP<CTabletTool> ensureTabletToolPresent(SP<Aquamarine::ITabletTool>);
|
||||
|
||||
void applyConfigToKeyboard(SP<IKeyboard>);
|
||||
|
||||
|
@ -278,6 +285,14 @@ class CInputManager {
|
|||
|
||||
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 CWLSurface;
|
||||
};
|
||||
|
|
|
@ -62,7 +62,7 @@ static void refocusTablet(SP<CTablet> tab, SP<CTabletTool> tool, bool motion = f
|
|||
if (!motion)
|
||||
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.
|
||||
// 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};
|
||||
|
||||
switch (e.tool->type) {
|
||||
case WLR_TABLET_TOOL_TYPE_MOUSE: {
|
||||
case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE: {
|
||||
g_pPointerManager->move(delta);
|
||||
break;
|
||||
}
|
||||
|
@ -205,12 +205,12 @@ void CInputManager::onTabletProximity(CTablet::SProximityEvent e) {
|
|||
PROTO::idle->onActivity();
|
||||
}
|
||||
|
||||
void CInputManager::newTablet(wlr_input_device* pDevice) {
|
||||
const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(wlr_tablet_from_input_device(pDevice)));
|
||||
void CInputManager::newTablet(SP<Aquamarine::ITablet> pDevice) {
|
||||
const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(pDevice));
|
||||
m_vHIDs.push_back(PNEWTABLET);
|
||||
|
||||
try {
|
||||
PNEWTABLET->hlName = deviceNameToInternalString(pDevice->name);
|
||||
PNEWTABLET->hlName = deviceNameToInternalString(pDevice->getName());
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Tablet had no name???"); // logic error
|
||||
}
|
||||
|
@ -227,28 +227,32 @@ void CInputManager::newTablet(wlr_input_device* pDevice) {
|
|||
setTabletConfigs();
|
||||
}
|
||||
|
||||
SP<CTabletTool> CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) {
|
||||
if (pTool->data == nullptr) {
|
||||
const auto PTOOL = m_vTabletTools.emplace_back(CTabletTool::create(pTool));
|
||||
m_vHIDs.push_back(PTOOL);
|
||||
SP<CTabletTool> CInputManager::ensureTabletToolPresent(SP<Aquamarine::ITabletTool> pTool) {
|
||||
|
||||
PTOOL->events.destroy.registerStaticListener(
|
||||
[this](void* owner, std::any d) {
|
||||
auto TOOL = ((CTabletTool*)owner)->self;
|
||||
destroyTabletTool(TOOL.lock());
|
||||
},
|
||||
PTOOL.get());
|
||||
for (auto& t : m_vTabletTools) {
|
||||
if (t->aq() == pTool)
|
||||
return t;
|
||||
}
|
||||
|
||||
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) {
|
||||
const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(wlr_tablet_pad_from_input_device(pDevice)));
|
||||
void CInputManager::newTabletPad(SP<Aquamarine::ITabletPad> pDevice) {
|
||||
const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(pDevice));
|
||||
m_vHIDs.push_back(PNEWPAD);
|
||||
|
||||
try {
|
||||
PNEWPAD->hlName = deviceNameToInternalString(pDevice->name);
|
||||
PNEWPAD->hlName = deviceNameToInternalString(pDevice->getName());
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Pad had no name???"); // logic error
|
||||
}
|
||||
|
@ -259,7 +263,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) {
|
|||
destroyTabletPad(PAD.lock());
|
||||
}, 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 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);
|
||||
}, 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 PPAD = ((CTabletPad*)owner)->self.lock();
|
||||
|
||||
PROTO::tablet->strip(PPAD, E.strip, E.position, E.finger, E.timeMs);
|
||||
}, 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 PPAD = ((CTabletPad*)owner)->self.lock();
|
||||
|
||||
PROTO::tablet->ring(PPAD, E.ring, E.position, E.finger, E.timeMs);
|
||||
}, 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 TOOL = std::any_cast<SP<CTabletTool>>(e);
|
||||
|
||||
PPAD->parent = TOOL;
|
||||
}, PNEWPAD.get());
|
||||
|
||||
// clang-format on
|
||||
}
|
||||
|
|
|
@ -41,14 +41,11 @@ void CTextInput::initCallbacks() {
|
|||
g_pInputManager->m_sIMERelay.removeTextInput(this);
|
||||
});
|
||||
} else {
|
||||
hyprListener_textInputEnable.initCallback(
|
||||
&pV1Input->sEnable, [this](void* owner, void* data) { onEnabled(); }, this, "textInput");
|
||||
hyprListener_textInputEnable.initCallback(&pV1Input->sEnable, [this](void* owner, void* data) { onEnabled(); }, this, "textInput");
|
||||
|
||||
hyprListener_textInputCommit.initCallback(
|
||||
&pV1Input->sCommit, [this](void* owner, void* data) { onCommit(); }, this, "textInput");
|
||||
hyprListener_textInputCommit.initCallback(&pV1Input->sCommit, [this](void* owner, void* data) { onCommit(); }, this, "textInput");
|
||||
|
||||
hyprListener_textInputDisable.initCallback(
|
||||
&pV1Input->sDisable, [this](void* owner, void* data) { onDisabled(); }, this, "textInput");
|
||||
hyprListener_textInputDisable.initCallback(&pV1Input->sDisable, [this](void* owner, void* data) { onDisabled(); }, this, "textInput");
|
||||
|
||||
hyprListener_textInputDestroy.initCallback(
|
||||
&pV1Input->sDestroy,
|
||||
|
|
|
@ -6,13 +6,15 @@
|
|||
#include "../SeatManager.hpp"
|
||||
|
||||
void CInputManager::onTouchDown(ITouch::SDownEvent e) {
|
||||
m_bLastInputTouch = true;
|
||||
|
||||
static auto PSWIPETOUCH = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch");
|
||||
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
|
||||
auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData();
|
||||
// TODO: WORKSPACERULE.gapsOut.value_or()
|
||||
auto gapsOut = *PGAPSOUT;
|
||||
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);
|
||||
|
||||
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.touchFocusSurface = m_pFoundSurfaceToFocus;
|
||||
m_sTouchData.touchFocusLS = m_pFoundLSToFocus;
|
||||
|
@ -83,6 +83,8 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) {
|
|||
}
|
||||
|
||||
void CInputManager::onTouchUp(ITouch::SUpEvent e) {
|
||||
m_bLastInputTouch = true;
|
||||
|
||||
EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e);
|
||||
if (m_sActiveSwipe.pWorkspaceBegin) {
|
||||
// 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) {
|
||||
m_bLastInputTouch = true;
|
||||
|
||||
EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e);
|
||||
if (m_sActiveSwipe.pWorkspaceBegin) {
|
||||
// Do nothing if this is using a different finger.
|
||||
|
@ -103,7 +107,7 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) {
|
|||
return;
|
||||
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
|
||||
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");
|
||||
const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX);
|
||||
// Handle the workspace swipe if there is one
|
||||
|
|
|
@ -2,18 +2,19 @@ globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
|
|||
src = globber.stdout().strip().split('\n')
|
||||
|
||||
executable('Hyprland', src,
|
||||
cpp_args: ['-DWLR_USE_UNSTABLE'],
|
||||
link_args: '-rdynamic',
|
||||
cpp_pch: 'pch/pch.hpp',
|
||||
dependencies: [
|
||||
server_protos,
|
||||
dependency('aquamarine'),
|
||||
dependency('gbm'),
|
||||
dependency('xcursor'),
|
||||
dependency('wayland-server'),
|
||||
dependency('wayland-client'),
|
||||
wlroots.get_variable('wlroots'),
|
||||
dependency('cairo'),
|
||||
dependency('hyprcursor'),
|
||||
dependency('hyprcursor', version: '>=0.1.7'),
|
||||
dependency('hyprlang', version: '>= 0.3.2'),
|
||||
dependency('hyprutils', version: '>= 0.1.1'),
|
||||
dependency('hyprutils', version: '>= 0.2.0'),
|
||||
dependency('libdrm'),
|
||||
dependency('egl'),
|
||||
dependency('xkbcommon'),
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "../Compositor.hpp"
|
||||
#include "../debug/HyprCtl.hpp"
|
||||
#include <dlfcn.h>
|
||||
#include <filesystem>
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
|
|
|
@ -87,7 +87,7 @@ void CAlphaModifierProtocol::destroyModifier(CAlphaModifier* modifier) {
|
|||
|
||||
void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
|
||||
if (std::find_if(m_mAlphaModifiers.begin(), m_mAlphaModifiers.end(), [surface](const auto& e) { return e.first == surface; }) != m_mAlphaModifiers.end()) {
|
||||
LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface);
|
||||
LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface.get());
|
||||
pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,48 +1,9 @@
|
|||
#include "CursorShape.hpp"
|
||||
#include <algorithm>
|
||||
#include "../helpers/CursorShapes.hpp"
|
||||
|
||||
#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) {
|
||||
;
|
||||
}
|
||||
|
@ -82,7 +43,7 @@ void CCursorShapeProtocol::createCursorShapeDevice(CWpCursorShapeManagerV1* pMgr
|
|||
}
|
||||
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
@ -90,7 +51,7 @@ void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t ser
|
|||
SSetShapeEvent event;
|
||||
event.pMgr = pMgr;
|
||||
event.shape = shape;
|
||||
event.shapeName = SHAPE_NAMES[shape];
|
||||
event.shapeName = CURSOR_SHAPE_NAMES.at(shape);
|
||||
|
||||
events.setShape.emit(event);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue