Core: move to hyprwayland-scanner (#624)

nix: add hyprwayland-scanner dep

flake.lock: update

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
Vaxry 2024-12-29 18:36:08 +00:00 committed by GitHub
parent 77d194c1e9
commit 753c538dea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 724 additions and 882 deletions

4
.gitignore vendored
View file

@ -8,6 +8,6 @@ Makefile
cmake_install.cmake
build/
compile_commands.json
protocols/*.c
protocols/*.h
protocols/*.cpp
protocols/*.hpp
*.kdev4

View file

@ -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)

View file

@ -28,6 +28,7 @@ You need the following dependencies
- wayland-client
- wayland-protocols
- mesa
- hyprwayland-scanner
And the development libraries for the following
- cairo

View file

@ -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"
}

View file

@ -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 = {

View file

@ -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
];

View file

@ -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 {

View file

@ -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<CCWpCursorShapeManagerV1> mgr) : mgr(mgr) {
if (!g_pSeatManager->m_pPointer)
return;
dev = wp_cursor_shape_manager_v1_get_pointer(mgr, g_pHyprlock->m_pPointer);
dev = makeShared<CCWpCursorShapeDeviceV1>(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);
}

View file

@ -1,18 +1,18 @@
#pragma once
#include <wayland-client.h>
#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<CCWpCursorShapeManagerV1> 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<CCWpCursorShapeManagerV1> mgr = nullptr;
SP<CCWpCursorShapeDeviceV1> dev = nullptr;
};

View file

@ -1,6 +1,5 @@
#pragma once
#include <wayland-client.h>
#include <memory>
#include <EGL/egl.h>

View file

@ -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<CCWlSurface>(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<CCWpFractionalScaleV1>(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<CCWpViewport>(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<CCExtSessionLockSurfaceV1>(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<CCWlCallback>(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;

View file

@ -1,9 +1,10 @@
#pragma once
#include <wayland-client.h>
#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 <wayland-egl.h>
#include <EGL/egl.h>
@ -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;
COutput* output = nullptr;
SP<CCWlSurface> surface = nullptr;
SP<CCExtSessionLockSurfaceV1> lockSurface = nullptr;
uint32_t serial = 0;
wl_egl_window* eglWindow = nullptr;
Vector2D size;
Vector2D logicalSize;
float appliedScale;
EGLSurface eglSurface = nullptr;
SP<CCWpFractionalScaleV1> fractional = nullptr;
SP<CCWpViewport> viewport = nullptr;
bool needsFrame = false;
bool needsFrame = false;
// wayland callbacks
wl_callback* frameCallback = nullptr;
SP<CCWlCallback> frameCallback = nullptr;
friend class CRenderer;
};

View file

@ -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;
COutput::COutput(SP<CCWlOutput> 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);
});
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<CSessionLockSurface>(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);
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<CSessionLockSurface>(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 : "");
});
}

View file

@ -1,13 +1,14 @@
#pragma once
#include <wayland-client.h>
#include "../defines.hpp"
#include "wayland.hpp"
#include "../helpers/Math.hpp"
#include "LockSurface.hpp"
#include <memory>
class COutput {
public:
COutput(wl_output* output, uint32_t name);
COutput(SP<CCWlOutput> output, uint32_t name);
uint32_t name = 0;
bool focused = false;
@ -20,7 +21,7 @@ class COutput {
std::unique_ptr<CSessionLockSurface> sessionLockSurface;
wl_output* output = nullptr;
SP<CCWlOutput> output = nullptr;
private:
};

138
src/core/Seat.cpp Normal file
View file

@ -0,0 +1,138 @@
#include "Seat.hpp"
#include "hyprlock.hpp"
#include "../helpers/Log.hpp"
#include "../config/ConfigManager.hpp"
#include <chrono>
#include <sys/mman.h>
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<CCWlSeat> 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<CCWlPointer>(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<CCWlKeyboard>(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<CCWpCursorShapeManagerV1> shape) {
m_pCursorShape = std::make_unique<CCursorShape>(shape);
}
bool CSeatManager::registered() {
return m_pSeat;
}

33
src/core/Seat.hpp Normal file
View file

@ -0,0 +1,33 @@
#pragma once
#include "../defines.hpp"
#include "CursorShape.hpp"
#include "wayland.hpp"
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
#include <memory>
class CSeatManager {
public:
CSeatManager() = default;
~CSeatManager();
void registerSeat(SP<CCWlSeat> seat);
void registerCursorShape(SP<CCWpCursorShapeManagerV1> shape);
bool registered();
SP<CCWlKeyboard> m_pKeeb;
SP<CCWlPointer> m_pPointer;
std::unique_ptr<CCursorShape> 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<CCWlSeat> m_pSeat;
};
inline std::unique_ptr<CSeatManager> g_pSeatManager = std::make_unique<CSeatManager>();

View file

@ -5,7 +5,6 @@
#include "../auth/Auth.hpp"
#include "../auth/Fingerprint.hpp"
#include "Egl.hpp"
#include "linux-dmabuf-unstable-v1-protocol.h"
#include <sys/wait.h>
#include <sys/poll.h>
#include <sys/mman.h>
@ -32,16 +31,11 @@ CHyprlock::CHyprlock(const std::string& wlDisplay, const bool immediate, const b
g_pEGL = std::make_unique<CEGL>(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 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 handleCapabilities(void* data, wl_seat* wl_seat, uint32_t capabilities);
static void handleName(void* data, struct wl_seat* wl_seat, const char* name);
static void handleUnlockSignal(int sig) {
if (sig == SIGUSR1) {
Debug::log(LOG, "Unlocking with a SIGUSR1");
g_pHyprlock->releaseSessionLock();
}
}
inline const wl_seat_listener seatListener = {
.capabilities = handleCapabilities,
.name = handleName,
};
static void handleForceUpdateSignal(int sig) {
if (sig == SIGUSR2) {
for (auto& t : g_pHyprlock->getTimers()) {
if (t->canForceUpdate()) {
t->call(t);
t->cancel();
}
}
}
}
// end wl_seat
// dmabuf
static void handleDMABUFFormat(void* data, struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, uint32_t format) {
static void handlePollTerminate(int sig) {
;
}
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});
static void handleCriticalSignal(int sig) {
g_pHyprlock->attemptRestoreOnDeath();
// 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);
abort();
}
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 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;
}
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 dmabufFeedbackTrancheFlags(void* data, zwp_linux_dmabuf_feedback_v1* feedback, uint32_t flags) {
;
}
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 dmabufFeedbackTrancheDone(void* data, struct zwp_linux_dmabuf_feedback_v1* zwp_linux_dmabuf_feedback_v1) {
Debug::log(TRACE, "[core] dmabufFeedbackTrancheDone");
g_pHyprlock->dma.deviceUsed = false;
}
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.");
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});
}
});
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.linuxDmabufFeedback->setDone([this](CCZwpLinuxDmabufFeedbackV1* r) {
Debug::log(TRACE, "[core] dmabufFeedbackDone");
if (dma.formatTable)
munmap(dma.formatTable, dma.formatTableSize);
dma.formatTable = nullptr;
dma.formatTableSize = 0;
});
dma.linuxDmabufFeedback->setFormatTable([this](CCZwpLinuxDmabufFeedbackV1* r, int fd, uint32_t size) {
Debug::log(TRACE, "[core] dmabufFeedbackFormatTable");
dma.dmabufMods.clear();
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;
}
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<COutput>((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<CCursorShape>((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");
return;
dma.formatTableSize = size;
});
dma.linuxDmabufFeedback->setMainDevice([this](CCZwpLinuxDmabufFeedbackV1* r, wl_array* device_arr) {
Debug::log(LOG, "[core] dmabufFeedbackMainDevice");
RASSERT(!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);
}
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.gbmDevice = createGBMDevice(drmDev);
drmFreeDevice(&drmDev);
});
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);
}
}
// end wl_registry
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);
}
static void handleUnlockSignal(int sig) {
if (sig == SIGUSR1) {
Debug::log(LOG, "Unlocking with a SIGUSR1");
g_pHyprlock->releaseSessionLock();
}
}
static void forceUpdateTimers() {
for (auto& t : g_pHyprlock->getTimers()) {
if (t->canForceUpdate()) {
t->call(t);
t->cancel();
}
}
}
static void handleForceUpdateSignal(int sig) {
if (sig == SIGUSR2) {
forceUpdateTimers();
}
}
static void handlePollTerminate(int sig) {
;
}
static void handleCriticalSignal(int sig) {
g_pHyprlock->attemptRestoreOnDeath();
// 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);
abort();
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<CCWlRegistry>((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);
wl_registry_add_listener(m_sWaylandState.registry, &registryListener, nullptr);
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<CCZwpLinuxDmabufV1>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &zwp_linux_dmabuf_v1_interface, 4));
dma.linuxDmabufFeedback = makeShared<CCZwpLinuxDmabufFeedbackV1>(dma.linuxDmabuf->sendGetDefaultFeedback());
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<CCWlSeat>((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<CCExtSessionLockManagerV1>((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<COutput>(makeShared<CCWlOutput>((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<CCWpCursorShapeManagerV1>((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<CCWlCompositor>((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<CCWpFractionalScaleManagerV1>((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<CCWpViewporter>((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<CCZwlrScreencopyManagerV1>((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;
g_pRenderer.reset();
g_pSeatManager.reset();
xkb_context_unref(m_pXKBContext);
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<CCExtSessionLockV1>(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<CCExtSessionLockManagerV1> CHyprlock::getSessionLockMgr() {
return m_sWaylandState.sessionLock;
}
ext_session_lock_v1* CHyprlock::getSessionLock() {
SP<CCExtSessionLockV1> CHyprlock::getSessionLock() {
return m_sLockState.lock;
}
wl_compositor* CHyprlock::getCompositor() {
SP<CCWlCompositor> 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<CCWpFractionalScaleManagerV1> CHyprlock::getFractionalMgr() {
return m_sWaylandState.fractional;
}
wp_viewporter* CHyprlock::getViewporter() {
SP<CCWpViewporter> CHyprlock::getViewporter() {
return m_sWaylandState.viewporter;
}
@ -1086,7 +821,17 @@ std::vector<std::shared_ptr<CTimer>> CHyprlock::getTimers() {
}
void CHyprlock::enqueueForceUpdateTimers() {
addTimer(std::chrono::milliseconds(1), [](std::shared_ptr<CTimer> self, void* data) { forceUpdateTimers(); }, nullptr, false);
addTimer(
std::chrono::milliseconds(1),
[](std::shared_ptr<CTimer> 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<CCZwlrScreencopyManagerV1> 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();

View file

@ -1,11 +1,14 @@
#pragma once
#include <wayland-client.h>
#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 <memory>
@ -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<CTimer> addTimer(const std::chrono::system_clock::duration& timeout, std::function<void(std::shared_ptr<CTimer> self, void* data)> cb_, void* data,
bool force = false);
std::shared_ptr<CTimer> addTimer(const std::chrono::system_clock::duration& timeout, std::function<void(std::shared_ptr<CTimer> 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<std::string> 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<std::string> 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<CCExtSessionLockManagerV1> getSessionLockMgr();
SP<CCExtSessionLockV1> getSessionLock();
SP<CCWlCompositor> getCompositor();
wl_display* getDisplay();
SP<CCWpFractionalScaleManagerV1> getFractionalMgr();
SP<CCWpViewporter> getViewporter();
SP<CCZwlrScreencopyManagerV1> getScreencopy();
wl_pointer* m_pPointer = nullptr;
std::unique_ptr<CCursorShape> 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<std::shared_ptr<CTimer>> getTimers();
struct {
void* linuxDmabuf = nullptr;
void* linuxDmabufFeedback = nullptr;
SP<CCZwpLinuxDmabufV1> linuxDmabuf = nullptr;
SP<CCZwpLinuxDmabufFeedbackV1> 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<SDMABUFModifier> dmabufMods;
std::vector<SDMABUFModifier> 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<CCWlRegistry> registry = nullptr;
SP<CCExtSessionLockManagerV1> sessionLock = nullptr;
SP<CCWlCompositor> compositor = nullptr;
SP<CCWpFractionalScaleManagerV1> fractional = nullptr;
SP<CCWpViewporter> viewporter = nullptr;
SP<CCZwlrScreencopyManagerV1> screencopy = nullptr;
} m_sWaylandState;
void addDmabufListener();
struct {
ext_session_lock_v1* lock = nullptr;
SP<CCExtSessionLockV1> lock = nullptr;
} m_sLockState;
struct {

View file

@ -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<CCZwlrScreencopyFrameV1>(g_pHyprlock->getScreencopy()->sendCaptureOutput(false, output_->output->resource()));
scdata.frame = this;
frameCb->setBufferDone([this](CCZwlrScreencopyFrameV1* r) {
Debug::log(TRACE, "[sc] wlrOnBufferDone for {}", (void*)this);
zwlr_screencopy_frame_v1_add_listener(frameCb, &wlrFrameListener, &scdata);
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();
});
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);
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<uint64_t> mods;
mods.resize(64);
std::vector<EGLBoolean> 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<uint64_t> 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<CCZwpLinuxBufferParamsV1>(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<CCWlBuffer>(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;

View file

@ -1,21 +1,14 @@
#pragma once
#include "../defines.hpp"
#include "../core/Output.hpp"
#include <gbm.h>
#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<CCWlBuffer> 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<CCZwlrScreencopyFrameV1> 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;
};

View file

@ -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;