From bffce0564846487d350bb85a3cd4adf5199ba92d Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Tue, 14 Oct 2025 21:22:03 +0200 Subject: [PATCH 01/16] add CWaylandOutput --- include/hyprtoolkit/core/Backend.hpp | 14 +++++++ include/hyprtoolkit/window/Window.hpp | 9 ++-- src/core/platforms/WaylandPlatform.cpp | 18 +++++++- src/core/platforms/WaylandPlatform.hpp | 3 ++ src/output/WaylandOutput.cpp | 57 ++++++++++++++++++++++++++ src/output/WaylandOutput.hpp | 29 +++++++++++++ src/window/Builder.cpp | 10 ++++- src/window/Window.hpp | 1 + 8 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 src/output/WaylandOutput.cpp create mode 100644 src/output/WaylandOutput.hpp diff --git a/include/hyprtoolkit/core/Backend.hpp b/include/hyprtoolkit/core/Backend.hpp index 47d4862..e0e6b72 100644 --- a/include/hyprtoolkit/core/Backend.hpp +++ b/include/hyprtoolkit/core/Backend.hpp @@ -15,6 +15,7 @@ namespace Hyprtoolkit { class IWindow; + class IOutput; class CTimer; class ISystemIconFactory; struct SWindowCreationData; @@ -73,6 +74,19 @@ namespace Hyprtoolkit { virtual Hyprutils::Memory::CSharedPointer getPalette() = 0; + /* + Get currently registered outputs. + Make sure you register the `removed` event to get rid of your reference once the output is removed. + */ + virtual std::vector> getOutputs() = 0; + + struct { + /* + Get notified when a new output was added. + */ + Hyprutils::Signal::CSignalT> outputAdded; + } m_events; + protected: IBackend(); }; diff --git a/include/hyprtoolkit/window/Window.hpp b/include/hyprtoolkit/window/Window.hpp index 4cc3e83..368c6f1 100644 --- a/include/hyprtoolkit/window/Window.hpp +++ b/include/hyprtoolkit/window/Window.hpp @@ -12,9 +12,10 @@ namespace Hyprtoolkit { struct SWindowCreationData; enum eWindowType : uint8_t { - HT_WINDOW_TOPLEVEL = 0, - HT_WINDOW_POPUP = 1, - HT_WINDOW_LAYER = 2, + HT_WINDOW_TOPLEVEL = 0, + HT_WINDOW_POPUP = 1, + HT_WINDOW_LAYER = 2, + HT_WINDOW_LOCK_SURFACE = 3, }; class CWindowBuilder { @@ -28,6 +29,8 @@ namespace Hyprtoolkit { Hyprutils::Memory::CSharedPointer preferredSize(const Hyprutils::Math::Vector2D&); Hyprutils::Memory::CSharedPointer minSize(const Hyprutils::Math::Vector2D&); Hyprutils::Memory::CSharedPointer maxSize(const Hyprutils::Math::Vector2D&); + // FIXME: implement for window types other than HT_WINDOW_LOCK_SURFACE + Hyprutils::Memory::CSharedPointer prefferedOutput(uint32_t); // only for HT_WINDOW_LAYER Hyprutils::Memory::CSharedPointer marginTopLeft(const Hyprutils::Math::Vector2D&); diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index 23b4918..4011342 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -9,6 +9,8 @@ #include "../../element/Element.hpp" #include "../../window/WaylandWindow.hpp" #include "../../window/WaylandLayer.hpp" +#include "../../output/WaylandOutput.hpp" +#include "../../sessionLock/WaylandSessionLock.hpp" #include "../../Macros.hpp" #include @@ -95,9 +97,23 @@ bool CWaylandPlatform::attempt() { g_logger->log(HT_LOG_ERROR, "Wayland platform cannot start: zwp_linux_dmabuf_v1 init failed"); m_waylandState.dmabufFailed = true; } + } else if (NAME == wl_output_interface.name) { + TRACE(g_logger->log(HT_LOG_TRACE, " > binding to global: {} (version {}) with id {}", name, 4, id)); + m_outputs.emplace_back(makeUnique((wl_proxy*)wl_registry_bind((wl_registry*)m_waylandState.registry->resource(), id, &wl_output_interface, 4), id)); + // FIXME: seems like m_idleCallbacks is not used and was moved to the loop state? + // probably move that there?? + // We just need to deferre it a bit so that the globals are defined before we emit the event. + // But once they are defined, we probably don't want it to be a idle function. + m_idleCallbacks.emplace_back([id]() { g_backend->m_events.outputAdded.emit(id); }); } }); - m_waylandState.registry->setGlobalRemove([](CCWlRegistry* r, uint32_t id) { g_logger->log(HT_LOG_DEBUG, "Global {} removed", id); }); + m_waylandState.registry->setGlobalRemove([this](CCWlRegistry* r, uint32_t id) { + auto outputIt = std::ranges::find_if(m_outputs, [id](const auto& other) { return other->m_id == id; }); + if (outputIt != m_outputs.end()) + m_outputs.erase(outputIt); + + g_logger->log(HT_LOG_DEBUG, "Global {} removed", id); + }); wl_display_roundtrip(m_waylandState.display); diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index ed881a2..8c7e668 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -33,6 +33,7 @@ namespace Hyprtoolkit { class CWaylandWindow; class IWaylandWindow; class CWaylandLayer; + class CWaylandOutput; class CWaylandPlatform { public: @@ -118,6 +119,8 @@ namespace Hyprtoolkit { std::string nodeName = ""; } m_drmState; + std::vector> m_outputs; + std::vector> m_windows; std::vector> m_layers; WP m_currentWindow; diff --git a/src/output/WaylandOutput.cpp b/src/output/WaylandOutput.cpp new file mode 100644 index 0000000..1c89acc --- /dev/null +++ b/src/output/WaylandOutput.cpp @@ -0,0 +1,57 @@ +#include "WaylandOutput.hpp" +#include "../core/InternalBackend.hpp" +#include "../helpers/Memory.hpp" + +using namespace Hyprtoolkit; + +static Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { + switch (t) { + case WL_OUTPUT_TRANSFORM_NORMAL: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; + case WL_OUTPUT_TRANSFORM_180: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_180; + case WL_OUTPUT_TRANSFORM_90: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_90; + case WL_OUTPUT_TRANSFORM_270: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_270; + case WL_OUTPUT_TRANSFORM_FLIPPED: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_FLIPPED; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_FLIPPED_180; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_FLIPPED_270; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_FLIPPED_90; + default: break; + } + return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; +} + +CWaylandOutput::CWaylandOutput(wl_proxy* wlResource, uint32_t id) : m_id(id), m_wlOutput(wlResource) { + m_wlOutput.setDescription([this](CCWlOutput* r, const char* description) { + m_configuration.desc = description ? std::string{description} : ""; + g_logger->log(HT_LOG_DEBUG, "wayland output {}: description {}", m_id, m_configuration.desc); + }); + + m_wlOutput.setName([this](CCWlOutput* r, const char* name) { + m_configuration.name = std::string{name} + m_configuration.name; + m_configuration.port = std::string{name}; + g_logger->log(HT_LOG_DEBUG, "wayland output {}: name {}", name, name); + }); + + m_wlOutput.setScale([this](CCWlOutput* r, int32_t sc) { m_configuration.scale = sc; }); + + m_wlOutput.setDone([this](CCWlOutput* r) { + m_configuration.done = true; + g_logger->log(HT_LOG_DEBUG, "wayland output {} done", m_id); + }); + + m_wlOutput.setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { + // handle portrait mode and flipped cases + if (m_configuration.transform % 2 == 1) + m_configuration.size = {height, width}; + else + m_configuration.size = {width, height}; + + g_logger->log(HT_LOG_DEBUG, "wayland output {} dimensions {}", m_id); + }); + + m_wlOutput.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_) { + m_configuration.transform = wlTransformToHyprutils((wl_output_transform)transform_); + + g_logger->log(HT_LOG_DEBUG, "wayland output {} make {} model {}", m_id, make ? make : "", model ? model : ""); + }); +} diff --git a/src/output/WaylandOutput.hpp b/src/output/WaylandOutput.hpp new file mode 100644 index 0000000..8d7de7f --- /dev/null +++ b/src/output/WaylandOutput.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "wayland.hpp" +#include +#include +#include +#include + +namespace Hyprtoolkit { + class CWaylandOutput { + public: + CWaylandOutput(wl_proxy* wlResource, uint32_t id); + ~CWaylandOutput() = default; + + uint32_t m_id = 0; + bool m_focused = false; + CCWlOutput m_wlOutput; + + struct { + bool done = false; + Hyprutils::Math::eTransform transform = Hyprutils::Math::HYPRUTILS_TRANSFORM_NORMAL; + Hyprutils::Math::Vector2D size; + int scale = 1; + std::string name = ""; + std::string port = ""; + std::string desc = ""; + } m_configuration; + }; +} diff --git a/src/window/Builder.cpp b/src/window/Builder.cpp index ac4d596..af1bdc8 100644 --- a/src/window/Builder.cpp +++ b/src/window/Builder.cpp @@ -41,6 +41,11 @@ SP CWindowBuilder::maxSize(const Hyprutils::Math::Vector2D& x) { return m_self.lock(); } +SP CWindowBuilder::prefferedOutput(uint32_t x) { + m_data->prefferedOutputId = x; + return m_self.lock(); +} + SP CWindowBuilder::parent(const SP& x) { m_data->parent = x; return m_self.lock(); @@ -94,7 +99,8 @@ SP CWindowBuilder::commence() { return reinterpretPointerCast(m_data->parent)->openPopup(*m_data); case HT_WINDOW_TOPLEVEL: - case HT_WINDOW_LAYER: return g_backend->openWindow(*m_data); + case HT_WINDOW_LAYER: + case HT_WINDOW_LOCK_SURFACE: return g_backend->openWindow(*m_data); } return nullptr; -} \ No newline at end of file +} diff --git a/src/window/Window.hpp b/src/window/Window.hpp index 22d19ee..b940ff7 100644 --- a/src/window/Window.hpp +++ b/src/window/Window.hpp @@ -12,6 +12,7 @@ namespace Hyprtoolkit { std::optional maxSize; std::string title = "Hyprtoolkit App"; std::string class_ = "hyprtoolkit-app"; + uint32_t prefferedOutputId; // popups Hyprutils::Math::Vector2D pos; From 4b311db47c0d2c76ad15edc74d7c60a935d55c77 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Sat, 11 Oct 2025 21:41:24 +0200 Subject: [PATCH 02/16] add WaylandLockSurface --- CMakeLists.txt | 1 + flake.lock | 18 ++-- flake.nix | 12 +++ src/core/platforms/WaylandPlatform.cpp | 10 +++ src/core/platforms/WaylandPlatform.hpp | 25 +++--- src/window/IWaylandWindow.hpp | 2 +- src/window/WaylandLockSurface.cpp | 118 +++++++++++++++++++++++++ src/window/WaylandLockSurface.hpp | 27 ++++++ src/window/Window.hpp | 1 + 9 files changed, 192 insertions(+), 22 deletions(-) create mode 100644 src/window/WaylandLockSurface.cpp create mode 100644 src/window/WaylandLockSurface.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 92fafef..673820f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,7 @@ 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("staging/ext-session-lock" "ext-session-lock-v1" false) protocolnew("stable/tablet" "tablet-v2" false) protocolnew("unstable/text-input" "text-input-unstable-v3" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) diff --git a/flake.lock b/flake.lock index 2259b61..24d9fa9 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1759499898, - "narHash": "sha256-UNzYHLWfkSzLHDep5Ckb5tXc0fdxwPIrT+MY4kpQttM=", + "lastModified": 1760101617, + "narHash": "sha256-8jf/3ZCi+B7zYpIyV04+3wm72BD7Z801IlOzsOACR7I=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "655e067f96fd44b3f5685e17f566b0e4d535d798", + "rev": "1826a9923881320306231b1c2090379ebf9fa4f8", "type": "github" }, "original": { @@ -91,11 +91,11 @@ ] }, "locked": { - "lastModified": 1759609323, - "narHash": "sha256-5c9sJ4CFdmYJ/EcIUSyzo3CZu3fR+k5r7lnOrtZ8sWA=", + "lastModified": 1759619523, + "narHash": "sha256-r1ed7AR2ZEb2U8gy321/Xcp1ho2tzn+gG1te/Wxsj1A=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "9ab64319e95374934aac5406df4e69fee77345ff", + "rev": "3df7bde01efb3a3e8e678d1155f2aa3f19e177ef", "type": "github" }, "original": { @@ -129,11 +129,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1759381078, - "narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=", + "lastModified": 1760038930, + "narHash": "sha256-Oncbh0UmHjSlxO7ErQDM3KM0A5/Znfofj2BSzlHLeVw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee", + "rev": "0b4defa2584313f3b781240b29d61f6f9f7e0df3", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 41b1355..5c83fa1 100644 --- a/flake.nix +++ b/flake.nix @@ -73,6 +73,18 @@ inherit (pkgsFor.${system}) hyprtoolkit; }); + devShells = eachSystem (system: { + default = + pkgsFor.${system}.mkShell.override { + inherit (self.packages.${system}.default) stdenv; + } { + name = "hyprtoolkit-shell"; + hardeningDisable = ["fortify"]; + inputsFrom = [pkgsFor.${system}.hyprtoolkit]; + packages = [pkgsFor.${system}.clang-tools]; + }; + }); + checks = eachSystem (system: self.packages.${system}); formatter = eachSystem (system: pkgsFor.${system}.alejandra); diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index 4011342..617a228 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -113,6 +113,7 @@ bool CWaylandPlatform::attempt() { m_outputs.erase(outputIt); g_logger->log(HT_LOG_DEBUG, "Global {} removed", id); + g_backend->m_events.outputRemoved.emit(id); }); wl_display_roundtrip(m_waylandState.display); @@ -198,6 +199,15 @@ SP CWaylandPlatform::windowForSurf(wl_proxy* proxy) { return nullptr; } +std::optional> CWaylandPlatform::outputForId(uint32_t id) { + for (const auto& o : m_outputs) { + if (o->m_id == id) { + return o; + } + } + return std::nullopt; +} + void CWaylandPlatform::initIM() { m_waylandState.textInput = makeShared(m_waylandState.textInputManager->sendGetTextInput(m_waylandState.seat->resource())); diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index 8c7e668..eca8059 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -40,23 +40,24 @@ namespace Hyprtoolkit { CWaylandPlatform() = default; ~CWaylandPlatform(); - bool attempt(); + bool attempt(); - void initSeat(); - void initShell(); - bool initDmabuf(); - void initIM(); - void setCursor(ePointerShape shape); + void initSeat(); + void initShell(); + bool initDmabuf(); + void initIM(); + void setCursor(ePointerShape shape); - bool dispatchEvents(); + bool dispatchEvents(); - SP windowForSurf(wl_proxy* proxy); + SP windowForSurf(wl_proxy* proxy); + std::optional> outputForId(uint32_t id); - void onKey(uint32_t keycode, bool state); - void startRepeatTimer(); - void stopRepeatTimer(); + void onKey(uint32_t keycode, bool state); + void startRepeatTimer(); + void stopRepeatTimer(); - void onRepeatTimerFire(); + void onRepeatTimerFire(); // std::vector m_idleCallbacks; diff --git a/src/window/IWaylandWindow.hpp b/src/window/IWaylandWindow.hpp index b8e9623..479a5d7 100644 --- a/src/window/IWaylandWindow.hpp +++ b/src/window/IWaylandWindow.hpp @@ -100,4 +100,4 @@ namespace Hyprtoolkit { friend class CWaylandWindow; }; -} \ No newline at end of file +} diff --git a/src/window/WaylandLockSurface.cpp b/src/window/WaylandLockSurface.cpp new file mode 100644 index 0000000..64518eb --- /dev/null +++ b/src/window/WaylandLockSurface.cpp @@ -0,0 +1,118 @@ +#include "WaylandLockSurface.hpp" + +#include +#include +#include + +#include "../core/AnimationManager.hpp" +#include "../core/InternalBackend.hpp" +#include "../core/platforms/WaylandPlatform.hpp" +#include "../element/Element.hpp" +#include "../output/WaylandOutput.hpp" +#include "../renderer/Renderer.hpp" + +#include "../Macros.hpp" + +using namespace Hyprtoolkit; +using namespace Hyprutils::Math; + +CWaylandLockSurface::CWaylandLockSurface(const SWindowCreationData& data, const SP& lockObject) : m_creationData(data), m_lockObject(lockObject) { + m_rootElement = CNullBuilder::begin()->commence(); +} + +CWaylandLockSurface::~CWaylandLockSurface() { + close(); +} + +void CWaylandLockSurface::open() { + if (m_open) + return; + + m_open = true; + + if (m_creationData.prefferedOutputId == 0) { + g_logger->log(HT_LOG_ERROR, "session lock missing prefferedOutputId."); + return; + } + + if (!g_waylandPlatform) { + g_logger->log(HT_LOG_ERROR, "wayland platform uninitialized!"); + return; + } + + m_rootElement->impl->window = m_self; + m_rootElement->impl->breadthfirst([this](SP e) { e->impl->window = m_self; }); + + if (!m_waylandState.surface) { + m_waylandState.surface = makeShared(g_waylandPlatform->m_waylandState.compositor->sendCreateSurface()); + if (!m_waylandState.surface->resource()) { + g_logger->log(HT_LOG_ERROR, "lock surface opening failed: no surface given. Errno: {}", errno); + return; + } + + auto inputRegion = makeShared(g_waylandPlatform->m_waylandState.compositor->sendCreateRegion()); + inputRegion->sendAdd(0, 0, INT32_MAX, INT32_MAX); + + m_waylandState.surface->sendSetInputRegion(inputRegion.get()); + + m_waylandState.fractional = makeShared(g_waylandPlatform->m_waylandState.fractional->sendGetFractionalScale(m_waylandState.surface->resource())); + + m_waylandState.fractional->setPreferredScale([this](CCWpFractionalScaleV1*, uint32_t scale) { + const bool SAMESCALE = m_fractionalScale == scale / 120.0; + m_fractionalScale = scale / 120.0; + + g_logger->log(HT_LOG_DEBUG, "layer: got fractional scale: {:.1f}%", m_fractionalScale * 100.F); + + if (!SAMESCALE && m_lockSurfaceState.configured) + onScaleUpdate(); + }); + + m_waylandState.viewport = makeShared(g_waylandPlatform->m_waylandState.viewporter->sendGetViewport(m_waylandState.surface->resource())); + } else + m_waylandState.surface->sendAttach(nullptr, 0, 0); + + m_lockSurfaceState.lockSurface = makeShared(m_lockObject->sendGetLockSurface(m_waylandState.surface->resource(), m_wlOutput)); + if (!m_lockSurfaceState.lockSurface->resource()) { + g_logger->log(HT_LOG_ERROR, "lock surface opening failed: no lock surface. Errno: {}", errno); + return; + } + + m_lockSurfaceState.lockSurface->setConfigure([this](CCExtSessionLockSurfaceV1* r, uint32_t serial, uint32_t w, uint32_t h) { + g_logger->log(HT_LOG_DEBUG, "wayland: configure layer with {}x{}", w, h); + m_lockSurfaceState.configured = true; + if (w == 0 || h == 0) { + g_logger->log(HT_LOG_ERROR, "configure: w/h is 0, for a lock surface is bogus. Still, trying with 1920x1080..."); + w = 1920; + h = 1080; + } + + if (m_waylandState.logicalSize == Vector2D{sc(w), sc(h)}) + return; + + m_lockSurfaceState.lockSurface->sendAckConfigure(serial); + + configure(Vector2D{sc(w), sc(h)}, m_waylandState.serial); + + m_events.resized.emit(m_waylandState.logicalSize); + }); +} + +void CWaylandLockSurface::close() { + if (!m_open) + return; + + m_open = false; + + m_waylandState.frameCallback.reset(); + + m_lockSurfaceState.lockSurface.reset(); + m_waylandState.logicalSize = {}; + m_lockSurfaceState.configured = false; +} + +void CWaylandLockSurface::render() { + if (!m_lockSurfaceState.configured) + return; + + IWaylandWindow::render(); +} diff --git a/src/window/WaylandLockSurface.hpp b/src/window/WaylandLockSurface.hpp new file mode 100644 index 0000000..f1bbc71 --- /dev/null +++ b/src/window/WaylandLockSurface.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "IWaylandWindow.hpp" +#include + +namespace Hyprtoolkit { + class CWaylandLockSurface : public IWaylandWindow { + public: + CWaylandLockSurface(const SWindowCreationData& data, const SP& lockObject); + virtual ~CWaylandLockSurface(); + + virtual void close(); + virtual void open(); + virtual void render(); + + private: + uint32_t m_outputId = 0; + WP m_lockObject; + + struct { + SP lockSurface; + bool configured = false; + } m_lockSurfaceState; + + friend class CWaylandPlatform; + }; +}; diff --git a/src/window/Window.hpp b/src/window/Window.hpp index b940ff7..35ff00b 100644 --- a/src/window/Window.hpp +++ b/src/window/Window.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "../helpers/Memory.hpp" From f9167862e38f1b9e1c52c8c815ed68865d668b1a Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Thu, 16 Oct 2025 10:16:12 +0200 Subject: [PATCH 03/16] add CCExtSessionLockV1 --- CMakeLists.txt | 5 + include/hyprtoolkit/core/Backend.hpp | 7 ++ src/core/Backend.cpp | 39 +++++-- src/core/platforms/WaylandPlatform.cpp | 71 +++++++++++-- src/core/platforms/WaylandPlatform.hpp | 25 +++-- src/output/WaylandOutput.cpp | 9 +- src/renderer/gl/OpenGL.cpp | 2 + src/window/Builder.cpp | 2 + src/window/WaylandLockSurface.cpp | 21 ++-- src/window/WaylandLockSurface.hpp | 5 +- tests/SimpleSessionLock.cpp | 136 +++++++++++++++++++++++++ 11 files changed, 289 insertions(+), 33 deletions(-) create mode 100644 tests/SimpleSessionLock.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 673820f..10093fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,11 @@ add_executable(controls "tests/Controls.cpp") target_link_libraries(controls PRIVATE PkgConfig::deps hyprtoolkit) add_dependencies(tests controls) +add_executable(simpleSessionLock "tests/SimpleSessionLock.cpp") +target_link_libraries(simpleSessionLock PRIVATE PkgConfig::deps hyprtoolkit) +add_dependencies(tests simpleSessionLock) + + # Installation install(TARGETS hyprtoolkit) install(DIRECTORY "include/hyprtoolkit" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/include/hyprtoolkit/core/Backend.hpp b/include/hyprtoolkit/core/Backend.hpp index e0e6b72..3c282d3 100644 --- a/include/hyprtoolkit/core/Backend.hpp +++ b/include/hyprtoolkit/core/Backend.hpp @@ -33,6 +33,13 @@ namespace Hyprtoolkit { */ static Hyprutils::Memory::CSharedPointer create(); + /* + Attempt to initialize the platform. + Optional. Can be used in case the outputAdded/Removed events are used to create new windows. + In such a szenario the platform must be initialized before opening a window. + */ + static bool attempt(); + /* Destroy the backend. Backend will be destroyed once: diff --git a/src/core/Backend.cpp b/src/core/Backend.cpp index 93e7652..039eafd 100644 --- a/src/core/Backend.cpp +++ b/src/core/Backend.cpp @@ -10,6 +10,7 @@ #include "../renderer/gl/OpenGL.hpp" #include "../window/WaylandWindow.hpp" #include "../window/WaylandLayer.hpp" +#include "../window/WaylandLockSurface.hpp" #include "../Macros.hpp" #include "../element/Element.hpp" #include "../palette/ConfigManager.hpp" @@ -72,6 +73,17 @@ SP IBackend::create() { return g_backend; }; +bool CBackend::attempt() { + g_waylandPlatform = makeUnique(); + if (!g_waylandPlatform->attempt()) { + g_waylandPlatform = nullptr; + return false; + } + g_openGL = makeShared(g_waylandPlatform->m_drmState.fd); + g_renderer = g_openGL; + return true; +} + void CBackend::destroy() { terminate(); } @@ -84,14 +96,16 @@ SP CBackend::getPalette() { return g_palette; } +void CBackend::unlockSession() { + if (!g_waylandPlatform) + return; + + g_waylandPlatform->unlockSessionLock(); +} + SP CBackend::openWindow(const SWindowCreationData& data) { - if (!g_waylandPlatform) { - g_waylandPlatform = makeUnique(); - if (!g_waylandPlatform->attempt()) - return nullptr; - g_openGL = makeShared(g_waylandPlatform->m_drmState.fd); - g_renderer = g_openGL; - } + if (!g_waylandPlatform && !attempt()) + return nullptr; if (data.type == HT_WINDOW_LAYER) { if (!g_waylandPlatform->m_waylandState.layerShell) @@ -102,6 +116,17 @@ SP CBackend::openWindow(const SWindowCreationData& data) { w->m_rootElement->impl->window = w; g_waylandPlatform->m_layers.emplace_back(w); return w; + } else if (data.type == HT_WINDOW_LOCK_SURFACE) { + if (!g_waylandPlatform->m_waylandState.sessionLock) { + g_logger->log(HT_LOG_ERROR, "No session lock manager. Does your compositor support it?"); + return nullptr; + } + + auto w = makeShared(data); + w->m_self = w; + w->m_rootElement->impl->window = w; + g_waylandPlatform->m_lockSurfaces.emplace_back(w); + return w; } auto w = makeShared(data); diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index 617a228..45c4d33 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "../InternalBackend.hpp" @@ -9,6 +10,7 @@ #include "../../element/Element.hpp" #include "../../window/WaylandWindow.hpp" #include "../../window/WaylandLayer.hpp" +#include "../../window/WaylandLockSurface.hpp" #include "../../output/WaylandOutput.hpp" #include "../../sessionLock/WaylandSessionLock.hpp" #include "../../Macros.hpp" @@ -105,15 +107,23 @@ bool CWaylandPlatform::attempt() { // We just need to deferre it a bit so that the globals are defined before we emit the event. // But once they are defined, we probably don't want it to be a idle function. m_idleCallbacks.emplace_back([id]() { g_backend->m_events.outputAdded.emit(id); }); + } else if (NAME == ext_session_lock_manager_v1_interface.name) { + TRACE(g_logger->log(HT_LOG_TRACE, " > binding to global: {} (version {}) with id {}", name, 1, id)); + m_waylandState.sessionLock = makeShared( + (wl_proxy*)wl_registry_bind((wl_registry*)m_waylandState.registry->resource(), id, &ext_session_lock_manager_v1_interface, 1)); } }); m_waylandState.registry->setGlobalRemove([this](CCWlRegistry* r, uint32_t id) { + TRACE(g_logger->log(HT_LOG_TRACE, "Global {} removed", id)); + + auto lockSurfaceIt = std::ranges::find_if(m_lockSurfaces, [id](const auto& other) { return other->m_outputId == id; }); + if (lockSurfaceIt != m_lockSurfaces.end()) { + (*lockSurfaceIt)->m_events.closeRequest.emit(); + m_lockSurfaces.erase(lockSurfaceIt); + } auto outputIt = std::ranges::find_if(m_outputs, [id](const auto& other) { return other->m_id == id; }); if (outputIt != m_outputs.end()) m_outputs.erase(outputIt); - - g_logger->log(HT_LOG_DEBUG, "Global {} removed", id); - g_backend->m_events.outputRemoved.emit(id); }); wl_display_roundtrip(m_waylandState.display); @@ -132,9 +142,7 @@ bool CWaylandPlatform::attempt() { } CWaylandPlatform::~CWaylandPlatform() { - const auto DPY = m_waylandState.display; - m_waylandState = {}; - wl_display_disconnect(DPY); + m_outputs.clear(); if (m_drmState.fd >= 0) close(m_drmState.fd); @@ -145,6 +153,10 @@ CWaylandPlatform::~CWaylandPlatform() { xkb_keymap_unref(m_waylandState.seatState.xkbKeymap); if (m_waylandState.seatState.xkbContext) xkb_context_unref(m_waylandState.seatState.xkbContext); + + const auto DPY = m_waylandState.display; + m_waylandState = {}; + wl_display_disconnect(DPY); } bool CWaylandPlatform::dispatchEvents() { @@ -626,3 +638,50 @@ void CWaylandPlatform::stopRepeatTimer() { m_waylandState.seatState.repeatTimer->cancel(); m_waylandState.seatState.repeatTimer.reset(); } + +SP CWaylandPlatform::aquireSessionLock() { + if (m_waylandState.sessionLockState.sessionLocked && m_waylandState.sessionLockState.sessionUnlocked) { + g_logger->log(HT_LOG_ERROR, "We already unlocked. We shouldn't be calling aquireSessionLock?"); + return nullptr; + } + + if (!m_waylandState.sessionLockState.lock) { + m_waylandState.sessionLockState.lock = makeShared(m_waylandState.sessionLock->sendLock()); + if (!m_waylandState.sessionLockState.lock) { + g_logger->log(HT_LOG_ERROR, "Failed to create a session lock object!"); + return nullptr; + } + + m_waylandState.sessionLockState.lock->setLocked([this](CCExtSessionLockV1* r) { m_waylandState.sessionLockState.sessionLocked = true; }); + + m_waylandState.sessionLockState.lock->setFinished([](CCExtSessionLockV1* r) { //FIXME: we need to make sure the client can exit after this event + }); + + // roundtrip in case the compositor sends `finished` right away + wl_display_roundtrip(m_waylandState.display); + + // FIXME: we need to test if finished was sent right here too! + } + + return m_waylandState.sessionLockState.lock; +} + +void CWaylandPlatform::unlockSessionLock() { + if (!m_waylandState.sessionLockState.lock) + return; + + m_waylandState.sessionLockState.lock->sendUnlockAndDestroy(); + m_waylandState.sessionLockState.lock = nullptr; + m_waylandState.sessionLockState.sessionUnlocked = true; + + // roundtrip in order to make sure we have unlocked before sending closeRequest + wl_display_roundtrip(m_waylandState.display); + + for (const auto& sls : m_lockSurfaces) { + if (sls.expired()) + continue; + sls->m_events.closeRequest.emit(); + } + + m_lockSurfaces.clear(); +} diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index eca8059..6e48446 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,7 @@ namespace Hyprtoolkit { class IWaylandWindow; class CWaylandLayer; class CWaylandOutput; + class CWaylandLockSurface; class CWaylandPlatform { public: @@ -59,6 +61,9 @@ namespace Hyprtoolkit { void onRepeatTimerFire(); + SP aquireSessionLock(); + void unlockSessionLock(); + // std::vector m_idleCallbacks; @@ -88,6 +93,7 @@ namespace Hyprtoolkit { Hyprutils::Memory::CSharedPointer textInput; Hyprutils::Memory::CSharedPointer layerShell; Hyprutils::Memory::CSharedPointer syncobj; + Hyprutils::Memory::CSharedPointer sessionLock; // control bool dmabufFailed = false; @@ -113,6 +119,12 @@ namespace Hyprtoolkit { std::string originalString; } imState; + + struct { + SP lock = nullptr; + bool sessionLocked = false; + bool sessionUnlocked = false; + } sessionLockState; } m_waylandState; struct { @@ -120,13 +132,14 @@ namespace Hyprtoolkit { std::string nodeName = ""; } m_drmState; - std::vector> m_outputs; + std::vector> m_outputs; - std::vector> m_windows; - std::vector> m_layers; - WP m_currentWindow; - uint32_t m_currentMods = 0; // HT modifiers, not xkb - uint32_t m_lastEnterSerial = 0; + std::vector> m_windows; + std::vector> m_layers; + std::vector> m_lockSurfaces; + WP m_currentWindow; + uint32_t m_currentMods = 0; // HT modifiers, not xkb + uint32_t m_lastEnterSerial = 0; }; inline UP g_waylandPlatform; diff --git a/src/output/WaylandOutput.cpp b/src/output/WaylandOutput.cpp index 1c89acc..18a925e 100644 --- a/src/output/WaylandOutput.cpp +++ b/src/output/WaylandOutput.cpp @@ -1,6 +1,5 @@ #include "WaylandOutput.hpp" #include "../core/InternalBackend.hpp" -#include "../helpers/Memory.hpp" using namespace Hyprtoolkit; @@ -28,14 +27,14 @@ CWaylandOutput::CWaylandOutput(wl_proxy* wlResource, uint32_t id) : m_id(id), m_ m_wlOutput.setName([this](CCWlOutput* r, const char* name) { m_configuration.name = std::string{name} + m_configuration.name; m_configuration.port = std::string{name}; - g_logger->log(HT_LOG_DEBUG, "wayland output {}: name {}", name, name); + g_logger->log(HT_LOG_DEBUG, "wayland output {}: name {}", m_id, name); }); m_wlOutput.setScale([this](CCWlOutput* r, int32_t sc) { m_configuration.scale = sc; }); m_wlOutput.setDone([this](CCWlOutput* r) { m_configuration.done = true; - g_logger->log(HT_LOG_DEBUG, "wayland output {} done", m_id); + g_logger->log(HT_LOG_DEBUG, "wayland output {}: done", m_id); }); m_wlOutput.setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { @@ -45,13 +44,13 @@ CWaylandOutput::CWaylandOutput(wl_proxy* wlResource, uint32_t id) : m_id(id), m_ else m_configuration.size = {width, height}; - g_logger->log(HT_LOG_DEBUG, "wayland output {} dimensions {}", m_id); + g_logger->log(HT_LOG_DEBUG, "wayland output {}: dimensions {}", m_id, m_configuration.size); }); m_wlOutput.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_) { m_configuration.transform = wlTransformToHyprutils((wl_output_transform)transform_); - g_logger->log(HT_LOG_DEBUG, "wayland output {} make {} model {}", m_id, make ? make : "", model ? model : ""); + g_logger->log(HT_LOG_DEBUG, "wayland output {}: make {} model {}", m_id, make ? make : "", model ? model : ""); }); } diff --git a/src/renderer/gl/OpenGL.cpp b/src/renderer/gl/OpenGL.cpp index 9d41565..fa1c00d 100644 --- a/src/renderer/gl/OpenGL.cpp +++ b/src/renderer/gl/OpenGL.cpp @@ -522,6 +522,8 @@ COpenGLRenderer::COpenGLRenderer(int drmFD) : m_drmFD(drmFD) { } COpenGLRenderer::~COpenGLRenderer() { + m_glTextures.clear(); + if (m_eglDisplay && m_eglContext != EGL_NO_CONTEXT) eglDestroyContext(m_eglDisplay, m_eglContext); diff --git a/src/window/Builder.cpp b/src/window/Builder.cpp index af1bdc8..d07d400 100644 --- a/src/window/Builder.cpp +++ b/src/window/Builder.cpp @@ -1,6 +1,8 @@ #include "Window.hpp" #include "../core/InternalBackend.hpp" #include "ToolkitWindow.hpp" +#include "core/platforms/WaylandPlatform.hpp" +#include "hyprtoolkit/core/LogTypes.hpp" using namespace Hyprtoolkit; diff --git a/src/window/WaylandLockSurface.cpp b/src/window/WaylandLockSurface.cpp index 64518eb..507ad61 100644 --- a/src/window/WaylandLockSurface.cpp +++ b/src/window/WaylandLockSurface.cpp @@ -16,7 +16,7 @@ using namespace Hyprtoolkit; using namespace Hyprutils::Math; -CWaylandLockSurface::CWaylandLockSurface(const SWindowCreationData& data, const SP& lockObject) : m_creationData(data), m_lockObject(lockObject) { +CWaylandLockSurface::CWaylandLockSurface(const SWindowCreationData& data) : m_outputId(data.prefferedOutputId) { m_rootElement = CNullBuilder::begin()->commence(); } @@ -28,18 +28,26 @@ void CWaylandLockSurface::open() { if (m_open) return; - m_open = true; - - if (m_creationData.prefferedOutputId == 0) { + if (m_outputId == 0) { g_logger->log(HT_LOG_ERROR, "session lock missing prefferedOutputId."); return; } if (!g_waylandPlatform) { - g_logger->log(HT_LOG_ERROR, "wayland platform uninitialized!"); + g_logger->log(HT_LOG_ERROR, "wayland platform not initialized."); return; } + auto lockObject = g_waylandPlatform->aquireSessionLock(); + if (!lockObject) + return; + + auto wlOutput = g_waylandPlatform->outputForId(m_outputId); + if (!wlOutput.has_value() || !wlOutput.value()) + return; + + m_open = true; + m_rootElement->impl->window = m_self; m_rootElement->impl->breadthfirst([this](SP e) { e->impl->window = m_self; }); @@ -71,7 +79,8 @@ void CWaylandLockSurface::open() { } else m_waylandState.surface->sendAttach(nullptr, 0, 0); - m_lockSurfaceState.lockSurface = makeShared(m_lockObject->sendGetLockSurface(m_waylandState.surface->resource(), m_wlOutput)); + m_lockSurfaceState.lockSurface = + makeShared(lockObject->sendGetLockSurface(m_waylandState.surface->resource(), wlOutput.value()->m_wlOutput.resource())); if (!m_lockSurfaceState.lockSurface->resource()) { g_logger->log(HT_LOG_ERROR, "lock surface opening failed: no lock surface. Errno: {}", errno); return; diff --git a/src/window/WaylandLockSurface.hpp b/src/window/WaylandLockSurface.hpp index f1bbc71..7fc427b 100644 --- a/src/window/WaylandLockSurface.hpp +++ b/src/window/WaylandLockSurface.hpp @@ -6,7 +6,7 @@ namespace Hyprtoolkit { class CWaylandLockSurface : public IWaylandWindow { public: - CWaylandLockSurface(const SWindowCreationData& data, const SP& lockObject); + CWaylandLockSurface(const SWindowCreationData& data); virtual ~CWaylandLockSurface(); virtual void close(); @@ -14,8 +14,7 @@ namespace Hyprtoolkit { virtual void render(); private: - uint32_t m_outputId = 0; - WP m_lockObject; + uint32_t m_outputId = 0; struct { SP lockSurface; diff --git a/tests/SimpleSessionLock.cpp b/tests/SimpleSessionLock.cpp new file mode 100644 index 0000000..b304442 --- /dev/null +++ b/tests/SimpleSessionLock.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace Hyprutils::Memory; +using namespace Hyprutils::Math; +using namespace Hyprtoolkit; + +#define SP CSharedPointer +#define WP CWeakPointer +#define UP CUniquePointer + +static SP backend; +static std::vector> windows; +static size_t buttonClicks = 1; + +static void addTimer(SP rect) { + backend->addTimer( + std::chrono::seconds(1), + [rect](Hyprutils::Memory::CAtomicSharedPointer timer, void* data) { + rect->rebuild()->color([] { return CHyprColor{rand() % 1000 / 1000.F, rand() % 1000 / 1000.F, rand() % 1000 / 1000.F, 1.F}; })->commence(); + + addTimer(rect); + }, + nullptr); +} + +static void layout(const SP& window) { + window->m_rootElement->addChild(CRectangleBuilder::begin()->color([] { return CHyprColor{0.1F, 0.1F, 0.1F}; })->commence()); + + auto layout = CRowLayoutBuilder::begin()->commence(); + + window->m_rootElement->addChild(layout); + + auto rect3 = CRectangleBuilder::begin() // + ->color([] { return CHyprColor{0.2F, 0.4F, 0.4F}; }) + ->rounding(10) + ->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {150, 150}}) + ->commence(); + + auto rect4 = CRectangleBuilder::begin() // + ->color([] { return CHyprColor{0.4F, 0.2F, 0.4F}; }) + ->rounding(10) + ->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {50, 50}}) + ->commence(); + + auto layout2 = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {0.5F, 1.F}})->commence(); + + auto image = CImageBuilder::begin() // + ->path("/home/max/media/picture/avatar.png") + ->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {447, 447}}) + ->commence(); + + auto text = CTextBuilder::begin()->text("world is a fuck")->color([] { return CHyprColor{0.4F, 0.4F, 0.4F}; })->commence(); + + auto button = CButtonBuilder::begin() + ->label("Click me bitch") + ->onMainClick([](SP el) { el->rebuild()->label(std::format("Clicked {} times bitch", buttonClicks++))->commence(); }) + ->onRightClick([](SP el) { el->rebuild()->label("Reset bitch")->commence(); }) + ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) + ->commence(); + + text->setGrow(true); + rect4->setGrow(true); + + addTimer(rect4); + + layout2->addChild(image); + layout2->addChild(button); + layout2->addChild(text); + layout->addChild(layout2); + layout->addChild(rect3); + layout->addChild(rect4); + + window->open(); +} + +static void onWindowClose(WP window) { + std::println("Remove surface {}!", (uintptr_t)windows.back().get()); + auto windowsIt = std::ranges::find_if(windows, [&window](const auto& w) { return w.get() == window.get(); }); + if (windowsIt == windows.end()) + return; + + (*windowsIt)->close(); + windows.erase(windowsIt); + if (windows.empty()) { + std::println("It's over!!!"); + backend->destroy(); + } +} + +int main(int argc, char** argv, char** envp) { + int unlockSecs = 1; + if (argc == 2) + unlockSecs = atoi(argv[1]); + + backend = IBackend::create(); + if (!backend) { + std::println("Backend create failed!"); + return 1; + } + + auto sessionLock = backend->aquireSessionLock(); + if (!sessionLock.has_value()) { + std::println("Cloudn't lock"); + return 1; + } + + sessionLock.value()->m_events.finished.listenStatic([] { + std::println("Compositor kicked us"); + for (const auto& w : windows) { + closeWindow(w); + } + }); + + if (!CBackend::attempt()) { + std::println("Backend attempt failed!"); + return -1; + } + + backend->addTimer(std::chrono::seconds(5), [](auto, auto) { backend->unlockSession(); }, nullptr); + + backend->enterLoop(); + + return 0; +} From 9cbe3acfeeaf7d9777c4ba9264c5598efaa44947 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Fri, 17 Oct 2025 15:54:18 +0200 Subject: [PATCH 04/16] add IOutput --- include/hyprtoolkit/core/Backend.hpp | 6 ++++++ include/hyprtoolkit/core/Output.hpp | 16 ++++++++++++++++ include/hyprtoolkit/window/Window.hpp | 3 ++- src/core/Backend.cpp | 10 +++++++++- src/core/Output.cpp | 0 src/core/platforms/WaylandPlatform.cpp | 15 +++++++++------ src/core/platforms/WaylandPlatform.hpp | 4 ++-- src/output/WaylandOutput.cpp | 19 ++++++++++++------- src/output/WaylandOutput.hpp | 13 +++++++++---- src/window/Builder.cpp | 7 +++---- src/window/WaylandLockSurface.cpp | 8 ++++---- src/window/WaylandLockSurface.hpp | 2 +- tests/SimpleSessionLock.cpp | 9 +++++++++ 13 files changed, 82 insertions(+), 30 deletions(-) create mode 100644 include/hyprtoolkit/core/Output.hpp create mode 100644 src/core/Output.cpp diff --git a/include/hyprtoolkit/core/Backend.hpp b/include/hyprtoolkit/core/Backend.hpp index 3c282d3..29dab7d 100644 --- a/include/hyprtoolkit/core/Backend.hpp +++ b/include/hyprtoolkit/core/Backend.hpp @@ -87,6 +87,12 @@ namespace Hyprtoolkit { */ virtual std::vector> getOutputs() = 0; + /* + Get currently registered outputs. + Make sure you register the `removed` event to get rid of your reference once the output is removed. + */ + std::vector> getOutputs(); + struct { /* Get notified when a new output was added. diff --git a/include/hyprtoolkit/core/Output.hpp b/include/hyprtoolkit/core/Output.hpp new file mode 100644 index 0000000..71cc8f5 --- /dev/null +++ b/include/hyprtoolkit/core/Output.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace Hyprtoolkit { + class IOutput { + public: + virtual ~IOutput() = default; + virtual uint32_t handle() = 0; + + struct { + // output removed + Hyprutils::Signal::CSignalT<> removed; + } m_events; + }; +} diff --git a/include/hyprtoolkit/window/Window.hpp b/include/hyprtoolkit/window/Window.hpp index 368c6f1..8902b1f 100644 --- a/include/hyprtoolkit/window/Window.hpp +++ b/include/hyprtoolkit/window/Window.hpp @@ -9,6 +9,7 @@ namespace Hyprtoolkit { class IElement; class IWindow; + class IOutput; struct SWindowCreationData; enum eWindowType : uint8_t { @@ -30,7 +31,7 @@ namespace Hyprtoolkit { Hyprutils::Memory::CSharedPointer minSize(const Hyprutils::Math::Vector2D&); Hyprutils::Memory::CSharedPointer maxSize(const Hyprutils::Math::Vector2D&); // FIXME: implement for window types other than HT_WINDOW_LOCK_SURFACE - Hyprutils::Memory::CSharedPointer prefferedOutput(uint32_t); + Hyprutils::Memory::CSharedPointer prefferedOutput(const Hyprutils::Memory::CSharedPointer& output); // only for HT_WINDOW_LAYER Hyprutils::Memory::CSharedPointer marginTopLeft(const Hyprutils::Math::Vector2D&); diff --git a/src/core/Backend.cpp b/src/core/Backend.cpp index 039eafd..fde981e 100644 --- a/src/core/Backend.cpp +++ b/src/core/Backend.cpp @@ -8,9 +8,10 @@ #include "./platforms/WaylandPlatform.hpp" #include "../renderer/gl/OpenGL.hpp" -#include "../window/WaylandWindow.hpp" +#include "../output/WaylandOutput.hpp" #include "../window/WaylandLayer.hpp" #include "../window/WaylandLockSurface.hpp" +#include "../window/WaylandWindow.hpp" #include "../Macros.hpp" #include "../element/Element.hpp" #include "../palette/ConfigManager.hpp" @@ -103,6 +104,13 @@ void CBackend::unlockSession() { g_waylandPlatform->unlockSessionLock(); } +std::vector> CBackend::getOutputs() { + if (!g_waylandPlatform) + return {}; + + return std::vector>(g_waylandPlatform->m_outputs.begin(), g_waylandPlatform->m_outputs.end()); +} + SP CBackend::openWindow(const SWindowCreationData& data) { if (!g_waylandPlatform && !attempt()) return nullptr; diff --git a/src/core/Output.cpp b/src/core/Output.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index 45c4d33..8faa053 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -101,12 +101,13 @@ bool CWaylandPlatform::attempt() { } } else if (NAME == wl_output_interface.name) { TRACE(g_logger->log(HT_LOG_TRACE, " > binding to global: {} (version {}) with id {}", name, 4, id)); - m_outputs.emplace_back(makeUnique((wl_proxy*)wl_registry_bind((wl_registry*)m_waylandState.registry->resource(), id, &wl_output_interface, 4), id)); + auto newOutput = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_waylandState.registry->resource(), id, &wl_output_interface, 4), id); + m_outputs.emplace_back(newOutput); // FIXME: seems like m_idleCallbacks is not used and was moved to the loop state? // probably move that there?? // We just need to deferre it a bit so that the globals are defined before we emit the event. // But once they are defined, we probably don't want it to be a idle function. - m_idleCallbacks.emplace_back([id]() { g_backend->m_events.outputAdded.emit(id); }); + m_idleCallbacks.emplace_back([newOutput]() { g_backend->m_events.outputAdded.emit(newOutput); }); } else if (NAME == ext_session_lock_manager_v1_interface.name) { TRACE(g_logger->log(HT_LOG_TRACE, " > binding to global: {} (version {}) with id {}", name, 1, id)); m_waylandState.sessionLock = makeShared( @@ -116,14 +117,16 @@ bool CWaylandPlatform::attempt() { m_waylandState.registry->setGlobalRemove([this](CCWlRegistry* r, uint32_t id) { TRACE(g_logger->log(HT_LOG_TRACE, "Global {} removed", id)); - auto lockSurfaceIt = std::ranges::find_if(m_lockSurfaces, [id](const auto& other) { return other->m_outputId == id; }); + auto lockSurfaceIt = std::ranges::find_if(m_lockSurfaces, [id](const auto& other) { return other->m_outputHandle == id; }); if (lockSurfaceIt != m_lockSurfaces.end()) { (*lockSurfaceIt)->m_events.closeRequest.emit(); m_lockSurfaces.erase(lockSurfaceIt); } auto outputIt = std::ranges::find_if(m_outputs, [id](const auto& other) { return other->m_id == id; }); - if (outputIt != m_outputs.end()) + if (outputIt != m_outputs.end()) { + (*outputIt)->m_events.removed.emit(); m_outputs.erase(outputIt); + } }); wl_display_roundtrip(m_waylandState.display); @@ -211,9 +214,9 @@ SP CWaylandPlatform::windowForSurf(wl_proxy* proxy) { return nullptr; } -std::optional> CWaylandPlatform::outputForId(uint32_t id) { +std::optional> CWaylandPlatform::outputForHandle(uint32_t handle) { for (const auto& o : m_outputs) { - if (o->m_id == id) { + if (o->m_id == handle) { return o; } } diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index 6e48446..67670e6 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -53,7 +53,7 @@ namespace Hyprtoolkit { bool dispatchEvents(); SP windowForSurf(wl_proxy* proxy); - std::optional> outputForId(uint32_t id); + std::optional> outputForHandle(uint32_t handle); void onKey(uint32_t keycode, bool state); void startRepeatTimer(); @@ -132,7 +132,7 @@ namespace Hyprtoolkit { std::string nodeName = ""; } m_drmState; - std::vector> m_outputs; + std::vector> m_outputs; std::vector> m_windows; std::vector> m_layers; diff --git a/src/output/WaylandOutput.cpp b/src/output/WaylandOutput.cpp index 18a925e..8ea03ad 100644 --- a/src/output/WaylandOutput.cpp +++ b/src/output/WaylandOutput.cpp @@ -1,5 +1,6 @@ #include "WaylandOutput.hpp" #include "../core/InternalBackend.hpp" +#include "../helpers/Memory.hpp" using namespace Hyprtoolkit; @@ -18,26 +19,26 @@ static Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; } -CWaylandOutput::CWaylandOutput(wl_proxy* wlResource, uint32_t id) : m_id(id), m_wlOutput(wlResource) { - m_wlOutput.setDescription([this](CCWlOutput* r, const char* description) { +CWaylandOutput::CWaylandOutput(wl_proxy* wlResource, uint32_t id) : m_id(id), m_wlOutput(makeShared(wlResource)) { + m_wlOutput->setDescription([this](CCWlOutput* r, const char* description) { m_configuration.desc = description ? std::string{description} : ""; g_logger->log(HT_LOG_DEBUG, "wayland output {}: description {}", m_id, m_configuration.desc); }); - m_wlOutput.setName([this](CCWlOutput* r, const char* name) { + m_wlOutput->setName([this](CCWlOutput* r, const char* name) { m_configuration.name = std::string{name} + m_configuration.name; m_configuration.port = std::string{name}; g_logger->log(HT_LOG_DEBUG, "wayland output {}: name {}", m_id, name); }); - m_wlOutput.setScale([this](CCWlOutput* r, int32_t sc) { m_configuration.scale = sc; }); + m_wlOutput->setScale([this](CCWlOutput* r, int32_t sc) { m_configuration.scale = sc; }); - m_wlOutput.setDone([this](CCWlOutput* r) { + m_wlOutput->setDone([this](CCWlOutput* r) { m_configuration.done = true; g_logger->log(HT_LOG_DEBUG, "wayland output {}: done", m_id); }); - m_wlOutput.setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { + m_wlOutput->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { // handle portrait mode and flipped cases if (m_configuration.transform % 2 == 1) m_configuration.size = {height, width}; @@ -47,10 +48,14 @@ CWaylandOutput::CWaylandOutput(wl_proxy* wlResource, uint32_t id) : m_id(id), m_ g_logger->log(HT_LOG_DEBUG, "wayland output {}: dimensions {}", m_id, m_configuration.size); }); - m_wlOutput.setGeometry( + m_wlOutput->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_) { m_configuration.transform = wlTransformToHyprutils((wl_output_transform)transform_); g_logger->log(HT_LOG_DEBUG, "wayland output {}: make {} model {}", m_id, make ? make : "", model ? model : ""); }); } + +uint32_t CWaylandOutput::handle() { + return m_id; +} diff --git a/src/output/WaylandOutput.hpp b/src/output/WaylandOutput.hpp index 8d7de7f..c470781 100644 --- a/src/output/WaylandOutput.hpp +++ b/src/output/WaylandOutput.hpp @@ -1,20 +1,25 @@ #pragma once #include "wayland.hpp" + +#include + #include #include #include #include namespace Hyprtoolkit { - class CWaylandOutput { + class CWaylandOutput : public IOutput { public: CWaylandOutput(wl_proxy* wlResource, uint32_t id); ~CWaylandOutput() = default; - uint32_t m_id = 0; - bool m_focused = false; - CCWlOutput m_wlOutput; + virtual uint32_t handle(); + + uint32_t m_id = 0; + bool m_focused = false; + Hyprutils::Memory::CSharedPointer m_wlOutput = nullptr; struct { bool done = false; diff --git a/src/window/Builder.cpp b/src/window/Builder.cpp index d07d400..2b0a08d 100644 --- a/src/window/Builder.cpp +++ b/src/window/Builder.cpp @@ -1,8 +1,7 @@ #include "Window.hpp" #include "../core/InternalBackend.hpp" +#include #include "ToolkitWindow.hpp" -#include "core/platforms/WaylandPlatform.hpp" -#include "hyprtoolkit/core/LogTypes.hpp" using namespace Hyprtoolkit; @@ -43,8 +42,8 @@ SP CWindowBuilder::maxSize(const Hyprutils::Math::Vector2D& x) { return m_self.lock(); } -SP CWindowBuilder::prefferedOutput(uint32_t x) { - m_data->prefferedOutputId = x; +SP CWindowBuilder::prefferedOutput(const SP& x) { + m_data->prefferedOutputId = x->handle(); return m_self.lock(); } diff --git a/src/window/WaylandLockSurface.cpp b/src/window/WaylandLockSurface.cpp index 507ad61..502ae98 100644 --- a/src/window/WaylandLockSurface.cpp +++ b/src/window/WaylandLockSurface.cpp @@ -16,7 +16,7 @@ using namespace Hyprtoolkit; using namespace Hyprutils::Math; -CWaylandLockSurface::CWaylandLockSurface(const SWindowCreationData& data) : m_outputId(data.prefferedOutputId) { +CWaylandLockSurface::CWaylandLockSurface(const SWindowCreationData& data) : m_outputHandle(data.prefferedOutputId) { m_rootElement = CNullBuilder::begin()->commence(); } @@ -28,7 +28,7 @@ void CWaylandLockSurface::open() { if (m_open) return; - if (m_outputId == 0) { + if (m_outputHandle == 0) { g_logger->log(HT_LOG_ERROR, "session lock missing prefferedOutputId."); return; } @@ -42,7 +42,7 @@ void CWaylandLockSurface::open() { if (!lockObject) return; - auto wlOutput = g_waylandPlatform->outputForId(m_outputId); + auto wlOutput = g_waylandPlatform->outputForHandle(m_outputHandle); if (!wlOutput.has_value() || !wlOutput.value()) return; @@ -80,7 +80,7 @@ void CWaylandLockSurface::open() { m_waylandState.surface->sendAttach(nullptr, 0, 0); m_lockSurfaceState.lockSurface = - makeShared(lockObject->sendGetLockSurface(m_waylandState.surface->resource(), wlOutput.value()->m_wlOutput.resource())); + makeShared(lockObject->sendGetLockSurface(m_waylandState.surface->resource(), wlOutput.value()->m_wlOutput->resource())); if (!m_lockSurfaceState.lockSurface->resource()) { g_logger->log(HT_LOG_ERROR, "lock surface opening failed: no lock surface. Errno: {}", errno); return; diff --git a/src/window/WaylandLockSurface.hpp b/src/window/WaylandLockSurface.hpp index 7fc427b..6315df8 100644 --- a/src/window/WaylandLockSurface.hpp +++ b/src/window/WaylandLockSurface.hpp @@ -14,7 +14,7 @@ namespace Hyprtoolkit { virtual void render(); private: - uint32_t m_outputId = 0; + uint32_t m_outputHandle = 0; struct { SP lockSurface; diff --git a/tests/SimpleSessionLock.cpp b/tests/SimpleSessionLock.cpp index b304442..9740345 100644 --- a/tests/SimpleSessionLock.cpp +++ b/tests/SimpleSessionLock.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -121,6 +122,14 @@ int main(int argc, char** argv, char** envp) { for (const auto& w : windows) { closeWindow(w); } + + backend->m_events.outputAdded.listenStatic([](SP output) { + windows.emplace_back(CWindowBuilder::begin()->type(HT_WINDOW_LOCK_SURFACE)->prefferedOutput(output)->commence()); + std::println("New surface {}!", (uintptr_t)windows.back().get()); + WP window = windows.back(); + window->m_events.closeRequest.listenStatic([window]() { onWindowClose(window); }); + + layout(window.lock()); }); if (!CBackend::attempt()) { From 82c278f65aab7c9c591ab9540bf7bd88bd89d69d Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Fri, 17 Oct 2025 16:06:40 +0200 Subject: [PATCH 05/16] add better emit of outputAdded --- include/hyprtoolkit/core/Backend.hpp | 4 ++-- src/core/platforms/WaylandPlatform.cpp | 18 +++++++----------- src/core/platforms/WaylandPlatform.hpp | 4 +--- tests/SimpleSessionLock.cpp | 18 +++++------------- 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/include/hyprtoolkit/core/Backend.hpp b/include/hyprtoolkit/core/Backend.hpp index 29dab7d..a9cde22 100644 --- a/include/hyprtoolkit/core/Backend.hpp +++ b/include/hyprtoolkit/core/Backend.hpp @@ -35,10 +35,10 @@ namespace Hyprtoolkit { /* Attempt to initialize the platform. - Optional. Can be used in case the outputAdded/Removed events are used to create new windows. + Optional. Can be used in case the outputAdded event is used to create new windows. In such a szenario the platform must be initialized before opening a window. */ - static bool attempt(); + bool attempt(); /* Destroy the backend. diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index 8faa053..9d6960a 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -103,11 +103,8 @@ bool CWaylandPlatform::attempt() { TRACE(g_logger->log(HT_LOG_TRACE, " > binding to global: {} (version {}) with id {}", name, 4, id)); auto newOutput = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_waylandState.registry->resource(), id, &wl_output_interface, 4), id); m_outputs.emplace_back(newOutput); - // FIXME: seems like m_idleCallbacks is not used and was moved to the loop state? - // probably move that there?? - // We just need to deferre it a bit so that the globals are defined before we emit the event. - // But once they are defined, we probably don't want it to be a idle function. - m_idleCallbacks.emplace_back([newOutput]() { g_backend->m_events.outputAdded.emit(newOutput); }); + if (m_waylandState.initialized) + g_backend->m_events.outputAdded.emit(newOutput); } else if (NAME == ext_session_lock_manager_v1_interface.name) { TRACE(g_logger->log(HT_LOG_TRACE, " > binding to global: {} (version {}) with id {}", name, 1, id)); m_waylandState.sessionLock = makeShared( @@ -141,6 +138,11 @@ bool CWaylandPlatform::attempt() { dispatchEvents(); + m_waylandState.initialized = true; + for (const auto& o : m_outputs) { + g_backend->m_events.outputAdded.emit(o); + } + return true; } @@ -177,12 +179,6 @@ bool CWaylandPlatform::dispatchEvents() { wl_display_flush(m_waylandState.display); } while (ret > 0); - // dispatch frames - for (auto const& f : m_idleCallbacks) { - f(); - } - m_idleCallbacks.clear(); - return true; } diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index 67670e6..5062177 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -64,9 +64,6 @@ namespace Hyprtoolkit { SP aquireSessionLock(); void unlockSessionLock(); - // - std::vector m_idleCallbacks; - // dmabuf formats std::vector m_dmabufFormats; @@ -96,6 +93,7 @@ namespace Hyprtoolkit { Hyprutils::Memory::CSharedPointer sessionLock; // control + bool initialized = false; bool dmabufFailed = false; struct { diff --git a/tests/SimpleSessionLock.cpp b/tests/SimpleSessionLock.cpp index 9740345..dfdb46d 100644 --- a/tests/SimpleSessionLock.cpp +++ b/tests/SimpleSessionLock.cpp @@ -104,40 +104,32 @@ int main(int argc, char** argv, char** envp) { int unlockSecs = 1; if (argc == 2) unlockSecs = atoi(argv[1]); - + backend = IBackend::create(); if (!backend) { std::println("Backend create failed!"); return 1; } - + auto sessionLock = backend->aquireSessionLock(); if (!sessionLock.has_value()) { std::println("Cloudn't lock"); return 1; } - + sessionLock.value()->m_events.finished.listenStatic([] { std::println("Compositor kicked us"); for (const auto& w : windows) { closeWindow(w); } - - backend->m_events.outputAdded.listenStatic([](SP output) { - windows.emplace_back(CWindowBuilder::begin()->type(HT_WINDOW_LOCK_SURFACE)->prefferedOutput(output)->commence()); - std::println("New surface {}!", (uintptr_t)windows.back().get()); - WP window = windows.back(); - window->m_events.closeRequest.listenStatic([window]() { onWindowClose(window); }); - - layout(window.lock()); }); - if (!CBackend::attempt()) { + if (!backend->attempt()) { std::println("Backend attempt failed!"); return -1; } - backend->addTimer(std::chrono::seconds(5), [](auto, auto) { backend->unlockSession(); }, nullptr); + backend->addTimer(std::chrono::seconds(unlockSecs), [](auto, auto) { backend->unlockSession(); }, nullptr); backend->enterLoop(); From 11689ade01f701ad7e64201829752ef522074072 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Sat, 18 Oct 2025 11:59:13 +0200 Subject: [PATCH 06/16] add m_lockSurfaces to windowForSurf to make click work --- src/core/platforms/WaylandPlatform.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index 9d6960a..a9df509 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -207,6 +207,11 @@ SP CWaylandPlatform::windowForSurf(wl_proxy* proxy) { return pp; } } + + for (const auto& w : m_lockSurfaces) { + if (w->m_waylandState.surface && w->m_waylandState.surface->resource() == proxy) + return w.lock(); + } return nullptr; } From 914480c06a83fed38651322e44e9bb2471523798 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Sat, 18 Oct 2025 12:14:12 +0200 Subject: [PATCH 07/16] handle CCExtSessionLockV1 finished event --- src/core/platforms/WaylandPlatform.cpp | 20 ++++++++++++++------ src/core/platforms/WaylandPlatform.hpp | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index a9df509..b55ade8 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -645,11 +645,11 @@ void CWaylandPlatform::stopRepeatTimer() { SP CWaylandPlatform::aquireSessionLock() { if (m_waylandState.sessionLockState.sessionLocked && m_waylandState.sessionLockState.sessionUnlocked) { - g_logger->log(HT_LOG_ERROR, "We already unlocked. We shouldn't be calling aquireSessionLock?"); + g_logger->log(HT_LOG_ERROR, "We already unlocked. We shouldn't be calling aquireSessionLock."); return nullptr; } - if (!m_waylandState.sessionLockState.lock) { + if (!m_waylandState.sessionLockState.lock && !m_waylandState.sessionLockState.denied) { m_waylandState.sessionLockState.lock = makeShared(m_waylandState.sessionLock->sendLock()); if (!m_waylandState.sessionLockState.lock) { g_logger->log(HT_LOG_ERROR, "Failed to create a session lock object!"); @@ -658,13 +658,21 @@ SP CWaylandPlatform::aquireSessionLock() { m_waylandState.sessionLockState.lock->setLocked([this](CCExtSessionLockV1* r) { m_waylandState.sessionLockState.sessionLocked = true; }); - m_waylandState.sessionLockState.lock->setFinished([](CCExtSessionLockV1* r) { //FIXME: we need to make sure the client can exit after this event + m_waylandState.sessionLockState.lock->setFinished([this](CCExtSessionLockV1* r) { + g_logger->log(HT_LOG_ERROR, "We got denied by the compositor to be the exclusive lock screen client. Is there another lock screen active?"); + for (const auto& w : m_lockSurfaces) { + if (w.expired()) + continue; + w->m_events.closeRequest.emit(); + } + + m_lockSurfaces.clear(); + m_waylandState.sessionLockState.lock.reset(); + m_waylandState.sessionLockState.denied = true; }); // roundtrip in case the compositor sends `finished` right away wl_display_roundtrip(m_waylandState.display); - - // FIXME: we need to test if finished was sent right here too! } return m_waylandState.sessionLockState.lock; @@ -675,7 +683,7 @@ void CWaylandPlatform::unlockSessionLock() { return; m_waylandState.sessionLockState.lock->sendUnlockAndDestroy(); - m_waylandState.sessionLockState.lock = nullptr; + m_waylandState.sessionLockState.lock.reset(); m_waylandState.sessionLockState.sessionUnlocked = true; // roundtrip in order to make sure we have unlocked before sending closeRequest diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index 5062177..4ce4a99 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -122,6 +122,7 @@ namespace Hyprtoolkit { SP lock = nullptr; bool sessionLocked = false; bool sessionUnlocked = false; + bool denied = false; // set on the finished event } sessionLockState; } m_waylandState; From 4a57813a006f6107ca4e3b3c18fd5a7f7533fc9e Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Sun, 19 Oct 2025 13:09:33 +0200 Subject: [PATCH 08/16] add needed stuff to IOutput --- include/hyprtoolkit/core/Output.hpp | 7 +++++-- src/output/WaylandOutput.cpp | 8 ++++++++ src/output/WaylandOutput.hpp | 2 ++ src/window/WaylandLockSurface.cpp | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/hyprtoolkit/core/Output.hpp b/include/hyprtoolkit/core/Output.hpp index 71cc8f5..43a35c5 100644 --- a/include/hyprtoolkit/core/Output.hpp +++ b/include/hyprtoolkit/core/Output.hpp @@ -1,12 +1,15 @@ #pragma once #include +#include namespace Hyprtoolkit { class IOutput { public: - virtual ~IOutput() = default; - virtual uint32_t handle() = 0; + virtual ~IOutput() = default; + virtual uint32_t handle() = 0; + virtual std::string port() = 0; + virtual std::string desc() = 0; struct { // output removed diff --git a/src/output/WaylandOutput.cpp b/src/output/WaylandOutput.cpp index 8ea03ad..fd38a32 100644 --- a/src/output/WaylandOutput.cpp +++ b/src/output/WaylandOutput.cpp @@ -59,3 +59,11 @@ CWaylandOutput::CWaylandOutput(wl_proxy* wlResource, uint32_t id) : m_id(id), m_ uint32_t CWaylandOutput::handle() { return m_id; } + +std::string CWaylandOutput::port() { + return m_configuration.port; +} + +std::string CWaylandOutput::desc() { + return m_configuration.desc; +} diff --git a/src/output/WaylandOutput.hpp b/src/output/WaylandOutput.hpp index c470781..c6edd36 100644 --- a/src/output/WaylandOutput.hpp +++ b/src/output/WaylandOutput.hpp @@ -16,6 +16,8 @@ namespace Hyprtoolkit { ~CWaylandOutput() = default; virtual uint32_t handle(); + virtual std::string port(); + virtual std::string desc(); uint32_t m_id = 0; bool m_focused = false; diff --git a/src/window/WaylandLockSurface.cpp b/src/window/WaylandLockSurface.cpp index 502ae98..8b45656 100644 --- a/src/window/WaylandLockSurface.cpp +++ b/src/window/WaylandLockSurface.cpp @@ -69,7 +69,7 @@ void CWaylandLockSurface::open() { const bool SAMESCALE = m_fractionalScale == scale / 120.0; m_fractionalScale = scale / 120.0; - g_logger->log(HT_LOG_DEBUG, "layer: got fractional scale: {:.1f}%", m_fractionalScale * 100.F); + g_logger->log(HT_LOG_DEBUG, "lock surface: got fractional scale: {:.1f}%", m_fractionalScale * 100.F); if (!SAMESCALE && m_lockSurfaceState.configured) onScaleUpdate(); From 6358473a9230eab6bc17d3b9e25922548a8aa407 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Thu, 23 Oct 2025 08:39:19 +0200 Subject: [PATCH 09/16] remove CBackend::attempt --- include/hyprtoolkit/core/Backend.hpp | 7 ----- src/core/Backend.cpp | 14 ++++----- tests/SimpleSessionLock.cpp | 45 +++++++++++++--------------- 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/include/hyprtoolkit/core/Backend.hpp b/include/hyprtoolkit/core/Backend.hpp index a9cde22..efc899b 100644 --- a/include/hyprtoolkit/core/Backend.hpp +++ b/include/hyprtoolkit/core/Backend.hpp @@ -33,13 +33,6 @@ namespace Hyprtoolkit { */ static Hyprutils::Memory::CSharedPointer create(); - /* - Attempt to initialize the platform. - Optional. Can be used in case the outputAdded event is used to create new windows. - In such a szenario the platform must be initialized before opening a window. - */ - bool attempt(); - /* Destroy the backend. Backend will be destroyed once: diff --git a/src/core/Backend.cpp b/src/core/Backend.cpp index fde981e..649cfc6 100644 --- a/src/core/Backend.cpp +++ b/src/core/Backend.cpp @@ -70,20 +70,16 @@ SP IBackend::create() { g_logger->log(HT_LOG_ERROR, "couldn't start aq backend"); return nullptr; } - - return g_backend; -}; - -bool CBackend::attempt() { g_waylandPlatform = makeUnique(); if (!g_waylandPlatform->attempt()) { g_waylandPlatform = nullptr; - return false; + return nullptr; } g_openGL = makeShared(g_waylandPlatform->m_drmState.fd); g_renderer = g_openGL; - return true; -} + + return g_backend; +}; void CBackend::destroy() { terminate(); @@ -112,7 +108,7 @@ std::vector> CBackend::getOutputs() { } SP CBackend::openWindow(const SWindowCreationData& data) { - if (!g_waylandPlatform && !attempt()) + if (!g_waylandPlatform) return nullptr; if (data.type == HT_WINDOW_LAYER) { diff --git a/tests/SimpleSessionLock.cpp b/tests/SimpleSessionLock.cpp index dfdb46d..c1d565a 100644 --- a/tests/SimpleSessionLock.cpp +++ b/tests/SimpleSessionLock.cpp @@ -51,7 +51,7 @@ static void layout(const SP& window) { auto rect4 = CRectangleBuilder::begin() // ->color([] { return CHyprColor{0.4F, 0.2F, 0.4F}; }) - ->rounding(10) + ->rounding(0) ->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {50, 50}}) ->commence(); @@ -62,12 +62,12 @@ static void layout(const SP& window) { ->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {447, 447}}) ->commence(); - auto text = CTextBuilder::begin()->text("world is a fuck")->color([] { return CHyprColor{0.4F, 0.4F, 0.4F}; })->commence(); + auto text = CTextBuilder::begin()->text("never give up")->color([] { return CHyprColor{0.4F, 0.4F, 0.4F}; })->commence(); auto button = CButtonBuilder::begin() - ->label("Click me bitch") - ->onMainClick([](SP el) { el->rebuild()->label(std::format("Clicked {} times bitch", buttonClicks++))->commence(); }) - ->onRightClick([](SP el) { el->rebuild()->label("Reset bitch")->commence(); }) + ->label("Click me kind person") + ->onMainClick([](SP el) { el->rebuild()->label(std::format("Clicked {} times", buttonClicks++))->commence(); }) + ->onRightClick([](SP el) { el->rebuild()->label("Reset")->commence(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence(); @@ -100,33 +100,30 @@ static void onWindowClose(WP window) { } } +static void createLockSurface(SP output) { + windows.emplace_back(CWindowBuilder::begin()->type(HT_WINDOW_LOCK_SURFACE)->prefferedOutput(output)->commence()); + std::println("New surface {}!", (uintptr_t)windows.back().get()); + WP weakWindow = windows.back(); + weakWindow->m_events.closeRequest.listenStatic([weakWindow]() { onWindowClose(weakWindow); }); + + layout(weakWindow.lock()); +} + int main(int argc, char** argv, char** envp) { int unlockSecs = 1; if (argc == 2) unlockSecs = atoi(argv[1]); - + backend = IBackend::create(); if (!backend) { std::println("Backend create failed!"); - return 1; - } - - auto sessionLock = backend->aquireSessionLock(); - if (!sessionLock.has_value()) { - std::println("Cloudn't lock"); - return 1; + return -1; } - - sessionLock.value()->m_events.finished.listenStatic([] { - std::println("Compositor kicked us"); - for (const auto& w : windows) { - closeWindow(w); - } - }); - - if (!backend->attempt()) { - std::println("Backend attempt failed!"); - return -1; + + backend->m_events.outputAdded.listenStatic(createLockSurface); + + for (const auto& o: backend->getOutputs()) { + createLockSurface(o); } backend->addTimer(std::chrono::seconds(unlockSecs), [](auto, auto) { backend->unlockSession(); }, nullptr); From bb734beb38d29cb7f98df1e7ea6c15e3fae9d26d Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Fri, 24 Oct 2025 07:55:06 +0200 Subject: [PATCH 10/16] add lockDenied event to the backend Lock screens need to know when to exit without an unlock. --- include/hyprtoolkit/core/Backend.hpp | 5 +++++ include/hyprtoolkit/core/Output.hpp | 8 ++++---- src/core/platforms/WaylandPlatform.cpp | 2 ++ tests/SimpleSessionLock.cpp | 1 + 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/hyprtoolkit/core/Backend.hpp b/include/hyprtoolkit/core/Backend.hpp index efc899b..6762a0b 100644 --- a/include/hyprtoolkit/core/Backend.hpp +++ b/include/hyprtoolkit/core/Backend.hpp @@ -91,6 +91,11 @@ namespace Hyprtoolkit { Get notified when a new output was added. */ Hyprutils::Signal::CSignalT> outputAdded; + + /* + Sent when the compositor denies us as the exclusive lock screen client. + */ + Hyprutils::Signal::CSignalT<> lockDenied; } m_events; protected: diff --git a/include/hyprtoolkit/core/Output.hpp b/include/hyprtoolkit/core/Output.hpp index 43a35c5..4abd68f 100644 --- a/include/hyprtoolkit/core/Output.hpp +++ b/include/hyprtoolkit/core/Output.hpp @@ -6,10 +6,10 @@ namespace Hyprtoolkit { class IOutput { public: - virtual ~IOutput() = default; - virtual uint32_t handle() = 0; - virtual std::string port() = 0; - virtual std::string desc() = 0; + virtual ~IOutput() = default; + virtual uint32_t handle() = 0; + virtual std::string port() = 0; + virtual std::string desc() = 0; struct { // output removed diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index b55ade8..91a72d2 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -660,6 +660,8 @@ SP CWaylandPlatform::aquireSessionLock() { m_waylandState.sessionLockState.lock->setFinished([this](CCExtSessionLockV1* r) { g_logger->log(HT_LOG_ERROR, "We got denied by the compositor to be the exclusive lock screen client. Is there another lock screen active?"); + g_backend->m_events.lockDenied.emit(); + for (const auto& w : m_lockSurfaces) { if (w.expired()) continue; diff --git a/tests/SimpleSessionLock.cpp b/tests/SimpleSessionLock.cpp index c1d565a..cd12ca6 100644 --- a/tests/SimpleSessionLock.cpp +++ b/tests/SimpleSessionLock.cpp @@ -121,6 +121,7 @@ int main(int argc, char** argv, char** envp) { } backend->m_events.outputAdded.listenStatic(createLockSurface); + backend->m_events.lockDenied.listenStatic([] { std::println("Lock denied!"); }); for (const auto& o: backend->getOutputs()) { createLockSurface(o); From 3503760180ee5d16d9c77165e40a510d07052a07 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Fri, 24 Oct 2025 08:17:59 +0200 Subject: [PATCH 11/16] add IOutput->fps --- include/hyprtoolkit/core/Output.hpp | 1 + src/output/WaylandOutput.cpp | 4 ++++ src/output/WaylandOutput.hpp | 5 ++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/hyprtoolkit/core/Output.hpp b/include/hyprtoolkit/core/Output.hpp index 4abd68f..94579fa 100644 --- a/include/hyprtoolkit/core/Output.hpp +++ b/include/hyprtoolkit/core/Output.hpp @@ -10,6 +10,7 @@ namespace Hyprtoolkit { virtual uint32_t handle() = 0; virtual std::string port() = 0; virtual std::string desc() = 0; + virtual uint32_t fps() = 0; struct { // output removed diff --git a/src/output/WaylandOutput.cpp b/src/output/WaylandOutput.cpp index fd38a32..bebb27a 100644 --- a/src/output/WaylandOutput.cpp +++ b/src/output/WaylandOutput.cpp @@ -67,3 +67,7 @@ std::string CWaylandOutput::port() { std::string CWaylandOutput::desc() { return m_configuration.desc; } + +uint32_t CWaylandOutput::fps() { + return m_configuration.fps; +} diff --git a/src/output/WaylandOutput.hpp b/src/output/WaylandOutput.hpp index c6edd36..d14d9ef 100644 --- a/src/output/WaylandOutput.hpp +++ b/src/output/WaylandOutput.hpp @@ -2,6 +2,7 @@ #include "wayland.hpp" +#include #include #include @@ -18,6 +19,7 @@ namespace Hyprtoolkit { virtual uint32_t handle(); virtual std::string port(); virtual std::string desc(); + virtual uint32_t fps(); uint32_t m_id = 0; bool m_focused = false; @@ -27,7 +29,8 @@ namespace Hyprtoolkit { bool done = false; Hyprutils::Math::eTransform transform = Hyprutils::Math::HYPRUTILS_TRANSFORM_NORMAL; Hyprutils::Math::Vector2D size; - int scale = 1; + uint32_t fps = 60; + uint32_t scale = 1; std::string name = ""; std::string port = ""; std::string desc = ""; From 283c51599b387e8f133820d1d8cb1c9b03fd3669 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Tue, 28 Oct 2025 19:55:02 +0100 Subject: [PATCH 12/16] add ISessionLockState and aquireSessionLock to CBackend --- include/hyprtoolkit/core/Backend.hpp | 13 ++-- include/hyprtoolkit/core/SessionLock.hpp | 22 +++++++ src/core/Backend.cpp | 22 ++++--- src/core/Output.cpp | 0 src/core/platforms/WaylandPlatform.cpp | 76 ++++++------------------ src/core/platforms/WaylandPlatform.hpp | 54 ++++++++--------- src/lock/WaylandSessionLock.cpp | 50 ++++++++++++++++ src/lock/WaylandSessionLock.hpp | 27 +++++++++ src/window/WaylandLockSurface.cpp | 8 +-- src/window/WaylandLockSurface.hpp | 3 +- tests/SimpleSessionLock.cpp | 30 +++++++--- 11 files changed, 188 insertions(+), 117 deletions(-) create mode 100644 include/hyprtoolkit/core/SessionLock.hpp delete mode 100644 src/core/Output.cpp create mode 100644 src/lock/WaylandSessionLock.cpp create mode 100644 src/lock/WaylandSessionLock.hpp diff --git a/include/hyprtoolkit/core/Backend.hpp b/include/hyprtoolkit/core/Backend.hpp index 6762a0b..c2d2892 100644 --- a/include/hyprtoolkit/core/Backend.hpp +++ b/include/hyprtoolkit/core/Backend.hpp @@ -5,10 +5,12 @@ #include #include #include +#include #include #include #include "LogTypes.hpp" +#include "SessionLock.hpp" #include "../palette/Palette.hpp" #include "CoreMacros.hpp" @@ -81,21 +83,16 @@ namespace Hyprtoolkit { virtual std::vector> getOutputs() = 0; /* - Get currently registered outputs. - Make sure you register the `removed` event to get rid of your reference once the output is removed. + Create and lock the graphical session. + It is required to call this before HT_WINDOW_LOCK_SURFACE can be used. */ - std::vector> getOutputs(); + virtual std::expected, eSessionLockError> aquireSessionLock() = 0; struct { /* Get notified when a new output was added. */ Hyprutils::Signal::CSignalT> outputAdded; - - /* - Sent when the compositor denies us as the exclusive lock screen client. - */ - Hyprutils::Signal::CSignalT<> lockDenied; } m_events; protected: diff --git a/include/hyprtoolkit/core/SessionLock.hpp b/include/hyprtoolkit/core/SessionLock.hpp new file mode 100644 index 0000000..2bc553b --- /dev/null +++ b/include/hyprtoolkit/core/SessionLock.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +namespace Hyprtoolkit { + enum eSessionLockError : uint8_t { + PLATFORM_UNINTIALIZED, + DENIED, + }; + + class ISessionLockState { + public: + virtual ~ISessionLockState() = default; + virtual void unlock() = 0; + + struct { + /* signals that we don't need to unlock anymore. It makes sense to exit upon recieving this */ + Hyprutils::Signal::CSignalT<> finished; + } m_events; + }; +} diff --git a/src/core/Backend.cpp b/src/core/Backend.cpp index 649cfc6..27047e3 100644 --- a/src/core/Backend.cpp +++ b/src/core/Backend.cpp @@ -16,6 +16,7 @@ #include "../element/Element.hpp" #include "../palette/ConfigManager.hpp" #include "../system/Icons.hpp" +#include "hyprtoolkit/core/SystemLock.hpp" #include #include @@ -93,18 +94,22 @@ SP CBackend::getPalette() { return g_palette; } -void CBackend::unlockSession() { +std::vector> CBackend::getOutputs() { if (!g_waylandPlatform) - return; + return {}; - g_waylandPlatform->unlockSessionLock(); + return std::vector>(g_waylandPlatform->m_outputs.begin(), g_waylandPlatform->m_outputs.end()); } -std::vector> CBackend::getOutputs() { +std::expected, eSessionLockError> CBackend::aquireSessionLock() { if (!g_waylandPlatform) - return {}; + return std::unexpected(PLATFORM_UNINTIALIZED); - return std::vector>(g_waylandPlatform->m_outputs.begin(), g_waylandPlatform->m_outputs.end()); + auto lockState = g_waylandPlatform->aquireSessionLock(); + if (!lockState || lockState->m_denied) + return std::unexpected(DENIED); + + return lockState; } SP CBackend::openWindow(const SWindowCreationData& data) { @@ -126,10 +131,13 @@ SP CBackend::openWindow(const SWindowCreationData& data) { return nullptr; } + if (!g_waylandPlatform->m_sessionLockState || g_waylandPlatform->m_sessionLockState->m_denied || g_waylandPlatform->m_sessionLockState->m_sessionUnlocked) + return nullptr; + auto w = makeShared(data); w->m_self = w; w->m_rootElement->impl->window = w; - g_waylandPlatform->m_lockSurfaces.emplace_back(w); + g_waylandPlatform->m_sessionLockState->m_lockSurfaces.emplace_back(w); return w; } diff --git a/src/core/Output.cpp b/src/core/Output.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index 91a72d2..eb79e36 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -1,6 +1,7 @@ #include "WaylandPlatform.hpp" #include +#include #include #include #include @@ -14,6 +15,8 @@ #include "../../output/WaylandOutput.hpp" #include "../../sessionLock/WaylandSessionLock.hpp" #include "../../Macros.hpp" +#include "ext-session-lock-v1.hpp" +#include "hyprtoolkit/core/SystemLock.hpp" #include #include @@ -114,11 +117,9 @@ bool CWaylandPlatform::attempt() { m_waylandState.registry->setGlobalRemove([this](CCWlRegistry* r, uint32_t id) { TRACE(g_logger->log(HT_LOG_TRACE, "Global {} removed", id)); - auto lockSurfaceIt = std::ranges::find_if(m_lockSurfaces, [id](const auto& other) { return other->m_outputHandle == id; }); - if (lockSurfaceIt != m_lockSurfaces.end()) { - (*lockSurfaceIt)->m_events.closeRequest.emit(); - m_lockSurfaces.erase(lockSurfaceIt); - } + if (m_sessionLockState) + m_sessionLockState->onOutputRemoved(id); + auto outputIt = std::ranges::find_if(m_outputs, [id](const auto& other) { return other->m_id == id; }); if (outputIt != m_outputs.end()) { (*outputIt)->m_events.removed.emit(); @@ -208,9 +209,11 @@ SP CWaylandPlatform::windowForSurf(wl_proxy* proxy) { } } - for (const auto& w : m_lockSurfaces) { - if (w->m_waylandState.surface && w->m_waylandState.surface->resource() == proxy) - return w.lock(); + if (m_sessionLockState) { + for (const auto& w : m_sessionLockState->m_lockSurfaces) { + if (w->m_waylandState.surface && w->m_waylandState.surface->resource() == proxy) + return w.lock(); + } } return nullptr; } @@ -643,59 +646,16 @@ void CWaylandPlatform::stopRepeatTimer() { m_waylandState.seatState.repeatTimer.reset(); } -SP CWaylandPlatform::aquireSessionLock() { - if (m_waylandState.sessionLockState.sessionLocked && m_waylandState.sessionLockState.sessionUnlocked) { - g_logger->log(HT_LOG_ERROR, "We already unlocked. We shouldn't be calling aquireSessionLock."); - return nullptr; - } - - if (!m_waylandState.sessionLockState.lock && !m_waylandState.sessionLockState.denied) { - m_waylandState.sessionLockState.lock = makeShared(m_waylandState.sessionLock->sendLock()); - if (!m_waylandState.sessionLockState.lock) { - g_logger->log(HT_LOG_ERROR, "Failed to create a session lock object!"); - return nullptr; - } - - m_waylandState.sessionLockState.lock->setLocked([this](CCExtSessionLockV1* r) { m_waylandState.sessionLockState.sessionLocked = true; }); - - m_waylandState.sessionLockState.lock->setFinished([this](CCExtSessionLockV1* r) { - g_logger->log(HT_LOG_ERROR, "We got denied by the compositor to be the exclusive lock screen client. Is there another lock screen active?"); - g_backend->m_events.lockDenied.emit(); - - for (const auto& w : m_lockSurfaces) { - if (w.expired()) - continue; - w->m_events.closeRequest.emit(); - } - - m_lockSurfaces.clear(); - m_waylandState.sessionLockState.lock.reset(); - m_waylandState.sessionLockState.denied = true; - }); - - // roundtrip in case the compositor sends `finished` right away - wl_display_roundtrip(m_waylandState.display); - } - - return m_waylandState.sessionLockState.lock; -} - -void CWaylandPlatform::unlockSessionLock() { - if (!m_waylandState.sessionLockState.lock) - return; +SP CWaylandPlatform::aquireSessionLock() { + if (m_sessionLockState) + return m_sessionLockState.lock(); - m_waylandState.sessionLockState.lock->sendUnlockAndDestroy(); - m_waylandState.sessionLockState.lock.reset(); - m_waylandState.sessionLockState.sessionUnlocked = true; + auto sessionLock = makeShared(makeShared(m_waylandState.sessionLock->sendLock())); - // roundtrip in order to make sure we have unlocked before sending closeRequest + // roundtrip in case the compositor sends `finished` right away wl_display_roundtrip(m_waylandState.display); - for (const auto& sls : m_lockSurfaces) { - if (sls.expired()) - continue; - sls->m_events.closeRequest.emit(); - } + m_sessionLockState = sessionLock; - m_lockSurfaces.clear(); + return sessionLock; } diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index 4ce4a99..24a7f12 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -5,6 +5,7 @@ #include #include "../../helpers/Memory.hpp" +#include "lock/WaylandSessionLock.hpp" #include #include @@ -35,34 +36,33 @@ namespace Hyprtoolkit { class IWaylandWindow; class CWaylandLayer; class CWaylandOutput; - class CWaylandLockSurface; + class CWaylandSessionLockState; class CWaylandPlatform { public: CWaylandPlatform() = default; ~CWaylandPlatform(); - bool attempt(); + bool attempt(); - void initSeat(); - void initShell(); - bool initDmabuf(); - void initIM(); - void setCursor(ePointerShape shape); + void initSeat(); + void initShell(); + bool initDmabuf(); + void initIM(); + void setCursor(ePointerShape shape); - bool dispatchEvents(); + bool dispatchEvents(); - SP windowForSurf(wl_proxy* proxy); - std::optional> outputForHandle(uint32_t handle); + SP windowForSurf(wl_proxy* proxy); + std::optional> outputForHandle(uint32_t handle); - void onKey(uint32_t keycode, bool state); - void startRepeatTimer(); - void stopRepeatTimer(); + void onKey(uint32_t keycode, bool state); + void startRepeatTimer(); + void stopRepeatTimer(); - void onRepeatTimerFire(); + void onRepeatTimerFire(); - SP aquireSessionLock(); - void unlockSessionLock(); + SP aquireSessionLock(); // dmabuf formats std::vector m_dmabufFormats; @@ -117,13 +117,6 @@ namespace Hyprtoolkit { std::string originalString; } imState; - - struct { - SP lock = nullptr; - bool sessionLocked = false; - bool sessionUnlocked = false; - bool denied = false; // set on the finished event - } sessionLockState; } m_waylandState; struct { @@ -131,14 +124,15 @@ namespace Hyprtoolkit { std::string nodeName = ""; } m_drmState; - std::vector> m_outputs; + std::vector> m_outputs; + + std::vector> m_windows; + std::vector> m_layers; + WP m_currentWindow; + uint32_t m_currentMods = 0; // HT modifiers, not xkb + uint32_t m_lastEnterSerial = 0; - std::vector> m_windows; - std::vector> m_layers; - std::vector> m_lockSurfaces; - WP m_currentWindow; - uint32_t m_currentMods = 0; // HT modifiers, not xkb - uint32_t m_lastEnterSerial = 0; + WP m_sessionLockState; }; inline UP g_waylandPlatform; diff --git a/src/lock/WaylandSessionLock.cpp b/src/lock/WaylandSessionLock.cpp new file mode 100644 index 0000000..7ceeb98 --- /dev/null +++ b/src/lock/WaylandSessionLock.cpp @@ -0,0 +1,50 @@ +#include "WaylandSessionLock.hpp" +#include "../core/InternalBackend.hpp" +#include "../core/platforms/WaylandPlatform.hpp" +#include "../window/WaylandLockSurface.hpp" + +using namespace Hyprtoolkit; + +CWaylandSessionLockState::CWaylandSessionLockState(SP lock) : m_lock(lock) { + m_lock->setLocked([this](CCExtSessionLockV1* r) { m_sessionLocked = true; }); + m_lock->setFinished([this](CCExtSessionLockV1* r) { + g_logger->log(HT_LOG_ERROR, "We got denied by the compositor to be the exclusive lock screen client. Is there another lock screen active?"); + m_denied = true; + m_events.finished.emit(); + }); +} + +void CWaylandSessionLockState::unlock() { + if (m_sessionUnlocked) { + g_logger->log(HT_LOG_WARNING, "Double unlock in WaylandSessionLockState!"); + return; + } + + if (!m_lock) { + g_logger->log(HT_LOG_WARNING, "Unlock without an active sessionLock object in WaylandSessionLockState!"); + return; + } + + m_lock->sendUnlockAndDestroy(); + m_lock.reset(); + m_sessionUnlocked = true; + + // roundtrip in order to make sure we have unlocked before sending closeRequest + wl_display_roundtrip(g_waylandPlatform->m_waylandState.display); + + for (const auto& sls : m_lockSurfaces) { + if (sls.expired()) + continue; + sls->m_events.closeRequest.emit(); + } + + m_lockSurfaces.clear(); +} + +void CWaylandSessionLockState::onOutputRemoved(uint32_t outputHandle) { + auto lockSurfaceIt = std::ranges::find_if(m_lockSurfaces, [outputHandle](const auto& other) { return other->m_outputHandle == outputHandle; }); + if (lockSurfaceIt != m_lockSurfaces.end()) { + (*lockSurfaceIt)->m_events.closeRequest.emit(); + m_lockSurfaces.erase(lockSurfaceIt); + } +} diff --git a/src/lock/WaylandSessionLock.hpp b/src/lock/WaylandSessionLock.hpp new file mode 100644 index 0000000..575575a --- /dev/null +++ b/src/lock/WaylandSessionLock.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "wayland.hpp" + +#include "../helpers/Memory.hpp" +#include +#include + +namespace Hyprtoolkit { + class CWaylandLockSurface; + + class CWaylandSessionLockState : public ISessionLockState { + public: + CWaylandSessionLockState(SP lock); + ~CWaylandSessionLockState() = default; + + virtual void unlock(); + + void onOutputRemoved(uint32_t outputHandle); + + std::vector> m_lockSurfaces; + SP m_lock = nullptr; + bool m_sessionLocked = false; + bool m_sessionUnlocked = false; + bool m_denied = false; // set on the finished event + }; +} diff --git a/src/window/WaylandLockSurface.cpp b/src/window/WaylandLockSurface.cpp index 8b45656..b3d4787 100644 --- a/src/window/WaylandLockSurface.cpp +++ b/src/window/WaylandLockSurface.cpp @@ -29,16 +29,16 @@ void CWaylandLockSurface::open() { return; if (m_outputHandle == 0) { - g_logger->log(HT_LOG_ERROR, "session lock missing prefferedOutputId."); + g_logger->log(HT_LOG_ERROR, "session lock missing prefferedOutputId"); return; } - if (!g_waylandPlatform) { - g_logger->log(HT_LOG_ERROR, "wayland platform not initialized."); + if (!g_waylandPlatform || !g_waylandPlatform->m_sessionLockState) { + g_logger->log(HT_LOG_ERROR, "wayland platform not initialized"); return; } - auto lockObject = g_waylandPlatform->aquireSessionLock(); + auto lockObject = g_waylandPlatform->m_sessionLockState->m_lock; if (!lockObject) return; diff --git a/src/window/WaylandLockSurface.hpp b/src/window/WaylandLockSurface.hpp index 6315df8..8d9bc72 100644 --- a/src/window/WaylandLockSurface.hpp +++ b/src/window/WaylandLockSurface.hpp @@ -1,6 +1,7 @@ #pragma once #include "IWaylandWindow.hpp" +#include "../lock/WaylandSessionLock.hpp" #include namespace Hyprtoolkit { @@ -21,6 +22,6 @@ namespace Hyprtoolkit { bool configured = false; } m_lockSurfaceState; - friend class CWaylandPlatform; + friend class CWaylandSessionLockState; }; }; diff --git a/tests/SimpleSessionLock.cpp b/tests/SimpleSessionLock.cpp index cd12ca6..f053c8d 100644 --- a/tests/SimpleSessionLock.cpp +++ b/tests/SimpleSessionLock.cpp @@ -86,7 +86,7 @@ static void layout(const SP& window) { window->open(); } -static void onWindowClose(WP window) { +static void closeWindow(WP window) { std::println("Remove surface {}!", (uintptr_t)windows.back().get()); auto windowsIt = std::ranges::find_if(windows, [&window](const auto& w) { return w.get() == window.get(); }); if (windowsIt == windows.end()) @@ -104,7 +104,7 @@ static void createLockSurface(SP output) { windows.emplace_back(CWindowBuilder::begin()->type(HT_WINDOW_LOCK_SURFACE)->prefferedOutput(output)->commence()); std::println("New surface {}!", (uintptr_t)windows.back().get()); WP weakWindow = windows.back(); - weakWindow->m_events.closeRequest.listenStatic([weakWindow]() { onWindowClose(weakWindow); }); + weakWindow->m_events.closeRequest.listenStatic([weakWindow]() { closeWindow(weakWindow); }); layout(weakWindow.lock()); } @@ -114,20 +114,32 @@ int main(int argc, char** argv, char** envp) { if (argc == 2) unlockSecs = atoi(argv[1]); - backend = IBackend::create(); - if (!backend) { - std::println("Backend create failed!"); - return -1; - } + backend = IBackend::create(); + if (!backend) { + std::println("Backend create failed!"); + return 1; + } + + auto sessionLock = backend->aquireSessionLock(); + if (!sessionLock.has_value()) { + std::println("Cloudn't lock"); + return 1; + } + + sessionLock.value()->m_events.finished.listenStatic([] { + std::println("Compositor kicked us"); + for (const auto& w : windows) { + closeWindow(w); + } + }); backend->m_events.outputAdded.listenStatic(createLockSurface); - backend->m_events.lockDenied.listenStatic([] { std::println("Lock denied!"); }); for (const auto& o: backend->getOutputs()) { createLockSurface(o); } - backend->addTimer(std::chrono::seconds(unlockSecs), [](auto, auto) { backend->unlockSession(); }, nullptr); + backend->addTimer(std::chrono::seconds(unlockSecs), [LOCK = sessionLock.value()](auto, auto) { LOCK->unlock(); }, nullptr); backend->enterLoop(); From d48d8e3391313d30140f8018647cbd4875159360 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Tue, 28 Oct 2025 21:47:09 +0100 Subject: [PATCH 13/16] include fixups --- flake.lock | 18 +++++++++--------- src/core/Backend.cpp | 2 +- src/core/Backend.hpp | 14 ++++++++------ src/core/platforms/WaylandPlatform.cpp | 2 -- src/core/platforms/WaylandPlatform.hpp | 2 +- .../WaylandSessionLock.cpp | 0 .../WaylandSessionLock.hpp | 2 +- src/window/WaylandLockSurface.hpp | 1 - 8 files changed, 20 insertions(+), 21 deletions(-) rename src/{lock => sessionLock}/WaylandSessionLock.cpp (100%) rename src/{lock => sessionLock}/WaylandSessionLock.hpp (95%) diff --git a/flake.lock b/flake.lock index 24d9fa9..29aa36b 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1760101617, - "narHash": "sha256-8jf/3ZCi+B7zYpIyV04+3wm72BD7Z801IlOzsOACR7I=", + "lastModified": 1761420899, + "narHash": "sha256-kxGCip6GNbcbNWKu4J2iKbNYfFTS8Zbjg9CWp0zmFoM=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "1826a9923881320306231b1c2090379ebf9fa4f8", + "rev": "62479232aae42c1ef09c2c027c8cfd91df060897", "type": "github" }, "original": { @@ -42,11 +42,11 @@ ] }, "locked": { - "lastModified": 1759490292, - "narHash": "sha256-T6iWzDOXp8Wv0KQOCTHpBcmAOdHJ6zc/l9xaztW6Ivc=", + "lastModified": 1760445448, + "narHash": "sha256-fXGjL6dw31FPFRrmIemzGiNSlfvEJTJNsmadZi+qNhI=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "9431db625cd9bb66ac55525479dce694101d6d7a", + "rev": "50fb9f069219f338a11cf0bcccb9e58357d67757", "type": "github" }, "original": { @@ -129,11 +129,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1760038930, - "narHash": "sha256-Oncbh0UmHjSlxO7ErQDM3KM0A5/Znfofj2BSzlHLeVw=", + "lastModified": 1761373498, + "narHash": "sha256-Q/uhWNvd7V7k1H1ZPMy/vkx3F8C13ZcdrKjO7Jv7v0c=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0b4defa2584313f3b781240b29d61f6f9f7e0df3", + "rev": "6a08e6bb4e46ff7fcbb53d409b253f6bad8a28ce", "type": "github" }, "original": { diff --git a/src/core/Backend.cpp b/src/core/Backend.cpp index 27047e3..b09f5f8 100644 --- a/src/core/Backend.cpp +++ b/src/core/Backend.cpp @@ -16,7 +16,7 @@ #include "../element/Element.hpp" #include "../palette/ConfigManager.hpp" #include "../system/Icons.hpp" -#include "hyprtoolkit/core/SystemLock.hpp" +#include "../sessionLock/WaylandSessionLock.hpp" #include #include diff --git a/src/core/Backend.hpp b/src/core/Backend.hpp index bb7674e..806f049 100644 --- a/src/core/Backend.hpp +++ b/src/core/Backend.hpp @@ -23,14 +23,16 @@ namespace Hyprtoolkit { virtual void addFd(int fd, std::function&& callback); virtual void removeFd(int fd); virtual SP systemIcons(); - virtual ASP addTimer(const std::chrono::system_clock::duration& timeout, std::function self, void* data)> cb_, void* data, bool force = false); - virtual void addIdle(const std::function& fn); - virtual void enterLoop(); - virtual SP getPalette(); + virtual ASP addTimer(const std::chrono::system_clock::duration& timeout, std::function self, void* data)> cb_, void* data, bool force = false); + virtual void addIdle(const std::function& fn); + virtual void enterLoop(); + virtual std::vector> getOutputs(); + virtual SP getPalette(); + virtual std::expected, eSessionLockError> aquireSessionLock(); - // ======================= Internal fns ======================= // + // ======================= Internal fns ======================= // - void terminate(); + void terminate(); void reloadTheme(); void rebuildPollfds(); diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index eb79e36..d0232c2 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -15,8 +15,6 @@ #include "../../output/WaylandOutput.hpp" #include "../../sessionLock/WaylandSessionLock.hpp" #include "../../Macros.hpp" -#include "ext-session-lock-v1.hpp" -#include "hyprtoolkit/core/SystemLock.hpp" #include #include diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index 24a7f12..c40fa70 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -3,9 +3,9 @@ #include #include #include +#include #include "../../helpers/Memory.hpp" -#include "lock/WaylandSessionLock.hpp" #include #include diff --git a/src/lock/WaylandSessionLock.cpp b/src/sessionLock/WaylandSessionLock.cpp similarity index 100% rename from src/lock/WaylandSessionLock.cpp rename to src/sessionLock/WaylandSessionLock.cpp diff --git a/src/lock/WaylandSessionLock.hpp b/src/sessionLock/WaylandSessionLock.hpp similarity index 95% rename from src/lock/WaylandSessionLock.hpp rename to src/sessionLock/WaylandSessionLock.hpp index 575575a..e589cbe 100644 --- a/src/lock/WaylandSessionLock.hpp +++ b/src/sessionLock/WaylandSessionLock.hpp @@ -3,7 +3,7 @@ #include "wayland.hpp" #include "../helpers/Memory.hpp" -#include +#include #include namespace Hyprtoolkit { diff --git a/src/window/WaylandLockSurface.hpp b/src/window/WaylandLockSurface.hpp index 8d9bc72..1e957c0 100644 --- a/src/window/WaylandLockSurface.hpp +++ b/src/window/WaylandLockSurface.hpp @@ -1,7 +1,6 @@ #pragma once #include "IWaylandWindow.hpp" -#include "../lock/WaylandSessionLock.hpp" #include namespace Hyprtoolkit { From 6384a105d93c6ebc63f3239ba59f35945b2e615c Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Tue, 28 Oct 2025 22:07:26 +0100 Subject: [PATCH 14/16] click to unlock in simple session lock --- src/core/Backend.hpp | 4 ++-- src/core/platforms/WaylandPlatform.hpp | 28 +++++++++++++------------- tests/SimpleSessionLock.cpp | 23 +++++++++++++-------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/core/Backend.hpp b/src/core/Backend.hpp index 806f049..48f41ef 100644 --- a/src/core/Backend.hpp +++ b/src/core/Backend.hpp @@ -30,9 +30,9 @@ namespace Hyprtoolkit { virtual SP getPalette(); virtual std::expected, eSessionLockError> aquireSessionLock(); - // ======================= Internal fns ======================= // + // ======================= Internal fns ======================= // - void terminate(); + void terminate(); void reloadTheme(); void rebuildPollfds(); diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index c40fa70..e9b80b4 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -43,26 +43,26 @@ namespace Hyprtoolkit { CWaylandPlatform() = default; ~CWaylandPlatform(); - bool attempt(); + bool attempt(); - void initSeat(); - void initShell(); - bool initDmabuf(); - void initIM(); - void setCursor(ePointerShape shape); + void initSeat(); + void initShell(); + bool initDmabuf(); + void initIM(); + void setCursor(ePointerShape shape); - bool dispatchEvents(); + bool dispatchEvents(); - SP windowForSurf(wl_proxy* proxy); - std::optional> outputForHandle(uint32_t handle); + SP windowForSurf(wl_proxy* proxy); + std::optional> outputForHandle(uint32_t handle); - void onKey(uint32_t keycode, bool state); - void startRepeatTimer(); - void stopRepeatTimer(); + void onKey(uint32_t keycode, bool state); + void startRepeatTimer(); + void stopRepeatTimer(); - void onRepeatTimerFire(); + void onRepeatTimerFire(); - SP aquireSessionLock(); + SP aquireSessionLock(); // dmabuf formats std::vector m_dmabufFormats; diff --git a/tests/SimpleSessionLock.cpp b/tests/SimpleSessionLock.cpp index f053c8d..741037b 100644 --- a/tests/SimpleSessionLock.cpp +++ b/tests/SimpleSessionLock.cpp @@ -1,3 +1,4 @@ +#include "hyprtoolkit/core/SessionLock.hpp" #include #include #include @@ -22,8 +23,8 @@ using namespace Hyprtoolkit; #define UP CUniquePointer static SP backend; +static SP lockState; static std::vector> windows; -static size_t buttonClicks = 1; static void addTimer(SP rect) { backend->addTimer( @@ -65,8 +66,11 @@ static void layout(const SP& window) { auto text = CTextBuilder::begin()->text("never give up")->color([] { return CHyprColor{0.4F, 0.4F, 0.4F}; })->commence(); auto button = CButtonBuilder::begin() - ->label("Click me kind person") - ->onMainClick([](SP el) { el->rebuild()->label(std::format("Clicked {} times", buttonClicks++))->commence(); }) + ->label("Click to unlock") + ->onMainClick([](SP el) { + el->rebuild()->label("Unlocking...")->commence(); + lockState->unlock(); + }) ->onRightClick([](SP el) { el->rebuild()->label("Reset")->commence(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence(); @@ -110,7 +114,7 @@ static void createLockSurface(SP output) { } int main(int argc, char** argv, char** envp) { - int unlockSecs = 1; + int unlockSecs = 10; if (argc == 2) unlockSecs = atoi(argv[1]); @@ -120,13 +124,16 @@ int main(int argc, char** argv, char** envp) { return 1; } - auto sessionLock = backend->aquireSessionLock(); - if (!sessionLock.has_value()) { + auto sessionLockState = backend->aquireSessionLock(); + if (sessionLockState.has_value()) + lockState = sessionLockState.value(); + + if (!lockState) { std::println("Cloudn't lock"); return 1; } - sessionLock.value()->m_events.finished.listenStatic([] { + lockState->m_events.finished.listenStatic([] { std::println("Compositor kicked us"); for (const auto& w : windows) { closeWindow(w); @@ -139,7 +146,7 @@ int main(int argc, char** argv, char** envp) { createLockSurface(o); } - backend->addTimer(std::chrono::seconds(unlockSecs), [LOCK = sessionLock.value()](auto, auto) { LOCK->unlock(); }, nullptr); + backend->addTimer(std::chrono::seconds(unlockSecs), [](auto, auto) { lockState->unlock(); }, nullptr); backend->enterLoop(); From 29992e2fb33ee14d39b2b48752a57c4f02ce5ad3 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Tue, 28 Oct 2025 22:19:33 +0100 Subject: [PATCH 15/16] remove optional, construct WP nullptr from SP --- src/core/platforms/WaylandPlatform.cpp | 4 ++-- src/core/platforms/WaylandPlatform.hpp | 2 +- src/window/WaylandLockSurface.cpp | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index d0232c2..0ab55b0 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -216,13 +216,13 @@ SP CWaylandPlatform::windowForSurf(wl_proxy* proxy) { return nullptr; } -std::optional> CWaylandPlatform::outputForHandle(uint32_t handle) { +WP CWaylandPlatform::outputForHandle(uint32_t handle) { for (const auto& o : m_outputs) { if (o->m_id == handle) { return o; } } - return std::nullopt; + return SP{}; } void CWaylandPlatform::initIM() { diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index e9b80b4..cda8712 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -54,7 +54,7 @@ namespace Hyprtoolkit { bool dispatchEvents(); SP windowForSurf(wl_proxy* proxy); - std::optional> outputForHandle(uint32_t handle); + WP outputForHandle(uint32_t handle); void onKey(uint32_t keycode, bool state); void startRepeatTimer(); diff --git a/src/window/WaylandLockSurface.cpp b/src/window/WaylandLockSurface.cpp index b3d4787..40c9c9d 100644 --- a/src/window/WaylandLockSurface.cpp +++ b/src/window/WaylandLockSurface.cpp @@ -10,6 +10,7 @@ #include "../element/Element.hpp" #include "../output/WaylandOutput.hpp" #include "../renderer/Renderer.hpp" +#include "../sessionLock/WaylandSessionLock.hpp" #include "../Macros.hpp" @@ -43,7 +44,7 @@ void CWaylandLockSurface::open() { return; auto wlOutput = g_waylandPlatform->outputForHandle(m_outputHandle); - if (!wlOutput.has_value() || !wlOutput.value()) + if (!wlOutput) return; m_open = true; @@ -80,7 +81,7 @@ void CWaylandLockSurface::open() { m_waylandState.surface->sendAttach(nullptr, 0, 0); m_lockSurfaceState.lockSurface = - makeShared(lockObject->sendGetLockSurface(m_waylandState.surface->resource(), wlOutput.value()->m_wlOutput->resource())); + makeShared(lockObject->sendGetLockSurface(m_waylandState.surface->resource(), wlOutput->m_wlOutput->resource())); if (!m_lockSurfaceState.lockSurface->resource()) { g_logger->log(HT_LOG_ERROR, "lock surface opening failed: no lock surface. Errno: {}", errno); return; From 1715e157ae487d02333ae4d6d079a3fd32a0e692 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Tue, 28 Oct 2025 22:23:55 +0100 Subject: [PATCH 16/16] fixups --- include/hyprtoolkit/core/Output.hpp | 2 +- include/hyprtoolkit/window/Window.hpp | 2 +- src/core/platforms/WaylandPlatform.cpp | 3 +-- src/core/platforms/WaylandPlatform.hpp | 28 +++++++++++++------------- src/window/IWaylandWindow.hpp | 2 +- src/window/WaylandLockSurface.cpp | 3 +-- src/window/Window.hpp | 6 +++--- tests/SimpleSessionLock.cpp | 12 +++++------ 8 files changed, 28 insertions(+), 30 deletions(-) diff --git a/include/hyprtoolkit/core/Output.hpp b/include/hyprtoolkit/core/Output.hpp index 94579fa..1b55865 100644 --- a/include/hyprtoolkit/core/Output.hpp +++ b/include/hyprtoolkit/core/Output.hpp @@ -13,7 +13,7 @@ namespace Hyprtoolkit { virtual uint32_t fps() = 0; struct { - // output removed + /* output removed */ Hyprutils::Signal::CSignalT<> removed; } m_events; }; diff --git a/include/hyprtoolkit/window/Window.hpp b/include/hyprtoolkit/window/Window.hpp index 8902b1f..51b09fa 100644 --- a/include/hyprtoolkit/window/Window.hpp +++ b/include/hyprtoolkit/window/Window.hpp @@ -30,7 +30,7 @@ namespace Hyprtoolkit { Hyprutils::Memory::CSharedPointer preferredSize(const Hyprutils::Math::Vector2D&); Hyprutils::Memory::CSharedPointer minSize(const Hyprutils::Math::Vector2D&); Hyprutils::Memory::CSharedPointer maxSize(const Hyprutils::Math::Vector2D&); - // FIXME: implement for window types other than HT_WINDOW_LOCK_SURFACE + // TODO: implement for window types other than HT_WINDOW_LOCK_SURFACE Hyprutils::Memory::CSharedPointer prefferedOutput(const Hyprutils::Memory::CSharedPointer& output); // only for HT_WINDOW_LAYER diff --git a/src/core/platforms/WaylandPlatform.cpp b/src/core/platforms/WaylandPlatform.cpp index 0ab55b0..210819a 100644 --- a/src/core/platforms/WaylandPlatform.cpp +++ b/src/core/platforms/WaylandPlatform.cpp @@ -218,9 +218,8 @@ SP CWaylandPlatform::windowForSurf(wl_proxy* proxy) { WP CWaylandPlatform::outputForHandle(uint32_t handle) { for (const auto& o : m_outputs) { - if (o->m_id == handle) { + if (o->m_id == handle) return o; - } } return SP{}; } diff --git a/src/core/platforms/WaylandPlatform.hpp b/src/core/platforms/WaylandPlatform.hpp index cda8712..ba2179f 100644 --- a/src/core/platforms/WaylandPlatform.hpp +++ b/src/core/platforms/WaylandPlatform.hpp @@ -43,26 +43,26 @@ namespace Hyprtoolkit { CWaylandPlatform() = default; ~CWaylandPlatform(); - bool attempt(); + bool attempt(); - void initSeat(); - void initShell(); - bool initDmabuf(); - void initIM(); - void setCursor(ePointerShape shape); + void initSeat(); + void initShell(); + bool initDmabuf(); + void initIM(); + void setCursor(ePointerShape shape); - bool dispatchEvents(); + bool dispatchEvents(); - SP windowForSurf(wl_proxy* proxy); - WP outputForHandle(uint32_t handle); + SP windowForSurf(wl_proxy* proxy); + WP outputForHandle(uint32_t handle); - void onKey(uint32_t keycode, bool state); - void startRepeatTimer(); - void stopRepeatTimer(); + void onKey(uint32_t keycode, bool state); + void startRepeatTimer(); + void stopRepeatTimer(); - void onRepeatTimerFire(); + void onRepeatTimerFire(); - SP aquireSessionLock(); + SP aquireSessionLock(); // dmabuf formats std::vector m_dmabufFormats; diff --git a/src/window/IWaylandWindow.hpp b/src/window/IWaylandWindow.hpp index 479a5d7..b8e9623 100644 --- a/src/window/IWaylandWindow.hpp +++ b/src/window/IWaylandWindow.hpp @@ -100,4 +100,4 @@ namespace Hyprtoolkit { friend class CWaylandWindow; }; -} +} \ No newline at end of file diff --git a/src/window/WaylandLockSurface.cpp b/src/window/WaylandLockSurface.cpp index 40c9c9d..9180576 100644 --- a/src/window/WaylandLockSurface.cpp +++ b/src/window/WaylandLockSurface.cpp @@ -80,8 +80,7 @@ void CWaylandLockSurface::open() { } else m_waylandState.surface->sendAttach(nullptr, 0, 0); - m_lockSurfaceState.lockSurface = - makeShared(lockObject->sendGetLockSurface(m_waylandState.surface->resource(), wlOutput->m_wlOutput->resource())); + m_lockSurfaceState.lockSurface = makeShared(lockObject->sendGetLockSurface(m_waylandState.surface->resource(), wlOutput->m_wlOutput->resource())); if (!m_lockSurfaceState.lockSurface->resource()) { g_logger->log(HT_LOG_ERROR, "lock surface opening failed: no lock surface. Errno: {}", errno); return; diff --git a/src/window/Window.hpp b/src/window/Window.hpp index 35ff00b..a25c607 100644 --- a/src/window/Window.hpp +++ b/src/window/Window.hpp @@ -11,9 +11,9 @@ namespace Hyprtoolkit { std::optional preferredSize; std::optional minSize; std::optional maxSize; - std::string title = "Hyprtoolkit App"; - std::string class_ = "hyprtoolkit-app"; - uint32_t prefferedOutputId; + std::string title = "Hyprtoolkit App"; + std::string class_ = "hyprtoolkit-app"; + uint32_t prefferedOutputId = 0; // popups Hyprutils::Math::Vector2D pos; diff --git a/tests/SimpleSessionLock.cpp b/tests/SimpleSessionLock.cpp index 741037b..b7c4fad 100644 --- a/tests/SimpleSessionLock.cpp +++ b/tests/SimpleSessionLock.cpp @@ -114,9 +114,9 @@ static void createLockSurface(SP output) { } int main(int argc, char** argv, char** envp) { - int unlockSecs = 10; - if (argc == 2) - unlockSecs = atoi(argv[1]); + int unlockSecs = 10; + if (argc == 2) + unlockSecs = atoi(argv[1]); backend = IBackend::create(); if (!backend) { @@ -140,10 +140,10 @@ int main(int argc, char** argv, char** envp) { } }); - backend->m_events.outputAdded.listenStatic(createLockSurface); + backend->m_events.outputAdded.listenStatic(createLockSurface); - for (const auto& o: backend->getOutputs()) { - createLockSurface(o); + for (const auto& o : backend->getOutputs()) { + createLockSurface(o); } backend->addTimer(std::chrono::seconds(unlockSecs), [](auto, auto) { lockState->unlock(); }, nullptr);