From 753c538dea87cd57042481608a4d9c6882f053ba Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sun, 29 Dec 2024 18:36:08 +0000 Subject: [PATCH] Core: move to hyprwayland-scanner (#624) nix: add hyprwayland-scanner dep flake.lock: update --------- Co-authored-by: Mihai Fufezan --- .gitignore | 4 +- CMakeLists.txt | 74 ++-- README.md | 1 + flake.lock | 48 ++- flake.nix | 6 + nix/default.nix | 2 + nix/overlays.nix | 1 + src/core/CursorShape.cpp | 14 +- src/core/CursorShape.hpp | 12 +- src/core/Egl.hpp | 1 - src/core/LockSurface.cpp | 99 ++--- src/core/LockSurface.hpp | 37 +- src/core/Output.cpp | 94 ++--- src/core/Output.hpp | 7 +- src/core/Seat.cpp | 138 +++++++ src/core/Seat.hpp | 33 ++ src/core/hyprlock.cpp | 683 ++++++++++--------------------- src/core/hyprlock.hpp | 149 ++++--- src/renderer/DMAFrame.cpp | 139 +++---- src/renderer/DMAFrame.hpp | 32 +- src/renderer/widgets/IWidget.cpp | 2 +- 21 files changed, 709 insertions(+), 867 deletions(-) create mode 100644 src/core/Seat.cpp create mode 100644 src/core/Seat.hpp diff --git a/.gitignore b/.gitignore index 2e1902ed..e12d18d9 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,6 @@ Makefile cmake_install.cmake build/ compile_commands.json -protocols/*.c -protocols/*.h +protocols/*.cpp +protocols/*.hpp *.kdev4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 704d0799..296ef8eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ message(STATUS "Checking deps...") find_package(Threads REQUIRED) find_package(PkgConfig REQUIRED) find_package(OpenGL REQUIRED) +find_package(hyprwayland-scanner 0.4.4 REQUIRED) pkg_check_modules( deps REQUIRED @@ -85,54 +86,49 @@ target_link_libraries(hyprlock PRIVATE pam rt Threads::Threads PkgConfig::deps OpenGL::EGL OpenGL::GL) # protocols -find_program(WaylandScanner NAMES wayland-scanner) -message(STATUS "Found WaylandScanner at ${WaylandScanner}") -execute_process( - COMMAND pkg-config --variable=pkgdatadir wayland-protocols - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE WAYLAND_PROTOCOLS_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) +pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") +pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) +message( + STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}") -function(protocol protoPath protoName external) +function(protocolnew protoPath protoName external) if(external) - execute_process( - COMMAND ${WaylandScanner} client-header ${protoPath} - protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - execute_process( - COMMAND ${WaylandScanner} private-code ${protoPath} - protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(hyprlock PRIVATE protocols/${protoName}-protocol.c) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) else() - execute_process( - COMMAND - ${WaylandScanner} client-header ${WAYLAND_PROTOCOLS_DIR}/${protoPath} - protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - execute_process( - COMMAND - ${WaylandScanner} private-code ${WAYLAND_PROTOCOLS_DIR}/${protoPath} - protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(hyprlock PRIVATE protocols/${protoName}-protocol.c) + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) endif() + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp + ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp + COMMAND hyprwayland-scanner --client ${path}/${protoName}.xml + ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(hyprlock PRIVATE protocols/${protoName}.cpp + protocols/${protoName}.hpp) +endfunction() +function(protocolWayland) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp + ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp + COMMAND hyprwayland-scanner --wayland-enums --client + ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(hyprlock PRIVATE protocols/wayland.cpp protocols/wayland.hpp) endfunction() make_directory(${CMAKE_SOURCE_DIR}/protocols) # we don't ship any custom ones so # the dir won't be there -protocol("staging/ext-session-lock/ext-session-lock-v1.xml" - "ext-session-lock-v1" false) -protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false) -protocol("unstable/tablet/tablet-unstable-v2.xml" "tablet-unstable-v2" false) -protocol("staging/fractional-scale/fractional-scale-v1.xml" - "fractional-scale-v1" false) -protocol("stable/viewporter/viewporter.xml" "viewporter" false) -protocol("protocols/wlr-screencopy-unstable-v1.xml" - "wlr-screencopy-unstable-v1" true) -protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" - "linux-dmabuf-unstable-v1" false) + +protocolwayland() + +protocolnew("protocols" "wlr-screencopy-unstable-v1" true) +protocolnew("staging/ext-session-lock" "ext-session-lock-v1" false) +protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false) +protocolnew("staging/fractional-scale" "fractional-scale-v1" false) +protocolnew("stable/viewporter" "viewporter" false) +protocolnew("staging/cursor-shape" "cursor-shape-v1" false) +protocolnew("stable/tablet" "tablet-v2" false) # Installation install(TARGETS hyprlock) diff --git a/README.md b/README.md index d00d6150..e8cd34ab 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ You need the following dependencies - wayland-client - wayland-protocols - mesa +- hyprwayland-scanner And the development libraries for the following - cairo diff --git a/flake.lock b/flake.lock index a6b069e4..cb8c168c 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1733684019, - "narHash": "sha256-2kYREgmSmbLsmDpLEq96hxVAU3qz8aCvVhF65yCFZHY=", + "lastModified": 1734906236, + "narHash": "sha256-vH/ysV2ONGQgYZPtcJKwc8jJivzyVxru2aaOxC20ZOE=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "fb2c0268645a77403af3b8a4ce8fa7ba5917f15d", + "rev": "6dea3fba08fd704dd624b6d4b261638fb4003c9c", "type": "github" }, "original": { @@ -39,11 +39,11 @@ ] }, "locked": { - "lastModified": 1734364628, - "narHash": "sha256-ii8fzJfI953n/EmIxVvq64ZAwhvwuuPHWfGd61/mJG8=", + "lastModified": 1735393019, + "narHash": "sha256-NPpqA8rtmDLsEmZOmz+qR67zsB6Y503Jnv+nSFLKJZ8=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "16e59c1eb13d9fb6de066f54e7555eb5e8a4aba5", + "rev": "55608efdaa387af7bfdc0eddb404c409958efa43", "type": "github" }, "original": { @@ -62,11 +62,11 @@ ] }, "locked": { - "lastModified": 1733502241, - "narHash": "sha256-KAUNC4Dgq8WQjYov5auBw/usaHixhacvb7cRDd0AG/k=", + "lastModified": 1735316583, + "narHash": "sha256-AiiUwHWHfEdpFzXy7l1x3zInCUa1xcRMrbZ1XRSkzwU=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "104117aed6dd68561be38b50f218190aa47f2cd8", + "rev": "8f15d45b120b33712f6db477fe5ffb18034d0ea8", "type": "github" }, "original": { @@ -75,13 +75,36 @@ "type": "github" } }, + "hyprwayland-scanner": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1735493474, + "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=", + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1734119587, - "narHash": "sha256-AKU6qqskl0yf2+JdRdD0cfxX4b9x3KKV5RqA6wijmPM=", + "lastModified": 1735291276, + "narHash": "sha256-NYVcA06+blsLG6wpAbSPTCyLvxD/92Hy4vlY9WxFI1M=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3566ab7246670a43abd2ffa913cc62dad9cdf7d5", + "rev": "634fd46801442d760e09493a794c4f15db2d0cbb", "type": "github" }, "original": { @@ -96,6 +119,7 @@ "hyprgraphics": "hyprgraphics", "hyprlang": "hyprlang", "hyprutils": "hyprutils", + "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", "systems": "systems" } diff --git a/flake.nix b/flake.nix index 7a75f434..1cc9a00d 100644 --- a/flake.nix +++ b/flake.nix @@ -24,6 +24,12 @@ inputs.systems.follows = "systems"; inputs.hyprutils.follows = "hyprutils"; }; + + hyprwayland-scanner = { + url = "github:hyprwm/hyprwayland-scanner"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + }; }; outputs = { diff --git a/nix/default.nix b/nix/default.nix index 08b9f999..670fed4f 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -14,6 +14,7 @@ hyprgraphics, hyprlang, hyprutils, + hyprwayland-scanner, pam, pango, sdbus-cpp, @@ -33,6 +34,7 @@ stdenv.mkDerivation { nativeBuildInputs = [ cmake pkg-config + hyprwayland-scanner wayland-scanner ]; diff --git a/nix/overlays.nix b/nix/overlays.nix index 512866fa..afedab6f 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -17,6 +17,7 @@ in { inputs.hyprgraphics.overlays.default inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default + inputs.hyprwayland-scanner.overlays.default inputs.self.overlays.sdbuscpp (final: prev: { hyprlock = prev.callPackage ./default.nix { diff --git a/src/core/CursorShape.cpp b/src/core/CursorShape.cpp index 25016dd6..dd3201cd 100644 --- a/src/core/CursorShape.cpp +++ b/src/core/CursorShape.cpp @@ -1,20 +1,20 @@ #include "CursorShape.hpp" -#include "hyprlock.hpp" +#include "Seat.hpp" -CCursorShape::CCursorShape(wp_cursor_shape_manager_v1* mgr) : mgr(mgr) { - if (!g_pHyprlock->m_pPointer) +CCursorShape::CCursorShape(SP mgr) : mgr(mgr) { + if (!g_pSeatManager->m_pPointer) return; - dev = wp_cursor_shape_manager_v1_get_pointer(mgr, g_pHyprlock->m_pPointer); + dev = makeShared(mgr->sendGetPointer(g_pSeatManager->m_pPointer->resource())); } -void CCursorShape::setShape(const wp_cursor_shape_device_v1_shape shape) { +void CCursorShape::setShape(const wpCursorShapeDeviceV1Shape shape) { if (!dev) return; - wp_cursor_shape_device_v1_set_shape(dev, lastCursorSerial, shape); + dev->sendSetShape(lastCursorSerial, shape); } void CCursorShape::hideCursor() { - wl_pointer_set_cursor(g_pHyprlock->m_pPointer, lastCursorSerial, nullptr, 0, 0); + g_pSeatManager->m_pPointer->sendSetCursor(lastCursorSerial, nullptr, 0, 0); } \ No newline at end of file diff --git a/src/core/CursorShape.hpp b/src/core/CursorShape.hpp index c0d858be..9c8ea904 100644 --- a/src/core/CursorShape.hpp +++ b/src/core/CursorShape.hpp @@ -1,18 +1,18 @@ #pragma once -#include -#include "cursor-shape-v1-protocol.h" +#include "../defines.hpp" +#include "cursor-shape-v1.hpp" class CCursorShape { public: - CCursorShape(wp_cursor_shape_manager_v1* mgr); + CCursorShape(SP mgr); - void setShape(const wp_cursor_shape_device_v1_shape shape); + void setShape(const wpCursorShapeDeviceV1Shape shape); void hideCursor(); uint32_t lastCursorSerial = 0; private: - wp_cursor_shape_manager_v1* mgr = nullptr; - wp_cursor_shape_device_v1* dev = nullptr; + SP mgr = nullptr; + SP dev = nullptr; }; \ No newline at end of file diff --git a/src/core/Egl.hpp b/src/core/Egl.hpp index 52cbb592..5a697d07 100644 --- a/src/core/Egl.hpp +++ b/src/core/Egl.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include diff --git a/src/core/LockSurface.cpp b/src/core/LockSurface.cpp index c8e4f829..757c63d7 100644 --- a/src/core/LockSurface.cpp +++ b/src/core/LockSurface.cpp @@ -5,51 +5,13 @@ #include "../renderer/Renderer.hpp" #include "src/config/ConfigManager.hpp" -static void handleConfigure(void* data, ext_session_lock_surface_v1* surf, uint32_t serial, uint32_t width, uint32_t height) { - const auto PSURF = (CSessionLockSurface*)data; - PSURF->configure({(double)width, (double)height}, serial); -} - -static const ext_session_lock_surface_v1_listener lockListener = { - .configure = handleConfigure, -}; - -static void handlePreferredScale(void* data, wp_fractional_scale_v1* wp_fractional_scale_v1, uint32_t scale) { - const auto PSURF = (CSessionLockSurface*)data; - const bool SAMESCALE = PSURF->fractionalScale == scale / 120.0; - PSURF->fractionalScale = scale / 120.0; - - Debug::log(LOG, "Got fractional scale: {}", PSURF->fractionalScale); - - if (!SAMESCALE && PSURF->readyForFrame) - PSURF->onScaleUpdate(); -} - -static const wp_fractional_scale_v1_listener fsListener = { - .preferred_scale = handlePreferredScale, -}; - CSessionLockSurface::~CSessionLockSurface() { - if (fractional) { - wp_viewport_destroy(viewport); - wp_fractional_scale_v1_destroy(fractional); - } - if (eglWindow) wl_egl_window_destroy(eglWindow); - - if (lockSurface) - ext_session_lock_surface_v1_destroy(lockSurface); - - if (surface) - wl_surface_destroy(surface); - - if (frameCallback) - wl_callback_destroy(frameCallback); } CSessionLockSurface::CSessionLockSurface(COutput* output) : output(output) { - surface = wl_compositor_create_surface(g_pHyprlock->getCompositor()); + surface = makeShared(g_pHyprlock->getCompositor()->sendCreateSurface()); if (!surface) { Debug::log(CRIT, "Couldn't create wl_surface"); @@ -62,11 +24,19 @@ CSessionLockSurface::CSessionLockSurface(COutput* output) : output(output) { const auto PVIEWPORTER = g_pHyprlock->getViewporter(); if (ENABLE_FSV1 && PFRACTIONALMGR && PVIEWPORTER) { - fractional = wp_fractional_scale_manager_v1_get_fractional_scale(PFRACTIONALMGR, surface); - if (fractional) { - wp_fractional_scale_v1_add_listener(fractional, &fsListener, this); - viewport = wp_viewporter_get_viewport(PVIEWPORTER, surface); - } + fractional = makeShared(PFRACTIONALMGR->sendGetFractionalScale(surface->resource())); + + fractional->setPreferredScale([this](CCWpFractionalScaleV1*, uint32_t scale) { + const bool SAMESCALE = fractionalScale == scale / 120.0; + fractionalScale = scale / 120.0; + + Debug::log(LOG, "Got fractional scale: {:.1f}%", fractionalScale * 100.F); + + if (!SAMESCALE && readyForFrame) + onScaleUpdate(); + }); + + viewport = makeShared(PVIEWPORTER->sendGetViewport(surface->resource())); } if (!PFRACTIONALMGR) @@ -74,14 +44,14 @@ CSessionLockSurface::CSessionLockSurface(COutput* output) : output(output) { if (!PVIEWPORTER) Debug::log(LOG, "No viewporter support! Oops, won't be able to scale!"); - lockSurface = ext_session_lock_v1_get_lock_surface(g_pHyprlock->getSessionLock(), surface, output->output); + lockSurface = makeShared(g_pHyprlock->getSessionLock()->sendGetLockSurface(surface->resource(), output->output->resource())); if (!lockSurface) { Debug::log(CRIT, "Couldn't create ext_session_lock_surface_v1"); exit(1); } - ext_session_lock_surface_v1_add_listener(lockSurface, &lockListener, this); + lockSurface->setConfigure([this](CCExtSessionLockSurfaceV1* r, uint32_t serial, uint32_t width, uint32_t height) { configure({(double)width, (double)height}, serial); }); } void CSessionLockSurface::configure(const Vector2D& size_, uint32_t serial_) { @@ -97,22 +67,22 @@ void CSessionLockSurface::configure(const Vector2D& size_, uint32_t serial_) { if (fractional) { size = (size_ * fractionalScale).floor(); - wp_viewport_set_destination(viewport, logicalSize.x, logicalSize.y); - wl_surface_set_buffer_scale(surface, 1); + viewport->sendSetDestination(logicalSize.x, logicalSize.y); + surface->sendSetBufferScale(1); } else { size = size_ * output->scale; - wl_surface_set_buffer_scale(surface, output->scale); + surface->sendSetBufferScale(output->scale); } if (!SAMESERIAL) - ext_session_lock_surface_v1_ack_configure(lockSurface, serial); + lockSurface->sendAckConfigure(serial); Debug::log(LOG, "Configuring surface for logical {} and pixel {}", logicalSize, size); - wl_surface_damage_buffer(surface, 0, 0, 0xFFFF, 0xFFFF); + surface->sendDamageBuffer(0, 0, 0xFFFF, 0xFFFF); if (!eglWindow) { - eglWindow = wl_egl_window_create(surface, size.x, size.y); + eglWindow = wl_egl_window_create((wl_surface*)surface->resource(), size.x, size.y); if (!eglWindow) { Debug::log(CRIT, "Couldn't create eglWindow"); exit(1); @@ -145,19 +115,6 @@ void CSessionLockSurface::onScaleUpdate() { configure(logicalSize, serial); } -static void handleDone(void* data, wl_callback* wl_callback, uint32_t callback_data) { - const auto PSURF = (CSessionLockSurface*)data; - - if (g_pHyprlock->m_bTerminate) - return; - - PSURF->onCallback(); -} - -static const wl_callback_listener callbackListener = { - .done = handleDone, -}; - void CSessionLockSurface::render() { Debug::log(TRACE, "render lock"); @@ -167,8 +124,13 @@ void CSessionLockSurface::render() { } const auto FEEDBACK = g_pRenderer->renderLock(*this); - frameCallback = wl_surface_frame(surface); - wl_callback_add_listener(frameCallback, &callbackListener, this); + frameCallback = makeShared(surface->sendFrame()); + frameCallback->setDone([this](CCWlCallback* r, uint32_t data) { + if (g_pHyprlock->m_bTerminate) + return; + + onCallback(); + }); eglSwapBuffers(g_pEGL->eglDisplay, eglSurface); @@ -176,8 +138,7 @@ void CSessionLockSurface::render() { } void CSessionLockSurface::onCallback() { - wl_callback_destroy(frameCallback); - frameCallback = nullptr; + frameCallback.reset(); if (needsFrame && !g_pHyprlock->m_bTerminate && g_pEGL) { needsFrame = false; diff --git a/src/core/LockSurface.hpp b/src/core/LockSurface.hpp index f1f19180..9461541c 100644 --- a/src/core/LockSurface.hpp +++ b/src/core/LockSurface.hpp @@ -1,9 +1,10 @@ #pragma once -#include -#include "ext-session-lock-v1-protocol.h" -#include "viewporter-protocol.h" -#include "fractional-scale-v1-protocol.h" +#include "../defines.hpp" +#include "wayland.hpp" +#include "ext-session-lock-v1.hpp" +#include "viewporter.hpp" +#include "fractional-scale-v1.hpp" #include "../helpers/Math.hpp" #include #include @@ -27,22 +28,22 @@ class CSessionLockSurface { void onScaleUpdate(); private: - COutput* output = nullptr; - wl_surface* surface = nullptr; - ext_session_lock_surface_v1* lockSurface = nullptr; - uint32_t serial = 0; - wl_egl_window* eglWindow = nullptr; - Vector2D size; - Vector2D logicalSize; - float appliedScale; - EGLSurface eglSurface = nullptr; - wp_fractional_scale_v1* fractional = nullptr; - wp_viewport* viewport = nullptr; - - bool needsFrame = false; + COutput* output = nullptr; + SP surface = nullptr; + SP lockSurface = nullptr; + uint32_t serial = 0; + wl_egl_window* eglWindow = nullptr; + Vector2D size; + Vector2D logicalSize; + float appliedScale; + EGLSurface eglSurface = nullptr; + SP fractional = nullptr; + SP viewport = nullptr; + + bool needsFrame = false; // wayland callbacks - wl_callback* frameCallback = nullptr; + SP frameCallback = nullptr; friend class CRenderer; }; \ No newline at end of file diff --git a/src/core/Output.cpp b/src/core/Output.cpp index 3b0a8a42..18148708 100644 --- a/src/core/Output.cpp +++ b/src/core/Output.cpp @@ -3,61 +3,41 @@ #include "hyprlock.hpp" #include "../renderer/Renderer.hpp" -static void handleGeometry(void* data, wl_output* output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char* make, - const char* model, int32_t transform) { - const auto POUTPUT = (COutput*)data; - POUTPUT->transform = (wl_output_transform)transform; - - Debug::log(LOG, "output {} make {} model {}", POUTPUT->name, make ? make : "", model ? model : ""); -} - -static void handleMode(void* data, wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { - const auto POUTPUT = (COutput*)data; - - // handle portrait mode and flipped cases - if (POUTPUT->transform % 2 == 1) - POUTPUT->size = {height, width}; - else - POUTPUT->size = {width, height}; -} - -static void handleDone(void* data, wl_output* output) { - const auto POUTPUT = (COutput*)data; - Debug::log(LOG, "output {} done", POUTPUT->name); - if (g_pHyprlock->m_bLocked && !POUTPUT->sessionLockSurface) { - // if we are already locked, create a surface dynamically - Debug::log(LOG, "Creating a surface dynamically for output as we are already locked"); - POUTPUT->sessionLockSurface = std::make_unique(POUTPUT); - } -} - -static void handleScale(void* data, wl_output* output, int32_t factor) { - const auto POUTPUT = (COutput*)data; - POUTPUT->scale = factor; -} - -static void handleName(void* data, wl_output* output, const char* name) { - const auto POUTPUT = (COutput*)data; - POUTPUT->stringName = std::string{name} + POUTPUT->stringName; - POUTPUT->stringPort = std::string{name}; - Debug::log(LOG, "output {} name {}", POUTPUT->name, name); -} - -static void handleDescription(void* data, wl_output* output, const char* description) { - const auto POUTPUT = (COutput*)data; - POUTPUT->stringDesc = description ? std::string{description} : ""; - Debug::log(LOG, "output {} description {}", POUTPUT->name, POUTPUT->stringDesc); -} - -static const wl_output_listener outputListener = { - .geometry = handleGeometry, - .mode = handleMode, - .done = handleDone, - .scale = handleScale, - .name = handleName, - .description = handleDescription, -}; - -COutput::COutput(wl_output* output, uint32_t name) : name(name), output(output) { - wl_output_add_listener(output, &outputListener, this); +COutput::COutput(SP output_, uint32_t name_) : name(name_), output(output_) { + output->setDescription([this](CCWlOutput* r, const char* description) { + stringDesc = description ? std::string{description} : ""; + Debug::log(LOG, "output {} description {}", name, stringDesc); + }); + + output->setName([this](CCWlOutput* r, const char* name) { + stringName = std::string{name} + stringName; + stringPort = std::string{name}; + Debug::log(LOG, "output {} name {}", name, name); + }); + + output->setScale([this](CCWlOutput* r, int32_t sc) { scale = sc; }); + + output->setDone([this](CCWlOutput* r) { + Debug::log(LOG, "output {} done", name); + if (g_pHyprlock->m_bLocked && !sessionLockSurface) { + // if we are already locked, create a surface dynamically + Debug::log(LOG, "Creating a surface dynamically for output as we are already locked"); + sessionLockSurface = std::make_unique(this); + } + }); + + output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { + // handle portrait mode and flipped cases + if (transform % 2 == 1) + size = {height, width}; + else + size = {width, height}; + }); + + output->setGeometry( + [this](CCWlOutput* r, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char* make, const char* model, int32_t transform) { + transform = (wl_output_transform)transform; + + Debug::log(LOG, "output {} make {} model {}", name, make ? make : "", model ? model : ""); + }); } diff --git a/src/core/Output.hpp b/src/core/Output.hpp index d6429024..d42c8008 100644 --- a/src/core/Output.hpp +++ b/src/core/Output.hpp @@ -1,13 +1,14 @@ #pragma once -#include +#include "../defines.hpp" +#include "wayland.hpp" #include "../helpers/Math.hpp" #include "LockSurface.hpp" #include class COutput { public: - COutput(wl_output* output, uint32_t name); + COutput(SP output, uint32_t name); uint32_t name = 0; bool focused = false; @@ -20,7 +21,7 @@ class COutput { std::unique_ptr sessionLockSurface; - wl_output* output = nullptr; + SP output = nullptr; private: }; diff --git a/src/core/Seat.cpp b/src/core/Seat.cpp new file mode 100644 index 00000000..1be3db6c --- /dev/null +++ b/src/core/Seat.cpp @@ -0,0 +1,138 @@ +#include "Seat.hpp" +#include "hyprlock.hpp" +#include "../helpers/Log.hpp" +#include "../config/ConfigManager.hpp" +#include +#include + +CSeatManager::~CSeatManager() { + if (m_pXKBState) + xkb_state_unref(m_pXKBState); + if (m_pXKBKeymap) + xkb_keymap_unref(m_pXKBKeymap); + if (m_pXKBContext) + xkb_context_unref(m_pXKBContext); +} + +void CSeatManager::registerSeat(SP seat) { + m_pSeat = seat; + + m_pXKBContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!m_pXKBContext) + Debug::log(ERR, "Failed to create xkb context"); + + m_pSeat->setCapabilities([this](CCWlSeat* r, wl_seat_capability caps) { + if (caps & WL_SEAT_CAPABILITY_POINTER) { + m_pPointer = makeShared(r->sendGetPointer()); + + m_pPointer->setMotion([](CCWlPointer* r, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + if (std::chrono::system_clock::now() > g_pHyprlock->m_tGraceEnds) + return; + + if (!g_pHyprlock->isUnlocked() && g_pHyprlock->m_vLastEnterCoords.distance({wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)}) > 5) { + Debug::log(LOG, "In grace and cursor moved more than 5px, unlocking!"); + g_pHyprlock->unlock(); + } + }); + + m_pPointer->setEnter([this](CCWlPointer* r, uint32_t serial, wl_proxy* surf, wl_fixed_t surface_x, wl_fixed_t surface_y) { + if (!m_pCursorShape) + return; + + static auto* const PHIDE = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:hide_cursor"); + + m_pCursorShape->lastCursorSerial = serial; + + if (**PHIDE) + m_pCursorShape->hideCursor(); + else + m_pCursorShape->setShape(wpCursorShapeDeviceV1Shape::WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT); + + g_pHyprlock->m_vLastEnterCoords = {wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)}; + }); + } + + if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { + m_pKeeb = makeShared(r->sendGetKeyboard()); + + m_pKeeb->setKeymap([this](CCWlKeyboard*, wl_keyboard_keymap_format format, int32_t fd, uint32_t size) { + if (!m_pXKBContext) + return; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + Debug::log(ERR, "Could not recognise keymap format"); + return; + } + + const char* buf = (const char*)mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (buf == MAP_FAILED) { + Debug::log(ERR, "Failed to mmap xkb keymap: {}", errno); + return; + } + + m_pXKBKeymap = xkb_keymap_new_from_buffer(m_pXKBContext, buf, size - 1, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + + munmap((void*)buf, size); + close(fd); + + if (!m_pXKBKeymap) { + Debug::log(ERR, "Failed to compile xkb keymap"); + return; + } + + m_pXKBState = xkb_state_new(m_pXKBKeymap); + if (!m_pXKBState) { + Debug::log(ERR, "Failed to create xkb state"); + return; + } + + const auto PCOMOPOSETABLE = xkb_compose_table_new_from_locale(m_pXKBContext, setlocale(LC_CTYPE, nullptr), XKB_COMPOSE_COMPILE_NO_FLAGS); + + if (!PCOMOPOSETABLE) { + Debug::log(ERR, "Failed to create xkb compose table"); + return; + } + + m_pXKBComposeState = xkb_compose_state_new(PCOMOPOSETABLE, XKB_COMPOSE_STATE_NO_FLAGS); + }); + + m_pKeeb->setKey([](CCWlKeyboard* r, uint32_t serial, uint32_t time, uint32_t key, wl_keyboard_key_state state) { + g_pHyprlock->onKey(key, state == WL_KEYBOARD_KEY_STATE_PRESSED); + }); + + m_pKeeb->setModifiers([this](CCWlKeyboard* r, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { + if (!m_pXKBState) + return; + + if (group != g_pHyprlock->m_uiActiveLayout) { + g_pHyprlock->m_uiActiveLayout = group; + for (auto& t : g_pHyprlock->getTimers()) { + if (t->canForceUpdate()) { + t->call(t); + t->cancel(); + } + } + } + + xkb_state_update_mask(m_pXKBState, mods_depressed, mods_latched, mods_locked, 0, 0, group); + g_pHyprlock->m_bCapsLock = xkb_state_mod_name_is_active(m_pXKBState, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED); + g_pHyprlock->m_bNumLock = xkb_state_mod_name_is_active(m_pXKBState, XKB_MOD_NAME_NUM, XKB_STATE_MODS_LOCKED); + }); + + m_pKeeb->setRepeatInfo([](CCWlKeyboard* r, int32_t rate, int32_t delay) { + g_pHyprlock->m_iKeebRepeatRate = rate; + g_pHyprlock->m_iKeebRepeatDelay = delay; + }); + } + }); + + m_pSeat->setName([](CCWlSeat* r, const char* name) { Debug::log(LOG, "Exposed seat name: {}", name ? name : "nullptr"); }); +} + +void CSeatManager::registerCursorShape(SP shape) { + m_pCursorShape = std::make_unique(shape); +} + +bool CSeatManager::registered() { + return m_pSeat; +} diff --git a/src/core/Seat.hpp b/src/core/Seat.hpp new file mode 100644 index 00000000..4a89738d --- /dev/null +++ b/src/core/Seat.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "../defines.hpp" +#include "CursorShape.hpp" +#include "wayland.hpp" +#include +#include +#include + +class CSeatManager { + public: + CSeatManager() = default; + ~CSeatManager(); + + void registerSeat(SP seat); + void registerCursorShape(SP shape); + bool registered(); + + SP m_pKeeb; + SP m_pPointer; + + std::unique_ptr m_pCursorShape; + + xkb_context* m_pXKBContext = nullptr; + xkb_keymap* m_pXKBKeymap = nullptr; + xkb_state* m_pXKBState = nullptr; + xkb_compose_state* m_pXKBComposeState = nullptr; + + private: + SP m_pSeat; +}; + +inline std::unique_ptr g_pSeatManager = std::make_unique(); diff --git a/src/core/hyprlock.cpp b/src/core/hyprlock.cpp index e2ec08bc..ccb85103 100644 --- a/src/core/hyprlock.cpp +++ b/src/core/hyprlock.cpp @@ -5,7 +5,6 @@ #include "../auth/Auth.hpp" #include "../auth/Fingerprint.hpp" #include "Egl.hpp" -#include "linux-dmabuf-unstable-v1-protocol.h" #include #include #include @@ -32,16 +31,11 @@ CHyprlock::CHyprlock(const std::string& wlDisplay, const bool immediate, const b g_pEGL = std::make_unique(m_sWaylandState.display); - m_pXKBContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!m_pXKBContext) - Debug::log(ERR, "Failed to create xkb context"); - if (!immediate) { const auto PGRACE = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:grace"); m_tGraceEnds = **PGRACE ? std::chrono::system_clock::now() + std::chrono::seconds(**PGRACE) : std::chrono::system_clock::from_time_t(0); - } else { + } else m_tGraceEnds = std::chrono::system_clock::from_time_t(0); - } const auto PIMMEDIATERENDER = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:immediate_render"); m_bImmediateRender = immediateRender || **PIMMEDIATERENDER; @@ -57,159 +51,55 @@ CHyprlock::CHyprlock(const std::string& wlDisplay, const bool immediate, const b CHyprlock::~CHyprlock() { if (dma.gbmDevice) gbm_device_destroy(dma.gbmDevice); - - if (m_pXKBState) - xkb_state_unref(m_pXKBState); - - if (m_pXKBKeymap) - xkb_keymap_unref(m_pXKBKeymap); -} - -// wl_seat - -static void handleCapabilities(void* data, wl_seat* wl_seat, uint32_t capabilities); -static void handleName(void* data, struct wl_seat* wl_seat, const char* name); - -inline const wl_seat_listener seatListener = { - .capabilities = handleCapabilities, - .name = handleName, -}; - -// end wl_seat - -// dmabuf - -static void handleDMABUFFormat(void* data, struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, uint32_t format) { - ; -} - -static void handleDMABUFModifier(void* data, struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) { - g_pHyprlock->dma.dmabufMods.push_back({format, (((uint64_t)modifier_hi) << 32) | modifier_lo}); } -inline const zwp_linux_dmabuf_v1_listener dmabufListener = { - .format = handleDMABUFFormat, - .modifier = handleDMABUFModifier, -}; - -static void dmabufFeedbackMainDevice(void* data, zwp_linux_dmabuf_feedback_v1* feedback, wl_array* device_arr) { - Debug::log(LOG, "[core] dmabufFeedbackMainDevice"); - - RASSERT(!g_pHyprlock->dma.gbm, "double dmabuf feedback"); - - dev_t device; - assert(device_arr->size == sizeof(device)); - memcpy(&device, device_arr->data, sizeof(device)); - - drmDevice* drmDev; - if (drmGetDeviceFromDevId(device, /* flags */ 0, &drmDev) != 0) { - Debug::log(WARN, "[dmabuf] unable to open main device?"); - exit(1); - } - - g_pHyprlock->dma.gbmDevice = g_pHyprlock->createGBMDevice(drmDev); - drmFreeDevice(&drmDev); +static void registerSignalAction(int sig, void (*handler)(int), int sa_flags = 0) { + struct sigaction sa; + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = sa_flags; + sigaction(sig, &sa, nullptr); } -static void dmabufFeedbackFormatTable(void* data, zwp_linux_dmabuf_feedback_v1* feedback, int fd, uint32_t size) { - Debug::log(TRACE, "[core] dmabufFeedbackFormatTable"); - - g_pHyprlock->dma.dmabufMods.clear(); - - g_pHyprlock->dma.formatTable = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - - if (g_pHyprlock->dma.formatTable == MAP_FAILED) { - Debug::log(ERR, "[core] format table failed to mmap"); - g_pHyprlock->dma.formatTable = nullptr; - g_pHyprlock->dma.formatTableSize = 0; - return; +static void handleUnlockSignal(int sig) { + if (sig == SIGUSR1) { + Debug::log(LOG, "Unlocking with a SIGUSR1"); + g_pHyprlock->releaseSessionLock(); } - - g_pHyprlock->dma.formatTableSize = size; -} - -static void dmabufFeedbackDone(void* data, zwp_linux_dmabuf_feedback_v1* feedback) { - Debug::log(TRACE, "[core] dmabufFeedbackDone"); - - if (g_pHyprlock->dma.formatTable) - munmap(g_pHyprlock->dma.formatTable, g_pHyprlock->dma.formatTableSize); - - g_pHyprlock->dma.formatTable = nullptr; - g_pHyprlock->dma.formatTableSize = 0; } -static void dmabufFeedbackTrancheTargetDevice(void* data, zwp_linux_dmabuf_feedback_v1* feedback, wl_array* device_arr) { - Debug::log(TRACE, "[core] dmabufFeedbackTrancheTargetDevice"); - - dev_t device; - assert(device_arr->size == sizeof(device)); - memcpy(&device, device_arr->data, sizeof(device)); - - drmDevice* drmDev; - if (drmGetDeviceFromDevId(device, /* flags */ 0, &drmDev) != 0) - return; - - if (g_pHyprlock->dma.gbmDevice) { - drmDevice* drmDevRenderer = NULL; - drmGetDevice2(gbm_device_get_fd(g_pHyprlock->dma.gbmDevice), /* flags */ 0, &drmDevRenderer); - g_pHyprlock->dma.deviceUsed = drmDevicesEqual(drmDevRenderer, drmDev); - } else { - g_pHyprlock->dma.gbmDevice = g_pHyprlock->createGBMDevice(drmDev); - g_pHyprlock->dma.deviceUsed = g_pHyprlock->dma.gbm; +static void handleForceUpdateSignal(int sig) { + if (sig == SIGUSR2) { + for (auto& t : g_pHyprlock->getTimers()) { + if (t->canForceUpdate()) { + t->call(t); + t->cancel(); + } + } } } -static void dmabufFeedbackTrancheFlags(void* data, zwp_linux_dmabuf_feedback_v1* feedback, uint32_t flags) { +static void handlePollTerminate(int sig) { ; } -static void dmabufFeedbackTrancheFormats(void* data, zwp_linux_dmabuf_feedback_v1* feedback, wl_array* indices) { - Debug::log(TRACE, "[core] dmabufFeedbackTrancheFormats"); - - if (!g_pHyprlock->dma.deviceUsed || !g_pHyprlock->dma.formatTable) - return; - - struct fm_entry { - uint32_t format; - uint32_t padding; - uint64_t modifier; - }; - // An entry in the table has to be 16 bytes long - assert(sizeof(fm_entry) == 16); - - uint32_t n_modifiers = g_pHyprlock->dma.formatTableSize / sizeof(fm_entry); - fm_entry* fm_entry = (struct fm_entry*)g_pHyprlock->dma.formatTable; - uint16_t* idx; - - for (idx = (uint16_t*)indices->data; (const char*)idx < (const char*)indices->data + indices->size; idx++) { - if (*idx >= n_modifiers) - continue; - - Debug::log(TRACE, "GPU Reports supported format {:x} with modifier {:x}", (fm_entry + *idx)->format, (fm_entry + *idx)->modifier); - - g_pHyprlock->dma.dmabufMods.push_back({(fm_entry + *idx)->format, (fm_entry + *idx)->modifier}); - } -} +static void handleCriticalSignal(int sig) { + g_pHyprlock->attemptRestoreOnDeath(); -static void dmabufFeedbackTrancheDone(void* data, struct zwp_linux_dmabuf_feedback_v1* zwp_linux_dmabuf_feedback_v1) { - Debug::log(TRACE, "[core] dmabufFeedbackTrancheDone"); + // remove our handlers + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGABRT, &sa, nullptr); + sigaction(SIGSEGV, &sa, nullptr); - g_pHyprlock->dma.deviceUsed = false; + abort(); } -inline const zwp_linux_dmabuf_feedback_v1_listener dmabufFeedbackListener = { - .done = dmabufFeedbackDone, - .format_table = dmabufFeedbackFormatTable, - .main_device = dmabufFeedbackMainDevice, - .tranche_done = dmabufFeedbackTrancheDone, - .tranche_target_device = dmabufFeedbackTrancheTargetDevice, - .tranche_formats = dmabufFeedbackTrancheFormats, - .tranche_flags = dmabufFeedbackTrancheFlags, -}; - static char* gbm_find_render_node(drmDevice* device) { drmDevice* devices[64]; - char* render_node = NULL; + char* render_node = nullptr; int n = drmGetDevices2(0, devices, sizeof(devices) / sizeof(devices[0])); for (int i = 0; i < n; ++i) { @@ -242,140 +132,175 @@ gbm_device* CHyprlock::createGBMDevice(drmDevice* dev) { if (fd < 0) { Debug::log(ERR, "[core] couldn't open render node"); free(renderNode); - return NULL; + return nullptr; } free(renderNode); return gbm_create_device(fd); } -// end dmabuf +void CHyprlock::addDmabufListener() { + dma.linuxDmabufFeedback->setTrancheDone([this](CCZwpLinuxDmabufFeedbackV1* r) { + Debug::log(TRACE, "[core] dmabufFeedbackTrancheDone"); -// wl_registry + dma.deviceUsed = false; + }); -static void handleGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) { - g_pHyprlock->onGlobal(data, registry, name, interface, version); -} + dma.linuxDmabufFeedback->setTrancheFormats([this](CCZwpLinuxDmabufFeedbackV1* r, wl_array* indices) { + Debug::log(TRACE, "[core] dmabufFeedbackTrancheFormats"); -static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name) { - g_pHyprlock->onGlobalRemoved(data, registry, name); -} + if (!dma.deviceUsed || !dma.formatTable) + return; -inline const wl_registry_listener registryListener = { - .global = handleGlobal, - .global_remove = handleGlobalRemove, -}; + struct fm_entry { + uint32_t format; + uint32_t padding; + uint64_t modifier; + }; + // An entry in the table has to be 16 bytes long + assert(sizeof(fm_entry) == 16); -void CHyprlock::onGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) { - const std::string IFACE = interface; - Debug::log(LOG, " | got iface: {} v{}", IFACE, version); + uint32_t n_modifiers = dma.formatTableSize / sizeof(fm_entry); + fm_entry* fm_entry = (struct fm_entry*)dma.formatTable; + uint16_t* idx; - if (IFACE == ext_session_lock_manager_v1_interface.name) { - m_sWaylandState.sessionLock = (ext_session_lock_manager_v1*)wl_registry_bind(registry, name, &ext_session_lock_manager_v1_interface, version); - Debug::log(LOG, " > Bound to {} v{}", IFACE, version); - } else if (IFACE == wl_seat_interface.name) { - if (m_sWaylandState.seat) { - Debug::log(WARN, "Hyprlock does not support multi-seat configurations. Only binding to the first seat."); - return; + for (idx = (uint16_t*)indices->data; (const char*)idx < (const char*)indices->data + indices->size; idx++) { + if (*idx >= n_modifiers) + continue; + + Debug::log(TRACE, "GPU Reports supported format {:x} with modifier {:x}", (fm_entry + *idx)->format, (fm_entry + *idx)->modifier); + + dma.dmabufMods.push_back({(fm_entry + *idx)->format, (fm_entry + *idx)->modifier}); } + }); - m_sWaylandState.seat = (wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, version); - wl_seat_add_listener(m_sWaylandState.seat, &seatListener, nullptr); - Debug::log(LOG, " > Bound to {} v{}", IFACE, version); - } else if (IFACE == wl_output_interface.name) { - m_vOutputs.emplace_back(std::make_unique((wl_output*)wl_registry_bind(registry, name, &wl_output_interface, version), name)); - Debug::log(LOG, " > Bound to {} v{}", IFACE, version); - } else if (IFACE == wp_cursor_shape_manager_v1_interface.name) { - m_pCursorShape = std::make_unique((wp_cursor_shape_manager_v1*)wl_registry_bind(registry, name, &wp_cursor_shape_manager_v1_interface, version)); - Debug::log(LOG, " > Bound to {} v{}", IFACE, version); - } else if (IFACE == wl_compositor_interface.name) { - m_sWaylandState.compositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, version); - Debug::log(LOG, " > Bound to {} v{}", IFACE, version); - } else if (IFACE == wp_fractional_scale_manager_v1_interface.name) { - m_sWaylandState.fractional = (wp_fractional_scale_manager_v1*)wl_registry_bind(registry, name, &wp_fractional_scale_manager_v1_interface, version); - Debug::log(LOG, " > Bound to {} v{}", IFACE, version); - } else if (IFACE == wp_viewporter_interface.name) { - m_sWaylandState.viewporter = (wp_viewporter*)wl_registry_bind(registry, name, &wp_viewporter_interface, version); - Debug::log(LOG, " > Bound to {} v{}", IFACE, version); - } else if (IFACE == zwp_linux_dmabuf_v1_interface.name) { - if (version < 4) { - Debug::log(ERR, "cannot use linux_dmabuf with ver < 4"); + dma.linuxDmabufFeedback->setTrancheTargetDevice([this](CCZwpLinuxDmabufFeedbackV1* r, wl_array* device_arr) { + Debug::log(TRACE, "[core] dmabufFeedbackTrancheTargetDevice"); + + dev_t device; + assert(device_arr->size == sizeof(device)); + memcpy(&device, device_arr->data, sizeof(device)); + + drmDevice* drmDev; + if (drmGetDeviceFromDevId(device, /* flags */ 0, &drmDev) != 0) return; + + if (dma.gbmDevice) { + drmDevice* drmDevRenderer = nullptr; + drmGetDevice2(gbm_device_get_fd(dma.gbmDevice), /* flags */ 0, &drmDevRenderer); + dma.deviceUsed = drmDevicesEqual(drmDevRenderer, drmDev); + } else { + dma.gbmDevice = createGBMDevice(drmDev); + dma.deviceUsed = dma.gbm; } + }); - dma.linuxDmabuf = wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, version); - dma.linuxDmabufFeedback = zwp_linux_dmabuf_v1_get_default_feedback((zwp_linux_dmabuf_v1*)dma.linuxDmabuf); - zwp_linux_dmabuf_feedback_v1_add_listener((zwp_linux_dmabuf_feedback_v1*)dma.linuxDmabufFeedback, &dmabufFeedbackListener, nullptr); - Debug::log(LOG, " > Bound to {} v{}", IFACE, version); - } else if (IFACE == zwlr_screencopy_manager_v1_interface.name) { - m_sWaylandState.screencopy = (zwlr_screencopy_manager_v1*)wl_registry_bind(registry, name, &zwlr_screencopy_manager_v1_interface, version); - Debug::log(LOG, " > Bound to {} v{}", IFACE, version); - } -} + dma.linuxDmabufFeedback->setDone([this](CCZwpLinuxDmabufFeedbackV1* r) { + Debug::log(TRACE, "[core] dmabufFeedbackDone"); -void CHyprlock::onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name) { - Debug::log(LOG, " | removed iface {}", name); - auto outputIt = std::find_if(m_vOutputs.begin(), m_vOutputs.end(), [name](const auto& other) { return other->name == name; }); - if (outputIt != m_vOutputs.end()) { - g_pRenderer->removeWidgetsFor(outputIt->get()->sessionLockSurface.get()); - m_vOutputs.erase(outputIt); - } -} + if (dma.formatTable) + munmap(dma.formatTable, dma.formatTableSize); -// end wl_registry + dma.formatTable = nullptr; + dma.formatTableSize = 0; + }); -static void registerSignalAction(int sig, void (*handler)(int), int sa_flags = 0) { - struct sigaction sa; - sa.sa_handler = handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = sa_flags; - sigaction(sig, &sa, NULL); -} + dma.linuxDmabufFeedback->setFormatTable([this](CCZwpLinuxDmabufFeedbackV1* r, int fd, uint32_t size) { + Debug::log(TRACE, "[core] dmabufFeedbackFormatTable"); -static void handleUnlockSignal(int sig) { - if (sig == SIGUSR1) { - Debug::log(LOG, "Unlocking with a SIGUSR1"); - g_pHyprlock->releaseSessionLock(); - } -} + dma.dmabufMods.clear(); -static void forceUpdateTimers() { - for (auto& t : g_pHyprlock->getTimers()) { - if (t->canForceUpdate()) { - t->call(t); - t->cancel(); + dma.formatTable = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); + + if (dma.formatTable == MAP_FAILED) { + Debug::log(ERR, "[core] format table failed to mmap"); + dma.formatTable = nullptr; + dma.formatTableSize = 0; + return; } - } -} -static void handleForceUpdateSignal(int sig) { - if (sig == SIGUSR2) { - forceUpdateTimers(); - } -} + dma.formatTableSize = size; + }); -static void handlePollTerminate(int sig) { - ; -} + dma.linuxDmabufFeedback->setMainDevice([this](CCZwpLinuxDmabufFeedbackV1* r, wl_array* device_arr) { + Debug::log(LOG, "[core] dmabufFeedbackMainDevice"); -static void handleCriticalSignal(int sig) { - g_pHyprlock->attemptRestoreOnDeath(); + RASSERT(!dma.gbm, "double dmabuf feedback"); - // remove our handlers - struct sigaction sa; - sa.sa_handler = SIG_IGN; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGABRT, &sa, NULL); - sigaction(SIGSEGV, &sa, NULL); + dev_t device; + assert(device_arr->size == sizeof(device)); + memcpy(&device, device_arr->data, sizeof(device)); - abort(); + drmDevice* drmDev; + if (drmGetDeviceFromDevId(device, /* flags */ 0, &drmDev) != 0) { + Debug::log(WARN, "[dmabuf] unable to open main device?"); + exit(1); + } + + dma.gbmDevice = createGBMDevice(drmDev); + drmFreeDevice(&drmDev); + }); + + dma.linuxDmabuf->setModifier([this](CCZwpLinuxDmabufV1* r, uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) { + dma.dmabufMods.push_back({format, (((uint64_t)modifier_hi) << 32) | modifier_lo}); + }); } void CHyprlock::run() { - m_sWaylandState.registry = wl_display_get_registry(m_sWaylandState.display); + m_sWaylandState.registry = makeShared((wl_proxy*)wl_display_get_registry(m_sWaylandState.display)); + m_sWaylandState.registry->setGlobal([this](CCWlRegistry* r, uint32_t name, const char* interface, uint32_t version) { + const std::string IFACE = interface; + Debug::log(LOG, " | got iface: {} v{}", IFACE, version); + + if (IFACE == zwp_linux_dmabuf_v1_interface.name) { + if (version < 4) { + Debug::log(ERR, "cannot use linux_dmabuf with ver < 4"); + return; + } + + dma.linuxDmabuf = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &zwp_linux_dmabuf_v1_interface, 4)); + dma.linuxDmabufFeedback = makeShared(dma.linuxDmabuf->sendGetDefaultFeedback()); - wl_registry_add_listener(m_sWaylandState.registry, ®istryListener, nullptr); + addDmabufListener(); + } else if (IFACE == wl_seat_interface.name) { + if (g_pSeatManager->registered()) { + Debug::log(WARN, "Hyprlock does not support multi-seat configurations. Only binding to the first seat."); + return; + } + + g_pSeatManager->registerSeat(makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wl_seat_interface, 9))); + } else if (IFACE == ext_session_lock_manager_v1_interface.name) + m_sWaylandState.sessionLock = + makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &ext_session_lock_manager_v1_interface, 1)); + else if (IFACE == wl_output_interface.name) + m_vOutputs.emplace_back( + std::make_unique(makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wl_output_interface, 4)), name)); + else if (IFACE == wp_cursor_shape_manager_v1_interface.name) + g_pSeatManager->registerCursorShape( + makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wp_cursor_shape_manager_v1_interface, 1))); + else if (IFACE == wl_compositor_interface.name) + m_sWaylandState.compositor = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wl_compositor_interface, 4)); + else if (IFACE == wp_fractional_scale_manager_v1_interface.name) + m_sWaylandState.fractional = + makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wp_fractional_scale_manager_v1_interface, 1)); + else if (IFACE == wp_viewporter_interface.name) + m_sWaylandState.viewporter = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wp_viewporter_interface, 1)); + else if (IFACE == zwlr_screencopy_manager_v1_interface.name) + m_sWaylandState.screencopy = + makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &zwlr_screencopy_manager_v1_interface, 3)); + else + return; + + Debug::log(LOG, " > Bound to {} v{}", IFACE, version); + }); + m_sWaylandState.registry->setGlobalRemove([this](CCWlRegistry* r, uint32_t name) { + Debug::log(LOG, " | removed iface {}", name); + auto outputIt = std::find_if(m_vOutputs.begin(), m_vOutputs.end(), [name](const auto& other) { return other->name == name; }); + if (outputIt != m_vOutputs.end()) { + g_pRenderer->removeWidgetsFor(outputIt->get()->sessionLockSurface.get()); + m_vOutputs.erase(outputIt); + } + }); wl_display_roundtrip(m_sWaylandState.display); @@ -576,18 +501,21 @@ void CHyprlock::run() { } } + const auto DPY = m_sWaylandState.display; + m_sLoopState.timerEvent = true; m_sLoopState.timerCV.notify_all(); g_pRenderer->asyncResourceGatherer->notify(); g_pRenderer->asyncResourceGatherer->await(); + m_sWaylandState = {}; + dma = {}; m_vOutputs.clear(); g_pEGL.reset(); - g_pRenderer = nullptr; - - xkb_context_unref(m_pXKBContext); + g_pRenderer.reset(); + g_pSeatManager.reset(); - wl_display_disconnect(m_sWaylandState.display); + wl_display_disconnect(DPY); pthread_kill(pollThr.native_handle(), SIGRTMIN); @@ -618,202 +546,6 @@ bool CHyprlock::isUnlocked() { return m_bFadeStarted || m_bTerminate; } -// wl_seat - -static void handlePointerEnter(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - if (!g_pHyprlock->m_pCursorShape) - return; - - static auto* const PHIDE = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:hide_cursor"); - - g_pHyprlock->m_pCursorShape->lastCursorSerial = serial; - - if (**PHIDE) - g_pHyprlock->m_pCursorShape->hideCursor(); - else - g_pHyprlock->m_pCursorShape->setShape(wp_cursor_shape_device_v1_shape::WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT); - - g_pHyprlock->m_vLastEnterCoords = {wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)}; -} - -static void handlePointerLeave(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface) { - ; -} - -static void handlePointerAxis(void* data, wl_pointer* wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { - // ignored -} - -static void handlePointerMotion(void* data, struct wl_pointer* wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - static auto* const PHIDE = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:hide_cursor"); - - if (std::chrono::system_clock::now() > g_pHyprlock->m_tGraceEnds) - return; - - if (!g_pHyprlock->isUnlocked() && g_pHyprlock->m_vLastEnterCoords.distance({wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)}) > 5) { - Debug::log(LOG, "In grace and cursor moved more than 5px, unlocking!"); - g_pHyprlock->unlock(); - } -} - -static void handlePointerButton(void* data, struct wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) { - ; -} - -static void handleFrame(void* data, struct wl_pointer* wl_pointer) { - ; -} - -static void handleAxisSource(void* data, struct wl_pointer* wl_pointer, uint32_t axis_source) { - ; -} - -static void handleAxisStop(void* data, struct wl_pointer* wl_pointer, uint32_t time, uint32_t axis) { - ; -} - -static void handleAxisDiscrete(void* data, struct wl_pointer* wl_pointer, uint32_t axis, int32_t discrete) { - ; -} - -static void handleAxisValue120(void* data, struct wl_pointer* wl_pointer, uint32_t axis, int32_t value120) { - ; -} - -static void handleAxisRelativeDirection(void* data, struct wl_pointer* wl_pointer, uint32_t axis, uint32_t direction) { - ; -} - -inline const wl_pointer_listener pointerListener = { - .enter = handlePointerEnter, - .leave = handlePointerLeave, - .motion = handlePointerMotion, - .button = handlePointerButton, - .axis = handlePointerAxis, - .frame = handleFrame, - .axis_source = handleAxisSource, - .axis_stop = handleAxisStop, - .axis_discrete = handleAxisDiscrete, - .axis_value120 = handleAxisValue120, - .axis_relative_direction = handleAxisRelativeDirection, -}; - -static void handleKeyboardKeymap(void* data, wl_keyboard* wl_keyboard, uint format, int fd, uint size) { - if (!g_pHyprlock->m_pXKBContext) - return; - - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - Debug::log(ERR, "Could not recognise keymap format"); - return; - } - - const char* buf = (const char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (buf == MAP_FAILED) { - Debug::log(ERR, "Failed to mmap xkb keymap: {}", errno); - return; - } - - g_pHyprlock->m_pXKBKeymap = xkb_keymap_new_from_buffer(g_pHyprlock->m_pXKBContext, buf, size - 1, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - - munmap((void*)buf, size); - close(fd); - - if (!g_pHyprlock->m_pXKBKeymap) { - Debug::log(ERR, "Failed to compile xkb keymap"); - return; - } - - g_pHyprlock->m_pXKBState = xkb_state_new(g_pHyprlock->m_pXKBKeymap); - if (!g_pHyprlock->m_pXKBState) { - Debug::log(ERR, "Failed to create xkb state"); - return; - } - - const auto PCOMOPOSETABLE = xkb_compose_table_new_from_locale(g_pHyprlock->m_pXKBContext, setlocale(LC_CTYPE, nullptr), XKB_COMPOSE_COMPILE_NO_FLAGS); - - if (!PCOMOPOSETABLE) { - Debug::log(ERR, "Failed to create xkb compose table"); - return; - } - - g_pHyprlock->m_pXKBComposeState = xkb_compose_state_new(PCOMOPOSETABLE, XKB_COMPOSE_STATE_NO_FLAGS); -} - -static void handleKeyboardKey(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - g_pHyprlock->onKey(key, state == WL_KEYBOARD_KEY_STATE_PRESSED); -} - -static void handleKeyboardEnter(void* data, wl_keyboard* wl_keyboard, uint serial, wl_surface* surface, wl_array* keys) { - ; -} - -static void handleKeyboardLeave(void* data, wl_keyboard* wl_keyboard, uint serial, wl_surface* surface) { - ; -} - -static void handleKeyboardModifiers(void* data, wl_keyboard* wl_keyboard, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group) { - if (!g_pHyprlock->m_pXKBState) - return; - - if (group != g_pHyprlock->m_uiActiveLayout) { - g_pHyprlock->m_uiActiveLayout = group; - forceUpdateTimers(); - } - - xkb_state_update_mask(g_pHyprlock->m_pXKBState, mods_depressed, mods_latched, mods_locked, 0, 0, group); - g_pHyprlock->m_bCapsLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED); - g_pHyprlock->m_bNumLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_NUM, XKB_STATE_MODS_LOCKED); -} - -static void handleRepeatInfo(void* data, struct wl_keyboard* wl_keyboard, int32_t rate, int32_t delay) { - g_pHyprlock->m_iKeebRepeatRate = rate; - g_pHyprlock->m_iKeebRepeatDelay = delay; -} - -inline const wl_keyboard_listener keyboardListener = { - .keymap = handleKeyboardKeymap, - .enter = handleKeyboardEnter, - .leave = handleKeyboardLeave, - .key = handleKeyboardKey, - .modifiers = handleKeyboardModifiers, - .repeat_info = handleRepeatInfo, -}; - -static void handleCapabilities(void* data, wl_seat* wl_seat, uint32_t capabilities) { - if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - g_pHyprlock->m_pPointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(g_pHyprlock->m_pPointer, &pointerListener, wl_seat); - } - - if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - g_pHyprlock->m_pKeeb = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(g_pHyprlock->m_pKeeb, &keyboardListener, wl_seat); - } -} - -static void handleName(void* data, struct wl_seat* wl_seat, const char* name) { - ; -} - -// end wl_seat - -// session_lock - -static void handleLocked(void* data, ext_session_lock_v1* ext_session_lock_v1) { - g_pHyprlock->onLockLocked(); -} - -static void handleFinished(void* data, ext_session_lock_v1* ext_session_lock_v1) { - g_pHyprlock->onLockFinished(); -} - -static const ext_session_lock_v1_listener sessionLockListener = { - .locked = handleLocked, - .finished = handleFinished, -}; - -// end session_lock - void CHyprlock::clearPasswordBuffer() { if (m_sPasswordState.passBuffer.empty()) return; @@ -852,8 +584,8 @@ void CHyprlock::startKeyRepeat(xkb_keysym_t sym) { m_pKeyRepeatTimer.reset(); } - if (m_pXKBComposeState) - xkb_compose_state_reset(m_pXKBComposeState); + if (g_pSeatManager->m_pXKBComposeState) + xkb_compose_state_reset(g_pSeatManager->m_pXKBComposeState); if (m_iKeebRepeatDelay <= 0) return; @@ -907,16 +639,16 @@ void CHyprlock::onKey(uint32_t key, bool down) { } if (down) { - m_bCapsLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED); - m_bNumLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_NUM, XKB_STATE_MODS_LOCKED); - m_bCtrl = xkb_state_mod_name_is_active(m_pXKBState, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE); + m_bCapsLock = xkb_state_mod_name_is_active(g_pSeatManager->m_pXKBState, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED); + m_bNumLock = xkb_state_mod_name_is_active(g_pSeatManager->m_pXKBState, XKB_MOD_NAME_NUM, XKB_STATE_MODS_LOCKED); + m_bCtrl = xkb_state_mod_name_is_active(g_pSeatManager->m_pXKBState, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE); - const auto SYM = xkb_state_key_get_one_sym(m_pXKBState, key + 8); + const auto SYM = xkb_state_key_get_one_sym(g_pSeatManager->m_pXKBState, key + 8); enum xkb_compose_status composeStatus = XKB_COMPOSE_NOTHING; - if (m_pXKBComposeState) { - xkb_compose_state_feed(m_pXKBComposeState, SYM); - composeStatus = xkb_compose_state_get_status(m_pXKBComposeState); + if (g_pSeatManager->m_pXKBComposeState) { + xkb_compose_state_feed(g_pSeatManager->m_pXKBComposeState, SYM); + composeStatus = xkb_compose_state_get_status(g_pSeatManager->m_pXKBComposeState); } handleKeySym(SYM, composeStatus == XKB_COMPOSE_COMPOSED); @@ -924,8 +656,8 @@ void CHyprlock::onKey(uint32_t key, bool down) { if (SYM == XKB_KEY_BackSpace || SYM == XKB_KEY_Delete) // keys allowed to repeat startKeyRepeat(SYM); - } else if (m_pXKBComposeState && xkb_compose_state_get_status(m_pXKBComposeState) == XKB_COMPOSE_COMPOSED) - xkb_compose_state_reset(m_pXKBComposeState); + } else if (g_pSeatManager->m_pXKBComposeState && xkb_compose_state_get_status(g_pSeatManager->m_pXKBComposeState) == XKB_COMPOSE_COMPOSED) + xkb_compose_state_reset(g_pSeatManager->m_pXKBComposeState); renderAllOutputs(); } @@ -961,7 +693,7 @@ void CHyprlock::handleKeySym(xkb_keysym_t sym, bool composed) { m_bNumLock = !m_bNumLock; } else { char buf[16] = {0}; - int len = (composed) ? xkb_compose_state_get_utf8(m_pXKBComposeState, buf, sizeof(buf)) /* nullbyte */ + 1 : + int len = (composed) ? xkb_compose_state_get_utf8(g_pSeatManager->m_pXKBComposeState, buf, sizeof(buf)) /* nullbyte */ + 1 : xkb_keysym_to_utf8(SYM, buf, sizeof(buf)) /* already includes a nullbyte */; if (len > 1) @@ -971,8 +703,11 @@ void CHyprlock::handleKeySym(xkb_keysym_t sym, bool composed) { void CHyprlock::acquireSessionLock() { Debug::log(LOG, "Locking session"); - m_sLockState.lock = ext_session_lock_manager_v1_lock(m_sWaylandState.sessionLock); - ext_session_lock_v1_add_listener(m_sLockState.lock, &sessionLockListener, nullptr); + m_sLockState.lock = makeShared(m_sWaylandState.sessionLock->sendLock()); + + m_sLockState.lock->setLocked([this](CCExtSessionLockV1* r) { onLockLocked(); }); + + m_sLockState.lock->setFinished([this](CCExtSessionLockV1* r) { onLockFinished(); }); // roundtrip in case the compositor sends `finished` right away wl_display_roundtrip(m_sWaylandState.display); @@ -996,7 +731,7 @@ void CHyprlock::releaseSessionLock() { return; } - ext_session_lock_v1_unlock_and_destroy(m_sLockState.lock); + m_sLockState.lock->sendUnlockAndDestroy(); m_sLockState.lock = nullptr; Debug::log(LOG, "Unlocked, exiting!"); @@ -1030,24 +765,24 @@ void CHyprlock::onLockFinished() { if (m_bLocked) // The `finished` event specifies that whenever the `locked` event has been recieved and the compositor sends `finished`, // `unlock_and_destroy` should be called by the client. - // This does not mean the session gets unlocked! That is ultimatly the responsiblity of the compositor. - ext_session_lock_v1_unlock_and_destroy(m_sLockState.lock); + // This does not mean the session gets unlocked! That is ultimately the responsiblity of the compositor. + m_sLockState.lock->sendUnlockAndDestroy(); else - ext_session_lock_v1_destroy(m_sLockState.lock); + m_sLockState.lock.reset(); m_sLockState.lock = nullptr; m_bTerminate = true; } -ext_session_lock_manager_v1* CHyprlock::getSessionLockMgr() { +SP CHyprlock::getSessionLockMgr() { return m_sWaylandState.sessionLock; } -ext_session_lock_v1* CHyprlock::getSessionLock() { +SP CHyprlock::getSessionLock() { return m_sLockState.lock; } -wl_compositor* CHyprlock::getCompositor() { +SP CHyprlock::getCompositor() { return m_sWaylandState.compositor; } @@ -1055,11 +790,11 @@ wl_display* CHyprlock::getDisplay() { return m_sWaylandState.display; } -wp_fractional_scale_manager_v1* CHyprlock::getFractionalMgr() { +SP CHyprlock::getFractionalMgr() { return m_sWaylandState.fractional; } -wp_viewporter* CHyprlock::getViewporter() { +SP CHyprlock::getViewporter() { return m_sWaylandState.viewporter; } @@ -1086,7 +821,17 @@ std::vector> CHyprlock::getTimers() { } void CHyprlock::enqueueForceUpdateTimers() { - addTimer(std::chrono::milliseconds(1), [](std::shared_ptr self, void* data) { forceUpdateTimers(); }, nullptr, false); + addTimer( + std::chrono::milliseconds(1), + [](std::shared_ptr self, void* data) { + for (auto& t : g_pHyprlock->getTimers()) { + if (t->canForceUpdate()) { + t->call(t); + t->cancel(); + } + } + }, + nullptr, false); } std::string CHyprlock::spawnSync(const std::string& cmd) { @@ -1102,7 +847,7 @@ std::string CHyprlock::spawnSync(const std::string& cmd) { return proc.stdOut(); } -zwlr_screencopy_manager_v1* CHyprlock::getScreencopy() { +SP CHyprlock::getScreencopy() { return m_sWaylandState.screencopy; } @@ -1146,7 +891,7 @@ void CHyprlock::attemptRestoreOnDeath() { ofs.close(); if (m_bLocked && m_sLockState.lock) { - ext_session_lock_v1_destroy(m_sLockState.lock); + m_sLockState.lock.reset(); // Destroy sessionLockSurfaces m_vOutputs.clear(); diff --git a/src/core/hyprlock.hpp b/src/core/hyprlock.hpp index 8b2cdf85..2655cd6e 100644 --- a/src/core/hyprlock.hpp +++ b/src/core/hyprlock.hpp @@ -1,11 +1,14 @@ #pragma once -#include -#include "ext-session-lock-v1-protocol.h" -#include "fractional-scale-v1-protocol.h" -#include "wlr-screencopy-unstable-v1-protocol.h" -#include "viewporter-protocol.h" +#include "../defines.hpp" +#include "wayland.hpp" +#include "ext-session-lock-v1.hpp" +#include "fractional-scale-v1.hpp" +#include "wlr-screencopy-unstable-v1.hpp" +#include "linux-dmabuf-v1.hpp" +#include "viewporter.hpp" #include "Output.hpp" +#include "Seat.hpp" #include "CursorShape.hpp" #include "Timer.hpp" #include @@ -29,82 +32,73 @@ class CHyprlock { CHyprlock(const std::string& wlDisplay, const bool immediate, const bool immediateRender, const bool noFadeIn); ~CHyprlock(); - void run(); + void run(); - void unlock(); - bool isUnlocked(); + void unlock(); + bool isUnlocked(); - void onGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version); - void onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name); + void onGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version); + void onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name); - std::shared_ptr addTimer(const std::chrono::system_clock::duration& timeout, std::function self, void* data)> cb_, void* data, - bool force = false); + std::shared_ptr addTimer(const std::chrono::system_clock::duration& timeout, std::function self, void* data)> cb_, void* data, + bool force = false); - void enqueueForceUpdateTimers(); + void enqueueForceUpdateTimers(); - void onLockLocked(); - void onLockFinished(); + void onLockLocked(); + void onLockFinished(); - void acquireSessionLock(); - void releaseSessionLock(); + void acquireSessionLock(); + void releaseSessionLock(); - void createSessionLockSurfaces(); + void createSessionLockSurfaces(); - void attemptRestoreOnDeath(); + void attemptRestoreOnDeath(); - std::string spawnSync(const std::string& cmd); + std::string spawnSync(const std::string& cmd); - void onKey(uint32_t key, bool down); - void startKeyRepeat(xkb_keysym_t sym); - void repeatKey(xkb_keysym_t sym); - void handleKeySym(xkb_keysym_t sym, bool compose); - void onPasswordCheckTimer(); - void clearPasswordBuffer(); - bool passwordCheckWaiting(); - std::optional passwordLastFailReason(); + void onKey(uint32_t key, bool down); + void startKeyRepeat(xkb_keysym_t sym); + void repeatKey(xkb_keysym_t sym); + void handleKeySym(xkb_keysym_t sym, bool compose); + void onPasswordCheckTimer(); + void clearPasswordBuffer(); + bool passwordCheckWaiting(); + std::optional passwordLastFailReason(); - void renderOutput(const std::string& stringPort); - void renderAllOutputs(); + void renderOutput(const std::string& stringPort); + void renderAllOutputs(); - size_t getPasswordBufferLen(); - size_t getPasswordBufferDisplayLen(); + size_t getPasswordBufferLen(); + size_t getPasswordBufferDisplayLen(); - ext_session_lock_manager_v1* getSessionLockMgr(); - ext_session_lock_v1* getSessionLock(); - wl_compositor* getCompositor(); - wl_display* getDisplay(); - wp_fractional_scale_manager_v1* getFractionalMgr(); - wp_viewporter* getViewporter(); - zwlr_screencopy_manager_v1* getScreencopy(); + SP getSessionLockMgr(); + SP getSessionLock(); + SP getCompositor(); + wl_display* getDisplay(); + SP getFractionalMgr(); + SP getViewporter(); + SP getScreencopy(); - wl_pointer* m_pPointer = nullptr; - std::unique_ptr m_pCursorShape; + int32_t m_iKeebRepeatRate = 25; + int32_t m_iKeebRepeatDelay = 600; - wl_keyboard* m_pKeeb = nullptr; - xkb_context* m_pXKBContext = nullptr; - xkb_keymap* m_pXKBKeymap = nullptr; - xkb_state* m_pXKBState = nullptr; - xkb_compose_state* m_pXKBComposeState = nullptr; + xkb_layout_index_t m_uiActiveLayout = 0; - int32_t m_iKeebRepeatRate = 25; - int32_t m_iKeebRepeatDelay = 600; + bool m_bTerminate = false; - xkb_layout_index_t m_uiActiveLayout = 0; + bool m_bLocked = false; - bool m_bTerminate = false; + bool m_bCapsLock = false; + bool m_bNumLock = false; + bool m_bCtrl = false; + bool m_bFadeStarted = false; - bool m_bLocked = false; + bool m_bImmediateRender = false; - bool m_bCapsLock = false; - bool m_bNumLock = false; - bool m_bCtrl = false; - bool m_bFadeStarted = false; + bool m_bNoFadeIn = false; - bool m_bImmediateRender = false; - - bool m_bNoFadeIn = false; - - std::string m_sCurrentDesktop = ""; + std::string m_sCurrentDesktop = ""; // std::chrono::system_clock::time_point m_tGraceEnds; @@ -117,34 +111,35 @@ class CHyprlock { std::vector> getTimers(); struct { - void* linuxDmabuf = nullptr; - void* linuxDmabufFeedback = nullptr; + SP linuxDmabuf = nullptr; + SP linuxDmabufFeedback = nullptr; - gbm_bo* gbm = nullptr; - gbm_device* gbmDevice = nullptr; + gbm_bo* gbm = nullptr; + gbm_device* gbmDevice = nullptr; - void* formatTable = nullptr; - size_t formatTableSize = 0; - bool deviceUsed = false; + void* formatTable = nullptr; + size_t formatTableSize = 0; + bool deviceUsed = false; - std::vector dmabufMods; + std::vector dmabufMods; } dma; gbm_device* createGBMDevice(drmDevice* dev); private: struct { - wl_display* display = nullptr; - wl_registry* registry = nullptr; - wl_seat* seat = nullptr; - ext_session_lock_manager_v1* sessionLock = nullptr; - wl_compositor* compositor = nullptr; - wp_fractional_scale_manager_v1* fractional = nullptr; - wp_viewporter* viewporter = nullptr; - zwlr_screencopy_manager_v1* screencopy = nullptr; + wl_display* display = nullptr; + SP registry = nullptr; + SP sessionLock = nullptr; + SP compositor = nullptr; + SP fractional = nullptr; + SP viewporter = nullptr; + SP screencopy = nullptr; } m_sWaylandState; + void addDmabufListener(); + struct { - ext_session_lock_v1* lock = nullptr; + SP lock = nullptr; } m_sLockState; struct { diff --git a/src/renderer/DMAFrame.cpp b/src/renderer/DMAFrame.cpp index 134ad034..d7572c74 100644 --- a/src/renderer/DMAFrame.cpp +++ b/src/renderer/DMAFrame.cpp @@ -1,6 +1,4 @@ #include "DMAFrame.hpp" -#include "linux-dmabuf-unstable-v1-protocol.h" -#include "wlr-screencopy-unstable-v1-protocol.h" #include "../helpers/Log.hpp" #include "../core/hyprlock.hpp" #include "../core/Egl.hpp" @@ -15,77 +13,6 @@ static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullpt static PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr; // -static void wlrOnBuffer(void* data, zwlr_screencopy_frame_v1* frame, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) { - const auto PDATA = (SScreencopyData*)data; - - Debug::log(TRACE, "[sc] wlrOnBuffer for {}", (void*)PDATA); - - PDATA->size = stride * height; - PDATA->stride = stride; -} - -static void wlrOnFlags(void* data, zwlr_screencopy_frame_v1* frame, uint32_t flags) { - ; -} - -static void wlrOnReady(void* data, zwlr_screencopy_frame_v1* frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) { - const auto PDATA = (SScreencopyData*)data; - - Debug::log(TRACE, "[sc] wlrOnReady for {}", (void*)PDATA); - - if (!PDATA->frame->onBufferReady()) { - Debug::log(ERR, "onBufferReady failed"); - return; - } - - zwlr_screencopy_frame_v1_destroy(frame); -} - -static void wlrOnFailed(void* data, zwlr_screencopy_frame_v1* frame) { - ; -} - -static void wlrOnDamage(void* data, zwlr_screencopy_frame_v1* frame, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { - ; -} - -static void wlrOnDmabuf(void* data, zwlr_screencopy_frame_v1* frame, uint32_t format, uint32_t width, uint32_t height) { - const auto PDATA = (SScreencopyData*)data; - - Debug::log(TRACE, "[sc] wlrOnDmabuf for {}", (void*)PDATA); - - PDATA->w = width; - PDATA->h = height; - PDATA->fmt = format; - - Debug::log(TRACE, "[sc] DMABUF format reported: {:x}", format); -} - -static void wlrOnBufferDone(void* data, zwlr_screencopy_frame_v1* frame) { - const auto PDATA = (SScreencopyData*)data; - - Debug::log(TRACE, "[sc] wlrOnBufferDone for {}", (void*)PDATA); - - if (!PDATA->frame->onBufferDone()) { - Debug::log(ERR, "onBufferDone failed"); - return; - } - - zwlr_screencopy_frame_v1_copy(frame, PDATA->frame->wlBuffer); - - Debug::log(TRACE, "[sc] wlr frame copied"); -} - -static const zwlr_screencopy_frame_v1_listener wlrFrameListener = { - .buffer = wlrOnBuffer, - .flags = wlrOnFlags, - .ready = wlrOnReady, - .failed = wlrOnFailed, - .damage = wlrOnDamage, - .linux_dmabuf = wlrOnDmabuf, - .buffer_done = wlrOnBufferDone, -}; - std::string CDMAFrame::getResourceId(COutput* output) { return std::format("dma:{}-{}x{}", output->stringPort, output->size.x, output->size.y); } @@ -105,11 +32,48 @@ CDMAFrame::CDMAFrame(COutput* output_) { eglQueryDmaBufModifiersEXT = (PFNEGLQUERYDMABUFMODIFIERSEXTPROC)eglGetProcAddress("eglQueryDmaBufModifiersEXT"); // firstly, plant a listener for the frame - frameCb = zwlr_screencopy_manager_v1_capture_output(g_pHyprlock->getScreencopy(), false, output_->output); + frameCb = makeShared(g_pHyprlock->getScreencopy()->sendCaptureOutput(false, output_->output->resource())); + + frameCb->setBufferDone([this](CCZwlrScreencopyFrameV1* r) { + Debug::log(TRACE, "[sc] wlrOnBufferDone for {}", (void*)this); + + if (!onBufferDone()) { + Debug::log(ERR, "onBufferDone failed"); + return; + } + + frameCb->sendCopy(wlBuffer->resource()); + + Debug::log(TRACE, "[sc] wlr frame copied"); + }); + + frameCb->setLinuxDmabuf([this](CCZwlrScreencopyFrameV1* r, uint32_t format, uint32_t width, uint32_t height) { + Debug::log(TRACE, "[sc] wlrOnDmabuf for {}", (void*)this); + + w = width; + h = height; + fmt = format; + + Debug::log(TRACE, "[sc] DMABUF format reported: {:x}", format); + }); + + frameCb->setReady([this](CCZwlrScreencopyFrameV1* r, uint32_t, uint32_t, uint32_t) { + Debug::log(TRACE, "[sc] wlrOnReady for {}", (void*)this); + + if (!onBufferReady()) { + Debug::log(ERR, "onBufferReady failed"); + return; + } + + frameCb.reset(); + }); - scdata.frame = this; + frameCb->setBuffer([this](CCZwlrScreencopyFrameV1* r, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) { + Debug::log(TRACE, "[sc] wlrOnBuffer for {}", (void*)this); - zwlr_screencopy_frame_v1_add_listener(frameCb, &wlrFrameListener, &scdata); + frameSize = stride * height; + frameStride = stride; + }); } CDMAFrame::~CDMAFrame() { @@ -124,16 +88,16 @@ bool CDMAFrame::onBufferDone() { if (!eglQueryDmaBufModifiersEXT) { Debug::log(WARN, "Querying modifiers without eglQueryDmaBufModifiersEXT support"); - bo = gbm_bo_create(g_pHyprlock->dma.gbmDevice, scdata.w, scdata.h, scdata.fmt, flags); + bo = gbm_bo_create(g_pHyprlock->dma.gbmDevice, w, h, fmt, flags); } else { std::vector mods; mods.resize(64); std::vector externalOnly; externalOnly.resize(64); int num = 0; - if (!eglQueryDmaBufModifiersEXT(g_pEGL->eglDisplay, scdata.fmt, 64, mods.data(), externalOnly.data(), &num) || num == 0) { + if (!eglQueryDmaBufModifiersEXT(g_pEGL->eglDisplay, fmt, 64, mods.data(), externalOnly.data(), &num) || num == 0) { Debug::log(WARN, "eglQueryDmaBufModifiersEXT failed, falling back to regular bo"); - bo = gbm_bo_create(g_pHyprlock->dma.gbmDevice, scdata.w, scdata.h, scdata.fmt, flags); + bo = gbm_bo_create(g_pHyprlock->dma.gbmDevice, w, h, fmt, flags); } else { Debug::log(LOG, "eglQueryDmaBufModifiersEXT found {} mods", num); std::vector goodMods; @@ -150,8 +114,7 @@ bool CDMAFrame::onBufferDone() { uint64_t zero = 0; bool hasLinear = std::find(goodMods.begin(), goodMods.end(), 0) != goodMods.end(); - bo = gbm_bo_create_with_modifiers2(g_pHyprlock->dma.gbmDevice, scdata.w, scdata.h, scdata.fmt, hasLinear ? &zero : goodMods.data(), hasLinear ? 1 : goodMods.size(), - flags); + bo = gbm_bo_create_with_modifiers2(g_pHyprlock->dma.gbmDevice, w, h, fmt, hasLinear ? &zero : goodMods.data(), hasLinear ? 1 : goodMods.size(), flags); } } @@ -165,7 +128,7 @@ bool CDMAFrame::onBufferDone() { uint64_t mod = gbm_bo_get_modifier(bo); Debug::log(LOG, "bo chose modifier {:x}", mod); - zwp_linux_buffer_params_v1* params = zwp_linux_dmabuf_v1_create_params((zwp_linux_dmabuf_v1*)g_pHyprlock->dma.linuxDmabuf); + auto params = makeShared(g_pHyprlock->dma.linuxDmabuf->sendCreateParams()); if (!params) { Debug::log(ERR, "zwp_linux_dmabuf_v1_create_params failed"); gbm_bo_destroy(bo); @@ -180,7 +143,7 @@ bool CDMAFrame::onBufferDone() { if (fd[plane] < 0) { Debug::log(ERR, "gbm_bo_get_fd_for_plane failed"); - zwp_linux_buffer_params_v1_destroy(params); + params.reset(); gbm_bo_destroy(bo); for (size_t plane_tmp = 0; plane_tmp < plane; plane_tmp++) { close(fd[plane_tmp]); @@ -188,11 +151,11 @@ bool CDMAFrame::onBufferDone() { return false; } - zwp_linux_buffer_params_v1_add(params, fd[plane], plane, offset[plane], stride[plane], mod >> 32, mod & 0xffffffff); + params->sendAdd(fd[plane], plane, offset[plane], stride[plane], mod >> 32, mod & 0xffffffff); } - wlBuffer = zwp_linux_buffer_params_v1_create_immed(params, scdata.w, scdata.h, scdata.fmt, 0); - zwp_linux_buffer_params_v1_destroy(params); + wlBuffer = makeShared(params->sendCreateImmed(w, h, fmt, (zwpLinuxBufferParamsV1Flags)0)); + params.reset(); if (!wlBuffer) { Debug::log(ERR, "[pw] zwp_linux_buffer_params_v1_create_immed failed"); @@ -212,14 +175,14 @@ bool CDMAFrame::onBufferReady() { static const int entries_per_attrib = 2; EGLAttrib attribs[(general_attribs + plane_attribs * 4) * entries_per_attrib + 1]; int attr = 0; - Vector2D size{scdata.w, scdata.h}; + Vector2D size{w, h}; attribs[attr++] = EGL_WIDTH; attribs[attr++] = size.x; attribs[attr++] = EGL_HEIGHT; attribs[attr++] = size.y; attribs[attr++] = EGL_LINUX_DRM_FOURCC_EXT; - attribs[attr++] = scdata.fmt; + attribs[attr++] = fmt; attribs[attr++] = EGL_DMA_BUF_PLANE0_FD_EXT; attribs[attr++] = fd[0]; attribs[attr++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; diff --git a/src/renderer/DMAFrame.hpp b/src/renderer/DMAFrame.hpp index e4b7c667..0b26abdf 100644 --- a/src/renderer/DMAFrame.hpp +++ b/src/renderer/DMAFrame.hpp @@ -1,21 +1,14 @@ #pragma once +#include "../defines.hpp" #include "../core/Output.hpp" #include #include "Shared.hpp" - -struct zwlr_screencopy_frame_v1; +#include "linux-dmabuf-v1.hpp" +#include "wlr-screencopy-unstable-v1.hpp" class CDMAFrame; -struct SScreencopyData { - int w = 0, h = 0; - uint32_t fmt; - size_t size; - size_t stride; - CDMAFrame* frame = nullptr; -}; - class CDMAFrame { public: static std::string getResourceId(COutput* output); @@ -26,22 +19,25 @@ class CDMAFrame { bool onBufferDone(); bool onBufferReady(); - wl_buffer* wlBuffer = nullptr; + SP wlBuffer = nullptr; std::string resourceID; SPreloadedAsset asset; private: - gbm_bo* bo = nullptr; + gbm_bo* bo = nullptr; - int planes = 0; + int planes = 0; - int fd[4]; - uint32_t size[4], stride[4], offset[4]; + int fd[4]; + uint32_t size[4], stride[4], offset[4]; - zwlr_screencopy_frame_v1* frameCb = nullptr; - SScreencopyData scdata; + SP frameCb = nullptr; + int w = 0, h = 0; + uint32_t fmt = 0; + size_t frameSize = 0; + size_t frameStride = 0; - EGLImage image = nullptr; + EGLImage image = nullptr; }; \ No newline at end of file diff --git a/src/renderer/widgets/IWidget.cpp b/src/renderer/widgets/IWidget.cpp index 30b88e13..cc133d67 100644 --- a/src/renderer/widgets/IWidget.cpp +++ b/src/renderer/widgets/IWidget.cpp @@ -101,7 +101,7 @@ static void replaceAllAttempts(std::string& str) { static void replaceAllLayout(std::string& str) { const auto LAYOUTIDX = g_pHyprlock->m_uiActiveLayout; - const auto LAYOUTNAME = xkb_keymap_layout_get_name(g_pHyprlock->m_pXKBKeymap, LAYOUTIDX); + const auto LAYOUTNAME = xkb_keymap_layout_get_name(g_pSeatManager->m_pXKBKeymap, LAYOUTIDX); const std::string STR = LAYOUTNAME ? LAYOUTNAME : "error"; size_t pos = 0;