aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/actions/setup_base/action.yml6
-rw-r--r--.gitmodules4
-rw-r--r--CMakeLists.txt42
-rw-r--r--Makefile6
-rw-r--r--README.md9
-rw-r--r--flake.lock30
-rw-r--r--flake.nix8
-rw-r--r--hyprland.pc.in2
-rw-r--r--hyprpm/src/core/PluginManager.cpp7
-rw-r--r--meson.build11
-rw-r--r--nix/default.nix3
-rw-r--r--nix/overlays.nix1
-rwxr-xr-xnix/update-wlroots.sh17
-rw-r--r--protocols/meson.build2
-rw-r--r--src/Compositor.cpp391
-rw-r--r--src/Compositor.hpp36
-rw-r--r--src/config/ConfigManager.cpp23
-rw-r--r--src/debug/CrashReporter.cpp1
-rw-r--r--src/debug/HyprCtl.cpp183
-rw-r--r--src/debug/Log.cpp24
-rw-r--r--src/debug/Log.hpp2
-rw-r--r--src/desktop/Popup.cpp5
-rw-r--r--src/desktop/Popup.hpp4
-rw-r--r--src/desktop/Window.cpp3
-rw-r--r--src/devices/IKeyboard.cpp254
-rw-r--r--src/devices/IKeyboard.hpp73
-rw-r--r--src/devices/IPointer.hpp10
-rw-r--r--src/devices/ITouch.hpp10
-rw-r--r--src/devices/Keyboard.cpp66
-rw-r--r--src/devices/Keyboard.hpp22
-rw-r--r--src/devices/Mouse.cpp182
-rw-r--r--src/devices/Mouse.hpp41
-rw-r--r--src/devices/Tablet.cpp256
-rw-r--r--src/devices/Tablet.hpp156
-rw-r--r--src/devices/TouchDevice.cpp78
-rw-r--r--src/devices/TouchDevice.hpp26
-rw-r--r--src/devices/VirtualKeyboard.cpp67
-rw-r--r--src/devices/VirtualKeyboard.hpp21
-rw-r--r--src/devices/VirtualPointer.cpp176
-rw-r--r--src/devices/VirtualPointer.hpp37
-rw-r--r--src/events/Devices.cpp50
-rw-r--r--src/events/Events.hpp31
-rw-r--r--src/events/Misc.cpp54
-rw-r--r--src/events/Monitors.cpp135
-rw-r--r--src/helpers/CursorShapes.hpp43
-rw-r--r--src/helpers/Format.cpp16
-rw-r--r--src/helpers/Format.hpp9
-rw-r--r--src/helpers/MiscFunctions.cpp3
-rw-r--r--src/helpers/MiscFunctions.hpp1
-rw-r--r--src/helpers/Monitor.cpp293
-rw-r--r--src/helpers/Monitor.hpp136
-rw-r--r--src/helpers/WLClasses.hpp14
-rw-r--r--src/helpers/X11Stubs.hpp7
-rw-r--r--src/helpers/math/Math.cpp140
-rw-r--r--src/helpers/math/Math.hpp13
-rw-r--r--src/helpers/sync/SyncTimeline.cpp190
-rw-r--r--src/helpers/sync/SyncTimeline.hpp47
-rw-r--r--src/includes.hpp76
-rw-r--r--src/macros.hpp5
-rw-r--r--src/managers/AnimationManager.cpp2
-rw-r--r--src/managers/CursorManager.cpp303
-rw-r--r--src/managers/CursorManager.hpp70
-rw-r--r--src/managers/KeybindManager.cpp61
-rw-r--r--src/managers/KeybindManager.hpp1
-rw-r--r--src/managers/PointerManager.cpp283
-rw-r--r--src/managers/PointerManager.hpp54
-rw-r--r--src/managers/ProtocolManager.cpp20
-rw-r--r--src/managers/SeatManager.cpp10
-rw-r--r--src/managers/eventLoop/EventLoopManager.cpp15
-rw-r--r--src/managers/eventLoop/EventLoopManager.hpp16
-rw-r--r--src/managers/input/InputManager.cpp232
-rw-r--r--src/managers/input/InputManager.hpp23
-rw-r--r--src/managers/input/Tablets.cpp53
-rw-r--r--src/meson.build5
-rw-r--r--src/plugins/PluginAPI.cpp1
-rw-r--r--src/protocols/CursorShape.cpp45
-rw-r--r--src/protocols/DRMLease.cpp302
-rw-r--r--src/protocols/DRMLease.hpp137
-rw-r--r--src/protocols/DRMSyncobj.cpp183
-rw-r--r--src/protocols/DRMSyncobj.hpp82
-rw-r--r--src/protocols/GammaControl.cpp32
-rw-r--r--src/protocols/GammaControl.hpp2
-rw-r--r--src/protocols/InputMethodV2.cpp22
-rw-r--r--src/protocols/InputMethodV2.hpp7
-rw-r--r--src/protocols/LinuxDMABUF.cpp311
-rw-r--r--src/protocols/LinuxDMABUF.hpp52
-rw-r--r--src/protocols/MesaDRM.cpp42
-rw-r--r--src/protocols/MesaDRM.hpp2
-rw-r--r--src/protocols/OutputManagement.cpp56
-rw-r--r--src/protocols/OutputManagement.hpp15
-rw-r--r--src/protocols/OutputPower.cpp2
-rw-r--r--src/protocols/PresentationTime.cpp18
-rw-r--r--src/protocols/Screencopy.cpp52
-rw-r--r--src/protocols/Screencopy.hpp9
-rw-r--r--src/protocols/Tablet.cpp61
-rw-r--r--src/protocols/Tablet.hpp5
-rw-r--r--src/protocols/ToplevelExport.cpp19
-rw-r--r--src/protocols/ToplevelExport.hpp2
-rw-r--r--src/protocols/Viewporter.cpp29
-rw-r--r--src/protocols/Viewporter.hpp5
-rw-r--r--src/protocols/VirtualKeyboard.cpp60
-rw-r--r--src/protocols/VirtualKeyboard.hpp13
-rw-r--r--src/protocols/VirtualPointer.cpp80
-rw-r--r--src/protocols/VirtualPointer.hpp31
-rw-r--r--src/protocols/XDGOutput.cpp6
-rw-r--r--src/protocols/XDGShell.cpp1
-rw-r--r--src/protocols/core/Compositor.cpp149
-rw-r--r--src/protocols/core/Compositor.hpp14
-rw-r--r--src/protocols/core/Output.cpp10
-rw-r--r--src/protocols/core/Output.hpp3
-rw-r--r--src/protocols/core/Seat.cpp4
-rw-r--r--src/protocols/core/Shm.cpp27
-rw-r--r--src/protocols/core/Shm.hpp8
-rw-r--r--src/protocols/types/Buffer.cpp41
-rw-r--r--src/protocols/types/Buffer.hpp82
-rw-r--r--src/protocols/types/DMABuffer.cpp12
-rw-r--r--src/protocols/types/DMABuffer.hpp12
-rw-r--r--src/protocols/types/WLBuffer.cpp15
-rw-r--r--src/protocols/types/WLBuffer.hpp8
-rw-r--r--src/render/OpenGL.cpp483
-rw-r--r--src/render/OpenGL.hpp52
-rw-r--r--src/render/Renderbuffer.cpp67
-rw-r--r--src/render/Renderbuffer.hpp31
-rw-r--r--src/render/Renderer.cpp597
-rw-r--r--src/render/Renderer.hpp80
-rw-r--r--src/render/Texture.cpp62
-rw-r--r--src/render/Texture.hpp15
-rw-r--r--src/signal-safe.hpp1
-rw-r--r--src/xwayland/Server.cpp11
-rw-r--r--src/xwayland/XWM.cpp10
m---------subprojects/wlroots-hyprland0
131 files changed, 4740 insertions, 3444 deletions
diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml
index a7b9994c..26660ce6 100644
--- a/.github/actions/setup_base/action.yml
+++ b/.github/actions/setup_base/action.yml
@@ -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'
diff --git a/.gitmodules b/.gitmodules
index 37b48a5a..638f8ba9 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -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
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 07fa8cf6..e951b874 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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}
diff --git a/Makefile b/Makefile
index 493a6784..adf6fbe8 100644
--- a/Makefile
+++ b/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
diff --git a/README.md b/README.md
index ca44621d..fc2bd206 100644
--- a/README.md
+++ b/README.md
@@ -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*
diff --git a/flake.lock b/flake.lock
index b5f5738a..b2cc9703 100644
--- a/flake.lock
+++ b/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",
diff --git a/flake.nix b/flake.nix
index 88cb593b..9c20b3f5 100644
--- a/flake.nix
+++ b/flake.nix
@@ -7,6 +7,14 @@
# <https://github.com/nix-systems/nix-systems>
systems.url = "github:nix-systems/default-linux";
+ aquamarine = {
+ url = "github:hyprwm/aquamarine";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.systems.follows = "systems";
+ inputs.hyprutils.follows = "hyprutils";
+ inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
+ };
+
hyprcursor = {
url = "github:hyprwm/hyprcursor";
inputs.nixpkgs.follows = "nixpkgs";
diff --git a/hyprland.pc.in b/hyprland.pc.in
index 382fb1e6..81a0ef11 100644
--- a/hyprland.pc.in
+++ b/hyprland.pc.in
@@ -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
diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp
index 848b9cab..7d7cc079 100644
--- a/hyprpm/src/core/PluginManager.cpp
+++ b/hyprpm/src/core/PluginManager.cpp
@@ -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";
diff --git a/meson.build b/meson.build
index 49c48c6c..b8101f6c 100644
--- a/meson.build
+++ b/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'],
)
diff --git a/nix/default.nix b/nix/default.nix
index a2302688..7775b729 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -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
diff --git a/nix/overlays.nix b/nix/overlays.nix
index a4e1df37..9d100d51 100644
--- a/nix/overlays.nix
+++ b/nix/overlays.nix
@@ -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
diff --git a/nix/update-wlroots.sh b/nix/update-wlroots.sh
deleted file mode 100755
index 01f5cd83..00000000
--- a/nix/update-wlroots.sh
+++ /dev/null
@@ -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
diff --git a/protocols/meson.build b/protocols/meson.build
index 7c508659..5cdeb160 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -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 = []
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 7ffccf36..c7a0cfb1 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -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();
- m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD);
+ 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!");
}
- 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!");
- }
+ m_bInitialized = true;
- m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer);
+ m_iDRMFD = m_pAqBackend->drmFD();
+ Debug::log(LOG, "Running on DRMFD: {}", m_iDRMFD);
- if (!m_sWLRAllocator) {
- Debug::log(CRIT, "m_sWLRAllocator was NULL!");
- throwError("wlr_allocator_autocreate() failed!");
+ // get socket, avoid using 0
+ for (int candidate = 1; candidate <= 32; candidate++) {
+ const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate));
+ const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str());
+ if (RETVAL >= 0) {
+ m_szWLDisplaySocket = CANDIDATESTR;
+ Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL);
+ break;
+ } else {
+ Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
+ }
}
- m_sWLREGL = wlr_gles2_renderer_get_egl(m_sWLRRenderer);
+ if (m_szWLDisplaySocket.empty()) {
+ Debug::log(WARN, "All candidates failed, trying wl_display_add_socket_auto");
+ const auto SOCKETSTR = wl_display_add_socket_auto(m_sWLDisplay);
+ if (SOCKETSTR)
+ m_szWLDisplaySocket = SOCKETSTR;
+ }
- if (!m_sWLREGL) {
- Debug::log(CRIT, "m_sWLREGL was NULL!");
- throwError("wlr_gles2_renderer_get_egl() 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)");
}
+ 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");
+ initManagers(STAGE_LATE);
+
+ for (auto& o : pendingOutputs) {
+ onNewMonitor(o);
}
+ pendingOutputs.clear();
+}
- m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop);
+void CCompositor::initAllSignals() {
+ 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);
+
+ 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);
+
+ 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);
- if (!m_sWLRHeadlessBackend) {
- Debug::log(CRIT, "Couldn't create the headless backend");
- throwError("wlr_headless_backend_create() failed!");
- }
+ 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);
- wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
+ 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);
- initManagers(STAGE_LATE);
-}
+ 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);
-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");
+ 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!");
- if (m_sWRLDRMLeaseMgr)
- addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
+ m_bSessionActive = true;
- if (m_sWLRSession)
- addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
-}
+ for (auto& m : m_vMonitors) {
+ scheduleFrameForMonitor(m.get());
+ g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true);
+ }
-void CCompositor::removeAllSignals() {
- removeWLSignal(&Events::listen_newOutput);
- removeWLSignal(&Events::listen_newInput);
- removeWLSignal(&Events::listen_RendererDestroy);
+ g_pConfigManager->m_bWantsMonitorReload = true;
+ } else {
+ Debug::log(LOG, "Session got deactivated!");
- if (m_sWRLDRMLeaseMgr)
- removeWLSignal(&Events::listen_leaseRequest);
+ m_bSessionActive = false;
+
+ for (auto& m : m_vMonitors) {
+ m->noFrameSchedule = true;
+ m->framesToSkip = 1;
+ }
+ }
+ },
+ nullptr);
+ }
+}
- if (m_sWLRSession)
- removeWLSignal(&Events::listen_sessionActive);
+void CCompositor::removeAllSignals() {
+ ;
}
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);
+}
diff --git a/src/Compositor.hpp b/src/Compositor.hpp
index 4aec323f..58c5b33d 100644
--- a/src/Compositor.hpp
+++ b/src/Compositor.hpp
@@ -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;
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 71349068..a5f18693 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -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);
diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp
index ce1a92ba..c25212fe 100644
--- a/src/debug/CrashReporter.cpp
+++ b/src/debug/CrashReporter.cpp
@@ -5,6 +5,7 @@
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
+#include <filesystem>
#include "../plugins/PluginSystem.hpp"
#include "../signal-safe.hpp"
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index 08d2bb57..b81cfeff 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -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();
+
+ if (type == Aquamarine::AQ_BACKEND_HEADLESS && (vars[2] == "headless" || vars[2] == "auto")) {
+ added = true;
+ impl->createOutput(vars[3]);
+ break;
+ }
- wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result);
+ if (type == Aquamarine::AQ_BACKEND_WAYLAND && (vars[2] == "wayland" || vars[2] == "auto")) {
+ added = true;
+ impl->createOutput(vars[3]);
+ break;
+ }
+ }
- if (!result.added)
+ 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";
diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp
index 7547204a..c2939831 100644
--- a/src/debug/Log.cpp
+++ b/src/debug/Log.cpp
@@ -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;
diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp
index e8cd80cf..33f3c9c1 100644
--- a/src/debug/Log.hpp
+++ b/src/debug/Log.hpp
@@ -67,6 +67,4 @@ namespace Debug {
log(level, logMsg);
}
-
- void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
};
diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp
index f0fd556c..131a26b5 100644
--- a/src/desktop/Popup.cpp
+++ b/src/desktop/Popup.cpp
@@ -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();
}
diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp
index 47e180a8..d045cd41 100644
--- a/src/desktop/Popup.hpp
+++ b/src/desktop/Popup.hpp
@@ -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;
diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp
index 4ea34156..7497957a 100644
--- a/src/desktop/Window.cpp
+++ b/src/desktop/Window.cpp
@@ -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() {
diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp
index cb294d1a..284a8295 100644
--- a/src/devices/IKeyboard.cpp
+++ b/src/devices/IKeyboard.cpp
@@ -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)
+ clearManuallyAllocd();
+}
+
+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));
+ }
- xkb_state_unref(xkbTranslationState);
- xkbTranslationState = nullptr;
+ 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,
+ });
+ }
}
diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp
index b1757a18..1ae6c7bc 100644
--- a/src/devices/IKeyboard.hpp
+++ b/src/devices/IKeyboard.hpp
@@ -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;
+
+ struct {
+ uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
+ } modifiersState;
+
+ std::array<xkb_led_index_t, 3> ledIndexes = {XKB_MOD_INVALID};
+ std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID};
+ uint32_t leds = 0;
+
+ std::string hlName = "";
+ std::string xkbFilePath = "";
+ std::string xkbKeymapString = "";
+ int xkbKeymapFD = -1;
+
+ SStringRuleNames currentRules;
+ int repeatRate = 0;
+ int repeatDelay = 0;
+ int numlockOn = -1;
+ bool resolveBindsBySym = false;
- std::string hlName = "";
- std::string xkbFilePath = "";
+ WP<IKeyboard> self;
- SStringRuleNames currentRules;
- int repeatRate = 0;
- int repeatDelay = 0;
- int numlockOn = -1;
- bool resolveBindsBySym = false;
+ private:
+ void clearManuallyAllocd();
- WP<IKeyboard> self;
+ std::vector<uint32_t> pressedXKB;
};
diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp
index b2995b2f..5df47c04 100644
--- a/src/devices/IPointer.hpp
+++ b/src/devices/IPointer.hpp
@@ -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;
diff --git a/src/devices/ITouch.hpp b/src/devices/ITouch.hpp
index b9cbf2ae..cb8a6e90 100644
--- a/src/devices/ITouch.hpp
+++ b/src/devices/ITouch.hpp
@@ -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;
diff --git a/src/devices/Keyboard.cpp b/src/devices/Keyboard.cpp
index 17357edb..ae28c07d 100644
--- a/src/devices/Keyboard.cpp
+++ b/src/devices/Keyboard.cpp
@@ -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();
+ });
+
+ listeners.key = keeb->events.key.registerListener([this](std::any d) {
+ auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
- hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) {
- auto E = (wlr_keyboard_key_event*)data;
+ 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");
+ });
- hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) {
- keyboardEvents.modifiers.emit();
- }, this, "CKeyboard");
+ listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
+ updateModifiersState();
- hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) {
- keyboardEvents.repeatInfo.emit();
- }, this, "CKeyboard");
- // clang-format on
-
- deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN";
-}
+ keyboardEvents.modifiers.emit(SModifiersEvent{
+ .depressed = modifiersState.depressed,
+ .latched = modifiersState.latched,
+ .locked = modifiersState.locked,
+ .group = modifiersState.group,
+ });
+ });
-void CKeyboard::disconnectCallbacks() {
- hyprListener_destroy.removeCallback();
- hyprListener_key.removeCallback();
- hyprListener_keymap.removeCallback();
- hyprListener_repeatInfo.removeCallback();
- hyprListener_modifiers.removeCallback();
+ deviceName = keeb->getName();
}
diff --git a/src/devices/Keyboard.hpp b/src/devices/Keyboard.hpp
index cf01a9a7..f6de43cb 100644
--- a/src/devices/Keyboard.hpp
+++ b/src/devices/Keyboard.hpp
@@ -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;
}; \ No newline at end of file
diff --git a/src/devices/Mouse.cpp b/src/devices/Mouse.cpp
index b860298c..ae89ed92 100644
--- a/src/devices/Mouse.cpp
+++ b/src/devices/Mouse.cpp
@@ -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();
}
diff --git a/src/devices/Mouse.hpp b/src/devices/Mouse.hpp
index 40a65ca8..2b51fbe9 100644
--- a/src/devices/Mouse.hpp
+++ b/src/devices/Mouse.hpp
@@ -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;
};
diff --git a/src/devices/Tablet.cpp b/src/devices/Tablet.cpp
index b5ab16c1..71ca8991 100644
--- a/src/devices/Tablet.cpp
+++ b/src/devices/Tablet.cpp
@@ -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();
}
diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp
index ada2cf89..0efbe796 100644
--- a/src/devices/Tablet.hpp
+++ b/src/devices/Tablet.hpp
@@ -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;
-
- 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;
+ 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;
};
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);
-
- void disconnectCallbacks();
-
- WP<CWLSurfaceResource> pSurface;
-
- wlr_tablet_tool* tool = nullptr;
+ CTabletTool(SP<Aquamarine::ITabletTool> tool);
- DYNLISTENER(destroy);
+ WP<CWLSurfaceResource> pSurface;
+ WP<Aquamarine::ITabletTool> tool;
struct {
CHyprSignalListener destroySurface;
+ CHyprSignalListener destroyTool;
} listeners;
}; \ No newline at end of file
diff --git a/src/devices/TouchDevice.cpp b/src/devices/TouchDevice.cpp
index 64c521a2..25b7b503 100644
--- a/src/devices/TouchDevice.cpp
+++ b/src/devices/TouchDevice.cpp
@@ -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();
}
diff --git a/src/devices/TouchDevice.hpp b/src/devices/TouchDevice.hpp
index 51eb76d4..b18df2d0 100644
--- a/src/devices/TouchDevice.hpp
+++ b/src/devices/TouchDevice.hpp
@@ -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;
}; \ No newline at end of file
diff --git a/src/devices/VirtualKeyboard.cpp b/src/devices/VirtualKeyboard.cpp
index e2be0078..654ca9f5 100644
--- a/src/devices/VirtualKeyboard.cpp
+++ b/src/devices/VirtualKeyboard.cpp
@@ -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");
-
- 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,
+ events.destroy.emit();
+ });
+
+ 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");
-
- 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";
+ });
+ 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);
+ });
+
+ 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() {
diff --git a/src/devices/VirtualKeyboard.hpp b/src/devices/VirtualKeyboard.hpp
index 5ef88dd3..12a3907c 100644
--- a/src/devices/VirtualKeyboard.hpp
+++ b/src/devices/VirtualKeyboard.hpp
@@ -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;
};
diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp
index c8ee3332..faca27dc 100644
--- a/src/devices/VirtualPointer.cpp
+++ b/src/devices/VirtualPointer.cpp
@@ -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;
-
- 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";
+ });
+
+ 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); });
+
+ 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;
}
diff --git a/src/devices/VirtualPointer.hpp b/src/devices/VirtualPointer.hpp
index b22c8bf2..1ecfd842 100644
--- a/src/devices/VirtualPointer.hpp
+++ b/src/devices/VirtualPointer.hpp
@@ -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;
}; \ No newline at end of file
diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp
deleted file mode 100644
index fedc844e..00000000
--- a/src/events/Devices.cpp
+++ /dev/null
@@ -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();
-}
diff --git a/src/events/Events.hpp b/src/events/Events.hpp
index f8eb9d2f..8e73f54a 100644
--- a/src/events/Events.hpp
+++ b/src/events/Events.hpp
@@ -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);
};
diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp
deleted file mode 100644
index 32f894ec..00000000
--- a/src/events/Misc.cpp
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp
index 2536e1f7..40b6f17e 100644
--- a/src/events/Monitors.cpp
+++ b/src/events/Monitors.cpp
@@ -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);
}
}
diff --git a/src/helpers/CursorShapes.hpp b/src/helpers/CursorShapes.hpp
new file mode 100644
index 00000000..6f3c8a0e
--- /dev/null
+++ b/src/helpers/CursorShapes.hpp
@@ -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 \ No newline at end of file
diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp
index 5251002c..afc8b1c5 100644
--- a/src/helpers/Format.cpp
+++ b/src/helpers/Format.cpp
@@ -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;
+}
diff --git a/src/helpers/Format.hpp b/src/helpers/Format.hpp
index a1ef53f5..8269c5c3 100644
--- a/src/helpers/Format.hpp
+++ b/src/helpers/Format.hpp
@@ -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);
};
diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp
index 712e4e50..53c0dc13 100644
--- a/src/helpers/MiscFunctions.cpp
+++ b/src/helpers/MiscFunctions.cpp
@@ -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>
diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp
index 33be7965..49e3bced 100644
--- a/src/helpers/MiscFunctions.hpp
+++ b/src/helpers/MiscFunctions.hpp
@@ -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>
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index 20c2e81e..a23b9861 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -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;
+void CMonitor::onConnect(bool noRule) {
- PROTO::presentation->onPresented(PMONITOR, E->when, E->refresh, E->seq, E->flags);
-}
+ 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;
+ }
-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 (!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;
+ }
+
+ if (m_pOwner->output->state->state().buffer)
+ return;
-void CMonitorState::clear() {
- wlr_output_state_finish(&m_state);
- m_state = {0};
- wlr_output_state_init(&m_state);
+ // this is required for modesetting being possible and might be missing in case of first tests in the renderer
+ // where we test modes and buffers
+ Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer, attaching one from the swapchain for modeset being possible");
+ m_pOwner->output->state->setBuffer(m_pOwner->output->swapchain->next(nullptr));
+ m_pOwner->output->swapchain->rollback(); // restore the counter, don't advance the swapchain
}
bool CMonitorState::commit() {
- bool 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);
}
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 8a2acdaf..32fc768a 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -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;
+ 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;
- 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;
+ 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 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 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;
+ bool isBeingLeased = false;
- SMonitorRule activeMonitorRule;
+ SMonitorRule activeMonitorRule;
- WP<CMonitor> self;
+ // 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;
};
diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp
index 6b25e76d..51f90166 100644
--- a/src/helpers/WLClasses.hpp
+++ b/src/helpers/WLClasses.hpp
@@ -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;
-
- int status = -1; // uninitialized
+ WP<Aquamarine::ISwitch> pDevice;
- DYNLISTENER(destroy);
- DYNLISTENER(toggle);
+ struct {
+ CHyprSignalListener destroy;
+ CHyprSignalListener fire;
+ } listeners;
bool operator==(const SSwitchDevice& other) const {
- return pWlrDevice == other.pWlrDevice;
+ return pDevice == other.pDevice;
}
};
diff --git a/src/helpers/X11Stubs.hpp b/src/helpers/X11Stubs.hpp
deleted file mode 100644
index 19bea6f8..00000000
--- a/src/helpers/X11Stubs.hpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-inline bool wlr_backend_is_x11(void*) {
- return false;
-}
-
-inline void wlr_x11_output_create(void*) {}
diff --git a/src/helpers/math/Math.cpp b/src/helpers/math/Math.cpp
index 560f29c9..fccfd636 100644
--- a/src/helpers/math/Math.cpp
+++ b/src/helpers/math/Math.cpp
@@ -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;
+}
+
+void matrixTransform(float mat[9], eTransform transform) {
+ matrixMultiply(mat, mat, getTransforms().at(transform).data());
}
-static void matrixProjection(float mat[9], int width, int height, eTransform transform) {
+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;
+}
diff --git a/src/helpers/math/Math.hpp b/src/helpers/math/Math.hpp
index 4aa65c93..f57cef93 100644
--- a/src/helpers/math/Math.hpp
+++ b/src/helpers/math/Math.hpp
@@ -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);
diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp
new file mode 100644
index 00000000..352120ea
--- /dev/null
+++ b/src/helpers/sync/SyncTimeline.cpp
@@ -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;
+}
diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp
new file mode 100644
index 00000000..3d868a95
--- /dev/null
+++ b/src/helpers/sync/SyncTimeline.hpp
@@ -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;
+};
diff --git a/src/includes.hpp b/src/includes.hpp
index afec078a..8b3f3fad 100644
--- a/src/includes.hpp
+++ b/src/includes.hpp
@@ -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
diff --git a/src/macros.hpp b/src/macros.hpp
index f1393cbd..b2adb036 100644
--- a/src/macros.hpp
+++ b/src/macros.hpp
@@ -105,3 +105,8 @@
class name; \
} \
}
+
+#define AQUAMARINE_FORWARD(name) \
+ namespace Aquamarine { \
+ class name; \
+ }
diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp
index 677b2109..dcc7a45f 100644
--- a/src/managers/AnimationManager.cpp
+++ b/src/managers/AnimationManager.cpp
@@ -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.
diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp
index daa4f4be..3a13d10b 100644
--- a/src/managers/CursorManager.cpp
+++ b/src/managers/CursorManager.cpp
@@ -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);
+CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
+ pixelData = pixelData_;
+ size = size_;
+ stride = 4 * size_.x;
+}
- if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE)
- return false;
+CCursorManager::CCursorBuffer::~CCursorBuffer() {
+ ;
+}
- *data = buffer->pixelData ? buffer->pixelData : cairo_image_surface_get_data(buffer->surface);
- *stride = buffer->stride;
- *format = DRM_FORMAT_ARGB8888;
- return true;
+Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() {
+ return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
}
-static void cursorBufferEndDataPtr(struct wlr_buffer* wlr_buffer) {
+Aquamarine::eBufferType CCursorManager::CCursorBuffer::type() {
+ return Aquamarine::eBufferType::BUFFER_TYPE_SHM;
+}
+
+void CCursorManager::CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) {
;
}
-//
-static const wlr_buffer_impl bufferImpl = {
- .destroy = cursorBufferDestroy,
- .begin_data_ptr_access = cursorBufferBeginDataPtr,
- .end_data_ptr_access = cursorBufferEndDataPtr,
-};
+bool CCursorManager::CCursorBuffer::isSynchronous() {
+ return true;
+}
-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);
+bool CCursorManager::CCursorBuffer::good() {
+ return true;
}
-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;
+Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() {
+ Aquamarine::SSHMAttrs attrs;
+ attrs.success = true;
+ attrs.format = DRM_FORMAT_ARGB8888;
+ attrs.size = size;
+ attrs.stride = stride;
+ return attrs;
}
-CCursorManager::CCursorBuffer::~CCursorBuffer() {
- ; // will be freed in .destroy
+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};
}
-wlr_buffer* CCursorManager::getCursorBuffer() {
- return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr;
+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_szTheme = name;
+ m_iSize = size;
+ updateTheme();
+ return true;
+}
+
+// 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
- m_pWLRXCursorMgr = wlr_xcursor_manager_create(name.empty() ? "" : name.c_str(), size);
- bool xSuccess = wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0) == 1;
+void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int size) {
+ if (lastLoadSize == size && themeName == name)
+ return;
- // 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;
+ 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};
- Debug::log(ERR, "X also failed loading theme \"{}\", falling back to previous theme.", name);
+ defaultCursor->pixels.resize(img->width * img->height);
+ std::memcpy(defaultCursor->pixels.data(), img->pixels, img->width * img->height * sizeof(uint32_t));
- m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.c_str(), hcLogger);
+ themeLoaded = true;
- 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);
+ XcursorImageDestroy(img);
- updateTheme();
- return false;
+ // 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);
+ }
}
diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp
index 3ee98ca6..4324dfb4 100644
--- a/src/managers/CursorManager.hpp
+++ b/src/managers/CursorManager.hpp
@@ -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; \ No newline at end of file
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
index eb8a3232..e9dfd1ae 100644
--- a/src/managers/KeybindManager.cpp
+++ b/src/managers/KeybindManager.cpp
@@ -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;
diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp
index 2a256760..284280cd 100644
--- a/src/managers/KeybindManager.hpp
+++ b/src/managers/KeybindManager.hpp
@@ -6,6 +6,7 @@
#include "../Compositor.hpp"
#include <unordered_map>
#include <functional>
+#include <xkbcommon/xkbcommon.h>
#include "../devices/IPointer.hpp"
class CInputManager;
diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp
index 7090645f..cf10db71 100644
--- a/src/managers/PointerManager.cpp
+++ b/src/managers/PointerManager.cpp
@@ -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);
-
- if (w < currentCursorImage.size.x || h < currentCursorImage.size.y) {
- Debug::log(TRACE, "hardware cursor too big! {} > {}x{}", currentCursorImage.size, w, h);
- return nullptr;
- }
- }
+ auto maxSize = output->cursorPlaneSize();
+ auto cursorSize = currentCursorImage.size;
- 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;
+
+ if (!state->monitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size) {
- 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)
+ state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(state->monitor->output->getBackend()->preferredAllocator(), state->monitor->output->getBackend());
- if (!output->cursor_swapchain) {
- Debug::log(TRACE, "Failed to create cursor swapchain");
+ 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;
}
diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp
index da639340..cf4f1a94 100644
--- a/src/managers/PointerManager.hpp
+++ b/src/managers/PointerManager.hpp
@@ -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;
-
- Vector2D hotspot;
- Vector2D size;
- float scale = 1.F;
-
- CHyprSignalListener destroySurface;
- CHyprSignalListener commitSurface;
- DYNLISTENER(destroyBuffer);
+ SP<Aquamarine::IBuffer> pBuffer;
+ SP<CTexture> bufferTex;
+ WP<CWLSurface> surface;
+
+ Vector2D hotspot;
+ Vector2D size;
+ float scale = 1.F;
+
+ 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;
diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp
index 74cebd0c..387cac8f 100644
--- a/src/managers/ProtocolManager.cpp
+++ b/src/managers/ProtocolManager.cpp
@@ -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");
diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp
index 6589c4bf..801ae55a 100644
--- a/src/managers/SeatManager.cpp
+++ b/src/managers/SeatManager.cpp
@@ -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;
}
diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp
index 0d1b0223..ed7a4f72 100644
--- a/src/managers/eventLoop/EventLoopManager.cpp
+++ b/src/managers/eventLoop/EventLoopManager.cpp
@@ -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! :(");
diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp
index 0b2f9578..39d8bbeb 100644
--- a/src/managers/eventLoop/EventLoopManager.hpp
+++ b/src/managers/eventLoop/EventLoopManager.hpp
@@ -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; \ No newline at end of file
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index 23e183d0..255023b9 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -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;
-
- Debug::log(LOG, "New switch with name \"{}\" added", pDevice->name);
+void CInputManager::newSwitch(SP<Aquamarine::ISwitch> pDevice) {
+ const auto PNEWDEV = &m_lSwitches.emplace_back();
+ PNEWDEV->pDevice = pDevice;
- PNEWDEV->hyprListener_destroy.initCallback(&pDevice->events.destroy, [&](void* owner, void* data) { destroySwitch((SSwitchDevice*)owner); }, PNEWDEV, "SwitchDevice");
+ Debug::log(LOG, "New switch with name \"{}\" added", pDevice->getName());
- const auto PSWITCH = wlr_switch_from_input_device(pDevice);
+ PNEWDEV->listeners.destroy = pDevice->events.destroy.registerListener([this, PNEWDEV](std::any d) { destroySwitch(PNEWDEV); });
- 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;
+ 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);
- if (PDEVICE->status != -1 && PDEVICE->status == E->switch_state)
- return;
-
- Debug::log(LOG, "Switch {} fired, triggering binds.", NAME);
+ Debug::log(LOG, "Switch {} fired, triggering binds.", NAME);
- g_pKeybindManager->onSwitchEvent(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) {
diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp
index 85ae6197..ebf00b2d 100644
--- a/src/managers/input/InputManager.hpp
+++ b/src/managers/input/InputManager.hpp
@@ -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>);
diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp
index f1157e4b..5e50e851 100644
--- a/src/managers/input/Tablets.cpp
+++ b/src/managers/input/Tablets.cpp
@@ -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);
-
- PTOOL->events.destroy.registerStaticListener(
- [this](void* owner, std::any d) {
- auto TOOL = ((CTabletTool*)owner)->self;
- destroyTabletTool(TOOL.lock());
- },
- PTOOL.get());
+SP<CTabletTool> CInputManager::ensureTabletToolPresent(SP<Aquamarine::ITabletTool> pTool) {
+
+ 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
}
diff --git a/src/meson.build b/src/meson.build
index f6ae043d..71854fa4 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -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'),
diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp
index 6e09ba2c..098e3f12 100644
--- a/src/plugins/PluginAPI.cpp
+++ b/src/plugins/PluginAPI.cpp
@@ -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>
diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp
index 2f25b22b..812afe53 100644
--- a/src/protocols/CursorShape.cpp
+++ b/src/protocols/CursorShape.cpp
@@ -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);
} \ No newline at end of file
diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp
new file mode 100644
index 00000000..9f5b6312
--- /dev/null
+++ b/src/protocols/DRMLease.cpp
@@ -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();
+ }
+}
diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp
new file mode 100644
index 00000000..56eaa3db
--- /dev/null
+++ b/src/protocols/DRMLease.hpp
@@ -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;
+};
diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp
new file mode 100644
index 00000000..41178109
--- /dev/null
+++ b/src/protocols/DRMSyncobj.cpp
@@ -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; });
+}
diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp
new file mode 100644
index 00000000..c1c884ff
--- /dev/null
+++ b/src/protocols/DRMSyncobj.hpp
@@ -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;
+};
diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp
index 7c3b39ce..494d9862 100644
--- a/src/protocols/GammaControl.cpp
+++ b/src/protocols/GammaControl.cpp
@@ -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);
diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp
index 93465b81..963eea5c 100644
--- a/src/protocols/GammaControl.hpp
+++ b/src/protocols/GammaControl.hpp
@@ -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();
diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp
index 24f7ad54..def4d837 100644
--- a/src/protocols/InputMethodV2.cpp
+++ b/src/protocols/InputMethodV2.cpp
@@ -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();
diff --git a/src/protocols/InputMethodV2.hpp b/src/protocols/InputMethodV2.hpp
index bc21270c..0b2c7a49 100644
--- a/src/protocols/InputMethodV2.hpp
+++ b/src/protocols/InputMethodV2.hpp
@@ -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 {
diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp
index cf8f8730..0fbf832e 100644
--- a/src/protocols/LinuxDMABUF.cpp
+++ b/src/protocols/LinuxDMABUF.cpp
@@ -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);
+ 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());
+ }
+ }
+ }
+ }
+
+ tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry);
+
int fds[2] = {0};
- allocateSHMFilePair(tableLen, &fds[0], &fds[1]);
+ allocateSHMFilePair(tableSize, &fds[0], &fds[1]);
- auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0);
+ 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);
- }
-
- size_t i = 0;
- for (auto& [fmt, mod] : formatsVec) {
- arr[i++] = SDMABUFFeedbackTableEntry{
- .fmt = fmt,
- .modifier = mod,
- };
- }
+ std::copy(formatsVec.begin(), formatsVec.end(), arr);
- munmap(arr, tableLen);
+ munmap(arr, tableSize);
- 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,40 +308,52 @@ 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& formatTable = PROTO::linuxDma->formatTable;
+ resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize);
+ sendDefaultFeedback();
+}
- auto* feedback = PROTO::linuxDma->defaultFeedback.get();
+CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() {
+ ;
+}
- resource->sendFormatTable(feedback->tableFD, feedback->tableLen);
+bool CLinuxDMABUFFeedbackResource::good() {
+ return resource->resource();
+}
- // send default feedback
+void CLinuxDMABUFFeedbackResource::sendTranche(SDMABUFTranche& tranche) {
struct wl_array deviceArr = {
- .size = sizeof(feedback->mainDevice),
- .data = (void*)&feedback->mainDevice,
+ .size = sizeof(tranche.device),
+ .data = (void*)&tranche.device,
};
- 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->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)tranche.flags);
+
+ wl_array indices = {
+ .size = tranche.indicies.size() * sizeof(tranche.indicies.at(0)),
+ .data = tranche.indicies.data(),
+ };
resource->sendTrancheFormats(&indices);
- wl_array_release(&indices);
resource->sendTrancheDone();
-
- resource->sendDone();
}
-CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() {
- ;
-}
+// default tranche is based on renderer (egl)
+void CLinuxDMABUFFeedbackResource::sendDefaultFeedback() {
+ auto mainDevice = PROTO::linuxDma->mainDevice;
+ auto& formatTable = PROTO::linuxDma->formatTable;
-bool CLinuxDMABUFFeedbackResource::good() {
- return resource->resource();
+ 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_) {
@@ -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
+ // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166
- resource->sendModifier(fmt, mod >> 32, mod & 0xFFFFFFFF);
+ resource->sendModifier(fmt.drmFormat, 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;
+
+ 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();
+ });
+ }
- defaultFeedback = std::make_unique<CCompiledDMABUFFeedback>(*dev, tches);
+ 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;
+}
diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp
index 2b8ce736..0e25cdc6 100644
--- a/src/protocols/LinuxDMABUF.hpp
+++ b/src/protocols/LinuxDMABUF.hpp
@@ -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;
diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp
index 0bcf4a9c..ed412555 100644
--- a/src/protocols/MesaDRM.cpp
+++ b/src/protocols/MesaDRM.cpp
@@ -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);
diff --git a/src/protocols/MesaDRM.hpp b/src/protocols/MesaDRM.hpp
index ad31a182..46811d68 100644
--- a/src/protocols/MesaDRM.hpp
+++ b/src/protocols/MesaDRM.hpp
@@ -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();
diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp
index 68c50193..66f4c5f0 100644
--- a/src/protocols/OutputManagement.cpp
+++ b/src/protocols/OutputManagement.cpp
@@ -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) {
diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp
index 81ae9a71..36478d0b 100644
--- a/src/protocols/OutputManagement.hpp
+++ b/src/protocols/OutputManagement.hpp
@@ -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;
diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp
index ef287cfa..597b9871 100644
--- a/src/protocols/OutputPower.cpp
+++ b/src/protocols/OutputPower.cpp
@@ -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);
diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp
index 3907bf1e..e9472fc3 100644
--- a/src/protocols/PresentationTime.cpp
+++ b/src/protocols/PresentationTime.cpp
@@ -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)
diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp
index 8a6285a1..5d1c9332 100644
--- a/src/protocols/Screencopy.cpp
+++ b/src/protocols/Screencopy.cpp
@@ -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;
}
diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp
index be434285..4999773b 100644
--- a/src/protocols/Screencopy.hpp
+++ b/src/protocols/Screencopy.hpp
@@ -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);
diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp
index 7b62f245..72c7cfde 100644
--- a/src/protocols/Tablet.cpp
+++ b/src/protocols/Tablet.cpp
@@ -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)
diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp
index 58f13c1a..1ebcb1e5 100644
--- a/src/protocols/Tablet.hpp
+++ b/src/protocols/Tablet.hpp
@@ -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;
diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp
index d4c66c3b..0e78e5f7 100644
--- a/src/protocols/ToplevelExport.cpp
+++ b/src/protocols/ToplevelExport.cpp
@@ -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());
diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp
index f044a781..c3620d41 100644
--- a/src/protocols/ToplevelExport.hpp
+++ b/src/protocols/ToplevelExport.hpp
@@ -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;
diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp
index 8cb69dbe..03c5775e 100644
--- a/src/protocols/Viewporter.cpp
+++ b/src/protocols/Viewporter.cpp
@@ -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;
diff --git a/src/protocols/Viewporter.hpp b/src/protocols/Viewporter.hpp
index 01278203..3c2a4eef 100644
--- a/src/protocols/Viewporter.hpp
+++ b/src/protocols/Viewporter.hpp
@@ -15,11 +15,14 @@ class CViewportResource {
~CViewportResource();
bool good();
- void verify();
WP<CWLSurfaceResource> surface;
private:
SP<CWpViewport> resource;
+
+ struct {
+ CHyprSignalListener surfacePrecommit;
+ } listeners;
};
class CViewporterResource {
diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp
index 009c277c..2642ec11 100644
--- a/src/protocols/VirtualKeyboard.cpp
+++ b/src/protocols/VirtualKeyboard.cpp
@@ -1,12 +1,9 @@
#include "VirtualKeyboard.hpp"
#include <sys/mman.h>
+#include "../devices/IKeyboard.hpp"
#define LOGM PROTO::virtualKeyboard->protoLog
-static const struct wlr_keyboard_impl virtualKeyboardImpl = {
- .name = "virtual-keyboard",
-};
-
CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1> resource_) : resource(resource_) {
if (!good())
return;
@@ -28,13 +25,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
return;
}
- wlr_keyboard_key_event event = {
- .time_msec = timeMs,
- .keycode = key,
- .update_state = false,
- .state = (wl_keyboard_key_state)state,
- };
- wlr_keyboard_notify_key(&keyboard, &event);
+ events.key.emit(IKeyboard::SKeyEvent{
+ .timeMs = timeMs,
+ .keycode = key,
+ .state = (wl_keyboard_key_state)state,
+ });
+
+ const bool CONTAINS = std::find(pressed.begin(), pressed.end(), key) != pressed.end();
+ if (state && !CONTAINS)
+ pressed.emplace_back(key);
+ else if (!state && CONTAINS)
+ std::erase(pressed, key);
});
resource->setModifiers([this](CZwpVirtualKeyboardV1* r, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
@@ -43,7 +44,12 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
return;
}
- wlr_keyboard_notify_modifiers(&keyboard, depressed, latched, locked, group);
+ events.modifiers.emit(IKeyboard::SModifiersEvent{
+ .depressed = depressed,
+ .latched = latched,
+ .locked = locked,
+ .group = group,
+ });
});
resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) {
@@ -75,7 +81,9 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
return;
}
- wlr_keyboard_set_keymap(&keyboard, xkbKeymap);
+ events.keymap.emit(IKeyboard::SKeymapEvent{
+ .keymap = xkbKeymap,
+ });
hasKeymap = true;
xkb_keymap_unref(xkbKeymap);
@@ -83,22 +91,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
close(fd);
});
- wlr_keyboard_init(&keyboard, &virtualKeyboardImpl, "CVirtualKeyboard");
+ name = "hl-virtual-keyboard";
}
CVirtualKeyboardV1Resource::~CVirtualKeyboardV1Resource() {
events.destroy.emit();
- wlr_keyboard_finish(&keyboard);
}
bool CVirtualKeyboardV1Resource::good() {
return resource->resource();
}
-wlr_keyboard* CVirtualKeyboardV1Resource::wlr() {
- return &keyboard;
-}
-
wl_client* CVirtualKeyboardV1Resource::client() {
return resource->resource() ? resource->client() : nullptr;
}
@@ -106,17 +109,16 @@ wl_client* CVirtualKeyboardV1Resource::client() {
void CVirtualKeyboardV1Resource::releasePressed() {
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
- size_t keycodesNum = keyboard.num_keycodes;
-
- for (size_t i = 0; i < keycodesNum; ++i) {
- struct wlr_keyboard_key_event event = {
- .time_msec = (now.tv_sec * 1000 + now.tv_nsec / 1000000),
- .keycode = keyboard.keycodes[keycodesNum - i - 1],
- .update_state = false,
- .state = WL_KEYBOARD_KEY_STATE_RELEASED,
- };
- wlr_keyboard_notify_key(&keyboard, &event); // updates num_keycodes
+
+ for (auto& p : pressed) {
+ events.key.emit(IKeyboard::SKeyEvent{
+ .timeMs = now.tv_sec * 1000 + now.tv_nsec / 1000000,
+ .keycode = p,
+ .state = WL_KEYBOARD_KEY_STATE_RELEASED,
+ });
}
+
+ pressed.clear();
}
CVirtualKeyboardProtocol::CVirtualKeyboardProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp
index 447b5db9..93b63bb5 100644
--- a/src/protocols/VirtualKeyboard.hpp
+++ b/src/protocols/VirtualKeyboard.hpp
@@ -14,19 +14,24 @@ class CVirtualKeyboardV1Resource {
struct {
CSignal destroy;
+ CSignal key;
+ CSignal modifiers;
+ CSignal keymap;
} events;
- bool good();
- wlr_keyboard* wlr();
- wl_client* client();
+ bool good();
+ wl_client* client();
+
+ std::string name = "";
private:
SP<CZwpVirtualKeyboardV1> resource;
- wlr_keyboard keyboard;
void releasePressed();
bool hasKeymap = false;
+
+ std::vector<uint32_t> pressed;
};
class CVirtualKeyboardProtocol : public IWaylandProtocol {
diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp
index 1fb83888..bdeec32d 100644
--- a/src/protocols/VirtualPointer.cpp
+++ b/src/protocols/VirtualPointer.cpp
@@ -2,10 +2,6 @@
#define LOGM PROTO::virtualPointer->protoLog
-static const wlr_pointer_impl pointerImpl = {
- .name = "virtual-pointer-v1",
-};
-
CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> resource_) : resource(resource_) {
if (!good())
return;
@@ -19,41 +15,30 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> r
PROTO::virtualPointer->destroyResource(this);
});
- wlr_pointer_init(&pointer, &pointerImpl, "CVirtualPointerV1Resource");
-
resource->setMotion([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, wl_fixed_t dx, wl_fixed_t dy) {
- wlr_pointer_motion_event event = {
- .pointer = &pointer,
- .time_msec = timeMs,
- .delta_x = wl_fixed_to_double(dx),
- .delta_y = wl_fixed_to_double(dy),
- .unaccel_dx = wl_fixed_to_double(dx),
- .unaccel_dy = wl_fixed_to_double(dy),
- };
- wl_signal_emit_mutable(&pointer.events.motion, &event);
+ events.move.emit(IPointer::SMotionEvent{
+ .timeMs = timeMs,
+ .delta = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)},
+ .unaccel = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)},
+ });
});
resource->setMotionAbsolute([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t x, uint32_t y, uint32_t xExtent, uint32_t yExtent) {
if (!xExtent || !yExtent)
return;
- wlr_pointer_motion_absolute_event event = {
- .pointer = &pointer,
- .time_msec = timeMs,
- .x = (double)x / xExtent,
- .y = (double)y / yExtent,
- };
- wl_signal_emit_mutable(&pointer.events.motion_absolute, &event);
+ events.warp.emit(IPointer::SMotionAbsoluteEvent{
+ .timeMs = timeMs,
+ .absolute = {(double)x / xExtent, (double)y / yExtent},
+ });
});
resource->setButton([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t button, uint32_t state) {
- struct wlr_pointer_button_event event = {
- .pointer = &pointer,
- .time_msec = timeMs,
- .button = button,
- .state = (wl_pointer_button_state)state,
- };
- wl_signal_emit_mutable(&pointer.events.button, &event);
+ events.button.emit(IPointer::SButtonEvent{
+ .timeMs = timeMs,
+ .button = button,
+ .state = (wl_pointer_button_state)state,
+ });
});
resource->setAxis([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value) {
@@ -63,18 +48,18 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> r
}
axis = axis_;
- axisEvents[axis] = wlr_pointer_axis_event{.pointer = &pointer, .time_msec = timeMs, .orientation = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)};
+ axisEvents[axis] = IPointer::SAxisEvent{.timeMs = timeMs, .axis = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)};
});
resource->setFrame([this](CZwlrVirtualPointerV1* r) {
for (auto& e : axisEvents) {
- if (!e.pointer)
+ if (!e.timeMs)
continue;
- wl_signal_emit_mutable(&pointer.events.axis, &e);
- e.pointer = nullptr;
+ events.axis.emit(e);
+ e.timeMs = 0;
}
- wl_signal_emit_mutable(&pointer.events.frame, &pointer);
+ events.frame.emit();
});
resource->setAxisSource([this](CZwlrVirtualPointerV1* r, uint32_t source) { axisEvents[axis].source = (wl_pointer_axis_source)source; });
@@ -85,12 +70,11 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> r
return;
}
- axis = axis_;
- axisEvents[axis].pointer = &pointer;
- axisEvents[axis].time_msec = timeMs;
- axisEvents[axis].orientation = (wl_pointer_axis)axis;
- axisEvents[axis].delta = 0;
- axisEvents[axis].delta_discrete = 0;
+ axis = axis_;
+ axisEvents[axis].timeMs = timeMs;
+ axisEvents[axis].axis = (wl_pointer_axis)axis;
+ axisEvents[axis].delta = 0;
+ axisEvents[axis].deltaDiscrete = 0;
});
resource->setAxisDiscrete([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value, int32_t discrete) {
@@ -99,17 +83,15 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> r
return;
}
- axis = axis_;
- axisEvents[axis].pointer = &pointer;
- axisEvents[axis].time_msec = timeMs;
- axisEvents[axis].orientation = (wl_pointer_axis)axis;
- axisEvents[axis].delta = wl_fixed_to_double(value);
- axisEvents[axis].delta_discrete = discrete * 120;
+ axis = axis_;
+ axisEvents[axis].timeMs = timeMs;
+ axisEvents[axis].axis = (wl_pointer_axis)axis;
+ axisEvents[axis].delta = wl_fixed_to_double(value);
+ axisEvents[axis].deltaDiscrete = discrete * 120;
});
}
CVirtualPointerV1Resource::~CVirtualPointerV1Resource() {
- wlr_pointer_finish(&pointer);
events.destroy.emit();
}
@@ -117,10 +99,6 @@ bool CVirtualPointerV1Resource::good() {
return resource->resource();
}
-wlr_pointer* CVirtualPointerV1Resource::wlr() {
- return &pointer;
-}
-
wl_client* CVirtualPointerV1Resource::client() {
return resource->client();
}
diff --git a/src/protocols/VirtualPointer.hpp b/src/protocols/VirtualPointer.hpp
index 59a7e739..ee5ee7e2 100644
--- a/src/protocols/VirtualPointer.hpp
+++ b/src/protocols/VirtualPointer.hpp
@@ -7,6 +7,7 @@
#include "WaylandProtocol.hpp"
#include "wlr-virtual-pointer-unstable-v1.hpp"
#include "../helpers/signal/Signal.hpp"
+#include "../devices/IPointer.hpp"
class CVirtualPointerV1Resource {
public:
@@ -15,19 +16,35 @@ class CVirtualPointerV1Resource {
struct {
CSignal destroy;
+ CSignal move;
+ CSignal warp;
+ CSignal button;
+ CSignal axis;
+ CSignal frame;
+
+ CSignal swipeBegin;
+ CSignal swipeUpdate;
+ CSignal swipeEnd;
+
+ CSignal pinchBegin;
+ CSignal pinchUpdate;
+ CSignal pinchEnd;
+
+ CSignal holdBegin;
+ CSignal holdEnd;
} events;
- bool good();
- wlr_pointer* wlr();
- wl_client* client();
+ bool good();
+ wl_client* client();
+
+ std::string name;
private:
- SP<CZwlrVirtualPointerV1> resource;
- wlr_pointer pointer;
+ SP<CZwlrVirtualPointerV1> resource;
- uint32_t axis = 0;
+ uint32_t axis = 0;
- std::array<wlr_pointer_axis_event, 2> axisEvents;
+ std::array<IPointer::SAxisEvent, 2> axisEvents;
};
class CVirtualPointerProtocol : public IWaylandProtocol {
diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp
index 03e58956..073aa502 100644
--- a/src/protocols/XDGOutput.cpp
+++ b/src/protocols/XDGOutput.cpp
@@ -75,8 +75,8 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32
if (XDGVER >= OUTPUT_NAME_SINCE_VERSION)
pXDGOutput->resource->sendName(PMONITOR->szName.c_str());
- if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && PMONITOR->output->description)
- pXDGOutput->resource->sendDescription(PMONITOR->output->description);
+ if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && !PMONITOR->output->description.empty())
+ pXDGOutput->resource->sendDescription(PMONITOR->output->description.c_str());
pXDGOutput->sendDetails();
@@ -93,7 +93,7 @@ void CXDGOutputProtocol::updateAllOutputs() {
o->sendDetails();
- wlr_output_schedule_done(o->monitor->output);
+ o->monitor->scheduleDone();
}
}
diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp
index 9c56df93..8276ed55 100644
--- a/src/protocols/XDGShell.cpp
+++ b/src/protocols/XDGShell.cpp
@@ -4,6 +4,7 @@
#include "../managers/SeatManager.hpp"
#include "core/Seat.hpp"
#include "core/Compositor.hpp"
+#include <cstring>
#define LOGM PROTO::xdgShell->protoLog
diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp
index 691267b0..5cd6005a 100644
--- a/src/protocols/core/Compositor.cpp
+++ b/src/protocols/core/Compositor.cpp
@@ -6,6 +6,9 @@
#include "Subcompositor.hpp"
#include "../Viewporter.hpp"
#include "../../helpers/Monitor.hpp"
+#include "../PresentationTime.hpp"
+#include "../DRMSyncobj.hpp"
+#include "../../render/Renderer.hpp"
#define LOGM PROTO::compositor->protoLog
@@ -102,58 +105,14 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
pending.size = tfs / pending.scale;
}
- if (viewportResource)
- viewportResource->verify();
-
pending.damage.intersect(CBox{{}, pending.size});
- auto previousBuffer = current.buffer;
- CRegion previousBufferDamage = accumulateCurrentBufferDamage();
-
- current = pending;
- pending.damage.clear();
- pending.bufferDamage.clear();
-
- if (current.buffer && !bufferReleased) {
- // without previous dolphin et al are weird vvv
- //CRegion surfaceDamage =
- // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage);
- current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this.
-
- // release the buffer if it's synchronous as update() has done everything thats needed
- // so we can let the app know we're done.
- if (current.buffer->isSynchronous()) {
- current.buffer->sendRelease();
- bufferReleased = true;
- }
- }
-
- // TODO: we should _accumulate_ and not replace above if sync
- if (role->role() == SURFACE_ROLE_SUBSURFACE) {
- auto subsurface = (CWLSubsurfaceResource*)role.get();
- if (subsurface->sync)
- return;
-
- events.commit.emit();
- } else {
- // send commit to all synced surfaces in this tree.
- breadthfirst(
- [](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) {
- if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) {
- auto subsurface = (CWLSubsurfaceResource*)surf->role.get();
- if (!subsurface->sync)
- return;
- }
- surf->events.commit.emit();
- },
- nullptr);
- }
+ events.precommit.emit();
+ if (pending.rejected)
+ return;
- // for async buffers, we can only release the buffer once we are unrefing it from current.
- if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) {
- previousBuffer->sendRelease();
- bufferReleased = true;
- }
+ if (stateLocks <= 0)
+ commitPendingState();
});
resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); });
@@ -426,7 +385,97 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size;
- return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(wlr_output_transform_invert(current.transform)), trc.x, trc.y).add(current.bufferDamage);
+ return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage);
+}
+
+void CWLSurfaceResource::lockPendingState() {
+ stateLocks++;
+}
+
+void CWLSurfaceResource::unlockPendingState() {
+ stateLocks--;
+ if (stateLocks <= 0)
+ commitPendingState();
+}
+
+void CWLSurfaceResource::commitPendingState() {
+ auto previousBuffer = current.buffer;
+ CRegion previousBufferDamage = accumulateCurrentBufferDamage();
+
+ current = pending;
+ pending.damage.clear();
+ pending.bufferDamage.clear();
+
+ if (current.buffer && !bufferReleased) {
+ // without previous dolphin et al are weird vvv
+ //CRegion surfaceDamage =
+ // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage);
+ current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this.
+
+ // release the buffer if it's synchronous as update() has done everything thats needed
+ // so we can let the app know we're done.
+ if (current.buffer->isSynchronous()) {
+ current.buffer->sendReleaseWithSurface(self.lock());
+ bufferReleased = true;
+ }
+ }
+
+ // TODO: we should _accumulate_ and not replace above if sync
+ if (role->role() == SURFACE_ROLE_SUBSURFACE) {
+ auto subsurface = (CWLSubsurfaceResource*)role.get();
+ if (subsurface->sync)
+ return;
+
+ events.commit.emit();
+ } else {
+ // send commit to all synced surfaces in this tree.
+ breadthfirst(
+ [](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) {
+ if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) {
+ auto subsurface = (CWLSubsurfaceResource*)surf->role.get();
+ if (!subsurface->sync)
+ return;
+ }
+ surf->events.commit.emit();
+ },
+ nullptr);
+ }
+
+ // for async buffers, we can only release the buffer once we are unrefing it from current.
+ if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) {
+ if (previousBuffer->lockedByBackend) {
+ previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) {
+ if (!self.expired()) // could be dead in the dtor
+ previousBuffer->sendReleaseWithSurface(self.lock());
+ else
+ previousBuffer->sendRelease();
+ previousBuffer->hlEvents.backendRelease.reset();
+ bufferReleased = true;
+ });
+ } else
+ previousBuffer->sendReleaseWithSurface(self.lock());
+
+ bufferReleased = true;
+ }
+}
+
+void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) {
+ frame(when);
+ auto FEEDBACK = makeShared<CQueuedPresentationData>(self.lock());
+ FEEDBACK->attachMonitor(pMonitor);
+ FEEDBACK->discarded();
+ PROTO::presentation->queueData(FEEDBACK);
+
+ if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync)
+ return;
+
+ // attach explicit sync
+ g_pHyprRenderer->explicitPresented.emplace_back(self.lock());
+
+ if (syncobj->acquirePoint > pMonitor->lastWaitPoint) {
+ Debug::log(TRACE, "presentFeedback lastWaitPoint {} -> {}", pMonitor->lastWaitPoint, syncobj->acquirePoint);
+ pMonitor->lastWaitPoint = syncobj->acquirePoint;
+ }
}
CWLCompositorResource::CWLCompositorResource(SP<CWlCompositor> resource_) : resource(resource_) {
diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp
index 2f276719..5e6413c8 100644
--- a/src/protocols/core/Compositor.hpp
+++ b/src/protocols/core/Compositor.hpp
@@ -24,6 +24,7 @@ class CWLSurface;
class CWLSurfaceResource;
class CWLSubsurfaceResource;
class CViewportResource;
+class CDRMSyncobjSurfaceResource;
class CWLCallbackResource {
public:
@@ -74,6 +75,7 @@ class CWLSurfaceResource {
Vector2D sourceSize();
struct {
+ CSignal precommit;
CSignal commit;
CSignal map;
CSignal unmap;
@@ -81,11 +83,11 @@ class CWLSurfaceResource {
CSignal destroy;
} events;
- struct {
+ struct SState {
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
int scale = 1;
- SP<IWLBuffer> buffer;
+ SP<IHLBuffer> buffer;
SP<CTexture> texture;
Vector2D offset;
Vector2D size;
@@ -95,6 +97,7 @@ class CWLSurfaceResource {
Vector2D destination;
CBox source;
} viewport;
+ bool rejected = false;
//
void reset() {
@@ -115,9 +118,13 @@ class CWLSurfaceResource {
std::vector<WP<CWLSubsurfaceResource>> subsurfaces;
WP<ISurfaceRole> role;
WP<CViewportResource> viewportResource;
+ WP<CDRMSyncobjSurfaceResource> syncobj; // may not be present
void breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
CRegion accumulateCurrentBufferDamage();
+ void presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync = false);
+ void lockPendingState();
+ void unlockPendingState();
// returns a pair: found surface (null if not found) and surface local coords.
// localCoords param is relative to 0,0 of this surface
@@ -130,7 +137,10 @@ class CWLSurfaceResource {
// tracks whether we should release the buffer
bool bufferReleased = false;
+ int stateLocks = 0;
+
void destroy();
+ void commitPendingState();
void bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
};
diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp
index 10daa15e..4ba23cbe 100644
--- a/src/protocols/core/Output.cpp
+++ b/src/protocols/core/Output.cpp
@@ -21,8 +21,8 @@ CWLOutputResource::CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> pMoni
PROTO::outputs.at(monitor->szName)->destroyResource(this);
});
- resource->sendGeometry(0, 0, monitor->output->phys_width, monitor->output->phys_height, monitor->output->subpixel, monitor->output->make ? monitor->output->make : "null",
- monitor->output->model ? monitor->output->model : "null", monitor->transform);
+ resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(),
+ monitor->output->model.c_str(), monitor->transform);
if (resource->version() >= 4) {
resource->sendName(monitor->szName.c_str());
resource->sendDescription(monitor->szDescription.c_str());
@@ -115,3 +115,9 @@ void CWLOutputProtocol::remove() {
bool CWLOutputProtocol::isDefunct() {
return defunct;
}
+
+void CWLOutputProtocol::sendDone() {
+ for (auto& r : m_vOutputs) {
+ r->resource->sendDone();
+ }
+}
diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp
index 46981635..46e4057b 100644
--- a/src/protocols/core/Output.hpp
+++ b/src/protocols/core/Output.hpp
@@ -26,6 +26,8 @@ class CWLOutputResource {
private:
SP<CWlOutput> resource;
wl_client* pClient = nullptr;
+
+ friend class CWLOutputProtocol;
};
class CWLOutputProtocol : public IWaylandProtocol {
@@ -35,6 +37,7 @@ class CWLOutputProtocol : public IWaylandProtocol {
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
SP<CWLOutputResource> outputResourceFrom(wl_client* client);
+ void sendDone();
WP<CMonitor> monitor;
diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp
index 464a901c..21a47575 100644
--- a/src/protocols/core/Seat.cpp
+++ b/src/protocols/core/Seat.cpp
@@ -254,8 +254,8 @@ void CWLKeyboardResource::sendKeymap(SP<IKeyboard> keyboard) {
int fd;
uint32_t size;
if (keyboard) {
- fd = keyboard->wlr()->keymap_fd;
- size = keyboard->wlr()->keymap_size;
+ fd = keyboard->xkbKeymapFD;
+ size = keyboard->xkbKeymapString.length() + 1;
} else {
fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
if (fd < 0) {
diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp
index 4088949f..75c2134a 100644
--- a/src/protocols/core/Shm.cpp
+++ b/src/protocols/core/Shm.cpp
@@ -41,20 +41,20 @@ CWLSHMBuffer::~CWLSHMBuffer() {
;
}
-eBufferCapability CWLSHMBuffer::caps() {
- return BUFFER_CAPABILITY_DATAPTR;
+Aquamarine::eBufferCapability CWLSHMBuffer::caps() {
+ return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
}
-eBufferType CWLSHMBuffer::type() {
- return BUFFER_TYPE_SHM;
+Aquamarine::eBufferType CWLSHMBuffer::type() {
+ return Aquamarine::eBufferType::BUFFER_TYPE_SHM;
}
bool CWLSHMBuffer::isSynchronous() {
return true;
}
-SSHMAttrs CWLSHMBuffer::shm() {
- SSHMAttrs attrs;
+Aquamarine::SSHMAttrs CWLSHMBuffer::shm() {
+ Aquamarine::SSHMAttrs attrs;
attrs.success = true;
attrs.fd = pool->fd;
attrs.format = FormatUtils::shmToDRM(fmt);
@@ -188,11 +188,18 @@ CWLSHMProtocol::CWLSHMProtocol(const wl_interface* iface, const int& ver, const
void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
if (shmFormats.empty()) {
- size_t len = 0;
- const uint32_t* formats = wlr_renderer_get_shm_texture_formats(g_pCompositor->m_sWLRRenderer, &len);
+ shmFormats.push_back(WL_SHM_FORMAT_ARGB8888);
+ shmFormats.push_back(WL_SHM_FORMAT_XRGB8888);
- for (size_t i = 0; i < len; ++i) {
- shmFormats.push_back(FormatUtils::drmToShm(formats[i]));
+ static const std::array<DRMFormat, 6> supportedShmFourccFormats = {
+ DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010,
+ };
+
+ for (auto& fmt : g_pHyprOpenGL->getDRMFormats()) {
+ if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end())
+ continue;
+
+ shmFormats.push_back(fmt.drmFormat);
}
}
diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp
index 70a8b208..fab325fe 100644
--- a/src/protocols/core/Shm.hpp
+++ b/src/protocols/core/Shm.hpp
@@ -29,16 +29,16 @@ class CSHMPool {
void resize(size_t size);
};
-class CWLSHMBuffer : public IWLBuffer {
+class CWLSHMBuffer : public IHLBuffer {
public:
CWLSHMBuffer(SP<CWLSHMPoolResource> pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt);
virtual ~CWLSHMBuffer();
- virtual eBufferCapability caps();
- virtual eBufferType type();
+ virtual Aquamarine::eBufferCapability caps();
+ virtual Aquamarine::eBufferType type();
virtual void update(const CRegion& damage);
virtual bool isSynchronous();
- virtual SSHMAttrs shm();
+ virtual Aquamarine::SSHMAttrs shm();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp
index 5ed942e1..0217f7e2 100644
--- a/src/protocols/types/Buffer.cpp
+++ b/src/protocols/types/Buffer.cpp
@@ -1,41 +1,10 @@
#include "Buffer.hpp"
-#include "WLBuffer.hpp"
-SDMABUFAttrs IWLBuffer::dmabuf() {
- return SDMABUFAttrs{};
+void IHLBuffer::sendRelease() {
+ resource->sendRelease();
}
-SSHMAttrs IWLBuffer::shm() {
- return SSHMAttrs{};
-}
-
-std::tuple<uint8_t*, uint32_t, size_t> IWLBuffer::beginDataPtr(uint32_t flags) {
- return {nullptr, 0, 0};
-}
-
-void IWLBuffer::endDataPtr() {
- ; // empty
-}
-
-void IWLBuffer::sendRelease() {
- if (!resource || !resource->resource)
- return;
- resource->resource->sendRelease();
-}
-
-void IWLBuffer::lock() {
- locks++;
-}
-
-void IWLBuffer::unlock() {
- locks--;
-
- ASSERT(locks >= 0);
-
- if (locks <= 0)
- sendRelease();
-}
-
-bool IWLBuffer::locked() {
- return locks;
+void IHLBuffer::sendReleaseWithSurface(SP<CWLSurfaceResource> surf) {
+ if (resource && resource->good())
+ resource->sendReleaseWithSurface(surf);
}
diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp
index 9999a4e9..ba8278f3 100644
--- a/src/protocols/types/Buffer.hpp
+++ b/src/protocols/types/Buffer.hpp
@@ -1,75 +1,29 @@
#pragma once
#include "../../defines.hpp"
-#include "../../helpers/signal/Signal.hpp"
#include "../../render/Texture.hpp"
+#include "./WLBuffer.hpp"
-#include <array>
-#include <tuple>
+#include <aquamarine/buffer/Buffer.hpp>
-enum eBufferCapability {
- BUFFER_CAPABILITY_DATAPTR = (1 << 0),
-};
-
-enum eBufferType {
- BUFFER_TYPE_DMABUF = 0,
- BUFFER_TYPE_SHM,
- BUFFER_TYPE_MISC,
-};
-
-class CWLBufferResource;
-
-struct SDMABUFAttrs {
- bool success = false;
- Vector2D size;
- uint32_t format = 0; // fourcc
- uint64_t modifier = 0;
-
- int planes = 1;
- std::array<uint32_t, 4> offsets = {0};
- std::array<uint32_t, 4> strides = {0};
- std::array<int, 4> fds = {-1, -1, -1, -1};
-};
-
-struct SSHMAttrs {
- bool success = false;
- int fd = 0;
- uint32_t format = 0;
- Vector2D size;
- int stride = 0;
- int64_t offset = 0;
-};
-
-class IWLBuffer {
+class IHLBuffer : public Aquamarine::IBuffer {
public:
- virtual ~IWLBuffer() {
+ virtual ~IHLBuffer() {
;
- };
-
- virtual eBufferCapability caps() = 0;
- virtual eBufferType type() = 0;
- virtual void update(const CRegion& damage) = 0;
- virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu
- virtual SDMABUFAttrs dmabuf();
- virtual SSHMAttrs shm();
- virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
- virtual void endDataPtr();
- virtual void sendRelease();
- virtual void lock();
- virtual void unlock();
- virtual bool locked();
-
- Vector2D size;
- bool opaque = false;
-
- SP<CWLBufferResource> resource;
-
- SP<CTexture> texture;
+ }
+ virtual Aquamarine::eBufferCapability caps() = 0;
+ virtual Aquamarine::eBufferType type() = 0;
+ virtual void update(const CRegion& damage) = 0;
+ virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu
+ virtual bool good() = 0;
+ virtual void sendRelease();
+ virtual void sendReleaseWithSurface(SP<CWLSurfaceResource>);
+
+ SP<CTexture> texture;
+ bool opaque = false;
+ SP<CWLBufferResource> resource;
struct {
- CSignal destroy;
- } events;
-
- private:
- int locks = 0;
+ CHyprSignalListener backendRelease;
+ } hlEvents;
};
diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp
index 7c3a9886..63a26c76 100644
--- a/src/protocols/types/DMABuffer.cpp
+++ b/src/protocols/types/DMABuffer.cpp
@@ -3,7 +3,7 @@
#include "../../render/Renderer.hpp"
#include "../../helpers/Format.hpp"
-CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_) : attrs(attrs_) {
+CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_) : attrs(attrs_) {
g_pHyprRenderer->makeEGLCurrent();
listeners.resourceDestroy = events.destroy.registerListener([this](std::any d) {
@@ -31,12 +31,12 @@ CDMABuffer::~CDMABuffer() {
closeFDs();
}
-eBufferCapability CDMABuffer::caps() {
- return BUFFER_CAPABILITY_DATAPTR;
+Aquamarine::eBufferCapability CDMABuffer::caps() {
+ return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
}
-eBufferType CDMABuffer::type() {
- return BUFFER_TYPE_DMABUF;
+Aquamarine::eBufferType CDMABuffer::type() {
+ return Aquamarine::eBufferType::BUFFER_TYPE_DMABUF;
}
void CDMABuffer::update(const CRegion& damage) {
@@ -47,7 +47,7 @@ bool CDMABuffer::isSynchronous() {
return false;
}
-SDMABUFAttrs CDMABuffer::dmabuf() {
+Aquamarine::SDMABUFAttrs CDMABuffer::dmabuf() {
return attrs;
}
diff --git a/src/protocols/types/DMABuffer.hpp b/src/protocols/types/DMABuffer.hpp
index d07840b7..6977df4c 100644
--- a/src/protocols/types/DMABuffer.hpp
+++ b/src/protocols/types/DMABuffer.hpp
@@ -2,16 +2,16 @@
#include "Buffer.hpp"
-class CDMABuffer : public IWLBuffer {
+class CDMABuffer : public IHLBuffer {
public:
- CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_);
+ CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_);
virtual ~CDMABuffer();
- virtual eBufferCapability caps();
- virtual eBufferType type();
+ virtual Aquamarine::eBufferCapability caps();
+ virtual Aquamarine::eBufferType type();
virtual bool isSynchronous();
virtual void update(const CRegion& damage);
- virtual SDMABUFAttrs dmabuf();
+ virtual Aquamarine::SDMABUFAttrs dmabuf();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
bool good();
@@ -21,7 +21,7 @@ class CDMABuffer : public IWLBuffer {
bool success = false;
private:
- SDMABUFAttrs attrs;
+ Aquamarine::SDMABUFAttrs attrs;
struct {
CHyprSignalListener resourceDestroy;
diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp
index e53538cb..d34a867d 100644
--- a/src/protocols/types/WLBuffer.cpp
+++ b/src/protocols/types/WLBuffer.cpp
@@ -1,5 +1,10 @@
#include "WLBuffer.hpp"
#include "Buffer.hpp"
+#include "../core/Compositor.hpp"
+#include "../DRMSyncobj.hpp"
+#include "../../helpers/sync/SyncTimeline.hpp"
+#include "../../Compositor.hpp"
+#include <xf86drm.h>
CWLBufferResource::CWLBufferResource(SP<CWlBuffer> resource_) : resource(resource_) {
if (!good())
@@ -27,6 +32,16 @@ void CWLBufferResource::sendRelease() {
resource->sendRelease();
}
+void CWLBufferResource::sendReleaseWithSurface(SP<CWLSurfaceResource> surf) {
+ sendRelease();
+
+ if (!surf || !surf->syncobj)
+ return;
+
+ if (drmSyncobjTimelineSignal(g_pCompositor->m_iDRMFD, &surf->syncobj->releaseTimeline->timeline->handle, &surf->syncobj->releasePoint, 1))
+ Debug::log(ERR, "sendReleaseWithSurface: drmSyncobjTimelineSignal failed");
+}
+
wl_resource* CWLBufferResource::getResource() {
return resource->resource();
}
diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp
index ac177965..59512128 100644
--- a/src/protocols/types/WLBuffer.hpp
+++ b/src/protocols/types/WLBuffer.hpp
@@ -7,7 +7,8 @@
#include "wayland.hpp"
#include "../../helpers/signal/Signal.hpp"
-class IWLBuffer;
+class IHLBuffer;
+class CWLSurfaceResource;
class CWLBufferResource {
public:
@@ -16,9 +17,10 @@ class CWLBufferResource {
bool good();
void sendRelease();
+ void sendReleaseWithSurface(SP<CWLSurfaceResource>);
wl_resource* getResource();
- WP<IWLBuffer> buffer;
+ WP<IHLBuffer> buffer;
WP<CWLBufferResource> self;
@@ -27,5 +29,5 @@ class CWLBufferResource {
SP<CWlBuffer> resource;
- friend class IWLBuffer;
+ friend class IHLBuffer;
};
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index e127ec2d..b2b046ce 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -9,6 +9,9 @@
#include "../protocols/LayerShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include <xf86drm.h>
+#include <fcntl.h>
+#include <gbm.h>
+#include <filesystem>
inline void loadGLProc(void* pProc, const char* name) {
void* proc = (void*)eglGetProcAddress(name);
@@ -19,24 +22,147 @@ inline void loadGLProc(void* pProc, const char* name) {
*(void**)pProc = proc;
}
-CHyprOpenGLImpl::CHyprOpenGLImpl() {
- RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)),
- "Couldn't unset current EGL!");
+static enum LogLevel eglLogToLevel(EGLint type) {
+ switch (type) {
+ case EGL_DEBUG_MSG_CRITICAL_KHR: return CRIT;
+ case EGL_DEBUG_MSG_ERROR_KHR: return ERR;
+ case EGL_DEBUG_MSG_WARN_KHR: return WARN;
+ case EGL_DEBUG_MSG_INFO_KHR: return LOG;
+ default: return LOG;
+ }
+}
- auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS);
- const std::string EGLEXTENSIONS = (const char*)eglQueryString(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_EXTENSIONS);
+static const char* eglErrorToString(EGLint error) {
+ switch (error) {
+ case EGL_SUCCESS: return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+ case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+ case EGL_BAD_DEVICE_EXT: return "EGL_BAD_DEVICE_EXT";
+ case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+ case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+ case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+ case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+ }
+ return "Unknown";
+}
- RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!");
+static void eglLog(EGLenum error, const char* command, EGLint type, EGLLabelKHR thread, EGLLabelKHR obj, const char* msg) {
+ Debug::log(eglLogToLevel(type), "[EGL] Command {} errored out with {} (0x{}): {}", command, eglErrorToString(error), error, msg);
+}
- m_iDRMFD = g_pCompositor->m_iDRMFD;
+static int openRenderNode(int drmFd) {
+ auto renderName = drmGetRenderDeviceNameFromFd(drmFd);
+ if (!renderName) {
+ // This can happen on split render/display platforms, fallback to
+ // primary node
+ renderName = drmGetPrimaryDeviceNameFromFd(drmFd);
+ if (!renderName) {
+ Debug::log(ERR, "drmGetPrimaryDeviceNameFromFd failed");
+ return -1;
+ }
+ Debug::log(LOG, "DRM dev {} has no render node, falling back to primary", renderName);
+
+ drmVersion* render_version = drmGetVersion(drmFd);
+ if (render_version && render_version->name) {
+ Debug::log(LOG, "DRM dev versionName", render_version->name);
+ if (strcmp(render_version->name, "evdi") == 0) {
+ free(renderName);
+ renderName = (char*)malloc(sizeof(char) * 15);
+ strcpy(renderName, "/dev/dri/card0");
+ }
+ drmFreeVersion(render_version);
+ }
+ }
- m_szExtensions = EXTENSIONS;
+ Debug::log(LOG, "openRenderNode got drm device {}", renderName);
- Debug::log(LOG, "Creating the Hypr OpenGL Renderer!");
- Debug::log(LOG, "Using: {}", (char*)glGetString(GL_VERSION));
- Debug::log(LOG, "Vendor: {}", (char*)glGetString(GL_VENDOR));
- Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER));
- Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions);
+ int renderFD = open(renderName, O_RDWR | O_CLOEXEC);
+ if (renderFD < 0)
+ Debug::log(ERR, "openRenderNode failed to open drm device {}", renderName);
+
+ free(renderName);
+ return renderFD;
+}
+
+void CHyprOpenGLImpl::initEGL(bool gbm) {
+ std::vector<EGLint> attrs;
+ if (m_sExts.KHR_display_reference) {
+ attrs.push_back(EGL_TRACK_REFERENCES_KHR);
+ attrs.push_back(EGL_TRUE);
+ }
+
+ attrs.push_back(EGL_NONE);
+
+ m_pEglDisplay = m_sProc.eglGetPlatformDisplayEXT(gbm ? EGL_PLATFORM_GBM_KHR : EGL_PLATFORM_DEVICE_EXT, gbm ? m_pGbmDevice : nullptr, attrs.data());
+ if (m_pEglDisplay == EGL_NO_DISPLAY)
+ RASSERT(false, "EGL: failed to create a platform display");
+
+ attrs.clear();
+
+ EGLint major, minor;
+ if (eglInitialize(m_pEglDisplay, &major, &minor) == EGL_FALSE)
+ RASSERT(false, "EGL: failed to initialize a platform display");
+
+ const std::string EGLEXTENSIONS = (const char*)eglQueryString(m_pEglDisplay, EGL_EXTENSIONS);
+
+ m_sExts.IMG_context_priority = EGLEXTENSIONS.contains("IMG_context_priority");
+ m_sExts.EXT_create_context_robustness = EGLEXTENSIONS.contains("EXT_create_context_robustness");
+ m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import");
+ m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers");
+
+ if (m_sExts.IMG_context_priority) {
+ Debug::log(LOG, "EGL: IMG_context_priority supported, requesting high");
+ attrs.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
+ attrs.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+ }
+
+ if (m_sExts.EXT_create_context_robustness) {
+ Debug::log(LOG, "EGL: EXT_create_context_robustness supported, requesting lose on reset");
+ attrs.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
+ attrs.push_back(EGL_LOSE_CONTEXT_ON_RESET_EXT);
+ }
+
+ attrs.push_back(EGL_CONTEXT_MAJOR_VERSION);
+ attrs.push_back(3);
+ attrs.push_back(EGL_CONTEXT_MINOR_VERSION);
+ attrs.push_back(2);
+ attrs.push_back(EGL_CONTEXT_OPENGL_DEBUG);
+ attrs.push_back(ISDEBUG ? EGL_TRUE : EGL_FALSE);
+
+ attrs.push_back(EGL_NONE);
+
+ m_pEglContext = eglCreateContext(m_pEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attrs.data());
+ if (m_pEglContext == EGL_NO_CONTEXT)
+ RASSERT(false, "EGL: failed to create a context");
+
+ if (m_sExts.IMG_context_priority) {
+ EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
+ eglQueryContext(m_pEglDisplay, m_pEglContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &priority);
+ if (priority != EGL_CONTEXT_PRIORITY_HIGH_IMG)
+ Debug::log(ERR, "EGL: Failed to obtain a high priority context");
+ else
+ Debug::log(LOG, "EGL: Got a high priority context");
+ }
+
+ eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_pEglContext);
+}
+
+CHyprOpenGLImpl::CHyprOpenGLImpl() {
+ const std::string EGLEXTENSIONS = (const char*)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+
+ Debug::log(LOG, "Supported EGL extensions: ({}) {}", std::count(EGLEXTENSIONS.begin(), EGLEXTENSIONS.end(), ' '), EGLEXTENSIONS);
+
+ m_iDRMFD = g_pCompositor->m_iDRMFD;
+
+ m_sExts.KHR_display_reference = EGLEXTENSIONS.contains("KHR_display_reference");
loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES");
loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR");
@@ -44,10 +170,64 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT");
loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT");
loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES");
+ loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR");
+ loadGLProc(&m_sProc.eglGetPlatformDisplayEXT, "eglGetPlatformDisplayEXT");
+ loadGLProc(&m_sProc.eglCreateSyncKHR, "eglCreateSyncKHR");
+ loadGLProc(&m_sProc.eglDestroySyncKHR, "eglDestroySyncKHR");
+ loadGLProc(&m_sProc.eglDupNativeFenceFDANDROID, "eglDupNativeFenceFDANDROID");
+ loadGLProc(&m_sProc.eglWaitSyncKHR, "eglWaitSyncKHR");
- m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra");
- m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import");
- m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers");
+ RASSERT(m_sProc.eglCreateSyncKHR, "Display driver doesn't support eglCreateSyncKHR");
+ RASSERT(m_sProc.eglDupNativeFenceFDANDROID, "Display driver doesn't support eglDupNativeFenceFDANDROID");
+ RASSERT(m_sProc.eglWaitSyncKHR, "Display driver doesn't support eglWaitSyncKHR");
+
+ if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_enumeration"))
+ loadGLProc(&m_sProc.eglQueryDevicesEXT, "eglQueryDevicesEXT");
+
+ if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_query")) {
+ loadGLProc(&m_sProc.eglQueryDeviceStringEXT, "eglQueryDeviceStringEXT");
+ loadGLProc(&m_sProc.eglQueryDisplayAttribEXT, "eglQueryDisplayAttribEXT");
+ }
+
+ if (EGLEXTENSIONS.contains("EGL_KHR_debug")) {
+ loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR");
+ static const EGLAttrib debugAttrs[] = {
+ EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, EGL_NONE,
+ };
+ m_sProc.eglDebugMessageControlKHR(::eglLog, debugAttrs);
+ }
+
+ RASSERT(eglBindAPI(EGL_OPENGL_ES_API) != EGL_FALSE, "Couldn't bind to EGL's opengl ES API. This means your gpu driver f'd up. This is not a hyprland issue.");
+
+ // if (m_sProc.eglQueryDevicesEXT) {
+ // // TODO:
+ // }
+
+ if (EGLEXTENSIONS.contains("KHR_platform_gbm")) {
+ m_iGBMFD = openRenderNode(m_iDRMFD);
+ if (m_iGBMFD < 0)
+ RASSERT(false, "Couldn't open a gbm fd");
+
+ m_pGbmDevice = gbm_create_device(m_iGBMFD);
+ if (!m_pGbmDevice)
+ RASSERT(false, "Couldn't open a gbm device");
+
+ initEGL(true);
+ } else
+ RASSERT(false, "EGL does not support KHR_platform_gbm, this is an issue with your gpu driver.");
+
+ auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS);
+ RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!");
+
+ m_szExtensions = EXTENSIONS;
+
+ Debug::log(LOG, "Creating the Hypr OpenGL Renderer!");
+ Debug::log(LOG, "Using: {}", (char*)glGetString(GL_VERSION));
+ Debug::log(LOG, "Vendor: {}", (char*)glGetString(GL_VENDOR));
+ Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER));
+ Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions);
+
+ m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra");
RASSERT(m_szExtensions.contains("GL_EXT_texture_format_BGRA8888"), "GL_EXT_texture_format_BGRA8888 support by the GPU driver is required");
@@ -74,7 +254,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast<CMonitor*>(data)); });
- RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
+ RASSERT(eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
m_tGlobalTimer.reset();
}
@@ -86,7 +266,7 @@ std::optional<std::vector<uint64_t>> CHyprOpenGLImpl::getModsForFormat(EGLint fo
return std::nullopt;
EGLint len = 0;
- if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) {
+ if (!m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, 0, nullptr, nullptr, &len)) {
Debug::log(ERR, "EGL: Failed to query mods");
return std::nullopt;
}
@@ -100,7 +280,7 @@ std::optional<std::vector<uint64_t>> CHyprOpenGLImpl::getModsForFormat(EGLint fo
mods.resize(len);
external.resize(len);
- m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len);
+ m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, len, mods.data(), external.data(), &len);
std::vector<uint64_t> result;
bool linearIsExternal = false;
@@ -139,9 +319,9 @@ void CHyprOpenGLImpl::initDRMFormats() {
Debug::log(WARN, "EGL: No mod support");
} else {
EGLint len = 0;
- m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), 0, nullptr, &len);
+ m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, 0, nullptr, &len);
formats.resize(len);
- m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), len, formats.data(), &len);
+ m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, len, formats.data(), &len);
}
if (formats.size() == 0) {
@@ -149,7 +329,7 @@ void CHyprOpenGLImpl::initDRMFormats() {
return;
}
- wlr_log(WLR_DEBUG, "Supported DMA-BUF formats:");
+ Debug::log(LOG, "Supported DMA-BUF formats:");
std::vector<SDRMFormat> dmaFormats;
@@ -170,8 +350,8 @@ void CHyprOpenGLImpl::initDRMFormats() {
mods.push_back(DRM_FORMAT_MOD_INVALID);
dmaFormats.push_back(SDRMFormat{
- .format = fmt,
- .mods = mods,
+ .drmFormat = fmt,
+ .modifiers = mods,
});
std::vector<std::pair<uint64_t, std::string>> modifierData;
@@ -209,7 +389,7 @@ void CHyprOpenGLImpl::initDRMFormats() {
drmFormats = dmaFormats;
}
-EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) {
+EGLImageKHR CHyprOpenGLImpl::createEGLImage(const Aquamarine::SDMABUFAttrs& attrs) {
std::vector<uint32_t> attribs;
attribs.push_back(EGL_WIDTH);
@@ -251,7 +431,7 @@ EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) {
attribs.push_back(EGL_NONE);
- EGLImageKHR image = m_sProc.eglCreateImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data());
+ EGLImageKHR image = m_sProc.eglCreateImageKHR(m_pEglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data());
if (image == EGL_NO_IMAGE_KHR) {
Debug::log(ERR, "EGL: EGLCreateImageKHR failed: {}", eglGetError());
return EGL_NO_IMAGE_KHR;
@@ -342,7 +522,8 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool
}
bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) {
- // passes requiring introspection are the ones that need to render blur.
+ // passes requiring introspection are the ones that need to render blur,
+ // or when we are rendering to a multigpu target
static auto PBLUR = CConfigValue<Hyprlang::INT>("decoration:blur:enabled");
static auto PXRAY = CConfigValue<Hyprlang::INT>("decoration:blur:xray");
@@ -446,7 +627,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) {
return false;
}
-void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRenderbuffer* rb, CFramebuffer* fb) {
+void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP<CRenderbuffer> rb, CFramebuffer* fb) {
m_RenderData.pMonitor = pMonitor;
#ifndef GLES2
@@ -472,12 +653,12 @@ void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRe
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
- wlr_matrix_identity(m_RenderData.monitorProjection.data());
+ matrixIdentity(m_RenderData.monitorProjection.data());
if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) {
const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize;
- wlr_matrix_translate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0);
- wlr_matrix_transform(m_RenderData.monitorProjection.data(), pMonitor->transform);
- wlr_matrix_translate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0);
+ matrixTranslate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0);
+ matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(pMonitor->transform));
+ matrixTranslate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0);
}
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
@@ -545,10 +726,10 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu
m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
- m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
- m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
- m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
- m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
+ m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
+ m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
+ m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
+ m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
}
if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty())
@@ -597,7 +778,7 @@ void CHyprOpenGLImpl::end() {
TRACY_GPU_ZONE("RenderEnd");
- // end the render, copy the data to the WLR framebuffer
+ // end the render, copy the data to the main framebuffer
if (m_bOffloadedFramebuffer) {
m_RenderData.damage = m_RenderData.finalDamage;
m_bEndFrame = true;
@@ -915,11 +1096,8 @@ void CHyprOpenGLImpl::scissor(const CBox* pBox, bool transform) {
CBox newBox = *pBox;
if (transform) {
- int w, h;
- wlr_output_transformed_resolution(m_RenderData.pMonitor->output, &w, &h);
-
- const auto TR = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform));
- newBox.transform(TR, w, h);
+ const auto TR = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform));
+ newBox.transform(TR, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y);
}
glScissor(newBox.x, newBox.y, newBox.width, newBox.height);
@@ -1008,18 +1186,18 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
box = &newBox;
float matrix[9];
- projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
- m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here
+ projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
+ m_RenderData.monitorProjection.data());
float glMatrix[9];
- wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
+ matrixMultiply(glMatrix, m_RenderData.projection, matrix);
glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix);
#else
- wlr_matrix_transpose(glMatrix, glMatrix);
+ matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix);
#endif
@@ -1027,7 +1205,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r * col.a, col.g * col.a, col.b * col.a, col.a);
CBox transformedBox = *box;
- transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
+ transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
m_RenderData.pMonitor->vecTransformedSize.y);
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
@@ -1072,16 +1250,17 @@ void CHyprOpenGLImpl::renderTexture(SP<CTexture> tex, CBox* pBox, float alpha, i
scissor((CBox*)nullptr);
}
-void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) {
+void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV,
+ SP<CSyncTimeline> waitTimeline, uint64_t waitPoint) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
- renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true);
+ renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint);
scissor((CBox*)nullptr);
}
void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV,
- bool allowDim) {
+ bool allowDim, SP<CSyncTimeline> waitTimeline, uint64_t waitPoint) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!");
@@ -1099,12 +1278,19 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
static auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
// get transform
- const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
+ const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
float matrix[9];
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
float glMatrix[9];
- wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
+ matrixMultiply(glMatrix, m_RenderData.projection, matrix);
+
+ if (waitTimeline != nullptr) {
+ if (!waitForTimelinePoint(waitTimeline, waitPoint)) {
+ Debug::log(ERR, "renderTextureInternalWithDamage: failed to wait for explicit sync point {}", waitPoint);
+ return;
+ }
+ }
CShader* shader = nullptr;
@@ -1151,7 +1337,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
#ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
#else
- wlr_matrix_transpose(glMatrix, glMatrix);
+ matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1i(shader->tex, 0);
@@ -1187,7 +1373,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
}
CBox transformedBox = newBox;
- transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
+ transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
m_RenderData.pMonitor->vecTransformedSize.y);
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
@@ -1262,12 +1448,12 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) {
m_RenderData.renderModif.applyToBox(newBox);
// get transform
- const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
+ const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
float matrix[9];
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
float glMatrix[9];
- wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
+ matrixMultiply(glMatrix, m_RenderData.projection, matrix);
CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA;
@@ -1279,7 +1465,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) {
#ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
#else
- wlr_matrix_transpose(glMatrix, glMatrix);
+ matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1i(shader->tex, 0);
@@ -1316,12 +1502,12 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuf
m_RenderData.renderModif.applyToBox(newBox);
// get transform
- const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
+ const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
float matrix[9];
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
float glMatrix[9];
- wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
+ matrixMultiply(glMatrix, m_RenderData.projection, matrix);
CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE;
@@ -1330,7 +1516,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuf
#ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
#else
- wlr_matrix_transpose(glMatrix, glMatrix);
+ matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1i(shader->tex, 0);
@@ -1374,13 +1560,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glDisable(GL_STENCIL_TEST);
// get transforms for the full monitor
- const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform));
+ const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform));
float matrix[9];
CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
projectBox(matrix, MONITORBOX, TRANSFORM, 0, m_RenderData.monitorProjection.data());
float glMatrix[9];
- wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
+ matrixMultiply(glMatrix, m_RenderData.projection, matrix);
// get the config settings
static auto PBLURSIZE = CConfigValue<Hyprlang::INT>("decoration:blur:size");
@@ -1390,9 +1576,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
// prep damage
CRegion damage{*originalDamage};
- wlr_region_transform(damage.pixman(), damage.pixman(), wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x,
- m_RenderData.pMonitor->vecTransformedSize.y);
- wlr_region_expand(damage.pixman(), damage.pixman(), *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES));
+ damage.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
+ m_RenderData.pMonitor->vecTransformedSize.y);
+ damage.expand(*PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES));
// helper
const auto PMIRRORFB = &m_RenderData.pCurrentMonData->mirrorFB;
@@ -1419,7 +1605,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix);
#else
- wlr_matrix_transpose(glMatrix, glMatrix);
+ matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST);
@@ -1464,7 +1650,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
#ifndef GLES2
glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix);
#else
- wlr_matrix_transpose(glMatrix, glMatrix);
+ matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a
@@ -1511,13 +1697,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
// and draw
for (int i = 1; i <= *PBLURPASSES; ++i) {
- wlr_region_scale(tempDamage.pixman(), damage.pixman(), 1.f / (1 << i));
+ tempDamage = damage.copy().scale(1.f / (1 << i));
drawPass(&m_RenderData.pCurrentMonData->m_shBLUR1, &tempDamage); // down
}
for (int i = *PBLURPASSES - 1; i >= 0; --i) {
- wlr_region_scale(tempDamage.pixman(), damage.pixman(), 1.f / (1 << i)); // when upsampling we make the region twice as big
- drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up
+ tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big
+ drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up
}
// finalize the image
@@ -1541,7 +1727,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix);
#else
- wlr_matrix_transpose(glMatrix, glMatrix);
+ matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE);
@@ -1679,7 +1865,8 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
const auto POUTFB = blurMainFramebufferWithDamage(1, &fakeDamage);
// render onto blurFB
- m_RenderData.pCurrentMonData->blurFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->drmFormat);
+ m_RenderData.pCurrentMonData->blurFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y,
+ m_RenderData.pMonitor->output->state->state().drmFormat);
m_RenderData.pCurrentMonData->blurFB.bind();
clear(CColor(0, 0, 0, 0));
@@ -1773,7 +1960,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP<CTexture> tex, CBox* pBox, float
inverseOpaque = {0, 0, pBox->width, pBox->height};
}
- wlr_region_scale(inverseOpaque.pixman(), inverseOpaque.pixman(), m_RenderData.pMonitor->scale);
+ inverseOpaque.scale(m_RenderData.pMonitor->scale);
// vvv TODO: layered blur fbs?
const bool USENEWOPTIMIZE = shouldUseNewBlurOptimizations(m_pCurrentLayer, m_pCurrentWindow.lock()) && !blockBlurOptimization;
@@ -1872,11 +2059,11 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
round += round == 0 ? 0 : scaledBorderSize;
float matrix[9];
- projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
- m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here
+ projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
+ m_RenderData.monitorProjection.data());
float glMatrix[9];
- wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
+ matrixMultiply(glMatrix, m_RenderData.projection, matrix);
const auto BLEND = m_bBlend;
blend(true);
@@ -1886,7 +2073,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix);
#else
- wlr_matrix_transpose(glMatrix, glMatrix);
+ matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
#endif
@@ -1898,7 +2085,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a);
CBox transformedBox = *box;
- transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
+ transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
m_RenderData.pMonitor->vecTransformedSize.y);
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
@@ -1949,14 +2136,14 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr
// we need to "damage" the entire monitor
// so that we render the entire window
- // this is temporary, doesnt mess with the actual wlr damage
+ // this is temporary, doesnt mess with the actual damage
CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y};
g_pHyprRenderer->makeEGLCurrent();
pFramebuffer->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
- pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
+ pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat);
g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, pFramebuffer);
@@ -2000,7 +2187,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) {
// we need to "damage" the entire monitor
// so that we render the entire window
- // this is temporary, doesnt mess with the actual wlr damage
+ // this is temporary, doesnt mess with the actual damage
CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y};
PHLWINDOWREF ref{pWindow};
@@ -2009,7 +2196,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) {
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[ref];
- PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
+ PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat);
g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
@@ -2049,14 +2236,14 @@ void CHyprOpenGLImpl::makeLayerSnapshot(PHLLS pLayer) {
// we need to "damage" the entire monitor
// so that we render the entire window
- // this is temporary, doesnt mess with the actual wlr damage
+ // this is temporary, doesnt mess with the actual damage
CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y};
g_pHyprRenderer->makeEGLCurrent();
const auto PFRAMEBUFFER = &m_mLayerFramebuffers[pLayer];
- PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
+ PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat);
g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
@@ -2178,11 +2365,11 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
const auto col = color;
float matrix[9];
- projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
- m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here
+ projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
+ m_RenderData.monitorProjection.data());
float glMatrix[9];
- wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
+ matrixMultiply(glMatrix, m_RenderData.projection, matrix);
glEnable(GL_BLEND);
@@ -2191,7 +2378,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix);
#else
- wlr_matrix_transpose(glMatrix, glMatrix);
+ matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a);
@@ -2238,7 +2425,8 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
void CHyprOpenGLImpl::saveBufferForMirror(CBox* box) {
if (!m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated())
- m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->drmFormat);
+ m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y,
+ m_RenderData.pMonitor->output->state->state().drmFormat);
m_RenderData.pCurrentMonData->monitorMirrorFB.bind();
@@ -2270,11 +2458,11 @@ void CHyprOpenGLImpl::renderMirrored() {
return;
// replace monitor projection to undo the mirrored monitor's projection
- wlr_matrix_identity(monitor->projMatrix.data());
- wlr_matrix_translate(monitor->projMatrix.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0);
- wlr_matrix_transform(monitor->projMatrix.data(), monitor->transform);
- wlr_matrix_transform(monitor->projMatrix.data(), wlr_output_transform_invert(mirrored->transform));
- wlr_matrix_translate(monitor->projMatrix.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0);
+ matrixIdentity(m_RenderData.monitorProjection.data());
+ matrixTranslate(m_RenderData.monitorProjection.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0);
+ matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(monitor->transform));
+ matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(invertTransform(mirrored->transform)));
+ matrixTranslate(m_RenderData.monitorProjection.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0);
// clear stuff outside of mirrored area (e.g. when changing to mirrored)
clear(CColor(0, 0, 0, 0));
@@ -2282,7 +2470,7 @@ void CHyprOpenGLImpl::renderMirrored() {
renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false);
// reset matrix for further drawing
- monitor->updateMatrix();
+ m_RenderData.monitorProjection = monitor->projMatrix;
}
void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) {
@@ -2338,7 +2526,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
const auto PFB = &m_mMonitorBGFBs[pMonitor];
PFB->release();
- PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
+ PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
Debug::log(LOG, "Allocated texture for BGTex");
// TODO: use relative paths to the installation
@@ -2474,6 +2662,9 @@ void CHyprOpenGLImpl::clearWithTex() {
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
g_pHyprRenderer->makeEGLCurrent();
+ if (!g_pHyprOpenGL)
+ return;
+
auto RESIT = g_pHyprOpenGL->m_mMonitorRenderResources.find(pMonitor);
if (RESIT != g_pHyprOpenGL->m_mMonitorRenderResources.end()) {
RESIT->second.mirrorFB.release();
@@ -2500,8 +2691,8 @@ void CHyprOpenGLImpl::saveMatrix() {
}
void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) {
- wlr_matrix_scale(m_RenderData.projection, scale, scale);
- wlr_matrix_translate(m_RenderData.projection, translate.x, translate.y);
+ matrixScale(m_RenderData.projection, scale, scale);
+ matrixTranslate(m_RenderData.projection, translate.x, translate.y);
}
void CHyprOpenGLImpl::restoreMatrix() {
@@ -2533,27 +2724,61 @@ void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) {
}
uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) {
- GLint glf = -1, glt = -1, as = 0;
- /*glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &glf);
- glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &glt);
- glGetIntegerv(GL_ALPHA_BITS, &as);*/
+ return pMonitor->output->state->state().drmFormat;
+}
- if (glf == 0 || glt == 0) {
- glf = FormatUtils::drmFormatToGL(pMonitor->drmFormat);
- glt = FormatUtils::glFormatToType(glf);
- }
+std::vector<SDRMFormat> CHyprOpenGLImpl::getDRMFormats() {
+ return drmFormats;
+}
+
+SP<CEGLSync> CHyprOpenGLImpl::createEGLSync(int fenceFD) {
+ std::vector<EGLint> attribs;
+ int dupFd = -1;
+ if (fenceFD > 0) {
+ int dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0);
+ if (dupFd < 0) {
+ Debug::log(ERR, "createEGLSync: dup failed");
+ return nullptr;
+ }
- if (const auto FMT = FormatUtils::getPixelFormatFromGL(glf, glt, as > 0); FMT)
- return FMT->drmFormat;
+ attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID);
+ attribs.push_back(dupFd);
+ attribs.push_back(EGL_NONE);
+ }
- if (m_sExts.EXT_read_format_bgra)
- return DRM_FORMAT_XRGB8888;
+ EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data());
+ if (sync == EGL_NO_SYNC_KHR) {
+ Debug::log(ERR, "eglCreateSyncKHR failed");
+ if (dupFd >= 0)
+ close(dupFd);
+ return nullptr;
+ }
- return DRM_FORMAT_XBGR8888;
+ auto eglsync = SP<CEGLSync>(new CEGLSync);
+ eglsync->sync = sync;
+ return eglsync;
}
-std::vector<SDRMFormat> CHyprOpenGLImpl::getDRMFormats() {
- return drmFormats;
+bool CHyprOpenGLImpl::waitForTimelinePoint(SP<CSyncTimeline> timeline, uint64_t point) {
+ int fd = timeline->exportAsSyncFileFD(point);
+ if (fd < 0) {
+ Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline");
+ return false;
+ }
+
+ auto sync = g_pHyprOpenGL->createEGLSync(fd);
+ close(fd);
+ if (!sync) {
+ Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline");
+ return false;
+ }
+
+ if (!sync->wait()) {
+ Debug::log(ERR, "waitForTimelinePoint: failed to wait on an eglsync from explicit timeline");
+ return false;
+ }
+
+ return true;
}
void SRenderModifData::applyToBox(CBox& box) {
@@ -2616,3 +2841,35 @@ float SRenderModifData::combinedScale() {
}
return scale;
}
+
+CEGLSync::~CEGLSync() {
+ if (sync == EGL_NO_SYNC_KHR)
+ return;
+
+ if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE)
+ Debug::log(ERR, "eglDestroySyncKHR failed");
+}
+
+int CEGLSync::dupFenceFD() {
+ if (sync == EGL_NO_SYNC_KHR)
+ return -1;
+
+ int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync);
+ if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ Debug::log(ERR, "eglDupNativeFenceFDANDROID failed");
+ return -1;
+ }
+
+ return fd;
+}
+
+bool CEGLSync::wait() {
+ if (sync == EGL_NO_SYNC_KHR)
+ return false;
+
+ if (g_pHyprOpenGL->m_sProc.eglWaitSyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync, 0) != EGL_TRUE) {
+ Debug::log(ERR, "eglWaitSyncKHR failed");
+ return false;
+ }
+ return true;
+}
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 814b80fe..712b87f3 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -6,6 +6,8 @@
#include "../helpers/Timer.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/Format.hpp"
+#include "../helpers/sync/SyncTimeline.hpp"
+#include <cstdint>
#include <list>
#include <unordered_map>
#include <map>
@@ -18,10 +20,14 @@
#include "Transformer.hpp"
#include "Renderbuffer.hpp"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
#include <GLES2/gl2ext.h>
+#include <aquamarine/buffer/Buffer.hpp>
#include "../debug/TracyDefines.hpp"
+struct gbm_device;
class CHyprRenderer;
inline const float fullVerts[] = {
@@ -119,6 +125,21 @@ struct SCurrentRenderData {
float discardOpacity = 0.f;
};
+class CEGLSync {
+ public:
+ ~CEGLSync();
+
+ EGLSyncKHR sync = nullptr;
+
+ int dupFenceFD();
+ bool wait();
+
+ private:
+ CEGLSync() = default;
+
+ friend class CHyprOpenGLImpl;
+};
+
class CGradientValueData;
class CHyprOpenGLImpl {
@@ -126,14 +147,15 @@ class CHyprOpenGLImpl {
CHyprOpenGLImpl();
void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {});
- void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr);
+ void beginSimple(CMonitor*, const CRegion& damage, SP<CRenderbuffer> rb = nullptr, CFramebuffer* fb = nullptr);
void end();
void renderRect(CBox*, const CColor&, int round = 0);
void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false);
void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0);
void renderTexture(SP<CTexture>, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
- void renderTextureWithDamage(SP<CTexture>, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
+ void renderTextureWithDamage(SP<CTexture>, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false,
+ SP<CSyncTimeline> waitTimeline = nullptr, uint64_t waitPoint = 0);
void renderTextureWithBlur(SP<CTexture>, CBox*, float a, SP<CWLSurfaceResource> pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f);
void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0);
void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */);
@@ -182,12 +204,19 @@ class CHyprOpenGLImpl {
uint32_t getPreferredReadFormat(CMonitor* pMonitor);
std::vector<SDRMFormat> getDRMFormats();
- EGLImageKHR createEGLImage(const SDMABUFAttrs& attrs);
+ EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
+ SP<CEGLSync> createEGLSync(int fenceFD);
+ bool waitForTimelinePoint(SP<CSyncTimeline> timeline, uint64_t point);
SCurrentRenderData m_RenderData;
GLint m_iCurrentOutputFb = 0;
+ int m_iGBMFD = -1;
+ gbm_device* m_pGbmDevice = nullptr;
+ EGLContext m_pEglContext = nullptr;
+ EGLDisplay m_pEglDisplay = nullptr;
+
bool m_bReloadScreenShader = true; // at launch it can be set
PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window
@@ -205,12 +234,24 @@ class CHyprOpenGLImpl {
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr;
+ PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr;
+ PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr;
+ PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr;
+ PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr;
+ PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
+ PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
+ PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr;
+ PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr;
} m_sProc;
struct {
bool EXT_read_format_bgra = false;
bool EXT_image_dma_buf_import = false;
bool EXT_image_dma_buf_import_modifiers = false;
+ bool KHR_display_reference = false;
+ bool IMG_context_priority = false;
+ bool EXT_create_context_robustness = false;
} m_sExts;
private:
@@ -220,7 +261,7 @@ class CHyprOpenGLImpl {
std::vector<SDRMFormat> drmFormats;
bool m_bHasModifiers = false;
- int m_iDRMFD;
+ int m_iDRMFD = -1;
std::string m_szExtensions;
bool m_bFakeFrame = false;
@@ -238,6 +279,7 @@ class CHyprOpenGLImpl {
void createBGTextureForMonitor(CMonitor*);
void initShaders();
void initDRMFormats();
+ void initEGL(bool gbm);
//
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
@@ -246,7 +288,7 @@ class CHyprOpenGLImpl {
CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage);
void renderTextureInternalWithDamage(SP<CTexture>, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false,
- bool allowCustomUV = false, bool allowDim = false);
+ bool allowCustomUV = false, bool allowDim = false, SP<CSyncTimeline> = nullptr, uint64_t waitPoint = 0);
void renderTexturePrimitive(SP<CTexture> tex, CBox* pBox);
void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size);
diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp
index 3f591d13..58ed88d6 100644
--- a/src/render/Renderbuffer.cpp
+++ b/src/render/Renderbuffer.cpp
@@ -2,6 +2,8 @@
#include "OpenGL.hpp"
#include "../Compositor.hpp"
#include "../protocols/types/Buffer.hpp"
+#include <hyprutils/signal/Listener.hpp>
+#include <hyprutils/signal/Signal.hpp>
#include <dlfcn.h>
@@ -15,33 +17,17 @@ CRenderbuffer::~CRenderbuffer() {
m_sFramebuffer.release();
glDeleteRenderbuffers(1, &m_iRBO);
- g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage);
+ g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_iImage);
}
-CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer), m_uDrmFormat(format) {
-
- // EVIL, but we can't include a hidden header because nixos is fucking special
- static EGLImageKHR (*PWLREGLCREATEIMAGEFROMDMABUF)(wlr_egl*, wlr_dmabuf_attributes*, bool*);
- static bool symbolFound = false;
- if (!symbolFound) {
- PWLREGLCREATEIMAGEFROMDMABUF = reinterpret_cast<EGLImageKHR (*)(wlr_egl*, wlr_dmabuf_attributes*, bool*)>(dlsym(RTLD_DEFAULT, "wlr_egl_create_image_from_dmabuf"));
-
- symbolFound = true;
-
- RASSERT(PWLREGLCREATEIMAGEFROMDMABUF, "wlr_egl_create_image_from_dmabuf was not found in wlroots!");
+CRenderbuffer::CRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) {
+ auto dma = buffer->dmabuf();
- Debug::log(LOG, "CRenderbuffer: wlr_egl_create_image_from_dmabuf found at {:x}", (uintptr_t)PWLREGLCREATEIMAGEFROMDMABUF);
+ m_iImage = g_pHyprOpenGL->createEGLImage(dma);
+ if (m_iImage == EGL_NO_IMAGE_KHR) {
+ Debug::log(ERR, "rb: createEGLImage failed");
+ return;
}
- // end evil hack
-
- struct wlr_dmabuf_attributes dmabuf = {0};
- if (!wlr_buffer_get_dmabuf(buffer, &dmabuf))
- throw std::runtime_error("wlr_buffer_get_dmabuf failed");
-
- bool externalOnly;
- m_iImage = PWLREGLCREATEIMAGEFROMDMABUF(g_pCompositor->m_sWLREGL, &dmabuf, &externalOnly);
- if (m_iImage == EGL_NO_IMAGE_KHR)
- throw std::runtime_error("wlr_egl_create_image_from_dmabuf failed");
glGenRenderbuffers(1, &m_iRBO);
glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO);
@@ -49,39 +35,24 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &m_sFramebuffer.m_iFb);
- m_sFramebuffer.m_vSize = {buffer->width, buffer->height};
+ m_sFramebuffer.m_vSize = buffer->size;
m_sFramebuffer.bind();
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO);
- if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
- throw std::runtime_error("rbo: glCheckFramebufferStatus failed");
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ Debug::log(ERR, "rbo: glCheckFramebufferStatus failed");
+ return;
+ }
glBindFramebuffer(GL_FRAMEBUFFER, 0);
- hyprListener_destroyBuffer.initCallback(&buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer");
-}
-
-CRenderbuffer::CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) {
- auto dma = buffer->dmabuf();
-
- m_iImage = g_pHyprOpenGL->createEGLImage(dma);
- if (m_iImage == EGL_NO_IMAGE_KHR)
- throw std::runtime_error("createEGLImage failed");
-
- glGenRenderbuffers(1, &m_iRBO);
- glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO);
- g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage);
- glBindRenderbuffer(GL_RENDERBUFFER, 0);
-
- glGenFramebuffers(1, &m_sFramebuffer.m_iFb);
- m_sFramebuffer.m_vSize = buffer->size;
- m_sFramebuffer.bind();
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO);
+ listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) { g_pHyprRenderer->onRenderbufferDestroy(this); });
- if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
- throw std::runtime_error("rbo: glCheckFramebufferStatus failed");
+ m_bGood = true;
+}
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+bool CRenderbuffer::good() {
+ return m_bGood;
}
void CRenderbuffer::bind() {
diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp
index ed7050c5..e6bfa909 100644
--- a/src/render/Renderbuffer.hpp
+++ b/src/render/Renderbuffer.hpp
@@ -1,30 +1,35 @@
#pragma once
+#include "../helpers/signal/Signal.hpp"
+#include "../helpers/memory/Memory.hpp"
+#include "../helpers/WLListener.hpp"
#include "Framebuffer.hpp"
+#include <aquamarine/buffer/Buffer.hpp>
class CMonitor;
-class IWLBuffer;
class CRenderbuffer {
public:
- CRenderbuffer(wlr_buffer* buffer, uint32_t format);
- CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format);
+ CRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
~CRenderbuffer();
- void bind();
- void bindFB();
- void unbind();
- CFramebuffer* getFB();
- uint32_t getFormat();
+ bool good();
+ void bind();
+ void bindFB();
+ void unbind();
+ CFramebuffer* getFB();
+ uint32_t getFormat();
- wlr_buffer* m_pWlrBuffer = nullptr;
- WP<IWLBuffer> m_pHLBuffer = {};
-
- DYNLISTENER(destroyBuffer);
+ WP<Aquamarine::IBuffer> m_pHLBuffer;
private:
- EGLImageKHR m_iImage = 0;
+ void* m_iImage = nullptr;
GLuint m_iRBO = 0;
CFramebuffer m_sFramebuffer;
uint32_t m_uDrmFormat = 0;
+ bool m_bGood = false;
+
+ struct {
+ CHyprSignalListener destroyBuffer;
+ } listeners;
}; \ No newline at end of file
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index a7f3c941..82dfc887 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -2,6 +2,8 @@
#include "../Compositor.hpp"
#include "../helpers/math/Math.hpp"
#include <algorithm>
+#include <aquamarine/output/Output.hpp>
+#include <cstring>
#include "../config/ConfigValue.hpp"
#include "../managers/CursorManager.hpp"
#include "../managers/PointerManager.hpp"
@@ -13,6 +15,10 @@
#include "../protocols/PresentationTime.hpp"
#include "../protocols/core/DataDevice.hpp"
#include "../protocols/core/Compositor.hpp"
+#include "../protocols/DRMSyncobj.hpp"
+#include "../protocols/LinuxDMABUF.hpp"
+#include "../helpers/sync/SyncTimeline.hpp"
+#include "debug/Log.hpp"
extern "C" {
#include <xf86drm.h>
@@ -25,11 +31,11 @@ static int cursorTicker(void* data) {
}
CHyprRenderer::CHyprRenderer() {
- if (g_pCompositor->m_sWLRSession) {
- wlr_device* dev;
- wl_list_for_each(dev, &g_pCompositor->m_sWLRSession->devices, link) {
- const auto DRMV = drmGetVersion(dev->fd);
-
+ if (g_pCompositor->m_pAqBackend->hasSession()) {
+ for (auto& dev : g_pCompositor->m_pAqBackend->session->sessionDevices) {
+ const auto DRMV = drmGetVersion(dev->fd);
+ if (!DRMV)
+ continue;
std::string name = std::string{DRMV->name, DRMV->name_len};
std::transform(name.begin(), name.end(), name.begin(), tolower);
@@ -42,7 +48,7 @@ CHyprRenderer::CHyprRenderer() {
drmFreeVersion(DRMV);
}
} else {
- Debug::log(LOG, "m_sWLRSession is null, omitting full DRM node checks");
+ Debug::log(LOG, "Aq backend has no session, omitting full DRM node checks");
const auto DRMV = drmGetVersion(g_pCompositor->m_iDRMFD);
@@ -108,6 +114,14 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
if (!TEXTURE->m_iTexID)
return;
+ // explicit sync: wait for the timeline, if any
+ if (surface->syncobj && surface->syncobj->acquireTimeline) {
+ if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->acquireTimeline->timeline, surface->syncobj->acquirePoint)) {
+ Debug::log(ERR, "Renderer: failed to wait for explicit timeline");
+ return;
+ }
+ }
+
TRACY_GPU_ZONE("RenderSurface");
double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y;
@@ -167,12 +181,10 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
if (windowBox.width <= 1 || windowBox.height <= 1) {
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
- surface->frame(RDATA->when);
- auto FEEDBACK = makeShared<CQueuedPresentationData>(surface);
- FEEDBACK->attachMonitor(RDATA->pMonitor);
- FEEDBACK->discarded();
- PROTO::presentation->queueData(FEEDBACK);
+ Debug::log(TRACE, "presentFeedback for invisible surface");
+ surface->presentFeedback(RDATA->when, RDATA->pMonitor);
}
+
return; // invisible
}
@@ -225,11 +237,8 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
}
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
- surface->frame(RDATA->when);
- auto FEEDBACK = makeShared<CQueuedPresentationData>(surface);
- FEEDBACK->attachMonitor(RDATA->pMonitor);
- FEEDBACK->presented();
- PROTO::presentation->queueData(FEEDBACK);
+ Debug::log(TRACE, "presentFeedback for visible surface");
+ surface->presentFeedback(RDATA->when, RDATA->pMonitor);
}
g_pHyprOpenGL->blend(true);
@@ -1079,53 +1088,6 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
}
}
-bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
- return false; // FIXME: fix when we move to new lib for backend.
-
- // if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked)
- // return false; // do not DS if this monitor is being mirrored. Will break the functionality.
-
- // if (!wlr_output_is_direct_scanout_allowed(pMonitor->output))
- // return false;
-
- // const auto PCANDIDATE = pMonitor->solitaryClient.lock();
-
- // if (!PCANDIDATE)
- // return false;
-
- // const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
-
- // if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
- // return false;
-
- // // finally, we should be GTG.
- // wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base);
-
- // if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr()))
- // return false;
-
- // timespec now;
- // clock_gettime(CLOCK_MONOTONIC, &now);
- // PSURFACE->frame(&now);
- // auto FEEDBACK = makeShared<CQueuedPresentationData>(PSURFACE);
- // FEEDBACK->attachMonitor(pMonitor);
- // FEEDBACK->presented();
- // FEEDBACK->setPresentationType(true);
- // PROTO::presentation->queueData(FEEDBACK);
-
- // if (pMonitor->state.commit()) {
- // if (m_pLastScanout.expired()) {
- // m_pLastScanout = PCANDIDATE;
- // Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
- // }
- // } else {
- // m_pLastScanout.reset();
- // return false;
- // }
-
- // return true;
-}
-
void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now();
static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now();
@@ -1177,7 +1139,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
pMonitor->framesToSkip -= 1;
if (!pMonitor->noFrameSchedule)
- g_pCompositor->scheduleFrameForMonitor(pMonitor);
+ g_pCompositor->scheduleFrameForMonitor(pMonitor, Aquamarine::IOutput::AQ_SCHEDULE_RENDER_MONITOR);
else
Debug::log(LOG, "NoFrameSchedule hit for {}.", pMonitor->szName);
@@ -1205,6 +1167,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
}
+ if (!pMonitor->output->needsFrame && pMonitor->forceFullFrames == 0)
+ return;
+
// tearing and DS first
bool shouldTear = false;
if (pMonitor->tearingState.nextRenderTorn) {
@@ -1230,11 +1195,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
}
if (!*PNODIRECTSCANOUT && !shouldTear) {
- if (attemptDirectScanout(pMonitor)) {
+ if (pMonitor->attemptDirectScanout()) {
return;
- } else if (!m_pLastScanout.expired()) {
+ } else if (!pMonitor->lastScanout.expired()) {
Debug::log(LOG, "Left a direct scanout.");
- m_pLastScanout.reset();
+ pMonitor->lastScanout.reset();
}
}
@@ -1249,7 +1214,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
clock_gettime(CLOCK_MONOTONIC, &now);
// check the damage
- bool hasChanged = pMonitor->output->needs_frame || pMonitor->damage.hasChanged();
+ bool hasChanged = pMonitor->output->needsFrame || pMonitor->damage.hasChanged();
if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0)
return;
@@ -1295,7 +1260,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
CRegion damage, finalDamage;
if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) {
Debug::log(ERR, "renderer: couldn't beginRender()!");
- pMonitor->state.clear();
return;
}
@@ -1316,11 +1280,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
*PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think.
// now, prep the damage, get the extended damage region
- wlr_region_expand(damage.pixman(), damage.pixman(), BLURRADIUS); // expand for proper blurring
+ damage.expand(BLURRADIUS); // expand for proper blurring
finalDamage = damage;
- wlr_region_expand(damage.pixman(), damage.pixman(), BLURRADIUS); // expand for proper blurring 2
+ damage.expand(BLURRADIUS); // expand for proper blurring
} else
finalDamage = damage;
}
@@ -1396,10 +1360,10 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
TRACY_GPU_COLLECT;
if (!pMonitor->mirrors.empty()) {
- CRegion frameDamage{};
+ CRegion frameDamage{finalDamage};
- const auto TRANSFORM = wlr_output_transform_invert(pMonitor->output->transform);
- wlr_region_transform(frameDamage.pixman(), finalDamage.pixman(), TRANSFORM, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
+ const auto TRANSFORM = invertTransform(pMonitor->transform);
+ frameDamage.transform(wlTransformToHyprutils(TRANSFORM), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y);
if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR)
frameDamage.add(0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
@@ -1414,18 +1378,16 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
EMIT_HOOK_EVENT("render", RENDER_POST);
- pMonitor->state.wlr()->tearing_page_flip = shouldTear;
+ pMonitor->output->state->setPresentationMode(shouldTear ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
+ Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
- if (!pMonitor->state.commit()) {
- pMonitor->damage.damageEntire();
- return;
- }
+ commitPendingAndDoExplicitSync(pMonitor);
if (shouldTear)
pMonitor->tearingState.busy = true;
if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame)
- g_pCompositor->scheduleFrameForMonitor(pMonitor);
+ g_pCompositor->scheduleFrameForMonitor(pMonitor, Aquamarine::IOutput::AQ_SCHEDULE_RENDER_MONITOR);
pMonitor->pendingFrame = false;
@@ -1442,6 +1404,63 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
}
}
+bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) {
+ static auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("experimental:explicit_sync");
+
+ // apply timelines for explicit sync
+ pMonitor->output->state->resetExplicitFences();
+
+ bool anyExplicit = !explicitPresented.empty();
+ if (anyExplicit) {
+ Debug::log(TRACE, "Explicit sync presented begin");
+ auto inFence = pMonitor->inTimeline->exportAsSyncFileFD(pMonitor->lastWaitPoint);
+ if (inFence < 0)
+ Debug::log(ERR, "Export lastWaitPoint {} as sync explicitInFence failed", pMonitor->lastWaitPoint);
+
+ pMonitor->output->state->setExplicitInFence(inFence);
+
+ for (auto& e : explicitPresented) {
+ Debug::log(TRACE, "Explicit sync presented releasePoint {}", e->syncobj && e->syncobj->releaseTimeline ? e->syncobj->releasePoint : -1);
+ if (!e->syncobj || !e->syncobj->releaseTimeline)
+ continue;
+ e->syncobj->releaseTimeline->timeline->transfer(pMonitor->outTimeline, pMonitor->commitSeq, e->syncobj->releasePoint);
+ }
+
+ explicitPresented.clear();
+ auto outFence = pMonitor->outTimeline->exportAsSyncFileFD(pMonitor->commitSeq);
+ if (outFence < 0)
+ Debug::log(ERR, "Export commitSeq {} as sync explicitOutFence failed", pMonitor->commitSeq);
+
+ pMonitor->output->state->setExplicitOutFence(outFence);
+ Debug::log(TRACE, "Explicit sync presented end");
+ }
+
+ pMonitor->lastWaitPoint = 0;
+
+ bool ok = pMonitor->state.commit();
+ if (!ok) {
+ Debug::log(TRACE, "Monitor state commit failed");
+ // rollback the buffer to avoid writing to the front buffer that is being
+ // displayed
+ pMonitor->output->swapchain->rollback();
+ pMonitor->damage.damageEntire();
+ }
+
+ if (!*PENABLEEXPLICIT)
+ return ok;
+
+ if (pMonitor->output->state->state().explicitInFence >= 0)
+ close(pMonitor->output->state->state().explicitInFence);
+
+ if (pMonitor->output->state->state().explicitOutFence >= 0) {
+ if (ok)
+ pMonitor->outTimeline->importFromSyncFileFD(pMonitor->commitSeq, pMonitor->output->state->state().explicitOutFence);
+ close(pMonitor->output->state->state().explicitOutFence);
+ }
+
+ return ok;
+}
+
void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry) {
Vector2D translate = {geometry.x, geometry.y};
float scale = (float)geometry.width / pMonitor->vecPixelSize.x;
@@ -1480,33 +1499,11 @@ void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE
}
}
-void CHyprRenderer::setWindowScanoutMode(PHLWINDOW pWindow) {
- // FIXME: fix when moved to new impl
- // if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked())
- // return;
-
- // if (!pWindow->m_bIsFullscreen) {
- // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), nullptr);
- // Debug::log(LOG, "Scanout mode OFF set for {}", pWindow);
- // return;
- // }
-
- // const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
-
- // const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = {
- // .main_renderer = g_pCompositor->m_sWLRRenderer,
- // .scanout_primary_output = PMONITOR->output,
- // };
-
- // wlr_linux_dmabuf_feedback_v1 feedback = {0};
-
- // if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS))
- // return;
-
- // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), &feedback);
- // wlr_linux_dmabuf_feedback_v1_finish(&feedback);
+void CHyprRenderer::setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, SP<CMonitor> monitor) {
+ if (!PROTO::linuxDma)
+ return;
- // Debug::log(LOG, "Scanout mode ON set for {}", pWindow);
+ PROTO::linuxDma->updateScanoutTranche(surface, monitor);
}
// taken from Sway.
@@ -1572,7 +1569,7 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector<PHLL
CBox full_area = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y};
for (auto& ls : layerSurfaces) {
- if (ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess)
+ if (!ls || ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess)
continue;
const auto PLAYER = ls->layerSurface;
@@ -1708,7 +1705,7 @@ void CHyprRenderer::damageSurface(SP<CWLSurfaceResource> pSurface, double x, dou
damageBox.scale(scale);
// schedule frame events
- g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y)));
+ g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y)), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
if (damageBox.empty())
return;
@@ -1820,13 +1817,13 @@ void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion
monbox.x = (monitor->vecTransformedSize.x - monbox.w) / 2;
monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2;
- wlr_region_scale(transformed.pixman(), transformed.pixman(), scale);
+ transformed.scale(scale);
transformed.transform(wlTransformToHyprutils(mirrored->transform), mirrored->vecPixelSize.x * scale, mirrored->vecPixelSize.y * scale);
transformed.translate(Vector2D(monbox.x, monbox.y));
mirror->addDamage(&transformed);
- g_pCompositor->scheduleFrameForMonitor(mirror);
+ g_pCompositor->scheduleFrameForMonitor(mirror, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
}
}
@@ -1869,7 +1866,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
// don't touch VR headsets
- if (pMonitor->output->non_desktop)
+ if (pMonitor->output->nonDesktop)
return true;
if (!pMonitor->m_bEnabled) {
@@ -1900,7 +1897,10 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
// Needed in case we are switching from a custom modeline to a standard mode
pMonitor->customDrmMode = {};
pMonitor->currentMode = nullptr;
- bool autoScale = false;
+
+ pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888);
+
+ bool autoScale = false;
if (RULE->scale > 0.1) {
pMonitor->scale = RULE->scale;
@@ -1910,38 +1910,35 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->scale = DEFAULTSCALE;
}
- wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale);
- pMonitor->setScale = pMonitor->scale;
-
- wlr_output_state_set_transform(pMonitor->state.wlr(), RULE->transform);
+ pMonitor->setScale = pMonitor->scale;
pMonitor->transform = RULE->transform;
- const auto WLRREFRESHRATE = (wlr_backend_is_wl(pMonitor->output->backend) || wlr_backend_is_x11(pMonitor->output->backend)) ? 0 : RULE->refreshRate * 1000;
+ const auto WLRREFRESHRATE = pMonitor->output->getBackend()->type() == Aquamarine::eBackendType::AQ_BACKEND_DRM ? RULE->refreshRate * 1000 : 0;
// loop over modes and choose an appropriate one.
if (RULE->resolution != Vector2D() && RULE->resolution != Vector2D(-1, -1) && RULE->resolution != Vector2D(-1, -2)) {
- if (!wl_list_empty(&pMonitor->output->modes) && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) {
- wlr_output_mode* mode;
- bool found = false;
+ if (!pMonitor->output->modes.empty() && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) {
+ bool found = false;
- wl_list_for_each(mode, &pMonitor->output->modes, link) {
+ for (auto& mode : pMonitor->output->modes) {
// if delta of refresh rate, w and h chosen and mode is < 1 we accept it
- if (DELTALESSTHAN(mode->width, RULE->resolution.x, 1) && DELTALESSTHAN(mode->height, RULE->resolution.y, 1) &&
- DELTALESSTHAN(mode->refresh / 1000.f, RULE->refreshRate, 1)) {
- wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
+ if (DELTALESSTHAN(mode->pixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(mode->pixelSize.y, RULE->resolution.y, 1) &&
+ DELTALESSTHAN(mode->refreshRate / 1000.f, RULE->refreshRate, 1)) {
+ pMonitor->output->state->setMode(mode);
- if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
- Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f);
+ if (!pMonitor->state.test()) {
+ Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y,
+ mode->refreshRate / 1000.f);
continue;
}
Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution,
- (float)RULE->refreshRate, mode->width, mode->height, mode->refresh);
+ (float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate);
found = true;
- pMonitor->refreshRate = mode->refresh / 1000.f;
- pMonitor->vecSize = Vector2D(mode->width, mode->height);
+ pMonitor->refreshRate = mode->refreshRate / 1000.f;
+ pMonitor->vecSize = mode->pixelSize;
pMonitor->currentMode = mode;
break;
@@ -1949,14 +1946,14 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
if (!found) {
- wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE);
+ pMonitor->output->state->setCustomMode(makeShared<Aquamarine::SOutputMode>(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE}));
pMonitor->vecSize = RULE->resolution;
pMonitor->refreshRate = RULE->refreshRate;
- if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
+ if (!pMonitor->state.test()) {
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
- const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
+ const auto PREFERREDMODE = pMonitor->output->preferredMode();
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution,
@@ -1965,13 +1962,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
// Preferred is valid
- wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
+ pMonitor->output->state->setMode(PREFERREDMODE);
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
- (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
+ (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f);
- pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
- pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
+ pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f;
+ pMonitor->vecSize = PREFERREDMODE->pixelSize;
pMonitor->currentMode = PREFERREDMODE;
} else {
Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate);
@@ -1982,30 +1979,30 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
bool fail = false;
if (RULE->drmMode.type == DRM_MODE_TYPE_USERDEF) {
- if (!wlr_output_is_drm(pMonitor->output)) {
+ if (pMonitor->output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM) {
Debug::log(ERR, "Tried to set custom modeline on non-DRM output");
fail = true;
} else {
- auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode);
- if (mode) {
- wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
- pMonitor->customDrmMode = RULE->drmMode;
- } else {
- Debug::log(ERR, "wlr_drm_connector_add_mode failed");
- fail = true;
- }
+ // FIXME:
+ // auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode);
+ // if (mode) {
+ // wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
+ // pMonitor->customDrmMode = RULE->drmMode;
+ // } else {
+ // Debug::log(ERR, "wlr_drm_connector_add_mode failed");
+ // fail = true;
+ // }
}
- } else {
- wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE);
- }
+ } else
+ pMonitor->output->state->setCustomMode(makeShared<Aquamarine::SOutputMode>(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE}));
pMonitor->vecSize = RULE->resolution;
pMonitor->refreshRate = RULE->refreshRate;
- if (fail || !wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
+ if (fail || !pMonitor->state.test()) {
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
- const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
+ const auto PREFERREDMODE = pMonitor->output->preferredMode();
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->output->name, RULE->resolution,
@@ -2014,48 +2011,47 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
// Preferred is valid
- wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
+ pMonitor->output->state->setMode(PREFERREDMODE);
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
- (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
+ (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f);
- pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
- pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
+ pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f;
+ pMonitor->vecSize = PREFERREDMODE->pixelSize;
pMonitor->customDrmMode = {};
- } else {
+ } else
Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate);
- }
}
} else if (RULE->resolution != Vector2D()) {
- if (!wl_list_empty(&pMonitor->output->modes)) {
- wlr_output_mode* mode;
- float currentWidth = 0;
- float currentHeight = 0;
- float currentRefresh = 0;
- bool success = false;
+ if (!pMonitor->output->modes.empty()) {
+ float currentWidth = 0;
+ float currentHeight = 0;
+ float currentRefresh = 0;
+ bool success = false;
//(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution
if (RULE->resolution == Vector2D(-1, -1)) {
- wl_list_for_each(mode, &pMonitor->output->modes, link) {
- if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || mode->refresh > (currentRefresh + 3000.f)) {
- wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
- if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
- currentWidth = mode->width;
- currentHeight = mode->height;
- currentRefresh = mode->refresh;
+ for (auto& mode : pMonitor->output->modes) {
+ if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) ||
+ mode->refreshRate > (currentRefresh + 3000.f)) {
+ pMonitor->output->state->setMode(mode);
+ if (pMonitor->state.test()) {
+ currentWidth = mode->pixelSize.x;
+ currentHeight = mode->pixelSize.y;
+ currentRefresh = mode->refreshRate;
success = true;
}
}
}
} else {
- wl_list_for_each(mode, &pMonitor->output->modes, link) {
- if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) ||
- (mode->width > currentWidth && mode->height > currentHeight)) {
- wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
- if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
- currentWidth = mode->width;
- currentHeight = mode->height;
- currentRefresh = mode->refresh;
+ for (auto& mode : pMonitor->output->modes) {
+ if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) ||
+ (mode->pixelSize.x > currentWidth && mode->pixelSize.y > currentHeight)) {
+ pMonitor->output->state->setMode(mode);
+ if (pMonitor->state.test()) {
+ currentWidth = mode->pixelSize.x;
+ currentHeight = mode->pixelSize.y;
+ currentRefresh = mode->refreshRate;
success = true;
}
}
@@ -2063,10 +2059,12 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
if (!success) {
- Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
- (float)RULE->refreshRate, mode->width, mode->height, mode->refresh / 1000.f);
+ if (pMonitor->output->state->state().mode)
+ Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
+ (float)RULE->refreshRate, pMonitor->output->state->state().mode->pixelSize.x, pMonitor->output->state->state().mode->pixelSize.y,
+ pMonitor->output->state->state().mode->refreshRate / 1000.f);
- const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
+ const auto PREFERREDMODE = pMonitor->output->preferredMode();
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution, (float)RULE->refreshRate);
@@ -2074,13 +2072,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
// Preferred is valid
- wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
+ pMonitor->output->state->setMode(PREFERREDMODE);
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
- (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
+ (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f);
- pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
- pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
+ pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f;
+ pMonitor->vecSize = PREFERREDMODE->pixelSize;
pMonitor->currentMode = PREFERREDMODE;
} else {
@@ -2091,27 +2089,26 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
}
} else {
- const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
+ const auto PREFERREDMODE = pMonitor->output->preferredMode();
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", pMonitor->output->name);
- if (!wl_list_empty(&pMonitor->output->modes)) {
- wlr_output_mode* mode;
-
- wl_list_for_each(mode, &pMonitor->output->modes, link) {
- wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
+ if (!pMonitor->output->modes.empty()) {
+ for (auto& mode : pMonitor->output->modes) {
+ pMonitor->output->state->setMode(mode);
- if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
- Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f);
+ if (!pMonitor->state.test()) {
+ Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y,
+ mode->refreshRate / 1000.f);
continue;
}
Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution,
- (float)RULE->refreshRate, mode->width, mode->height, mode->refresh);
+ (float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate);
- pMonitor->refreshRate = mode->refresh / 1000.f;
- pMonitor->vecSize = Vector2D(mode->width, mode->height);
+ pMonitor->refreshRate = mode->refreshRate / 1000.f;
+ pMonitor->vecSize = mode->pixelSize;
pMonitor->currentMode = mode;
break;
@@ -2119,21 +2116,49 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
} else {
// Preferred is valid
- wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
+ pMonitor->output->state->setMode(PREFERREDMODE);
- pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
- pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
+ pMonitor->vecSize = PREFERREDMODE->pixelSize;
+ pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f;
pMonitor->currentMode = PREFERREDMODE;
Debug::log(LOG, "Setting preferred mode for {}", pMonitor->output->name);
}
}
- pMonitor->vrrActive = pMonitor->state.wlr()->adaptive_sync_enabled // disabled here, will be tested in CConfigManager::ensureVRR()
- || pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync
+ pMonitor->vrrActive = pMonitor->output->state->state().adaptiveSync // disabled here, will be tested in CConfigManager::ensureVRR()
+ || pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync
pMonitor->vecPixelSize = pMonitor->vecSize;
+ // clang-format off
+ static const std::array<std::vector<std::pair<std::string, uint32_t>>, 2> formats{
+ std::vector<std::pair<std::string, uint32_t>>{ /* 10-bit */
+ {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID}
+ },
+ std::vector<std::pair<std::string, uint32_t>>{ /* 8-bit */
+ {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID}
+ }
+ };
+ // clang-format on
+
+ bool set10bit = false;
+
+ for (auto& fmt : formats[(int)!RULE->enable10bit]) {
+ pMonitor->output->state->setFormat(fmt.second);
+
+ if (!pMonitor->state.test()) {
+ Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first);
+ } else {
+ Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first);
+ if (RULE->enable10bit && fmt.first.contains("101010"))
+ set10bit = true;
+ break;
+ }
+ }
+
+ pMonitor->enabled10bit = set10bit;
+
Vector2D logicalSize = pMonitor->vecPixelSize / pMonitor->scale;
if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) {
// invalid scale, will produce fractional pixels.
@@ -2145,10 +2170,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
double scaleZero = searchScale / 120.0;
Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero;
- if (logicalZero == logicalZero.round()) {
+ if (logicalZero == logicalZero.round())
pMonitor->scale = scaleZero;
- wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale);
- } else {
+ else {
for (size_t i = 1; i < 90; ++i) {
double scaleUp = (searchScale + i) / 120.0;
double scaleDown = (searchScale - i) / 120.0;
@@ -2185,57 +2209,21 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} else
pMonitor->scale = searchScale;
}
-
- // for wlroots, that likes flooring, we have to do this.
- double logicalX = std::round(pMonitor->vecPixelSize.x / pMonitor->scale);
- logicalX += 0.1;
-
- wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->vecPixelSize.x / logicalX);
- }
- }
-
- // clang-format off
- static const std::array<std::vector<std::pair<std::string, uint32_t>>, 2> formats{
- std::vector<std::pair<std::string, uint32_t>>{ /* 10-bit */
- {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID}
- },
- std::vector<std::pair<std::string, uint32_t>>{ /* 8-bit */
- {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID}
- }
- };
- // clang-format on
-
- bool set10bit = false;
- pMonitor->drmFormat = DRM_FORMAT_INVALID;
-
- for (auto& fmt : formats[(int)!RULE->enable10bit]) {
- wlr_output_state_set_render_format(pMonitor->state.wlr(), fmt.second);
-
- if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
- Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first);
- } else {
- Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first);
- if (RULE->enable10bit && fmt.first.contains("101010"))
- set10bit = true;
-
- pMonitor->drmFormat = fmt.second;
- break;
}
}
- pMonitor->enabled10bit = set10bit;
+ pMonitor->output->scheduleFrame();
if (!pMonitor->state.commit())
Debug::log(ERR, "Couldn't commit output named {}", pMonitor->output->name);
- int x, y;
- wlr_output_transformed_resolution(pMonitor->output, &x, &y);
- pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).round();
- pMonitor->vecTransformedSize = Vector2D(x, y);
+ Vector2D xfmd = pMonitor->transform % 2 == 1 ? Vector2D{pMonitor->vecPixelSize.y, pMonitor->vecPixelSize.x} : pMonitor->vecPixelSize;
+ pMonitor->vecSize = (xfmd / pMonitor->scale).round();
+ pMonitor->vecTransformedSize = xfmd;
if (pMonitor->createdByUser) {
CBox transformedBox = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y};
- transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->output->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y);
+ transformedBox.transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y);
pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height);
}
@@ -2245,7 +2233,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
if (WAS10B != pMonitor->enabled10bit || OLDRES != pMonitor->vecPixelSize)
g_pHyprOpenGL->destroyMonitorResources(pMonitor);
- // updato wlroots
g_pCompositor->arrangeMonitors();
pMonitor->damage.setSize(pMonitor->vecTransformedSize);
@@ -2260,9 +2247,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
// updato us
arrangeLayersForMonitor(pMonitor->ID);
- // frame skip
- pMonitor->framesToSkip = 1;
-
// reload to fix mirrors
g_pConfigManager->m_bWantsMonitorReload = true;
@@ -2329,7 +2313,7 @@ void CHyprRenderer::ensureCursorRenderingMode() {
Debug::log(LOG, "Hiding the cursor (hl-mandated)");
for (auto& m : g_pCompositor->m_vMonitors) {
- if (m->output->software_cursor_locks == 0)
+ if (!g_pPointerManager->softwareLockedFor(m))
continue;
g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area?
@@ -2341,7 +2325,7 @@ void CHyprRenderer::ensureCursorRenderingMode() {
Debug::log(LOG, "Showing the cursor (hl-mandated)");
for (auto& m : g_pCompositor->m_vMonitors) {
- if (m->output->software_cursor_locks == 0)
+ if (!g_pPointerManager->softwareLockedFor(m))
continue;
g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area?
@@ -2570,37 +2554,37 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) {
pMonitor->solitaryClient = PCANDIDATE;
}
-CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt) {
- auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pWlrBuffer == buffer; });
+SP<CRenderbuffer> CHyprRenderer::getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
+ auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; });
if (it != m_vRenderbuffers.end())
- return it->get();
+ return *it;
- return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get();
-}
+ auto buf = makeShared<CRenderbuffer>(buffer, fmt);
-CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt) {
- auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; });
-
- if (it != m_vRenderbuffers.end())
- return it->get();
+ if (!buf->good())
+ return nullptr;
- return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get();
+ m_vRenderbuffers.emplace_back(buf);
+ return buf;
}
void CHyprRenderer::makeEGLCurrent() {
- if (!g_pCompositor)
+ if (!g_pCompositor || !g_pHyprOpenGL)
return;
- if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL))
- eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL));
+ if (eglGetCurrentContext() != g_pHyprOpenGL->m_pEglContext)
+ eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, g_pHyprOpenGL->m_pEglContext);
}
void CHyprRenderer::unsetEGL() {
- eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (!g_pHyprOpenGL)
+ return;
+
+ eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
-bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP<IWLBuffer> buffer, CFramebuffer* fb, bool simple) {
+bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP<IHLBuffer> buffer, CFramebuffer* fb, bool simple) {
makeEGLCurrent();
@@ -2618,35 +2602,33 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
return true;
}
- int bufferAge = 0;
+ /* This is a constant expression, as we always use double-buffering in our swapchain
+ TODO: Rewrite the CDamageRing to take advantage of that maybe? It's made to support longer swapchains atm because we used to do wlroots */
+ static constexpr const int HL_BUFFER_AGE = 2;
if (!buffer) {
- if (!wlr_output_configure_primary_swapchain(pMonitor->output, pMonitor->state.wlr(), &pMonitor->output->swapchain)) {
- Debug::log(ERR, "Failed to configure primary swapchain for {}", pMonitor->szName);
- return false;
- }
-
- m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &bufferAge);
- if (!m_pCurrentWlrBuffer) {
+ m_pCurrentBuffer = pMonitor->output->swapchain->next(nullptr);
+ if (!m_pCurrentBuffer) {
Debug::log(ERR, "Failed to acquire swapchain buffer for {}", pMonitor->szName);
return false;
}
} else
- m_pCurrentHLBuffer = buffer;
+ m_pCurrentBuffer = buffer;
try {
- if (m_pCurrentWlrBuffer)
- m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat);
- else
- m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentHLBuffer.lock(), pMonitor->drmFormat);
+ m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentBuffer, pMonitor->output->state->state().drmFormat);
} catch (std::exception& e) {
Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName);
- wlr_buffer_unlock(m_pCurrentWlrBuffer);
+ return false;
+ }
+
+ if (!m_pCurrentRenderbuffer) {
+ Debug::log(ERR, "failed to start a render pass for output {}, no RBO could be obtained", pMonitor->szName);
return false;
}
if (mode == RENDER_MODE_NORMAL) {
- damage = pMonitor->damage.getBufferDamage(bufferAge);
+ damage = pMonitor->damage.getBufferDamage(HL_BUFFER_AGE);
pMonitor->damage.rotate();
}
@@ -2662,6 +2644,9 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
void CHyprRenderer::endRender() {
const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor;
static auto PNVIDIAANTIFLICKER = CConfigValue<Hyprlang::INT>("opengl:nvidia_anti_flicker");
+ static auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("experimental:explicit_sync");
+
+ PMONITOR->commitSeq++;
if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY)
g_pHyprOpenGL->end();
@@ -2674,29 +2659,57 @@ void CHyprRenderer::endRender() {
if (m_eRenderMode == RENDER_MODE_FULL_FAKE)
return;
- if (isNvidia() && *PNVIDIAANTIFLICKER)
- glFinish();
- else
- glFlush();
-
if (m_eRenderMode == RENDER_MODE_NORMAL) {
- wlr_output_state_set_buffer(PMONITOR->state.wlr(), m_pCurrentWlrBuffer);
- unsetEGL(); // flush the context
- }
+ PMONITOR->output->state->setBuffer(m_pCurrentBuffer);
+
+ if (PMONITOR->inTimeline && *PENABLEEXPLICIT) {
+ auto sync = g_pHyprOpenGL->createEGLSync(-1);
+ if (!sync) {
+ m_pCurrentRenderbuffer->unbind();
+ m_pCurrentRenderbuffer = nullptr;
+ m_pCurrentBuffer = nullptr;
+ Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender");
+ return;
+ }
+
+ auto dupedfd = sync->dupFenceFD();
+ sync.reset();
+ if (dupedfd < 0) {
+ m_pCurrentRenderbuffer->unbind();
+ m_pCurrentRenderbuffer = nullptr;
+ m_pCurrentBuffer = nullptr;
+ Debug::log(ERR, "renderer: couldn't dup an EGLSync fence for out in endRender");
+ return;
+ }
- wlr_buffer_unlock(m_pCurrentWlrBuffer);
+ bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, dupedfd);
+ close(dupedfd);
+ if (!ok) {
+ m_pCurrentRenderbuffer->unbind();
+ m_pCurrentRenderbuffer = nullptr;
+ m_pCurrentBuffer = nullptr;
+ Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender");
+ return;
+ }
+ } else {
+ if (isNvidia() && *PNVIDIAANTIFLICKER)
+ glFinish();
+ else
+ glFlush();
+ }
+ }
m_pCurrentRenderbuffer->unbind();
m_pCurrentRenderbuffer = nullptr;
- m_pCurrentWlrBuffer = nullptr;
+ m_pCurrentBuffer = nullptr;
}
void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) {
std::erase_if(m_vRenderbuffers, [&](const auto& rbo) { return rbo.get() == rb; });
}
-CRenderbuffer* CHyprRenderer::getCurrentRBO() {
+SP<CRenderbuffer> CHyprRenderer::getCurrentRBO() {
return m_pCurrentRenderbuffer;
}
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index 8f404c88..72efe8c4 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -12,7 +12,7 @@ struct SMonitorRule;
class CWorkspace;
class CWindow;
class CInputPopup;
-class IWLBuffer;
+class IHLBuffer;
// TODO: add fuller damage tracking for updating only parts of a window
enum DAMAGETRACKINGMODES {
@@ -69,35 +69,35 @@ class CHyprRenderer {
void setCursorSurface(SP<CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
void setCursorFromName(const std::string& name, bool force = false);
void onRenderbufferDestroy(CRenderbuffer* rb);
- CRenderbuffer* getCurrentRBO();
+ SP<CRenderbuffer> getCurrentRBO();
bool isNvidia();
void makeEGLCurrent();
void unsetEGL();
// if RENDER_MODE_NORMAL, provided damage will be written to.
// otherwise, it will be the one used.
- bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IWLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
- void endRender();
+ bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
+ void endRender();
- bool m_bBlockSurfaceFeedback = false;
- bool m_bRenderingSnapshot = false;
- PHLWINDOWREF m_pLastScanout;
- CMonitor* m_pMostHzMonitor = nullptr;
- bool m_bDirectScanoutBlocked = false;
+ bool m_bBlockSurfaceFeedback = false;
+ bool m_bRenderingSnapshot = false;
+ CMonitor* m_pMostHzMonitor = nullptr;
+ bool m_bDirectScanoutBlocked = false;
DAMAGETRACKINGMODES
damageTrackingModeFromStr(const std::string&);
- bool attemptDirectScanout(CMonitor*);
- void setWindowScanoutMode(PHLWINDOW);
- void initiateManualCrash();
+ void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, SP<CMonitor> monitor); // nullptr monitor resets
+ void initiateManualCrash();
- bool m_bCrashingInProgress = false;
- float m_fCrashingDistort = 0.5f;
- wl_event_source* m_pCrashingLoop = nullptr;
- wl_event_source* m_pCursorTicker = nullptr;
+ bool m_bCrashingInProgress = false;
+ float m_fCrashingDistort = 0.5f;
+ wl_event_source* m_pCrashingLoop = nullptr;
+ wl_event_source* m_pCursorTicker = nullptr;
- CTimer m_tRenderTimer;
+ CTimer m_tRenderTimer;
+
+ std::vector<SP<CWLSurfaceResource>> explicitPresented;
struct {
int hotspotX;
@@ -107,26 +107,27 @@ class CHyprRenderer {
} m_sLastCursorData;
private:
- void arrangeLayerArray(CMonitor*, const std::vector<PHLLSREF>&, bool, CBox*);
- void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
- void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special)
- void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false);
- void renderLayer(PHLLS, CMonitor*, timespec*, bool popups = false);
- void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*);
- void renderDragIcon(CMonitor*, timespec*);
- void renderIMEPopup(CInputPopup*, CMonitor*, timespec*);
- void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry);
- void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything
- void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
-
- bool m_bCursorHidden = false;
- bool m_bCursorHasSurface = false;
- CRenderbuffer* m_pCurrentRenderbuffer = nullptr;
- wlr_buffer* m_pCurrentWlrBuffer = nullptr;
- WP<IWLBuffer> m_pCurrentHLBuffer = {};
- eRenderMode m_eRenderMode = RENDER_MODE_NORMAL;
-
- bool m_bNvidia = false;
+ void arrangeLayerArray(CMonitor*, const std::vector<PHLLSREF>&, bool, CBox*);
+ void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
+ void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special)
+ void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false);
+ void renderLayer(PHLLS, CMonitor*, timespec*, bool popups = false);
+ void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*);
+ void renderDragIcon(CMonitor*, timespec*);
+ void renderIMEPopup(CInputPopup*, CMonitor*, timespec*);
+ void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry);
+ void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything
+ void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
+
+ bool commitPendingAndDoExplicitSync(CMonitor* pMonitor);
+
+ bool m_bCursorHidden = false;
+ bool m_bCursorHasSurface = false;
+ SP<CRenderbuffer> m_pCurrentRenderbuffer = nullptr;
+ SP<Aquamarine::IBuffer> m_pCurrentBuffer;
+ eRenderMode m_eRenderMode = RENDER_MODE_NORMAL;
+
+ bool m_bNvidia = false;
struct {
bool hiddenOnTouch = false;
@@ -134,9 +135,8 @@ class CHyprRenderer {
bool hiddenOnKeyboard = false;
} m_sCursorHiddenConditions;
- CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt);
- CRenderbuffer* getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt);
- std::vector<std::unique_ptr<CRenderbuffer>> m_vRenderbuffers;
+ SP<CRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt);
+ std::vector<SP<CRenderbuffer>> m_vRenderbuffers;
friend class CHyprOpenGLImpl;
friend class CToplevelExportProtocolManager;
diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp
index 46c501a0..0f5b4c4c 100644
--- a/src/render/Texture.cpp
+++ b/src/render/Texture.cpp
@@ -9,7 +9,7 @@ CTexture::CTexture() {
}
CTexture::~CTexture() {
- if (m_bNonOwning || !g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer)
+ if (!g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer)
return;
g_pHyprRenderer->makeEGLCurrent();
@@ -17,6 +17,45 @@ CTexture::~CTexture() {
}
CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
+ createFromShm(drmFormat, pixels, stride, size_);
+}
+
+CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
+ createFromDma(attrs, image);
+}
+
+CTexture::CTexture(const SP<Aquamarine::IBuffer> buffer) {
+ if (!buffer)
+ return;
+
+ auto attrs = buffer->dmabuf();
+
+ if (!attrs.success) {
+ // attempt shm
+ auto shm = buffer->shm();
+
+ if (!shm.success) {
+ Debug::log(ERR, "Cannot create a texture: buffer has no dmabuf or shm");
+ return;
+ }
+
+ auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0);
+
+ createFromShm(fmt, pixelData, bufLen, shm.size);
+ return;
+ }
+
+ auto image = g_pHyprOpenGL->createEGLImage(buffer->dmabuf());
+
+ if (!image) {
+ Debug::log(ERR, "Cannot create a texture: failed to create an EGLImage");
+ return;
+ }
+
+ createFromDma(attrs, image);
+}
+
+void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
g_pHyprRenderer->makeEGLCurrent();
const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat);
@@ -41,24 +80,7 @@ CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const V
GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
}
-CTexture::CTexture(wlr_texture* tex) {
- RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!");
- wlr_gles2_texture_attribs attrs;
- wlr_gles2_texture_get_attribs(tex, &attrs);
-
- m_iTarget = attrs.target;
- m_iTexID = attrs.tex;
- m_bNonOwning = true;
-
- if (m_iTarget == GL_TEXTURE_2D)
- m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX;
- else
- m_iType = TEXTURE_EXTERNAL;
-
- m_vSize = Vector2D((int)tex->width, (int)tex->height);
-}
-
-CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) {
+void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
if (!g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES) {
Debug::log(ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES");
return;
@@ -119,7 +141,7 @@ void CTexture::destroyTexture() {
}
if (m_pEglImage)
- g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_pEglImage);
+ g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_pEglImage);
m_pEglImage = nullptr;
}
diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp
index c80e943d..0da95300 100644
--- a/src/render/Texture.hpp
+++ b/src/render/Texture.hpp
@@ -1,9 +1,9 @@
#pragma once
#include "../defines.hpp"
+#include <aquamarine/buffer/Buffer.hpp>
-class IWLBuffer;
-struct SDMABUFAttrs;
+class IHLBuffer;
HYPRUTILS_FORWARD(Math, CRegion);
enum TEXTURETYPE {
@@ -23,10 +23,10 @@ class CTexture {
CTexture(const CTexture&) = delete;
CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
- CTexture(wlr_texture*);
+ CTexture(const SP<Aquamarine::IBuffer> buffer);
// this ctor takes ownership of the eglImage.
- CTexture(const SDMABUFAttrs&, void* image);
+ CTexture(const Aquamarine::SDMABUFAttrs&, void* image);
~CTexture();
void destroyTexture();
@@ -37,6 +37,9 @@ class CTexture {
GLenum m_iTarget = GL_TEXTURE_2D;
GLuint m_iTexID = 0;
Vector2D m_vSize;
- void* m_pEglImage = nullptr;
- bool m_bNonOwning = false; // wlr
+ void* m_pEglImage = nullptr;
+
+ private:
+ void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
+ void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image);
}; \ No newline at end of file
diff --git a/src/signal-safe.hpp b/src/signal-safe.hpp
index 70320ad1..3a38f043 100644
--- a/src/signal-safe.hpp
+++ b/src/signal-safe.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "defines.hpp"
+#include <cstring>
template <uint16_t N>
class MaxLengthCString {
diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp
index e2dab412..3f4e7b43 100644
--- a/src/xwayland/Server.cpp
+++ b/src/xwayland/Server.cpp
@@ -18,12 +18,13 @@
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
+#include <filesystem>
// TODO: cleanup
static bool set_cloexec(int fd, bool cloexec) {
int flags = fcntl(fd, F_GETFD);
if (flags == -1) {
- wlr_log_errno(WLR_ERROR, "fcntl failed");
+ Debug::log(ERR, "fcntl failed");
return false;
}
if (cloexec) {
@@ -32,7 +33,7 @@ static bool set_cloexec(int fd, bool cloexec) {
flags = flags & ~FD_CLOEXEC;
}
if (fcntl(fd, F_SETFD, flags) == -1) {
- wlr_log_errno(WLR_ERROR, "fcntl failed");
+ Debug::log(ERR, "fcntl failed");
return false;
}
return true;
@@ -44,7 +45,7 @@ static int openSocket(struct sockaddr_un* addr, size_t path_size) {
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
- wlr_log_errno(WLR_ERROR, "Failed to create socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
+ Debug::log(ERR, "failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
return -1;
}
if (!set_cloexec(fd, true)) {
@@ -57,12 +58,12 @@ static int openSocket(struct sockaddr_un* addr, size_t path_size) {
}
if (bind(fd, (struct sockaddr*)addr, size) < 0) {
rc = errno;
- wlr_log_errno(WLR_ERROR, "Failed to bind socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
+ Debug::log(ERR, "failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
goto cleanup;
}
if (listen(fd, 1) < 0) {
rc = errno;
- wlr_log_errno(WLR_ERROR, "Failed to listen to socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
+ Debug::log(ERR, "failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
goto cleanup;
}
diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp
index b34d0cfe..b55df7fc 100644
--- a/src/xwayland/XWM.cpp
+++ b/src/xwayland/XWM.cpp
@@ -299,8 +299,8 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) {
auto id = e->data.data32[0];
auto resource = wl_client_get_object(g_pXWayland->pServer->xwaylandClient, id);
if (resource) {
- auto wlrSurface = CWLSurfaceResource::fromResource(resource);
- associate(XSURF, wlrSurface);
+ auto surf = CWLSurfaceResource::fromResource(resource);
+ associate(XSURF, surf);
}
} else if (e->type == HYPRATOMS["WL_SURFACE_SERIAL"]) {
if (XSURF->wlSerial) {
@@ -755,7 +755,7 @@ void CXWM::getVisual() {
}
if (visualtype == NULL) {
- wlr_log(WLR_DEBUG, "No 32 bit visualtype\n");
+ Debug::log(LOG, "xwm: No 32-bit visualtype");
return;
}
@@ -768,7 +768,7 @@ void CXWM::getRenderFormat() {
xcb_render_query_pict_formats_cookie_t cookie = xcb_render_query_pict_formats(connection);
xcb_render_query_pict_formats_reply_t* reply = xcb_render_query_pict_formats_reply(connection, cookie, NULL);
if (!reply) {
- wlr_log(WLR_ERROR, "Did not get any reply from xcb_render_query_pict_formats");
+ Debug::log(LOG, "xwm: No xcb_render_query_pict_formats_reply_t reply");
return;
}
xcb_render_pictforminfo_iterator_t iter = xcb_render_query_pict_formats_formats_iterator(reply);
@@ -783,7 +783,7 @@ void CXWM::getRenderFormat() {
}
if (format == NULL) {
- wlr_log(WLR_DEBUG, "No 32 bit render format");
+ Debug::log(LOG, "xwm: No 32-bit render format");
free(reply);
return;
}
diff --git a/subprojects/wlroots-hyprland b/subprojects/wlroots-hyprland
deleted file mode 160000
-Subproject 422207dbcf0949e28042403edab539159282885