mirror of
https://github.com/hyprwm/Hyprland.git
synced 2024-11-22 03:06:28 +03:00
Core: Move to aquamarine (#6608)
Moves Hyprland from wlroots to aquamarine for the backend. --------- Signed-off-by: Vaxry <vaxry@vaxry.net> Co-authored-by: Mihai Fufezan <mihai@fufexan.net> Co-authored-by: Jan Beich <jbeich@FreeBSD.org> Co-authored-by: vaxerski <vaxerski@users.noreply.github.com> Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com> Co-authored-by: Tom Englund <tomenglund26@gmail.com> Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com> Co-authored-by: diniamo <diniamo53@gmail.com>
This commit is contained in:
parent
f642fb97df
commit
016da234d0
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'
|
||||
|
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
|
||||
|
@ -1,7 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.27)
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(ExternalProject)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Get version
|
||||
@ -31,9 +30,6 @@ execute_process(
|
||||
# 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")
|
||||
@ -53,18 +49,6 @@ 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)
|
||||
@ -84,12 +68,9 @@ endif()
|
||||
include_directories(
|
||||
.
|
||||
"src/"
|
||||
"subprojects/wlroots-hyprland/include/"
|
||||
"subprojects/wlroots-hyprland/build/include/"
|
||||
"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}/=)
|
||||
@ -109,9 +90,10 @@ endif()
|
||||
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
||||
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET
|
||||
aquamarine
|
||||
xkbcommon uuid
|
||||
wayland-server wayland-client wayland-cursor wayland-protocols
|
||||
cairo pango pangocairo pixman-1
|
||||
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
|
||||
)
|
||||
@ -127,7 +109,6 @@ if(USE_TRACY)
|
||||
endif()
|
||||
|
||||
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
|
||||
add_dependencies(Hyprland wlroots-hyprland)
|
||||
|
||||
set(USE_GPROF ON)
|
||||
|
||||
@ -266,7 +247,6 @@ function(protocolWayland)
|
||||
endfunction()
|
||||
|
||||
target_link_libraries(Hyprland
|
||||
${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a
|
||||
OpenGL::EGL
|
||||
OpenGL::GL
|
||||
Threads::Threads
|
||||
@ -314,6 +294,8 @@ 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()
|
||||
|
||||
@ -326,8 +308,8 @@ install(TARGETS Hyprland)
|
||||
|
||||
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
|
||||
)"
|
||||
)
|
||||
|
||||
@ -358,18 +340,6 @@ install(FILES ${MANPAGES}
|
||||
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}
|
||||
|
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*
|
||||
|
||||
|
30
flake.lock
30
flake.lock
@ -1,5 +1,34 @@
|
||||
{
|
||||
"nodes": {
|
||||
"aquamarine": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
"hyprutils"
|
||||
],
|
||||
"hyprwayland-scanner": [
|
||||
"hyprwayland-scanner"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1721487522,
|
||||
"narHash": "sha256-aF3uwUwUK2CgbItoMe3IJF0yidIEWcDx47AiH5y8VKk=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "aquamarine",
|
||||
"rev": "acfea3bd1d9e756c7152e639240d52c6628844b0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "aquamarine",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprcursor": {
|
||||
"inputs": {
|
||||
"hyprlang": [
|
||||
@ -141,6 +170,7 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"aquamarine": "aquamarine",
|
||||
"hyprcursor": "hyprcursor",
|
||||
"hyprlang": "hyprlang",
|
||||
"hyprutils": "hyprutils",
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -356,7 +356,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 +493,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";
|
||||
|
11
meson.build
11
meson.build
@ -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,
|
||||
@ -104,6 +105,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||
|
||||
buildInputs = lib.concatLists [
|
||||
[
|
||||
aquamarine
|
||||
cairo
|
||||
expat
|
||||
fribidi
|
||||
@ -136,6 +138,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||
(lib.optionals stdenv.hostPlatform.isMusl [libexecinfo])
|
||||
(lib.optionals enableXWayland [
|
||||
xorg.libxcb
|
||||
xorg.libXcursor
|
||||
xorg.libXdmcp
|
||||
xorg.xcbutil
|
||||
xorg.xcbutilerrors
|
||||
|
@ -21,6 +21,7 @@ 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
|
||||
|
@ -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
|
@ -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 = []
|
||||
|
@ -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,16 +25,20 @@
|
||||
#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);
|
||||
|
||||
@ -72,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);
|
||||
@ -180,6 +204,9 @@ void CCompositor::setRandomSplash() {
|
||||
m_szCurrentSplash = SPLASHES[distribution(engine)];
|
||||
}
|
||||
|
||||
static std::vector<SP<Aquamarine::IOutput>> pendingOutputs;
|
||||
|
||||
//
|
||||
void CCompositor::initServer() {
|
||||
|
||||
m_sWLDisplay = wl_display_create();
|
||||
@ -200,102 +227,179 @@ 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.
|
||||
} 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!");
|
||||
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);
|
||||
|
||||
// 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!");
|
||||
}
|
||||
Debug::log(LOG, "Setting WAYLAND_DISPLAY to {}", m_szWLDisplaySocket);
|
||||
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() {
|
||||
@ -309,7 +413,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 "
|
||||
@ -352,7 +456,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();
|
||||
}
|
||||
|
||||
@ -389,14 +493,8 @@ 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);
|
||||
@ -442,6 +540,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!");
|
||||
@ -472,9 +573,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>();
|
||||
|
||||
@ -517,26 +615,23 @@ 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);
|
||||
SP<Aquamarine::IBackendImplementation> headless;
|
||||
for (auto& impl : m_pAqBackend->getImplementations()) {
|
||||
if (impl->type() == Aquamarine::AQ_BACKEND_HEADLESS) {
|
||||
headless = impl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!headless) {
|
||||
Debug::log(WARN, "Unsafe state will be ineffective, no fallback output");
|
||||
Debug::log(WARN, "No headless in prepareFallbackOutput?!");
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_headless_add_output(headless, 1920, 1080);
|
||||
headless->createOutput();
|
||||
}
|
||||
|
||||
void CCompositor::startCompositor(std::string socketName, int socketFd) {
|
||||
initAllSignals();
|
||||
|
||||
if (!socketName.empty() && socketFd != -1) {
|
||||
fcntl(socketFd, F_SETFD, FD_CLOEXEC);
|
||||
const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd);
|
||||
@ -568,15 +663,15 @@ void CCompositor::startCompositor(std::string socketName, int socketFd) {
|
||||
|
||||
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);
|
||||
setenv("XDG_SESSION_TYPE", "wayland", 1);
|
||||
|
||||
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 "
|
||||
@ -588,13 +683,6 @@ void CCompositor::startCompositor(std::string socketName, int socketFd) {
|
||||
|
||||
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");
|
||||
@ -882,7 +970,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();
|
||||
@ -892,7 +980,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();
|
||||
@ -2240,8 +2328,12 @@ 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.
|
||||
g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr);
|
||||
|
||||
g_pConfigManager->ensureVRR(PMONITOR);
|
||||
}
|
||||
@ -2282,8 +2374,8 @@ void CCompositor::updateWorkspaceWindowData(const int& id) {
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@ -2292,7 +2384,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) {
|
||||
@ -2808,3 +2900,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 = "";
|
||||
|
||||
@ -94,10 +86,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 +107,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);
|
||||
@ -157,7 +148,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 +173,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;
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <ranges>
|
||||
#include <unordered_set>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <filesystem>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
extern "C" char** environ;
|
||||
@ -539,6 +540,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});
|
||||
|
||||
@ -557,6 +559,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});
|
||||
@ -1285,7 +1289,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 "
|
||||
@ -1410,7 +1414,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);
|
||||
@ -1419,11 +1424,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())
|
||||
@ -1442,19 +1447,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);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <filesystem>
|
||||
|
||||
#include "../plugins/PluginSystem.hpp"
|
||||
#include "../signal-safe.hpp"
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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";
|
||||
@ -1368,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, ' ');
|
||||
|
||||
@ -1413,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") {
|
||||
@ -1433,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";
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -1155,7 +1155,8 @@ int CWindow::getRealBorderSize() {
|
||||
}
|
||||
|
||||
bool CWindow::canBeTorn() {
|
||||
return m_sWindowData.tearing.valueOr(m_bTearingHint);
|
||||
static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
|
||||
return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING;
|
||||
}
|
||||
|
||||
bool CWindow::shouldSendFullscreenState() {
|
||||
|
@ -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,149 @@ 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
// set internal translation state
|
||||
// demo sunao ni ienai
|
||||
xkbStaticState = xkb_state_new(xkbKeymap);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
xkb_context_unref(CONTEXT);
|
||||
|
||||
g_pSeatManager->updateActiveKeyboardData();
|
||||
}
|
||||
|
||||
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
|
||||
|
||||
if (xkbTranslationState)
|
||||
xkb_state_unref(xkbTranslationState);
|
||||
if (xkbState)
|
||||
xkb_state_unref(xkbState);
|
||||
|
||||
xkbState = nullptr;
|
||||
|
||||
if (keymap) {
|
||||
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
|
||||
xkbTranslationState = 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 +209,7 @@ 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);
|
||||
|
||||
xkb_keymap_unref(KEYMAP);
|
||||
xkb_context_unref(PCONTEXT);
|
||||
@ -94,16 +230,15 @@ 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);
|
||||
|
||||
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 +255,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 +268,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,46 @@ class IKeyboard : public IHID {
|
||||
std::string rules = "";
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
bool active = false;
|
||||
bool enabled = true;
|
||||
|
||||
xkb_layout_index_t activeLayout = 0;
|
||||
xkb_state* xkbTranslationState = nullptr;
|
||||
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;
|
||||
|
||||
std::string hlName = "";
|
||||
std::string xkbFilePath = "";
|
||||
struct {
|
||||
uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
|
||||
} modifiersState;
|
||||
|
||||
SStringRuleNames currentRules;
|
||||
int repeatRate = 0;
|
||||
int repeatDelay = 0;
|
||||
int numlockOn = -1;
|
||||
bool resolveBindsBySym = false;
|
||||
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;
|
||||
|
||||
WP<IKeyboard> self;
|
||||
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);
|
||||
|
||||
updateXkbStateWithKey(E.key + 8, E.pressed);
|
||||
|
||||
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");
|
||||
listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
|
||||
updateModifiersState();
|
||||
|
||||
hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) {
|
||||
keyboardEvents.modifiers.emit();
|
||||
}, this, "CKeyboard");
|
||||
keyboardEvents.modifiers.emit(SModifiersEvent{
|
||||
.depressed = modifiersState.depressed,
|
||||
.latched = modifiersState.latched,
|
||||
.locked = modifiersState.locked,
|
||||
.group = modifiersState.group,
|
||||
});
|
||||
});
|
||||
|
||||
hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) {
|
||||
keyboardEvents.repeatInfo.emit();
|
||||
}, this, "CKeyboard");
|
||||
// clang-format on
|
||||
|
||||
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;
|
||||
|
||||
padEvents.attach.emit(CTabletTool::fromWlr((wlr_tablet_tool*)data));
|
||||
}, this, "CTabletPad");
|
||||
// clang-format on
|
||||
listeners.attach = pad->events.attach.registerListener([this](std::any d) {
|
||||
; // TODO: this doesn't do anything in aq atm
|
||||
});
|
||||
|
||||
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,37 @@ 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);
|
||||
xkbKeymap = xkb_keymap_ref(E.keymap);
|
||||
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,32 @@ 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) { pointerEvents.motionAbsolute.emit(d); });
|
||||
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,7 @@
|
||||
#include "Events.hpp"
|
||||
#include "../debug/HyprCtl.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
|
||||
// --------------------------------------------------------- //
|
||||
// __ __ ____ _ _ _____ _______ ____ _____ _____ //
|
||||
@ -16,99 +17,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 +84,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 +98,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 +108,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
|
||||
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR);
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
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>
|
||||
|
@ -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,14 +137,14 @@ 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);
|
||||
|
||||
@ -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
|
||||
|
@ -105,3 +105,8 @@
|
||||
class name; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AQUAMARINE_FORWARD(name) \
|
||||
namespace Aquamarine { \
|
||||
class name; \
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
@ -157,37 +160,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;
|
||||
}
|
||||
}
|
||||
@ -366,8 +369,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 +557,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;
|
||||
}
|
||||
@ -786,7 +789,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 +813,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 +895,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);
|
||||
@ -1659,7 +1662,7 @@ void CKeybindManager::renameWorkspace(std::string args) {
|
||||
}
|
||||
|
||||
void CKeybindManager::exitHyprland(std::string argz) {
|
||||
g_pCompositor->m_bExitTriggered = true;
|
||||
g_pEventLoopManager->doLater([]() { g_pCompositor->cleanup(); });
|
||||
}
|
||||
|
||||
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
|
||||
@ -2121,8 +2124,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);
|
||||
@ -2259,7 +2262,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;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "../Compositor.hpp"
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "../devices/IPointer.hpp"
|
||||
|
||||
class CInputManager;
|
||||
|
@ -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) {
|
||||
@ -201,6 +76,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 +96,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,10 +112,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;
|
||||
@ -317,8 +195,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;
|
||||
@ -339,16 +217,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};
|
||||
@ -370,9 +243,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;
|
||||
}
|
||||
}
|
||||
@ -418,18 +290,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();
|
||||
|
||||
@ -459,64 +331,62 @@ 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);
|
||||
auto buf = state->monitor->cursorSwapchain->next(nullptr);
|
||||
if (!buf) {
|
||||
Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain");
|
||||
return nullptr;
|
||||
@ -525,16 +395,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);
|
||||
@ -543,9 +442,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;
|
||||
}
|
||||
@ -579,7 +476,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);
|
||||
@ -587,17 +484,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();
|
||||
}
|
||||
|
||||
@ -799,10 +698,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,45 +138,42 @@ 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;
|
||||
|
||||
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;
|
||||
|
@ -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,8 @@
|
||||
#include "../protocols/Viewporter.hpp"
|
||||
#include "../protocols/MesaDRM.hpp"
|
||||
#include "../protocols/LinuxDMABUF.hpp"
|
||||
#include "../protocols/DRMLease.hpp"
|
||||
#include "../protocols/DRMSyncobj.hpp"
|
||||
|
||||
#include "../protocols/core/Seat.hpp"
|
||||
#include "../protocols/core/DataDevice.hpp"
|
||||
@ -45,6 +49,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();
|
||||
@ -65,6 +73,8 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) {
|
||||
|
||||
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);
|
||||
@ -131,6 +141,16 @@ CProtocolManager::CProtocolManager() {
|
||||
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");
|
||||
|
||||
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");
|
||||
PROTO::linuxDma = std::make_unique<CLinuxDMABufV1Protocol>(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
@ -25,9 +28,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;
|
@ -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();
|
||||
|
||||
@ -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)) {
|
||||
@ -843,8 +845,8 @@ 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);
|
||||
|
||||
@ -856,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
|
||||
}
|
||||
@ -962,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();
|
||||
|
||||
@ -1053,11 +984,11 @@ 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);
|
||||
|
||||
@ -1068,13 +999,13 @@ 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),
|
||||
@ -1120,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) &&
|
||||
@ -1261,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);
|
||||
@ -1287,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);
|
||||
@ -1333,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) {
|
||||
@ -1374,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);
|
||||
@ -1392,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);
|
||||
@ -1409,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}));
|
||||
@ -1524,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;
|
||||
@ -1543,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
|
||||
}
|
||||
@ -1572,8 +1489,8 @@ 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);
|
||||
if (dev->aq() && dev->aq()->getLibinputHandle()) {
|
||||
const auto LIBINPUTDEV = dev->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;
|
||||
@ -1589,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;
|
||||
@ -1617,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;
|
||||
@ -1647,51 +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>);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -2,14 +2,15 @@ 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', version: '>=0.1.7'),
|
||||
dependency('hyprlang', version: '>= 0.3.2'),
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
302
src/protocols/DRMLease.cpp
Normal file
302
src/protocols/DRMLease.cpp
Normal file
@ -0,0 +1,302 @@
|
||||
#include "DRMLease.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include <aquamarine/backend/DRM.hpp>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define LOGM PROTO::lease->protoLog
|
||||
|
||||
CDRMLeaseResource::CDRMLeaseResource(SP<CWpDrmLeaseV1> resource_, SP<CDRMLeaseRequestResource> request) : resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setOnDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); });
|
||||
resource->setDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); });
|
||||
|
||||
parent = request->parent;
|
||||
requested = request->requested;
|
||||
|
||||
for (auto& m : requested) {
|
||||
if (!m->monitor || m->monitor->isBeingLeased) {
|
||||
LOGM(ERR, "Rejecting lease: no monitor or monitor is being leased for {}", (m->monitor ? m->monitor->szName : "null"));
|
||||
resource->sendFinished();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// grant the lease if it is seemingly valid
|
||||
|
||||
LOGM(LOG, "Leasing outputs: {}", [this]() {
|
||||
std::string roll;
|
||||
for (auto& o : requested) {
|
||||
roll += std::format("{} ", o->monitor->szName);
|
||||
}
|
||||
return roll;
|
||||
}());
|
||||
|
||||
std::vector<SP<Aquamarine::IOutput>> outputs;
|
||||
for (auto& m : requested) {
|
||||
outputs.emplace_back(m->monitor->output);
|
||||
}
|
||||
|
||||
auto aqlease = Aquamarine::CDRMLease::create(outputs);
|
||||
if (!aqlease) {
|
||||
LOGM(ERR, "Rejecting lease: backend failed to alloc a lease");
|
||||
resource->sendFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
LOGM(LOG, "Granting lease, sending fd {}", aqlease->leaseFD);
|
||||
|
||||
resource->sendLeaseFd(aqlease->leaseFD);
|
||||
|
||||
lease = aqlease;
|
||||
|
||||
for (auto& m : requested) {
|
||||
m->monitor->isBeingLeased = true;
|
||||
}
|
||||
|
||||
listeners.destroyLease = lease->events.destroy.registerListener([this](std::any d) {
|
||||
for (auto& m : requested) {
|
||||
if (m && m->monitor)
|
||||
m->monitor->isBeingLeased = false;
|
||||
}
|
||||
|
||||
resource->sendFinished();
|
||||
});
|
||||
|
||||
close(lease->leaseFD);
|
||||
}
|
||||
|
||||
bool CDRMLeaseResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP<CWpDrmLeaseRequestV1> resource_) : resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setOnDestroy([this](CWpDrmLeaseRequestV1* r) { PROTO::lease->destroyResource(this); });
|
||||
|
||||
resource->setRequestConnector([this](CWpDrmLeaseRequestV1* r, wl_resource* conn) {
|
||||
if (!conn) {
|
||||
resource->error(-1, "Null connector");
|
||||
return;
|
||||
}
|
||||
|
||||
auto CONNECTOR = CDRMLeaseConnectorResource::fromResource(conn);
|
||||
|
||||
if (std::find(requested.begin(), requested.end(), CONNECTOR) != requested.end()) {
|
||||
resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR, "Connector already requested");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: when (if) we add multi, make sure this is from the correct device.
|
||||
|
||||
requested.emplace_back(CONNECTOR);
|
||||
});
|
||||
|
||||
resource->setSubmit([this](CWpDrmLeaseRequestV1* r, uint32_t id) {
|
||||
if (requested.empty()) {
|
||||
resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE, "No connectors added");
|
||||
return;
|
||||
}
|
||||
|
||||
auto RESOURCE = makeShared<CDRMLeaseResource>(makeShared<CWpDrmLeaseV1>(resource->client(), resource->version(), -1), self.lock());
|
||||
if (!RESOURCE) {
|
||||
resource->noMemory();
|
||||
return;
|
||||
}
|
||||
|
||||
PROTO::lease->m_vLeases.emplace_back(RESOURCE);
|
||||
|
||||
// per protcol, after submit, this is dead.
|
||||
PROTO::lease->destroyResource(this);
|
||||
});
|
||||
}
|
||||
|
||||
bool CDRMLeaseRequestResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
SP<CDRMLeaseConnectorResource> CDRMLeaseConnectorResource::fromResource(wl_resource* res) {
|
||||
auto data = (CDRMLeaseConnectorResource*)(((CWpDrmLeaseConnectorV1*)wl_resource_get_user_data(res))->data());
|
||||
return data ? data->self.lock() : nullptr;
|
||||
}
|
||||
|
||||
CDRMLeaseConnectorResource::CDRMLeaseConnectorResource(SP<CWpDrmLeaseConnectorV1> resource_, SP<CMonitor> monitor_) : monitor(monitor_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setOnDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); });
|
||||
resource->setDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); });
|
||||
|
||||
resource->setData(this);
|
||||
|
||||
listeners.destroyMonitor = monitor->events.destroy.registerListener([this](std::any d) {
|
||||
resource->sendWithdrawn();
|
||||
dead = true;
|
||||
});
|
||||
}
|
||||
|
||||
bool CDRMLeaseConnectorResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CDRMLeaseConnectorResource::sendData() {
|
||||
resource->sendName(monitor->szName.c_str());
|
||||
resource->sendDescription(monitor->szDescription.c_str());
|
||||
|
||||
auto AQDRMOutput = (Aquamarine::CDRMOutput*)monitor->output.get();
|
||||
resource->sendConnectorId(AQDRMOutput->getConnectorID());
|
||||
|
||||
resource->sendDone();
|
||||
}
|
||||
|
||||
CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP<CWpDrmLeaseDeviceV1> resource_) : resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setOnDestroy([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); });
|
||||
resource->setRelease([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); });
|
||||
|
||||
resource->setCreateLeaseRequest([this](CWpDrmLeaseDeviceV1* r, uint32_t id) {
|
||||
auto RESOURCE = makeShared<CDRMLeaseRequestResource>(makeShared<CWpDrmLeaseRequestV1>(resource->client(), resource->version(), id));
|
||||
if (!RESOURCE) {
|
||||
resource->noMemory();
|
||||
return;
|
||||
}
|
||||
|
||||
RESOURCE->self = RESOURCE;
|
||||
|
||||
PROTO::lease->m_vRequests.emplace_back(RESOURCE);
|
||||
|
||||
LOGM(LOG, "New lease request {}", id);
|
||||
|
||||
RESOURCE->parent = self;
|
||||
});
|
||||
|
||||
int fd = ((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD();
|
||||
if (fd < 0) {
|
||||
LOGM(ERR, "Failed to dup fd in lease");
|
||||
return;
|
||||
}
|
||||
|
||||
LOGM(LOG, "Sending DRMFD {} to new lease device", fd);
|
||||
resource->sendDrmFd(fd);
|
||||
close(fd);
|
||||
|
||||
for (auto& m : PROTO::lease->primaryDevice->offeredOutputs) {
|
||||
sendConnector(m.lock());
|
||||
}
|
||||
|
||||
resource->sendDone();
|
||||
}
|
||||
|
||||
bool CDRMLeaseDeviceResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CDRMLeaseDeviceResource::sendConnector(SP<CMonitor> monitor) {
|
||||
if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e->monitor == monitor; }) != connectorsSent.end())
|
||||
return;
|
||||
|
||||
auto RESOURCE = makeShared<CDRMLeaseConnectorResource>(makeShared<CWpDrmLeaseConnectorV1>(resource->client(), resource->version(), -1), monitor);
|
||||
if (!RESOURCE) {
|
||||
resource->noMemory();
|
||||
return;
|
||||
}
|
||||
|
||||
RESOURCE->parent = self;
|
||||
RESOURCE->self = RESOURCE;
|
||||
|
||||
LOGM(LOG, "Sending new connector {}", monitor->szName);
|
||||
|
||||
connectorsSent.emplace_back(RESOURCE);
|
||||
PROTO::lease->m_vConnectors.emplace_back(RESOURCE);
|
||||
|
||||
resource->sendConnector(RESOURCE->resource.get());
|
||||
|
||||
RESOURCE->sendData();
|
||||
}
|
||||
|
||||
CDRMLeaseDevice::CDRMLeaseDevice(SP<Aquamarine::CDRMBackend> drmBackend) : backend(drmBackend) {
|
||||
auto drm = (Aquamarine::CDRMBackend*)drmBackend.get();
|
||||
|
||||
auto fd = drm->getNonMasterFD();
|
||||
|
||||
if (fd < 0) {
|
||||
LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName);
|
||||
return;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
success = true;
|
||||
name = drm->gpuName;
|
||||
}
|
||||
|
||||
CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||
for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) {
|
||||
if (b->type() != Aquamarine::AQ_BACKEND_DRM)
|
||||
continue;
|
||||
|
||||
auto drm = ((Aquamarine::CDRMBackend*)b.get())->self.lock();
|
||||
|
||||
primaryDevice = makeShared<CDRMLeaseDevice>(drm);
|
||||
|
||||
if (primaryDevice->success)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!primaryDevice || primaryDevice->success) {
|
||||
PROTO::lease.reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CDRMLeaseDeviceResource>(makeShared<CWpDrmLeaseDeviceV1>(client, ver, id)));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
wl_client_post_no_memory(client);
|
||||
m_vManagers.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
RESOURCE->self = RESOURCE;
|
||||
}
|
||||
|
||||
void CDRMLeaseProtocol::destroyResource(CDRMLeaseDeviceResource* resource) {
|
||||
std::erase_if(m_vManagers, [resource](const auto& e) { return e.get() == resource; });
|
||||
}
|
||||
|
||||
void CDRMLeaseProtocol::destroyResource(CDRMLeaseConnectorResource* resource) {
|
||||
std::erase_if(m_vConnectors, [resource](const auto& e) { return e.get() == resource; });
|
||||
}
|
||||
|
||||
void CDRMLeaseProtocol::destroyResource(CDRMLeaseRequestResource* resource) {
|
||||
std::erase_if(m_vRequests, [resource](const auto& e) { return e.get() == resource; });
|
||||
}
|
||||
|
||||
void CDRMLeaseProtocol::destroyResource(CDRMLeaseResource* resource) {
|
||||
std::erase_if(m_vLeases, [resource](const auto& e) { return e.get() == resource; });
|
||||
}
|
||||
|
||||
void CDRMLeaseProtocol::offer(SP<CMonitor> monitor) {
|
||||
if (std::find(primaryDevice->offeredOutputs.begin(), primaryDevice->offeredOutputs.end(), monitor) != primaryDevice->offeredOutputs.end())
|
||||
return;
|
||||
|
||||
if (monitor->output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM)
|
||||
return;
|
||||
|
||||
if (monitor->output->getBackend() != primaryDevice->backend) {
|
||||
LOGM(ERR, "Monitor {} cannot be leased: primaryDevice lease is for a different device", monitor->szName);
|
||||
return;
|
||||
}
|
||||
|
||||
primaryDevice->offeredOutputs.emplace_back(monitor);
|
||||
|
||||
for (auto& m : m_vManagers) {
|
||||
m->sendConnector(monitor);
|
||||
m->resource->sendDone();
|
||||
}
|
||||
}
|
137
src/protocols/DRMLease.hpp
Normal file
137
src/protocols/DRMLease.hpp
Normal file
@ -0,0 +1,137 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "drm-lease-v1.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
/*
|
||||
TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu)
|
||||
*/
|
||||
|
||||
AQUAMARINE_FORWARD(CDRMBackend);
|
||||
AQUAMARINE_FORWARD(CDRMLease);
|
||||
class CDRMLeaseDeviceResource;
|
||||
class CMonitor;
|
||||
class CDRMLeaseProtocol;
|
||||
class CDRMLeaseConnectorResource;
|
||||
class CDRMLeaseRequestResource;
|
||||
|
||||
class CDRMLeaseResource {
|
||||
public:
|
||||
CDRMLeaseResource(SP<CWpDrmLeaseV1> resource_, SP<CDRMLeaseRequestResource> request);
|
||||
|
||||
bool good();
|
||||
|
||||
WP<CDRMLeaseDeviceResource> parent;
|
||||
std::vector<WP<CDRMLeaseConnectorResource>> requested;
|
||||
WP<Aquamarine::CDRMLease> lease;
|
||||
|
||||
int leaseFD = -1;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener destroyLease;
|
||||
} listeners;
|
||||
|
||||
private:
|
||||
SP<CWpDrmLeaseV1> resource;
|
||||
};
|
||||
|
||||
class CDRMLeaseRequestResource {
|
||||
public:
|
||||
CDRMLeaseRequestResource(SP<CWpDrmLeaseRequestV1> resource_);
|
||||
|
||||
bool good();
|
||||
|
||||
WP<CDRMLeaseDeviceResource> parent;
|
||||
WP<CDRMLeaseRequestResource> self;
|
||||
std::vector<WP<CDRMLeaseConnectorResource>> requested;
|
||||
|
||||
private:
|
||||
SP<CWpDrmLeaseRequestV1> resource;
|
||||
};
|
||||
|
||||
class CDRMLeaseConnectorResource {
|
||||
public:
|
||||
CDRMLeaseConnectorResource(SP<CWpDrmLeaseConnectorV1> resource_, SP<CMonitor> monitor_);
|
||||
static SP<CDRMLeaseConnectorResource> fromResource(wl_resource*);
|
||||
|
||||
bool good();
|
||||
void sendData();
|
||||
|
||||
WP<CDRMLeaseConnectorResource> self;
|
||||
WP<CDRMLeaseDeviceResource> parent;
|
||||
WP<CMonitor> monitor;
|
||||
bool dead = false;
|
||||
|
||||
private:
|
||||
SP<CWpDrmLeaseConnectorV1> resource;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener destroyMonitor;
|
||||
} listeners;
|
||||
|
||||
friend class CDRMLeaseDeviceResource;
|
||||
};
|
||||
|
||||
class CDRMLeaseDeviceResource {
|
||||
public:
|
||||
CDRMLeaseDeviceResource(SP<CWpDrmLeaseDeviceV1> resource_);
|
||||
|
||||
bool good();
|
||||
void sendConnector(SP<CMonitor> monitor);
|
||||
|
||||
std::vector<WP<CDRMLeaseConnectorResource>> connectorsSent;
|
||||
|
||||
WP<CDRMLeaseDeviceResource> self;
|
||||
|
||||
private:
|
||||
SP<CWpDrmLeaseDeviceV1> resource;
|
||||
|
||||
friend class CDRMLeaseProtocol;
|
||||
};
|
||||
|
||||
class CDRMLeaseDevice {
|
||||
public:
|
||||
CDRMLeaseDevice(SP<Aquamarine::CDRMBackend> drmBackend);
|
||||
|
||||
std::string name = "";
|
||||
bool success = false;
|
||||
SP<Aquamarine::CDRMBackend> backend;
|
||||
|
||||
std::vector<WP<CMonitor>> offeredOutputs;
|
||||
};
|
||||
|
||||
class CDRMLeaseProtocol : public IWaylandProtocol {
|
||||
public:
|
||||
CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name);
|
||||
|
||||
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
|
||||
|
||||
void offer(SP<CMonitor> monitor);
|
||||
|
||||
private:
|
||||
void destroyResource(CDRMLeaseDeviceResource* resource);
|
||||
void destroyResource(CDRMLeaseConnectorResource* resource);
|
||||
void destroyResource(CDRMLeaseRequestResource* resource);
|
||||
void destroyResource(CDRMLeaseResource* resource);
|
||||
|
||||
//
|
||||
std::vector<SP<CDRMLeaseDeviceResource>> m_vManagers;
|
||||
std::vector<SP<CDRMLeaseConnectorResource>> m_vConnectors;
|
||||
std::vector<SP<CDRMLeaseRequestResource>> m_vRequests;
|
||||
std::vector<SP<CDRMLeaseResource>> m_vLeases;
|
||||
|
||||
SP<CDRMLeaseDevice> primaryDevice;
|
||||
|
||||
friend class CDRMLeaseDeviceResource;
|
||||
friend class CDRMLeaseConnectorResource;
|
||||
friend class CDRMLeaseRequestResource;
|
||||
friend class CDRMLeaseResource;
|
||||
};
|
||||
|
||||
namespace PROTO {
|
||||
inline UP<CDRMLeaseProtocol> lease;
|
||||
};
|
183
src/protocols/DRMSyncobj.cpp
Normal file
183
src/protocols/DRMSyncobj.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
#include "DRMSyncobj.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
#include "core/Compositor.hpp"
|
||||
#include "../helpers/sync/SyncTimeline.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#define LOGM PROTO::sync->protoLog
|
||||
|
||||
CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurfaceV1> resource_, SP<CWLSurfaceResource> surface_) : surface(surface_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setData(this);
|
||||
|
||||
resource->setOnDestroy([this](CWpLinuxDrmSyncobjSurfaceV1* r) { PROTO::sync->destroyResource(this); });
|
||||
resource->setDestroy([this](CWpLinuxDrmSyncobjSurfaceV1* r) { PROTO::sync->destroyResource(this); });
|
||||
|
||||
resource->setSetAcquirePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) {
|
||||
if (!surface) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface is gone");
|
||||
return;
|
||||
}
|
||||
|
||||
auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
|
||||
acquireTimeline = timeline;
|
||||
acquirePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
|
||||
});
|
||||
|
||||
resource->setSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) {
|
||||
if (!surface) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface is gone");
|
||||
return;
|
||||
}
|
||||
|
||||
auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
|
||||
releaseTimeline = timeline;
|
||||
releasePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
|
||||
});
|
||||
|
||||
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
|
||||
if (!!acquireTimeline != !!releaseTimeline) {
|
||||
resource->error(acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing timeline");
|
||||
surface->pending.rejected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((acquireTimeline || releaseTimeline) && !surface->pending.buffer) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
|
||||
surface->pending.rejected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!acquireTimeline)
|
||||
return;
|
||||
|
||||
// wait for the acquire timeline to materialize
|
||||
auto materialized = acquireTimeline->timeline->check(acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
|
||||
if (!materialized.has_value()) {
|
||||
LOGM(ERR, "Failed to check the acquire timeline");
|
||||
resource->noMemory();
|
||||
return;
|
||||
}
|
||||
|
||||
if (materialized)
|
||||
return;
|
||||
|
||||
surface->lockPendingState();
|
||||
acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
|
||||
});
|
||||
}
|
||||
|
||||
bool CDRMSyncobjSurfaceResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP<CWpLinuxDrmSyncobjTimelineV1> resource_, int fd_) : fd(fd_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setData(this);
|
||||
|
||||
resource->setOnDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); });
|
||||
resource->setDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); });
|
||||
|
||||
timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd);
|
||||
|
||||
if (!timeline) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Timeline failed importing");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SP<CDRMSyncobjTimelineResource> CDRMSyncobjTimelineResource::fromResource(wl_resource* res) {
|
||||
auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data());
|
||||
return data ? data->self.lock() : nullptr;
|
||||
}
|
||||
|
||||
bool CDRMSyncobjTimelineResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SP<CWpLinuxDrmSyncobjManagerV1> resource_) : resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setOnDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); });
|
||||
resource->setDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); });
|
||||
|
||||
resource->setGetSurface([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, wl_resource* surf) {
|
||||
if (!surf) {
|
||||
resource->error(-1, "Invalid surface");
|
||||
return;
|
||||
}
|
||||
|
||||
auto SURF = CWLSurfaceResource::fromResource(surf);
|
||||
if (!SURF) {
|
||||
resource->error(-1, "Invalid surface (2)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SURF->syncobj) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_SURFACE_EXISTS, "Surface already has a syncobj attached");
|
||||
return;
|
||||
}
|
||||
|
||||
auto RESOURCE = makeShared<CDRMSyncobjSurfaceResource>(makeShared<CWpLinuxDrmSyncobjSurfaceV1>(resource->client(), resource->version(), id), SURF);
|
||||
if (!RESOURCE->good()) {
|
||||
resource->noMemory();
|
||||
return;
|
||||
}
|
||||
|
||||
PROTO::sync->m_vSurfaces.emplace_back(RESOURCE);
|
||||
SURF->syncobj = RESOURCE;
|
||||
|
||||
LOGM(LOG, "New linux_syncobj at {:x} for surface {:x}", (uintptr_t)RESOURCE.get(), (uintptr_t)SURF.get());
|
||||
});
|
||||
|
||||
resource->setImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) {
|
||||
auto RESOURCE = makeShared<CDRMSyncobjTimelineResource>(makeShared<CWpLinuxDrmSyncobjTimelineV1>(resource->client(), resource->version(), id), fd);
|
||||
if (!RESOURCE->good()) {
|
||||
resource->noMemory();
|
||||
return;
|
||||
}
|
||||
|
||||
PROTO::sync->m_vTimelines.emplace_back(RESOURCE);
|
||||
RESOURCE->self = RESOURCE;
|
||||
|
||||
LOGM(LOG, "New linux_drm_timeline at {:x}", (uintptr_t)RESOURCE.get());
|
||||
});
|
||||
}
|
||||
|
||||
bool CDRMSyncobjManagerResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
CDRMSyncobjProtocol::CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||
drmFD = g_pCompositor->m_iDRMFD;
|
||||
}
|
||||
|
||||
void CDRMSyncobjProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CDRMSyncobjManagerResource>(makeShared<CWpLinuxDrmSyncobjManagerV1>(client, ver, id)));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
wl_client_post_no_memory(client);
|
||||
m_vManagers.pop_back();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjManagerResource* resource) {
|
||||
std::erase_if(m_vManagers, [resource](const auto& e) { return e.get() == resource; });
|
||||
}
|
||||
|
||||
void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjTimelineResource* resource) {
|
||||
std::erase_if(m_vTimelines, [resource](const auto& e) { return e.get() == resource; });
|
||||
}
|
||||
|
||||
void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjSurfaceResource* resource) {
|
||||
std::erase_if(m_vSurfaces, [resource](const auto& e) { return e.get() == resource; });
|
||||
}
|
82
src/protocols/DRMSyncobj.hpp
Normal file
82
src/protocols/DRMSyncobj.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "linux-drm-syncobj-v1.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CWLSurfaceResource;
|
||||
class CDRMSyncobjTimelineResource;
|
||||
class CSyncTimeline;
|
||||
|
||||
class CDRMSyncobjSurfaceResource {
|
||||
public:
|
||||
CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurfaceV1> resource_, SP<CWLSurfaceResource> surface_);
|
||||
|
||||
bool good();
|
||||
|
||||
WP<CWLSurfaceResource> surface;
|
||||
WP<CDRMSyncobjTimelineResource> acquireTimeline, releaseTimeline;
|
||||
uint64_t acquirePoint = 0, releasePoint = 0;
|
||||
|
||||
private:
|
||||
SP<CWpLinuxDrmSyncobjSurfaceV1> resource;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener surfacePrecommit;
|
||||
} listeners;
|
||||
};
|
||||
|
||||
class CDRMSyncobjTimelineResource {
|
||||
public:
|
||||
CDRMSyncobjTimelineResource(SP<CWpLinuxDrmSyncobjTimelineV1> resource_, int fd_);
|
||||
static SP<CDRMSyncobjTimelineResource> fromResource(wl_resource*);
|
||||
|
||||
bool good();
|
||||
|
||||
WP<CDRMSyncobjTimelineResource> self;
|
||||
int fd = -1;
|
||||
SP<CSyncTimeline> timeline;
|
||||
|
||||
private:
|
||||
SP<CWpLinuxDrmSyncobjTimelineV1> resource;
|
||||
};
|
||||
|
||||
class CDRMSyncobjManagerResource {
|
||||
public:
|
||||
CDRMSyncobjManagerResource(SP<CWpLinuxDrmSyncobjManagerV1> resource_);
|
||||
|
||||
bool good();
|
||||
|
||||
private:
|
||||
SP<CWpLinuxDrmSyncobjManagerV1> resource;
|
||||
};
|
||||
|
||||
class CDRMSyncobjProtocol : public IWaylandProtocol {
|
||||
public:
|
||||
CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name);
|
||||
|
||||
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
|
||||
|
||||
private:
|
||||
void destroyResource(CDRMSyncobjManagerResource* resource);
|
||||
void destroyResource(CDRMSyncobjTimelineResource* resource);
|
||||
void destroyResource(CDRMSyncobjSurfaceResource* resource);
|
||||
|
||||
//
|
||||
std::vector<SP<CDRMSyncobjManagerResource>> m_vManagers;
|
||||
std::vector<SP<CDRMSyncobjTimelineResource>> m_vTimelines;
|
||||
std::vector<SP<CDRMSyncobjSurfaceResource>> m_vSurfaces;
|
||||
|
||||
//
|
||||
int drmFD = -1;
|
||||
|
||||
friend class CDRMSyncobjManagerResource;
|
||||
friend class CDRMSyncobjTimelineResource;
|
||||
friend class CDRMSyncobjSurfaceResource;
|
||||
};
|
||||
|
||||
namespace PROTO {
|
||||
inline UP<CDRMSyncobjProtocol> sync;
|
||||
};
|
@ -34,7 +34,7 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* out
|
||||
}
|
||||
}
|
||||
|
||||
gammaSize = wlr_output_get_gamma_size(pMonitor->output);
|
||||
gammaSize = pMonitor->output->getGammaSize();
|
||||
|
||||
if (gammaSize <= 0) {
|
||||
LOGM(ERR, "Output {} doesn't support gamma", pMonitor->szName);
|
||||
@ -81,6 +81,24 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* out
|
||||
|
||||
gammaTableSet = true;
|
||||
close(fd);
|
||||
|
||||
// translate the table to AQ format
|
||||
std::vector<uint16_t> red, green, blue;
|
||||
red.resize(gammaTable.size() / 3);
|
||||
green.resize(gammaTable.size() / 3);
|
||||
blue.resize(gammaTable.size() / 3);
|
||||
for (size_t i = 0; i < gammaTable.size() / 3; ++i) {
|
||||
red.at(i) = gammaTable.at(i);
|
||||
green.at(i) = gammaTable.at(gammaTable.size() / 3 + i);
|
||||
blue.at(i) = gammaTable.at((gammaTable.size() / 3) * 2 + i);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < gammaTable.size() / 3; ++i) {
|
||||
gammaTable.at(i * 3) = red.at(i);
|
||||
gammaTable.at(i * 3 + 1) = green.at(i);
|
||||
gammaTable.at(i * 3 + 2) = blue.at(i);
|
||||
}
|
||||
|
||||
applyToMonitor();
|
||||
});
|
||||
|
||||
@ -95,7 +113,7 @@ CGammaControl::~CGammaControl() {
|
||||
return;
|
||||
|
||||
// reset the LUT if the client dies for whatever reason and doesn't unset the gamma
|
||||
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
|
||||
pMonitor->output->state->setGammaLut({});
|
||||
}
|
||||
|
||||
bool CGammaControl::good() {
|
||||
@ -109,19 +127,15 @@ void CGammaControl::applyToMonitor() {
|
||||
LOGM(LOG, "setting to monitor {}", pMonitor->szName);
|
||||
|
||||
if (!gammaTableSet) {
|
||||
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
|
||||
pMonitor->output->state->setGammaLut({});
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t* red = &gammaTable.at(0);
|
||||
uint16_t* green = &gammaTable.at(gammaSize);
|
||||
uint16_t* blue = &gammaTable.at(gammaSize * 2);
|
||||
|
||||
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), gammaSize, red, green, blue);
|
||||
pMonitor->output->state->setGammaLut(gammaTable);
|
||||
|
||||
if (!pMonitor->state.test()) {
|
||||
LOGM(LOG, "setting to monitor {} failed", pMonitor->szName);
|
||||
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
|
||||
pMonitor->output->state->setGammaLut({});
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageMonitor(pMonitor);
|
||||
|
@ -23,7 +23,7 @@ class CGammaControl {
|
||||
CMonitor* pMonitor = nullptr;
|
||||
size_t gammaSize = 0;
|
||||
bool gammaTableSet = false;
|
||||
std::vector<uint16_t> gammaTable;
|
||||
std::vector<uint16_t> gammaTable; // [r,g,b]+
|
||||
|
||||
void onMonitorDestroy();
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "../devices/IKeyboard.hpp"
|
||||
#include <sys/mman.h>
|
||||
#include "core/Compositor.hpp"
|
||||
#include <cstring>
|
||||
|
||||
#define LOGM PROTO::ime->protoLog
|
||||
|
||||
@ -19,7 +20,7 @@ CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SP<CZwpInputMethodKeyboar
|
||||
return;
|
||||
}
|
||||
|
||||
sendKeyboardData(g_pSeatManager->keyboard->wlr());
|
||||
sendKeyboardData(g_pSeatManager->keyboard.lock());
|
||||
}
|
||||
|
||||
CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() {
|
||||
@ -27,37 +28,36 @@ CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() {
|
||||
std::erase_if(owner->grabs, [](const auto& g) { return g.expired(); });
|
||||
}
|
||||
|
||||
void CInputMethodKeyboardGrabV2::sendKeyboardData(wlr_keyboard* keyboard) {
|
||||
void CInputMethodKeyboardGrabV2::sendKeyboardData(SP<IKeyboard> keyboard) {
|
||||
|
||||
if (keyboard == pLastKeyboard)
|
||||
return;
|
||||
|
||||
pLastKeyboard = keyboard;
|
||||
|
||||
int keymapFD = allocateSHMFile(keyboard->keymap_size);
|
||||
int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1);
|
||||
if (keymapFD < 0) {
|
||||
LOGM(ERR, "Failed to create a keymap file for keyboard grab");
|
||||
return;
|
||||
}
|
||||
|
||||
void* data = mmap(nullptr, keyboard->keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0);
|
||||
void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0);
|
||||
if (data == MAP_FAILED) {
|
||||
LOGM(ERR, "Failed to mmap a keymap file for keyboard grab");
|
||||
close(keymapFD);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(data, keyboard->keymap_string, keyboard->keymap_size);
|
||||
munmap(data, keyboard->keymap_size);
|
||||
memcpy(data, keyboard->xkbKeymapString.c_str(), keyboard->xkbKeymapString.length());
|
||||
munmap(data, keyboard->xkbKeymapString.length() + 1);
|
||||
|
||||
resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->keymap_size);
|
||||
resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->xkbKeymapString.length() + 1);
|
||||
|
||||
close(keymapFD);
|
||||
|
||||
const auto MODS = keyboard->modifiers;
|
||||
sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group);
|
||||
sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group);
|
||||
|
||||
resource->sendRepeatInfo(keyboard->repeat_info.rate, keyboard->repeat_info.delay);
|
||||
resource->sendRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay);
|
||||
}
|
||||
|
||||
void CInputMethodKeyboardGrabV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state) {
|
||||
@ -316,7 +316,7 @@ void CInputMethodV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t loc
|
||||
}
|
||||
}
|
||||
|
||||
void CInputMethodV2::setKeyboard(wlr_keyboard* keyboard) {
|
||||
void CInputMethodV2::setKeyboard(SP<IKeyboard> keyboard) {
|
||||
for (auto& gw : grabs) {
|
||||
auto g = gw.lock();
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
class CInputMethodKeyboardGrabV2;
|
||||
class CInputMethodPopupV2;
|
||||
class IKeyboard;
|
||||
|
||||
class CInputMethodV2 {
|
||||
public:
|
||||
@ -58,7 +59,7 @@ class CInputMethodV2 {
|
||||
bool hasGrab();
|
||||
void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state);
|
||||
void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
|
||||
void setKeyboard(wlr_keyboard* keyboard);
|
||||
void setKeyboard(SP<IKeyboard> keyboard);
|
||||
|
||||
wl_client* client();
|
||||
wl_client* grabClient();
|
||||
@ -90,13 +91,13 @@ class CInputMethodKeyboardGrabV2 {
|
||||
|
||||
void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state);
|
||||
void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
|
||||
void sendKeyboardData(wlr_keyboard* keyboard);
|
||||
void sendKeyboardData(SP<IKeyboard> keyboard);
|
||||
|
||||
private:
|
||||
SP<CZwpInputMethodKeyboardGrabV2> resource;
|
||||
WP<CInputMethodV2> owner;
|
||||
|
||||
wlr_keyboard* pLastKeyboard = nullptr; // READ-ONLY
|
||||
WP<IKeyboard> pLastKeyboard;
|
||||
};
|
||||
|
||||
class CInputMethodPopupV2 {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <sys/mman.h>
|
||||
#include <xf86drm.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include "core/Compositor.hpp"
|
||||
#include "types/DMABuffer.hpp"
|
||||
#include "types/WLBuffer.hpp"
|
||||
@ -22,21 +23,66 @@ static std::optional<dev_t> devIDFromFD(int fd) {
|
||||
return stat.st_rdev;
|
||||
}
|
||||
|
||||
CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector<SDMABufTranche> tranches_) {
|
||||
CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector<std::pair<SP<CMonitor>, SDMABUFTranche>> tranches_) :
|
||||
rendererTranche(_rendererTranche), monitorTranches(tranches_) {
|
||||
|
||||
std::vector<SDMABUFFormatTableEntry> formatsVec;
|
||||
std::set<std::pair<uint32_t, uint64_t>> formats;
|
||||
for (auto& t : tranches_) {
|
||||
for (auto& fmt : t.formats) {
|
||||
for (auto& mod : fmt.mods) {
|
||||
formats.insert(std::make_pair<>(fmt.format, mod));
|
||||
|
||||
// insert formats into vec if they got inserted into set, meaning they're unique
|
||||
size_t i = 0;
|
||||
|
||||
rendererTranche.indicies.clear();
|
||||
for (auto& fmt : rendererTranche.formats) {
|
||||
for (auto& mod : fmt.modifiers) {
|
||||
auto format = std::make_pair<>(fmt.drmFormat, mod);
|
||||
auto [_, inserted] = formats.insert(format);
|
||||
if (inserted) {
|
||||
// if it was inserted into set, then its unique and will have a new index in vec
|
||||
rendererTranche.indicies.push_back(i++);
|
||||
formatsVec.push_back(SDMABUFFormatTableEntry{
|
||||
.fmt = fmt.drmFormat,
|
||||
.modifier = mod,
|
||||
});
|
||||
} else {
|
||||
// if it wasn't inserted then find its index in vec
|
||||
auto it =
|
||||
std::find_if(formatsVec.begin(), formatsVec.end(), [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; });
|
||||
rendererTranche.indicies.push_back(it - formatsVec.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tableLen = formats.size() * sizeof(SDMABUFFeedbackTableEntry);
|
||||
int fds[2] = {0};
|
||||
allocateSHMFilePair(tableLen, &fds[0], &fds[1]);
|
||||
for (auto& [monitor, tranche] : monitorTranches) {
|
||||
tranche.indicies.clear();
|
||||
for (auto& fmt : tranche.formats) {
|
||||
for (auto& mod : fmt.modifiers) {
|
||||
// apparently these can implode on planes, so dont use them
|
||||
if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR)
|
||||
continue;
|
||||
auto format = std::make_pair<>(fmt.drmFormat, mod);
|
||||
auto [_, inserted] = formats.insert(format);
|
||||
if (inserted) {
|
||||
tranche.indicies.push_back(i++);
|
||||
formatsVec.push_back(SDMABUFFormatTableEntry{
|
||||
.fmt = fmt.drmFormat,
|
||||
.modifier = mod,
|
||||
});
|
||||
} else {
|
||||
auto it = std::find_if(formatsVec.begin(), formatsVec.end(),
|
||||
[fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; });
|
||||
tranche.indicies.push_back(it - formatsVec.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0);
|
||||
tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry);
|
||||
|
||||
int fds[2] = {0};
|
||||
allocateSHMFilePair(tableSize, &fds[0], &fds[1]);
|
||||
|
||||
auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0);
|
||||
|
||||
if (arr == MAP_FAILED) {
|
||||
LOGM(ERR, "mmap failed");
|
||||
@ -47,33 +93,18 @@ CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector<SDMAB
|
||||
|
||||
close(fds[0]);
|
||||
|
||||
std::vector<std::pair<uint32_t, uint64_t>> formatsVec;
|
||||
for (auto& f : formats) {
|
||||
formatsVec.push_back(f);
|
||||
}
|
||||
std::copy(formatsVec.begin(), formatsVec.end(), arr);
|
||||
|
||||
size_t i = 0;
|
||||
for (auto& [fmt, mod] : formatsVec) {
|
||||
arr[i++] = SDMABUFFeedbackTableEntry{
|
||||
.fmt = fmt,
|
||||
.modifier = mod,
|
||||
};
|
||||
}
|
||||
munmap(arr, tableSize);
|
||||
|
||||
munmap(arr, tableLen);
|
||||
|
||||
mainDevice = device;
|
||||
tableFD = fds[1];
|
||||
tranches = formatsVec;
|
||||
|
||||
// TODO: maybe calculate indices? currently we send all as available which could be wrong? I ain't no kernel dev tho.
|
||||
tableFD = fds[1];
|
||||
}
|
||||
|
||||
CCompiledDMABUFFeedback::~CCompiledDMABUFFeedback() {
|
||||
CDMABUFFormatTable::~CDMABUFFormatTable() {
|
||||
close(tableFD);
|
||||
}
|
||||
|
||||
CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs) {
|
||||
CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs) {
|
||||
buffer = makeShared<CDMABuffer>(id, client, attrs);
|
||||
|
||||
buffer->resource->buffer = buffer;
|
||||
@ -103,7 +134,7 @@ CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParam
|
||||
resource->setOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); });
|
||||
resource->setDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); });
|
||||
|
||||
attrs = makeShared<SDMABUFAttrs>();
|
||||
attrs = makeShared<Aquamarine::SDMABUFAttrs>();
|
||||
|
||||
attrs->success = true;
|
||||
|
||||
@ -190,7 +221,7 @@ void CLinuxDMABBUFParamsResource::create(uint32_t id) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, attrs->format, attrs->planes);
|
||||
LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, FormatUtils::drmFormatName(attrs->format), attrs->planes);
|
||||
for (int i = 0; i < attrs->planes; ++i) {
|
||||
LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs->modifier, attrs->fds[i], attrs->strides[i], attrs->offsets[i]);
|
||||
}
|
||||
@ -277,32 +308,9 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SP<CZwpLinuxDmabufFee
|
||||
resource->setOnDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); });
|
||||
resource->setDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); });
|
||||
|
||||
if (surface)
|
||||
LOGM(ERR, "FIXME: surface feedback stub");
|
||||
|
||||
auto* feedback = PROTO::linuxDma->defaultFeedback.get();
|
||||
|
||||
resource->sendFormatTable(feedback->tableFD, feedback->tableLen);
|
||||
|
||||
// send default feedback
|
||||
struct wl_array deviceArr = {
|
||||
.size = sizeof(feedback->mainDevice),
|
||||
.data = (void*)&feedback->mainDevice,
|
||||
};
|
||||
resource->sendMainDevice(&deviceArr);
|
||||
resource->sendTrancheTargetDevice(&deviceArr);
|
||||
resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)0);
|
||||
|
||||
wl_array indices;
|
||||
wl_array_init(&indices);
|
||||
for (size_t i = 0; i < feedback->tranches.size(); ++i) {
|
||||
*((uint16_t*)wl_array_add(&indices, sizeof(uint16_t))) = i;
|
||||
}
|
||||
resource->sendTrancheFormats(&indices);
|
||||
wl_array_release(&indices);
|
||||
resource->sendTrancheDone();
|
||||
|
||||
resource->sendDone();
|
||||
auto& formatTable = PROTO::linuxDma->formatTable;
|
||||
resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize);
|
||||
sendDefaultFeedback();
|
||||
}
|
||||
|
||||
CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() {
|
||||
@ -313,6 +321,41 @@ bool CLinuxDMABUFFeedbackResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CLinuxDMABUFFeedbackResource::sendTranche(SDMABUFTranche& tranche) {
|
||||
struct wl_array deviceArr = {
|
||||
.size = sizeof(tranche.device),
|
||||
.data = (void*)&tranche.device,
|
||||
};
|
||||
resource->sendTrancheTargetDevice(&deviceArr);
|
||||
|
||||
resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)tranche.flags);
|
||||
|
||||
wl_array indices = {
|
||||
.size = tranche.indicies.size() * sizeof(tranche.indicies.at(0)),
|
||||
.data = tranche.indicies.data(),
|
||||
};
|
||||
resource->sendTrancheFormats(&indices);
|
||||
resource->sendTrancheDone();
|
||||
}
|
||||
|
||||
// default tranche is based on renderer (egl)
|
||||
void CLinuxDMABUFFeedbackResource::sendDefaultFeedback() {
|
||||
auto mainDevice = PROTO::linuxDma->mainDevice;
|
||||
auto& formatTable = PROTO::linuxDma->formatTable;
|
||||
|
||||
struct wl_array deviceArr = {
|
||||
.size = sizeof(mainDevice),
|
||||
.data = (void*)&mainDevice,
|
||||
};
|
||||
resource->sendMainDevice(&deviceArr);
|
||||
|
||||
sendTranche(formatTable->rendererTranche);
|
||||
|
||||
resource->sendDone();
|
||||
|
||||
lastFeedbackWasScanout = false;
|
||||
}
|
||||
|
||||
CLinuxDMABUFResource::CLinuxDMABUFResource(SP<CZwpLinuxDmabufV1> resource_) : resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
@ -361,48 +404,81 @@ bool CLinuxDMABUFResource::good() {
|
||||
}
|
||||
|
||||
void CLinuxDMABUFResource::sendMods() {
|
||||
for (auto& [fmt, mod] : PROTO::linuxDma->defaultFeedback->tranches) {
|
||||
if (resource->version() < 3) {
|
||||
if (mod == DRM_FORMAT_MOD_INVALID)
|
||||
resource->sendFormat(fmt);
|
||||
continue;
|
||||
for (auto& fmt : PROTO::linuxDma->formatTable->rendererTranche.formats) {
|
||||
for (auto& mod : fmt.modifiers) {
|
||||
if (resource->version() < 3) {
|
||||
if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR)
|
||||
resource->sendFormat(fmt.drmFormat);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166
|
||||
|
||||
resource->sendModifier(fmt.drmFormat, mod >> 32, mod & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
// TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166
|
||||
|
||||
resource->sendModifier(fmt, mod >> 32, mod & 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||
static auto P = g_pHookSystem->hookDynamic("ready", [this](void* self, SCallbackInfo& info, std::any d) {
|
||||
int rendererFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
|
||||
int rendererFD = g_pCompositor->m_iDRMFD;
|
||||
auto dev = devIDFromFD(rendererFD);
|
||||
|
||||
if (!dev.has_value()) {
|
||||
LOGM(ERR, "failed to get drm dev");
|
||||
PROTO::linuxDma.reset();
|
||||
protoLog(ERR, "failed to get drm dev, disabling linux dmabuf");
|
||||
removeGlobal();
|
||||
return;
|
||||
}
|
||||
|
||||
mainDevice = *dev;
|
||||
|
||||
auto fmts = g_pHyprOpenGL->getDRMFormats();
|
||||
|
||||
SDMABufTranche tranche = {
|
||||
.device = *dev,
|
||||
.formats = fmts,
|
||||
SDMABUFTranche eglTranche = {
|
||||
.device = mainDevice,
|
||||
.flags = 0, // renderer isnt for ds so dont set flag.
|
||||
.formats = g_pHyprOpenGL->getDRMFormats(),
|
||||
};
|
||||
|
||||
std::vector<SDMABufTranche> tches;
|
||||
tches.push_back(tranche);
|
||||
std::vector<std::pair<SP<CMonitor>, SDMABUFTranche>> tches;
|
||||
|
||||
defaultFeedback = std::make_unique<CCompiledDMABUFFeedback>(*dev, tches);
|
||||
if (g_pCompositor->m_pAqBackend->hasSession()) {
|
||||
// this assumes there's only 1 device used for both scanout and rendering
|
||||
// also that each monitor never changes its primary plane
|
||||
|
||||
for (auto& mon : g_pCompositor->m_vMonitors) {
|
||||
auto tranche = SDMABUFTranche{
|
||||
.device = mainDevice,
|
||||
.flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT,
|
||||
.formats = mon->output->getRenderFormats(),
|
||||
};
|
||||
tches.push_back(std::make_pair<>(mon, tranche));
|
||||
}
|
||||
|
||||
static auto monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) {
|
||||
auto pMonitor = std::any_cast<CMonitor*>(param);
|
||||
auto mon = pMonitor->self.lock();
|
||||
auto tranche = SDMABUFTranche{
|
||||
.device = mainDevice,
|
||||
.flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT,
|
||||
.formats = mon->output->getRenderFormats(),
|
||||
};
|
||||
formatTable->monitorTranches.push_back(std::make_pair<>(mon, tranche));
|
||||
resetFormatTable();
|
||||
});
|
||||
|
||||
static auto monitorRemoved = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) {
|
||||
auto pMonitor = std::any_cast<CMonitor*>(param);
|
||||
auto mon = pMonitor->self.lock();
|
||||
std::erase_if(formatTable->monitorTranches, [mon](std::pair<SP<CMonitor>, SDMABUFTranche> pair) { return pair.first == mon; });
|
||||
resetFormatTable();
|
||||
});
|
||||
}
|
||||
|
||||
formatTable = std::make_unique<CDMABUFFormatTable>(eglTranche, tches);
|
||||
|
||||
drmDevice* device = nullptr;
|
||||
if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) {
|
||||
LOGM(ERR, "failed to get drm dev");
|
||||
PROTO::linuxDma.reset();
|
||||
protoLog(ERR, "failed to get drm dev, disabling linux dmabuf");
|
||||
removeGlobal();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -411,17 +487,51 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const
|
||||
mainDeviceFD = open(name, O_RDWR | O_CLOEXEC);
|
||||
drmFreeDevice(&device);
|
||||
if (mainDeviceFD < 0) {
|
||||
LOGM(ERR, "failed to open drm dev");
|
||||
PROTO::linuxDma.reset();
|
||||
protoLog(ERR, "failed to open drm dev, disabling linux dmabuf");
|
||||
removeGlobal();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
LOGM(ERR, "DRM device {} has no render node!!", device->nodes[DRM_NODE_PRIMARY]);
|
||||
protoLog(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null");
|
||||
drmFreeDevice(&device);
|
||||
removeGlobal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CLinuxDMABufV1Protocol::resetFormatTable() {
|
||||
if (!formatTable)
|
||||
return;
|
||||
|
||||
LOGM(LOG, "Resetting format table");
|
||||
|
||||
// this might be a big copy
|
||||
auto newFormatTable = std::make_unique<CDMABUFFormatTable>(formatTable->rendererTranche, formatTable->monitorTranches);
|
||||
|
||||
for (auto& feedback : m_vFeedbacks) {
|
||||
feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize);
|
||||
if (feedback->lastFeedbackWasScanout) {
|
||||
SP<CMonitor> mon;
|
||||
auto HLSurface = CWLSurface::fromResource(feedback->surface);
|
||||
if (auto w = HLSurface->getWindow(); w)
|
||||
if (auto m = g_pCompositor->getMonitorFromID(w->m_iMonitorID); m)
|
||||
mon = m->self.lock();
|
||||
|
||||
if (!mon) {
|
||||
feedback->sendDefaultFeedback();
|
||||
return;
|
||||
}
|
||||
|
||||
updateScanoutTranche(feedback->surface, mon);
|
||||
} else {
|
||||
feedback->sendDefaultFeedback();
|
||||
}
|
||||
}
|
||||
|
||||
// delete old table after we sent new one
|
||||
formatTable = std::move(newFormatTable);
|
||||
}
|
||||
|
||||
CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() {
|
||||
if (mainDeviceFD >= 0)
|
||||
close(mainDeviceFD);
|
||||
@ -452,3 +562,52 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABBUFParamsResource* resour
|
||||
void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) {
|
||||
std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CLinuxDMABufV1Protocol::updateScanoutTranche(SP<CWLSurfaceResource> surface, SP<CMonitor> pMonitor) {
|
||||
SP<CLinuxDMABUFFeedbackResource> feedbackResource;
|
||||
for (auto& f : m_vFeedbacks) {
|
||||
if (f->surface != surface)
|
||||
continue;
|
||||
|
||||
feedbackResource = f;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!feedbackResource) {
|
||||
LOGM(LOG, "updateScanoutTranche: surface has no dmabuf_feedback");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pMonitor) {
|
||||
LOGM(LOG, "updateScanoutTranche: resetting feedback");
|
||||
feedbackResource->sendDefaultFeedback();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& monitorTranchePair = std::find_if(formatTable->monitorTranches.begin(), formatTable->monitorTranches.end(),
|
||||
[pMonitor](std::pair<SP<CMonitor>, SDMABUFTranche> pair) { return pair.first == pMonitor; });
|
||||
|
||||
if (monitorTranchePair == formatTable->monitorTranches.end()) {
|
||||
LOGM(LOG, "updateScanoutTranche: monitor has no tranche");
|
||||
return;
|
||||
}
|
||||
|
||||
auto& monitorTranche = (*monitorTranchePair).second;
|
||||
|
||||
LOGM(LOG, "updateScanoutTranche: sending a scanout tranche");
|
||||
|
||||
struct wl_array deviceArr = {
|
||||
.size = sizeof(mainDevice),
|
||||
.data = (void*)&mainDevice,
|
||||
};
|
||||
feedbackResource->resource->sendMainDevice(&deviceArr);
|
||||
|
||||
// prioritize scnaout tranche but have renderer fallback tranche
|
||||
// also yes formats can be duped here because different tranche flags (ds and no ds)
|
||||
feedbackResource->sendTranche(monitorTranche);
|
||||
feedbackResource->sendTranche(formatTable->rendererTranche);
|
||||
|
||||
feedbackResource->resource->sendDone();
|
||||
|
||||
feedbackResource->lastFeedbackWasScanout = true;
|
||||
}
|
||||
|
@ -7,15 +7,16 @@
|
||||
#include "wayland.hpp"
|
||||
#include "linux-dmabuf-v1.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include "../helpers/Format.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include <aquamarine/buffer/Buffer.hpp>
|
||||
|
||||
class CDMABuffer;
|
||||
struct SDRMFormat;
|
||||
struct SDMABUFAttrs;
|
||||
class CWLSurfaceResource;
|
||||
|
||||
class CLinuxDMABuffer {
|
||||
public:
|
||||
CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs);
|
||||
CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs);
|
||||
~CLinuxDMABuffer();
|
||||
|
||||
bool good();
|
||||
@ -31,34 +32,29 @@ class CLinuxDMABuffer {
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct SDMABUFFeedbackTableEntry {
|
||||
struct SDMABUFFormatTableEntry {
|
||||
uint32_t fmt = 0;
|
||||
char pad[4];
|
||||
uint64_t modifier = 0;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class SCompiledDMABUFTranche {
|
||||
dev_t device = 0;
|
||||
uint32_t flags = 0;
|
||||
std::vector<uint16_t> indices;
|
||||
};
|
||||
|
||||
struct SDMABufTranche {
|
||||
struct SDMABUFTranche {
|
||||
dev_t device = 0;
|
||||
uint32_t flags = 0;
|
||||
std::vector<SDRMFormat> formats;
|
||||
std::vector<uint16_t> indicies;
|
||||
};
|
||||
|
||||
class CCompiledDMABUFFeedback {
|
||||
class CDMABUFFormatTable {
|
||||
public:
|
||||
CCompiledDMABUFFeedback(dev_t device, std::vector<SDMABufTranche> tranches);
|
||||
~CCompiledDMABUFFeedback();
|
||||
CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector<std::pair<SP<CMonitor>, SDMABUFTranche>> tranches);
|
||||
~CDMABUFFormatTable();
|
||||
|
||||
dev_t mainDevice = 0;
|
||||
int tableFD = -1;
|
||||
size_t tableLen = 0;
|
||||
std::vector<std::pair<uint32_t, uint64_t>> tranches;
|
||||
int tableFD = -1;
|
||||
size_t tableSize = 0;
|
||||
SDMABUFTranche rendererTranche;
|
||||
std::vector<std::pair<SP<CMonitor>, SDMABUFTranche>> monitorTranches;
|
||||
};
|
||||
|
||||
class CLinuxDMABBUFParamsResource {
|
||||
@ -66,12 +62,12 @@ class CLinuxDMABBUFParamsResource {
|
||||
CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParamsV1> resource_);
|
||||
~CLinuxDMABBUFParamsResource();
|
||||
|
||||
bool good();
|
||||
void create(uint32_t id); // 0 means not immed
|
||||
bool good();
|
||||
void create(uint32_t id); // 0 means not immed
|
||||
|
||||
SP<SDMABUFAttrs> attrs;
|
||||
WP<CLinuxDMABuffer> createdBuffer;
|
||||
bool used = false;
|
||||
SP<Aquamarine::SDMABUFAttrs> attrs;
|
||||
WP<CLinuxDMABuffer> createdBuffer;
|
||||
bool used = false;
|
||||
|
||||
private:
|
||||
SP<CZwpLinuxBufferParamsV1> resource;
|
||||
@ -86,11 +82,16 @@ class CLinuxDMABUFFeedbackResource {
|
||||
~CLinuxDMABUFFeedbackResource();
|
||||
|
||||
bool good();
|
||||
void sendDefaultFeedback();
|
||||
void sendTranche(SDMABUFTranche& tranche);
|
||||
|
||||
SP<CWLSurfaceResource> surface; // optional, for surface feedbacks
|
||||
|
||||
private:
|
||||
SP<CZwpLinuxDmabufFeedbackV1> resource;
|
||||
bool lastFeedbackWasScanout = false;
|
||||
|
||||
friend class CLinuxDMABufV1Protocol;
|
||||
};
|
||||
|
||||
class CLinuxDMABUFResource {
|
||||
@ -110,6 +111,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol {
|
||||
~CLinuxDMABufV1Protocol();
|
||||
|
||||
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
|
||||
void updateScanoutTranche(SP<CWLSurfaceResource> surface, SP<CMonitor> pMonitor);
|
||||
|
||||
private:
|
||||
void destroyResource(CLinuxDMABUFResource* resource);
|
||||
@ -117,13 +119,15 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol {
|
||||
void destroyResource(CLinuxDMABBUFParamsResource* resource);
|
||||
void destroyResource(CLinuxDMABuffer* resource);
|
||||
|
||||
void resetFormatTable();
|
||||
|
||||
//
|
||||
std::vector<SP<CLinuxDMABUFResource>> m_vManagers;
|
||||
std::vector<SP<CLinuxDMABUFFeedbackResource>> m_vFeedbacks;
|
||||
std::vector<SP<CLinuxDMABBUFParamsResource>> m_vParams;
|
||||
std::vector<SP<CLinuxDMABuffer>> m_vBuffers;
|
||||
|
||||
UP<CCompiledDMABUFFeedback> defaultFeedback;
|
||||
UP<CDMABUFFormatTable> formatTable;
|
||||
dev_t mainDevice;
|
||||
int mainDeviceFD = -1;
|
||||
|
||||
|
@ -2,12 +2,11 @@
|
||||
#include <algorithm>
|
||||
#include <xf86drm.h>
|
||||
#include "../Compositor.hpp"
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
#include "types/WLBuffer.hpp"
|
||||
|
||||
#define LOGM PROTO::mesaDRM->protoLog
|
||||
|
||||
CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) {
|
||||
CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) {
|
||||
LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes);
|
||||
for (int i = 0; i < attrs_.planes; ++i) {
|
||||
LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]);
|
||||
@ -60,10 +59,27 @@ CMesaDRMResource::CMesaDRMResource(SP<CWlDrm> resource_) : resource(resource_) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDMABUFAttrs attrs;
|
||||
uint64_t mod = DRM_FORMAT_MOD_INVALID;
|
||||
|
||||
auto fmts = g_pHyprOpenGL->getDRMFormats();
|
||||
for (auto& f : fmts) {
|
||||
if (f.drmFormat != fmt)
|
||||
continue;
|
||||
|
||||
for (auto& m : f.modifiers) {
|
||||
if (m == DRM_FORMAT_MOD_LINEAR)
|
||||
continue;
|
||||
|
||||
mod = m;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Aquamarine::SDMABUFAttrs attrs;
|
||||
attrs.success = true;
|
||||
attrs.size = {w, h};
|
||||
attrs.modifier = DRM_FORMAT_MOD_INVALID;
|
||||
attrs.modifier = mod;
|
||||
attrs.planes = 1;
|
||||
attrs.offsets[0] = off0;
|
||||
attrs.strides[0] = str0;
|
||||
@ -87,7 +103,7 @@ CMesaDRMResource::CMesaDRMResource(SP<CWlDrm> resource_) : resource(resource_) {
|
||||
|
||||
auto fmts = g_pHyprOpenGL->getDRMFormats();
|
||||
for (auto& fmt : fmts) {
|
||||
resource->sendFormat(fmt.format);
|
||||
resource->sendFormat(fmt.drmFormat);
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,10 +113,10 @@ bool CMesaDRMResource::good() {
|
||||
|
||||
CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||
drmDevice* dev = nullptr;
|
||||
int drmFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
|
||||
int drmFD = g_pCompositor->m_iDRMFD;
|
||||
if (drmGetDevice2(drmFD, 0, &dev) != 0) {
|
||||
LOGM(ERR, "Failed to get device");
|
||||
PROTO::mesaDRM.reset();
|
||||
protoLog(ERR, "Failed to get device, disabling MesaDRM");
|
||||
removeGlobal();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -108,7 +124,15 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co
|
||||
nodeName = dev->nodes[DRM_NODE_RENDER];
|
||||
} else {
|
||||
ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY));
|
||||
LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]);
|
||||
|
||||
if (!dev->nodes[DRM_NODE_PRIMARY]) {
|
||||
protoLog(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM");
|
||||
drmFreeDevice(&dev);
|
||||
removeGlobal();
|
||||
return;
|
||||
}
|
||||
|
||||
protoLog(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]);
|
||||
nodeName = dev->nodes[DRM_NODE_PRIMARY];
|
||||
}
|
||||
drmFreeDevice(&dev);
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
class CMesaDRMBufferResource {
|
||||
public:
|
||||
CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs);
|
||||
CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs);
|
||||
~CMesaDRMBufferResource();
|
||||
|
||||
bool good();
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include <algorithm>
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
using namespace Aquamarine;
|
||||
|
||||
#define LOGM PROTO::outputManagement->protoLog
|
||||
|
||||
COutputManager::COutputManager(SP<CZwlrOutputManagerV1> resource_) : resource(resource_) {
|
||||
@ -123,8 +125,8 @@ void COutputHead::sendAllData() {
|
||||
|
||||
resource->sendName(pMonitor->szName.c_str());
|
||||
resource->sendDescription(pMonitor->szDescription.c_str());
|
||||
if (pMonitor->output->phys_width > 0 && pMonitor->output->phys_height > 0)
|
||||
resource->sendPhysicalSize(pMonitor->output->phys_width, pMonitor->output->phys_height);
|
||||
if (pMonitor->output->physicalSize.x > 0 && pMonitor->output->physicalSize.y > 0)
|
||||
resource->sendPhysicalSize(pMonitor->output->physicalSize.x, pMonitor->output->physicalSize.y);
|
||||
resource->sendEnabled(pMonitor->m_bEnabled);
|
||||
|
||||
if (pMonitor->m_bEnabled) {
|
||||
@ -133,12 +135,12 @@ void COutputHead::sendAllData() {
|
||||
resource->sendScale(wl_fixed_from_double(pMonitor->scale));
|
||||
}
|
||||
|
||||
if (pMonitor->output->make && VERSION >= 2)
|
||||
resource->sendMake(pMonitor->output->make);
|
||||
if (pMonitor->output->model && VERSION >= 2)
|
||||
resource->sendModel(pMonitor->output->model);
|
||||
if (pMonitor->output->serial && VERSION >= 2)
|
||||
resource->sendSerialNumber(pMonitor->output->serial);
|
||||
if (!pMonitor->output->make.empty() && VERSION >= 2)
|
||||
resource->sendMake(pMonitor->output->make.c_str());
|
||||
if (!pMonitor->output->model.empty() && VERSION >= 2)
|
||||
resource->sendModel(pMonitor->output->model.c_str());
|
||||
if (!pMonitor->output->serial.empty() && VERSION >= 2)
|
||||
resource->sendSerialNumber(pMonitor->output->serial.c_str());
|
||||
|
||||
if (VERSION >= 4)
|
||||
resource->sendAdaptiveSync(pMonitor->vrrActive ? ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED : ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED);
|
||||
@ -146,12 +148,12 @@ void COutputHead::sendAllData() {
|
||||
// send all available modes
|
||||
|
||||
if (modes.empty()) {
|
||||
if (!wl_list_empty(&pMonitor->output->modes)) {
|
||||
wlr_output_mode* mode;
|
||||
|
||||
wl_list_for_each(mode, &pMonitor->output->modes, link) {
|
||||
makeAndSendNewMode(mode);
|
||||
if (!pMonitor->output->modes.empty()) {
|
||||
for (auto& m : pMonitor->output->modes) {
|
||||
makeAndSendNewMode(m);
|
||||
}
|
||||
} else if (pMonitor->output->state->state().customMode) {
|
||||
makeAndSendNewMode(pMonitor->output->state->state().customMode);
|
||||
} else
|
||||
makeAndSendNewMode(nullptr);
|
||||
}
|
||||
@ -164,9 +166,9 @@ void COutputHead::sendAllData() {
|
||||
if (!m)
|
||||
continue;
|
||||
|
||||
if (m->mode == pMonitor->currentMode) {
|
||||
if (m->mode == pMonitor->output->state->state().mode) {
|
||||
if (m->mode)
|
||||
LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh);
|
||||
LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate);
|
||||
else
|
||||
LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName);
|
||||
resource->sendCurrentMode(m->resource.get());
|
||||
@ -197,7 +199,7 @@ void COutputHead::updateMode() {
|
||||
|
||||
if (m->mode == pMonitor->currentMode) {
|
||||
if (m->mode)
|
||||
LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh);
|
||||
LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate);
|
||||
else
|
||||
LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName);
|
||||
resource->sendCurrentMode(m->resource.get());
|
||||
@ -207,7 +209,7 @@ void COutputHead::updateMode() {
|
||||
}
|
||||
}
|
||||
|
||||
void COutputHead::makeAndSendNewMode(wlr_output_mode* mode) {
|
||||
void COutputHead::makeAndSendNewMode(SP<Aquamarine::SOutputMode> mode) {
|
||||
const auto RESOURCE = PROTO::outputManagement->m_vModes.emplace_back(makeShared<COutputMode>(makeShared<CZwlrOutputModeV1>(resource->client(), resource->version(), 0), mode));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
@ -225,7 +227,7 @@ CMonitor* COutputHead::monitor() {
|
||||
return pMonitor;
|
||||
}
|
||||
|
||||
COutputMode::COutputMode(SP<CZwlrOutputModeV1> resource_, wlr_output_mode* mode_) : resource(resource_), mode(mode_) {
|
||||
COutputMode::COutputMode(SP<CZwlrOutputModeV1> resource_, SP<Aquamarine::SOutputMode> mode_) : resource(resource_), mode(mode_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
@ -237,11 +239,11 @@ void COutputMode::sendAllData() {
|
||||
if (!mode)
|
||||
return;
|
||||
|
||||
LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->width, mode->height, mode->refresh, mode->preferred);
|
||||
LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate, mode->preferred);
|
||||
|
||||
resource->sendSize(mode->width, mode->height);
|
||||
if (mode->refresh > 0)
|
||||
resource->sendRefresh(mode->refresh);
|
||||
resource->sendSize(mode->pixelSize.x, mode->pixelSize.y);
|
||||
if (mode->refreshRate > 0)
|
||||
resource->sendRefresh(mode->refreshRate);
|
||||
if (mode->preferred)
|
||||
resource->sendPreferred();
|
||||
}
|
||||
@ -250,8 +252,8 @@ bool COutputMode::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
wlr_output_mode* COutputMode::getMode() {
|
||||
return mode;
|
||||
SP<Aquamarine::SOutputMode> COutputMode::getMode() {
|
||||
return mode.lock();
|
||||
}
|
||||
|
||||
COutputConfiguration::COutputConfiguration(SP<CZwlrOutputConfigurationV1> resource_, SP<COutputManager> owner_) : resource(resource_), owner(owner_) {
|
||||
@ -364,8 +366,8 @@ bool COutputConfiguration::applyTestConfiguration(bool test) {
|
||||
newRule.disabled = false;
|
||||
|
||||
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) {
|
||||
newRule.resolution = {head->state.mode->getMode()->width, head->state.mode->getMode()->height};
|
||||
newRule.refreshRate = head->state.mode->getMode()->refresh / 1000.F;
|
||||
newRule.resolution = head->state.mode->getMode()->pixelSize;
|
||||
newRule.refreshRate = head->state.mode->getMode()->refreshRate / 1000.F;
|
||||
} else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) {
|
||||
newRule.resolution = head->state.customMode.size;
|
||||
newRule.refreshRate = head->state.customMode.refresh / 1000.F;
|
||||
@ -425,7 +427,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
|
||||
committedProperties |= OUTPUT_HEAD_COMMITTED_MODE;
|
||||
state.mode = MODE;
|
||||
|
||||
LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->width, MODE->getMode()->height, MODE->getMode()->refresh);
|
||||
LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate);
|
||||
});
|
||||
|
||||
resource->setSetCustomMode([this](CZwlrOutputConfigurationHeadV1* r, int32_t w, int32_t h, int32_t refresh) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "wlr-output-management-unstable-v1.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
|
||||
class CMonitor;
|
||||
|
||||
@ -34,15 +35,15 @@ class COutputManager {
|
||||
|
||||
class COutputMode {
|
||||
public:
|
||||
COutputMode(SP<CZwlrOutputModeV1> resource_, wlr_output_mode* mode_);
|
||||
COutputMode(SP<CZwlrOutputModeV1> resource_, SP<Aquamarine::SOutputMode> mode_);
|
||||
|
||||
bool good();
|
||||
wlr_output_mode* getMode();
|
||||
void sendAllData();
|
||||
bool good();
|
||||
SP<Aquamarine::SOutputMode> getMode();
|
||||
void sendAllData();
|
||||
|
||||
private:
|
||||
SP<CZwlrOutputModeV1> resource;
|
||||
wlr_output_mode* mode = nullptr;
|
||||
SP<CZwlrOutputModeV1> resource;
|
||||
WP<Aquamarine::SOutputMode> mode;
|
||||
|
||||
friend class COutputHead;
|
||||
friend class COutputManagementProtocol;
|
||||
@ -61,7 +62,7 @@ class COutputHead {
|
||||
SP<CZwlrOutputHeadV1> resource;
|
||||
CMonitor* pMonitor = nullptr;
|
||||
|
||||
void makeAndSendNewMode(wlr_output_mode* mode);
|
||||
void makeAndSendNewMode(SP<Aquamarine::SOutputMode> mode);
|
||||
void sendCurrentMode();
|
||||
|
||||
std::vector<WP<COutputMode>> modes;
|
||||
|
@ -17,7 +17,7 @@ COutputPower::COutputPower(SP<CZwlrOutputPowerV1> resource_, CMonitor* pMonitor_
|
||||
|
||||
pMonitor->dpmsStatus = mode == ZWLR_OUTPUT_POWER_V1_MODE_ON;
|
||||
|
||||
wlr_output_state_set_enabled(pMonitor->state.wlr(), pMonitor->dpmsStatus);
|
||||
pMonitor->output->state->setEnabled(mode == ZWLR_OUTPUT_POWER_V1_MODE_ON);
|
||||
|
||||
if (!pMonitor->state.commit())
|
||||
LOGM(ERR, "Couldn't set dpms to {} for {}", pMonitor->dpmsStatus, pMonitor->szName);
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../managers/HookSystemManager.hpp"
|
||||
#include "core/Compositor.hpp"
|
||||
#include "core/Output.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
|
||||
#define LOGM PROTO::presentation->protoLog
|
||||
|
||||
@ -41,13 +43,11 @@ bool CPresentationFeedback::good() {
|
||||
}
|
||||
|
||||
void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
|
||||
auto client = resource->client();
|
||||
wl_resource* res;
|
||||
wl_resource_for_each(res, &data->pMonitor->output->resources) {
|
||||
if (client == wl_resource_get_client(res)) {
|
||||
resource->sendSyncOutput(res);
|
||||
break;
|
||||
}
|
||||
auto client = resource->client();
|
||||
|
||||
if (PROTO::outputs.contains(data->pMonitor->szName)) {
|
||||
if (auto outputResource = PROTO::outputs.at(data->pMonitor->szName)->outputResourceFrom(client); outputResource)
|
||||
resource->sendSyncOutput(outputResource->getResource()->resource());
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
@ -55,9 +55,9 @@ void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> data, timespe
|
||||
flags |= WP_PRESENTATION_FEEDBACK_KIND_VSYNC;
|
||||
if (data->zeroCopy)
|
||||
flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
|
||||
if (reportedFlags & WLR_OUTPUT_PRESENT_HW_CLOCK)
|
||||
if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_CLOCK)
|
||||
flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
|
||||
if (reportedFlags & WLR_OUTPUT_PRESENT_HW_COMPLETION)
|
||||
if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION)
|
||||
flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
|
||||
|
||||
if (data->wasPresented && when)
|
||||
|
@ -266,20 +266,17 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
|
||||
return;
|
||||
}
|
||||
|
||||
if (PFRAME->pMonitor->output->allocator && (PFRAME->pMonitor->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) {
|
||||
PFRAME->dmabufFormat = PFRAME->pMonitor->output->render_format;
|
||||
} else {
|
||||
PFRAME->dmabufFormat = DRM_FORMAT_INVALID;
|
||||
}
|
||||
PFRAME->dmabufFormat = PFRAME->pMonitor->output->state->state().drmFormat;
|
||||
|
||||
if (box.width == 0 && box.height == 0)
|
||||
PFRAME->box = {0, 0, (int)(PFRAME->pMonitor->vecSize.x), (int)(PFRAME->pMonitor->vecSize.y)};
|
||||
else {
|
||||
PFRAME->box = box;
|
||||
}
|
||||
int ow, oh;
|
||||
wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh);
|
||||
PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), ow, oh).scale(PFRAME->pMonitor->scale).round();
|
||||
|
||||
PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), PFRAME->pMonitor->vecTransformedSize.x, PFRAME->pMonitor->vecTransformedSize.y)
|
||||
.scale(PFRAME->pMonitor->scale)
|
||||
.round();
|
||||
|
||||
PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w);
|
||||
|
||||
@ -383,10 +380,10 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
|
||||
g_pHyprRenderer->damageMonitor(PFRAME->pMonitor);
|
||||
}
|
||||
|
||||
void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) {
|
||||
m_pLastMonitorBackBuffer = e->state->buffer;
|
||||
void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor) {
|
||||
m_pLastMonitorBackBuffer = pMonitor->output->state->state().buffer;
|
||||
shareAllFrames(pMonitor);
|
||||
m_pLastMonitorBackBuffer = nullptr;
|
||||
m_pLastMonitorBackBuffer.reset();
|
||||
}
|
||||
|
||||
void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) {
|
||||
@ -473,11 +470,7 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) {
|
||||
}
|
||||
|
||||
bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
|
||||
wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer);
|
||||
if (!sourceTex)
|
||||
return false;
|
||||
|
||||
auto TEXTURE = makeShared<CTexture>(sourceTex);
|
||||
auto TEXTURE = makeShared<CTexture>(m_pLastMonitorBackBuffer);
|
||||
|
||||
auto shm = frame->buffer->shm();
|
||||
auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm
|
||||
@ -487,10 +480,10 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
CFramebuffer fb;
|
||||
fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->drmFormat);
|
||||
fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->output->state->state().drmFormat);
|
||||
|
||||
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) {
|
||||
wlr_texture_destroy(sourceTex);
|
||||
Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -509,8 +502,8 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
|
||||
|
||||
const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format);
|
||||
if (!PFORMAT) {
|
||||
Debug::log(ERR, "Screencopy: can't copy: failed to find a pixel format");
|
||||
g_pHyprRenderer->endRender();
|
||||
wlr_texture_destroy(sourceTex);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -539,27 +532,24 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
|
||||
|
||||
wlr_texture_destroy(sourceTex);
|
||||
Debug::log(TRACE, "Screencopy: copied frame via shm");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
|
||||
wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer);
|
||||
if (!sourceTex)
|
||||
return false;
|
||||
|
||||
auto TEXTURE = makeShared<CTexture>(sourceTex);
|
||||
auto TEXTURE = makeShared<CTexture>(m_pLastMonitorBackBuffer);
|
||||
|
||||
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
|
||||
|
||||
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true))
|
||||
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) {
|
||||
Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering to dma frame");
|
||||
return false;
|
||||
}
|
||||
|
||||
CBox monbox =
|
||||
CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y}
|
||||
.translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh.
|
||||
.transform(wlTransformToHyprutils(wlr_output_transform_invert(frame->pMonitor->output->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y);
|
||||
CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y}
|
||||
.translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh.
|
||||
.transform(wlTransformToHyprutils(invertTransform(frame->pMonitor->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y);
|
||||
g_pHyprOpenGL->setMonitorTransformEnabled(true);
|
||||
g_pHyprOpenGL->setRenderModifEnabled(false);
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1);
|
||||
@ -569,7 +559,7 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
|
||||
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
|
||||
g_pHyprRenderer->endRender();
|
||||
|
||||
wlr_texture_destroy(sourceTex);
|
||||
Debug::log(TRACE, "Screencopy: copied frame via dma");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -8,9 +8,10 @@
|
||||
#include "../managers/HookSystemManager.hpp"
|
||||
#include "../helpers/Timer.hpp"
|
||||
#include "../managers/eventLoop/EventLoopTimer.hpp"
|
||||
#include <aquamarine/buffer/Buffer.hpp>
|
||||
|
||||
class CMonitor;
|
||||
class IWLBuffer;
|
||||
class IHLBuffer;
|
||||
|
||||
enum eClientOwners {
|
||||
CLIENT_SCREENCOPY = 0,
|
||||
@ -56,7 +57,7 @@ struct SScreencopyFrame {
|
||||
|
||||
bool bufferDMA = false;
|
||||
|
||||
WP<IWLBuffer> buffer;
|
||||
WP<IHLBuffer> buffer;
|
||||
|
||||
CMonitor* pMonitor = nullptr;
|
||||
PHLWINDOWREF pWindow;
|
||||
@ -79,7 +80,7 @@ class CScreencopyProtocolManager {
|
||||
|
||||
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer);
|
||||
|
||||
void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e);
|
||||
void onOutputCommit(CMonitor* pMonitor);
|
||||
|
||||
private:
|
||||
wl_global* m_pGlobal = nullptr;
|
||||
@ -93,7 +94,7 @@ class CScreencopyProtocolManager {
|
||||
|
||||
std::vector<SScreencopyFrame*> m_vFramesAwaitingWrite;
|
||||
|
||||
wlr_buffer* m_pLastMonitorBackBuffer = nullptr;
|
||||
SP<Aquamarine::IBuffer> m_pLastMonitorBackBuffer;
|
||||
|
||||
void shareAllFrames(CMonitor* pMonitor);
|
||||
void shareFrame(SScreencopyFrame* frame);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "core/Seat.hpp"
|
||||
#include "core/Compositor.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#define LOGM PROTO::tablet->protoLog
|
||||
|
||||
@ -44,17 +45,17 @@ bool CTabletPadGroupV2Resource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CTabletPadGroupV2Resource::sendData(SP<CTabletPad> pad, wlr_tablet_pad_group* group) {
|
||||
resource->sendModes(group->mode_count);
|
||||
void CTabletPadGroupV2Resource::sendData(SP<CTabletPad> pad, SP<Aquamarine::ITabletPad::STabletPadGroup> group) {
|
||||
resource->sendModes(group->modes);
|
||||
|
||||
wl_array buttonArr;
|
||||
wl_array_init(&buttonArr);
|
||||
wl_array_add(&buttonArr, group->button_count * sizeof(int));
|
||||
memcpy(buttonArr.data, group->buttons, group->button_count * sizeof(int));
|
||||
wl_array_add(&buttonArr, group->buttons.size() * sizeof(int));
|
||||
memcpy(buttonArr.data, group->buttons.data(), group->buttons.size() * sizeof(int));
|
||||
resource->sendButtons(&buttonArr);
|
||||
wl_array_release(&buttonArr);
|
||||
|
||||
for (size_t i = 0; i < group->strip_count; ++i) {
|
||||
for (size_t i = 0; i < group->strips.size(); ++i) {
|
||||
const auto RESOURCE =
|
||||
PROTO::tablet->m_vStrips.emplace_back(makeShared<CTabletPadStripV2Resource>(makeShared<CZwpTabletPadStripV2>(resource->client(), resource->version(), 0), i));
|
||||
|
||||
@ -67,7 +68,7 @@ void CTabletPadGroupV2Resource::sendData(SP<CTabletPad> pad, wlr_tablet_pad_grou
|
||||
resource->sendStrip(RESOURCE->resource.get());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < group->ring_count; ++i) {
|
||||
for (size_t i = 0; i < group->rings.size(); ++i) {
|
||||
const auto RESOURCE =
|
||||
PROTO::tablet->m_vRings.emplace_back(makeShared<CTabletPadRingV2Resource>(makeShared<CZwpTabletPadRingV2>(resource->client(), resource->version(), 0), i));
|
||||
|
||||
@ -97,23 +98,20 @@ bool CTabletPadV2Resource::good() {
|
||||
|
||||
void CTabletPadV2Resource::sendData() {
|
||||
// this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts
|
||||
const char** path_ptr;
|
||||
for (path_ptr = (const char**)(&pad->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&pad->wlr()->paths)->data + (&pad->wlr()->paths)->size); (path_ptr)++) {
|
||||
resource->sendPath(*path_ptr);
|
||||
for (auto& p : pad->aq()->paths) {
|
||||
resource->sendPath(p.c_str());
|
||||
}
|
||||
|
||||
resource->sendButtons(pad->wlr()->button_count);
|
||||
resource->sendButtons(pad->aq()->buttons);
|
||||
|
||||
wlr_tablet_pad_group* group;
|
||||
size_t i = 0;
|
||||
wl_list_for_each(group, &pad->wlr()->groups, link) {
|
||||
createGroup(group, i++);
|
||||
for (size_t i = 0; i < pad->aq()->groups.size(); ++i) {
|
||||
createGroup(pad->aq()->groups.at(i), i);
|
||||
}
|
||||
|
||||
resource->sendDone();
|
||||
}
|
||||
|
||||
void CTabletPadV2Resource::createGroup(wlr_tablet_pad_group* group, size_t idx) {
|
||||
void CTabletPadV2Resource::createGroup(SP<Aquamarine::ITabletPad::STabletPadGroup> group, size_t idx) {
|
||||
const auto RESOURCE =
|
||||
PROTO::tablet->m_vGroups.emplace_back(makeShared<CTabletPadGroupV2Resource>(makeShared<CZwpTabletPadGroupV2>(resource->client(), resource->version(), 0), idx));
|
||||
|
||||
@ -142,13 +140,10 @@ bool CTabletV2Resource::good() {
|
||||
|
||||
void CTabletV2Resource::sendData() {
|
||||
resource->sendName(tablet->deviceName.c_str());
|
||||
resource->sendId(tablet->wlr()->usb_vendor_id, tablet->wlr()->usb_product_id);
|
||||
resource->sendId(tablet->aq()->usbVendorID, tablet->aq()->usbProductID);
|
||||
|
||||
// this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts
|
||||
const char** path_ptr;
|
||||
for (path_ptr = (const char**)(&tablet->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&tablet->wlr()->paths)->data + (&tablet->wlr()->paths)->size);
|
||||
(path_ptr)++) {
|
||||
resource->sendPath(*path_ptr);
|
||||
for (auto& p : tablet->aq()->paths) {
|
||||
resource->sendPath(p.c_str());
|
||||
}
|
||||
|
||||
resource->sendDone();
|
||||
@ -179,23 +174,23 @@ bool CTabletToolV2Resource::good() {
|
||||
}
|
||||
|
||||
void CTabletToolV2Resource::sendData() {
|
||||
static auto WLR_TYPE_TO_PROTO = [](uint32_t wlr) -> zwpTabletToolV2Type {
|
||||
switch (wlr) {
|
||||
case WLR_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN;
|
||||
case WLR_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER;
|
||||
case WLR_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH;
|
||||
case WLR_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL;
|
||||
case WLR_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH;
|
||||
case WLR_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE;
|
||||
case WLR_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS;
|
||||
static auto AQ_TYPE_TO_PROTO = [](uint32_t aq) -> zwpTabletToolV2Type {
|
||||
switch (aq) {
|
||||
case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN;
|
||||
case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER;
|
||||
case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH;
|
||||
case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL;
|
||||
case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH;
|
||||
case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE;
|
||||
case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS;
|
||||
default: ASSERT(false);
|
||||
}
|
||||
UNREACHABLE();
|
||||
};
|
||||
|
||||
resource->sendType(WLR_TYPE_TO_PROTO(tool->wlr()->type));
|
||||
resource->sendHardwareSerial(tool->wlr()->hardware_serial >> 32, tool->wlr()->hardware_serial & 0xFFFFFFFF);
|
||||
resource->sendHardwareIdWacom(tool->wlr()->hardware_wacom >> 32, tool->wlr()->hardware_wacom & 0xFFFFFFFF);
|
||||
resource->sendType(AQ_TYPE_TO_PROTO(tool->aq()->type));
|
||||
resource->sendHardwareSerial(tool->aq()->serial >> 32, tool->aq()->serial & 0xFFFFFFFF);
|
||||
resource->sendHardwareIdWacom(tool->aq()->id >> 32, tool->aq()->id & 0xFFFFFFFF);
|
||||
if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_DISTANCE)
|
||||
resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE);
|
||||
if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_PRESSURE)
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "tablet-v2.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
|
||||
class CTablet;
|
||||
class CTabletTool;
|
||||
@ -51,7 +52,7 @@ class CTabletPadGroupV2Resource {
|
||||
CTabletPadGroupV2Resource(SP<CZwpTabletPadGroupV2> resource_, size_t idx);
|
||||
|
||||
bool good();
|
||||
void sendData(SP<CTabletPad> pad, wlr_tablet_pad_group* group);
|
||||
void sendData(SP<CTabletPad> pad, SP<Aquamarine::ITabletPad::STabletPadGroup> group);
|
||||
|
||||
std::vector<WP<CTabletPadRingV2Resource>> rings;
|
||||
std::vector<WP<CTabletPadStripV2Resource>> strips;
|
||||
@ -83,7 +84,7 @@ class CTabletPadV2Resource {
|
||||
private:
|
||||
SP<CZwpTabletPadV2> resource;
|
||||
|
||||
void createGroup(wlr_tablet_pad_group* group, size_t idx);
|
||||
void createGroup(SP<Aquamarine::ITabletPad::STabletPadGroup> group, size_t idx);
|
||||
|
||||
friend class CTabletSeat;
|
||||
friend class CTabletV2Protocol;
|
||||
|
@ -193,16 +193,11 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou
|
||||
return;
|
||||
}
|
||||
|
||||
if (PMONITOR->output->allocator && (PMONITOR->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) {
|
||||
PFRAME->dmabufFormat = PMONITOR->output->render_format;
|
||||
} else {
|
||||
PFRAME->dmabufFormat = DRM_FORMAT_INVALID;
|
||||
}
|
||||
PFRAME->dmabufFormat = PMONITOR->output->state->state().drmFormat;
|
||||
|
||||
PFRAME->box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)};
|
||||
int ow, oh;
|
||||
wlr_output_effective_resolution(PMONITOR->output, &ow, &oh);
|
||||
PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), ow, oh).round();
|
||||
|
||||
PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round();
|
||||
|
||||
PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w);
|
||||
|
||||
@ -289,12 +284,10 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r
|
||||
m_vFramesAwaitingWrite.emplace_back(PFRAME);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) {
|
||||
void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor) {
|
||||
if (m_vFramesAwaitingWrite.empty())
|
||||
return; // nothing to share
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(e->output);
|
||||
|
||||
std::vector<SScreencopyFrame*> framesToRemove;
|
||||
|
||||
// share frame if correct output
|
||||
@ -306,7 +299,7 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PMONITOR != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID))
|
||||
if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID))
|
||||
continue;
|
||||
|
||||
CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y};
|
||||
@ -370,7 +363,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
CFramebuffer outFB;
|
||||
outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->drmFormat);
|
||||
outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->output->state->state().drmFormat);
|
||||
|
||||
if (frame->overlayCursor) {
|
||||
g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock());
|
||||
|
@ -21,7 +21,7 @@ class CToplevelExportProtocolManager {
|
||||
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
|
||||
void displayDestroy();
|
||||
void onWindowUnmap(PHLWINDOW pWindow);
|
||||
void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e);
|
||||
void onOutputCommit(CMonitor* pMonitor);
|
||||
|
||||
private:
|
||||
wl_global* m_pGlobal = nullptr;
|
||||
|
@ -52,6 +52,21 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
|
||||
surface->pending.viewport.hasSource = true;
|
||||
surface->pending.viewport.source = {x, y, w, h};
|
||||
});
|
||||
|
||||
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
|
||||
if (!surface || !surface->pending.buffer)
|
||||
return;
|
||||
|
||||
if (surface->pending.viewport.hasSource) {
|
||||
auto& src = surface->pending.viewport.source;
|
||||
|
||||
if (src.w + src.x > surface->pending.buffer->size.x || src.h + src.y > surface->pending.buffer->size.y) {
|
||||
resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
|
||||
surface->pending.rejected = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CViewportResource::~CViewportResource() {
|
||||
@ -66,20 +81,6 @@ bool CViewportResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CViewportResource::verify() {
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
if (surface->pending.viewport.hasSource) {
|
||||
auto& src = surface->pending.viewport.source;
|
||||
|
||||
if (src.w + src.x > surface->pending.size.x || src.h + src.y > surface->pending.size.y) {
|
||||
resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CViewporterResource::CViewporterResource(SP<CWpViewporter> resource_) : resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
@ -15,11 +15,14 @@ class CViewportResource {
|
||||
~CViewportResource();
|
||||
|
||||
bool good();
|
||||
void verify();
|
||||
WP<CWLSurfaceResource> surface;
|
||||
|
||||
private:
|
||||
SP<CWpViewport> resource;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener surfacePrecommit;
|
||||
} listeners;
|
||||
};
|
||||
|
||||
class CViewporterResource {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user