From 8e15f91c2417c8f05d69a93f1294185ccc5f8f3e Mon Sep 17 00:00:00 2001 From: Agent00Ming <107314235+Agent00Ming@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:57:08 -0400 Subject: [PATCH 01/14] input: Emulate discrete scrolling from v120 events (#6881) * seat: avoid sending axis_stop() when source is wheel * fix rounding for absolute discrete values greater than 1 Co-authored-by: Agent_00Ming --- src/config/ConfigManager.cpp | 1 + src/managers/SeatManager.cpp | 4 +-- src/managers/input/InputManager.cpp | 42 ++++++++++++++++++++++++++--- src/managers/input/InputManager.hpp | 8 ++++++ 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 944aa0b2..71349068 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -472,6 +472,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("input:scroll_button_lock", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:scroll_factor", {1.f}); m_pConfig->addConfigValue("input:scroll_points", {STRVAL_EMPTY}); + m_pConfig->addConfigValue("input:emulate_discrete_scroll", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:touchpad:natural_scroll", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:touchpad:disable_while_typing", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:touchpad:clickfinger_behavior", Hyprlang::INT{0}); diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index fc14f0fc..6589c4bf 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -333,9 +333,7 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double if (source == 0) { p->sendAxisValue120(axis, value120); p->sendAxisDiscrete(axis, discrete); - } - - if (value == 0) + } else if (value == 0) p->sendAxisStop(timeMs, axis); } } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index b2bbd577..23e183d0 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -760,6 +760,7 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { static auto POFFWINDOWAXIS = CConfigValue("input:off_window_axis_events"); static auto PINPUTSCROLLFACTOR = CConfigValue("input:scroll_factor"); static auto PTOUCHPADSCROLLFACTOR = CConfigValue("input:touchpad:scroll_factor"); + static auto PEMULATEDISCRETE = CConfigValue("input:emulate_discrete_scroll"); auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR); @@ -798,9 +799,44 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { } } } - double deltaDiscrete = (e.deltaDiscrete != 0) ? (factor * e.deltaDiscrete / std::abs(e.deltaDiscrete)) : 0; - g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, deltaDiscrete > 0 ? std::ceil(deltaDiscrete) : std::floor(deltaDiscrete), - std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); + + double discrete = (e.deltaDiscrete != 0) ? (factor * e.deltaDiscrete / std::abs(e.deltaDiscrete)) : 0; + double delta = e.delta * factor; + + if (e.source == 0) { + // if an application supports v120, it should ignore discrete anyways + if ((*PEMULATEDISCRETE >= 1 && std::abs(e.deltaDiscrete) != 120) || *PEMULATEDISCRETE >= 2) { + + const int interval = factor != 0 ? std::round(120 * (1 / factor)) : 120; + + // reset the accumulator when timeout is reached or direction/axis has changed + if (std::signbit(e.deltaDiscrete) != m_ScrollWheelState.lastEventSign || e.axis != m_ScrollWheelState.lastEventAxis || + e.timeMs - m_ScrollWheelState.lastEventTime > 500 /* 500ms taken from libinput default timeout */) { + + m_ScrollWheelState.accumulatedScroll = 0; + // send 1 discrete on first event for responsiveness + discrete = std::copysign(1, e.deltaDiscrete); + } else + discrete = 0; + + for (int ac = m_ScrollWheelState.accumulatedScroll; ac >= interval; ac -= interval) { + discrete += std::copysign(1, e.deltaDiscrete); + m_ScrollWheelState.accumulatedScroll -= interval; + } + + m_ScrollWheelState.lastEventSign = std::signbit(e.deltaDiscrete); + m_ScrollWheelState.lastEventAxis = e.axis; + m_ScrollWheelState.lastEventTime = e.timeMs; + m_ScrollWheelState.accumulatedScroll += std::abs(e.deltaDiscrete); + + delta = 15.0 * discrete * factor; + } + } + + int32_t value120 = std::round(factor * e.deltaDiscrete); + int32_t deltaDiscrete = std::abs(discrete) != 0 && std::abs(discrete) < 1 ? std::copysign(1, discrete) : std::round(discrete); + + g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, delta, deltaDiscrete, value120, e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); } Vector2D CInputManager::getMouseCoordsInternal() { diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 8050defe..85ae6197 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -278,6 +278,14 @@ class CInputManager { void restoreCursorIconToApp(); // no-op if restored + // discrete scrolling emulation using v120 data + struct { + bool lastEventSign = 0; + bool lastEventAxis = 0; + uint32_t lastEventTime = 0; + uint32_t accumulatedScroll = 0; + } m_ScrollWheelState; + friend class CKeybindManager; friend class CWLSurface; }; From efccf25fcc72b416c63ff540703d9f061f39a7f2 Mon Sep 17 00:00:00 2001 From: Ferdinand Bachmann Date: Sat, 20 Jul 2024 00:37:20 +0200 Subject: [PATCH 02/14] compositor: implement wayland socket handover (#6930) * compositor: implement wayland socket handover This commit implements the compositor side of the Wayland socket handover protocol as described in the [KDE Wiki]. The CLI options are chosen so that they are compatible with Kwin. [KDE Wiki]: https://invent.kde.org/plasma/kwin/-/wikis/Restarting * main: verify that --wayland-fd is a valid file descriptor * main: fail if only one of --socket and --wayland-fd is passed --- docs/Hyprland.1 | 4 ++++ docs/Hyprland.1.rst | 6 ++++++ src/Compositor.cpp | 30 ++++++++++++++++++++---------- src/Compositor.hpp | 2 +- src/main.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 74 insertions(+), 12 deletions(-) diff --git a/docs/Hyprland.1 b/docs/Hyprland.1 index f43d2c5d..5ef24fd5 100644 --- a/docs/Hyprland.1 +++ b/docs/Hyprland.1 @@ -32,6 +32,10 @@ Show command usage. .TP \f[B]-c\f[R], \f[B]--config\f[R] Specify config file to use. +\f[B]--socket\f[R] +Sets the Wayland socket name (for Wayland socket handover) +\f[B]--wayland-fd\f[R] +Sets the Wayland socket file descriptor (for Wayland socket handover) .SH BUGS .TP Submit bug reports and request features online at: diff --git a/docs/Hyprland.1.rst b/docs/Hyprland.1.rst index 54126501..c73b4343 100644 --- a/docs/Hyprland.1.rst +++ b/docs/Hyprland.1.rst @@ -41,6 +41,12 @@ OPTIONS **-c**, **--config** Specify config file to use. +**--socket** + Sets the Wayland socket name (for Wayland socket handover) + +**--wayland-fd** + Sets the Wayland socket file descriptor (for Wayland socket handover) + BUGS ==== diff --git a/src/Compositor.cpp b/src/Compositor.cpp index d1c51075..7ffccf36 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -27,6 +27,7 @@ #include using namespace Hyprutils::String; +#include #include #include #include @@ -533,19 +534,28 @@ void CCompositor::prepareFallbackOutput() { wlr_headless_add_output(headless, 1920, 1080); } -void CCompositor::startCompositor() { +void CCompositor::startCompositor(std::string socketName, int socketFd) { initAllSignals(); - // get socket, avoid using 0 - for (int candidate = 1; candidate <= 32; candidate++) { - const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); - const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (!socketName.empty() && socketFd != -1) { + fcntl(socketFd, F_SETFD, FD_CLOEXEC); + const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd); if (RETVAL >= 0) { - m_szWLDisplaySocket = CANDIDATESTR; - Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); - break; - } else { - Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); + m_szWLDisplaySocket = socketName; + Debug::log(LOG, "wl_display_add_socket_fd for {} succeeded with {}", socketName, RETVAL); + } else + Debug::log(WARN, "wl_display_add_socket_fd for {} returned {}: skipping", socketName, RETVAL); + } else { + // get socket, avoid using 0 + for (int candidate = 1; candidate <= 32; candidate++) { + const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); + const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (RETVAL >= 0) { + m_szWLDisplaySocket = CANDIDATESTR; + Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); + break; + } else + Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); } } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 17db2c8b..4aec323f 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -78,7 +78,7 @@ class CCompositor { std::unordered_map m_mMonitorIDMap; void initServer(); - void startCompositor(); + void startCompositor(std::string socketName, int socketFd); void cleanup(); void createLockFile(); void removeLockFile(); diff --git a/src/main.cpp b/src/main.cpp index 7e6fee02..1ac3ab8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include "config/ConfigManager.hpp" #include "init/initHelpers.hpp" +#include #include #include #include @@ -16,6 +17,8 @@ void help() { std::cout << "\nArguments:\n"; std::cout << " --help -h - Show this message again\n"; std::cout << " --config FILE -c FILE - Specify config file to use\n"; + std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; + std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; } @@ -37,6 +40,8 @@ int main(int argc, char** argv) { // parse some args std::string configPath; + std::string socketName; + int socketFd = -1; bool ignoreSudo = false; std::vector args{argv + 1, argv + argc}; @@ -46,6 +51,36 @@ int main(int argc, char** argv) { std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n"; ignoreSudo = true; + } else if (it->compare("--socket") == 0) { + if (std::next(it) == args.end()) { + help(); + + return 1; + } + + socketName = *std::next(it); + it++; + } else if (it->compare("--wayland-fd") == 0) { + if (std::next(it) == args.end()) { + help(); + + return 1; + } + + try { + socketFd = std::stoi(std::next(it)->c_str()); + + // check if socketFd is a valid file descriptor + if (fcntl(socketFd, F_GETFD) == -1) + throw std::exception(); + } catch (...) { + std::cerr << "[ ERROR ] Invalid Wayland FD!\n"; + help(); + + return 1; + } + + it++; } else if (it->compare("-c") == 0 || it->compare("--config") == 0) { if (std::next(it) == args.end()) { help(); @@ -93,6 +128,13 @@ int main(int argc, char** argv) { std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n"; } + if (socketName.empty() ^ (socketFd == -1)) { + std::cerr << "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n"; + std::cerr << " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover.\n"; + + return 1; + } + std::cout << "Welcome to Hyprland!\n"; // let's init the compositor. @@ -113,7 +155,7 @@ int main(int argc, char** argv) { Debug::log(LOG, "Hyprland init finished."); // If all's good to go, start. - g_pCompositor->startCompositor(); + g_pCompositor->startCompositor(socketName, socketFd); g_pCompositor->m_bIsShuttingDown = true; From 9b0993cc49b7285a2724a87fdb72bfc90cc75cc5 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 19 Jul 2024 22:37:42 +0000 Subject: [PATCH 03/14] [gha] build man pages --- docs/Hyprland.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Hyprland.1 b/docs/Hyprland.1 index 5ef24fd5..92061da2 100644 --- a/docs/Hyprland.1 +++ b/docs/Hyprland.1 @@ -32,8 +32,10 @@ Show command usage. .TP \f[B]-c\f[R], \f[B]--config\f[R] Specify config file to use. +.TP \f[B]--socket\f[R] Sets the Wayland socket name (for Wayland socket handover) +.TP \f[B]--wayland-fd\f[R] Sets the Wayland socket file descriptor (for Wayland socket handover) .SH BUGS From f642fb97df5c69267a03452533de383ff8023570 Mon Sep 17 00:00:00 2001 From: phonetic112 <73647246+phonetic112@users.noreply.github.com> Date: Sat, 20 Jul 2024 04:11:32 -0400 Subject: [PATCH 04/14] core: Fix crash on opening chromium (#6932) --- src/protocols/PresentationTime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 0275b53f..3907bf1e 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -60,7 +60,7 @@ void CPresentationFeedback::sendQueued(SP data, timespe if (reportedFlags & WLR_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; - if (data->wasPresented) + if (data->wasPresented && when) resource->sendPresented((uint32_t)(when->tv_sec >> 32), (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32), (uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags); else From 016da234d0e852de3ef20eb2e89ac58d2a85f6e7 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:09:54 +0200 Subject: [PATCH 05/14] Core: Move to aquamarine (#6608) Moves Hyprland from wlroots to aquamarine for the backend. --------- Signed-off-by: Vaxry Co-authored-by: Mihai Fufezan Co-authored-by: Jan Beich Co-authored-by: vaxerski Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com> Co-authored-by: Tom Englund Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com> Co-authored-by: diniamo --- .github/actions/setup_base/action.yml | 6 + .gitmodules | 4 - CMakeLists.txt | 42 +- Makefile | 6 +- README.md | 9 +- flake.lock | 30 + flake.nix | 8 + hyprland.pc.in | 2 +- hyprpm/src/core/PluginManager.cpp | 7 +- meson.build | 11 +- nix/default.nix | 3 + nix/overlays.nix | 1 + nix/update-wlroots.sh | 17 - protocols/meson.build | 2 + src/Compositor.cpp | 399 +++++++++---- src/Compositor.hpp | 36 +- src/config/ConfigManager.cpp | 23 +- src/debug/CrashReporter.cpp | 1 + src/debug/HyprCtl.cpp | 183 +++--- src/debug/Log.cpp | 24 - src/debug/Log.hpp | 2 - src/desktop/Popup.cpp | 5 +- src/desktop/Popup.hpp | 4 +- src/desktop/Window.cpp | 3 +- src/devices/IKeyboard.cpp | 256 ++++++++- src/devices/IKeyboard.hpp | 73 ++- src/devices/IPointer.hpp | 10 +- src/devices/ITouch.hpp | 10 +- src/devices/Keyboard.cpp | 66 +-- src/devices/Keyboard.hpp | 22 +- src/devices/Mouse.cpp | 182 +++--- src/devices/Mouse.hpp | 41 +- src/devices/Tablet.cpp | 256 ++++----- src/devices/Tablet.hpp | 154 +++-- src/devices/TouchDevice.cpp | 78 ++- src/devices/TouchDevice.hpp | 26 +- src/devices/VirtualKeyboard.cpp | 63 +- src/devices/VirtualKeyboard.hpp | 21 +- src/devices/VirtualPointer.cpp | 172 +----- src/devices/VirtualPointer.hpp | 37 +- src/events/Devices.cpp | 50 -- src/events/Events.hpp | 31 - src/events/Misc.cpp | 54 -- src/events/Monitors.cpp | 135 +---- src/helpers/CursorShapes.hpp | 43 ++ src/helpers/Format.cpp | 16 + src/helpers/Format.hpp | 9 +- src/helpers/MiscFunctions.cpp | 3 + src/helpers/MiscFunctions.hpp | 1 - src/helpers/Monitor.cpp | 293 ++++++---- src/helpers/Monitor.hpp | 136 +++-- src/helpers/WLClasses.hpp | 14 +- src/helpers/X11Stubs.hpp | 7 - src/helpers/math/Math.cpp | 140 +---- src/helpers/math/Math.hpp | 13 +- src/helpers/sync/SyncTimeline.cpp | 190 +++++++ src/helpers/sync/SyncTimeline.hpp | 47 ++ src/includes.hpp | 76 --- src/macros.hpp | 5 + src/managers/AnimationManager.cpp | 2 +- src/managers/CursorManager.cpp | 327 +++++++---- src/managers/CursorManager.hpp | 70 ++- src/managers/KeybindManager.cpp | 61 +- src/managers/KeybindManager.hpp | 1 + src/managers/PointerManager.cpp | 283 +++------ src/managers/PointerManager.hpp | 50 +- src/managers/ProtocolManager.cpp | 20 + src/managers/SeatManager.cpp | 10 +- src/managers/eventLoop/EventLoopManager.cpp | 15 + src/managers/eventLoop/EventLoopManager.hpp | 16 +- src/managers/input/InputManager.cpp | 232 +++----- src/managers/input/InputManager.hpp | 23 +- src/managers/input/Tablets.cpp | 51 +- src/meson.build | 5 +- src/plugins/PluginAPI.cpp | 1 + src/protocols/CursorShape.cpp | 45 +- src/protocols/DRMLease.cpp | 302 ++++++++++ src/protocols/DRMLease.hpp | 137 +++++ src/protocols/DRMSyncobj.cpp | 183 ++++++ src/protocols/DRMSyncobj.hpp | 82 +++ src/protocols/GammaControl.cpp | 32 +- src/protocols/GammaControl.hpp | 2 +- src/protocols/InputMethodV2.cpp | 22 +- src/protocols/InputMethodV2.hpp | 7 +- src/protocols/LinuxDMABUF.cpp | 323 ++++++++--- src/protocols/LinuxDMABUF.hpp | 52 +- src/protocols/MesaDRM.cpp | 42 +- src/protocols/MesaDRM.hpp | 2 +- src/protocols/OutputManagement.cpp | 56 +- src/protocols/OutputManagement.hpp | 15 +- src/protocols/OutputPower.cpp | 2 +- src/protocols/PresentationTime.cpp | 18 +- src/protocols/Screencopy.cpp | 52 +- src/protocols/Screencopy.hpp | 9 +- src/protocols/Tablet.cpp | 61 +- src/protocols/Tablet.hpp | 5 +- src/protocols/ToplevelExport.cpp | 19 +- src/protocols/ToplevelExport.hpp | 2 +- src/protocols/Viewporter.cpp | 29 +- src/protocols/Viewporter.hpp | 5 +- src/protocols/VirtualKeyboard.cpp | 58 +- src/protocols/VirtualKeyboard.hpp | 13 +- src/protocols/VirtualPointer.cpp | 80 +-- src/protocols/VirtualPointer.hpp | 31 +- src/protocols/XDGOutput.cpp | 6 +- src/protocols/XDGShell.cpp | 1 + src/protocols/core/Compositor.cpp | 149 +++-- src/protocols/core/Compositor.hpp | 14 +- src/protocols/core/Output.cpp | 10 +- src/protocols/core/Output.hpp | 3 + src/protocols/core/Seat.cpp | 4 +- src/protocols/core/Shm.cpp | 27 +- src/protocols/core/Shm.hpp | 8 +- src/protocols/types/Buffer.cpp | 41 +- src/protocols/types/Buffer.hpp | 80 +-- src/protocols/types/DMABuffer.cpp | 12 +- src/protocols/types/DMABuffer.hpp | 12 +- src/protocols/types/WLBuffer.cpp | 15 + src/protocols/types/WLBuffer.hpp | 8 +- src/render/OpenGL.cpp | 487 ++++++++++++---- src/render/OpenGL.hpp | 52 +- src/render/Renderbuffer.cpp | 69 +-- src/render/Renderbuffer.hpp | 31 +- src/render/Renderer.cpp | 599 ++++++++++---------- src/render/Renderer.hpp | 76 +-- src/render/Texture.cpp | 62 +- src/render/Texture.hpp | 15 +- src/signal-safe.hpp | 1 + src/xwayland/Server.cpp | 11 +- src/xwayland/XWM.cpp | 10 +- subprojects/wlroots-hyprland | 1 - 131 files changed, 4755 insertions(+), 3460 deletions(-) delete mode 100755 nix/update-wlroots.sh delete mode 100644 src/events/Devices.cpp delete mode 100644 src/events/Misc.cpp create mode 100644 src/helpers/CursorShapes.hpp delete mode 100644 src/helpers/X11Stubs.hpp create mode 100644 src/helpers/sync/SyncTimeline.cpp create mode 100644 src/helpers/sync/SyncTimeline.hpp create mode 100644 src/protocols/DRMLease.cpp create mode 100644 src/protocols/DRMLease.hpp create mode 100644 src/protocols/DRMSyncobj.cpp create mode 100644 src/protocols/DRMSyncobj.hpp delete mode 160000 subprojects/wlroots-hyprland diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml index a7b9994c..26660ce6 100644 --- a/.github/actions/setup_base/action.yml +++ b/.github/actions/setup_base/action.yml @@ -34,6 +34,7 @@ runs: libglvnd \ libinput \ libliftoff \ + libxcursor \ libxcvt \ libxfont2 \ libxkbcommon \ @@ -73,6 +74,11 @@ runs: run: | git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build + - name: Get aquamarine-git + shell: bash + run: | + git clone https://github.com/hyprwm/aquamarine && cd aquamarine && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target aquamarine && cmake --install build + - name: Get Xorg pacman pkgs shell: bash if: inputs.INSTALL_XORG_PKGS == 'true' diff --git a/.gitmodules b/.gitmodules index 37b48a5a..638f8ba9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,3 @@ [submodule "subprojects/tracy"] path = subprojects/tracy url = https://github.com/wolfpld/tracy -[submodule "subprojects/wlroots-hyprland"] - path = subprojects/wlroots-hyprland - url = https://github.com/hyprwm/wlroots-hyprland - ignore = dirty diff --git a/CMakeLists.txt b/CMakeLists.txt index 07fa8cf6..e951b874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,6 @@ cmake_minimum_required(VERSION 3.27) include(CheckIncludeFile) -include(ExternalProject) include(GNUInstallDirs) # Get version @@ -31,9 +30,6 @@ execute_process( # udis add_subdirectory("subprojects/udis86") -# wlroots -message(STATUS "Setting up wlroots") - if(CMAKE_BUILD_TYPE) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) if(BUILDTYPE_LOWER STREQUAL "release") @@ -53,18 +49,6 @@ else() set(BUILDTYPE_LOWER "release") endif() -ExternalProject_Add( - wlroots-hyprland - PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland - SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland - CONFIGURE_COMMAND meson setup --reconfigure --clearcache build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$,disabled,enabled> -Dexamples=false -Drenderers=gles2 -Dbackends=drm,libinput $,-Db_sanitize=address,-Db_sanitize=none> - BUILD_COMMAND ninja -C build - BUILD_ALWAYS true - BUILD_IN_SOURCE true - BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a - INSTALL_COMMAND echo "wlroots-hyprland: install not needed" -) - find_package(PkgConfig REQUIRED) pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner) @@ -84,12 +68,9 @@ endif() include_directories( . "src/" - "subprojects/wlroots-hyprland/include/" - "subprojects/wlroots-hyprland/build/include/" "subprojects/udis86/" "protocols/") set(CMAKE_CXX_STANDARD 23) -add_compile_definitions(WLR_USE_UNSTABLE) add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) @@ -109,9 +90,10 @@ endif() find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(deps REQUIRED IMPORTED_TARGET + aquamarine xkbcommon uuid wayland-server wayland-client wayland-cursor wayland-protocols - cairo pango pangocairo pixman-1 + cairo pango pangocairo pixman-1 xcursor libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.2.0 ) @@ -127,7 +109,6 @@ if(USE_TRACY) endif() add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) -add_dependencies(Hyprland wlroots-hyprland) set(USE_GPROF ON) @@ -266,7 +247,6 @@ function(protocolWayland) endfunction() target_link_libraries(Hyprland - ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a OpenGL::EGL OpenGL::GL Threads::Threads @@ -314,6 +294,8 @@ protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false) protocolNew("stable/viewporter" "viewporter" false) protocolNew("stable/linux-dmabuf" "linux-dmabuf-v1" false) +protocolNew("staging/drm-lease" "drm-lease-v1" false) +protocolNew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolWayland() @@ -326,8 +308,8 @@ install(TARGETS Hyprland) install(CODE "execute_process( \ COMMAND ${CMAKE_COMMAND} -E create_symlink \ - ${CMAKE_INSTALL_BINDIR}/Hyprland \ - ${CMAKE_INSTALL_BINDIR}/hyprland + ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \ + ${CMAKE_INSTALL_FULL_BINDIR}/hyprland )" ) @@ -358,18 +340,6 @@ install(FILES ${MANPAGES} install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) -# wlroots headers -set(HEADERS_WLR "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/include/wlr") -install(DIRECTORY ${HEADERS_WLR} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland - FILES_MATCHING PATTERN "*.h") - -# config.h and version.h -set(HEADERS_WLR_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/build/include/wlr") -install(DIRECTORY ${HEADERS_WLR_ROOT}/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland/wlr - FILES_MATCHING PATTERN "*.h") - # protocol headers set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols") install(DIRECTORY ${HEADERS_PROTO} diff --git a/Makefile b/Makefile index 493a6784..adf6fbe8 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,6 @@ nopch: clear: rm -rf build rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp - rm -rf ./subprojects/wlroots-hyprland/build all: $(MAKE) clear @@ -50,14 +49,11 @@ installheaders: rm -fr ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland/protocols - mkdir -p ${PREFIX}/include/hyprland/wlr mkdir -p ${PREFIX}/share/pkgconfig cmake --build ./build --config Release --target generate-protocol-headers find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland - cd subprojects/wlroots-hyprland/include/wlr && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../.. - cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../.. cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi @@ -88,7 +84,7 @@ asan: @pidof Hyprland > /dev/null && exit 1 || echo "" rm -rf ./wayland - git reset --hard + #git reset --hard @echo -en "If you want to apply a patch, input its path (leave empty for none):\n" @read patchvar diff --git a/README.md b/README.md index ca44621d..fc2bd206 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@
-Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks. +Hyprland is a 100% independent, dynamic tiling Wayland compositor that doesn't sacrifice on its looks. It provides the latest Wayland features, is highly customizable, has all the eyecandy, the most powerful plugins, -easy IPC, much more QoL stuff than other wlr-based compositors and more... +easy IPC, much more QoL stuff than other compositors and more...

@@ -37,7 +37,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more... - All of the eyecandy: gradient borders, blur, animations, shadows and much more - A lot of customization -- Much more QoL stuff than other wlr-based compositors +- 100% independent, no wlroots, no libweston, no kwin, no mutter. - Custom bezier curves for the best animations - Powerful plugin support - Built-in plugin manager @@ -48,7 +48,6 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more... - Config reloaded instantly upon saving - Fully dynamic workspaces - Two built-in layouts and more available as plugins -- Uses forked wlroots with QoL patches - Global keybinds passed to your apps of choice - Tiling/pseudotiling/floating/fullscreen windows - Special workspaces (scratchpads) @@ -86,7 +85,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
-**[wlroots]** - *For their amazing library* +**[wlroots]** - *For powering Hyprland in the past* **[tinywl]** - *For showing how 2 do stuff* diff --git a/flake.lock b/flake.lock index b5f5738a..b2cc9703 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,34 @@ { "nodes": { + "aquamarine": { + "inputs": { + "hyprutils": [ + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprwayland-scanner" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1721487522, + "narHash": "sha256-aF3uwUwUK2CgbItoMe3IJF0yidIEWcDx47AiH5y8VKk=", + "owner": "hyprwm", + "repo": "aquamarine", + "rev": "acfea3bd1d9e756c7152e639240d52c6628844b0", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "aquamarine", + "type": "github" + } + }, "hyprcursor": { "inputs": { "hyprlang": [ @@ -141,6 +170,7 @@ }, "root": { "inputs": { + "aquamarine": "aquamarine", "hyprcursor": "hyprcursor", "hyprlang": "hyprlang", "hyprutils": "hyprutils", diff --git a/flake.nix b/flake.nix index 88cb593b..9c20b3f5 100644 --- a/flake.nix +++ b/flake.nix @@ -7,6 +7,14 @@ # systems.url = "github:nix-systems/default-linux"; + aquamarine = { + url = "github:hyprwm/aquamarine"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + inputs.hyprutils.follows = "hyprutils"; + inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; + }; + hyprcursor = { url = "github:hyprwm/hyprcursor"; inputs.nixpkgs.follows = "nixpkgs"; diff --git a/hyprland.pc.in b/hyprland.pc.in index 382fb1e6..81a0ef11 100644 --- a/hyprland.pc.in +++ b/hyprland.pc.in @@ -4,4 +4,4 @@ Name: Hyprland URL: https://github.com/hyprwm/Hyprland Description: Hyprland header files Version: @HYPRLAND_VERSION@ -Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland -I${prefix}/hyprland/wlr +Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 848b9cab..7d7cc079 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -356,7 +356,7 @@ eHeadersErrors CPluginManager::headersValid() { else headers = ""; - if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland")) + if (PATH.ends_with("protocols")) continue; verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h"; @@ -493,11 +493,6 @@ bool CPluginManager::updateHeaders(bool force) { return false; } - // le hack. Wlroots has to generate its build/include - ret = execAndGet("cd " + WORKINGDIR + "/subprojects/wlroots-hyprland && meson setup -Drenderers=gles2 -Dexamples=false build"); - if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " configured Hyprland"); progress.m_iSteps = 4; progress.m_szCurrentMessage = "Installing sources"; diff --git a/meson.build b/meson.build index 49c48c6c..b8101f6c 100644 --- a/meson.build +++ b/meson.build @@ -24,8 +24,6 @@ if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif -wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2']) -have_xwlr = wlroots.get_variable('features').get('xwayland') xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland')) @@ -38,12 +36,7 @@ cmake = import('cmake') udis = cmake.subproject('udis86') udis86 = udis.dependency('libudis86') -if get_option('xwayland').enabled() and not have_xwlr - error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support') -endif -have_xwayland = xcb_dep.found() and have_xwlr - -if not have_xwayland +if not xcb_dep.found() add_project_arguments('-DNO_XWAYLAND', language: 'cpp') endif @@ -86,5 +79,5 @@ import('pkgconfig').generate( url: 'https://github.com/hyprwm/Hyprland', description: 'Hyprland header files', install_dir: pkg_install_dir, - subdirs: ['', 'hyprland/protocols', 'hyprland', 'hyprland/wlr'], + subdirs: ['', 'hyprland/protocols', 'hyprland'], ) diff --git a/nix/default.nix b/nix/default.nix index a2302688..7775b729 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -6,6 +6,7 @@ makeWrapper, cmake, ninja, + aquamarine, binutils, cairo, expat, @@ -104,6 +105,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov buildInputs = lib.concatLists [ [ + aquamarine cairo expat fribidi @@ -136,6 +138,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) (lib.optionals enableXWayland [ xorg.libxcb + xorg.libXcursor xorg.libXdmcp xorg.xcbutil xorg.xcbutilerrors diff --git a/nix/overlays.nix b/nix/overlays.nix index a4e1df37..9d100d51 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -21,6 +21,7 @@ in { # Packages for variations of Hyprland, dependencies included. hyprland-packages = lib.composeManyExtensions [ # Dependencies + inputs.aquamarine.overlays.default inputs.hyprcursor.overlays.default inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default diff --git a/nix/update-wlroots.sh b/nix/update-wlroots.sh deleted file mode 100755 index 01f5cd83..00000000 --- a/nix/update-wlroots.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env -S nix shell nixpkgs#gawk nixpkgs#git nixpkgs#gnused nixpkgs#ripgrep -c bash - -# get wlroots revision from submodule -SUB_REV=$(git submodule status | rg wlroots | awk '{ print substr($1,2) }') -# and from lockfile -CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }') - -if [ "$SUB_REV" != "$CRT_REV" ]; then - echo "Updating wlroots..." - # update wlroots to submodule revision - sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix - nix flake lock - - echo "wlroots: $CRT_REV -> $SUB_REV" -else - echo "wlroots is up to date!" -fi diff --git a/protocols/meson.build b/protocols/meson.build index 7c508659..5cdeb160 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -66,6 +66,8 @@ new_protocols = [ [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], [wl_protocol_dir, 'stable/viewporter/viewporter.xml'], [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], + [wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'], + [wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7ffccf36..c7a0cfb1 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -6,7 +6,10 @@ #include "managers/PointerManager.hpp" #include "managers/SeatManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" +#include #include +#include +#include #include #include "debug/HyprCtl.hpp" #include "debug/CrashReporter.hpp" @@ -22,16 +25,20 @@ #include "protocols/core/Compositor.hpp" #include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" +#include "render/Renderer.hpp" #include "xwayland/XWayland.hpp" #include -using namespace Hyprutils::String; +#include #include #include #include #include +using namespace Hyprutils::String; +using namespace Aquamarine; + int handleCritSignal(int signo, void* data) { Debug::log(LOG, "Hyprland received signal {}", signo); @@ -72,6 +79,23 @@ void handleUserSignal(int sig) { } } +static LogLevel aqLevelToHl(Aquamarine::eBackendLogLevel level) { + switch (level) { + case Aquamarine::eBackendLogLevel::AQ_LOG_TRACE: return TRACE; + case Aquamarine::eBackendLogLevel::AQ_LOG_DEBUG: return LOG; + case Aquamarine::eBackendLogLevel::AQ_LOG_ERROR: return ERR; + case Aquamarine::eBackendLogLevel::AQ_LOG_WARNING: return WARN; + case Aquamarine::eBackendLogLevel::AQ_LOG_CRITICAL: return CRIT; + default: break; + } + + return NONE; +} + +void aqLog(Aquamarine::eBackendLogLevel level, std::string msg) { + Debug::log(aqLevelToHl(level), "[AQ] {}", msg); +} + void CCompositor::bumpNofile() { if (!getrlimit(RLIMIT_NOFILE, &m_sOriginalNofile)) Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", m_sOriginalNofile.rlim_cur, m_sOriginalNofile.rlim_max); @@ -180,6 +204,9 @@ void CCompositor::setRandomSplash() { m_szCurrentSplash = SPLASHES[distribution(engine)]; } +static std::vector> pendingOutputs; + +// void CCompositor::initServer() { m_sWLDisplay = wl_display_create(); @@ -200,102 +227,179 @@ void CCompositor::initServer() { if (envEnabled("HYPRLAND_TRACE")) Debug::trace = true; - wlr_log_init(WLR_INFO, NULL); + Aquamarine::SBackendOptions options; + options.logFunction = aqLog; - if (envEnabled("HYPRLAND_LOG_WLR")) - wlr_log_init(WLR_DEBUG, Debug::wlrLog); - else - wlr_log_init(WLR_ERROR, Debug::wlrLog); + std::vector implementations; + Aquamarine::SBackendImplementationOptions option; + option.backendType = Aquamarine::eBackendType::AQ_BACKEND_HEADLESS; + option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_MANDATORY; + implementations.emplace_back(option); + option.backendType = Aquamarine::eBackendType::AQ_BACKEND_DRM; + option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_IF_AVAILABLE; + implementations.emplace_back(option); + option.backendType = Aquamarine::eBackendType::AQ_BACKEND_WAYLAND; + option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_FALLBACK; + implementations.emplace_back(option); - m_sWLRBackend = wlr_backend_autocreate(m_sWLEventLoop, &m_sWLRSession); + m_pAqBackend = CBackend::create(implementations, options); - if (!m_sWLRBackend) { - Debug::log(CRIT, "m_sWLRBackend was NULL! This usually means wlroots could not find a GPU or enountered some issues."); - throwError("wlr_backend_autocreate() failed!"); + if (!m_pAqBackend) { + Debug::log(CRIT, + "m_pAqBackend was null! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a Wayland " + "session, NOT an X11 one."); + throwError("CBackend::create() failed!"); } - bool isHeadlessOnly = true; - wlr_multi_for_each_backend( - m_sWLRBackend, - [](wlr_backend* backend, void* isHeadlessOnly) { - if (!wlr_backend_is_headless(backend) && !wlr_backend_is_libinput(backend)) - *(bool*)isHeadlessOnly = false; - }, - &isHeadlessOnly); + // TODO: headless only - if (isHeadlessOnly) { - m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); // TODO: remove this, it's barely needed now. - } else { - m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend); - if (m_iDRMFD < 0) { - Debug::log(CRIT, "Couldn't query the DRM FD!"); - throwError("wlr_backend_get_drm_fd() failed!"); + initAllSignals(); + + if (!m_pAqBackend->start()) { + Debug::log(CRIT, + "m_pAqBackend couldn't start! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a " + "Wayland session, NOT an X11 one."); + throwError("CBackend::create() failed!"); + } + + m_bInitialized = true; + + m_iDRMFD = m_pAqBackend->drmFD(); + Debug::log(LOG, "Running on DRMFD: {}", m_iDRMFD); + + // get socket, avoid using 0 + for (int candidate = 1; candidate <= 32; candidate++) { + const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); + const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (RETVAL >= 0) { + m_szWLDisplaySocket = CANDIDATESTR; + Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); + break; + } else { + Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); } - - m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD); } - if (!m_sWLRRenderer) { - Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues."); - throwError("wlr_gles2_renderer_create_with_drm_fd() failed!"); + if (m_szWLDisplaySocket.empty()) { + Debug::log(WARN, "All candidates failed, trying wl_display_add_socket_auto"); + const auto SOCKETSTR = wl_display_add_socket_auto(m_sWLDisplay); + if (SOCKETSTR) + m_szWLDisplaySocket = SOCKETSTR; } - m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer); - - if (!m_sWLRAllocator) { - Debug::log(CRIT, "m_sWLRAllocator was NULL!"); - throwError("wlr_allocator_autocreate() failed!"); + if (m_szWLDisplaySocket.empty()) { + Debug::log(CRIT, "m_szWLDisplaySocket NULL!"); + throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)"); } - m_sWLREGL = wlr_gles2_renderer_get_egl(m_sWLRRenderer); - - if (!m_sWLREGL) { - Debug::log(CRIT, "m_sWLREGL was NULL!"); - throwError("wlr_gles2_renderer_get_egl() failed!"); - } + Debug::log(LOG, "Setting WAYLAND_DISPLAY to {}", m_szWLDisplaySocket); + setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); + setenv("XDG_SESSION_TYPE", "wayland", 1); initManagers(STAGE_BASICINIT); - m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend); - if (!m_sWRLDRMLeaseMgr) { - Debug::log(INFO, "Failed to create wlr_drm_lease_v1_manager"); - Debug::log(INFO, "VR will not be available"); - } - - m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop); - - if (!m_sWLRHeadlessBackend) { - Debug::log(CRIT, "Couldn't create the headless backend"); - throwError("wlr_headless_backend_create() failed!"); - } - - wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend); - initManagers(STAGE_LATE); + + for (auto& o : pendingOutputs) { + onNewMonitor(o); + } + pendingOutputs.clear(); } void CCompositor::initAllSignals() { - addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend"); - addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend"); - addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); + m_pAqBackend->events.newOutput.registerStaticListener( + [this](void* p, std::any data) { + auto output = std::any_cast>(data); + Debug::log(LOG, "New aquamarine output with name {}", output->name); + if (m_bInitialized) + onNewMonitor(output); + else + pendingOutputs.emplace_back(output); + }, + nullptr); - if (m_sWRLDRMLeaseMgr) - addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM"); + m_pAqBackend->events.newPointer.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine pointer with name {}", dev->getName()); + g_pInputManager->newMouse(dev); + g_pInputManager->updateCapabilities(); + }, + nullptr); - if (m_sWLRSession) - addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session"); + m_pAqBackend->events.newKeyboard.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine keyboard with name {}", dev->getName()); + g_pInputManager->newKeyboard(dev); + g_pInputManager->updateCapabilities(); + }, + nullptr); + + m_pAqBackend->events.newTouch.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine touch with name {}", dev->getName()); + g_pInputManager->newTouchDevice(dev); + g_pInputManager->updateCapabilities(); + }, + nullptr); + + m_pAqBackend->events.newSwitch.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine switch with name {}", dev->getName()); + g_pInputManager->newSwitch(dev); + }, + nullptr); + + m_pAqBackend->events.newTablet.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine tablet with name {}", dev->getName()); + g_pInputManager->newTablet(dev); + }, + nullptr); + + m_pAqBackend->events.newTabletPad.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine tablet pad with name {}", dev->getName()); + g_pInputManager->newTabletPad(dev); + }, + nullptr); + + if (m_pAqBackend->hasSession()) { + m_pAqBackend->session->events.changeActive.registerStaticListener( + [this](void*, std::any) { + if (m_pAqBackend->session->active) { + Debug::log(LOG, "Session got activated!"); + + m_bSessionActive = true; + + for (auto& m : m_vMonitors) { + scheduleFrameForMonitor(m.get()); + g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); + } + + g_pConfigManager->m_bWantsMonitorReload = true; + } else { + Debug::log(LOG, "Session got deactivated!"); + + m_bSessionActive = false; + + for (auto& m : m_vMonitors) { + m->noFrameSchedule = true; + m->framesToSkip = 1; + } + } + }, + nullptr); + } } void CCompositor::removeAllSignals() { - removeWLSignal(&Events::listen_newOutput); - removeWLSignal(&Events::listen_newInput); - removeWLSignal(&Events::listen_RendererDestroy); - - if (m_sWRLDRMLeaseMgr) - removeWLSignal(&Events::listen_leaseRequest); - - if (m_sWLRSession) - removeWLSignal(&Events::listen_sessionActive); + ; } void CCompositor::cleanEnvironment() { @@ -309,7 +413,7 @@ void CCompositor::cleanEnvironment() { unsetenv("XDG_BACKEND"); unsetenv("XDG_CURRENT_DESKTOP"); - if (m_sWLRSession) { + if (m_pAqBackend->hasSession()) { const auto CMD = #ifdef USES_SYSTEMD "systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " @@ -352,7 +456,7 @@ void CCompositor::cleanup() { for (auto& m : m_vMonitors) { g_pHyprOpenGL->destroyMonitorResources(m.get()); - wlr_output_state_set_enabled(m->state.wlr(), false); + m->output->state->setEnabled(false); m->state.commit(); } @@ -389,14 +493,8 @@ void CCompositor::cleanup() { g_pHyprCtl.reset(); g_pEventLoopManager.reset(); - if (m_sWLRRenderer) - wlr_renderer_destroy(m_sWLRRenderer); - - if (m_sWLRAllocator) - wlr_allocator_destroy(m_sWLRAllocator); - - if (m_sWLRBackend) - wlr_backend_destroy(m_sWLRBackend); + if (m_pAqBackend) + m_pAqBackend.reset(); if (m_critSigSource) wl_event_source_remove(m_critSigSource); @@ -442,6 +540,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the PointerManager!"); g_pPointerManager = std::make_unique(); + + Debug::log(LOG, "Creating the EventManager!"); + g_pEventManager = std::make_unique(); } break; case STAGE_BASICINIT: { Debug::log(LOG, "Creating the CHyprOpenGLImpl!"); @@ -472,9 +573,6 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the SessionLockManager!"); g_pSessionLockManager = std::make_unique(); - Debug::log(LOG, "Creating the EventManager!"); - g_pEventManager = std::make_unique(); - Debug::log(LOG, "Creating the HyprDebugOverlay!"); g_pDebugOverlay = std::make_unique(); @@ -517,26 +615,23 @@ void CCompositor::removeLockFile() { void CCompositor::prepareFallbackOutput() { // create a backup monitor - wlr_backend* headless = nullptr; - wlr_multi_for_each_backend( - m_sWLRBackend, - [](wlr_backend* b, void* data) { - if (wlr_backend_is_headless(b)) - *((wlr_backend**)data) = b; - }, - &headless); + SP headless; + for (auto& impl : m_pAqBackend->getImplementations()) { + if (impl->type() == Aquamarine::AQ_BACKEND_HEADLESS) { + headless = impl; + break; + } + } if (!headless) { - Debug::log(WARN, "Unsafe state will be ineffective, no fallback output"); + Debug::log(WARN, "No headless in prepareFallbackOutput?!"); return; } - wlr_headless_add_output(headless, 1920, 1080); + headless->createOutput(); } void CCompositor::startCompositor(std::string socketName, int socketFd) { - initAllSignals(); - if (!socketName.empty() && socketFd != -1) { fcntl(socketFd, F_SETFD, FD_CLOEXEC); const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd); @@ -568,15 +663,15 @@ void CCompositor::startCompositor(std::string socketName, int socketFd) { if (m_szWLDisplaySocket.empty()) { Debug::log(CRIT, "m_szWLDisplaySocket NULL!"); - wlr_backend_destroy(m_sWLRBackend); throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)"); } setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); + setenv("XDG_SESSION_TYPE", "wayland", 1); signal(SIGPIPE, SIG_IGN); - if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */) { + if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) { const auto CMD = #ifdef USES_SYSTEMD "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " @@ -588,13 +683,6 @@ void CCompositor::startCompositor(std::string socketName, int socketFd) { Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket); - if (!wlr_backend_start(m_sWLRBackend)) { - Debug::log(CRIT, "Backend did not start!"); - wlr_backend_destroy(m_sWLRBackend); - wl_display_destroy(m_sWLDisplay); - throwError("The backend could not start!"); - } - prepareFallbackOutput(); g_pHyprRenderer->setCursorFromName("left_ptr"); @@ -882,7 +970,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; } -CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) { +CMonitor* CCompositor::getMonitorFromOutput(SP out) { for (auto& m : m_vMonitors) { if (m->output == out) { return m.get(); @@ -892,7 +980,7 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) { return nullptr; } -CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) { +CMonitor* CCompositor::getRealMonitorFromOutput(SP out) { for (auto& m : m_vRealMonitors) { if (m->output == out) { return m.get(); @@ -2240,8 +2328,12 @@ void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMod g_pInputManager->recheckIdleInhibitorStatus(); - // DMAbuf stuff for direct scanout - g_pHyprRenderer->setWindowScanoutMode(pWindow); + // further updates require a monitor + if (!PMONITOR) + return; + + // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. + g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr); g_pConfigManager->ensureVRR(PMONITOR); } @@ -2282,8 +2374,8 @@ void CCompositor::updateWorkspaceWindowData(const int& id) { } } -void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) { - if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive) +void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleFrameReason reason) { + if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive) return; if (!pMonitor->m_bEnabled) @@ -2292,7 +2384,7 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) { if (pMonitor->renderingActive) pMonitor->pendingFrame = true; - wlr_output_schedule_frame(pMonitor->output); + pMonitor->output->scheduleFrame(reason); } PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { @@ -2808,3 +2900,84 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { return {}; } + +static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { + static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); + static auto firstMonitorAdded = std::chrono::system_clock::now(); + static bool cursorDefaultDone = false; + static bool firstLaunch = true; + + const auto POS = PNEWMONITOR->middle(); + + // by default, cursor should be set to first monitor detected + // this is needed as a default if the monitor given in config above doesn't exist + if (firstLaunch) { + firstLaunch = false; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + } + + if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY) + return; + + // after 10s, don't set cursor to default monitor + auto timePassedSec = std::chrono::duration_cast(std::chrono::system_clock::now() - firstMonitorAdded); + if (timePassedSec.count() > 10) { + cursorDefaultDone = true; + return; + } + + if (*PCURSORMONITOR == monitorName) { + cursorDefaultDone = true; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + } +} + +void CCompositor::onNewMonitor(SP output) { + // add it to real + auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); + if (std::string("HEADLESS-1") == output->name) { + g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); + output->name = "FALLBACK"; // we are allowed to do this :) + } + + Debug::log(LOG, "New output with name {}", output->name); + + PNEWMONITOR->szName = output->name; + PNEWMONITOR->output = output; + PNEWMONITOR->self = PNEWMONITOR; + const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false; + PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(output->name); + PNEWMONITOR->isUnsafeFallback = FALLBACK; + + EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR); + + if (!FALLBACK) + PNEWMONITOR->onConnect(false); + + if (!PNEWMONITOR->m_bEnabled || FALLBACK) + return; + + // ready to process if we have a real monitor + + if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled) + g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get(); + + g_pCompositor->m_bReadyToProcess = true; + + g_pConfigManager->m_bWantsMonitorReload = true; + g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); + + checkDefaultCursorWarp(PNEWMONITOR, output->name); + + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_iMonitorID == PNEWMONITOR->ID) { + w->m_iLastSurfaceMonitorID = -1; + w->updateSurfaceScaleTransformDetails(); + } + } + + g_pHyprRenderer->damageMonitor(PNEWMONITOR.get()); + Events::listener_monitorFrame(PNEWMONITOR.get(), nullptr); +} diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 4aec323f..58c5b33d 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -30,6 +30,9 @@ #include "plugins/PluginSystem.hpp" #include "helpers/Watchdog.hpp" +#include +#include + class CWLSurfaceResource; enum eManagersInitStage { @@ -43,22 +46,11 @@ class CCompositor { CCompositor(); ~CCompositor(); - // ------------------ WLR BASICS ------------------ // - wl_display* m_sWLDisplay; - wl_event_loop* m_sWLEventLoop; - wlr_backend* m_sWLRBackend; - wlr_session* m_sWLRSession; - wlr_renderer* m_sWLRRenderer; - wlr_allocator* m_sWLRAllocator; - wlr_compositor* m_sWLRCompositor; - wlr_subcompositor* m_sWLRSubCompositor; - wlr_drm* m_sWRLDRM; - wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_egl* m_sWLREGL; - int m_iDRMFD; - wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; - wlr_backend* m_sWLRHeadlessBackend; - // ------------------------------------------------- // + wl_display* m_sWLDisplay; + wl_event_loop* m_sWLEventLoop; + int m_iDRMFD = -1; + bool m_bInitialized = false; + SP m_pAqBackend; std::string m_szHyprTempDataRoot = ""; @@ -94,10 +86,9 @@ class CCompositor { bool m_bReadyToProcess = false; bool m_bSessionActive = true; bool m_bDPMSStateON = true; - bool m_bUnsafeState = false; // unsafe state is when there is no monitors. - bool m_bNextIsUnsafe = false; // because wlroots + bool m_bUnsafeState = false; // unsafe state is when there is no monitors. + bool m_bNextIsUnsafe = false; CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state - bool m_bExitTriggered = false; // For exit dispatcher bool m_bIsShuttingDown = false; // ------------------------------------------------- // @@ -116,8 +107,8 @@ class CCompositor { SP vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); SP vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP); - CMonitor* getMonitorFromOutput(wlr_output*); - CMonitor* getRealMonitorFromOutput(wlr_output*); + CMonitor* getMonitorFromOutput(SP); + CMonitor* getRealMonitorFromOutput(SP); PHLWINDOW getWindowFromSurface(SP); PHLWINDOW getWindowFromHandle(uint32_t); bool isWorkspaceVisible(PHLWORKSPACE); @@ -157,7 +148,7 @@ class CCompositor { void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); PHLWINDOW getX11Parent(PHLWINDOW); - void scheduleFrameForMonitor(CMonitor*); + void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN); void addToFadingOutSafe(PHLLS); void removeFromFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLWINDOW); @@ -182,6 +173,7 @@ class CCompositor { void setPreferredTransformForSurface(SP pSurface, wl_output_transform transform); void updateSuspendedStates(); PHLWINDOW windowForCPointer(CWindow*); + void onNewMonitor(SP output); std::string explicitConfigPath; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 71349068..a5f18693 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using namespace Hyprutils::String; extern "C" char** environ; @@ -539,6 +540,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); + m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); @@ -557,6 +559,8 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"}); + m_pConfig->addConfigValue("experimental:explicit_sync", Hyprlang::INT{0}); + // devices m_pConfig->addSpecialCategory("device", {"name"}); m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F}); @@ -1285,7 +1289,7 @@ void CConfigManager::dispatchExecOnce() { return; // update dbus env - if (g_pCompositor->m_sWLRSession) + if (g_pCompositor->m_pAqBackend->hasSession()) handleRawExec("", #ifdef USES_SYSTEMD "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " @@ -1410,7 +1414,8 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { if (USEVRR == 0) { if (m->vrrActive) { - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); + + m->output->state->setAdaptiveSync(false); if (!m->state.commit()) Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); @@ -1419,11 +1424,11 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { return; } else if (USEVRR == 1) { if (!m->vrrActive) { - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1); + m->output->state->setAdaptiveSync(true); if (!m->state.test()) { Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); + m->output->state->setAdaptiveSync(false); } if (!m->state.commit()) @@ -1442,19 +1447,19 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; - if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) { - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1); + if (WORKSPACEFULL) { + m->output->state->setAdaptiveSync(true); if (!m->state.test()) { Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); + m->output->state->setAdaptiveSync(false); } if (!m->state.commit()) Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); - } else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) { - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); + } else if (!WORKSPACEFULL) { + m->output->state->setAdaptiveSync(false); if (!m->state.commit()) Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp index ce1a92ba..c25212fe 100644 --- a/src/debug/CrashReporter.cpp +++ b/src/debug/CrashReporter.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../plugins/PluginSystem.hpp" #include "../signal-safe.hpp" diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 08d2bb57..b81cfeff 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -20,6 +22,7 @@ #include using namespace Hyprutils::String; +#include #include "../config/ConfigDataValues.hpp" #include "../config/ConfigValue.hpp" @@ -53,20 +56,15 @@ static std::string formatToString(uint32_t drmFormat) { static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) { std::string result; - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; - - wl_list_for_each(mode, &pMonitor->output->modes, link) { - - if (format == FORMAT_NORMAL) - result += std::format("{}x{}@{:.2f}Hz ", mode->width, mode->height, mode->refresh / 1000.0); - else - result += std::format("\"{}x{}@{:.2f}Hz\",", mode->width, mode->height, mode->refresh / 1000.0); - } - - result.pop_back(); + for (auto& m : pMonitor->output->modes) { + if (format == FORMAT_NORMAL) + result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0); + else + result += std::format("\"{}x{}@{:.2f}Hz\",", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0); } + trimTrailingComma(result); + return result; } @@ -75,8 +73,10 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer if (!m->output || m->ID == -1ull) return ""; - result += std::format( - R"#({{ + if (format == eHyprCtlOutputFormat::FORMAT_JSON) { + + result += std::format( + R"#({{ "id": {}, "name": "{}", "description": "{}", @@ -107,14 +107,27 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer "currentFormat": "{}", "availableModes": [{}] }},)#", - m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make ? m->output->make : ""), - escapeJSONStrings(m->output->model ? m->output->model : ""), escapeJSONStrings(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, - m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), - m->activeSpecialWorkspaceID(), escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, - (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, - (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), - (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), - (m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); + + m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make), escapeJSONStrings(m->output->model), + escapeJSONStrings(m->output->serial), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, + m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), + escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, + (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), + (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), + (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + + } else { + result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" + "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" + "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", + m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, + m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), + m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, + (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, + (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing, + !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + } + return result; } @@ -144,16 +157,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { if (!m->output || m->ID == -1ull) continue; - result += std::format( - "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" - "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" - "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", - m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, - (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(), - (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), - (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, - (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), - m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); + result += + std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" + "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" + "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", + m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, + m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), + m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, + (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, + (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), + m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); } } @@ -552,8 +565,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { "defaultSpeed": {:.5f} }},)#", (uintptr_t)m.get(), escapeJSONStrings(m->hlName), - wlr_input_device_is_libinput(&m->wlr()->base) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) : - 0.f); + m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f); } trimTrailingComma(result); @@ -611,9 +623,8 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { R"#( {{ "address": "0x{:x}", "type": "tabletTool", - "belongsTo": "0x{:x}" }},)#", - (uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); + (uintptr_t)d.get()); } trimTrailingComma(result); @@ -641,7 +652,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { "address": "0x{:x}", "name": "{}" }},)#", - (uintptr_t)&d, escapeJSONStrings(d.pWlrDevice ? d.pWlrDevice->name : "")); + (uintptr_t)&d, escapeJSONStrings(d.pDevice ? d.pDevice->getName() : "")); } trimTrailingComma(result); @@ -654,9 +665,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { for (auto& m : g_pInputManager->m_vPointers) { result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", (uintptr_t)m.get(), m->hlName, - (wlr_input_device_is_libinput(&m->wlr()->base) ? - libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) : - 0.f)); + (m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f)); } result += "\n\nKeyboards:\n"; @@ -675,11 +684,11 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { } for (auto& d : g_pInputManager->m_vTablets) { - result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->wlr()->width_mm, d->wlr()->height_mm); + result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->aq()->physicalSize.x, d->aq()->physicalSize.y); } for (auto& d : g_pInputManager->m_vTabletTools) { - result += std::format("\tTablet Tool at {:x} (belongs to {:x})\n", (uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); + result += std::format("\tTablet Tool at {:x}\n", (uintptr_t)d.get()); } result += "\n\nTouch:\n"; @@ -691,7 +700,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n\nSwitches:\n"; for (auto& d : g_pInputManager->m_lSwitches) { - result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pWlrDevice ? d.pWlrDevice->name : ""); + result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pDevice ? d.pDevice->getName() : ""); } } @@ -1125,24 +1134,22 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ if (PKEYBOARD == g_pInputManager->m_vKeyboards.end()) return "device not found"; - const auto PWLRKEYBOARD = (*PKEYBOARD)->wlr(); - const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap); + const auto KEEB = *PKEYBOARD; + + const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap); xkb_layout_index_t activeLayout = 0; while (activeLayout < LAYOUTS) { - if (xkb_state_layout_index_is_active(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) + if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) break; activeLayout++; } - if (CMD == "next") { - wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, - activeLayout > LAYOUTS ? 0 : activeLayout + 1); - } else if (CMD == "prev") { - wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, - activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1); - } else { - + if (CMD == "next") + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1); + else if (CMD == "prev") + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1); + else { int requestedLayout = 0; try { requestedLayout = std::stoi(CMD); @@ -1152,7 +1159,7 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ return "layout idx out of range of " + std::to_string(LAYOUTS); } - wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, requestedLayout); + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout); } return "ok"; @@ -1368,43 +1375,6 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) return result; } -static bool addOutput(wlr_backend* backend, const std::string& type, const std::string& name) { - wlr_output* output = nullptr; - - if (type.empty() || type == "auto") { - if (wlr_backend_is_wl(backend)) - output = wlr_wl_output_create(backend); - else if (wlr_backend_is_headless(backend)) - output = wlr_headless_add_output(backend, 1920, 1080); - } else { - if (wlr_backend_is_wl(backend) && type == "wayland") - output = wlr_wl_output_create(backend); - else if (wlr_backend_is_headless(backend) && type == "headless") - output = wlr_headless_add_output(backend, 1920, 1080); - } - - if (output && !name.empty()) - g_pCompositor->getMonitorFromOutput(output)->szName = name; - - return output != nullptr; -} - -struct outputData { - std::string type; - std::string name; - bool added; -}; - -void createOutputIter(wlr_backend* backend, void* data) { - const auto DATA = static_cast(data); - - if (DATA->added) - return; - - if (addOutput(backend, DATA->type, DATA->name)) - DATA->added = true; -} - std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { CVarList vars(request, 0, ' '); @@ -1413,15 +1383,36 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { const auto MODE = vars[1]; + bool added = false; + + if (!vars[3].empty()) { + for (auto& m : g_pCompositor->m_vRealMonitors) { + if (m->szName == vars[3]) + return "Name already taken"; + } + } + if (MODE == "create" || MODE == "add") { if (g_pCompositor->getMonitorFromName(vars[3])) return "A real monitor already uses that name."; - outputData result{vars[2], vars[3], false}; + for (auto& impl : g_pCompositor->m_pAqBackend->getImplementations() | std::views::reverse) { + auto type = impl->type(); - wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result); + if (type == Aquamarine::AQ_BACKEND_HEADLESS && (vars[2] == "headless" || vars[2] == "auto")) { + added = true; + impl->createOutput(vars[3]); + break; + } - if (!result.added) + if (type == Aquamarine::AQ_BACKEND_WAYLAND && (vars[2] == "wayland" || vars[2] == "auto")) { + added = true; + impl->createOutput(vars[3]); + break; + } + } + + if (!added) return "no backend replied to the request"; } else if (MODE == "destroy" || MODE == "remove") { @@ -1433,7 +1424,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { if (!PMONITOR->createdByUser) return "cannot remove a real display. Use the monitor keyword."; - wlr_output_destroy(PMONITOR->output); + PMONITOR->output->destroy(); } return "ok"; diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index 7547204a..c2939831 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -10,30 +10,6 @@ void Debug::init(const std::string& IS) { logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); } -void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) { - if (level > wlr_log_get_verbosity()) - return; - - char* outputStr = nullptr; - - vasprintf(&outputStr, fmt, args); - - std::string output = std::string(outputStr); - free(outputStr); - - rollingLog += output + "\n"; - - if (!disableLogs || !**disableLogs) { - std::ofstream ofs; - ofs.open(logFile, std::ios::out | std::ios::app); - ofs << "[wlr] " << output << "\n"; - ofs.close(); - } - - if (!disableStdout) - std::cout << output << "\n"; -} - void Debug::log(LogLevel level, std::string str) { if (level == TRACE && !trace) return; diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index e8cd80cf..33f3c9c1 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -67,6 +67,4 @@ namespace Debug { log(level, logMsg); } - - void wlrLog(wlr_log_importance level, const char* fmt, va_list args); }; diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index f0fd556c..131a26b5 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -55,7 +55,7 @@ void CPopup::initAllSignals() { } void CPopup::onNewPopup(SP popup) { - const auto POPUP = m_vChildren.emplace_back(std::make_unique(popup, this)).get(); + const auto POPUP = m_vChildren.emplace_back(makeShared(popup, this)).get(); Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); } @@ -250,7 +250,8 @@ void CPopup::recheckTree() { } void CPopup::recheckChildrenRecursive() { - for (auto& c : m_vChildren) { + auto cpy = m_vChildren; + for (auto& c : cpy) { c->onCommit(true); c->recheckChildrenRecursive(); } diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 47e180a8..d045cd41 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -60,8 +60,8 @@ class CPopup { bool m_bMapped = false; // - std::vector> m_vChildren; - std::unique_ptr m_pSubsurfaceHead; + std::vector> m_vChildren; + std::unique_ptr m_pSubsurfaceHead; struct { CHyprSignalListener newPopup; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 4ea34156..7497957a 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1155,7 +1155,8 @@ int CWindow::getRealBorderSize() { } bool CWindow::canBeTorn() { - return m_sWindowData.tearing.valueOr(m_bTearingHint); + static auto PTEARING = CConfigValue("general:allow_tearing"); + return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING; } bool CWindow::shouldSendFullscreenState() { diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index cb294d1a..284a8295 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -2,7 +2,21 @@ #include "../defines.hpp" #include "../helpers/varlist/VarList.hpp" #include "../managers/input/InputManager.hpp" +#include "../managers/SeatManager.hpp" +#include "../config/ConfigManager.hpp" +#include +#include +#include +#define LED_COUNT 3 + +constexpr static std::array MODNAMES = { + XKB_MOD_NAME_SHIFT, XKB_MOD_NAME_CAPS, XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT, XKB_MOD_NAME_NUM, "Mod3", XKB_MOD_NAME_LOGO, "Mod5", +}; + +constexpr static std::array LEDNAMES = {XKB_LED_NAME_NUM, XKB_LED_NAME_CAPS, XKB_LED_NAME_SCROLL}; + +// uint32_t IKeyboard::getCapabilities() { return HID_INPUT_CAPABILITY_KEYBOARD; } @@ -14,27 +28,149 @@ eHIDType IKeyboard::getType() { IKeyboard::~IKeyboard() { events.destroy.emit(); - if (!xkbTranslationState) - return; + clearManuallyAllocd(); +} - xkb_state_unref(xkbTranslationState); - xkbTranslationState = nullptr; +void IKeyboard::clearManuallyAllocd() { + if (xkbStaticState) + xkb_state_unref(xkbStaticState); + + if (xkbState) + xkb_state_unref(xkbState); + + if (xkbKeymap) + xkb_keymap_unref(xkbKeymap); + + if (xkbKeymapFD >= 0) + close(xkbKeymapFD); + + xkbKeymap = nullptr; + xkbState = nullptr; + xkbStaticState = nullptr; + xkbKeymapFD = -1; +} + +void IKeyboard::setKeymap(const SStringRuleNames& rules) { + currentRules = rules; + xkb_rule_names XKBRULES = { + .rules = rules.rules.c_str(), + .model = rules.model.c_str(), + .layout = rules.layout.c_str(), + .variant = rules.variant.c_str(), + .options = rules.options.c_str(), + }; + + const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + if (!CONTEXT) { + Debug::log(ERR, "setKeymap: CONTEXT null??"); + return; + } + + clearManuallyAllocd(); + + Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model, + rules.options); + + if (!xkbFilePath.empty()) { + auto path = absolutePath(xkbFilePath, g_pConfigManager->configCurrentPath); + + if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE) + Debug::log(ERR, "Cannot open input:kb_file= file for reading"); + else { + xkbKeymap = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + fclose(KEYMAPFILE); + } + } + + if (!xkbKeymap) + xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS); + + if (!xkbKeymap) { + g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant + + ", options: " + rules.options + ", layout: " + rules.layout + " )"); + + Debug::log(ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, + rules.options); + memset(&XKBRULES, 0, sizeof(XKBRULES)); + + currentRules.rules = ""; + currentRules.model = ""; + currentRules.variant = ""; + currentRules.options = ""; + currentRules.layout = "us"; + + xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS); + } + + // set internal translation state + // demo sunao ni ienai + xkbStaticState = xkb_state_new(xkbKeymap); + + updateXKBTranslationState(xkbKeymap); + + const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default"); + + if (NUMLOCKON == 1) { + // lock numlock + const auto IDX = xkb_map_mod_get_index(xkbKeymap, XKB_MOD_NAME_NUM); + + if (IDX != XKB_MOD_INVALID) + modifiersState.locked |= (uint32_t)1 << IDX; + + updateModifiers(modifiersState.depressed, modifiersState.latched, modifiersState.locked, modifiersState.group); + } + + for (size_t i = 0; i < LEDNAMES.size(); ++i) { + ledIndexes.at(i) = xkb_map_led_get_index(xkbKeymap, LEDNAMES.at(i)); + Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES.at(i), ledIndexes.at(i)); + } + + for (size_t i = 0; i < MODNAMES.size(); ++i) { + modIndexes.at(i) = xkb_map_mod_get_index(xkbKeymap, MODNAMES.at(i)); + Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i)); + } + + auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); + xkbKeymapString = cKeymapStr; + free(cKeymapStr); + + int rw, ro; + if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro)) + Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap"); + else { + auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0); + close(rw); + if (keymapFDDest == MAP_FAILED) { + Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap"); + close(ro); + } else { + memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length()); + munmap(keymapFDDest, xkbKeymapString.length() + 1); + xkbKeymapFD = ro; + } + } + + xkb_context_unref(CONTEXT); + + g_pSeatManager->updateActiveKeyboardData(); } void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { - if (xkbTranslationState) - xkb_state_unref(xkbTranslationState); + if (xkbState) + xkb_state_unref(xkbState); + + xkbState = nullptr; if (keymap) { Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); - xkbTranslationState = xkb_state_new(keymap); + xkbState = xkb_state_new(keymap); return; } - const auto WLRKB = wlr(); - const auto KEYMAP = WLRKB->keymap; - const auto STATE = WLRKB->xkb_state; + const auto KEYMAP = xkbKeymap; + const auto STATE = xkbState; const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); @@ -73,7 +209,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); } - xkbTranslationState = xkb_state_new(KEYMAP); + xkbState = xkb_state_new(KEYMAP); xkb_keymap_unref(KEYMAP); xkb_context_unref(PCONTEXT); @@ -94,16 +230,15 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - xkbTranslationState = xkb_state_new(NEWKEYMAP); + xkbState = xkb_state_new(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP); xkb_context_unref(PCONTEXT); } std::string IKeyboard::getActiveLayout() { - const auto WLRKB = wlr(); - const auto KEYMAP = WLRKB->keymap; - const auto STATE = WLRKB->xkb_state; + const auto KEYMAP = xkbKeymap; + const auto STATE = xkbState; const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); for (uint32_t i = 0; i < LAYOUTSNUM; ++i) { @@ -120,14 +255,12 @@ std::string IKeyboard::getActiveLayout() { } void IKeyboard::updateLEDs() { - auto keyboard = wlr(); - - if (!keyboard || keyboard->xkb_state == nullptr) + if (xkbState == nullptr) return; uint32_t leds = 0; - for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) { - if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i])) + for (uint32_t i = 0; i < LED_COUNT; ++i) { + if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i))) leds |= (1 << i); } @@ -135,13 +268,88 @@ void IKeyboard::updateLEDs() { } void IKeyboard::updateLEDs(uint32_t leds) { - auto keyboard = wlr(); - - if (!keyboard || keyboard->xkb_state == nullptr) + if (!xkbState) return; if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock())) return; - wlr_keyboard_led_update(keyboard, leds); + if (!aq()) + return; + + aq()->updateLEDs(leds); +} + +uint32_t IKeyboard::getModifiers() { + uint32_t modMask = modifiersState.depressed | modifiersState.latched; + uint32_t mods = 0; + for (size_t i = 0; i < modIndexes.size(); ++i) { + if (modIndexes.at(i) == XKB_MOD_INVALID) + continue; + + if (!(modMask & (1 << modIndexes.at(i)))) + continue; + + mods |= (1 << i); + } + + return mods; +} + +void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { + if (!xkbState) + return; + + xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group); + + if (!updateModifiersState()) + return; + + updateLEDs(); +} + +bool IKeyboard::updateModifiersState() { + if (!xkbState) + return false; + + auto depressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED); + auto latched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED); + auto locked = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED); + auto group = xkb_state_serialize_layout(xkbState, XKB_STATE_LAYOUT_EFFECTIVE); + + if (depressed == modifiersState.depressed && latched == modifiersState.latched && locked == modifiersState.locked && group == modifiersState.group) + return false; + + modifiersState.depressed = depressed; + modifiersState.latched = latched; + modifiersState.locked = locked; + modifiersState.group = group; + + return true; +} + +void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) { + + const auto contains = std::find(pressedXKB.begin(), pressedXKB.end(), xkbKey) != pressedXKB.end(); + + if (contains && pressed) + return; + if (!contains && !pressed) + return; + + if (contains) + std::erase(pressedXKB, xkbKey); + else + pressedXKB.emplace_back(xkbKey); + + xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); + + if (updateModifiersState()) { + keyboardEvents.modifiers.emit(SModifiersEvent{ + .depressed = modifiersState.depressed, + .latched = modifiersState.latched, + .locked = modifiersState.locked, + .group = modifiersState.group, + }); + } } diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index b1757a18..1ae6c7bc 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -7,15 +7,26 @@ #include -struct wlr_keyboard; +AQUAMARINE_FORWARD(IKeyboard); + +enum eKeyboardModifiers { + HL_MODIFIER_SHIFT = (1 << 0), + HL_MODIFIER_CAPS = (1 << 1), + HL_MODIFIER_CTRL = (1 << 2), + HL_MODIFIER_ALT = (1 << 3), + HL_MODIFIER_MOD2 = (1 << 4), + HL_MODIFIER_MOD3 = (1 << 5), + HL_MODIFIER_META = (1 << 6), + HL_MODIFIER_MOD5 = (1 << 7), +}; class IKeyboard : public IHID { public: virtual ~IKeyboard(); - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - virtual bool isVirtual() = 0; - virtual wlr_keyboard* wlr() = 0; + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + virtual bool isVirtual() = 0; + virtual SP aq() = 0; struct SKeyEvent { uint32_t timeMs = 0; @@ -24,6 +35,17 @@ class IKeyboard : public IHID { wl_keyboard_key_state state = WL_KEYBOARD_KEY_STATE_PRESSED; }; + struct SKeymapEvent { + xkb_keymap* keymap = nullptr; + }; + + struct SModifiersEvent { + uint32_t depressed = 0; + uint32_t latched = 0; + uint32_t locked = 0; + uint32_t group = 0; + }; + struct { CSignal key; CSignal modifiers; @@ -39,25 +61,46 @@ class IKeyboard : public IHID { std::string rules = ""; }; + void setKeymap(const SStringRuleNames& rules); void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); std::string getActiveLayout(); void updateLEDs(); void updateLEDs(uint32_t leds); + uint32_t getModifiers(); + void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); + bool updateModifiersState(); // rets whether changed + void updateXkbStateWithKey(uint32_t xkbKey, bool pressed); bool active = false; bool enabled = true; - xkb_layout_index_t activeLayout = 0; - xkb_state* xkbTranslationState = nullptr; + xkb_layout_index_t activeLayout = 0; + xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr; + xkb_keymap* xkbKeymap = nullptr; - std::string hlName = ""; - std::string xkbFilePath = ""; + struct { + uint32_t depressed = 0, latched = 0, locked = 0, group = 0; + } modifiersState; - SStringRuleNames currentRules; - int repeatRate = 0; - int repeatDelay = 0; - int numlockOn = -1; - bool resolveBindsBySym = false; + std::array ledIndexes = {XKB_MOD_INVALID}; + std::array modIndexes = {XKB_MOD_INVALID}; + uint32_t leds = 0; - WP self; + std::string hlName = ""; + std::string xkbFilePath = ""; + std::string xkbKeymapString = ""; + int xkbKeymapFD = -1; + + SStringRuleNames currentRules; + int repeatRate = 0; + int repeatDelay = 0; + int numlockOn = -1; + bool resolveBindsBySym = false; + + WP self; + + private: + void clearManuallyAllocd(); + + std::vector pressedXKB; }; diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index b2995b2f..5df47c04 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -5,17 +5,17 @@ #include "../macros.hpp" #include "../helpers/math/Math.hpp" -struct wlr_pointer; +AQUAMARINE_FORWARD(IPointer); /* Base class for a pointer. */ class IPointer : public IHID { public: - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - virtual bool isVirtual() = 0; - virtual wlr_pointer* wlr() = 0; + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + virtual bool isVirtual() = 0; + virtual SP aq() = 0; struct SMotionEvent { uint32_t timeMs = 0; diff --git a/src/devices/ITouch.hpp b/src/devices/ITouch.hpp index b9cbf2ae..cb8a6e90 100644 --- a/src/devices/ITouch.hpp +++ b/src/devices/ITouch.hpp @@ -5,14 +5,14 @@ #include "../macros.hpp" #include "../helpers/math/Math.hpp" -struct wlr_touch; +AQUAMARINE_FORWARD(ITouch); class ITouch : public IHID { public: - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - virtual bool isVirtual() = 0; - virtual wlr_touch* wlr() = 0; + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + virtual bool isVirtual() = 0; + virtual SP aq() = 0; struct SDownEvent { uint32_t timeMs = 0; diff --git a/src/devices/Keyboard.cpp b/src/devices/Keyboard.cpp index 17357edb..ae28c07d 100644 --- a/src/devices/Keyboard.cpp +++ b/src/devices/Keyboard.cpp @@ -1,7 +1,10 @@ #include "Keyboard.hpp" #include "../defines.hpp" +#include "../Compositor.hpp" -SP CKeyboard::create(wlr_keyboard* keeb) { +#include + +SP CKeyboard::create(SP keeb) { SP pKeeb = SP(new CKeyboard(keeb)); pKeeb->self = pKeeb; @@ -13,52 +16,41 @@ bool CKeyboard::isVirtual() { return false; } -wlr_keyboard* CKeyboard::wlr() { - return keyboard; +SP CKeyboard::aq() { + return keyboard.lock(); } -CKeyboard::CKeyboard(wlr_keyboard* keeb) : keyboard(keeb) { +CKeyboard::CKeyboard(SP keeb) : keyboard(keeb) { if (!keeb) return; - // clang-format off - hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) { - disconnectCallbacks(); - keyboard = nullptr; - events.destroy.emit(); - }, this, "CKeyboard"); + listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) { + keyboard.reset(); + events.destroy.emit(); + }); - hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) { - auto E = (wlr_keyboard_key_event*)data; + listeners.key = keeb->events.key.registerListener([this](std::any d) { + auto E = std::any_cast(d); + + updateXkbStateWithKey(E.key + 8, E.pressed); keyboardEvents.key.emit(SKeyEvent{ - .timeMs = E->time_msec, - .keycode = E->keycode, - .updateMods = E->update_state, - .state = E->state, + .timeMs = E.timeMs, + .keycode = E.key, + .state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED, }); - }, this, "CKeyboard"); + }); - hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) { - keyboardEvents.keymap.emit(); - }, this, "CKeyboard"); + listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) { + updateModifiersState(); - hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) { - keyboardEvents.modifiers.emit(); - }, this, "CKeyboard"); + keyboardEvents.modifiers.emit(SModifiersEvent{ + .depressed = modifiersState.depressed, + .latched = modifiersState.latched, + .locked = modifiersState.locked, + .group = modifiersState.group, + }); + }); - hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) { - keyboardEvents.repeatInfo.emit(); - }, this, "CKeyboard"); - // clang-format on - - deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN"; -} - -void CKeyboard::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_key.removeCallback(); - hyprListener_keymap.removeCallback(); - hyprListener_repeatInfo.removeCallback(); - hyprListener_modifiers.removeCallback(); + deviceName = keeb->getName(); } diff --git a/src/devices/Keyboard.hpp b/src/devices/Keyboard.hpp index cf01a9a7..f6de43cb 100644 --- a/src/devices/Keyboard.hpp +++ b/src/devices/Keyboard.hpp @@ -4,21 +4,19 @@ class CKeyboard : public IKeyboard { public: - static SP create(wlr_keyboard* keeb); + static SP create(SP keeb); - virtual bool isVirtual(); - virtual wlr_keyboard* wlr(); + virtual bool isVirtual(); + virtual SP aq(); private: - CKeyboard(wlr_keyboard* keeb); + CKeyboard(SP keeb); - wlr_keyboard* keyboard = nullptr; + WP keyboard; - void disconnectCallbacks(); - - DYNLISTENER(destroy); - DYNLISTENER(key); - DYNLISTENER(modifiers); - DYNLISTENER(keymap); - DYNLISTENER(repeatInfo); + struct { + CHyprSignalListener destroy; + CHyprSignalListener key; + CHyprSignalListener modifiers; + } listeners; }; \ No newline at end of file diff --git a/src/devices/Mouse.cpp b/src/devices/Mouse.cpp index b860298c..ae89ed92 100644 --- a/src/devices/Mouse.cpp +++ b/src/devices/Mouse.cpp @@ -1,7 +1,8 @@ #include "Mouse.hpp" #include "../defines.hpp" +#include -SP CMouse::create(wlr_pointer* mouse) { +SP CMouse::create(SP mouse) { SP pMouse = SP(new CMouse(mouse)); pMouse->self = pMouse; @@ -9,166 +10,143 @@ SP CMouse::create(wlr_pointer* mouse) { return pMouse; } -CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) { +CMouse::CMouse(SP mouse_) : mouse(mouse_) { if (!mouse) return; - // clang-format off - hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) { - disconnectCallbacks(); - mouse = nullptr; + listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) { + mouse.reset(); events.destroy.emit(); - }, this, "CMouse"); + }); - hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) { - auto E = (wlr_pointer_motion_event*)data; + listeners.motion = mouse->events.move.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.motion.emit(SMotionEvent{ - .timeMs = E->time_msec, - .delta = {E->delta_x, E->delta_y}, - .unaccel = {E->unaccel_dx, E->unaccel_dy}, + .timeMs = E.timeMs, + .delta = E.delta, + .unaccel = E.unaccel, }); - }, this, "CMouse"); + }); - hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) { - auto E = (wlr_pointer_motion_absolute_event*)data; + listeners.motionAbsolute = mouse->events.warp.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ - .timeMs = E->time_msec, - .absolute = {E->x, E->y}, + .timeMs = E.timeMs, + .absolute = E.absolute, .device = self.lock(), }); - }, this, "CMouse"); + }); - hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) { - auto E = (wlr_pointer_button_event*)data; + listeners.button = mouse->events.button.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.button.emit(SButtonEvent{ - .timeMs = E->time_msec, - .button = E->button, - .state = (wl_pointer_button_state)E->state, + .timeMs = E.timeMs, + .button = E.button, + .state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED, }); - }, this, "CMouse"); + }); - hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) { - auto E = (wlr_pointer_axis_event*)data; + listeners.axis = mouse->events.axis.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.axis.emit(SAxisEvent{ - .timeMs = E->time_msec, - .source = E->source, - .axis = E->orientation, - .relativeDirection = E->relative_direction, - .delta = E->delta, - .deltaDiscrete = E->delta_discrete, + .timeMs = E.timeMs, + .source = (wl_pointer_axis_source)E.source, + .axis = (wl_pointer_axis)E.axis, + .relativeDirection = (wl_pointer_axis_relative_direction)E.direction, + .delta = E.delta, + .deltaDiscrete = E.discrete, }); - }, this, "CMouse"); + }); - hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) { - pointerEvents.frame.emit(); - }, this, "CMouse"); + listeners.frame = mouse->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); }); - hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_begin_event*)data; + listeners.swipeBegin = mouse->events.swipeBegin.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.swipeBegin.emit(SSwipeBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, + .timeMs = E.timeMs, + .fingers = E.fingers, }); - }, this, "CMouse"); + }); - hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_end_event*)data; + listeners.swipeEnd = mouse->events.swipeEnd.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.swipeEnd.emit(SSwipeEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, + .timeMs = E.timeMs, + .cancelled = E.cancelled, }); - }, this, "CMouse"); + }); - hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_update_event*)data; + listeners.swipeUpdate = mouse->events.swipeUpdate.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - .delta = {E->dx, E->dy}, + .timeMs = E.timeMs, + .fingers = E.fingers, + .delta = E.delta, }); - }, this, "CMouse"); + }); - hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_begin_event*)data; + listeners.pinchBegin = mouse->events.pinchBegin.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.pinchBegin.emit(SPinchBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, + .timeMs = E.timeMs, + .fingers = E.fingers, }); - }, this, "CMouse"); + }); - hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_end_event*)data; + listeners.pinchEnd = mouse->events.pinchEnd.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.pinchEnd.emit(SPinchEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, + .timeMs = E.timeMs, + .cancelled = E.cancelled, }); - }, this, "CMouse"); + }); - hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_update_event*)data; + listeners.pinchUpdate = mouse->events.pinchUpdate.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - .delta = {E->dx, E->dy}, - .scale = E->scale, - .rotation = E->rotation, + .timeMs = E.timeMs, + .fingers = E.fingers, + .delta = E.delta, + .scale = E.scale, + .rotation = E.rotation, }); - }, this, "CMouse"); + }); - hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_hold_begin_event*)data; + listeners.holdBegin = mouse->events.holdBegin.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.holdBegin.emit(SHoldBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, + .timeMs = E.timeMs, + .fingers = E.fingers, }); - }, this, "CMouse"); + }); - hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_hold_end_event*)data; + listeners.holdEnd = mouse->events.holdEnd.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.holdEnd.emit(SHoldEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, + .timeMs = E.timeMs, + .cancelled = E.cancelled, }); - }, this, "CMouse"); + }); - // clang-format on - - deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN"; -} - -void CMouse::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_motion.removeCallback(); - hyprListener_motionAbsolute.removeCallback(); - hyprListener_button.removeCallback(); - hyprListener_axis.removeCallback(); - hyprListener_frame.removeCallback(); - hyprListener_swipeBegin.removeCallback(); - hyprListener_swipeEnd.removeCallback(); - hyprListener_swipeUpdate.removeCallback(); - hyprListener_pinchBegin.removeCallback(); - hyprListener_pinchEnd.removeCallback(); - hyprListener_pinchUpdate.removeCallback(); - hyprListener_holdBegin.removeCallback(); - hyprListener_holdEnd.removeCallback(); + deviceName = mouse->getName(); } bool CMouse::isVirtual() { return false; } -wlr_pointer* CMouse::wlr() { - return mouse; +SP CMouse::aq() { + return mouse.lock(); } diff --git a/src/devices/Mouse.hpp b/src/devices/Mouse.hpp index 40a65ca8..2b51fbe9 100644 --- a/src/devices/Mouse.hpp +++ b/src/devices/Mouse.hpp @@ -4,33 +4,34 @@ class CMouse : public IPointer { public: - static SP create(wlr_pointer* mouse); + static SP create(SP mouse); - virtual bool isVirtual(); - virtual wlr_pointer* wlr(); + virtual bool isVirtual(); + virtual SP aq(); private: - CMouse(wlr_pointer* mouse); + CMouse(SP mouse); - wlr_pointer* mouse = nullptr; + WP mouse; - void disconnectCallbacks(); + struct { + CHyprSignalListener destroy; - DYNLISTENER(destroy); - DYNLISTENER(motion); - DYNLISTENER(motionAbsolute); - DYNLISTENER(button); - DYNLISTENER(axis); - DYNLISTENER(frame); + CHyprSignalListener motion; + CHyprSignalListener motionAbsolute; + CHyprSignalListener button; + CHyprSignalListener axis; + CHyprSignalListener frame; - DYNLISTENER(swipeBegin); - DYNLISTENER(swipeEnd); - DYNLISTENER(swipeUpdate); + CHyprSignalListener swipeBegin; + CHyprSignalListener swipeEnd; + CHyprSignalListener swipeUpdate; - DYNLISTENER(pinchBegin); - DYNLISTENER(pinchEnd); - DYNLISTENER(pinchUpdate); + CHyprSignalListener pinchBegin; + CHyprSignalListener pinchEnd; + CHyprSignalListener pinchUpdate; - DYNLISTENER(holdBegin); - DYNLISTENER(holdEnd); + CHyprSignalListener holdBegin; + CHyprSignalListener holdEnd; + } listeners; }; diff --git a/src/devices/Tablet.cpp b/src/devices/Tablet.cpp index b5ab16c1..71ca8991 100644 --- a/src/devices/Tablet.cpp +++ b/src/devices/Tablet.cpp @@ -2,8 +2,9 @@ #include "../defines.hpp" #include "../protocols/Tablet.hpp" #include "../protocols/core/Compositor.hpp" +#include -SP CTablet::create(wlr_tablet* tablet) { +SP CTablet::create(SP tablet) { SP pTab = SP(new CTablet(tablet)); pTab->self = pTab; @@ -13,7 +14,7 @@ SP CTablet::create(wlr_tablet* tablet) { return pTab; } -SP CTabletTool::create(wlr_tablet_tool* tablet) { +SP CTabletTool::create(SP tablet) { SP pTab = SP(new CTabletTool(tablet)); pTab->self = pTab; @@ -23,7 +24,7 @@ SP CTabletTool::create(wlr_tablet_tool* tablet) { return pTab; } -SP CTabletPad::create(wlr_tablet_pad* tablet) { +SP CTabletPad::create(SP tablet) { SP pTab = SP(new CTabletPad(tablet)); pTab->self = pTab; @@ -33,33 +34,25 @@ SP CTabletPad::create(wlr_tablet_pad* tablet) { return pTab; } -SP CTabletTool::fromWlr(wlr_tablet_tool* tool) { - return ((CTabletTool*)tool->data)->self.lock(); -} - -SP CTablet::fromWlr(wlr_tablet* tablet) { - return ((CTablet*)tablet->data)->self.lock(); -} - -static uint32_t wlrUpdateToHl(uint32_t wlr) { +static uint32_t aqUpdateToHl(uint32_t aq) { uint32_t result = 0; - if (wlr & WLR_TABLET_TOOL_AXIS_X) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_X) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X; - if (wlr & WLR_TABLET_TOOL_AXIS_Y) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_Y) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y; - if (wlr & WLR_TABLET_TOOL_AXIS_DISTANCE) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_DISTANCE) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE; - if (wlr & WLR_TABLET_TOOL_AXIS_PRESSURE) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_PRESSURE) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE; - if (wlr & WLR_TABLET_TOOL_AXIS_TILT_X) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_TILT_X) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X; - if (wlr & WLR_TABLET_TOOL_AXIS_TILT_Y) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_TILT_Y) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y; - if (wlr & WLR_TABLET_TOOL_AXIS_ROTATION) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_ROTATION) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION; - if (wlr & WLR_TABLET_TOOL_AXIS_SLIDER) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_SLIDER) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER; - if (wlr & WLR_TABLET_TOOL_AXIS_WHEEL) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_WHEEL) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL; return result; } @@ -68,97 +61,81 @@ uint32_t CTablet::getCapabilities() { return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; } -wlr_tablet* CTablet::wlr() { - return tablet; +SP CTablet::aq() { + return tablet.lock(); } -CTablet::CTablet(wlr_tablet* tablet_) : tablet(tablet_) { +CTablet::CTablet(SP tablet_) : tablet(tablet_) { if (!tablet) return; - tablet->data = this; - - // clang-format off - hyprListener_destroy.initCallback(&tablet->base.events.destroy, [this] (void* owner, void* data) { - tablet = nullptr; - disconnectCallbacks(); + listeners.destroy = tablet->events.destroy.registerListener([this](std::any d) { + tablet.reset(); events.destroy.emit(); - }, this, "CTablet"); + }); - hyprListener_axis.initCallback(&tablet->events.axis, [this] (void* owner, void* data) { - auto E = (wlr_tablet_tool_axis_event*)data; + listeners.axis = tablet->events.axis.registerListener([this](std::any d) { + auto E = std::any_cast(d); tabletEvents.axis.emit(SAxisEvent{ - .tool = E->tool, + .tool = E.tool, .tablet = self.lock(), - .timeMs = E->time_msec, - .updatedAxes = wlrUpdateToHl(E->updated_axes), - .axis = {E->x, E->y}, - .axisDelta = {E->dx, E->dy}, - .tilt = {E->tilt_x, E->tilt_y}, - .pressure = E->pressure, - .distance = E->distance, - .rotation = E->rotation, - .slider = E->slider, - .wheelDelta = E->wheel_delta, + .timeMs = E.timeMs, + .updatedAxes = aqUpdateToHl(E.updatedAxes), + .axis = E.absolute, + .axisDelta = E.delta, + .tilt = E.tilt, + .pressure = E.pressure, + .distance = E.distance, + .rotation = E.rotation, + .slider = E.slider, + .wheelDelta = E.wheelDelta, }); - }, this, "CTablet"); + }); - hyprListener_proximity.initCallback(&tablet->events.proximity, [this] (void* owner, void* data) { - auto E = (wlr_tablet_tool_proximity_event*)data; + listeners.proximity = tablet->events.proximity.registerListener([this](std::any d) { + auto E = std::any_cast(d); tabletEvents.proximity.emit(SProximityEvent{ - .tool = E->tool, + .tool = E.tool, .tablet = self.lock(), - .timeMs = E->time_msec, - .proximity = {E->x, E->y}, - .in = E->state == WLR_TABLET_TOOL_PROXIMITY_IN, + .timeMs = E.timeMs, + .proximity = E.absolute, + .in = E.in, }); - }, this, "CTablet"); + }); - hyprListener_tip.initCallback(&tablet->events.tip, [this] (void* owner, void* data) { - auto E = (wlr_tablet_tool_tip_event*)data; + listeners.tip = tablet->events.tip.registerListener([this](std::any d) { + auto E = std::any_cast(d); tabletEvents.tip.emit(STipEvent{ - .tool = E->tool, + .tool = E.tool, .tablet = self.lock(), - .timeMs = E->time_msec, - .tip = {E->x, E->y}, - .in = E->state == WLR_TABLET_TOOL_TIP_DOWN, + .timeMs = E.timeMs, + .tip = E.absolute, + .in = E.down, }); - }, this, "CTablet"); + }); - hyprListener_button.initCallback(&tablet->events.button, [this] (void* owner, void* data) { - auto E = (wlr_tablet_tool_button_event*)data; + listeners.button = tablet->events.button.registerListener([this](std::any d) { + auto E = std::any_cast(d); tabletEvents.button.emit(SButtonEvent{ - .tool = E->tool, + .tool = E.tool, .tablet = self.lock(), - .timeMs = E->time_msec, - .button = E->button, - .down = E->state == WLR_BUTTON_PRESSED, + .timeMs = E.timeMs, + .button = E.button, + .down = E.down, }); - }, this, "CTablet"); - // clang-format on + }); - deviceName = tablet->base.name ? tablet->base.name : "UNKNOWN"; + deviceName = tablet->getName(); } CTablet::~CTablet() { - if (tablet) - tablet->data = nullptr; - PROTO::tablet->recheckRegisteredDevices(); } -void CTablet::disconnectCallbacks() { - hyprListener_axis.removeCallback(); - hyprListener_button.removeCallback(); - hyprListener_destroy.removeCallback(); - hyprListener_proximity.removeCallback(); - hyprListener_tip.removeCallback(); -} - eHIDType CTablet::getType() { return HID_TYPE_TABLET; } @@ -167,138 +144,111 @@ uint32_t CTabletPad::getCapabilities() { return HID_INPUT_CAPABILITY_TABLET; } -wlr_tablet_pad* CTabletPad::wlr() { - return pad; +SP CTabletPad::aq() { + return pad.lock(); } eHIDType CTabletPad::getType() { return HID_TYPE_TABLET_PAD; } -CTabletPad::CTabletPad(wlr_tablet_pad* pad_) : pad(pad_) { +CTabletPad::CTabletPad(SP pad_) : pad(pad_) { if (!pad) return; - // clang-format off - hyprListener_destroy.initCallback(&pad->base.events.destroy, [this] (void* owner, void* data) { - pad = nullptr; - disconnectCallbacks(); + listeners.destroy = pad->events.destroy.registerListener([this](std::any d) { + pad.reset(); events.destroy.emit(); - }, this, "CTabletPad"); + }); - hyprListener_button.initCallback(&pad->events.button, [this] (void* owner, void* data) { - auto E = (wlr_tablet_pad_button_event*)data; + listeners.button = pad->events.button.registerListener([this](std::any d) { + auto E = std::any_cast(d); padEvents.button.emit(SButtonEvent{ - .timeMs = E->time_msec, - .button = E->button, - .down = E->state == WLR_BUTTON_PRESSED, - .mode = E->mode, - .group = E->group, + .timeMs = E.timeMs, + .button = E.button, + .down = E.down, + .mode = E.mode, + .group = E.group, }); - }, this, "CTabletPad"); + }); - hyprListener_ring.initCallback(&pad->events.ring, [this] (void* owner, void* data) { - auto E = (wlr_tablet_pad_ring_event*)data; + listeners.ring = pad->events.ring.registerListener([this](std::any d) { + auto E = std::any_cast(d); padEvents.ring.emit(SRingEvent{ - .timeMs = E->time_msec, - .finger = E->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, - .ring = E->ring, - .position = E->position, - .mode = E->mode, + .timeMs = E.timeMs, + .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_RING_SOURCE_FINGER, + .ring = E.ring, + .position = E.pos, + .mode = E.mode, }); - }, this, "CTabletPad"); + }); - hyprListener_strip.initCallback(&pad->events.strip, [this] (void* owner, void* data) { - auto E = (wlr_tablet_pad_strip_event*)data; + listeners.strip = pad->events.strip.registerListener([this](std::any d) { + auto E = std::any_cast(d); padEvents.strip.emit(SStripEvent{ - .timeMs = E->time_msec, - .finger = E->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, - .strip = E->strip, - .position = E->position, - .mode = E->mode, + .timeMs = E.timeMs, + .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_STRIP_SOURCE_FINGER, + .strip = E.strip, + .position = E.pos, + .mode = E.mode, }); - }, this, "CTabletPad"); + }); - hyprListener_attach.initCallback(&pad->events.attach_tablet, [this] (void* owner, void* data) { - if (!data) - return; - - padEvents.attach.emit(CTabletTool::fromWlr((wlr_tablet_tool*)data)); - }, this, "CTabletPad"); - // clang-format on + listeners.attach = pad->events.attach.registerListener([this](std::any d) { + ; // TODO: this doesn't do anything in aq atm + }); - deviceName = pad->base.name ? pad->base.name : "UNKNOWN"; + deviceName = pad->getName(); } CTabletPad::~CTabletPad() { PROTO::tablet->recheckRegisteredDevices(); } -void CTabletPad::disconnectCallbacks() { - hyprListener_ring.removeCallback(); - hyprListener_button.removeCallback(); - hyprListener_destroy.removeCallback(); - hyprListener_strip.removeCallback(); - hyprListener_attach.removeCallback(); -} - uint32_t CTabletTool::getCapabilities() { return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; } -wlr_tablet_tool* CTabletTool::wlr() { - return tool; +SP CTabletTool::aq() { + return tool.lock(); } eHIDType CTabletTool::getType() { return HID_TYPE_TABLET_TOOL; } -CTabletTool::CTabletTool(wlr_tablet_tool* tool_) : tool(tool_) { +CTabletTool::CTabletTool(SP tool_) : tool(tool_) { if (!tool) return; - // clang-format off - hyprListener_destroy.initCallback(&tool->events.destroy, [this] (void* owner, void* data) { - tool = nullptr; - disconnectCallbacks(); + listeners.destroyTool = tool->events.destroy.registerListener([this](std::any d) { + tool.reset(); events.destroy.emit(); - }, this, "CTabletTool"); - // clang-format on + }); - if (tool->tilt) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_TILT) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT; - if (tool->pressure) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_PRESSURE) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE; - if (tool->distance) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_DISTANCE) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE; - if (tool->rotation) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_ROTATION) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION; - if (tool->slider) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_SLIDER) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER; - if (tool->wheel) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_WHEEL) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL; - tool->data = this; - - deviceName = std::to_string(tool->hardware_serial) + std::to_string(tool->hardware_wacom); + deviceName = std::format("{:x}-{:x}", tool->serial, tool->id); } CTabletTool::~CTabletTool() { - if (tool) - tool->data = nullptr; - PROTO::tablet->recheckRegisteredDevices(); } -void CTabletTool::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - listeners.destroySurface.reset(); -} - SP CTabletTool::getSurface() { return pSurface.lock(); } diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp index ada2cf89..0efbe796 100644 --- a/src/devices/Tablet.hpp +++ b/src/devices/Tablet.hpp @@ -6,9 +6,9 @@ #include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp" -struct wlr_tablet; -struct wlr_tablet_tool; -struct wlr_tablet_pad; +AQUAMARINE_FORWARD(ITablet); +AQUAMARINE_FORWARD(ITabletTool); +AQUAMARINE_FORWARD(ITabletPad); class CTabletTool; class CTabletPad; @@ -21,13 +21,12 @@ class CWLSurfaceResource; */ class CTablet : public IHID { public: - static SP create(wlr_tablet* tablet); - static SP fromWlr(wlr_tablet* tablet); + static SP create(SP tablet); ~CTablet(); - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - wlr_tablet* wlr(); + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + SP aq(); enum eTabletToolAxes { HID_TABLET_TOOL_AXIS_X = (1 << 0), @@ -42,46 +41,46 @@ class CTablet : public IHID { }; struct SAxisEvent { - wlr_tablet_tool* tool; - SP tablet; + SP tool; + SP tablet; - uint32_t timeMs = 0; - uint32_t updatedAxes = 0; // eTabletToolAxes - Vector2D axis; - Vector2D axisDelta; - Vector2D tilt; - double pressure = 0; - double distance = 0; - double rotation = 0; - double slider = 0; - double wheelDelta = 0; + uint32_t timeMs = 0; + uint32_t updatedAxes = 0; // eTabletToolAxes + Vector2D axis; + Vector2D axisDelta; + Vector2D tilt; + double pressure = 0; + double distance = 0; + double rotation = 0; + double slider = 0; + double wheelDelta = 0; }; struct SProximityEvent { - wlr_tablet_tool* tool; - SP tablet; + SP tool; + SP tablet; - uint32_t timeMs = 0; - Vector2D proximity; - bool in = false; + uint32_t timeMs = 0; + Vector2D proximity; + bool in = false; }; struct STipEvent { - wlr_tablet_tool* tool; - SP tablet; + SP tool; + SP tablet; - uint32_t timeMs = 0; - Vector2D tip; - bool in = false; + uint32_t timeMs = 0; + Vector2D tip; + bool in = false; }; struct SButtonEvent { - wlr_tablet_tool* tool; - SP tablet; + SP tool; + SP tablet; - uint32_t timeMs = 0; - uint32_t button; - bool down = false; + uint32_t timeMs = 0; + uint32_t button; + bool down = false; }; struct { @@ -100,27 +99,27 @@ class CTablet : public IHID { CBox boundBox; // output-local private: - CTablet(wlr_tablet* tablet); + CTablet(SP tablet); - void disconnectCallbacks(); + WP tablet; - wlr_tablet* tablet = nullptr; - - DYNLISTENER(destroy); - DYNLISTENER(axis); - DYNLISTENER(proximity); - DYNLISTENER(tip); - DYNLISTENER(button); + struct { + CHyprSignalListener destroy; + CHyprSignalListener axis; + CHyprSignalListener proximity; + CHyprSignalListener tip; + CHyprSignalListener button; + } listeners; }; class CTabletPad : public IHID { public: - static SP create(wlr_tablet_pad* pad); + static SP create(SP pad); ~CTabletPad(); - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - wlr_tablet_pad* wlr(); + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + SP aq(); struct SButtonEvent { uint32_t timeMs = 0; @@ -159,23 +158,22 @@ class CTabletPad : public IHID { std::string hlName; private: - CTabletPad(wlr_tablet_pad* pad); + CTabletPad(SP pad); - void disconnectCallbacks(); + WP pad; - wlr_tablet_pad* pad = nullptr; - - DYNLISTENER(destroy); - DYNLISTENER(ring); - DYNLISTENER(strip); - DYNLISTENER(button); - DYNLISTENER(attach); + struct { + CHyprSignalListener destroy; + CHyprSignalListener ring; + CHyprSignalListener strip; + CHyprSignalListener button; + CHyprSignalListener attach; + } listeners; }; class CTabletTool : public IHID { public: - static SP create(wlr_tablet_tool* tool); - static SP fromWlr(wlr_tablet_tool* tool); + static SP create(SP tool); ~CTabletTool(); enum eTabletToolType { @@ -198,35 +196,31 @@ class CTabletTool : public IHID { HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5), }; - virtual uint32_t getCapabilities(); - wlr_tablet_tool* wlr(); - virtual eHIDType getType(); - SP getSurface(); - void setSurface(SP); + virtual uint32_t getCapabilities(); + SP aq(); + virtual eHIDType getType(); + SP getSurface(); + void setSurface(SP); - WP self; - Vector2D tilt; - bool active = false; // true if in proximity - uint32_t toolCapabilities = 0; + WP self; + Vector2D tilt; + bool active = false; // true if in proximity + uint32_t toolCapabilities = 0; - bool isDown = false; - std::vector buttonsDown; - Vector2D absolutePos; // last known absolute position. + bool isDown = false; + std::vector buttonsDown; + Vector2D absolutePos; // last known absolute position. - std::string hlName; + std::string hlName; private: - CTabletTool(wlr_tablet_tool* tool); + CTabletTool(SP tool); - void disconnectCallbacks(); - - WP pSurface; - - wlr_tablet_tool* tool = nullptr; - - DYNLISTENER(destroy); + WP pSurface; + WP tool; struct { CHyprSignalListener destroySurface; + CHyprSignalListener destroyTool; } listeners; }; \ No newline at end of file diff --git a/src/devices/TouchDevice.cpp b/src/devices/TouchDevice.cpp index 64c521a2..25b7b503 100644 --- a/src/devices/TouchDevice.cpp +++ b/src/devices/TouchDevice.cpp @@ -1,7 +1,8 @@ #include "TouchDevice.hpp" #include "../defines.hpp" +#include -SP CTouchDevice::create(wlr_touch* touch) { +SP CTouchDevice::create(SP touch) { SP pTouch = SP(new CTouchDevice(touch)); pTouch->self = pTouch; @@ -9,78 +10,63 @@ SP CTouchDevice::create(wlr_touch* touch) { return pTouch; } -CTouchDevice::CTouchDevice(wlr_touch* touch_) : touch(touch_) { +CTouchDevice::CTouchDevice(SP touch_) : touch(touch_) { if (!touch) return; - // clang-format off - hyprListener_destroy.initCallback(&touch->base.events.destroy, [this] (void* owner, void* data) { + listeners.destroy = touch->events.destroy.registerListener([this](std::any d) { events.destroy.emit(); - disconnectCallbacks(); - touch = nullptr; - }, this, "CTouchDevice"); + touch.reset(); + }); - hyprListener_down.initCallback(&touch->events.down, [this] (void* owner, void* data) { - auto E = (wlr_touch_down_event*)data; + listeners.down = touch->events.down.registerListener([this](std::any d) { + auto E = std::any_cast(d); touchEvents.down.emit(SDownEvent{ - .timeMs = E->time_msec, - .touchID = E->touch_id, - .pos = {E->x, E->y}, + .timeMs = E.timeMs, + .touchID = E.touchID, + .pos = E.pos, .device = self.lock(), }); - }, this, "CTouchDevice"); + }); - hyprListener_up.initCallback(&touch->events.up, [this] (void* owner, void* data) { - auto E = (wlr_touch_up_event*)data; + listeners.up = touch->events.up.registerListener([this](std::any d) { + auto E = std::any_cast(d); touchEvents.up.emit(SUpEvent{ - .timeMs = E->time_msec, - .touchID = E->touch_id + .timeMs = E.timeMs, + .touchID = E.touchID, }); - }, this, "CTouchDevice"); + }); - hyprListener_motion.initCallback(&touch->events.motion, [this] (void* owner, void* data) { - auto E = (wlr_touch_motion_event*)data; + listeners.motion = touch->events.move.registerListener([this](std::any d) { + auto E = std::any_cast(d); touchEvents.motion.emit(SMotionEvent{ - .timeMs = E->time_msec, - .touchID = E->touch_id, - .pos = {E->x, E->y}, + .timeMs = E.timeMs, + .touchID = E.touchID, + .pos = E.pos, }); - }, this, "CTouchDevice"); + }); - hyprListener_cancel.initCallback(&touch->events.cancel, [this] (void* owner, void* data) { - auto E = (wlr_touch_cancel_event*)data; + listeners.cancel = touch->events.cancel.registerListener([this](std::any d) { + auto E = std::any_cast(d); touchEvents.cancel.emit(SCancelEvent{ - .timeMs = E->time_msec, - .touchID = E->touch_id + .timeMs = E.timeMs, + .touchID = E.touchID, }); - }, this, "CTouchDevice"); + }); - hyprListener_frame.initCallback(&touch->events.frame, [this] (void* owner, void* data) { - touchEvents.frame.emit(); - }, this, "CTouchDevice"); + listeners.frame = touch->events.frame.registerListener([this](std::any d) { touchEvents.frame.emit(); }); - // clang-format on - - deviceName = touch->base.name ? touch->base.name : "UNKNOWN"; + deviceName = touch->getName(); } bool CTouchDevice::isVirtual() { return false; } -wlr_touch* CTouchDevice::wlr() { - return touch; -} - -void CTouchDevice::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_down.removeCallback(); - hyprListener_up.removeCallback(); - hyprListener_motion.removeCallback(); - hyprListener_cancel.removeCallback(); - hyprListener_frame.removeCallback(); +SP CTouchDevice::aq() { + return touch.lock(); } diff --git a/src/devices/TouchDevice.hpp b/src/devices/TouchDevice.hpp index 51eb76d4..b18df2d0 100644 --- a/src/devices/TouchDevice.hpp +++ b/src/devices/TouchDevice.hpp @@ -4,22 +4,22 @@ class CTouchDevice : public ITouch { public: - static SP create(wlr_touch* touch); + static SP create(SP touch); - virtual bool isVirtual(); - virtual wlr_touch* wlr(); + virtual bool isVirtual(); + virtual SP aq(); private: - CTouchDevice(wlr_touch* touch); + CTouchDevice(SP touch); - wlr_touch* touch = nullptr; + WP touch; - void disconnectCallbacks(); - - DYNLISTENER(destroy); - DYNLISTENER(down); - DYNLISTENER(up); - DYNLISTENER(motion); - DYNLISTENER(cancel); - DYNLISTENER(frame); + struct { + CHyprSignalListener destroy; + CHyprSignalListener down; + CHyprSignalListener up; + CHyprSignalListener motion; + CHyprSignalListener cancel; + CHyprSignalListener frame; + } listeners; }; \ No newline at end of file diff --git a/src/devices/VirtualKeyboard.cpp b/src/devices/VirtualKeyboard.cpp index e2be0078..654ca9f5 100644 --- a/src/devices/VirtualKeyboard.cpp +++ b/src/devices/VirtualKeyboard.cpp @@ -14,58 +14,37 @@ CVirtualKeyboard::CVirtualKeyboard(SP keeb_) : keybo if (!keeb_) return; - auto keeb = keeb_->wlr(); - - // clang-format off - hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) { - disconnectCallbacks(); + listeners.destroy = keeb_->events.destroy.registerListener([this](std::any d) { keyboard.reset(); - events.destroy.emit(); - }, this, "CVirtualKeyboard"); + events.destroy.emit(); + }); - hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) { - auto E = (wlr_keyboard_key_event*)data; - - keyboardEvents.key.emit(SKeyEvent{ - .timeMs = E->time_msec, - .keycode = E->keycode, - .updateMods = E->update_state, - .state = E->state, + listeners.key = keeb_->events.key.registerListener([this](std::any d) { keyboardEvents.key.emit(d); }); + listeners.modifiers = keeb_->events.modifiers.registerListener([this](std::any d) { + auto E = std::any_cast(d); + updateModifiers(E.depressed, E.latched, E.locked, E.group); + keyboardEvents.modifiers.emit(SModifiersEvent{ + .depressed = modifiersState.depressed, + .latched = modifiersState.latched, + .locked = modifiersState.locked, + .group = modifiersState.group, }); - }, this, "CVirtualKeyboard"); + }); + listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) { + auto E = std::any_cast(d); + xkbKeymap = xkb_keymap_ref(E.keymap); + keyboardEvents.keymap.emit(d); + }); - hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) { - keyboardEvents.keymap.emit(); - }, this, "CVirtualKeyboard"); - - hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) { - keyboardEvents.modifiers.emit(); - }, this, "CVirtualKeyboard"); - - hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) { - keyboardEvents.repeatInfo.emit(); - }, this, "CVirtualKeyboard"); - // clang-format on - - deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN"; + deviceName = keeb_->name; } bool CVirtualKeyboard::isVirtual() { return true; } -wlr_keyboard* CVirtualKeyboard::wlr() { - if (keyboard.expired()) - return nullptr; - return keyboard->wlr(); -} - -void CVirtualKeyboard::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_key.removeCallback(); - hyprListener_keymap.removeCallback(); - hyprListener_repeatInfo.removeCallback(); - hyprListener_modifiers.removeCallback(); +SP CVirtualKeyboard::aq() { + return nullptr; } wl_client* CVirtualKeyboard::getClient() { diff --git a/src/devices/VirtualKeyboard.hpp b/src/devices/VirtualKeyboard.hpp index 5ef88dd3..12a3907c 100644 --- a/src/devices/VirtualKeyboard.hpp +++ b/src/devices/VirtualKeyboard.hpp @@ -6,23 +6,22 @@ class CVirtualKeyboardV1Resource; class CVirtualKeyboard : public IKeyboard { public: - static SP create(SP keeb); + static SP create(SP keeb); - virtual bool isVirtual(); - virtual wlr_keyboard* wlr(); + virtual bool isVirtual(); + virtual SP aq(); - wl_client* getClient(); + wl_client* getClient(); private: CVirtualKeyboard(SP keeb); WP keyboard; - void disconnectCallbacks(); - - DYNLISTENER(destroy); - DYNLISTENER(key); - DYNLISTENER(modifiers); - DYNLISTENER(keymap); - DYNLISTENER(repeatInfo); + struct { + CHyprSignalListener destroy; + CHyprSignalListener key; + CHyprSignalListener modifiers; + CHyprSignalListener keymap; + } listeners; }; diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index c8ee3332..faca27dc 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -1,5 +1,6 @@ #include "VirtualPointer.hpp" #include "../protocols/VirtualPointer.hpp" +#include SP CVirtualPointer::create(SP resource) { SP pPointer = SP(new CVirtualPointer(resource)); @@ -13,165 +14,32 @@ CVirtualPointer::CVirtualPointer(SP resource) : point if (!resource->good()) return; - auto mouse = resource->wlr(); - - // clang-format off - hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) { - disconnectCallbacks(); + listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) { + pointer.reset(); events.destroy.emit(); - }, this, "CVirtualPointer"); + }); - hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) { - auto E = (wlr_pointer_motion_event*)data; + listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); }); + listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) { pointerEvents.motionAbsolute.emit(d); }); + listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); }); + listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); }); + listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); }); + listeners.swipeBegin = pointer->events.swipeBegin.registerListener([this](std::any d) { pointerEvents.swipeBegin.emit(d); }); + listeners.swipeEnd = pointer->events.swipeEnd.registerListener([this](std::any d) { pointerEvents.swipeEnd.emit(d); }); + listeners.swipeUpdate = pointer->events.swipeUpdate.registerListener([this](std::any d) { pointerEvents.swipeUpdate.emit(d); }); + listeners.pinchBegin = pointer->events.pinchBegin.registerListener([this](std::any d) { pointerEvents.pinchBegin.emit(d); }); + listeners.pinchEnd = pointer->events.pinchEnd.registerListener([this](std::any d) { pointerEvents.pinchEnd.emit(d); }); + listeners.pinchUpdate = pointer->events.pinchUpdate.registerListener([this](std::any d) { pointerEvents.pinchUpdate.emit(d); }); + listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); }); + listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); }); - pointerEvents.motion.emit(SMotionEvent{ - .timeMs = E->time_msec, - .delta = {E->delta_x, E->delta_y}, - .unaccel = {E->unaccel_dx, E->unaccel_dy}, - }); - }, this, "CVirtualPointer"); - - hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) { - auto E = (wlr_pointer_motion_absolute_event*)data; - - pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ - .timeMs = E->time_msec, - .absolute = {E->x, E->y}, - .device = self.lock(), - }); - }, this, "CVirtualPointer"); - - hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) { - auto E = (wlr_pointer_button_event*)data; - - pointerEvents.button.emit(SButtonEvent{ - .timeMs = E->time_msec, - .button = E->button, - .state = (wl_pointer_button_state)E->state, - }); - }, this, "CVirtualPointer"); - - hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) { - auto E = (wlr_pointer_axis_event*)data; - - pointerEvents.axis.emit(SAxisEvent{ - .timeMs = E->time_msec, - .source = E->source, - .axis = E->orientation, - .relativeDirection = E->relative_direction, - .delta = E->delta, - .deltaDiscrete = E->delta_discrete, - }); - }, this, "CVirtualPointer"); - - hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) { - pointerEvents.frame.emit(); - }, this, "CVirtualPointer"); - - hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_begin_event*)data; - - pointerEvents.swipeBegin.emit(SSwipeBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - }); - }, this, "CVirtualPointer"); - - hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_end_event*)data; - - pointerEvents.swipeEnd.emit(SSwipeEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, - }); - }, this, "CVirtualPointer"); - - hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_update_event*)data; - - pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - .delta = {E->dx, E->dy}, - }); - }, this, "CVirtualPointer"); - - hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_begin_event*)data; - - pointerEvents.pinchBegin.emit(SPinchBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - }); - }, this, "CVirtualPointer"); - - hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_end_event*)data; - - pointerEvents.pinchEnd.emit(SPinchEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, - }); - }, this, "CVirtualPointer"); - - hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_update_event*)data; - - pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - .delta = {E->dx, E->dy}, - .scale = E->scale, - .rotation = E->rotation, - }); - }, this, "CVirtualPointer"); - - hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_hold_begin_event*)data; - - pointerEvents.holdBegin.emit(SHoldBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - }); - }, this, "CVirtualPointer"); - - hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_hold_end_event*)data; - - pointerEvents.holdEnd.emit(SHoldEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, - }); - }, this, "CVirtualPointer"); - - // clang-format on - - deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN"; + deviceName = pointer->name; } bool CVirtualPointer::isVirtual() { return true; } -void CVirtualPointer::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_motion.removeCallback(); - hyprListener_motionAbsolute.removeCallback(); - hyprListener_button.removeCallback(); - hyprListener_axis.removeCallback(); - hyprListener_frame.removeCallback(); - hyprListener_swipeBegin.removeCallback(); - hyprListener_swipeEnd.removeCallback(); - hyprListener_swipeUpdate.removeCallback(); - hyprListener_pinchBegin.removeCallback(); - hyprListener_pinchEnd.removeCallback(); - hyprListener_pinchUpdate.removeCallback(); - hyprListener_holdBegin.removeCallback(); - hyprListener_holdEnd.removeCallback(); -} - -wlr_pointer* CVirtualPointer::wlr() { - if (pointer.expired()) - return nullptr; - return pointer->wlr(); +SP CVirtualPointer::aq() { + return nullptr; } diff --git a/src/devices/VirtualPointer.hpp b/src/devices/VirtualPointer.hpp index b22c8bf2..1ecfd842 100644 --- a/src/devices/VirtualPointer.hpp +++ b/src/devices/VirtualPointer.hpp @@ -6,33 +6,34 @@ class CVirtualPointerV1Resource; class CVirtualPointer : public IPointer { public: - static SP create(SP resource); + static SP create(SP resource); - virtual bool isVirtual(); - virtual wlr_pointer* wlr(); + virtual bool isVirtual(); + virtual SP aq(); private: CVirtualPointer(SP); WP pointer; - void disconnectCallbacks(); + struct { + CHyprSignalListener destroy; - DYNLISTENER(destroy); - DYNLISTENER(motion); - DYNLISTENER(motionAbsolute); - DYNLISTENER(button); - DYNLISTENER(axis); - DYNLISTENER(frame); + CHyprSignalListener motion; + CHyprSignalListener motionAbsolute; + CHyprSignalListener button; + CHyprSignalListener axis; + CHyprSignalListener frame; - DYNLISTENER(swipeBegin); - DYNLISTENER(swipeEnd); - DYNLISTENER(swipeUpdate); + CHyprSignalListener swipeBegin; + CHyprSignalListener swipeEnd; + CHyprSignalListener swipeUpdate; - DYNLISTENER(pinchBegin); - DYNLISTENER(pinchEnd); - DYNLISTENER(pinchUpdate); + CHyprSignalListener pinchBegin; + CHyprSignalListener pinchEnd; + CHyprSignalListener pinchUpdate; - DYNLISTENER(holdBegin); - DYNLISTENER(holdEnd); + CHyprSignalListener holdBegin; + CHyprSignalListener holdEnd; + } listeners; }; \ No newline at end of file diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp deleted file mode 100644 index fedc844e..00000000 --- a/src/events/Devices.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "Events.hpp" - -#include "../Compositor.hpp" -#include "../helpers/WLClasses.hpp" -#include "../managers/input/InputManager.hpp" -#include "../render/Renderer.hpp" - -// ---------------------------------------------------- // -// _____ ________ _______ _____ ______ _____ // -// | __ \| ____\ \ / /_ _/ ____| ____|/ ____| // -// | | | | |__ \ \ / / | || | | |__ | (___ // -// | | | | __| \ \/ / | || | | __| \___ \ // -// | |__| | |____ \ / _| || |____| |____ ____) | // -// |_____/|______| \/ |_____\_____|______|_____/ // -// // -// ---------------------------------------------------- // - -void Events::listener_newInput(wl_listener* listener, void* data) { - const auto DEVICE = (wlr_input_device*)data; - - switch (DEVICE->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - Debug::log(LOG, "Attached a keyboard with name {}", DEVICE->name); - g_pInputManager->newKeyboard(DEVICE); - break; - case WLR_INPUT_DEVICE_POINTER: - Debug::log(LOG, "Attached a mouse with name {}", DEVICE->name); - g_pInputManager->newMouse(DEVICE); - break; - case WLR_INPUT_DEVICE_TOUCH: - Debug::log(LOG, "Attached a touch device with name {}", DEVICE->name); - g_pInputManager->newTouchDevice(DEVICE); - break; - case WLR_INPUT_DEVICE_TABLET: - Debug::log(LOG, "Attached a tablet with name {}", DEVICE->name); - g_pInputManager->newTablet(DEVICE); - break; - case WLR_INPUT_DEVICE_TABLET_PAD: - Debug::log(LOG, "Attached a tablet pad with name {}", DEVICE->name); - g_pInputManager->newTabletPad(DEVICE); - break; - case WLR_INPUT_DEVICE_SWITCH: - Debug::log(LOG, "Attached a switch device with name {}", DEVICE->name); - g_pInputManager->newSwitch(DEVICE); - break; - default: Debug::log(WARN, "Unrecognized input device plugged in: {}", DEVICE->name); break; - } - - g_pInputManager->updateCapabilities(); -} diff --git a/src/events/Events.hpp b/src/events/Events.hpp index f8eb9d2f..8e73f54a 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -8,16 +8,6 @@ // namespace Events { - // Monitor events - LISTENER(change); - LISTENER(newOutput); - - // DRM events - LISTENER(leaseRequest); - - // Layer events - LISTENER(newLayerSurface); - // Window events DYNLISTENFUNC(commitWindow); DYNLISTENFUNC(mapWindow); @@ -35,15 +25,6 @@ namespace Events { DYNLISTENFUNC(setOverrideRedirect); DYNLISTENFUNC(ackConfigure); - LISTENER(newInput); - - // Virt Ptr - LISTENER(newVirtPtr); - - // Various - LISTENER(requestSetSel); - LISTENER(requestSetPrimarySel); - // Monitor part 2 the sequel DYNLISTENFUNC(monitorFrame); DYNLISTENFUNC(monitorDestroy); @@ -52,16 +33,4 @@ namespace Events { DYNLISTENFUNC(monitorNeedsFrame); DYNLISTENFUNC(monitorCommit); DYNLISTENFUNC(monitorBind); - - // XWayland - LISTENER(surfaceXWayland); - - // Renderer destroy - LISTENER(RendererDestroy); - - // session - LISTENER(sessionActive); - - // Session Lock - LISTENER(newSessionLock); }; diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp deleted file mode 100644 index 32f894ec..00000000 --- a/src/events/Misc.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "Events.hpp" - -#include "../Compositor.hpp" -#include "../helpers/WLClasses.hpp" -#include "../managers/input/InputManager.hpp" -#include "../render/Renderer.hpp" -#include "../managers/CursorManager.hpp" - -// ------------------------------ // -// __ __ _____ _____ _____ // -// | \/ |_ _|/ ____|/ ____| // -// | \ / | | | | (___ | | // -// | |\/| | | | \___ \| | // -// | | | |_| |_ ____) | |____ // -// |_| |_|_____|_____/ \_____| // -// // -// ------------------------------ // - -void Events::listener_leaseRequest(wl_listener* listener, void* data) { - const auto REQUEST = (wlr_drm_lease_request_v1*)data; - struct wlr_drm_lease_v1* lease = wlr_drm_lease_request_v1_grant(REQUEST); - if (!lease) { - Debug::log(ERR, "Failed to grant lease request!"); - wlr_drm_lease_request_v1_reject(REQUEST); - } -} - -void Events::listener_RendererDestroy(wl_listener* listener, void* data) { - Debug::log(LOG, "!!Renderer destroyed!!"); -} - -void Events::listener_sessionActive(wl_listener* listener, void* data) { - if (g_pCompositor->m_sWLRSession->active) { - Debug::log(LOG, "Session got activated!"); - - g_pCompositor->m_bSessionActive = true; - - for (auto& m : g_pCompositor->m_vMonitors) { - g_pCompositor->scheduleFrameForMonitor(m.get()); - g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); - } - - g_pConfigManager->m_bWantsMonitorReload = true; - } else { - Debug::log(LOG, "Session got inactivated!"); - - g_pCompositor->m_bSessionActive = false; - - for (auto& m : g_pCompositor->m_vMonitors) { - m->noFrameSchedule = true; - m->framesToSkip = 1; - } - } -} diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 2536e1f7..40b6f17e 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -5,6 +5,7 @@ #include "Events.hpp" #include "../debug/HyprCtl.hpp" #include "../config/ConfigValue.hpp" +#include // --------------------------------------------------------- // // __ __ ____ _ _ _____ _______ ____ _____ _____ // @@ -16,99 +17,10 @@ // // // --------------------------------------------------------- // -static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { - - static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); - static auto firstMonitorAdded = std::chrono::steady_clock::now(); - static bool cursorDefaultDone = false; - static bool firstLaunch = true; - - const auto POS = PNEWMONITOR->middle(); - - // by default, cursor should be set to first monitor detected - // this is needed as a default if the monitor given in config above doesn't exist - if (firstLaunch) { - firstLaunch = false; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } - - if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY) - return; - - // after 10s, don't set cursor to default monitor - auto timePassedSec = std::chrono::duration_cast(std::chrono::steady_clock::now() - firstMonitorAdded); - if (timePassedSec.count() > 10) { - cursorDefaultDone = true; - return; - } - - if (*PCURSORMONITOR == monitorName) { - cursorDefaultDone = true; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } -} - -void Events::listener_newOutput(wl_listener* listener, void* data) { - // new monitor added, let's accommodate for that. - const auto OUTPUT = (wlr_output*)data; - - if (!OUTPUT->name) { - Debug::log(ERR, "New monitor has no name?? Ignoring"); - return; - } - - // add it to real - auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); - if (std::string("HEADLESS-1") == OUTPUT->name) - g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); - - PNEWMONITOR->output = OUTPUT; - PNEWMONITOR->self = PNEWMONITOR; - const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false; - PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name); - PNEWMONITOR->isUnsafeFallback = FALLBACK; - - EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR); - - if (!FALLBACK) - PNEWMONITOR->onConnect(false); - - if (!PNEWMONITOR->m_bEnabled || FALLBACK) - return; - - // ready to process if we have a real monitor - - if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled) - g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get(); - - g_pCompositor->m_bReadyToProcess = true; - - g_pConfigManager->m_bWantsMonitorReload = true; - g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get()); - - checkDefaultCursorWarp(PNEWMONITOR, OUTPUT->name); - - for (auto& w : g_pCompositor->m_vWindows) { - if (w->m_iMonitorID == PNEWMONITOR->ID) { - w->m_iLastSurfaceMonitorID = -1; - w->updateSurfaceScaleTransformDetails(); - } - } -} - void Events::listener_monitorFrame(void* owner, void* data) { - if (g_pCompositor->m_bExitTriggered) { - // Only signal cleanup once - g_pCompositor->m_bExitTriggered = false; - g_pCompositor->cleanup(); - return; - } - CMonitor* const PMONITOR = (CMonitor*)owner; - if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { + if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { Debug::log(WARN, "Attempted to render frame on inactive session!"); if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) { @@ -172,12 +84,10 @@ void Events::listener_monitorFrame(void* owner, void* data) { } void Events::listener_monitorDestroy(void* owner, void* data) { - const auto OUTPUT = (wlr_output*)data; - - CMonitor* pMonitor = nullptr; + CMonitor* pMonitor = (CMonitor*)owner; for (auto& m : g_pCompositor->m_vRealMonitors) { - if (m->output == OUTPUT) { + if (m->output == pMonitor->output) { pMonitor = m.get(); break; } @@ -188,9 +98,6 @@ void Events::listener_monitorDestroy(void* owner, void* data) { Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name); - if (pMonitor->output->idle_frame) - wl_event_source_remove(pMonitor->output->idle_frame); - pMonitor->onDisconnect(true); pMonitor->output = nullptr; @@ -201,44 +108,18 @@ void Events::listener_monitorDestroy(void* owner, void* data) { std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP& el) { return el.get() == pMonitor; }); } -void Events::listener_monitorStateRequest(void* owner, void* data) { - const auto PMONITOR = (CMonitor*)owner; - const auto E = (wlr_output_event_request_state*)data; - - if (!PMONITOR->createdByUser) - return; - - const auto SIZE = E->state->mode ? Vector2D{E->state->mode->width, E->state->mode->height} : Vector2D{E->state->custom_mode.width, E->state->custom_mode.height}; - - PMONITOR->forceSize = SIZE; - - SMonitorRule rule = PMONITOR->activeMonitorRule; - rule.resolution = SIZE; - - g_pHyprRenderer->applyMonitorRule(PMONITOR, &rule); -} - -void Events::listener_monitorDamage(void* owner, void* data) { - const auto PMONITOR = (CMonitor*)owner; - const auto E = (wlr_output_event_damage*)data; - - PMONITOR->addDamage(E->damage); -} - void Events::listener_monitorNeedsFrame(void* owner, void* data) { const auto PMONITOR = (CMonitor*)owner; - g_pCompositor->scheduleFrameForMonitor(PMONITOR); + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); } void Events::listener_monitorCommit(void* owner, void* data) { const auto PMONITOR = (CMonitor*)owner; - const auto E = (wlr_output_event_commit*)data; - - if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) { - g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E); - g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E); + if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER + g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR); + g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR); } } diff --git a/src/helpers/CursorShapes.hpp b/src/helpers/CursorShapes.hpp new file mode 100644 index 00000000..6f3c8a0e --- /dev/null +++ b/src/helpers/CursorShapes.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +// clang-format off +constexpr std::array CURSOR_SHAPE_NAMES = { + "invalid", + "default", + "context-menu", + "help", + "pointer", + "progress", + "wait", + "cell", + "crosshair", + "text", + "vertical-text", + "alias", + "copy", + "move", + "no-drop", + "not-allowed", + "grab", + "grabbing", + "e-resize", + "n-resize", + "ne-resize", + "nw-resize", + "s-resize", + "se-resize", + "sw-resize", + "w-resize", + "ew-resize", + "ns-resize", + "nesw-resize", + "nwse-resize", + "col-resize", + "row-resize", + "all-scroll", + "zoom-in", + "zoom-out", +}; +// clang-format on \ No newline at end of file diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 5251002c..afc8b1c5 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -3,6 +3,8 @@ #include "../includes.hpp" #include "debug/Log.hpp" #include "../macros.hpp" +#include +#include /* DRM formats are LE, while OGL is BE. The two primary formats @@ -309,3 +311,17 @@ uint32_t FormatUtils::glFormatToType(uint32_t gl) { #endif GL_UNSIGNED_BYTE; } + +std::string FormatUtils::drmFormatName(DRMFormat drm) { + auto n = drmGetFormatName(drm); + std::string name = n; + free(n); + return name; +} + +std::string FormatUtils::drmModifierName(uint64_t mod) { + auto n = drmGetFormatModifierName(mod); + std::string name = n; + free(n); + return name; +} diff --git a/src/helpers/Format.hpp b/src/helpers/Format.hpp index a1ef53f5..8269c5c3 100644 --- a/src/helpers/Format.hpp +++ b/src/helpers/Format.hpp @@ -1,7 +1,9 @@ #pragma once #include +#include #include "math/Math.hpp" +#include typedef uint32_t DRMFormat; typedef uint32_t SHMFormat; @@ -18,10 +20,7 @@ struct SPixelFormat { Vector2D blockSize; }; -struct SDRMFormat { - uint32_t format = 0; - std::vector mods; -}; +typedef Aquamarine::SDRMFormat SDRMFormat; namespace FormatUtils { SHMFormat drmToShm(DRMFormat drm); @@ -34,4 +33,6 @@ namespace FormatUtils { int minStride(const SPixelFormat* const fmt, int32_t width); uint32_t drmFormatToGL(DRMFormat drm); uint32_t glFormatToType(uint32_t gl); + std::string drmFormatName(DRMFormat drm); + std::string drmModifierName(uint64_t mod); }; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 712e4e50..53c0dc13 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -4,9 +4,12 @@ #include "../Compositor.hpp" #include "../managers/TokenManager.hpp" #include +#include +#include #include #include #include +#include #include #include #include diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 33be7965..49e3bced 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "math/Math.hpp" #include #include diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 20c2e81e..a23b9861 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1,12 +1,18 @@ #include "Monitor.hpp" #include "MiscFunctions.hpp" +#include "math/Math.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/GammaControl.hpp" #include "../devices/ITouch.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" +#include "../protocols/DRMLease.hpp" +#include "../protocols/core/Output.hpp" #include "../managers/PointerManager.hpp" +#include "../protocols/core/Compositor.hpp" +#include "sync/SyncTimeline.hpp" +#include #include using namespace Hyprutils::String; @@ -21,62 +27,73 @@ CMonitor::CMonitor() : state(this) { } CMonitor::~CMonitor() { - hyprListener_monitorDestroy.removeCallback(); - hyprListener_monitorFrame.removeCallback(); - hyprListener_monitorStateRequest.removeCallback(); - hyprListener_monitorDamage.removeCallback(); - hyprListener_monitorNeedsFrame.removeCallback(); - hyprListener_monitorCommit.removeCallback(); - hyprListener_monitorBind.removeCallback(); - events.destroy.emit(); } -static void onPresented(void* owner, void* data) { - const auto PMONITOR = (CMonitor*)owner; - auto E = (wlr_output_event_present*)data; - - PROTO::presentation->onPresented(PMONITOR, E->when, E->refresh, E->seq, E->flags); -} - void CMonitor::onConnect(bool noRule) { - hyprListener_monitorDestroy.removeCallback(); - hyprListener_monitorFrame.removeCallback(); - hyprListener_monitorStateRequest.removeCallback(); - hyprListener_monitorDamage.removeCallback(); - hyprListener_monitorNeedsFrame.removeCallback(); - hyprListener_monitorCommit.removeCallback(); - hyprListener_monitorBind.removeCallback(); - hyprListener_monitorPresented.removeCallback(); - hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this, "CMonitor"); - hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this, "CMonitor"); - hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this, "CMonitor"); - hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this, "CMonitor"); - hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this, "CMonitor"); - hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this, "CMonitor"); - hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this, "CMonitor"); - hyprListener_monitorPresented.initCallback(&output->events.present, ::onPresented, this, "CMonitor"); - tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm + if (output->supportsExplicit) { + inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); + outTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); + } + + listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); }); + listeners.destroy = output->events.destroy.registerListener([this](std::any d) { Events::listener_monitorDestroy(this, nullptr); }); + listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); }); + listeners.needsFrame = + output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); }); + listeners.presented = output->events.present.registerListener([this](std::any d) { + auto E = std::any_cast(d); + PROTO::presentation->onPresented(this, E.when, E.refresh, E.seq, E.flags); + }); + + listeners.state = output->events.state.registerListener([this](std::any d) { + auto E = std::any_cast(d); + + if (E.size == Vector2D{}) { + // an indication to re-set state + // we can't do much for createdByUser displays I think + if (createdByUser) + return; + + Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName); + g_pHyprRenderer->applyMonitorRule(this, &activeMonitorRule, true); + return; + } + + if (!createdByUser) + return; + + const auto SIZE = E.size; + + forceSize = SIZE; + + SMonitorRule rule = activeMonitorRule; + rule.resolution = SIZE; + + g_pHyprRenderer->applyMonitorRule(this, &rule); + }); + + tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; if (m_bEnabled) { - wlr_output_state_set_enabled(state.wlr(), true); + output->state->setEnabled(true); state.commit(); return; } szName = output->name; - szDescription = output->description ? output->description : ""; + szDescription = output->description; // remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description std::erase(szDescription, ','); // field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix - szShortDescription = trim(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : "")); + szShortDescription = trim(std::format("{} {} {}", output->make, output->model, output->serial)); std::erase(szShortDescription, ','); - if (!wlr_backend_is_drm(output->backend)) - createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable + if (output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM) + createdByUser = true; // should be true. WL and Headless backends should be addable / removable // get monitor rule that matches SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this); @@ -84,54 +101,23 @@ void CMonitor::onConnect(bool noRule) { // if it's disabled, disable and ignore if (monitorRule.disabled) { - wlr_output_state_set_scale(state.wlr(), 1); - wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL); - - auto PREFSTATE = wlr_output_preferred_mode(output); - - if (!PREFSTATE) { - wlr_output_mode* mode; - - wl_list_for_each(mode, &output->modes, link) { - wlr_output_state_set_mode(state.wlr(), mode); - - if (!wlr_output_test_state(output, state.wlr())) - continue; - - PREFSTATE = mode; - break; - } - } - - if (PREFSTATE) - wlr_output_state_set_mode(state.wlr(), PREFSTATE); - else - Debug::log(WARN, "No mode found for disabled output {}", output->name); - - wlr_output_state_set_enabled(state.wlr(), 0); + output->state->setEnabled(false); if (!state.commit()) Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name); m_bEnabled = false; - hyprListener_monitorFrame.removeCallback(); + listeners.frame.reset(); return; } - if (output->non_desktop) { + if (output->nonDesktop) { Debug::log(LOG, "Not configuring non-desktop output"); - if (g_pCompositor->m_sWRLDRMLeaseMgr) { - wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output); - } - return; - } + if (PROTO::lease) + PROTO::lease->offer(self.lock()); - if (!m_bRenderingInitPassed) { - output->allocator = nullptr; - output->renderer = nullptr; - wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer); - m_bRenderingInitPassed = true; + return; } SP* thisWrapper = nullptr; @@ -151,14 +137,14 @@ void CMonitor::onConnect(bool noRule) { m_bEnabled = true; - wlr_output_state_set_enabled(state.wlr(), 1); + output->state->setEnabled(true); // set mode, also applies if (!noRule) g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); if (!state.commit()) - Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit"); + Debug::log(WARN, "state.commit() failed in CMonitor::onCommit"); damage.setSize(vecTransformedSize); @@ -214,7 +200,7 @@ void CMonitor::onConnect(bool noRule) { renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this); - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR); PROTO::gamma->applyGammaToState(this); @@ -261,12 +247,10 @@ void CMonitor::onDisconnect(bool destroy) { g_pConfigManager->m_bWantsMonitorReload = true; } - hyprListener_monitorFrame.removeCallback(); - hyprListener_monitorPresented.removeCallback(); - hyprListener_monitorDamage.removeCallback(); - hyprListener_monitorNeedsFrame.removeCallback(); - hyprListener_monitorCommit.removeCallback(); - hyprListener_monitorBind.removeCallback(); + listeners.frame.reset(); + listeners.presented.reset(); + listeners.needsFrame.reset(); + listeners.commit.reset(); for (size_t i = 0; i < 4; ++i) { for (auto& ls : m_aLayerSurfaceLayers[i]) { @@ -316,10 +300,10 @@ void CMonitor::onDisconnect(bool destroy) { activeWorkspace->m_bVisible = false; activeWorkspace.reset(); - wlr_output_state_set_enabled(state.wlr(), false); + output->state->setEnabled(false); if (!state.commit()) - Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect"); + Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect"); if (g_pCompositor->m_pLastMonitor.get() == this) g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput); @@ -344,9 +328,9 @@ void CMonitor::addDamage(const pixman_region32_t* rg) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { damage.damageEntire(); - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } else if (damage.damage(rg)) - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } void CMonitor::addDamage(const CRegion* rg) { @@ -357,11 +341,11 @@ void CMonitor::addDamage(const CBox* box) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { damage.damageEntire(); - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } if (damage.damage(*box)) - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { @@ -369,8 +353,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { static auto PMINRR = CConfigValue("cursor:min_refresh_rate"); // skip scheduling extra frames for fullsreen apps with vrr - bool shouldSkip = *PNOBREAK && output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && - activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL; + bool shouldSkip = + *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL; // keep requested minimum refresh rate if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { @@ -563,7 +547,7 @@ float CMonitor::getDefaultScale() { static constexpr double MMPERINCH = 25.4; const auto DIAGONALPX = sqrt(pow(vecPixelSize.x, 2) + pow(vecPixelSize.y, 2)); - const auto DIAGONALIN = sqrt(pow(output->phys_width / MMPERINCH, 2) + pow(output->phys_height / MMPERINCH, 2)); + const auto DIAGONALIN = sqrt(pow(output->physicalSize.x / MMPERINCH, 2) + pow(output->physicalSize.y / MMPERINCH, 2)); const auto PPI = DIAGONALPX / DIAGONALIN; @@ -767,11 +751,11 @@ Vector2D CMonitor::middle() { } void CMonitor::updateMatrix() { - wlr_matrix_identity(projMatrix.data()); + matrixIdentity(projMatrix.data()); if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { - wlr_matrix_translate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0); - wlr_matrix_transform(projMatrix.data(), transform); - wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0); + matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0); + matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform)); + matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0); } } @@ -787,31 +771,124 @@ CBox CMonitor::logicalBox() { return {vecPosition, vecSize}; } +static void onDoneSource(void* data) { + auto pMonitor = (CMonitor*)data; + + if (!PROTO::outputs.contains(pMonitor->szName)) + return; + + PROTO::outputs.at(pMonitor->szName)->sendDone(); +} + +void CMonitor::scheduleDone() { + if (doneSource) + return; + + doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this); +} + +bool CMonitor::attemptDirectScanout() { + if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked) + return false; // do not DS if this monitor is being mirrored. Will break the functionality. + + if (g_pPointerManager->softwareLockedFor(self.lock())) + return false; + + const auto PCANDIDATE = solitaryClient.lock(); + + if (!PCANDIDATE) + return false; + + const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); + + if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != vecPixelSize || PSURFACE->current.transform != transform) + return false; + + // we can't scanout shm buffers. + if (!PSURFACE->current.buffer->dmabuf().success) + return false; + + // FIXME: make sure the buffer actually follows the available scanout dmabuf formats + // and comes from the appropriate device. This may implode on multi-gpu!! + + output->state->setBuffer(PSURFACE->current.buffer); + output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); + + if (!state.test()) + return false; + + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + Debug::log(TRACE, "presentFeedback for DS"); + PSURFACE->presentFeedback(&now, this, true); + + if (state.commit()) { + if (lastScanout.expired()) { + lastScanout = PCANDIDATE; + Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); + } + } else { + lastScanout.reset(); + return false; + } + + return true; +} + CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; - wlr_output_state_init(&m_state); } CMonitorState::~CMonitorState() { - wlr_output_state_finish(&m_state); + ; } -wlr_output_state* CMonitorState::wlr() { - return &m_state; -} +void CMonitorState::ensureBufferPresent() { + if (!m_pOwner->output->state->state().enabled) { + Debug::log(TRACE, "CMonitorState::ensureBufferPresent: Ignoring, monitor is not enabled"); + return; + } -void CMonitorState::clear() { - wlr_output_state_finish(&m_state); - m_state = {0}; - wlr_output_state_init(&m_state); + if (m_pOwner->output->state->state().buffer) + return; + + // this is required for modesetting being possible and might be missing in case of first tests in the renderer + // where we test modes and buffers + Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer, attaching one from the swapchain for modeset being possible"); + m_pOwner->output->state->setBuffer(m_pOwner->output->swapchain->next(nullptr)); + m_pOwner->output->swapchain->rollback(); // restore the counter, don't advance the swapchain } bool CMonitorState::commit() { - bool ret = wlr_output_commit_state(m_pOwner->output, &m_state); - clear(); + if (!updateSwapchain()) + return false; + + ensureBufferPresent(); + + bool ret = m_pOwner->output->commit(); return ret; } bool CMonitorState::test() { - return wlr_output_test_state(m_pOwner->output, &m_state); + if (!updateSwapchain()) + return false; + + ensureBufferPresent(); + + return m_pOwner->output->test(); +} + +bool CMonitorState::updateSwapchain() { + auto options = m_pOwner->output->swapchain->currentOptions(); + const auto& STATE = m_pOwner->output->state->state(); + const auto& MODE = STATE.mode ? STATE.mode : STATE.customMode; + if (!MODE) { + Debug::log(WARN, "updateSwapchain: No mode?"); + return true; + } + options.format = STATE.drmFormat; + options.scanout = true; + options.length = 2; + options.size = MODE->pixelSize; + return m_pOwner->output->swapchain->reconfigure(options); } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 8a2acdaf..32fc768a 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -12,6 +12,8 @@ #include #include "signal/Signal.hpp" #include "DamageRing.hpp" +#include +#include // Enum for the different types of auto directions, e.g. auto-left, auto-up. enum eAutoDirs { @@ -38,22 +40,21 @@ struct SMonitorRule { }; class CMonitor; +class CSyncTimeline; -// Class for wrapping the wlr state class CMonitorState { public: CMonitorState(CMonitor* owner); ~CMonitorState(); - wlr_output_state* wlr(); - void clear(); - // commit() will also clear() bool commit(); bool test(); + bool updateSwapchain(); private: - wlr_output_state m_state = {0}; - CMonitor* m_pOwner; + void ensureBufferPresent(); + + CMonitor* m_pOwner; }; class CMonitor { @@ -61,61 +62,69 @@ class CMonitor { CMonitor(); ~CMonitor(); - Vector2D vecPosition = Vector2D(-1, -1); // means unset - Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset - Vector2D vecSize = Vector2D(0, 0); - Vector2D vecPixelSize = Vector2D(0, 0); - Vector2D vecTransformedSize = Vector2D(0, 0); + Vector2D vecPosition = Vector2D(-1, -1); // means unset + Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset + Vector2D vecSize = Vector2D(0, 0); + Vector2D vecPixelSize = Vector2D(0, 0); + Vector2D vecTransformedSize = Vector2D(0, 0); - bool primary = false; + bool primary = false; - uint64_t ID = -1; - PHLWORKSPACE activeWorkspace = nullptr; - PHLWORKSPACE activeSpecialWorkspace = nullptr; - float setScale = 1; // scale set by cfg - float scale = 1; // real scale + uint64_t ID = -1; + PHLWORKSPACE activeWorkspace = nullptr; + PHLWORKSPACE activeSpecialWorkspace = nullptr; + float setScale = 1; // scale set by cfg + float scale = 1; // real scale - std::string szName = ""; - std::string szDescription = ""; - std::string szShortDescription = ""; + std::string szName = ""; + std::string szDescription = ""; + std::string szShortDescription = ""; - Vector2D vecReservedTopLeft = Vector2D(0, 0); - Vector2D vecReservedBottomRight = Vector2D(0, 0); + Vector2D vecReservedTopLeft = Vector2D(0, 0); + Vector2D vecReservedBottomRight = Vector2D(0, 0); - drmModeModeInfo customDrmMode = {}; + drmModeModeInfo customDrmMode = {}; - CMonitorState state; - CDamageRing damage; + CMonitorState state; + CDamageRing damage; - wlr_output* output = nullptr; - float refreshRate = 60; - int framesToSkip = 0; - int forceFullFrames = 0; - bool noFrameSchedule = false; - bool scheduledRecalc = false; - wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; - float xwaylandScale = 1.f; - std::array projMatrix = {0}; - std::optional forceSize; - wlr_output_mode* currentMode = nullptr; + SP output; + float refreshRate = 60; + int framesToSkip = 0; + int forceFullFrames = 0; + bool noFrameSchedule = false; + bool scheduledRecalc = false; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + float xwaylandScale = 1.f; + std::array projMatrix = {0}; + std::optional forceSize; + SP currentMode; + SP cursorSwapchain; - bool dpmsStatus = true; - bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. - bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed. - bool createdByUser = false; - uint32_t drmFormat = DRM_FORMAT_INVALID; - bool isUnsafeFallback = false; + bool dpmsStatus = true; + bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. + bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed. + bool createdByUser = false; + bool isUnsafeFallback = false; - bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after - bool renderingActive = false; + bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after + bool renderingActive = false; - wl_event_source* renderTimer = nullptr; // for RAT - bool RATScheduled = false; - CTimer lastPresentationTimer; + wl_event_source* renderTimer = nullptr; // for RAT + bool RATScheduled = false; + CTimer lastPresentationTimer; - SMonitorRule activeMonitorRule; + bool isBeingLeased = false; - WP self; + SMonitorRule activeMonitorRule; + + // explicit sync + SP inTimeline; + SP outTimeline; + uint64_t lastWaitPoint = 0; + uint64_t commitSeq = 0; + + WP self; // mirroring CMonitor* pMirrorOf = nullptr; @@ -124,6 +133,9 @@ class CMonitor { // for tearing PHLWINDOWREF solitaryClient; + // for direct scanout + PHLWINDOWREF lastScanout; + struct { bool canTear = false; bool nextRenderTorn = false; @@ -143,15 +155,6 @@ class CMonitor { std::array, 4> m_aLayerSurfaceLayers; - DYNLISTENER(monitorFrame); - DYNLISTENER(monitorDestroy); - DYNLISTENER(monitorStateRequest); - DYNLISTENER(monitorDamage); - DYNLISTENER(monitorNeedsFrame); - DYNLISTENER(monitorCommit); - DYNLISTENER(monitorBind); - DYNLISTENER(monitorPresented); - // methods void onConnect(bool noRule); void onDisconnect(bool destroy = false); @@ -173,6 +176,8 @@ class CMonitor { int64_t activeWorkspaceID(); int64_t activeSpecialWorkspaceID(); CBox logicalBox(); + void scheduleDone(); + bool attemptDirectScanout(); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; @@ -184,6 +189,17 @@ class CMonitor { } private: - void setupDefaultWS(const SMonitorRule&); - int findAvailableDefaultWS(); + void setupDefaultWS(const SMonitorRule&); + int findAvailableDefaultWS(); + + wl_event_source* doneSource = nullptr; + + struct { + CHyprSignalListener frame; + CHyprSignalListener destroy; + CHyprSignalListener state; + CHyprSignalListener needsFrame; + CHyprSignalListener presented; + CHyprSignalListener commit; + } listeners; }; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 6b25e76d..51f90166 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -15,6 +15,8 @@ class IPointer; class IKeyboard; class CWLSurfaceResource; +AQUAMARINE_FORWARD(ISwitch); + struct SRenderData { CMonitor* pMonitor; timespec* when; @@ -70,14 +72,14 @@ struct SSwipeGesture { }; struct SSwitchDevice { - wlr_input_device* pWlrDevice = nullptr; + WP pDevice; - int status = -1; // uninitialized - - DYNLISTENER(destroy); - DYNLISTENER(toggle); + struct { + CHyprSignalListener destroy; + CHyprSignalListener fire; + } listeners; bool operator==(const SSwitchDevice& other) const { - return pWlrDevice == other.pWlrDevice; + return pDevice == other.pDevice; } }; diff --git a/src/helpers/X11Stubs.hpp b/src/helpers/X11Stubs.hpp deleted file mode 100644 index 19bea6f8..00000000 --- a/src/helpers/X11Stubs.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -inline bool wlr_backend_is_x11(void*) { - return false; -} - -inline void wlr_x11_output_create(void*) {} diff --git a/src/helpers/math/Math.cpp b/src/helpers/math/Math.cpp index 560f29c9..fccfd636 100644 --- a/src/helpers/math/Math.cpp +++ b/src/helpers/math/Math.cpp @@ -17,14 +17,14 @@ Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; } -static void matrixIdentity(float mat[9]) { +void matrixIdentity(float mat[9]) { static const float identity[9] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; memcpy(mat, identity, sizeof(identity)); } -static void matrixMultiply(float mat[9], const float a[9], const float b[9]) { +void matrixMultiply(float mat[9], const float a[9], const float b[9]) { float product[9]; product[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6]; @@ -42,141 +42,56 @@ static void matrixMultiply(float mat[9], const float a[9], const float b[9]) { memcpy(mat, product, sizeof(product)); } -static void matrixTranspose(float mat[9], const float a[9]) { +void matrixTranspose(float mat[9], const float a[9]) { float transposition[9] = { a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8], }; memcpy(mat, transposition, sizeof(transposition)); } -static void matrixTranslate(float mat[9], float x, float y) { +void matrixTranslate(float mat[9], float x, float y) { float translate[9] = { 1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f, }; matrixMultiply(mat, mat, translate); } -static void matrixScale(float mat[9], float x, float y) { +void matrixScale(float mat[9], float x, float y) { float scale[9] = { x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f, }; matrixMultiply(mat, mat, scale); } -static void matrixRotate(float mat[9], float rad) { +void matrixRotate(float mat[9], float rad) { float rotate[9] = { cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f, }; matrixMultiply(mat, mat, rotate); } -static std::unordered_map> transforms = { - {HYPRUTILS_TRANSFORM_NORMAL, - { - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_90, - { - 0.0f, - 1.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_180, - { - -1.0f, - 0.0f, - 0.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_270, - { - 0.0f, - -1.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_FLIPPED, - { - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_FLIPPED_90, - { - 0.0f, - 1.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_FLIPPED_180, - { - 1.0f, - 0.0f, - 0.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_FLIPPED_270, - { - 0.0f, - -1.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, -}; - -static void matrixTransform(float mat[9], eTransform transform) { - matrixMultiply(mat, mat, transforms.at(transform).data()); +const std::unordered_map>& getTransforms() { + static std::unordered_map> transforms = { + {HYPRUTILS_TRANSFORM_NORMAL, {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_90, {0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_180, {-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_270, {0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_FLIPPED, {-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_FLIPPED_90, {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_FLIPPED_180, {1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_FLIPPED_270, {0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + }; + return transforms; } -static void matrixProjection(float mat[9], int width, int height, eTransform transform) { +void matrixTransform(float mat[9], eTransform transform) { + matrixMultiply(mat, mat, getTransforms().at(transform).data()); +} + +void matrixProjection(float mat[9], int width, int height, eTransform transform) { memset(mat, 0, sizeof(*mat) * 9); - const float* t = transforms.at(transform).data(); + const float* t = getTransforms().at(transform).data(); float x = 2.0f / width; float y = 2.0f / height; @@ -219,3 +134,10 @@ void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, c matrixMultiply(mat, projection, mat); } + +wl_output_transform invertTransform(wl_output_transform tr) { + if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED)) + tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180); + + return tr; +} diff --git a/src/helpers/math/Math.hpp b/src/helpers/math/Math.hpp index 4aa65c93..f57cef93 100644 --- a/src/helpers/math/Math.hpp +++ b/src/helpers/math/Math.hpp @@ -7,5 +7,14 @@ using namespace Hyprutils::Math; -eTransform wlTransformToHyprutils(wl_output_transform t); -void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]); +eTransform wlTransformToHyprutils(wl_output_transform t); +void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]); +void matrixProjection(float mat[9], int width, int height, eTransform transform); +void matrixTransform(float mat[9], eTransform transform); +void matrixRotate(float mat[9], float rad); +void matrixScale(float mat[9], float x, float y); +void matrixTranslate(float mat[9], float x, float y); +void matrixTranspose(float mat[9], const float a[9]); +void matrixMultiply(float mat[9], const float a[9], const float b[9]); +void matrixIdentity(float mat[9]); +wl_output_transform invertTransform(wl_output_transform tr); diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp new file mode 100644 index 00000000..352120ea --- /dev/null +++ b/src/helpers/sync/SyncTimeline.cpp @@ -0,0 +1,190 @@ +#include "SyncTimeline.hpp" +#include "../../defines.hpp" +#include "../../managers/eventLoop/EventLoopManager.hpp" + +#include +#include + +SP CSyncTimeline::create(int drmFD_) { + auto timeline = SP(new CSyncTimeline); + timeline->drmFD = drmFD_; + timeline->self = timeline; + + if (drmSyncobjCreate(drmFD_, 0, &timeline->handle)) { + Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj??"); + return nullptr; + } + + return timeline; +} + +SP CSyncTimeline::create(int drmFD_, int drmSyncobjFD) { + auto timeline = SP(new CSyncTimeline); + timeline->drmFD = drmFD_; + timeline->self = timeline; + + if (drmSyncobjFDToHandle(drmFD_, drmSyncobjFD, &timeline->handle)) { + Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj from fd??"); + return nullptr; + } + + return timeline; +} + +CSyncTimeline::~CSyncTimeline() { + if (handle == 0) + return; + + drmSyncobjDestroy(drmFD, handle); +} + +std::optional CSyncTimeline::check(uint64_t point, uint32_t flags) { +#ifdef __FreeBSD__ + constexpr int ETIME_ERR = ETIMEDOUT; +#else + constexpr int ETIME_ERR = ETIME; +#endif + + uint32_t signaled = 0; + int ret = drmSyncobjTimelineWait(drmFD, &handle, &point, 1, 0, flags, &signaled); + if (ret != 0 && ret != -ETIME_ERR) { + Debug::log(ERR, "CSyncTimeline::check: drmSyncobjTimelineWait failed"); + return std::nullopt; + } + + return ret == 0; +} + +static int handleWaiterFD(int fd, uint32_t mask, void* data) { + auto waiter = (CSyncTimeline::SWaiter*)data; + + if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) { + Debug::log(ERR, "handleWaiterFD: eventfd error"); + return 0; + } + + if (mask & WL_EVENT_READABLE) { + uint64_t value = 0; + if (read(fd, &value, sizeof(value)) <= 0) + Debug::log(ERR, "handleWaiterFD: failed to read from eventfd"); + } + + wl_event_source_remove(waiter->source); + waiter->source = nullptr; + + if (waiter->fn) + waiter->fn(); + + if (waiter->timeline) + waiter->timeline->removeWaiter(waiter); + + return 0; +} + +bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t point, uint32_t flags) { + auto w = makeShared(); + w->fn = waiter; + w->timeline = self; + + int eventFD = eventfd(0, EFD_CLOEXEC); + + if (eventFD < 0) { + Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd"); + return false; + } + + drm_syncobj_eventfd syncobjEventFD = { + .handle = handle, + .flags = flags, + .point = point, + .fd = eventFD, + }; + + if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) { + Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed"); + close(eventFD); + return false; + } + + w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get()); + if (!w->source) { + Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed"); + close(eventFD); + return false; + } + + waiters.emplace_back(w); + + return true; +} + +void CSyncTimeline::removeWaiter(SWaiter* w) { + if (w->source) { + wl_event_source_remove(w->source); + w->source = nullptr; + } + std::erase_if(waiters, [w](const auto& e) { return e.get() == w; }); +} + +int CSyncTimeline::exportAsSyncFileFD(uint64_t src) { + int sync = -1; + + uint32_t syncHandle = 0; + if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { + Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed"); + return -1; + } + + if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) { + Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed"); + drmSyncobjDestroy(drmFD, syncHandle); + return -1; + } + + if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) { + Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed"); + drmSyncobjDestroy(drmFD, syncHandle); + return -1; + } + + drmSyncobjDestroy(drmFD, syncHandle); + return sync; +} + +bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { + uint32_t syncHandle = 0; + + if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { + Debug::log(ERR, "importFromSyncFileFD: drmSyncobjCreate failed"); + return false; + } + + if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) { + Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed"); + drmSyncobjDestroy(drmFD, syncHandle); + return false; + } + + if (drmSyncobjTransfer(drmFD, handle, dst, syncHandle, 0, 0)) { + Debug::log(ERR, "importFromSyncFileFD: drmSyncobjTransfer failed"); + drmSyncobjDestroy(drmFD, syncHandle); + return false; + } + + drmSyncobjDestroy(drmFD, syncHandle); + return true; +} + +bool CSyncTimeline::transfer(SP from, uint64_t fromPoint, uint64_t toPoint) { + if (drmFD != from->drmFD) { + Debug::log(ERR, "CSyncTimeline::transfer: cannot transfer timelines between gpus, {} -> {}", from->drmFD, drmFD); + return false; + } + + if (drmSyncobjTransfer(drmFD, handle, toPoint, from->handle, fromPoint, 0)) { + Debug::log(ERR, "CSyncTimeline::transfer: drmSyncobjTransfer failed"); + return false; + } + + return true; +} diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp new file mode 100644 index 00000000..3d868a95 --- /dev/null +++ b/src/helpers/sync/SyncTimeline.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include +#include "../memory/Memory.hpp" + +/* + Hyprland synchronization timelines are based on the wlroots' ones, which + are based on Vk timeline semaphores: https://www.khronos.org/blog/vulkan-timeline-semaphores +*/ + +struct wl_event_source; + +class CSyncTimeline { + public: + static SP create(int drmFD_); + static SP create(int drmFD_, int drmSyncobjFD); + ~CSyncTimeline(); + + struct SWaiter { + std::function fn; + wl_event_source* source = nullptr; + WP timeline; + }; + + // check if the timeline point has been signaled + // flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE + // std::nullopt on fail + std::optional check(uint64_t point, uint32_t flags); + + bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); + void removeWaiter(SWaiter*); + int exportAsSyncFileFD(uint64_t src); + bool importFromSyncFileFD(uint64_t dst, int fd); + bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); + + int drmFD = -1; + uint32_t handle = 0; + WP self; + + private: + CSyncTimeline() = default; + + std::vector> waiters; +}; diff --git a/src/includes.hpp b/src/includes.hpp index afec078a..8b3f3fad 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -16,78 +16,6 @@ #include #include #include -#include -#include -#include -#include - -#if true -// wlroots uses dumb-ass shit that makes it not compile on C++, let's fix that. -// https://github.com/swaywm/wlroots/issues/682 -// pthread first because it uses class in a C++ way and XWayland includes that... -#include - -#define class _class -#define namespace _namespace -#define static -#define delete delete_ - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if WLR_HAS_X11_BACKEND -#include -#endif -} - -#undef delete -#undef class -#undef namespace -#undef static -#endif #ifdef LEGACY_RENDERER #include @@ -99,10 +27,6 @@ extern "C" { #include #endif -#if !WLR_HAS_X11_BACKEND -#include "helpers/X11Stubs.hpp" -#endif - #ifdef NO_XWAYLAND #define XWAYLAND false #else diff --git a/src/macros.hpp b/src/macros.hpp index f1393cbd..b2adb036 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -105,3 +105,8 @@ class name; \ } \ } + +#define AQUAMARINE_FORWARD(name) \ + namespace Aquamarine { \ + class name; \ + } diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 677b2109..dcc7a45f 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -259,7 +259,7 @@ void CAnimationManager::tick() { // manually schedule a frame if (PMONITOR) - g_pCompositor->scheduleFrameForMonitor(PMONITOR); + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); } // do it here, because if this alters the animation vars deque we would be in trouble above. diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index daa4f4be..3a13d10b 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -3,10 +3,11 @@ #include "../config/ConfigValue.hpp" #include "PointerManager.hpp" #include "../xwayland/XWayland.hpp" +#include +#include "../helpers/CursorShapes.hpp" extern "C" { -#include -#include +#include } static int cursorAnimTimer(void* data) { @@ -45,8 +46,7 @@ CCursorManager::CCursorManager() { if (m_iSize == 0) m_iSize = 24; - m_pWLRXCursorMgr = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"), m_iSize); - wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0); + xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "", m_iSize * std::ceil(m_fCursorScale)); m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr); @@ -56,9 +56,6 @@ CCursorManager::CCursorManager() { } CCursorManager::~CCursorManager() { - if (m_pWLRXCursorMgr) - wlr_xcursor_manager_destroy(m_pWLRXCursorMgr); - if (m_pAnimationTimer) wl_event_source_remove(m_pAnimationTimer); } @@ -67,54 +64,61 @@ void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) { std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; }); } -static void cursorBufferDestroy(struct wlr_buffer* wlr_buffer) { - CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base); - g_pCursorManager->dropBufferRef(buffer->parent); +CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { + surface = surf; + size = size_; + stride = cairo_image_surface_get_stride(surf); } -static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t flags, void** data, uint32_t* format, size_t* stride) { - CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base); - - if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) - return false; - - *data = buffer->pixelData ? buffer->pixelData : cairo_image_surface_get_data(buffer->surface); - *stride = buffer->stride; - *format = DRM_FORMAT_ARGB8888; - return true; -} - -static void cursorBufferEndDataPtr(struct wlr_buffer* wlr_buffer) { - ; -} - -// -static const wlr_buffer_impl bufferImpl = { - .destroy = cursorBufferDestroy, - .begin_data_ptr_access = cursorBufferBeginDataPtr, - .end_data_ptr_access = cursorBufferEndDataPtr, -}; - -CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) { - wlrBuffer.surface = surf; - wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y); - wlrBuffer.parent = this; - wlrBuffer.stride = cairo_image_surface_get_stride(surf); -} - -CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) { - wlrBuffer.pixelData = pixelData; - wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y); - wlrBuffer.parent = this; - wlrBuffer.stride = 4 * size_.x; +CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { + pixelData = pixelData_; + size = size_; + stride = 4 * size_.x; } CCursorManager::CCursorBuffer::~CCursorBuffer() { - ; // will be freed in .destroy + ; } -wlr_buffer* CCursorManager::getCursorBuffer() { - return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr; +Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; +} + +Aquamarine::eBufferType CCursorManager::CCursorBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_SHM; +} + +void CCursorManager::CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) { + ; +} + +bool CCursorManager::CCursorBuffer::isSynchronous() { + return true; +} + +bool CCursorManager::CCursorBuffer::good() { + return true; +} + +Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() { + Aquamarine::SSHMAttrs attrs; + attrs.success = true; + attrs.format = DRM_FORMAT_ARGB8888; + attrs.size = size; + attrs.stride = stride; + return attrs; +} + +std::tuple CCursorManager::CCursorBuffer::beginDataPtr(uint32_t flags) { + return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride}; +} + +void CCursorManager::CCursorBuffer::endDataPtr() { + ; +} + +SP CCursorManager::getCursorBuffer() { + return !m_vCursorBuffers.empty() ? m_vCursorBuffers.back() : nullptr; } void CCursorManager::setCursorSurface(SP surf, const Vector2D& hotspot) { @@ -127,34 +131,24 @@ void CCursorManager::setCursorSurface(SP surf, const Vector2D& hotsp } void CCursorManager::setXCursor(const std::string& name) { - if (!m_pWLRXCursorMgr) { - g_pPointerManager->resetCursorImage(); - return; - } - float scale = std::ceil(m_fCursorScale); - wlr_xcursor_manager_load(m_pWLRXCursorMgr, scale); - auto xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, name.c_str(), scale); - if (!xcursor) { - Debug::log(ERR, "XCursor has no shape {}, retrying with left-ptr", name); - xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left-ptr", scale); - } - - if (!xcursor || !xcursor->images[0]) { - Debug::log(ERR, "XCursor is broken. F this garbage."); + if (!xcursor.themeLoaded) { + Debug::log(ERR, "XCursor failed to find theme in setXCursor"); g_pPointerManager->resetCursorImage(); return; } - auto image = xcursor->images[0]; + auto& icon = xcursor.defaultCursor; + // try to get an icon we know if we have one + if (xcursor.cursors.contains(name)) + icon = xcursor.cursors.at(name); - m_vCursorBuffers.emplace_back( - std::make_unique(image->buffer, Vector2D{(int)image->width, (int)image->height}, Vector2D{(double)image->hotspot_x, (double)image->hotspot_y})); + m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot)); - g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{(double)image->hotspot_x, (double)image->hotspot_y} / scale, scale); + g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon->hotspot / scale, scale); if (m_vCursorBuffers.size() > 1) - wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); + dropBufferRef(m_vCursorBuffers.at(0).get()); m_bOurBufferConnected = true; } @@ -196,14 +190,14 @@ void CCursorManager::setCursorFromName(const std::string& name) { } } - m_vCursorBuffers.emplace_back(std::make_unique(m_sCurrentCursorShapeData.images[0].surface, - Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, - Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); + m_vCursorBuffers.emplace_back(makeShared(m_sCurrentCursorShapeData.images[0].surface, + Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, + Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale, m_fCursorScale); if (m_vCursorBuffers.size() > 1) - wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); + dropBufferRef(m_vCursorBuffers.at(0).get()); m_bOurBufferConnected = true; @@ -225,7 +219,7 @@ void CCursorManager::tickAnimatedCursor() { if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size()) m_iCurrentAnimationFrame = 0; - m_vCursorBuffers.emplace_back(std::make_unique( + m_vCursorBuffers.emplace_back(makeShared( m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface, Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size}, Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY})); @@ -256,10 +250,9 @@ void CCursorManager::setXWaylandCursor() { if (CURSOR.surface) { g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, {CURSOR.hotspotX, CURSOR.hotspotY}); - } else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) { - g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {(int)XCURSOR->images[0]->width, (int)XCURSOR->images[0]->height}, - {(double)XCURSOR->images[0]->hotspot_x, (double)XCURSOR->images[0]->hotspot_y}); - } else + } else if (xcursor.themeLoaded) + g_pXWayland->setCursor((uint8_t*)xcursor.defaultCursor->pixels.data(), xcursor.defaultCursor->size.x * 4, xcursor.defaultCursor->size, xcursor.defaultCursor->hotspot); + else Debug::log(ERR, "CursorManager: no valid cursor for xwayland"); } @@ -284,7 +277,7 @@ void CCursorManager::updateTheme() { for (auto& m : g_pCompositor->m_vMonitors) { m->forceFullFrames = 5; - g_pCompositor->scheduleFrameForMonitor(m.get()); + g_pCompositor->scheduleFrameForMonitor(m.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); } } @@ -303,37 +296,163 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) { Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name); - if (m_pWLRXCursorMgr) - wlr_xcursor_manager_destroy(m_pWLRXCursorMgr); + xcursor.loadTheme(name, size); - m_pWLRXCursorMgr = wlr_xcursor_manager_create(name.empty() ? "" : name.c_str(), size); - bool xSuccess = wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0) == 1; + m_szTheme = name; + m_iSize = size; + updateTheme(); + return true; +} - // this basically checks if xcursor changed used theme to default but better - bool diffTheme = false; - wlr_xcursor_manager_theme* theme; - wl_list_for_each(theme, &m_pWLRXCursorMgr->scaled_themes, link) { - if (std::string{theme->theme->name} != name) { - diffTheme = true; - break; +// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c +// however modified to fit wayland cursor shape names better. +// _ -> - +// clang-format off +static std::array XCURSOR_STANDARD_NAMES = { + "X_cursor", + "default", // arrow + "ns-resize", // based-arrow-down + "ns-resize", // based-arrow-up + "boat", + "bogosity", + "sw-resize", // bottom-left-corner + "se-resize", // bottom-right-corner + "s-resize", // bottom-side + "bottom-tee", + "box-spiral", + "center-ptr", + "circle", + "clock", + "coffee-mug", + "cross", + "cross-reverse", + "crosshair", + "diamond-cross", + "dot", + "dotbox", + "double-arrow", + "draft-large", + "draft-small", + "draped-box", + "exchange", + "move", // fleur + "gobbler", + "gumby", + "pointer", // hand1 + "grabbing", // hand2 + "heart", + "icon", + "iron-cross", + "default", // left-ptr + "w-resize", // left-side + "left-tee", + "leftbutton", + "ll-angle", + "lr-angle", + "man", + "middlebutton", + "mouse", + "pencil", + "pirate", + "plus", + "help", // question-arrow + "right-ptr", + "e-resize", // right-side + "right-tee", + "rightbutton", + "rtl-logo", + "sailboat", + "ns-resize", // sb-down-arrow + "ew-resize", // sb-h-double-arrow + "ew-resize", // sb-left-arrow + "ew-resize", // sb-right-arrow + "n-resize", // sb-up-arrow + "s-resize", // sb-v-double-arrow + "shuttle", + "sizing", + "spider", + "spraycan", + "star", + "target", + "cell", // tcross + "nw-resize", // top-left-arrow + "nw-resize", // top-left-corner + "ne-resize", // top-right-corner + "n-resize", // top-side + "top-tee", + "trek", + "ul-angle", + "umbrella", + "ur-angle", + "wait", // watch + "text", // xterm +}; +// clang-format on + +void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int size) { + if (lastLoadSize == size && themeName == name) + return; + + lastLoadSize = size; + themeLoaded = false; + themeName = name.empty() ? "default" : name; + + auto img = XcursorShapeLoadImage(2, themeName.c_str(), size); + + if (!img) { + Debug::log(ERR, "XCursor failed finding theme \"{}\". Trying size 24.", themeName); + size = 24; + img = XcursorShapeLoadImage(2, themeName.c_str(), size); + if (!img) { + Debug::log(ERR, "XCursor failed finding theme \"{}\".", themeName); + return; } } - if (xSuccess && !diffTheme) { - m_szTheme = name; - m_iSize = size; - updateTheme(); - return true; + defaultCursor = makeShared(); + defaultCursor->size = {(int)img->width, (int)img->height}; + defaultCursor->hotspot = {(int)img->xhot, (int)img->yhot}; + + defaultCursor->pixels.resize(img->width * img->height); + std::memcpy(defaultCursor->pixels.data(), img->pixels, img->width * img->height * sizeof(uint32_t)); + + themeLoaded = true; + + XcursorImageDestroy(img); + + // gather as many shapes as we can find. + cursors.clear(); + + for (auto& shape : CURSOR_SHAPE_NAMES) { + int id = -1; + for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) { + if (XCURSOR_STANDARD_NAMES.at(i) == std::string{shape}) { + id = i; + break; + } + } + + if (id < 0) { + Debug::log(LOG, "XCursor has no shape {}, skipping", shape); + continue; + } + + auto xImage = XcursorShapeLoadImage(id << 1 /* wtf xcursor? */, themeName.c_str(), size); + + if (!xImage) { + Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape); + continue; + } + + auto xcursor = makeShared(); + xcursor->size = {(int)xImage->width, (int)xImage->height}; + xcursor->hotspot = {(int)xImage->xhot, (int)xImage->yhot}; + + xcursor->pixels.resize(xImage->width * xImage->height); + std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t)); + + cursors.emplace(std::string{shape}, xcursor); + + XcursorImageDestroy(xImage); } - - Debug::log(ERR, "X also failed loading theme \"{}\", falling back to previous theme.", name); - - m_pHyprcursor = std::make_unique(m_szTheme.c_str(), hcLogger); - - wlr_xcursor_manager_destroy(m_pWLRXCursorMgr); - m_pWLRXCursorMgr = wlr_xcursor_manager_create(m_szTheme.c_str(), m_iSize); - wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0); - - updateTheme(); - return false; } diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index 3ee98ca6..4324dfb4 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -6,47 +6,51 @@ #include "../includes.hpp" #include "../helpers/math/Math.hpp" #include "../helpers/memory/Memory.hpp" +#include "../macros.hpp" +#include -struct wlr_buffer; -struct wlr_xcursor_manager; class CWLSurface; +AQUAMARINE_FORWARD(IBuffer); + class CCursorManager { public: CCursorManager(); ~CCursorManager(); - wlr_buffer* getCursorBuffer(); + SP getCursorBuffer(); - void setCursorFromName(const std::string& name); - void setCursorSurface(SP surf, const Vector2D& hotspot); - void setXCursor(const std::string& name); + void setCursorFromName(const std::string& name); + void setCursorSurface(SP surf, const Vector2D& hotspot); + void setXCursor(const std::string& name); - bool changeTheme(const std::string& name, const int size); - void updateTheme(); - SCursorImageData dataFor(const std::string& name); // for xwayland - void setXWaylandCursor(); + bool changeTheme(const std::string& name, const int size); + void updateTheme(); + SCursorImageData dataFor(const std::string& name); // for xwayland + void setXWaylandCursor(); - void tickAnimatedCursor(); + void tickAnimatedCursor(); - class CCursorBuffer { + class CCursorBuffer : public Aquamarine::IBuffer { public: CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot); CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot); ~CCursorBuffer(); - struct SCursorWlrBuffer { - wlr_buffer base; - cairo_surface_t* surface = nullptr; - bool dropped = false; - CCursorBuffer* parent = nullptr; - uint8_t* pixelData = nullptr; - size_t stride = 0; - } wlrBuffer; + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); + virtual void update(const Hyprutils::Math::CRegion& damage); + virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu + virtual bool good(); + virtual Aquamarine::SSHMAttrs shm(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); private: - Vector2D size; - Vector2D hotspot; + Vector2D hotspot; + cairo_surface_t* surface = nullptr; + uint8_t* pixelData = nullptr; + size_t stride = 0; friend class CCursorManager; }; @@ -56,7 +60,7 @@ class CCursorManager { bool m_bOurBufferConnected = false; private: - std::vector> m_vCursorBuffers; + std::vector> m_vCursorBuffers; std::unique_ptr m_pHyprcursor; @@ -70,8 +74,24 @@ class CCursorManager { int m_iCurrentAnimationFrame = 0; Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData; - // xcursor fallback - wlr_xcursor_manager* m_pWLRXCursorMgr = nullptr; + // gangsta bootleg XCursor impl. Whenever Hyprland has to use + // an xcursor, just use the pointer. + struct SXCursor { + Vector2D size; + Vector2D hotspot; + std::vector pixels; // XPixel is a u32 + }; + + struct SXCursorManager { + void loadTheme(const std::string& name, int size); + + int lastLoadSize = 0; + + bool themeLoaded = false; + std::string themeName = ""; + SP defaultCursor; + std::unordered_map> cursors; + } xcursor; }; inline std::unique_ptr g_pCursorManager; \ No newline at end of file diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index eb8a3232..e9dfd1ae 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -4,10 +4,12 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/ShortcutsInhibit.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" +#include "../devices/IKeyboard.hpp" #include "KeybindManager.hpp" #include "PointerManager.hpp" #include "Compositor.hpp" #include "TokenManager.hpp" +#include "eventLoop/EventLoopManager.hpp" #include "debug/Log.hpp" #include "helpers/varlist/VarList.hpp" @@ -15,6 +17,7 @@ #include #include #include +#include #include using namespace Hyprutils::String; @@ -157,37 +160,37 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) { uint32_t modMask = 0; std::transform(mods.begin(), mods.end(), mods.begin(), ::toupper); if (mods.contains("SHIFT")) - modMask |= WLR_MODIFIER_SHIFT; + modMask |= HL_MODIFIER_SHIFT; if (mods.contains("CAPS")) - modMask |= WLR_MODIFIER_CAPS; + modMask |= HL_MODIFIER_CAPS; if (mods.contains("CTRL") || mods.contains("CONTROL")) - modMask |= WLR_MODIFIER_CTRL; + modMask |= HL_MODIFIER_CTRL; if (mods.contains("ALT") || mods.contains("MOD1")) - modMask |= WLR_MODIFIER_ALT; + modMask |= HL_MODIFIER_ALT; if (mods.contains("MOD2")) - modMask |= WLR_MODIFIER_MOD2; + modMask |= HL_MODIFIER_MOD2; if (mods.contains("MOD3")) - modMask |= WLR_MODIFIER_MOD3; - if (mods.contains("SUPER") || mods.contains("WIN") || mods.contains("LOGO") || mods.contains("MOD4")) - modMask |= WLR_MODIFIER_LOGO; + modMask |= HL_MODIFIER_MOD3; + if (mods.contains("SUPER") || mods.contains("WIN") || mods.contains("LOGO") || mods.contains("MOD4") || mods.contains("META")) + modMask |= HL_MODIFIER_META; if (mods.contains("MOD5")) - modMask |= WLR_MODIFIER_MOD5; + modMask |= HL_MODIFIER_MOD5; return modMask; } uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) { switch (keycode - 8) { - case KEY_LEFTMETA: return WLR_MODIFIER_LOGO; - case KEY_RIGHTMETA: return WLR_MODIFIER_LOGO; - case KEY_LEFTSHIFT: return WLR_MODIFIER_SHIFT; - case KEY_RIGHTSHIFT: return WLR_MODIFIER_SHIFT; - case KEY_LEFTCTRL: return WLR_MODIFIER_CTRL; - case KEY_RIGHTCTRL: return WLR_MODIFIER_CTRL; - case KEY_LEFTALT: return WLR_MODIFIER_ALT; - case KEY_RIGHTALT: return WLR_MODIFIER_ALT; - case KEY_CAPSLOCK: return WLR_MODIFIER_CAPS; - case KEY_NUMLOCK: return WLR_MODIFIER_MOD2; + case KEY_LEFTMETA: return HL_MODIFIER_META; + case KEY_RIGHTMETA: return HL_MODIFIER_META; + case KEY_LEFTSHIFT: return HL_MODIFIER_SHIFT; + case KEY_RIGHTSHIFT: return HL_MODIFIER_SHIFT; + case KEY_LEFTCTRL: return HL_MODIFIER_CTRL; + case KEY_RIGHTCTRL: return HL_MODIFIER_CTRL; + case KEY_LEFTALT: return HL_MODIFIER_ALT; + case KEY_RIGHTALT: return HL_MODIFIER_ALT; + case KEY_CAPSLOCK: return HL_MODIFIER_CAPS; + case KEY_NUMLOCK: return HL_MODIFIER_MOD2; default: return 0; } } @@ -366,8 +369,8 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput - const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbTranslationState : m_pXKBTranslationState, KEYCODE); - const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->wlr()->xkb_state, KEYCODE); + const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbStaticState : m_pXKBTranslationState, KEYCODE); + const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); if (handleInternalKeybinds(internalKeysym)) return true; @@ -554,7 +557,7 @@ int repeatKeyHandler(void* data) { Debug::log(LOG, "Keybind repeat triggered, calling dispatcher."); DISPATCHER->second((*ppActiveKeybind)->arg); - wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->wlr()->repeat_info.rate); + wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->repeatRate); return 0; } @@ -786,7 +789,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { // beyond this point, return true to not handle anything else. // we'll avoid printing shit to active windows. - if (g_pCompositor->m_sWLRSession) { + if (g_pCompositor->m_pAqBackend->hasSession()) { const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; // vtnr is bugged for some reason. @@ -810,8 +813,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { Debug::log(LOG, "Switching from VT {} to VT {}", ttynum, TTY); - wlr_session_change_vt(g_pCompositor->m_sWLRSession, TTY); - return true; + g_pCompositor->m_pAqBackend->session->switchVT(TTY); } return true; @@ -893,6 +895,7 @@ uint64_t CKeybindManager::spawnRaw(std::string args) { for (auto& e : HLENV) { setenv(e.first.c_str(), e.second.c_str(), 1); } + setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); close(socket[0]); close(socket[1]); execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); @@ -1659,7 +1662,7 @@ void CKeybindManager::renameWorkspace(std::string args) { } void CKeybindManager::exitHyprland(std::string argz) { - g_pCompositor->m_bExitTriggered = true; + g_pEventLoopManager->doLater([]() { g_pCompositor->cleanup(); }); } void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { @@ -2121,8 +2124,8 @@ void CKeybindManager::sendshortcut(std::string args) { const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY); if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) { - xkb_keymap* km = KB->wlr()->keymap; - xkb_state* ks = KB->xkbTranslationState; + xkb_keymap* km = KB->xkbKeymap; + xkb_state* ks = KB->xkbState; xkb_keycode_t keycode_min, keycode_max; keycode_min = xkb_keymap_min_keycode(km); @@ -2259,7 +2262,7 @@ void CKeybindManager::dpms(std::string arg) { if (!port.empty() && m->szName != port) continue; - wlr_output_state_set_enabled(m->state.wlr(), enable); + m->output->state->setEnabled(enable); m->dpmsStatus = enable; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 2a256760..284280cd 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -6,6 +6,7 @@ #include "../Compositor.hpp" #include #include +#include #include "../devices/IPointer.hpp" class CInputManager; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 7090645f..cf10db71 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -6,133 +6,8 @@ #include "../protocols/core/Compositor.hpp" #include "eventLoop/EventLoopManager.hpp" #include "SeatManager.hpp" -#include -#include -#include - -// TODO: make nicer -// this will come with the eventual rewrite of wlr_drm, etc... -static bool wlr_drm_format_intersect(wlr_drm_format* dst, const wlr_drm_format* a, const wlr_drm_format* b) { - ASSERT(a->format == b->format); - - size_t capacity = a->len < b->len ? a->len : b->len; - uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * capacity); - if (!modifiers) - return false; - - struct wlr_drm_format fmt = { - .format = a->format, - .len = 0, - .capacity = capacity, - .modifiers = modifiers, - }; - - for (size_t i = 0; i < a->len; i++) { - for (size_t j = 0; j < b->len; j++) { - if (a->modifiers[i] == b->modifiers[j]) { - ASSERT(fmt.len < fmt.capacity); - fmt.modifiers[fmt.len++] = a->modifiers[i]; - break; - } - } - } - - wlr_drm_format_finish(dst); - *dst = fmt; - return true; -} - -static bool wlr_drm_format_copy(wlr_drm_format* dst, const wlr_drm_format* src) { - ASSERT(src->len <= src->capacity); - - uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * src->len); - if (!modifiers) - return false; - - memcpy(modifiers, src->modifiers, sizeof(*modifiers) * src->len); - - wlr_drm_format_finish(dst); - dst->capacity = src->len; - dst->len = src->len; - dst->format = src->format; - dst->modifiers = modifiers; - return true; -} - -static const wlr_drm_format_set* wlr_renderer_get_render_formats(wlr_renderer* r) { - if (!r->impl->get_render_formats) - return nullptr; - - return r->impl->get_render_formats(r); -} - -static bool output_pick_format(wlr_output* output, const wlr_drm_format_set* display_formats, wlr_drm_format* format, uint32_t fmt) { - - const wlr_drm_format_set* render_formats = wlr_renderer_get_render_formats(g_pCompositor->m_sWLRRenderer); - if (render_formats == NULL) { - wlr_log(WLR_ERROR, "Failed to get render formats"); - return false; - } - - const wlr_drm_format* render_format = wlr_drm_format_set_get(render_formats, fmt); - if (render_format == NULL) { - wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%" PRIX32, fmt); - return false; - } - - if (display_formats != NULL) { - const wlr_drm_format* display_format = wlr_drm_format_set_get(display_formats, fmt); - if (display_format == NULL) { - wlr_log(WLR_DEBUG, "Output doesn't support format 0x%" PRIX32, fmt); - return false; - } - if (!wlr_drm_format_intersect(format, display_format, render_format)) { - wlr_log(WLR_DEBUG, - "Failed to intersect display and render " - "modifiers for format 0x%" PRIX32 " on output %s", - fmt, output->name); - return false; - } - } else { - // The output can display any format - if (!wlr_drm_format_copy(format, render_format)) - return false; - } - - if (format->len == 0) { - wlr_drm_format_finish(format); - wlr_log(WLR_DEBUG, "Failed to pick output format"); - return false; - } - - return true; -} - -static bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_format* format) { - struct wlr_allocator* allocator = output->allocator; - ASSERT(allocator != NULL); - - const struct wlr_drm_format_set* display_formats = NULL; - if (output->impl->get_cursor_formats) { - display_formats = output->impl->get_cursor_formats(output, allocator->buffer_caps); - if (display_formats == NULL) { - wlr_log(WLR_DEBUG, "Failed to get cursor display formats"); - return false; - } - } - - // Note: taken from https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4596/diffs#diff-content-e3ea164da86650995728d70bd118f6aa8c386797 - // If this fails to find a shared modifier try to use a linear - // modifier. This avoids a scenario where the hardware cannot render to - // linear textures but only linear textures are supported for cursors, - // as is the case with Nvidia and VmWare GPUs - if (!output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888)) { - // Clear the format as output_pick_format doesn't zero it - memset(format, 0, sizeof(*format)); - return output_pick_format(output, NULL, format, DRM_FORMAT_ARGB8888); - } - return true; -} +#include +#include CPointerManager::CPointerManager() { hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) { @@ -201,6 +76,11 @@ void CPointerManager::unlockSoftwareForMonitor(SP mon) { updateCursorBackend(); } +bool CPointerManager::softwareLockedFor(SP mon) { + auto state = stateFor(mon); + return state->softwareLocks > 0 || state->hardwareFailed; +} + Vector2D CPointerManager::position() { return pointerPos; } @@ -216,7 +96,7 @@ SP CPointerManager::stateFor(SP return *it; } -void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale) { +void CPointerManager::setCursorBuffer(SP buf, const Vector2D& hotspot, const float& scale) { damageIfSoftware(); if (buf == currentCursorImage.pBuffer) { if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) { @@ -232,10 +112,8 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, resetCursorImage(false); if (buf) { - currentCursorImage.size = {buf->width, buf->height}; - currentCursorImage.pBuffer = wlr_buffer_lock(buf); - - currentCursorImage.hyprListener_destroyBuffer.initCallback(&buf->events.destroy, [this](void* owner, void* data) { resetCursorImage(); }, this, "CPointerManager"); + currentCursorImage.size = buf->size; + currentCursorImage.pBuffer = buf; } currentCursorImage.hotspot = hotspot; @@ -317,8 +195,8 @@ void CPointerManager::recheckEnteredOutputs() { // if we are using hw cursors, prevent // the cursor from being stuck at the last point. // if we are leaving it, move it to narnia. - if (!s->hardwareFailed && s->monitor->output->impl->move_cursor) - s->monitor->output->impl->move_cursor(s->monitor->output, -1337, -420); + if (!s->hardwareFailed && (s->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)) + s->monitor->output->moveCursor({-1337, -420}); if (!currentCursorImage.surface) continue; @@ -339,16 +217,11 @@ void CPointerManager::resetCursorImage(bool apply) { currentCursorImage.destroySurface.reset(); currentCursorImage.commitSurface.reset(); currentCursorImage.surface.reset(); - } else if (currentCursorImage.pBuffer) { - wlr_buffer_unlock(currentCursorImage.pBuffer); - currentCursorImage.hyprListener_destroyBuffer.removeCallback(); + } else if (currentCursorImage.pBuffer) currentCursorImage.pBuffer = nullptr; - } - if (currentCursorImage.pBufferTexture) { - wlr_texture_destroy(currentCursorImage.pBufferTexture); - currentCursorImage.pBufferTexture = nullptr; - } + if (currentCursorImage.bufferTex) + currentCursorImage.bufferTex = nullptr; currentCursorImage.scale = 1.F; currentCursorImage.hotspot = {0, 0}; @@ -370,9 +243,8 @@ void CPointerManager::resetCursorImage(bool apply) { } if (ms->cursorFrontBuffer) { - if (ms->monitor->output->impl->set_cursor) - ms->monitor->output->impl->set_cursor(ms->monitor->output, nullptr, 0, 0); - wlr_buffer_unlock(ms->cursorFrontBuffer); + if (ms->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER) + ms->monitor->output->setCursor(nullptr, {}); ms->cursorFrontBuffer = nullptr; } } @@ -418,18 +290,18 @@ void CPointerManager::onCursorMoved() { continue; const auto CURSORPOS = getCursorPosForMonitor(m); - m->output->impl->move_cursor(m->output, CURSORPOS.x, CURSORPOS.y); + m->output->moveCursor(CURSORPOS); } } bool CPointerManager::attemptHardwareCursor(SP state) { auto output = state->monitor->output; - if (!output->impl->set_cursor) + if (!(output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)) return false; const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock()); - state->monitor->output->impl->move_cursor(state->monitor->output, CURSORPOS.x, CURSORPOS.y); + state->monitor->output->moveCursor(CURSORPOS); auto texture = getCurrentCursorTexture(); @@ -459,64 +331,62 @@ bool CPointerManager::attemptHardwareCursor(SP state, wlr_buffer* buf) { - if (!state->monitor->output->impl->set_cursor) +bool CPointerManager::setHWCursorBuffer(SP state, SP buf) { + if (!(state->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)) return false; const auto HOTSPOT = transformedHotspot(state->monitor.lock()); Debug::log(TRACE, "[pointer] hw transformed hotspot for {}: {}", state->monitor->szName, HOTSPOT); - if (!state->monitor->output->impl->set_cursor(state->monitor->output, buf, HOTSPOT.x, HOTSPOT.y)) + if (!state->monitor->output->setCursor(buf, HOTSPOT)) return false; - wlr_buffer_unlock(state->cursorFrontBuffer); state->cursorFrontBuffer = buf; - g_pCompositor->scheduleFrameForMonitor(state->monitor.get()); - - if (buf) - wlr_buffer_lock(buf); + g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); return true; } -wlr_buffer* CPointerManager::renderHWCursorBuffer(SP state, SP texture) { +SP CPointerManager::renderHWCursorBuffer(SP state, SP texture) { auto output = state->monitor->output; - int w = currentCursorImage.size.x, h = currentCursorImage.size.y; - if (output->impl->get_cursor_size) { - output->impl->get_cursor_size(output, &w, &h); + auto maxSize = output->cursorPlaneSize(); + auto cursorSize = currentCursorImage.size; - if (w < currentCursorImage.size.x || h < currentCursorImage.size.y) { - Debug::log(TRACE, "hardware cursor too big! {} > {}x{}", currentCursorImage.size, w, h); - return nullptr; - } - } - - if (w <= 0 || h <= 0) { - Debug::log(TRACE, "hw cursor for output {} failed the size checks ({}x{} is invalid)", state->monitor->szName, w, h); + if (maxSize == Vector2D{}) return nullptr; - } - if (!output->cursor_swapchain || Vector2D{w, h} != Vector2D{output->cursor_swapchain->width, output->cursor_swapchain->height}) { - wlr_drm_format fmt = {0}; - if (!output_pick_cursor_format(output, &fmt)) { - Debug::log(TRACE, "Failed to pick cursor format"); + if (maxSize != Vector2D{-1, -1}) { + if (cursorSize.x > maxSize.x || cursorSize.y > maxSize.y) { + Debug::log(TRACE, "hardware cursor too big! {} > {}", currentCursorImage.size, maxSize); return nullptr; } + } else + maxSize = cursorSize; - wlr_swapchain_destroy(output->cursor_swapchain); - output->cursor_swapchain = wlr_swapchain_create(output->allocator, w, h, &fmt); - wlr_drm_format_finish(&fmt); + if (!state->monitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size) { - if (!output->cursor_swapchain) { - Debug::log(TRACE, "Failed to create cursor swapchain"); + if (!state->monitor->cursorSwapchain) + state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(state->monitor->output->getBackend()->preferredAllocator(), state->monitor->output->getBackend()); + + auto options = state->monitor->cursorSwapchain->currentOptions(); + options.size = maxSize; + options.length = 2; + options.scanout = true; + options.cursor = true; + options.multigpu = state->monitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; + // We do not set the format. If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, + // but if it's set, we don't wanna change it. + + if (!state->monitor->cursorSwapchain->reconfigure(options)) { + Debug::log(TRACE, "Failed to reconfigure cursor swapchain"); return nullptr; } } - wlr_buffer* buf = wlr_swapchain_acquire(output->cursor_swapchain, nullptr); + auto buf = state->monitor->cursorSwapchain->next(nullptr); if (!buf) { Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain"); return nullptr; @@ -525,16 +395,45 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SPmakeEGLCurrent(); - g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); // has to be set cuz allocs + g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); + + auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); + if (!RBO) { + Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", buf->dmabuf().format, buf->dmabuf().modifier); + static auto PDUMB = CConfigValue("cursor:allow_dumb_copy"); + if (!*PDUMB) + return nullptr; + + auto bufData = buf->beginDataPtr(0); + auto bufPtr = std::get<0>(bufData); + + // clear buffer + memset(bufPtr, 0, std::get<2>(bufData)); + + auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer; + + if (texBuffer) { + auto textAttrs = texBuffer->shm(); + auto texData = texBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE); + auto texPtr = std::get<0>(texData); + Debug::log(TRACE, "cursor texture {}x{} {} {} {}", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, textAttrs.stride); + // copy cursor texture + for (int i = 0; i < texBuffer->shm().size.y; i++) + memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * textAttrs.stride, textAttrs.stride); + } + + buf->endDataPtr(); + + return buf; + } - const auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, DRM_FORMAT_ARGB8888); RBO->bind(); g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO); g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F}); CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()}; - Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, Vector2D{w, h}, + Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, cursorSize, currentCursorImage.scale, state->monitor->scale, xbox.size()); g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F); @@ -543,9 +442,7 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SPm_RenderData.pMonitor = nullptr; - g_pHyprRenderer->onRenderbufferDestroy(RBO); - - wlr_buffer_unlock(buf); + g_pHyprRenderer->onRenderbufferDestroy(RBO.get()); return buf; } @@ -579,7 +476,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* box.x = std::round(box.x); box.y = std::round(box.y); - g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F); + g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F, 0, false, false, currentCursorImage.waitTimeline, currentCursorImage.waitPoint); if (currentCursorImage.surface) currentCursorImage.surface->resource()->frame(now); @@ -587,17 +484,19 @@ void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* Vector2D CPointerManager::getCursorPosForMonitor(SP pMonitor) { return CBox{pointerPos - pMonitor->vecPosition, {0, 0}} - //.transform(pMonitor->transform, pMonitor->vecTransformedSize.x / pMonitor->scale, pMonitor->vecTransformedSize.y / pMonitor->scale) + .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x / pMonitor->scale, + pMonitor->vecTransformedSize.y / pMonitor->scale) .pos() * pMonitor->scale; } Vector2D CPointerManager::transformedHotspot(SP pMonitor) { - if (!pMonitor->output->cursor_swapchain) + if (!pMonitor->cursorSwapchain) return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors return CBox{currentCursorImage.hotspot * pMonitor->scale, {0, 0}} - .transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->transform)), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height) + .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->cursorSwapchain->currentOptions().size.x, + pMonitor->cursorSwapchain->currentOptions().size.y) .pos(); } @@ -799,10 +698,8 @@ SP CPointerManager::getCurrentCursorTexture() { return nullptr; if (currentCursorImage.pBuffer) { - if (!currentCursorImage.pBufferTexture) { - currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer); - currentCursorImage.bufferTex = makeShared(currentCursorImage.pBufferTexture); - } + if (!currentCursorImage.bufferTex) + currentCursorImage.bufferTex = makeShared(currentCursorImage.pBuffer); return currentCursorImage.bufferTex; } diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index da639340..cf4f1a94 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -6,13 +6,15 @@ #include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp" #include "../desktop/WLSurface.hpp" +#include "../helpers/sync/SyncTimeline.hpp" #include class CMonitor; -struct wlr_input_device; class IHID; class CTexture; +AQUAMARINE_FORWARD(IBuffer); + /* The naming here is a bit confusing. CPointerManager manages the _position_ and _displaying_ of the cursor, @@ -37,7 +39,7 @@ class CPointerManager { void move(const Vector2D& deltaLogical); void warpAbsolute(Vector2D abs, SP dev); - void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale); + void setCursorBuffer(SP buf, const Vector2D& hotspot, const float& scale); void setCursorSurface(SP buf, const Vector2D& hotspot); void resetCursorImage(bool apply = true); @@ -47,6 +49,7 @@ class CPointerManager { void unlockSoftwareForMonitor(CMonitor* pMonitor); void lockSoftwareAll(); void unlockSoftwareAll(); + bool softwareLockedFor(SP pMonitor); void renderSoftwareCursorsFor(SP pMonitor, timespec* now, CRegion& damage /* logical */, std::optional overridePos = {} /* monitor-local */); @@ -135,45 +138,42 @@ class CPointerManager { } currentMonitorLayout; struct { - wlr_buffer* pBuffer = nullptr; - SP bufferTex; - WP surface; - wlr_texture* pBufferTexture = nullptr; + SP pBuffer; + SP bufferTex; + WP surface; - Vector2D hotspot; - Vector2D size; - float scale = 1.F; + Vector2D hotspot; + Vector2D size; + float scale = 1.F; - CHyprSignalListener destroySurface; - CHyprSignalListener commitSurface; - DYNLISTENER(destroyBuffer); + CHyprSignalListener destroySurface; + CHyprSignalListener commitSurface; + SP waitTimeline = nullptr; + uint64_t waitPoint = 0; } currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors Vector2D pointerPos = {0, 0}; struct SMonitorPointerState { SMonitorPointerState(SP m) : monitor(m) {} - ~SMonitorPointerState() { - if (cursorFrontBuffer) - wlr_buffer_unlock(cursorFrontBuffer); - } + ~SMonitorPointerState() {} - WP monitor; + WP monitor; - int softwareLocks = 0; - bool hardwareFailed = false; - CBox box; // logical - bool entered = false; - bool hwApplied = false; + int softwareLocks = 0; + bool hardwareFailed = false; + CBox box; // logical + bool entered = false; + bool hwApplied = false; - wlr_buffer* cursorFrontBuffer = nullptr; + SP cursorFrontBuffer; }; std::vector> monitorStates; SP stateFor(SP mon); bool attemptHardwareCursor(SP state); - wlr_buffer* renderHWCursorBuffer(SP state, SP texture); - bool setHWCursorBuffer(SP state, wlr_buffer* buf); + SP renderHWCursorBuffer(SP state, SP texture); + bool setHWCursorBuffer(SP state, SP buf); struct { SP monitorAdded; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 74cebd0c..387cac8f 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -1,5 +1,7 @@ #include "ProtocolManager.hpp" +#include "../config/ConfigValue.hpp" + #include "../protocols/TearingControl.hpp" #include "../protocols/FractionalScale.hpp" #include "../protocols/XDGOutput.hpp" @@ -35,6 +37,8 @@ #include "../protocols/Viewporter.hpp" #include "../protocols/MesaDRM.hpp" #include "../protocols/LinuxDMABUF.hpp" +#include "../protocols/DRMLease.hpp" +#include "../protocols/DRMSyncobj.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -45,6 +49,10 @@ #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" +#include "../Compositor.hpp" + +#include +#include void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { const bool ISMIRROR = pMonitor->isMirror(); @@ -65,6 +73,8 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { CProtocolManager::CProtocolManager() { + static const auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + // Outputs are a bit dumb, we have to agree. static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { auto M = std::any_cast(param); @@ -131,6 +141,16 @@ CProtocolManager::CProtocolManager() { PROTO::primarySelection = std::make_unique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); PROTO::xwaylandShell = std::make_unique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); + for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { + if (b->type() != Aquamarine::AQ_BACKEND_DRM) + continue; + + PROTO::lease = std::make_unique(&wp_drm_lease_device_v1_interface, 1, "DRMLease"); + if (*PENABLEEXPLICIT) + PROTO::sync = std::make_unique(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj"); + break; + } + if (g_pHyprOpenGL->getDRMFormats().size() > 0) { PROTO::mesaDRM = std::make_unique(&wl_drm_interface, 2, "MesaDRM"); PROTO::linuxDma = std::make_unique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 6589c4bf..801ae55a 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -94,8 +94,8 @@ void CSeatManager::setKeyboard(SP KEEB) { } void CSeatManager::updateActiveKeyboardData() { - if (keyboard && keyboard->wlr()) - PROTO::seat->updateRepeatInfo(keyboard->wlr()->repeat_info.rate, keyboard->wlr()->repeat_info.delay); + if (keyboard) + PROTO::seat->updateRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay); PROTO::seat->updateKeymap(); } @@ -103,7 +103,7 @@ void CSeatManager::setKeyboardFocus(SP surf) { if (state.keyboardFocus == surf) return; - if (!keyboard || !keyboard->wlr()) { + if (!keyboard) { Debug::log(ERR, "BUG THIS: setKeyboardFocus without a valid keyboard set"); return; } @@ -144,7 +144,7 @@ void CSeatManager::setKeyboardFocus(SP surf) { continue; k->sendEnter(surf); - k->sendMods(keyboard->wlr()->modifiers.depressed, keyboard->wlr()->modifiers.latched, keyboard->wlr()->modifiers.locked, keyboard->wlr()->modifiers.group); + k->sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group); } } @@ -196,7 +196,7 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& return; } - if (!mouse || !mouse->wlr()) { + if (!mouse) { Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set"); return; } diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 0d1b0223..ed7a4f72 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -1,5 +1,6 @@ #include "EventLoopManager.hpp" #include "../../debug/Log.hpp" +#include "../../Compositor.hpp" #include #include @@ -7,6 +8,8 @@ #include #include +#include + #define TIMESPEC_NSEC_PER_SEC 1000000000L CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) { @@ -25,9 +28,21 @@ static int timerWrite(int fd, uint32_t mask, void* data) { return 1; } +static int aquamarineFDWrite(int fd, uint32_t mask, void* data) { + auto POLLFD = (Aquamarine::SPollFD*)data; + POLLFD->onSignal(); + return 1; +} + void CEventLoopManager::enterLoop() { m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); + aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); + for (auto& fd : aqPollFDs) { + m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); + fd->onSignal(); // dispatch outstanding + } + wl_display_run(m_sWayland.display); Debug::log(LOG, "Kicked off the event loop! :("); diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 0b2f9578..39d8bbeb 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -7,6 +7,10 @@ #include "EventLoopTimer.hpp" +namespace Aquamarine { + struct SPollFD; +}; + class CEventLoopManager { public: CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop); @@ -33,9 +37,10 @@ class CEventLoopManager { private: struct { - wl_event_loop* loop = nullptr; - wl_display* display = nullptr; - wl_event_source* eventSource = nullptr; + wl_event_loop* loop = nullptr; + wl_display* display = nullptr; + wl_event_source* eventSource = nullptr; + std::vector aqEventSources; } m_sWayland; struct { @@ -43,7 +48,10 @@ class CEventLoopManager { int timerfd = -1; } m_sTimers; - SIdleData m_sIdle; + SIdleData m_sIdle; + std::vector> aqPollFDs; + + friend class CSyncTimeline; }; inline std::unique_ptr g_pEventLoopManager; \ No newline at end of file diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 23e183d0..255023b9 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1,6 +1,6 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" -#include "wlr/types/wlr_switch.h" +#include #include #include #include "../../config/ConfigValue.hpp" @@ -28,6 +28,8 @@ #include "../../managers/PointerManager.hpp" #include "../../managers/SeatManager.hpp" +#include + CInputManager::CInputManager() { m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) { if (!cursorImageUnlocked()) @@ -189,8 +191,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { bool skipFrameSchedule = PMONITOR->shouldSkipScheduleFrameOnMouseEvent(); - if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0 && !skipFrameSchedule) - g_pCompositor->scheduleFrameForMonitor(PMONITOR); + if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) && !skipFrameSchedule) + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); PHLWINDOW forcedFocus = m_pForcedFocus.lock(); @@ -372,8 +374,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface); - if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0 && !skipFrameSchedule) - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get()); + if (g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) > 0 && !skipFrameSchedule) + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); // grabs if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(foundSurface)) { @@ -843,8 +845,8 @@ Vector2D CInputManager::getMouseCoordsInternal() { return g_pPointerManager->position(); } -void CInputManager::newKeyboard(wlr_input_device* keyboard) { - const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(wlr_keyboard_from_input_device(keyboard))); +void CInputManager::newKeyboard(SP keyboard) { + const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(keyboard)); setupKeyboard(PNEWKEYBOARD); @@ -856,14 +858,14 @@ void CInputManager::newVirtualKeyboard(SP keyboard) setupKeyboard(PNEWKEYBOARD); - Debug::log(LOG, "New virtual keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard->wlr()); + Debug::log(LOG, "New virtual keyboard created at {:x}", (uintptr_t)PNEWKEYBOARD.get()); } void CInputManager::setupKeyboard(SP keeb) { m_vHIDs.push_back(keeb); try { - keeb->hlName = getNameForNewDevice(keeb->wlr()->base.name); + keeb->hlName = getNameForNewDevice(keeb->deviceName); } catch (std::exception& e) { Debug::log(ERR, "Keyboard had no name???"); // logic error } @@ -962,83 +964,12 @@ void CInputManager::applyConfigToKeyboard(SP pKeyboard) { // we can ignore those and just apply } - wlr_keyboard_set_repeat_info(pKeyboard->wlr(), std::max(0, REPEATRATE), std::max(0, REPEATDELAY)); - - pKeyboard->repeatDelay = REPEATDELAY; - pKeyboard->repeatRate = REPEATRATE; + pKeyboard->repeatRate = std::max(0, REPEATRATE); + pKeyboard->repeatDelay = std::max(0, REPEATDELAY); pKeyboard->numlockOn = NUMLOCKON; pKeyboard->xkbFilePath = FILEPATH; - xkb_rule_names rules = {.rules = RULES.c_str(), .model = MODEL.c_str(), .layout = LAYOUT.c_str(), .variant = VARIANT.c_str(), .options = OPTIONS.c_str()}; - - pKeyboard->currentRules.rules = RULES; - pKeyboard->currentRules.model = MODEL; - pKeyboard->currentRules.variant = VARIANT; - pKeyboard->currentRules.options = OPTIONS; - pKeyboard->currentRules.layout = LAYOUT; - - const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - if (!CONTEXT) { - Debug::log(ERR, "applyConfigToKeyboard: CONTEXT null??"); - return; - } - - Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model, - rules.options); - - xkb_keymap* KEYMAP = NULL; - - if (!FILEPATH.empty()) { - auto path = absolutePath(FILEPATH, g_pConfigManager->configCurrentPath); - - if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE) - Debug::log(ERR, "Cannot open input:kb_file= file for reading"); - else { - KEYMAP = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - fclose(KEYMAPFILE); - } - } - - if (!KEYMAP) - KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - - if (!KEYMAP) { - g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS + - ", layout: " + LAYOUT + " )"); - - Debug::log(ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, - rules.options); - memset(&rules, 0, sizeof(rules)); - - pKeyboard->currentRules.rules = ""; - pKeyboard->currentRules.model = ""; - pKeyboard->currentRules.variant = ""; - pKeyboard->currentRules.options = ""; - pKeyboard->currentRules.layout = "us"; - - KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - } - - wlr_keyboard_set_keymap(pKeyboard->wlr(), KEYMAP); - - pKeyboard->updateXKBTranslationState(); - - wlr_keyboard_modifiers wlrMods = {0}; - - if (NUMLOCKON == 1) { - // lock numlock - const auto IDX = xkb_map_mod_get_index(KEYMAP, XKB_MOD_NAME_NUM); - - if (IDX != XKB_MOD_INVALID) - wlrMods.locked |= (uint32_t)1 << IDX; - } - - if (wlrMods.locked != 0) - wlr_keyboard_notify_modifiers(pKeyboard->wlr(), 0, 0, wlrMods.locked, 0); - - xkb_keymap_unref(KEYMAP); - xkb_context_unref(CONTEXT); + pKeyboard->setKeymap(IKeyboard::SStringRuleNames{LAYOUT, MODEL, VARIANT, OPTIONS, RULES}); const auto LAYOUTSTR = pKeyboard->getActiveLayout(); @@ -1053,11 +984,11 @@ void CInputManager::newVirtualMouse(SP mouse) { setupMouse(PMOUSE); - Debug::log(LOG, "New virtual mouse created, pointer WLR: {:x}", (uintptr_t)mouse->wlr()); + Debug::log(LOG, "New virtual mouse created"); } -void CInputManager::newMouse(wlr_input_device* mouse) { - const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(wlr_pointer_from_input_device(mouse))); +void CInputManager::newMouse(SP mouse) { + const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(mouse)); setupMouse(PMOUSE); @@ -1068,13 +999,13 @@ void CInputManager::setupMouse(SP mauz) { m_vHIDs.push_back(mauz); try { - mauz->hlName = getNameForNewDevice(mauz->wlr()->base.name); + mauz->hlName = getNameForNewDevice(mauz->deviceName); } catch (std::exception& e) { Debug::log(ERR, "Mouse had no name???"); // logic error } - if (wlr_input_device_is_libinput(&mauz->wlr()->base)) { - const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&mauz->wlr()->base); + if (mauz->aq() && mauz->aq()->getLibinputHandle()) { + const auto LIBINPUTDEV = mauz->aq()->getLibinputHandle(); Debug::log(LOG, "New mouse has libinput sens {:.2f} ({:.2f}) with accel profile {} ({})", libinput_device_config_accel_get_speed(LIBINPUTDEV), libinput_device_config_accel_get_default_speed(LIBINPUTDEV), (int)libinput_device_config_accel_get_profile(LIBINPUTDEV), @@ -1120,8 +1051,8 @@ void CInputManager::setPointerConfigs() { } } - if (wlr_input_device_is_libinput(&m->wlr()->base)) { - const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base); + if (m->aq() && m->aq()->getLibinputHandle()) { + const auto LIBINPUTDEV = m->aq()->getLibinputHandle(); double touchw = 0, touchh = 0; const auto ISTOUCHPAD = libinput_device_has_capability(LIBINPUTDEV, LIBINPUT_DEVICE_CAP_POINTER) && @@ -1261,16 +1192,14 @@ static void removeFromHIDs(WP hid) { } void CInputManager::destroyKeyboard(SP pKeyboard) { - if (pKeyboard->xkbTranslationState) - xkb_state_unref(pKeyboard->xkbTranslationState); - pKeyboard->xkbTranslationState = nullptr; + Debug::log(LOG, "Keyboard at {:x} removed", (uintptr_t)pKeyboard.get()); std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; }); if (m_vKeyboards.size() > 0) { bool found = false; for (auto& k : m_vKeyboards | std::views::reverse) { - if (!k->wlr()) + if (!k) continue; g_pSeatManager->setKeyboard(k); @@ -1287,6 +1216,8 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { } void CInputManager::destroyPointer(SP mouse) { + Debug::log(LOG, "Pointer at {:x} removed", (uintptr_t)mouse.get()); + std::erase_if(m_vPointers, [mouse](const auto& other) { return other == mouse; }); g_pSeatManager->setMouse(m_vPointers.size() > 0 ? m_vPointers.front() : nullptr); @@ -1333,20 +1264,7 @@ void CInputManager::updateKeyboardsLeds(SP pKeyboard) { if (!pKeyboard) return; - auto keyboard = pKeyboard->wlr(); - - if (!keyboard || keyboard->xkb_state == nullptr) - return; - - uint32_t leds = 0; - for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) { - if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i])) - leds |= (1 << i); - } - - for (auto& k : m_vKeyboards) { - k->updateLEDs(leds); - } + pKeyboard->updateLEDs(); } void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { @@ -1374,7 +1292,7 @@ void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { const auto IME = m_sIMERelay.m_pIME.lock(); if (IME && IME->hasGrab() && !DISALLOWACTION) { - IME->setKeyboard(pKeyboard->wlr()); + IME->setKeyboard(pKeyboard); IME->sendKey(e.timeMs, e.keycode, e.state); } else { g_pSeatManager->setKeyboard(pKeyboard); @@ -1392,15 +1310,14 @@ void CInputManager::onKeyboardMod(SP pKeyboard) { const bool DISALLOWACTION = pKeyboard->isVirtual() && shouldIgnoreVirtualKeyboard(pKeyboard); const auto ALLMODS = accumulateModsFromAllKBs(); - const auto PWLRKB = pKeyboard->wlr(); - auto MODS = PWLRKB->modifiers; + auto MODS = pKeyboard->modifiersState; MODS.depressed = ALLMODS; const auto IME = m_sIMERelay.m_pIME.lock(); if (IME && IME->hasGrab() && !DISALLOWACTION) { - IME->setKeyboard(PWLRKB); + IME->setKeyboard(pKeyboard); IME->sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); } else { g_pSeatManager->setKeyboard(pKeyboard); @@ -1409,12 +1326,12 @@ void CInputManager::onKeyboardMod(SP pKeyboard) { updateKeyboardsLeds(pKeyboard); - if (PWLRKB->modifiers.group != pKeyboard->activeLayout) { - pKeyboard->activeLayout = PWLRKB->modifiers.group; + if (pKeyboard->modifiersState.group != pKeyboard->activeLayout) { + pKeyboard->activeLayout = pKeyboard->modifiersState.group; const auto LAYOUT = pKeyboard->getActiveLayout(); - pKeyboard->updateXKBTranslationState(); + Debug::log(LOG, "LAYOUT CHANGED TO {} GROUP {}", LAYOUT, MODS.group); g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->hlName + "," + LAYOUT}); EMIT_HOOK_EVENT("activeLayout", (std::vector{pKeyboard, LAYOUT})); @@ -1524,10 +1441,10 @@ uint32_t CInputManager::accumulateModsFromAllKBs() { if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb)) continue; - if (!kb->enabled || !kb->wlr()) + if (!kb->enabled) continue; - finalMask |= wlr_keyboard_get_modifiers(kb->wlr()); + finalMask |= kb->getModifiers(); } return finalMask; @@ -1543,12 +1460,12 @@ void CInputManager::disableAllKeyboards(bool virt) { } } -void CInputManager::newTouchDevice(wlr_input_device* pDevice) { - const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(wlr_touch_from_input_device(pDevice))); +void CInputManager::newTouchDevice(SP pDevice) { + const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(pDevice)); m_vHIDs.push_back(PNEWDEV); try { - PNEWDEV->hlName = getNameForNewDevice(pDevice->name); + PNEWDEV->hlName = getNameForNewDevice(PNEWDEV->deviceName); } catch (std::exception& e) { Debug::log(ERR, "Touch Device had no name???"); // logic error } @@ -1572,8 +1489,8 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) { void CInputManager::setTouchDeviceConfigs(SP dev) { auto setConfig = [&](SP PTOUCHDEV) -> void { - if (wlr_input_device_is_libinput(&PTOUCHDEV->wlr()->base)) { - const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&PTOUCHDEV->wlr()->base); + if (dev->aq() && dev->aq()->getLibinputHandle()) { + const auto LIBINPUTDEV = dev->aq()->getLibinputHandle(); const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->hlName, "enabled", "input:touchdevice:enabled"); const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; @@ -1589,11 +1506,12 @@ void CInputManager::setTouchDeviceConfigs(SP dev) { bool bound = !output.empty() && output != STRVAL_EMPTY; const bool AUTODETECT = output == "[[Auto]]"; if (!bound && AUTODETECT) { - const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name; - if (DEFAULTOUTPUT) { - output = DEFAULTOUTPUT; - bound = true; - } + // FIXME: + // const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name; + // if (DEFAULTOUTPUT) { + // output = DEFAULTOUTPUT; + // bound = true; + // } } PTOUCHDEV->boundOutput = bound ? output : ""; const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr; @@ -1617,9 +1535,9 @@ void CInputManager::setTouchDeviceConfigs(SP dev) { void CInputManager::setTabletConfigs() { for (auto& t : m_vTablets) { - if (wlr_input_device_is_libinput(&t->wlr()->base)) { + if (t->aq()->getLibinputHandle()) { const auto NAME = t->hlName; - const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&t->wlr()->base); + const auto LIBINPUTDEV = t->aq()->getLibinputHandle(); const auto RELINPUT = g_pConfigManager->getDeviceInt(NAME, "relative_input", "input:tablet:relative_input"); t->relativeInput = RELINPUT; @@ -1647,51 +1565,37 @@ void CInputManager::setTabletConfigs() { const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(NAME, "active_area_size", "input:tablet:active_area_size"); const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(NAME, "active_area_position", "input:tablet:active_area_position"); if (ACTIVE_AREA_SIZE.x != 0 || ACTIVE_AREA_SIZE.y != 0) { - t->activeArea = CBox{ACTIVE_AREA_POS.x / t->wlr()->width_mm, ACTIVE_AREA_POS.y / t->wlr()->height_mm, (ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t->wlr()->width_mm, - (ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t->wlr()->height_mm}; + t->activeArea = CBox{ACTIVE_AREA_POS.x / t->aq()->physicalSize.x, ACTIVE_AREA_POS.y / t->aq()->physicalSize.y, + (ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t->aq()->physicalSize.x, (ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t->aq()->physicalSize.y}; } } } } -void CInputManager::newSwitch(wlr_input_device* pDevice) { - const auto PNEWDEV = &m_lSwitches.emplace_back(); - PNEWDEV->pWlrDevice = pDevice; +void CInputManager::newSwitch(SP pDevice) { + const auto PNEWDEV = &m_lSwitches.emplace_back(); + PNEWDEV->pDevice = pDevice; - Debug::log(LOG, "New switch with name \"{}\" added", pDevice->name); + Debug::log(LOG, "New switch with name \"{}\" added", pDevice->getName()); - PNEWDEV->hyprListener_destroy.initCallback(&pDevice->events.destroy, [&](void* owner, void* data) { destroySwitch((SSwitchDevice*)owner); }, PNEWDEV, "SwitchDevice"); + PNEWDEV->listeners.destroy = pDevice->events.destroy.registerListener([this, PNEWDEV](std::any d) { destroySwitch(PNEWDEV); }); - const auto PSWITCH = wlr_switch_from_input_device(pDevice); + PNEWDEV->listeners.fire = pDevice->events.fire.registerListener([PNEWDEV](std::any d) { + const auto NAME = PNEWDEV->pDevice->getName(); + const auto E = std::any_cast(d); - PNEWDEV->hyprListener_toggle.initCallback( - &PSWITCH->events.toggle, - [&](void* owner, void* data) { - const auto PDEVICE = (SSwitchDevice*)owner; - const auto NAME = std::string(PDEVICE->pWlrDevice->name); - const auto E = (wlr_switch_toggle_event*)data; + Debug::log(LOG, "Switch {} fired, triggering binds.", NAME); - if (PDEVICE->status != -1 && PDEVICE->status == E->switch_state) - return; + g_pKeybindManager->onSwitchEvent(NAME); - Debug::log(LOG, "Switch {} fired, triggering binds.", NAME); - - g_pKeybindManager->onSwitchEvent(NAME); - - switch (E->switch_state) { - case WLR_SWITCH_STATE_ON: - Debug::log(LOG, "Switch {} turn on, triggering binds.", NAME); - g_pKeybindManager->onSwitchOnEvent(NAME); - break; - case WLR_SWITCH_STATE_OFF: - Debug::log(LOG, "Switch {} turn off, triggering binds.", NAME); - g_pKeybindManager->onSwitchOffEvent(NAME); - break; - } - - PDEVICE->status = E->switch_state; - }, - PNEWDEV, "SwitchDevice"); + if (E.enable) { + Debug::log(LOG, "Switch {} turn on, triggering binds.", NAME); + g_pKeybindManager->onSwitchOnEvent(NAME); + } else { + Debug::log(LOG, "Switch {} turn off, triggering binds.", NAME); + g_pKeybindManager->onSwitchOffEvent(NAME); + } + }); } void CInputManager::destroySwitch(SSwitchDevice* pDevice) { diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 85ae6197..ebf00b2d 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -18,6 +18,14 @@ class CVirtualKeyboardV1Resource; class CVirtualPointerV1Resource; class IKeyboard; +AQUAMARINE_FORWARD(IPointer); +AQUAMARINE_FORWARD(IKeyboard); +AQUAMARINE_FORWARD(ITouch); +AQUAMARINE_FORWARD(ISwitch); +AQUAMARINE_FORWARD(ITablet); +AQUAMARINE_FORWARD(ITabletTool); +AQUAMARINE_FORWARD(ITabletPad); + enum eClickBehaviorMode { CLICKMODE_DEFAULT = 0, CLICKMODE_KILL @@ -82,15 +90,14 @@ class CInputManager { void onKeyboardKey(std::any, SP); void onKeyboardMod(SP); - void newKeyboard(wlr_input_device*); + void newKeyboard(SP); void newVirtualKeyboard(SP); - void newMouse(wlr_input_device*); + void newMouse(SP); void newVirtualMouse(SP); - void newTouchDevice(wlr_input_device*); - void newSwitch(wlr_input_device*); - void newTabletTool(wlr_tablet_tool*); - void newTabletPad(wlr_input_device*); - void newTablet(wlr_input_device*); + void newTouchDevice(SP); + void newSwitch(SP); + void newTabletPad(SP); + void newTablet(SP); void destroyTouchDevice(SP); void destroyKeyboard(SP); void destroyPointer(SP); @@ -232,7 +239,7 @@ class CInputManager { void mouseMoveUnified(uint32_t, bool refocus = false); - SP ensureTabletToolPresent(wlr_tablet_tool*); + SP ensureTabletToolPresent(SP); void applyConfigToKeyboard(SP); diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index f1157e4b..5e50e851 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -62,7 +62,7 @@ static void refocusTablet(SP tab, SP tool, bool motion = f if (!motion) return; - if (LASTHLSURFACE->constraint() && tool->wlr()->type != WLR_TABLET_TOOL_TYPE_MOUSE) { + if (LASTHLSURFACE->constraint() && tool->aq()->type != Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE) { // cursor logic will completely break here as the cursor will be locked. // let's just "map" the desired position to the constraint area. @@ -102,7 +102,7 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { Vector2D delta = {std::isnan(dx) ? 0.0 : dx, std::isnan(dy) ? 0.0 : dy}; switch (e.tool->type) { - case WLR_TABLET_TOOL_TYPE_MOUSE: { + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE: { g_pPointerManager->move(delta); break; } @@ -205,12 +205,12 @@ void CInputManager::onTabletProximity(CTablet::SProximityEvent e) { PROTO::idle->onActivity(); } -void CInputManager::newTablet(wlr_input_device* pDevice) { - const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(wlr_tablet_from_input_device(pDevice))); +void CInputManager::newTablet(SP pDevice) { + const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(pDevice)); m_vHIDs.push_back(PNEWTABLET); try { - PNEWTABLET->hlName = deviceNameToInternalString(pDevice->name); + PNEWTABLET->hlName = deviceNameToInternalString(pDevice->getName()); } catch (std::exception& e) { Debug::log(ERR, "Tablet had no name???"); // logic error } @@ -227,28 +227,32 @@ void CInputManager::newTablet(wlr_input_device* pDevice) { setTabletConfigs(); } -SP CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) { - if (pTool->data == nullptr) { - const auto PTOOL = m_vTabletTools.emplace_back(CTabletTool::create(pTool)); - m_vHIDs.push_back(PTOOL); +SP CInputManager::ensureTabletToolPresent(SP pTool) { - PTOOL->events.destroy.registerStaticListener( - [this](void* owner, std::any d) { - auto TOOL = ((CTabletTool*)owner)->self; - destroyTabletTool(TOOL.lock()); - }, - PTOOL.get()); + for (auto& t : m_vTabletTools) { + if (t->aq() == pTool) + return t; } - return CTabletTool::fromWlr(pTool); + const auto PTOOL = m_vTabletTools.emplace_back(CTabletTool::create(pTool)); + m_vHIDs.push_back(PTOOL); + + PTOOL->events.destroy.registerStaticListener( + [this](void* owner, std::any d) { + auto TOOL = ((CTabletTool*)owner)->self; + destroyTabletTool(TOOL.lock()); + }, + PTOOL.get()); + + return PTOOL; } -void CInputManager::newTabletPad(wlr_input_device* pDevice) { - const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(wlr_tablet_pad_from_input_device(pDevice))); +void CInputManager::newTabletPad(SP pDevice) { + const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(pDevice)); m_vHIDs.push_back(PNEWPAD); try { - PNEWPAD->hlName = deviceNameToInternalString(pDevice->name); + PNEWPAD->hlName = deviceNameToInternalString(pDevice->getName()); } catch (std::exception& e) { Debug::log(ERR, "Pad had no name???"); // logic error } @@ -259,7 +263,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) { destroyTabletPad(PAD.lock()); }, PNEWPAD.get()); - PNEWPAD->padEvents.button.registerStaticListener([this](void* owner, std::any e) { + PNEWPAD->padEvents.button.registerStaticListener([](void* owner, std::any e) { const auto E = std::any_cast(e); const auto PPAD = ((CTabletPad*)owner)->self.lock(); @@ -267,26 +271,25 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) { PROTO::tablet->buttonPad(PPAD, E.button, E.timeMs, E.down); }, PNEWPAD.get()); - PNEWPAD->padEvents.strip.registerStaticListener([this](void* owner, std::any e) { + PNEWPAD->padEvents.strip.registerStaticListener([](void* owner, std::any e) { const auto E = std::any_cast(e); const auto PPAD = ((CTabletPad*)owner)->self.lock(); PROTO::tablet->strip(PPAD, E.strip, E.position, E.finger, E.timeMs); }, PNEWPAD.get()); - PNEWPAD->padEvents.ring.registerStaticListener([this](void* owner, std::any e) { + PNEWPAD->padEvents.ring.registerStaticListener([](void* owner, std::any e) { const auto E = std::any_cast(e); const auto PPAD = ((CTabletPad*)owner)->self.lock(); PROTO::tablet->ring(PPAD, E.ring, E.position, E.finger, E.timeMs); }, PNEWPAD.get()); - PNEWPAD->padEvents.attach.registerStaticListener([this](void* owner, std::any e) { + PNEWPAD->padEvents.attach.registerStaticListener([](void* owner, std::any e) { const auto PPAD = ((CTabletPad*)owner)->self.lock(); const auto TOOL = std::any_cast>(e); PPAD->parent = TOOL; }, PNEWPAD.get()); - // clang-format on } diff --git a/src/meson.build b/src/meson.build index f6ae043d..71854fa4 100644 --- a/src/meson.build +++ b/src/meson.build @@ -2,14 +2,15 @@ globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true) src = globber.stdout().strip().split('\n') executable('Hyprland', src, - cpp_args: ['-DWLR_USE_UNSTABLE'], link_args: '-rdynamic', cpp_pch: 'pch/pch.hpp', dependencies: [ server_protos, + dependency('aquamarine'), + dependency('gbm'), + dependency('xcursor'), dependency('wayland-server'), dependency('wayland-client'), - wlroots.get_variable('wlroots'), dependency('cairo'), dependency('hyprcursor', version: '>=0.1.7'), dependency('hyprlang', version: '>= 0.3.2'), diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index 6e09ba2c..098e3f12 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../debug/HyprCtl.hpp" #include +#include #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) #include diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp index 2f25b22b..812afe53 100644 --- a/src/protocols/CursorShape.cpp +++ b/src/protocols/CursorShape.cpp @@ -1,48 +1,9 @@ #include "CursorShape.hpp" #include +#include "../helpers/CursorShapes.hpp" #define LOGM PROTO::cursorShape->protoLog -// clang-format off -constexpr const char* SHAPE_NAMES[] = { - "invalid", - "default", - "context-menu", - "help", - "pointer", - "progress", - "wait", - "cell", - "crosshair", - "text", - "vertical-text", - "alias", - "copy", - "move", - "no-drop", - "not-allowed", - "grab", - "grabbing", - "e-resize", - "n-resize", - "ne-resize", - "nw-resize", - "s-resize", - "se-resize", - "sw-resize", - "w-resize", - "ew-resize", - "ns-resize", - "nesw-resize", - "nwse-resize", - "col-resize", - "row-resize", - "all-scroll", - "zoom-in", - "zoom-out", -}; -// clang-format on - CCursorShapeProtocol::CCursorShapeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -82,7 +43,7 @@ void CCursorShapeProtocol::createCursorShapeDevice(CWpCursorShapeManagerV1* pMgr } void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t serial, wpCursorShapeDeviceV1Shape shape) { - if ((uint32_t)shape == 0 || (uint32_t)shape > sizeof(SHAPE_NAMES)) { + if ((uint32_t)shape == 0 || (uint32_t)shape > CURSOR_SHAPE_NAMES.size()) { pMgr->error(WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE, "The shape is invalid"); return; } @@ -90,7 +51,7 @@ void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t ser SSetShapeEvent event; event.pMgr = pMgr; event.shape = shape; - event.shapeName = SHAPE_NAMES[shape]; + event.shapeName = CURSOR_SHAPE_NAMES.at(shape); events.setShape.emit(event); } \ No newline at end of file diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp new file mode 100644 index 00000000..9f5b6312 --- /dev/null +++ b/src/protocols/DRMLease.cpp @@ -0,0 +1,302 @@ +#include "DRMLease.hpp" +#include "../Compositor.hpp" +#include +#include + +#define LOGM PROTO::lease->protoLog + +CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); }); + resource->setDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); }); + + parent = request->parent; + requested = request->requested; + + for (auto& m : requested) { + if (!m->monitor || m->monitor->isBeingLeased) { + LOGM(ERR, "Rejecting lease: no monitor or monitor is being leased for {}", (m->monitor ? m->monitor->szName : "null")); + resource->sendFinished(); + return; + } + } + + // grant the lease if it is seemingly valid + + LOGM(LOG, "Leasing outputs: {}", [this]() { + std::string roll; + for (auto& o : requested) { + roll += std::format("{} ", o->monitor->szName); + } + return roll; + }()); + + std::vector> outputs; + for (auto& m : requested) { + outputs.emplace_back(m->monitor->output); + } + + auto aqlease = Aquamarine::CDRMLease::create(outputs); + if (!aqlease) { + LOGM(ERR, "Rejecting lease: backend failed to alloc a lease"); + resource->sendFinished(); + return; + } + + LOGM(LOG, "Granting lease, sending fd {}", aqlease->leaseFD); + + resource->sendLeaseFd(aqlease->leaseFD); + + lease = aqlease; + + for (auto& m : requested) { + m->monitor->isBeingLeased = true; + } + + listeners.destroyLease = lease->events.destroy.registerListener([this](std::any d) { + for (auto& m : requested) { + if (m && m->monitor) + m->monitor->isBeingLeased = false; + } + + resource->sendFinished(); + }); + + close(lease->leaseFD); +} + +bool CDRMLeaseResource::good() { + return resource->resource(); +} + +CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseRequestV1* r) { PROTO::lease->destroyResource(this); }); + + resource->setRequestConnector([this](CWpDrmLeaseRequestV1* r, wl_resource* conn) { + if (!conn) { + resource->error(-1, "Null connector"); + return; + } + + auto CONNECTOR = CDRMLeaseConnectorResource::fromResource(conn); + + if (std::find(requested.begin(), requested.end(), CONNECTOR) != requested.end()) { + resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR, "Connector already requested"); + return; + } + + // TODO: when (if) we add multi, make sure this is from the correct device. + + requested.emplace_back(CONNECTOR); + }); + + resource->setSubmit([this](CWpDrmLeaseRequestV1* r, uint32_t id) { + if (requested.empty()) { + resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE, "No connectors added"); + return; + } + + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), self.lock()); + if (!RESOURCE) { + resource->noMemory(); + return; + } + + PROTO::lease->m_vLeases.emplace_back(RESOURCE); + + // per protcol, after submit, this is dead. + PROTO::lease->destroyResource(this); + }); +} + +bool CDRMLeaseRequestResource::good() { + return resource->resource(); +} + +SP CDRMLeaseConnectorResource::fromResource(wl_resource* res) { + auto data = (CDRMLeaseConnectorResource*)(((CWpDrmLeaseConnectorV1*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +CDRMLeaseConnectorResource::CDRMLeaseConnectorResource(SP resource_, SP monitor_) : monitor(monitor_), resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); }); + resource->setDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); }); + + resource->setData(this); + + listeners.destroyMonitor = monitor->events.destroy.registerListener([this](std::any d) { + resource->sendWithdrawn(); + dead = true; + }); +} + +bool CDRMLeaseConnectorResource::good() { + return resource->resource(); +} + +void CDRMLeaseConnectorResource::sendData() { + resource->sendName(monitor->szName.c_str()); + resource->sendDescription(monitor->szDescription.c_str()); + + auto AQDRMOutput = (Aquamarine::CDRMOutput*)monitor->output.get(); + resource->sendConnectorId(AQDRMOutput->getConnectorID()); + + resource->sendDone(); +} + +CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); }); + resource->setRelease([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); }); + + resource->setCreateLeaseRequest([this](CWpDrmLeaseDeviceV1* r, uint32_t id) { + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id)); + if (!RESOURCE) { + resource->noMemory(); + return; + } + + RESOURCE->self = RESOURCE; + + PROTO::lease->m_vRequests.emplace_back(RESOURCE); + + LOGM(LOG, "New lease request {}", id); + + RESOURCE->parent = self; + }); + + int fd = ((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD(); + if (fd < 0) { + LOGM(ERR, "Failed to dup fd in lease"); + return; + } + + LOGM(LOG, "Sending DRMFD {} to new lease device", fd); + resource->sendDrmFd(fd); + close(fd); + + for (auto& m : PROTO::lease->primaryDevice->offeredOutputs) { + sendConnector(m.lock()); + } + + resource->sendDone(); +} + +bool CDRMLeaseDeviceResource::good() { + return resource->resource(); +} + +void CDRMLeaseDeviceResource::sendConnector(SP monitor) { + if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e->monitor == monitor; }) != connectorsSent.end()) + return; + + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), monitor); + if (!RESOURCE) { + resource->noMemory(); + return; + } + + RESOURCE->parent = self; + RESOURCE->self = RESOURCE; + + LOGM(LOG, "Sending new connector {}", monitor->szName); + + connectorsSent.emplace_back(RESOURCE); + PROTO::lease->m_vConnectors.emplace_back(RESOURCE); + + resource->sendConnector(RESOURCE->resource.get()); + + RESOURCE->sendData(); +} + +CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backend(drmBackend) { + auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); + + auto fd = drm->getNonMasterFD(); + + if (fd < 0) { + LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); + return; + } + + close(fd); + success = true; + name = drm->gpuName; +} + +CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { + if (b->type() != Aquamarine::AQ_BACKEND_DRM) + continue; + + auto drm = ((Aquamarine::CDRMBackend*)b.get())->self.lock(); + + primaryDevice = makeShared(drm); + + if (primaryDevice->success) + break; + } + + if (!primaryDevice || primaryDevice->success) { + PROTO::lease.reset(); + return; + } +} + +void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseDeviceResource* resource) { + std::erase_if(m_vManagers, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseConnectorResource* resource) { + std::erase_if(m_vConnectors, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseRequestResource* resource) { + std::erase_if(m_vRequests, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseResource* resource) { + std::erase_if(m_vLeases, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::offer(SP monitor) { + if (std::find(primaryDevice->offeredOutputs.begin(), primaryDevice->offeredOutputs.end(), monitor) != primaryDevice->offeredOutputs.end()) + return; + + if (monitor->output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM) + return; + + if (monitor->output->getBackend() != primaryDevice->backend) { + LOGM(ERR, "Monitor {} cannot be leased: primaryDevice lease is for a different device", monitor->szName); + return; + } + + primaryDevice->offeredOutputs.emplace_back(monitor); + + for (auto& m : m_vManagers) { + m->sendConnector(monitor); + m->resource->sendDone(); + } +} diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp new file mode 100644 index 00000000..56eaa3db --- /dev/null +++ b/src/protocols/DRMLease.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "drm-lease-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +/* + TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu) +*/ + +AQUAMARINE_FORWARD(CDRMBackend); +AQUAMARINE_FORWARD(CDRMLease); +class CDRMLeaseDeviceResource; +class CMonitor; +class CDRMLeaseProtocol; +class CDRMLeaseConnectorResource; +class CDRMLeaseRequestResource; + +class CDRMLeaseResource { + public: + CDRMLeaseResource(SP resource_, SP request); + + bool good(); + + WP parent; + std::vector> requested; + WP lease; + + int leaseFD = -1; + + struct { + CHyprSignalListener destroyLease; + } listeners; + + private: + SP resource; +}; + +class CDRMLeaseRequestResource { + public: + CDRMLeaseRequestResource(SP resource_); + + bool good(); + + WP parent; + WP self; + std::vector> requested; + + private: + SP resource; +}; + +class CDRMLeaseConnectorResource { + public: + CDRMLeaseConnectorResource(SP resource_, SP monitor_); + static SP fromResource(wl_resource*); + + bool good(); + void sendData(); + + WP self; + WP parent; + WP monitor; + bool dead = false; + + private: + SP resource; + + struct { + CHyprSignalListener destroyMonitor; + } listeners; + + friend class CDRMLeaseDeviceResource; +}; + +class CDRMLeaseDeviceResource { + public: + CDRMLeaseDeviceResource(SP resource_); + + bool good(); + void sendConnector(SP monitor); + + std::vector> connectorsSent; + + WP self; + + private: + SP resource; + + friend class CDRMLeaseProtocol; +}; + +class CDRMLeaseDevice { + public: + CDRMLeaseDevice(SP drmBackend); + + std::string name = ""; + bool success = false; + SP backend; + + std::vector> offeredOutputs; +}; + +class CDRMLeaseProtocol : public IWaylandProtocol { + public: + CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + void offer(SP monitor); + + private: + void destroyResource(CDRMLeaseDeviceResource* resource); + void destroyResource(CDRMLeaseConnectorResource* resource); + void destroyResource(CDRMLeaseRequestResource* resource); + void destroyResource(CDRMLeaseResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vConnectors; + std::vector> m_vRequests; + std::vector> m_vLeases; + + SP primaryDevice; + + friend class CDRMLeaseDeviceResource; + friend class CDRMLeaseConnectorResource; + friend class CDRMLeaseRequestResource; + friend class CDRMLeaseResource; +}; + +namespace PROTO { + inline UP lease; +}; diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp new file mode 100644 index 00000000..41178109 --- /dev/null +++ b/src/protocols/DRMSyncobj.cpp @@ -0,0 +1,183 @@ +#include "DRMSyncobj.hpp" +#include + +#include "core/Compositor.hpp" +#include "../helpers/sync/SyncTimeline.hpp" +#include "../Compositor.hpp" + +#include + +#define LOGM PROTO::sync->protoLog + +CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setOnDestroy([this](CWpLinuxDrmSyncobjSurfaceV1* r) { PROTO::sync->destroyResource(this); }); + resource->setDestroy([this](CWpLinuxDrmSyncobjSurfaceV1* r) { PROTO::sync->destroyResource(this); }); + + resource->setSetAcquirePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { + if (!surface) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_); + acquireTimeline = timeline; + acquirePoint = ((uint64_t)hi << 32) | (uint64_t)lo; + }); + + resource->setSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { + if (!surface) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_); + releaseTimeline = timeline; + releasePoint = ((uint64_t)hi << 32) | (uint64_t)lo; + }); + + listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) { + if (!!acquireTimeline != !!releaseTimeline) { + resource->error(acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing timeline"); + surface->pending.rejected = true; + return; + } + + if ((acquireTimeline || releaseTimeline) && !surface->pending.buffer) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); + surface->pending.rejected = true; + return; + } + + if (!acquireTimeline) + return; + + // wait for the acquire timeline to materialize + auto materialized = acquireTimeline->timeline->check(acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + if (!materialized.has_value()) { + LOGM(ERR, "Failed to check the acquire timeline"); + resource->noMemory(); + return; + } + + if (materialized) + return; + + surface->lockPendingState(); + acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + }); +} + +bool CDRMSyncobjSurfaceResource::good() { + return resource->resource(); +} + +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, int fd_) : fd(fd_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setOnDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); + resource->setDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); + + timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd); + + if (!timeline) { + resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Timeline failed importing"); + return; + } +} + +SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { + auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CDRMSyncobjTimelineResource::good() { + return resource->resource(); +} + +CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); }); + resource->setDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); }); + + resource->setGetSurface([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, wl_resource* surf) { + if (!surf) { + resource->error(-1, "Invalid surface"); + return; + } + + auto SURF = CWLSurfaceResource::fromResource(surf); + if (!SURF) { + resource->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->syncobj) { + resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_SURFACE_EXISTS, "Surface already has a syncobj attached"); + return; + } + + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), SURF); + if (!RESOURCE->good()) { + resource->noMemory(); + return; + } + + PROTO::sync->m_vSurfaces.emplace_back(RESOURCE); + SURF->syncobj = RESOURCE; + + LOGM(LOG, "New linux_syncobj at {:x} for surface {:x}", (uintptr_t)RESOURCE.get(), (uintptr_t)SURF.get()); + }); + + resource->setImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) { + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), fd); + if (!RESOURCE->good()) { + resource->noMemory(); + return; + } + + PROTO::sync->m_vTimelines.emplace_back(RESOURCE); + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New linux_drm_timeline at {:x}", (uintptr_t)RESOURCE.get()); + }); +} + +bool CDRMSyncobjManagerResource::good() { + return resource->resource(); +} + +CDRMSyncobjProtocol::CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + drmFD = g_pCompositor->m_iDRMFD; +} + +void CDRMSyncobjProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjManagerResource* resource) { + std::erase_if(m_vManagers, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjTimelineResource* resource) { + std::erase_if(m_vTimelines, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjSurfaceResource* resource) { + std::erase_if(m_vSurfaces, [resource](const auto& e) { return e.get() == resource; }); +} diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp new file mode 100644 index 00000000..c1c884ff --- /dev/null +++ b/src/protocols/DRMSyncobj.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include "WaylandProtocol.hpp" +#include "linux-drm-syncobj-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +class CWLSurfaceResource; +class CDRMSyncobjTimelineResource; +class CSyncTimeline; + +class CDRMSyncobjSurfaceResource { + public: + CDRMSyncobjSurfaceResource(SP resource_, SP surface_); + + bool good(); + + WP surface; + WP acquireTimeline, releaseTimeline; + uint64_t acquirePoint = 0, releasePoint = 0; + + private: + SP resource; + + struct { + CHyprSignalListener surfacePrecommit; + } listeners; +}; + +class CDRMSyncobjTimelineResource { + public: + CDRMSyncobjTimelineResource(SP resource_, int fd_); + static SP fromResource(wl_resource*); + + bool good(); + + WP self; + int fd = -1; + SP timeline; + + private: + SP resource; +}; + +class CDRMSyncobjManagerResource { + public: + CDRMSyncobjManagerResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CDRMSyncobjProtocol : public IWaylandProtocol { + public: + CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CDRMSyncobjManagerResource* resource); + void destroyResource(CDRMSyncobjTimelineResource* resource); + void destroyResource(CDRMSyncobjSurfaceResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vTimelines; + std::vector> m_vSurfaces; + + // + int drmFD = -1; + + friend class CDRMSyncobjManagerResource; + friend class CDRMSyncobjTimelineResource; + friend class CDRMSyncobjSurfaceResource; +}; + +namespace PROTO { + inline UP sync; +}; diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 7c3b39ce..494d9862 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -34,7 +34,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } } - gammaSize = wlr_output_get_gamma_size(pMonitor->output); + gammaSize = pMonitor->output->getGammaSize(); if (gammaSize <= 0) { LOGM(ERR, "Output {} doesn't support gamma", pMonitor->szName); @@ -81,6 +81,24 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out gammaTableSet = true; close(fd); + + // translate the table to AQ format + std::vector red, green, blue; + red.resize(gammaTable.size() / 3); + green.resize(gammaTable.size() / 3); + blue.resize(gammaTable.size() / 3); + for (size_t i = 0; i < gammaTable.size() / 3; ++i) { + red.at(i) = gammaTable.at(i); + green.at(i) = gammaTable.at(gammaTable.size() / 3 + i); + blue.at(i) = gammaTable.at((gammaTable.size() / 3) * 2 + i); + } + + for (size_t i = 0; i < gammaTable.size() / 3; ++i) { + gammaTable.at(i * 3) = red.at(i); + gammaTable.at(i * 3 + 1) = green.at(i); + gammaTable.at(i * 3 + 2) = blue.at(i); + } + applyToMonitor(); }); @@ -95,7 +113,7 @@ CGammaControl::~CGammaControl() { return; // reset the LUT if the client dies for whatever reason and doesn't unset the gamma - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr); + pMonitor->output->state->setGammaLut({}); } bool CGammaControl::good() { @@ -109,19 +127,15 @@ void CGammaControl::applyToMonitor() { LOGM(LOG, "setting to monitor {}", pMonitor->szName); if (!gammaTableSet) { - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr); + pMonitor->output->state->setGammaLut({}); return; } - uint16_t* red = &gammaTable.at(0); - uint16_t* green = &gammaTable.at(gammaSize); - uint16_t* blue = &gammaTable.at(gammaSize * 2); - - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), gammaSize, red, green, blue); + pMonitor->output->state->setGammaLut(gammaTable); if (!pMonitor->state.test()) { LOGM(LOG, "setting to monitor {} failed", pMonitor->szName); - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr); + pMonitor->output->state->setGammaLut({}); } g_pHyprRenderer->damageMonitor(pMonitor); diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp index 93465b81..963eea5c 100644 --- a/src/protocols/GammaControl.hpp +++ b/src/protocols/GammaControl.hpp @@ -23,7 +23,7 @@ class CGammaControl { CMonitor* pMonitor = nullptr; size_t gammaSize = 0; bool gammaTableSet = false; - std::vector gammaTable; + std::vector gammaTable; // [r,g,b]+ void onMonitorDestroy(); diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 24f7ad54..def4d837 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -4,6 +4,7 @@ #include "../devices/IKeyboard.hpp" #include #include "core/Compositor.hpp" +#include #define LOGM PROTO::ime->protoLog @@ -19,7 +20,7 @@ CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SPkeyboard->wlr()); + sendKeyboardData(g_pSeatManager->keyboard.lock()); } CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() { @@ -27,37 +28,36 @@ CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() { std::erase_if(owner->grabs, [](const auto& g) { return g.expired(); }); } -void CInputMethodKeyboardGrabV2::sendKeyboardData(wlr_keyboard* keyboard) { +void CInputMethodKeyboardGrabV2::sendKeyboardData(SP keyboard) { if (keyboard == pLastKeyboard) return; pLastKeyboard = keyboard; - int keymapFD = allocateSHMFile(keyboard->keymap_size); + int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); if (keymapFD < 0) { LOGM(ERR, "Failed to create a keymap file for keyboard grab"); return; } - void* data = mmap(nullptr, keyboard->keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); + void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); if (data == MAP_FAILED) { LOGM(ERR, "Failed to mmap a keymap file for keyboard grab"); close(keymapFD); return; } - memcpy(data, keyboard->keymap_string, keyboard->keymap_size); - munmap(data, keyboard->keymap_size); + memcpy(data, keyboard->xkbKeymapString.c_str(), keyboard->xkbKeymapString.length()); + munmap(data, keyboard->xkbKeymapString.length() + 1); - resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->keymap_size); + resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->xkbKeymapString.length() + 1); close(keymapFD); - const auto MODS = keyboard->modifiers; - sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); + sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group); - resource->sendRepeatInfo(keyboard->repeat_info.rate, keyboard->repeat_info.delay); + resource->sendRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay); } void CInputMethodKeyboardGrabV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state) { @@ -316,7 +316,7 @@ void CInputMethodV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t loc } } -void CInputMethodV2::setKeyboard(wlr_keyboard* keyboard) { +void CInputMethodV2::setKeyboard(SP keyboard) { for (auto& gw : grabs) { auto g = gw.lock(); diff --git a/src/protocols/InputMethodV2.hpp b/src/protocols/InputMethodV2.hpp index bc21270c..0b2c7a49 100644 --- a/src/protocols/InputMethodV2.hpp +++ b/src/protocols/InputMethodV2.hpp @@ -11,6 +11,7 @@ class CInputMethodKeyboardGrabV2; class CInputMethodPopupV2; +class IKeyboard; class CInputMethodV2 { public: @@ -58,7 +59,7 @@ class CInputMethodV2 { bool hasGrab(); void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state); void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - void setKeyboard(wlr_keyboard* keyboard); + void setKeyboard(SP keyboard); wl_client* client(); wl_client* grabClient(); @@ -90,13 +91,13 @@ class CInputMethodKeyboardGrabV2 { void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state); void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - void sendKeyboardData(wlr_keyboard* keyboard); + void sendKeyboardData(SP keyboard); private: SP resource; WP owner; - wlr_keyboard* pLastKeyboard = nullptr; // READ-ONLY + WP pLastKeyboard; }; class CInputMethodPopupV2 { diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index cf8f8730..0fbf832e 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "core/Compositor.hpp" #include "types/DMABuffer.hpp" #include "types/WLBuffer.hpp" @@ -22,21 +23,66 @@ static std::optional devIDFromFD(int fd) { return stat.st_rdev; } -CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector tranches_) { +CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector, SDMABUFTranche>> tranches_) : + rendererTranche(_rendererTranche), monitorTranches(tranches_) { + + std::vector formatsVec; std::set> formats; - for (auto& t : tranches_) { - for (auto& fmt : t.formats) { - for (auto& mod : fmt.mods) { - formats.insert(std::make_pair<>(fmt.format, mod)); + + // insert formats into vec if they got inserted into set, meaning they're unique + size_t i = 0; + + rendererTranche.indicies.clear(); + for (auto& fmt : rendererTranche.formats) { + for (auto& mod : fmt.modifiers) { + auto format = std::make_pair<>(fmt.drmFormat, mod); + auto [_, inserted] = formats.insert(format); + if (inserted) { + // if it was inserted into set, then its unique and will have a new index in vec + rendererTranche.indicies.push_back(i++); + formatsVec.push_back(SDMABUFFormatTableEntry{ + .fmt = fmt.drmFormat, + .modifier = mod, + }); + } else { + // if it wasn't inserted then find its index in vec + auto it = + std::find_if(formatsVec.begin(), formatsVec.end(), [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + rendererTranche.indicies.push_back(it - formatsVec.begin()); } } } - tableLen = formats.size() * sizeof(SDMABUFFeedbackTableEntry); - int fds[2] = {0}; - allocateSHMFilePair(tableLen, &fds[0], &fds[1]); + for (auto& [monitor, tranche] : monitorTranches) { + tranche.indicies.clear(); + for (auto& fmt : tranche.formats) { + for (auto& mod : fmt.modifiers) { + // apparently these can implode on planes, so dont use them + if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) + continue; + auto format = std::make_pair<>(fmt.drmFormat, mod); + auto [_, inserted] = formats.insert(format); + if (inserted) { + tranche.indicies.push_back(i++); + formatsVec.push_back(SDMABUFFormatTableEntry{ + .fmt = fmt.drmFormat, + .modifier = mod, + }); + } else { + auto it = std::find_if(formatsVec.begin(), formatsVec.end(), + [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + tranche.indicies.push_back(it - formatsVec.begin()); + } + } + } + } - auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry); + + int fds[2] = {0}; + allocateSHMFilePair(tableSize, &fds[0], &fds[1]); + + auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); if (arr == MAP_FAILED) { LOGM(ERR, "mmap failed"); @@ -47,33 +93,18 @@ CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector> formatsVec; - for (auto& f : formats) { - formatsVec.push_back(f); - } + std::copy(formatsVec.begin(), formatsVec.end(), arr); - size_t i = 0; - for (auto& [fmt, mod] : formatsVec) { - arr[i++] = SDMABUFFeedbackTableEntry{ - .fmt = fmt, - .modifier = mod, - }; - } + munmap(arr, tableSize); - munmap(arr, tableLen); - - mainDevice = device; - tableFD = fds[1]; - tranches = formatsVec; - - // TODO: maybe calculate indices? currently we send all as available which could be wrong? I ain't no kernel dev tho. + tableFD = fds[1]; } -CCompiledDMABUFFeedback::~CCompiledDMABUFFeedback() { +CDMABUFFormatTable::~CDMABUFFormatTable() { close(tableFD); } -CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs) { +CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs) { buffer = makeShared(id, client, attrs); buffer->resource->buffer = buffer; @@ -103,7 +134,7 @@ CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SPsetOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); resource->setDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); - attrs = makeShared(); + attrs = makeShared(); attrs->success = true; @@ -190,7 +221,7 @@ void CLinuxDMABBUFParamsResource::create(uint32_t id) { return; } - LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, attrs->format, attrs->planes); + LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, FormatUtils::drmFormatName(attrs->format), attrs->planes); for (int i = 0; i < attrs->planes; ++i) { LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs->modifier, attrs->fds[i], attrs->strides[i], attrs->offsets[i]); } @@ -277,32 +308,9 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPsetOnDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); resource->setDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); - if (surface) - LOGM(ERR, "FIXME: surface feedback stub"); - - auto* feedback = PROTO::linuxDma->defaultFeedback.get(); - - resource->sendFormatTable(feedback->tableFD, feedback->tableLen); - - // send default feedback - struct wl_array deviceArr = { - .size = sizeof(feedback->mainDevice), - .data = (void*)&feedback->mainDevice, - }; - resource->sendMainDevice(&deviceArr); - resource->sendTrancheTargetDevice(&deviceArr); - resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)0); - - wl_array indices; - wl_array_init(&indices); - for (size_t i = 0; i < feedback->tranches.size(); ++i) { - *((uint16_t*)wl_array_add(&indices, sizeof(uint16_t))) = i; - } - resource->sendTrancheFormats(&indices); - wl_array_release(&indices); - resource->sendTrancheDone(); - - resource->sendDone(); + auto& formatTable = PROTO::linuxDma->formatTable; + resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize); + sendDefaultFeedback(); } CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() { @@ -313,6 +321,41 @@ bool CLinuxDMABUFFeedbackResource::good() { return resource->resource(); } +void CLinuxDMABUFFeedbackResource::sendTranche(SDMABUFTranche& tranche) { + struct wl_array deviceArr = { + .size = sizeof(tranche.device), + .data = (void*)&tranche.device, + }; + resource->sendTrancheTargetDevice(&deviceArr); + + resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)tranche.flags); + + wl_array indices = { + .size = tranche.indicies.size() * sizeof(tranche.indicies.at(0)), + .data = tranche.indicies.data(), + }; + resource->sendTrancheFormats(&indices); + resource->sendTrancheDone(); +} + +// default tranche is based on renderer (egl) +void CLinuxDMABUFFeedbackResource::sendDefaultFeedback() { + auto mainDevice = PROTO::linuxDma->mainDevice; + auto& formatTable = PROTO::linuxDma->formatTable; + + struct wl_array deviceArr = { + .size = sizeof(mainDevice), + .data = (void*)&mainDevice, + }; + resource->sendMainDevice(&deviceArr); + + sendTranche(formatTable->rendererTranche); + + resource->sendDone(); + + lastFeedbackWasScanout = false; +} + CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : resource(resource_) { if (!good()) return; @@ -361,48 +404,81 @@ bool CLinuxDMABUFResource::good() { } void CLinuxDMABUFResource::sendMods() { - for (auto& [fmt, mod] : PROTO::linuxDma->defaultFeedback->tranches) { - if (resource->version() < 3) { - if (mod == DRM_FORMAT_MOD_INVALID) - resource->sendFormat(fmt); - continue; + for (auto& fmt : PROTO::linuxDma->formatTable->rendererTranche.formats) { + for (auto& mod : fmt.modifiers) { + if (resource->version() < 3) { + if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) + resource->sendFormat(fmt.drmFormat); + continue; + } + + // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 + + resource->sendModifier(fmt.drmFormat, mod >> 32, mod & 0xFFFFFFFF); } - - // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 - - resource->sendModifier(fmt, mod >> 32, mod & 0xFFFFFFFF); } } CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("ready", [this](void* self, SCallbackInfo& info, std::any d) { - int rendererFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + int rendererFD = g_pCompositor->m_iDRMFD; auto dev = devIDFromFD(rendererFD); if (!dev.has_value()) { - LOGM(ERR, "failed to get drm dev"); - PROTO::linuxDma.reset(); + protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + removeGlobal(); return; } mainDevice = *dev; - auto fmts = g_pHyprOpenGL->getDRMFormats(); - - SDMABufTranche tranche = { - .device = *dev, - .formats = fmts, + SDMABUFTranche eglTranche = { + .device = mainDevice, + .flags = 0, // renderer isnt for ds so dont set flag. + .formats = g_pHyprOpenGL->getDRMFormats(), }; - std::vector tches; - tches.push_back(tranche); + std::vector, SDMABUFTranche>> tches; - defaultFeedback = std::make_unique(*dev, tches); + if (g_pCompositor->m_pAqBackend->hasSession()) { + // this assumes there's only 1 device used for both scanout and rendering + // also that each monitor never changes its primary plane + + for (auto& mon : g_pCompositor->m_vMonitors) { + auto tranche = SDMABUFTranche{ + .device = mainDevice, + .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, + .formats = mon->output->getRenderFormats(), + }; + tches.push_back(std::make_pair<>(mon, tranche)); + } + + static auto monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { + auto pMonitor = std::any_cast(param); + auto mon = pMonitor->self.lock(); + auto tranche = SDMABUFTranche{ + .device = mainDevice, + .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, + .formats = mon->output->getRenderFormats(), + }; + formatTable->monitorTranches.push_back(std::make_pair<>(mon, tranche)); + resetFormatTable(); + }); + + static auto monitorRemoved = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { + auto pMonitor = std::any_cast(param); + auto mon = pMonitor->self.lock(); + std::erase_if(formatTable->monitorTranches, [mon](std::pair, SDMABUFTranche> pair) { return pair.first == mon; }); + resetFormatTable(); + }); + } + + formatTable = std::make_unique(eglTranche, tches); drmDevice* device = nullptr; if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) { - LOGM(ERR, "failed to get drm dev"); - PROTO::linuxDma.reset(); + protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + removeGlobal(); return; } @@ -411,17 +487,51 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); drmFreeDevice(&device); if (mainDeviceFD < 0) { - LOGM(ERR, "failed to open drm dev"); - PROTO::linuxDma.reset(); + protoLog(ERR, "failed to open drm dev, disabling linux dmabuf"); + removeGlobal(); return; } } else { - LOGM(ERR, "DRM device {} has no render node!!", device->nodes[DRM_NODE_PRIMARY]); + protoLog(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); drmFreeDevice(&device); + removeGlobal(); } }); } +void CLinuxDMABufV1Protocol::resetFormatTable() { + if (!formatTable) + return; + + LOGM(LOG, "Resetting format table"); + + // this might be a big copy + auto newFormatTable = std::make_unique(formatTable->rendererTranche, formatTable->monitorTranches); + + for (auto& feedback : m_vFeedbacks) { + feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); + if (feedback->lastFeedbackWasScanout) { + SP mon; + auto HLSurface = CWLSurface::fromResource(feedback->surface); + if (auto w = HLSurface->getWindow(); w) + if (auto m = g_pCompositor->getMonitorFromID(w->m_iMonitorID); m) + mon = m->self.lock(); + + if (!mon) { + feedback->sendDefaultFeedback(); + return; + } + + updateScanoutTranche(feedback->surface, mon); + } else { + feedback->sendDefaultFeedback(); + } + } + + // delete old table after we sent new one + formatTable = std::move(newFormatTable); +} + CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { if (mainDeviceFD >= 0) close(mainDeviceFD); @@ -452,3 +562,52 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABBUFParamsResource* resour void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) { std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); } + +void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface, SP pMonitor) { + SP feedbackResource; + for (auto& f : m_vFeedbacks) { + if (f->surface != surface) + continue; + + feedbackResource = f; + break; + } + + if (!feedbackResource) { + LOGM(LOG, "updateScanoutTranche: surface has no dmabuf_feedback"); + return; + } + + if (!pMonitor) { + LOGM(LOG, "updateScanoutTranche: resetting feedback"); + feedbackResource->sendDefaultFeedback(); + return; + } + + const auto& monitorTranchePair = std::find_if(formatTable->monitorTranches.begin(), formatTable->monitorTranches.end(), + [pMonitor](std::pair, SDMABUFTranche> pair) { return pair.first == pMonitor; }); + + if (monitorTranchePair == formatTable->monitorTranches.end()) { + LOGM(LOG, "updateScanoutTranche: monitor has no tranche"); + return; + } + + auto& monitorTranche = (*monitorTranchePair).second; + + LOGM(LOG, "updateScanoutTranche: sending a scanout tranche"); + + struct wl_array deviceArr = { + .size = sizeof(mainDevice), + .data = (void*)&mainDevice, + }; + feedbackResource->resource->sendMainDevice(&deviceArr); + + // prioritize scnaout tranche but have renderer fallback tranche + // also yes formats can be duped here because different tranche flags (ds and no ds) + feedbackResource->sendTranche(monitorTranche); + feedbackResource->sendTranche(formatTable->rendererTranche); + + feedbackResource->resource->sendDone(); + + feedbackResource->lastFeedbackWasScanout = true; +} diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 2b8ce736..0e25cdc6 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -7,15 +7,16 @@ #include "wayland.hpp" #include "linux-dmabuf-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include "../helpers/Format.hpp" +#include "../helpers/Monitor.hpp" +#include class CDMABuffer; -struct SDRMFormat; -struct SDMABUFAttrs; class CWLSurfaceResource; class CLinuxDMABuffer { public: - CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs); ~CLinuxDMABuffer(); bool good(); @@ -31,34 +32,29 @@ class CLinuxDMABuffer { }; #pragma pack(push, 1) -struct SDMABUFFeedbackTableEntry { +struct SDMABUFFormatTableEntry { uint32_t fmt = 0; char pad[4]; uint64_t modifier = 0; }; #pragma pack(pop) -class SCompiledDMABUFTranche { - dev_t device = 0; - uint32_t flags = 0; - std::vector indices; -}; - -struct SDMABufTranche { +struct SDMABUFTranche { dev_t device = 0; uint32_t flags = 0; std::vector formats; + std::vector indicies; }; -class CCompiledDMABUFFeedback { +class CDMABUFFormatTable { public: - CCompiledDMABUFFeedback(dev_t device, std::vector tranches); - ~CCompiledDMABUFFeedback(); + CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector, SDMABUFTranche>> tranches); + ~CDMABUFFormatTable(); - dev_t mainDevice = 0; - int tableFD = -1; - size_t tableLen = 0; - std::vector> tranches; + int tableFD = -1; + size_t tableSize = 0; + SDMABUFTranche rendererTranche; + std::vector, SDMABUFTranche>> monitorTranches; }; class CLinuxDMABBUFParamsResource { @@ -66,12 +62,12 @@ class CLinuxDMABBUFParamsResource { CLinuxDMABBUFParamsResource(SP resource_); ~CLinuxDMABBUFParamsResource(); - bool good(); - void create(uint32_t id); // 0 means not immed + bool good(); + void create(uint32_t id); // 0 means not immed - SP attrs; - WP createdBuffer; - bool used = false; + SP attrs; + WP createdBuffer; + bool used = false; private: SP resource; @@ -86,11 +82,16 @@ class CLinuxDMABUFFeedbackResource { ~CLinuxDMABUFFeedbackResource(); bool good(); + void sendDefaultFeedback(); + void sendTranche(SDMABUFTranche& tranche); SP surface; // optional, for surface feedbacks private: SP resource; + bool lastFeedbackWasScanout = false; + + friend class CLinuxDMABufV1Protocol; }; class CLinuxDMABUFResource { @@ -110,6 +111,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { ~CLinuxDMABufV1Protocol(); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + void updateScanoutTranche(SP surface, SP pMonitor); private: void destroyResource(CLinuxDMABUFResource* resource); @@ -117,13 +119,15 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { void destroyResource(CLinuxDMABBUFParamsResource* resource); void destroyResource(CLinuxDMABuffer* resource); + void resetFormatTable(); + // std::vector> m_vManagers; std::vector> m_vFeedbacks; std::vector> m_vParams; std::vector> m_vBuffers; - UP defaultFeedback; + UP formatTable; dev_t mainDevice; int mainDeviceFD = -1; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index 0bcf4a9c..ed412555 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -2,12 +2,11 @@ #include #include #include "../Compositor.hpp" -#include #include "types/WLBuffer.hpp" #define LOGM PROTO::mesaDRM->protoLog -CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) { +CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) { LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes); for (int i = 0; i < attrs_.planes; ++i) { LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]); @@ -60,10 +59,27 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { return; } - SDMABUFAttrs attrs; + uint64_t mod = DRM_FORMAT_MOD_INVALID; + + auto fmts = g_pHyprOpenGL->getDRMFormats(); + for (auto& f : fmts) { + if (f.drmFormat != fmt) + continue; + + for (auto& m : f.modifiers) { + if (m == DRM_FORMAT_MOD_LINEAR) + continue; + + mod = m; + break; + } + break; + } + + Aquamarine::SDMABUFAttrs attrs; attrs.success = true; attrs.size = {w, h}; - attrs.modifier = DRM_FORMAT_MOD_INVALID; + attrs.modifier = mod; attrs.planes = 1; attrs.offsets[0] = off0; attrs.strides[0] = str0; @@ -87,7 +103,7 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { auto fmts = g_pHyprOpenGL->getDRMFormats(); for (auto& fmt : fmts) { - resource->sendFormat(fmt.format); + resource->sendFormat(fmt.drmFormat); } } @@ -97,10 +113,10 @@ bool CMesaDRMResource::good() { CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { drmDevice* dev = nullptr; - int drmFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + int drmFD = g_pCompositor->m_iDRMFD; if (drmGetDevice2(drmFD, 0, &dev) != 0) { - LOGM(ERR, "Failed to get device"); - PROTO::mesaDRM.reset(); + protoLog(ERR, "Failed to get device, disabling MesaDRM"); + removeGlobal(); return; } @@ -108,7 +124,15 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co nodeName = dev->nodes[DRM_NODE_RENDER]; } else { ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); - LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); + + if (!dev->nodes[DRM_NODE_PRIMARY]) { + protoLog(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM"); + drmFreeDevice(&dev); + removeGlobal(); + return; + } + + protoLog(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); nodeName = dev->nodes[DRM_NODE_PRIMARY]; } drmFreeDevice(&dev); diff --git a/src/protocols/MesaDRM.hpp b/src/protocols/MesaDRM.hpp index ad31a182..46811d68 100644 --- a/src/protocols/MesaDRM.hpp +++ b/src/protocols/MesaDRM.hpp @@ -10,7 +10,7 @@ class CMesaDRMBufferResource { public: - CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs); ~CMesaDRMBufferResource(); bool good(); diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 68c50193..66f4c5f0 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -2,6 +2,8 @@ #include #include "../Compositor.hpp" +using namespace Aquamarine; + #define LOGM PROTO::outputManagement->protoLog COutputManager::COutputManager(SP resource_) : resource(resource_) { @@ -123,8 +125,8 @@ void COutputHead::sendAllData() { resource->sendName(pMonitor->szName.c_str()); resource->sendDescription(pMonitor->szDescription.c_str()); - if (pMonitor->output->phys_width > 0 && pMonitor->output->phys_height > 0) - resource->sendPhysicalSize(pMonitor->output->phys_width, pMonitor->output->phys_height); + if (pMonitor->output->physicalSize.x > 0 && pMonitor->output->physicalSize.y > 0) + resource->sendPhysicalSize(pMonitor->output->physicalSize.x, pMonitor->output->physicalSize.y); resource->sendEnabled(pMonitor->m_bEnabled); if (pMonitor->m_bEnabled) { @@ -133,12 +135,12 @@ void COutputHead::sendAllData() { resource->sendScale(wl_fixed_from_double(pMonitor->scale)); } - if (pMonitor->output->make && VERSION >= 2) - resource->sendMake(pMonitor->output->make); - if (pMonitor->output->model && VERSION >= 2) - resource->sendModel(pMonitor->output->model); - if (pMonitor->output->serial && VERSION >= 2) - resource->sendSerialNumber(pMonitor->output->serial); + if (!pMonitor->output->make.empty() && VERSION >= 2) + resource->sendMake(pMonitor->output->make.c_str()); + if (!pMonitor->output->model.empty() && VERSION >= 2) + resource->sendModel(pMonitor->output->model.c_str()); + if (!pMonitor->output->serial.empty() && VERSION >= 2) + resource->sendSerialNumber(pMonitor->output->serial.c_str()); if (VERSION >= 4) resource->sendAdaptiveSync(pMonitor->vrrActive ? ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED : ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED); @@ -146,12 +148,12 @@ void COutputHead::sendAllData() { // send all available modes if (modes.empty()) { - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; - - wl_list_for_each(mode, &pMonitor->output->modes, link) { - makeAndSendNewMode(mode); + if (!pMonitor->output->modes.empty()) { + for (auto& m : pMonitor->output->modes) { + makeAndSendNewMode(m); } + } else if (pMonitor->output->state->state().customMode) { + makeAndSendNewMode(pMonitor->output->state->state().customMode); } else makeAndSendNewMode(nullptr); } @@ -164,9 +166,9 @@ void COutputHead::sendAllData() { if (!m) continue; - if (m->mode == pMonitor->currentMode) { + if (m->mode == pMonitor->output->state->state().mode) { if (m->mode) - LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh); + LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate); else LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName); resource->sendCurrentMode(m->resource.get()); @@ -197,7 +199,7 @@ void COutputHead::updateMode() { if (m->mode == pMonitor->currentMode) { if (m->mode) - LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh); + LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate); else LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName); resource->sendCurrentMode(m->resource.get()); @@ -207,7 +209,7 @@ void COutputHead::updateMode() { } } -void COutputHead::makeAndSendNewMode(wlr_output_mode* mode) { +void COutputHead::makeAndSendNewMode(SP mode) { const auto RESOURCE = PROTO::outputManagement->m_vModes.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), mode)); if (!RESOURCE->good()) { @@ -225,7 +227,7 @@ CMonitor* COutputHead::monitor() { return pMonitor; } -COutputMode::COutputMode(SP resource_, wlr_output_mode* mode_) : resource(resource_), mode(mode_) { +COutputMode::COutputMode(SP resource_, SP mode_) : resource(resource_), mode(mode_) { if (!good()) return; @@ -237,11 +239,11 @@ void COutputMode::sendAllData() { if (!mode) return; - LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->width, mode->height, mode->refresh, mode->preferred); + LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate, mode->preferred); - resource->sendSize(mode->width, mode->height); - if (mode->refresh > 0) - resource->sendRefresh(mode->refresh); + resource->sendSize(mode->pixelSize.x, mode->pixelSize.y); + if (mode->refreshRate > 0) + resource->sendRefresh(mode->refreshRate); if (mode->preferred) resource->sendPreferred(); } @@ -250,8 +252,8 @@ bool COutputMode::good() { return resource->resource(); } -wlr_output_mode* COutputMode::getMode() { - return mode; +SP COutputMode::getMode() { + return mode.lock(); } COutputConfiguration::COutputConfiguration(SP resource_, SP owner_) : resource(resource_), owner(owner_) { @@ -364,8 +366,8 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { newRule.disabled = false; if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { - newRule.resolution = {head->state.mode->getMode()->width, head->state.mode->getMode()->height}; - newRule.refreshRate = head->state.mode->getMode()->refresh / 1000.F; + newRule.resolution = head->state.mode->getMode()->pixelSize; + newRule.refreshRate = head->state.mode->getMode()->refreshRate / 1000.F; } else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { newRule.resolution = head->state.customMode.size; newRule.refreshRate = head->state.customMode.refresh / 1000.F; @@ -425,7 +427,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, MODE->getMode()->width, MODE->getMode()->height, MODE->getMode()->refresh); + LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate); }); resource->setSetCustomMode([this](CZwlrOutputConfigurationHeadV1* r, int32_t w, int32_t h, int32_t refresh) { diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index 81ae9a71..36478d0b 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -6,6 +6,7 @@ #include "WaylandProtocol.hpp" #include "wlr-output-management-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CMonitor; @@ -34,15 +35,15 @@ class COutputManager { class COutputMode { public: - COutputMode(SP resource_, wlr_output_mode* mode_); + COutputMode(SP resource_, SP mode_); - bool good(); - wlr_output_mode* getMode(); - void sendAllData(); + bool good(); + SP getMode(); + void sendAllData(); private: - SP resource; - wlr_output_mode* mode = nullptr; + SP resource; + WP mode; friend class COutputHead; friend class COutputManagementProtocol; @@ -61,7 +62,7 @@ class COutputHead { SP resource; CMonitor* pMonitor = nullptr; - void makeAndSendNewMode(wlr_output_mode* mode); + void makeAndSendNewMode(SP mode); void sendCurrentMode(); std::vector> modes; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index ef287cfa..597b9871 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -17,7 +17,7 @@ COutputPower::COutputPower(SP resource_, CMonitor* pMonitor_ pMonitor->dpmsStatus = mode == ZWLR_OUTPUT_POWER_V1_MODE_ON; - wlr_output_state_set_enabled(pMonitor->state.wlr(), pMonitor->dpmsStatus); + pMonitor->output->state->setEnabled(mode == ZWLR_OUTPUT_POWER_V1_MODE_ON); if (!pMonitor->state.commit()) LOGM(ERR, "Couldn't set dpms to {} for {}", pMonitor->dpmsStatus, pMonitor->szName); diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 3907bf1e..e9472fc3 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -3,6 +3,8 @@ #include "../helpers/Monitor.hpp" #include "../managers/HookSystemManager.hpp" #include "core/Compositor.hpp" +#include "core/Output.hpp" +#include #define LOGM PROTO::presentation->protoLog @@ -41,13 +43,11 @@ bool CPresentationFeedback::good() { } void CPresentationFeedback::sendQueued(SP data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { - auto client = resource->client(); - wl_resource* res; - wl_resource_for_each(res, &data->pMonitor->output->resources) { - if (client == wl_resource_get_client(res)) { - resource->sendSyncOutput(res); - break; - } + auto client = resource->client(); + + if (PROTO::outputs.contains(data->pMonitor->szName)) { + if (auto outputResource = PROTO::outputs.at(data->pMonitor->szName)->outputResourceFrom(client); outputResource) + resource->sendSyncOutput(outputResource->getResource()->resource()); } uint32_t flags = 0; @@ -55,9 +55,9 @@ void CPresentationFeedback::sendQueued(SP data, timespe flags |= WP_PRESENTATION_FEEDBACK_KIND_VSYNC; if (data->zeroCopy) flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY; - if (reportedFlags & WLR_OUTPUT_PRESENT_HW_CLOCK) + if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_CLOCK) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; - if (reportedFlags & WLR_OUTPUT_PRESENT_HW_COMPLETION) + if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; if (data->wasPresented && when) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 8a6285a1..5d1c9332 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -266,20 +266,17 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r return; } - if (PFRAME->pMonitor->output->allocator && (PFRAME->pMonitor->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) { - PFRAME->dmabufFormat = PFRAME->pMonitor->output->render_format; - } else { - PFRAME->dmabufFormat = DRM_FORMAT_INVALID; - } + PFRAME->dmabufFormat = PFRAME->pMonitor->output->state->state().drmFormat; if (box.width == 0 && box.height == 0) PFRAME->box = {0, 0, (int)(PFRAME->pMonitor->vecSize.x), (int)(PFRAME->pMonitor->vecSize.y)}; else { PFRAME->box = box; } - int ow, oh; - wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh); - PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), ow, oh).scale(PFRAME->pMonitor->scale).round(); + + PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), PFRAME->pMonitor->vecTransformedSize.x, PFRAME->pMonitor->vecTransformedSize.y) + .scale(PFRAME->pMonitor->scale) + .round(); PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); @@ -383,10 +380,10 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou g_pHyprRenderer->damageMonitor(PFRAME->pMonitor); } -void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) { - m_pLastMonitorBackBuffer = e->state->buffer; +void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor) { + m_pLastMonitorBackBuffer = pMonitor->output->state->state().buffer; shareAllFrames(pMonitor); - m_pLastMonitorBackBuffer = nullptr; + m_pLastMonitorBackBuffer.reset(); } void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) { @@ -473,11 +470,7 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) { } bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { - wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer); - if (!sourceTex) - return false; - - auto TEXTURE = makeShared(sourceTex); + auto TEXTURE = makeShared(m_pLastMonitorBackBuffer); auto shm = frame->buffer->shm(); auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm @@ -487,10 +480,10 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* g_pHyprRenderer->makeEGLCurrent(); CFramebuffer fb; - fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->drmFormat); + fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->output->state->state().drmFormat); if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { - wlr_texture_destroy(sourceTex); + Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering"); return false; } @@ -509,8 +502,8 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { + Debug::log(ERR, "Screencopy: can't copy: failed to find a pixel format"); g_pHyprRenderer->endRender(); - wlr_texture_destroy(sourceTex); return false; } @@ -539,27 +532,24 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; - wlr_texture_destroy(sourceTex); + Debug::log(TRACE, "Screencopy: copied frame via shm"); return true; } bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { - wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer); - if (!sourceTex) - return false; - - auto TEXTURE = makeShared(sourceTex); + auto TEXTURE = makeShared(m_pLastMonitorBackBuffer); CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) + if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) { + Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering to dma frame"); return false; + } - CBox monbox = - CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} - .translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. - .transform(wlTransformToHyprutils(wlr_output_transform_invert(frame->pMonitor->output->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); + CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} + .translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. + .transform(wlTransformToHyprutils(invertTransform(frame->pMonitor->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); @@ -569,7 +559,7 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); - wlr_texture_destroy(sourceTex); + Debug::log(TRACE, "Screencopy: copied frame via dma"); return true; } diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index be434285..4999773b 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -8,9 +8,10 @@ #include "../managers/HookSystemManager.hpp" #include "../helpers/Timer.hpp" #include "../managers/eventLoop/EventLoopTimer.hpp" +#include class CMonitor; -class IWLBuffer; +class IHLBuffer; enum eClientOwners { CLIENT_SCREENCOPY = 0, @@ -56,7 +57,7 @@ struct SScreencopyFrame { bool bufferDMA = false; - WP buffer; + WP buffer; CMonitor* pMonitor = nullptr; PHLWINDOWREF pWindow; @@ -79,7 +80,7 @@ class CScreencopyProtocolManager { void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer); - void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e); + void onOutputCommit(CMonitor* pMonitor); private: wl_global* m_pGlobal = nullptr; @@ -93,7 +94,7 @@ class CScreencopyProtocolManager { std::vector m_vFramesAwaitingWrite; - wlr_buffer* m_pLastMonitorBackBuffer = nullptr; + SP m_pLastMonitorBackBuffer; void shareAllFrames(CMonitor* pMonitor); void shareFrame(SScreencopyFrame* frame); diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 7b62f245..72c7cfde 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -5,6 +5,7 @@ #include "core/Seat.hpp" #include "core/Compositor.hpp" #include +#include #define LOGM PROTO::tablet->protoLog @@ -44,17 +45,17 @@ bool CTabletPadGroupV2Resource::good() { return resource->resource(); } -void CTabletPadGroupV2Resource::sendData(SP pad, wlr_tablet_pad_group* group) { - resource->sendModes(group->mode_count); +void CTabletPadGroupV2Resource::sendData(SP pad, SP group) { + resource->sendModes(group->modes); wl_array buttonArr; wl_array_init(&buttonArr); - wl_array_add(&buttonArr, group->button_count * sizeof(int)); - memcpy(buttonArr.data, group->buttons, group->button_count * sizeof(int)); + wl_array_add(&buttonArr, group->buttons.size() * sizeof(int)); + memcpy(buttonArr.data, group->buttons.data(), group->buttons.size() * sizeof(int)); resource->sendButtons(&buttonArr); wl_array_release(&buttonArr); - for (size_t i = 0; i < group->strip_count; ++i) { + for (size_t i = 0; i < group->strips.size(); ++i) { const auto RESOURCE = PROTO::tablet->m_vStrips.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); @@ -67,7 +68,7 @@ void CTabletPadGroupV2Resource::sendData(SP pad, wlr_tablet_pad_grou resource->sendStrip(RESOURCE->resource.get()); } - for (size_t i = 0; i < group->ring_count; ++i) { + for (size_t i = 0; i < group->rings.size(); ++i) { const auto RESOURCE = PROTO::tablet->m_vRings.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); @@ -97,23 +98,20 @@ bool CTabletPadV2Resource::good() { void CTabletPadV2Resource::sendData() { // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts - const char** path_ptr; - for (path_ptr = (const char**)(&pad->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&pad->wlr()->paths)->data + (&pad->wlr()->paths)->size); (path_ptr)++) { - resource->sendPath(*path_ptr); + for (auto& p : pad->aq()->paths) { + resource->sendPath(p.c_str()); } - resource->sendButtons(pad->wlr()->button_count); + resource->sendButtons(pad->aq()->buttons); - wlr_tablet_pad_group* group; - size_t i = 0; - wl_list_for_each(group, &pad->wlr()->groups, link) { - createGroup(group, i++); + for (size_t i = 0; i < pad->aq()->groups.size(); ++i) { + createGroup(pad->aq()->groups.at(i), i); } resource->sendDone(); } -void CTabletPadV2Resource::createGroup(wlr_tablet_pad_group* group, size_t idx) { +void CTabletPadV2Resource::createGroup(SP group, size_t idx) { const auto RESOURCE = PROTO::tablet->m_vGroups.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), idx)); @@ -142,13 +140,10 @@ bool CTabletV2Resource::good() { void CTabletV2Resource::sendData() { resource->sendName(tablet->deviceName.c_str()); - resource->sendId(tablet->wlr()->usb_vendor_id, tablet->wlr()->usb_product_id); + resource->sendId(tablet->aq()->usbVendorID, tablet->aq()->usbProductID); - // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts - const char** path_ptr; - for (path_ptr = (const char**)(&tablet->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&tablet->wlr()->paths)->data + (&tablet->wlr()->paths)->size); - (path_ptr)++) { - resource->sendPath(*path_ptr); + for (auto& p : tablet->aq()->paths) { + resource->sendPath(p.c_str()); } resource->sendDone(); @@ -179,23 +174,23 @@ bool CTabletToolV2Resource::good() { } void CTabletToolV2Resource::sendData() { - static auto WLR_TYPE_TO_PROTO = [](uint32_t wlr) -> zwpTabletToolV2Type { - switch (wlr) { - case WLR_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN; - case WLR_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER; - case WLR_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH; - case WLR_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL; - case WLR_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH; - case WLR_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE; - case WLR_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS; + static auto AQ_TYPE_TO_PROTO = [](uint32_t aq) -> zwpTabletToolV2Type { + switch (aq) { + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS; default: ASSERT(false); } UNREACHABLE(); }; - resource->sendType(WLR_TYPE_TO_PROTO(tool->wlr()->type)); - resource->sendHardwareSerial(tool->wlr()->hardware_serial >> 32, tool->wlr()->hardware_serial & 0xFFFFFFFF); - resource->sendHardwareIdWacom(tool->wlr()->hardware_wacom >> 32, tool->wlr()->hardware_wacom & 0xFFFFFFFF); + resource->sendType(AQ_TYPE_TO_PROTO(tool->aq()->type)); + resource->sendHardwareSerial(tool->aq()->serial >> 32, tool->aq()->serial & 0xFFFFFFFF); + resource->sendHardwareIdWacom(tool->aq()->id >> 32, tool->aq()->id & 0xFFFFFFFF); if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_DISTANCE) resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE); if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_PRESSURE) diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp index 58f13c1a..1ebcb1e5 100644 --- a/src/protocols/Tablet.hpp +++ b/src/protocols/Tablet.hpp @@ -6,6 +6,7 @@ #include "WaylandProtocol.hpp" #include "tablet-v2.hpp" #include "../helpers/math/Math.hpp" +#include class CTablet; class CTabletTool; @@ -51,7 +52,7 @@ class CTabletPadGroupV2Resource { CTabletPadGroupV2Resource(SP resource_, size_t idx); bool good(); - void sendData(SP pad, wlr_tablet_pad_group* group); + void sendData(SP pad, SP group); std::vector> rings; std::vector> strips; @@ -83,7 +84,7 @@ class CTabletPadV2Resource { private: SP resource; - void createGroup(wlr_tablet_pad_group* group, size_t idx); + void createGroup(SP group, size_t idx); friend class CTabletSeat; friend class CTabletV2Protocol; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index d4c66c3b..0e78e5f7 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -193,16 +193,11 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou return; } - if (PMONITOR->output->allocator && (PMONITOR->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) { - PFRAME->dmabufFormat = PMONITOR->output->render_format; - } else { - PFRAME->dmabufFormat = DRM_FORMAT_INVALID; - } + PFRAME->dmabufFormat = PMONITOR->output->state->state().drmFormat; PFRAME->box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)}; - int ow, oh; - wlr_output_effective_resolution(PMONITOR->output, &ow, &oh); - PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), ow, oh).round(); + + PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round(); PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); @@ -289,12 +284,10 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r m_vFramesAwaitingWrite.emplace_back(PFRAME); } -void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) { +void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor) { if (m_vFramesAwaitingWrite.empty()) return; // nothing to share - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(e->output); - std::vector framesToRemove; // share frame if correct output @@ -306,7 +299,7 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp continue; } - if (PMONITOR != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) + if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) continue; CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; @@ -370,7 +363,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times g_pHyprRenderer->makeEGLCurrent(); CFramebuffer outFB; - outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->drmFormat); + outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->output->state->state().drmFormat); if (frame->overlayCursor) { g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index f044a781..c3620d41 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -21,7 +21,7 @@ class CToplevelExportProtocolManager { void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage); void displayDestroy(); void onWindowUnmap(PHLWINDOW pWindow); - void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e); + void onOutputCommit(CMonitor* pMonitor); private: wl_global* m_pGlobal = nullptr; diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp index 8cb69dbe..03c5775e 100644 --- a/src/protocols/Viewporter.cpp +++ b/src/protocols/Viewporter.cpp @@ -52,6 +52,21 @@ CViewportResource::CViewportResource(SP resource_, SPpending.viewport.hasSource = true; surface->pending.viewport.source = {x, y, w, h}; }); + + listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) { + if (!surface || !surface->pending.buffer) + return; + + if (surface->pending.viewport.hasSource) { + auto& src = surface->pending.viewport.source; + + if (src.w + src.x > surface->pending.buffer->size.x || src.h + src.y > surface->pending.buffer->size.y) { + resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit"); + surface->pending.rejected = true; + return; + } + } + }); } CViewportResource::~CViewportResource() { @@ -66,20 +81,6 @@ bool CViewportResource::good() { return resource->resource(); } -void CViewportResource::verify() { - if (!surface) - return; - - if (surface->pending.viewport.hasSource) { - auto& src = surface->pending.viewport.source; - - if (src.w + src.x > surface->pending.size.x || src.h + src.y > surface->pending.size.y) { - resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit"); - return; - } - } -} - CViewporterResource::CViewporterResource(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/Viewporter.hpp b/src/protocols/Viewporter.hpp index 01278203..3c2a4eef 100644 --- a/src/protocols/Viewporter.hpp +++ b/src/protocols/Viewporter.hpp @@ -15,11 +15,14 @@ class CViewportResource { ~CViewportResource(); bool good(); - void verify(); WP surface; private: SP resource; + + struct { + CHyprSignalListener surfacePrecommit; + } listeners; }; class CViewporterResource { diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 009c277c..2642ec11 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -1,12 +1,9 @@ #include "VirtualKeyboard.hpp" #include +#include "../devices/IKeyboard.hpp" #define LOGM PROTO::virtualKeyboard->protoLog -static const struct wlr_keyboard_impl virtualKeyboardImpl = { - .name = "virtual-keyboard", -}; - CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { if (!good()) return; @@ -28,13 +25,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; } - wlr_keyboard_key_event event = { - .time_msec = timeMs, - .keycode = key, - .update_state = false, - .state = (wl_keyboard_key_state)state, - }; - wlr_keyboard_notify_key(&keyboard, &event); + events.key.emit(IKeyboard::SKeyEvent{ + .timeMs = timeMs, + .keycode = key, + .state = (wl_keyboard_key_state)state, + }); + + const bool CONTAINS = std::find(pressed.begin(), pressed.end(), key) != pressed.end(); + if (state && !CONTAINS) + pressed.emplace_back(key); + else if (!state && CONTAINS) + std::erase(pressed, key); }); resource->setModifiers([this](CZwpVirtualKeyboardV1* r, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { @@ -43,7 +44,12 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; } - wlr_keyboard_notify_modifiers(&keyboard, depressed, latched, locked, group); + events.modifiers.emit(IKeyboard::SModifiersEvent{ + .depressed = depressed, + .latched = latched, + .locked = locked, + .group = group, + }); }); resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) { @@ -75,7 +81,9 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; } - wlr_keyboard_set_keymap(&keyboard, xkbKeymap); + events.keymap.emit(IKeyboard::SKeymapEvent{ + .keymap = xkbKeymap, + }); hasKeymap = true; xkb_keymap_unref(xkbKeymap); @@ -83,22 +91,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP close(fd); }); - wlr_keyboard_init(&keyboard, &virtualKeyboardImpl, "CVirtualKeyboard"); + name = "hl-virtual-keyboard"; } CVirtualKeyboardV1Resource::~CVirtualKeyboardV1Resource() { events.destroy.emit(); - wlr_keyboard_finish(&keyboard); } bool CVirtualKeyboardV1Resource::good() { return resource->resource(); } -wlr_keyboard* CVirtualKeyboardV1Resource::wlr() { - return &keyboard; -} - wl_client* CVirtualKeyboardV1Resource::client() { return resource->resource() ? resource->client() : nullptr; } @@ -106,17 +109,16 @@ wl_client* CVirtualKeyboardV1Resource::client() { void CVirtualKeyboardV1Resource::releasePressed() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - size_t keycodesNum = keyboard.num_keycodes; - for (size_t i = 0; i < keycodesNum; ++i) { - struct wlr_keyboard_key_event event = { - .time_msec = (now.tv_sec * 1000 + now.tv_nsec / 1000000), - .keycode = keyboard.keycodes[keycodesNum - i - 1], - .update_state = false, - .state = WL_KEYBOARD_KEY_STATE_RELEASED, - }; - wlr_keyboard_notify_key(&keyboard, &event); // updates num_keycodes + for (auto& p : pressed) { + events.key.emit(IKeyboard::SKeyEvent{ + .timeMs = now.tv_sec * 1000 + now.tv_nsec / 1000000, + .keycode = p, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + }); } + + pressed.clear(); } CVirtualKeyboardProtocol::CVirtualKeyboardProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp index 447b5db9..93b63bb5 100644 --- a/src/protocols/VirtualKeyboard.hpp +++ b/src/protocols/VirtualKeyboard.hpp @@ -14,19 +14,24 @@ class CVirtualKeyboardV1Resource { struct { CSignal destroy; + CSignal key; + CSignal modifiers; + CSignal keymap; } events; - bool good(); - wlr_keyboard* wlr(); - wl_client* client(); + bool good(); + wl_client* client(); + + std::string name = ""; private: SP resource; - wlr_keyboard keyboard; void releasePressed(); bool hasKeymap = false; + + std::vector pressed; }; class CVirtualKeyboardProtocol : public IWaylandProtocol { diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index 1fb83888..bdeec32d 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -2,10 +2,6 @@ #define LOGM PROTO::virtualPointer->protoLog -static const wlr_pointer_impl pointerImpl = { - .name = "virtual-pointer-v1", -}; - CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_) : resource(resource_) { if (!good()) return; @@ -19,41 +15,30 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r PROTO::virtualPointer->destroyResource(this); }); - wlr_pointer_init(&pointer, &pointerImpl, "CVirtualPointerV1Resource"); - resource->setMotion([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, wl_fixed_t dx, wl_fixed_t dy) { - wlr_pointer_motion_event event = { - .pointer = &pointer, - .time_msec = timeMs, - .delta_x = wl_fixed_to_double(dx), - .delta_y = wl_fixed_to_double(dy), - .unaccel_dx = wl_fixed_to_double(dx), - .unaccel_dy = wl_fixed_to_double(dy), - }; - wl_signal_emit_mutable(&pointer.events.motion, &event); + events.move.emit(IPointer::SMotionEvent{ + .timeMs = timeMs, + .delta = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)}, + .unaccel = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)}, + }); }); resource->setMotionAbsolute([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t x, uint32_t y, uint32_t xExtent, uint32_t yExtent) { if (!xExtent || !yExtent) return; - wlr_pointer_motion_absolute_event event = { - .pointer = &pointer, - .time_msec = timeMs, - .x = (double)x / xExtent, - .y = (double)y / yExtent, - }; - wl_signal_emit_mutable(&pointer.events.motion_absolute, &event); + events.warp.emit(IPointer::SMotionAbsoluteEvent{ + .timeMs = timeMs, + .absolute = {(double)x / xExtent, (double)y / yExtent}, + }); }); resource->setButton([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t button, uint32_t state) { - struct wlr_pointer_button_event event = { - .pointer = &pointer, - .time_msec = timeMs, - .button = button, - .state = (wl_pointer_button_state)state, - }; - wl_signal_emit_mutable(&pointer.events.button, &event); + events.button.emit(IPointer::SButtonEvent{ + .timeMs = timeMs, + .button = button, + .state = (wl_pointer_button_state)state, + }); }); resource->setAxis([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value) { @@ -63,18 +48,18 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r } axis = axis_; - axisEvents[axis] = wlr_pointer_axis_event{.pointer = &pointer, .time_msec = timeMs, .orientation = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)}; + axisEvents[axis] = IPointer::SAxisEvent{.timeMs = timeMs, .axis = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)}; }); resource->setFrame([this](CZwlrVirtualPointerV1* r) { for (auto& e : axisEvents) { - if (!e.pointer) + if (!e.timeMs) continue; - wl_signal_emit_mutable(&pointer.events.axis, &e); - e.pointer = nullptr; + events.axis.emit(e); + e.timeMs = 0; } - wl_signal_emit_mutable(&pointer.events.frame, &pointer); + events.frame.emit(); }); resource->setAxisSource([this](CZwlrVirtualPointerV1* r, uint32_t source) { axisEvents[axis].source = (wl_pointer_axis_source)source; }); @@ -85,12 +70,11 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r return; } - axis = axis_; - axisEvents[axis].pointer = &pointer; - axisEvents[axis].time_msec = timeMs; - axisEvents[axis].orientation = (wl_pointer_axis)axis; - axisEvents[axis].delta = 0; - axisEvents[axis].delta_discrete = 0; + axis = axis_; + axisEvents[axis].timeMs = timeMs; + axisEvents[axis].axis = (wl_pointer_axis)axis; + axisEvents[axis].delta = 0; + axisEvents[axis].deltaDiscrete = 0; }); resource->setAxisDiscrete([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value, int32_t discrete) { @@ -99,17 +83,15 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r return; } - axis = axis_; - axisEvents[axis].pointer = &pointer; - axisEvents[axis].time_msec = timeMs; - axisEvents[axis].orientation = (wl_pointer_axis)axis; - axisEvents[axis].delta = wl_fixed_to_double(value); - axisEvents[axis].delta_discrete = discrete * 120; + axis = axis_; + axisEvents[axis].timeMs = timeMs; + axisEvents[axis].axis = (wl_pointer_axis)axis; + axisEvents[axis].delta = wl_fixed_to_double(value); + axisEvents[axis].deltaDiscrete = discrete * 120; }); } CVirtualPointerV1Resource::~CVirtualPointerV1Resource() { - wlr_pointer_finish(&pointer); events.destroy.emit(); } @@ -117,10 +99,6 @@ bool CVirtualPointerV1Resource::good() { return resource->resource(); } -wlr_pointer* CVirtualPointerV1Resource::wlr() { - return &pointer; -} - wl_client* CVirtualPointerV1Resource::client() { return resource->client(); } diff --git a/src/protocols/VirtualPointer.hpp b/src/protocols/VirtualPointer.hpp index 59a7e739..ee5ee7e2 100644 --- a/src/protocols/VirtualPointer.hpp +++ b/src/protocols/VirtualPointer.hpp @@ -7,6 +7,7 @@ #include "WaylandProtocol.hpp" #include "wlr-virtual-pointer-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include "../devices/IPointer.hpp" class CVirtualPointerV1Resource { public: @@ -15,19 +16,35 @@ class CVirtualPointerV1Resource { struct { CSignal destroy; + CSignal move; + CSignal warp; + CSignal button; + CSignal axis; + CSignal frame; + + CSignal swipeBegin; + CSignal swipeUpdate; + CSignal swipeEnd; + + CSignal pinchBegin; + CSignal pinchUpdate; + CSignal pinchEnd; + + CSignal holdBegin; + CSignal holdEnd; } events; - bool good(); - wlr_pointer* wlr(); - wl_client* client(); + bool good(); + wl_client* client(); + + std::string name; private: - SP resource; - wlr_pointer pointer; + SP resource; - uint32_t axis = 0; + uint32_t axis = 0; - std::array axisEvents; + std::array axisEvents; }; class CVirtualPointerProtocol : public IWaylandProtocol { diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 03e58956..073aa502 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -75,8 +75,8 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 if (XDGVER >= OUTPUT_NAME_SINCE_VERSION) pXDGOutput->resource->sendName(PMONITOR->szName.c_str()); - if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && PMONITOR->output->description) - pXDGOutput->resource->sendDescription(PMONITOR->output->description); + if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && !PMONITOR->output->description.empty()) + pXDGOutput->resource->sendDescription(PMONITOR->output->description.c_str()); pXDGOutput->sendDetails(); @@ -93,7 +93,7 @@ void CXDGOutputProtocol::updateAllOutputs() { o->sendDetails(); - wlr_output_schedule_done(o->monitor->output); + o->monitor->scheduleDone(); } } diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 9c56df93..8276ed55 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -4,6 +4,7 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" +#include #define LOGM PROTO::xdgShell->protoLog diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 691267b0..5cd6005a 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -6,6 +6,9 @@ #include "Subcompositor.hpp" #include "../Viewporter.hpp" #include "../../helpers/Monitor.hpp" +#include "../PresentationTime.hpp" +#include "../DRMSyncobj.hpp" +#include "../../render/Renderer.hpp" #define LOGM PROTO::compositor->protoLog @@ -102,58 +105,14 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso pending.size = tfs / pending.scale; } - if (viewportResource) - viewportResource->verify(); - pending.damage.intersect(CBox{{}, pending.size}); - auto previousBuffer = current.buffer; - CRegion previousBufferDamage = accumulateCurrentBufferDamage(); + events.precommit.emit(); + if (pending.rejected) + return; - current = pending; - pending.damage.clear(); - pending.bufferDamage.clear(); - - if (current.buffer && !bufferReleased) { - // without previous dolphin et al are weird vvv - //CRegion surfaceDamage = - // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); - current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. - - // release the buffer if it's synchronous as update() has done everything thats needed - // so we can let the app know we're done. - if (current.buffer->isSynchronous()) { - current.buffer->sendRelease(); - bufferReleased = true; - } - } - - // TODO: we should _accumulate_ and not replace above if sync - if (role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)role.get(); - if (subsurface->sync) - return; - - events.commit.emit(); - } else { - // send commit to all synced surfaces in this tree. - breadthfirst( - [](SP surf, const Vector2D& offset, void* data) { - if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)surf->role.get(); - if (!subsurface->sync) - return; - } - surf->events.commit.emit(); - }, - nullptr); - } - - // for async buffers, we can only release the buffer once we are unrefing it from current. - if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) { - previousBuffer->sendRelease(); - bufferReleased = true; - } + if (stateLocks <= 0) + commitPendingState(); }); resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); }); @@ -426,7 +385,97 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; - return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(wlr_output_transform_invert(current.transform)), trc.x, trc.y).add(current.bufferDamage); + return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage); +} + +void CWLSurfaceResource::lockPendingState() { + stateLocks++; +} + +void CWLSurfaceResource::unlockPendingState() { + stateLocks--; + if (stateLocks <= 0) + commitPendingState(); +} + +void CWLSurfaceResource::commitPendingState() { + auto previousBuffer = current.buffer; + CRegion previousBufferDamage = accumulateCurrentBufferDamage(); + + current = pending; + pending.damage.clear(); + pending.bufferDamage.clear(); + + if (current.buffer && !bufferReleased) { + // without previous dolphin et al are weird vvv + //CRegion surfaceDamage = + // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); + current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. + + // release the buffer if it's synchronous as update() has done everything thats needed + // so we can let the app know we're done. + if (current.buffer->isSynchronous()) { + current.buffer->sendReleaseWithSurface(self.lock()); + bufferReleased = true; + } + } + + // TODO: we should _accumulate_ and not replace above if sync + if (role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)role.get(); + if (subsurface->sync) + return; + + events.commit.emit(); + } else { + // send commit to all synced surfaces in this tree. + breadthfirst( + [](SP surf, const Vector2D& offset, void* data) { + if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)surf->role.get(); + if (!subsurface->sync) + return; + } + surf->events.commit.emit(); + }, + nullptr); + } + + // for async buffers, we can only release the buffer once we are unrefing it from current. + if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) { + if (previousBuffer->lockedByBackend) { + previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) { + if (!self.expired()) // could be dead in the dtor + previousBuffer->sendReleaseWithSurface(self.lock()); + else + previousBuffer->sendRelease(); + previousBuffer->hlEvents.backendRelease.reset(); + bufferReleased = true; + }); + } else + previousBuffer->sendReleaseWithSurface(self.lock()); + + bufferReleased = true; + } +} + +void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) { + frame(when); + auto FEEDBACK = makeShared(self.lock()); + FEEDBACK->attachMonitor(pMonitor); + FEEDBACK->discarded(); + PROTO::presentation->queueData(FEEDBACK); + + if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync) + return; + + // attach explicit sync + g_pHyprRenderer->explicitPresented.emplace_back(self.lock()); + + if (syncobj->acquirePoint > pMonitor->lastWaitPoint) { + Debug::log(TRACE, "presentFeedback lastWaitPoint {} -> {}", pMonitor->lastWaitPoint, syncobj->acquirePoint); + pMonitor->lastWaitPoint = syncobj->acquirePoint; + } } CWLCompositorResource::CWLCompositorResource(SP resource_) : resource(resource_) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 2f276719..5e6413c8 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -24,6 +24,7 @@ class CWLSurface; class CWLSurfaceResource; class CWLSubsurfaceResource; class CViewportResource; +class CDRMSyncobjSurfaceResource; class CWLCallbackResource { public: @@ -74,6 +75,7 @@ class CWLSurfaceResource { Vector2D sourceSize(); struct { + CSignal precommit; CSignal commit; CSignal map; CSignal unmap; @@ -81,11 +83,11 @@ class CWLSurfaceResource { CSignal destroy; } events; - struct { + struct SState { CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; int scale = 1; - SP buffer; + SP buffer; SP texture; Vector2D offset; Vector2D size; @@ -95,6 +97,7 @@ class CWLSurfaceResource { Vector2D destination; CBox source; } viewport; + bool rejected = false; // void reset() { @@ -115,9 +118,13 @@ class CWLSurfaceResource { std::vector> subsurfaces; WP role; WP viewportResource; + WP syncobj; // may not be present void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); + void presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync = false); + void lockPendingState(); + void unlockPendingState(); // returns a pair: found surface (null if not found) and surface local coords. // localCoords param is relative to 0,0 of this surface @@ -130,7 +137,10 @@ class CWLSurfaceResource { // tracks whether we should release the buffer bool bufferReleased = false; + int stateLocks = 0; + void destroy(); + void commitPendingState(); void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); }; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 10daa15e..4ba23cbe 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -21,8 +21,8 @@ CWLOutputResource::CWLOutputResource(SP resource_, SP pMoni PROTO::outputs.at(monitor->szName)->destroyResource(this); }); - resource->sendGeometry(0, 0, monitor->output->phys_width, monitor->output->phys_height, monitor->output->subpixel, monitor->output->make ? monitor->output->make : "null", - monitor->output->model ? monitor->output->model : "null", monitor->transform); + resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(), + monitor->output->model.c_str(), monitor->transform); if (resource->version() >= 4) { resource->sendName(monitor->szName.c_str()); resource->sendDescription(monitor->szDescription.c_str()); @@ -115,3 +115,9 @@ void CWLOutputProtocol::remove() { bool CWLOutputProtocol::isDefunct() { return defunct; } + +void CWLOutputProtocol::sendDone() { + for (auto& r : m_vOutputs) { + r->resource->sendDone(); + } +} diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp index 46981635..46e4057b 100644 --- a/src/protocols/core/Output.hpp +++ b/src/protocols/core/Output.hpp @@ -26,6 +26,8 @@ class CWLOutputResource { private: SP resource; wl_client* pClient = nullptr; + + friend class CWLOutputProtocol; }; class CWLOutputProtocol : public IWaylandProtocol { @@ -35,6 +37,7 @@ class CWLOutputProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); SP outputResourceFrom(wl_client* client); + void sendDone(); WP monitor; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 464a901c..21a47575 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -254,8 +254,8 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { int fd; uint32_t size; if (keyboard) { - fd = keyboard->wlr()->keymap_fd; - size = keyboard->wlr()->keymap_size; + fd = keyboard->xkbKeymapFD; + size = keyboard->xkbKeymapString.length() + 1; } else { fd = open("/dev/null", O_RDONLY | O_CLOEXEC); if (fd < 0) { diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 4088949f..75c2134a 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -41,20 +41,20 @@ CWLSHMBuffer::~CWLSHMBuffer() { ; } -eBufferCapability CWLSHMBuffer::caps() { - return BUFFER_CAPABILITY_DATAPTR; +Aquamarine::eBufferCapability CWLSHMBuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } -eBufferType CWLSHMBuffer::type() { - return BUFFER_TYPE_SHM; +Aquamarine::eBufferType CWLSHMBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_SHM; } bool CWLSHMBuffer::isSynchronous() { return true; } -SSHMAttrs CWLSHMBuffer::shm() { - SSHMAttrs attrs; +Aquamarine::SSHMAttrs CWLSHMBuffer::shm() { + Aquamarine::SSHMAttrs attrs; attrs.success = true; attrs.fd = pool->fd; attrs.format = FormatUtils::shmToDRM(fmt); @@ -188,11 +188,18 @@ CWLSHMProtocol::CWLSHMProtocol(const wl_interface* iface, const int& ver, const void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { if (shmFormats.empty()) { - size_t len = 0; - const uint32_t* formats = wlr_renderer_get_shm_texture_formats(g_pCompositor->m_sWLRRenderer, &len); + shmFormats.push_back(WL_SHM_FORMAT_ARGB8888); + shmFormats.push_back(WL_SHM_FORMAT_XRGB8888); - for (size_t i = 0; i < len; ++i) { - shmFormats.push_back(FormatUtils::drmToShm(formats[i])); + static const std::array supportedShmFourccFormats = { + DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010, + }; + + for (auto& fmt : g_pHyprOpenGL->getDRMFormats()) { + if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end()) + continue; + + shmFormats.push_back(fmt.drmFormat); } } diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index 70a8b208..fab325fe 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -29,16 +29,16 @@ class CSHMPool { void resize(size_t size); }; -class CWLSHMBuffer : public IWLBuffer { +class CWLSHMBuffer : public IHLBuffer { public: CWLSHMBuffer(SP pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt); virtual ~CWLSHMBuffer(); - virtual eBufferCapability caps(); - virtual eBufferType type(); + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); virtual void update(const CRegion& damage); virtual bool isSynchronous(); - virtual SSHMAttrs shm(); + virtual Aquamarine::SSHMAttrs shm(); virtual std::tuple beginDataPtr(uint32_t flags); virtual void endDataPtr(); diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp index 5ed942e1..0217f7e2 100644 --- a/src/protocols/types/Buffer.cpp +++ b/src/protocols/types/Buffer.cpp @@ -1,41 +1,10 @@ #include "Buffer.hpp" -#include "WLBuffer.hpp" -SDMABUFAttrs IWLBuffer::dmabuf() { - return SDMABUFAttrs{}; +void IHLBuffer::sendRelease() { + resource->sendRelease(); } -SSHMAttrs IWLBuffer::shm() { - return SSHMAttrs{}; -} - -std::tuple IWLBuffer::beginDataPtr(uint32_t flags) { - return {nullptr, 0, 0}; -} - -void IWLBuffer::endDataPtr() { - ; // empty -} - -void IWLBuffer::sendRelease() { - if (!resource || !resource->resource) - return; - resource->resource->sendRelease(); -} - -void IWLBuffer::lock() { - locks++; -} - -void IWLBuffer::unlock() { - locks--; - - ASSERT(locks >= 0); - - if (locks <= 0) - sendRelease(); -} - -bool IWLBuffer::locked() { - return locks; +void IHLBuffer::sendReleaseWithSurface(SP surf) { + if (resource && resource->good()) + resource->sendReleaseWithSurface(surf); } diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index 9999a4e9..ba8278f3 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -1,75 +1,29 @@ #pragma once #include "../../defines.hpp" -#include "../../helpers/signal/Signal.hpp" #include "../../render/Texture.hpp" +#include "./WLBuffer.hpp" -#include -#include +#include -enum eBufferCapability { - BUFFER_CAPABILITY_DATAPTR = (1 << 0), -}; - -enum eBufferType { - BUFFER_TYPE_DMABUF = 0, - BUFFER_TYPE_SHM, - BUFFER_TYPE_MISC, -}; - -class CWLBufferResource; - -struct SDMABUFAttrs { - bool success = false; - Vector2D size; - uint32_t format = 0; // fourcc - uint64_t modifier = 0; - - int planes = 1; - std::array offsets = {0}; - std::array strides = {0}; - std::array fds = {-1, -1, -1, -1}; -}; - -struct SSHMAttrs { - bool success = false; - int fd = 0; - uint32_t format = 0; - Vector2D size; - int stride = 0; - int64_t offset = 0; -}; - -class IWLBuffer { +class IHLBuffer : public Aquamarine::IBuffer { public: - virtual ~IWLBuffer() { + virtual ~IHLBuffer() { ; - }; + } + virtual Aquamarine::eBufferCapability caps() = 0; + virtual Aquamarine::eBufferType type() = 0; + virtual void update(const CRegion& damage) = 0; + virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu + virtual bool good() = 0; + virtual void sendRelease(); + virtual void sendReleaseWithSurface(SP); - virtual eBufferCapability caps() = 0; - virtual eBufferType type() = 0; - virtual void update(const CRegion& damage) = 0; - virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu - virtual SDMABUFAttrs dmabuf(); - virtual SSHMAttrs shm(); - virtual std::tuple beginDataPtr(uint32_t flags); - virtual void endDataPtr(); - virtual void sendRelease(); - virtual void lock(); - virtual void unlock(); - virtual bool locked(); - - Vector2D size; - bool opaque = false; - - SP resource; - - SP texture; + SP texture; + bool opaque = false; + SP resource; struct { - CSignal destroy; - } events; - - private: - int locks = 0; + CHyprSignalListener backendRelease; + } hlEvents; }; diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index 7c3a9886..63a26c76 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -3,7 +3,7 @@ #include "../../render/Renderer.hpp" #include "../../helpers/Format.hpp" -CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_) : attrs(attrs_) { +CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_) : attrs(attrs_) { g_pHyprRenderer->makeEGLCurrent(); listeners.resourceDestroy = events.destroy.registerListener([this](std::any d) { @@ -31,12 +31,12 @@ CDMABuffer::~CDMABuffer() { closeFDs(); } -eBufferCapability CDMABuffer::caps() { - return BUFFER_CAPABILITY_DATAPTR; +Aquamarine::eBufferCapability CDMABuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } -eBufferType CDMABuffer::type() { - return BUFFER_TYPE_DMABUF; +Aquamarine::eBufferType CDMABuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_DMABUF; } void CDMABuffer::update(const CRegion& damage) { @@ -47,7 +47,7 @@ bool CDMABuffer::isSynchronous() { return false; } -SDMABUFAttrs CDMABuffer::dmabuf() { +Aquamarine::SDMABUFAttrs CDMABuffer::dmabuf() { return attrs; } diff --git a/src/protocols/types/DMABuffer.hpp b/src/protocols/types/DMABuffer.hpp index d07840b7..6977df4c 100644 --- a/src/protocols/types/DMABuffer.hpp +++ b/src/protocols/types/DMABuffer.hpp @@ -2,16 +2,16 @@ #include "Buffer.hpp" -class CDMABuffer : public IWLBuffer { +class CDMABuffer : public IHLBuffer { public: - CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_); + CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_); virtual ~CDMABuffer(); - virtual eBufferCapability caps(); - virtual eBufferType type(); + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); virtual bool isSynchronous(); virtual void update(const CRegion& damage); - virtual SDMABUFAttrs dmabuf(); + virtual Aquamarine::SDMABUFAttrs dmabuf(); virtual std::tuple beginDataPtr(uint32_t flags); virtual void endDataPtr(); bool good(); @@ -21,7 +21,7 @@ class CDMABuffer : public IWLBuffer { bool success = false; private: - SDMABUFAttrs attrs; + Aquamarine::SDMABUFAttrs attrs; struct { CHyprSignalListener resourceDestroy; diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index e53538cb..d34a867d 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -1,5 +1,10 @@ #include "WLBuffer.hpp" #include "Buffer.hpp" +#include "../core/Compositor.hpp" +#include "../DRMSyncobj.hpp" +#include "../../helpers/sync/SyncTimeline.hpp" +#include "../../Compositor.hpp" +#include CWLBufferResource::CWLBufferResource(SP resource_) : resource(resource_) { if (!good()) @@ -27,6 +32,16 @@ void CWLBufferResource::sendRelease() { resource->sendRelease(); } +void CWLBufferResource::sendReleaseWithSurface(SP surf) { + sendRelease(); + + if (!surf || !surf->syncobj) + return; + + if (drmSyncobjTimelineSignal(g_pCompositor->m_iDRMFD, &surf->syncobj->releaseTimeline->timeline->handle, &surf->syncobj->releasePoint, 1)) + Debug::log(ERR, "sendReleaseWithSurface: drmSyncobjTimelineSignal failed"); +} + wl_resource* CWLBufferResource::getResource() { return resource->resource(); } diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp index ac177965..59512128 100644 --- a/src/protocols/types/WLBuffer.hpp +++ b/src/protocols/types/WLBuffer.hpp @@ -7,7 +7,8 @@ #include "wayland.hpp" #include "../../helpers/signal/Signal.hpp" -class IWLBuffer; +class IHLBuffer; +class CWLSurfaceResource; class CWLBufferResource { public: @@ -16,9 +17,10 @@ class CWLBufferResource { bool good(); void sendRelease(); + void sendReleaseWithSurface(SP); wl_resource* getResource(); - WP buffer; + WP buffer; WP self; @@ -27,5 +29,5 @@ class CWLBufferResource { SP resource; - friend class IWLBuffer; + friend class IHLBuffer; }; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index e127ec2d..b2b046ce 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -9,6 +9,9 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/core/Compositor.hpp" #include +#include +#include +#include inline void loadGLProc(void* pProc, const char* name) { void* proc = (void*)eglGetProcAddress(name); @@ -19,17 +22,203 @@ inline void loadGLProc(void* pProc, const char* name) { *(void**)pProc = proc; } +static enum LogLevel eglLogToLevel(EGLint type) { + switch (type) { + case EGL_DEBUG_MSG_CRITICAL_KHR: return CRIT; + case EGL_DEBUG_MSG_ERROR_KHR: return ERR; + case EGL_DEBUG_MSG_WARN_KHR: return WARN; + case EGL_DEBUG_MSG_INFO_KHR: return LOG; + default: return LOG; + } +} + +static const char* eglErrorToString(EGLint error) { + switch (error) { + case EGL_SUCCESS: return "EGL_SUCCESS"; + case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; + case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; + case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; + case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; + case EGL_BAD_DEVICE_EXT: return "EGL_BAD_DEVICE_EXT"; + case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; + case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; + case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; + case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; + case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; + } + return "Unknown"; +} + +static void eglLog(EGLenum error, const char* command, EGLint type, EGLLabelKHR thread, EGLLabelKHR obj, const char* msg) { + Debug::log(eglLogToLevel(type), "[EGL] Command {} errored out with {} (0x{}): {}", command, eglErrorToString(error), error, msg); +} + +static int openRenderNode(int drmFd) { + auto renderName = drmGetRenderDeviceNameFromFd(drmFd); + if (!renderName) { + // This can happen on split render/display platforms, fallback to + // primary node + renderName = drmGetPrimaryDeviceNameFromFd(drmFd); + if (!renderName) { + Debug::log(ERR, "drmGetPrimaryDeviceNameFromFd failed"); + return -1; + } + Debug::log(LOG, "DRM dev {} has no render node, falling back to primary", renderName); + + drmVersion* render_version = drmGetVersion(drmFd); + if (render_version && render_version->name) { + Debug::log(LOG, "DRM dev versionName", render_version->name); + if (strcmp(render_version->name, "evdi") == 0) { + free(renderName); + renderName = (char*)malloc(sizeof(char) * 15); + strcpy(renderName, "/dev/dri/card0"); + } + drmFreeVersion(render_version); + } + } + + Debug::log(LOG, "openRenderNode got drm device {}", renderName); + + int renderFD = open(renderName, O_RDWR | O_CLOEXEC); + if (renderFD < 0) + Debug::log(ERR, "openRenderNode failed to open drm device {}", renderName); + + free(renderName); + return renderFD; +} + +void CHyprOpenGLImpl::initEGL(bool gbm) { + std::vector attrs; + if (m_sExts.KHR_display_reference) { + attrs.push_back(EGL_TRACK_REFERENCES_KHR); + attrs.push_back(EGL_TRUE); + } + + attrs.push_back(EGL_NONE); + + m_pEglDisplay = m_sProc.eglGetPlatformDisplayEXT(gbm ? EGL_PLATFORM_GBM_KHR : EGL_PLATFORM_DEVICE_EXT, gbm ? m_pGbmDevice : nullptr, attrs.data()); + if (m_pEglDisplay == EGL_NO_DISPLAY) + RASSERT(false, "EGL: failed to create a platform display"); + + attrs.clear(); + + EGLint major, minor; + if (eglInitialize(m_pEglDisplay, &major, &minor) == EGL_FALSE) + RASSERT(false, "EGL: failed to initialize a platform display"); + + const std::string EGLEXTENSIONS = (const char*)eglQueryString(m_pEglDisplay, EGL_EXTENSIONS); + + m_sExts.IMG_context_priority = EGLEXTENSIONS.contains("IMG_context_priority"); + m_sExts.EXT_create_context_robustness = EGLEXTENSIONS.contains("EXT_create_context_robustness"); + m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import"); + m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers"); + + if (m_sExts.IMG_context_priority) { + Debug::log(LOG, "EGL: IMG_context_priority supported, requesting high"); + attrs.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG); + attrs.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG); + } + + if (m_sExts.EXT_create_context_robustness) { + Debug::log(LOG, "EGL: EXT_create_context_robustness supported, requesting lose on reset"); + attrs.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT); + attrs.push_back(EGL_LOSE_CONTEXT_ON_RESET_EXT); + } + + attrs.push_back(EGL_CONTEXT_MAJOR_VERSION); + attrs.push_back(3); + attrs.push_back(EGL_CONTEXT_MINOR_VERSION); + attrs.push_back(2); + attrs.push_back(EGL_CONTEXT_OPENGL_DEBUG); + attrs.push_back(ISDEBUG ? EGL_TRUE : EGL_FALSE); + + attrs.push_back(EGL_NONE); + + m_pEglContext = eglCreateContext(m_pEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attrs.data()); + if (m_pEglContext == EGL_NO_CONTEXT) + RASSERT(false, "EGL: failed to create a context"); + + if (m_sExts.IMG_context_priority) { + EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG; + eglQueryContext(m_pEglDisplay, m_pEglContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &priority); + if (priority != EGL_CONTEXT_PRIORITY_HIGH_IMG) + Debug::log(ERR, "EGL: Failed to obtain a high priority context"); + else + Debug::log(LOG, "EGL: Got a high priority context"); + } + + eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_pEglContext); +} + CHyprOpenGLImpl::CHyprOpenGLImpl() { - RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)), - "Couldn't unset current EGL!"); + const std::string EGLEXTENSIONS = (const char*)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); - auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); - const std::string EGLEXTENSIONS = (const char*)eglQueryString(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_EXTENSIONS); - - RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!"); + Debug::log(LOG, "Supported EGL extensions: ({}) {}", std::count(EGLEXTENSIONS.begin(), EGLEXTENSIONS.end(), ' '), EGLEXTENSIONS); m_iDRMFD = g_pCompositor->m_iDRMFD; + m_sExts.KHR_display_reference = EGLEXTENSIONS.contains("KHR_display_reference"); + + loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); + loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR"); + loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR"); + loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT"); + loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT"); + loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES"); + loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR"); + loadGLProc(&m_sProc.eglGetPlatformDisplayEXT, "eglGetPlatformDisplayEXT"); + loadGLProc(&m_sProc.eglCreateSyncKHR, "eglCreateSyncKHR"); + loadGLProc(&m_sProc.eglDestroySyncKHR, "eglDestroySyncKHR"); + loadGLProc(&m_sProc.eglDupNativeFenceFDANDROID, "eglDupNativeFenceFDANDROID"); + loadGLProc(&m_sProc.eglWaitSyncKHR, "eglWaitSyncKHR"); + + RASSERT(m_sProc.eglCreateSyncKHR, "Display driver doesn't support eglCreateSyncKHR"); + RASSERT(m_sProc.eglDupNativeFenceFDANDROID, "Display driver doesn't support eglDupNativeFenceFDANDROID"); + RASSERT(m_sProc.eglWaitSyncKHR, "Display driver doesn't support eglWaitSyncKHR"); + + if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_enumeration")) + loadGLProc(&m_sProc.eglQueryDevicesEXT, "eglQueryDevicesEXT"); + + if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_query")) { + loadGLProc(&m_sProc.eglQueryDeviceStringEXT, "eglQueryDeviceStringEXT"); + loadGLProc(&m_sProc.eglQueryDisplayAttribEXT, "eglQueryDisplayAttribEXT"); + } + + if (EGLEXTENSIONS.contains("EGL_KHR_debug")) { + loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR"); + static const EGLAttrib debugAttrs[] = { + EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, EGL_NONE, + }; + m_sProc.eglDebugMessageControlKHR(::eglLog, debugAttrs); + } + + RASSERT(eglBindAPI(EGL_OPENGL_ES_API) != EGL_FALSE, "Couldn't bind to EGL's opengl ES API. This means your gpu driver f'd up. This is not a hyprland issue."); + + // if (m_sProc.eglQueryDevicesEXT) { + // // TODO: + // } + + if (EGLEXTENSIONS.contains("KHR_platform_gbm")) { + m_iGBMFD = openRenderNode(m_iDRMFD); + if (m_iGBMFD < 0) + RASSERT(false, "Couldn't open a gbm fd"); + + m_pGbmDevice = gbm_create_device(m_iGBMFD); + if (!m_pGbmDevice) + RASSERT(false, "Couldn't open a gbm device"); + + initEGL(true); + } else + RASSERT(false, "EGL does not support KHR_platform_gbm, this is an issue with your gpu driver."); + + auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); + RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!"); + m_szExtensions = EXTENSIONS; Debug::log(LOG, "Creating the Hypr OpenGL Renderer!"); @@ -38,16 +227,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER)); Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions); - loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); - loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR"); - loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR"); - loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT"); - loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT"); - loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES"); - - m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); - m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import"); - m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers"); + m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); RASSERT(m_szExtensions.contains("GL_EXT_texture_format_BGRA8888"), "GL_EXT_texture_format_BGRA8888 support by the GPU driver is required"); @@ -74,7 +254,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast(data)); }); - RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); + RASSERT(eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); m_tGlobalTimer.reset(); } @@ -86,7 +266,7 @@ std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint fo return std::nullopt; EGLint len = 0; - if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) { + if (!m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, 0, nullptr, nullptr, &len)) { Debug::log(ERR, "EGL: Failed to query mods"); return std::nullopt; } @@ -100,7 +280,7 @@ std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint fo mods.resize(len); external.resize(len); - m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len); + m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, len, mods.data(), external.data(), &len); std::vector result; bool linearIsExternal = false; @@ -139,9 +319,9 @@ void CHyprOpenGLImpl::initDRMFormats() { Debug::log(WARN, "EGL: No mod support"); } else { EGLint len = 0; - m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), 0, nullptr, &len); + m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, 0, nullptr, &len); formats.resize(len); - m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), len, formats.data(), &len); + m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, len, formats.data(), &len); } if (formats.size() == 0) { @@ -149,7 +329,7 @@ void CHyprOpenGLImpl::initDRMFormats() { return; } - wlr_log(WLR_DEBUG, "Supported DMA-BUF formats:"); + Debug::log(LOG, "Supported DMA-BUF formats:"); std::vector dmaFormats; @@ -170,8 +350,8 @@ void CHyprOpenGLImpl::initDRMFormats() { mods.push_back(DRM_FORMAT_MOD_INVALID); dmaFormats.push_back(SDRMFormat{ - .format = fmt, - .mods = mods, + .drmFormat = fmt, + .modifiers = mods, }); std::vector> modifierData; @@ -209,7 +389,7 @@ void CHyprOpenGLImpl::initDRMFormats() { drmFormats = dmaFormats; } -EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) { +EGLImageKHR CHyprOpenGLImpl::createEGLImage(const Aquamarine::SDMABUFAttrs& attrs) { std::vector attribs; attribs.push_back(EGL_WIDTH); @@ -251,7 +431,7 @@ EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) { attribs.push_back(EGL_NONE); - EGLImageKHR image = m_sProc.eglCreateImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data()); + EGLImageKHR image = m_sProc.eglCreateImageKHR(m_pEglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data()); if (image == EGL_NO_IMAGE_KHR) { Debug::log(ERR, "EGL: EGLCreateImageKHR failed: {}", eglGetError()); return EGL_NO_IMAGE_KHR; @@ -342,7 +522,8 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool } bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { - // passes requiring introspection are the ones that need to render blur. + // passes requiring introspection are the ones that need to render blur, + // or when we are rendering to a multigpu target static auto PBLUR = CConfigValue("decoration:blur:enabled"); static auto PXRAY = CConfigValue("decoration:blur:xray"); @@ -446,7 +627,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { return false; } -void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRenderbuffer* rb, CFramebuffer* fb) { +void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP rb, CFramebuffer* fb) { m_RenderData.pMonitor = pMonitor; #ifndef GLES2 @@ -472,12 +653,12 @@ void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRe matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); - wlr_matrix_identity(m_RenderData.monitorProjection.data()); + matrixIdentity(m_RenderData.monitorProjection.data()); if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) { const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize; - wlr_matrix_translate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0); - wlr_matrix_transform(m_RenderData.monitorProjection.data(), pMonitor->transform); - wlr_matrix_translate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0); + matrixTranslate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0); + matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(pMonitor->transform)); + matrixTranslate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0); } m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; @@ -545,10 +726,10 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); - m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); - m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); - m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); + m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); } if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty()) @@ -597,7 +778,7 @@ void CHyprOpenGLImpl::end() { TRACY_GPU_ZONE("RenderEnd"); - // end the render, copy the data to the WLR framebuffer + // end the render, copy the data to the main framebuffer if (m_bOffloadedFramebuffer) { m_RenderData.damage = m_RenderData.finalDamage; m_bEndFrame = true; @@ -915,11 +1096,8 @@ void CHyprOpenGLImpl::scissor(const CBox* pBox, bool transform) { CBox newBox = *pBox; if (transform) { - int w, h; - wlr_output_transformed_resolution(m_RenderData.pMonitor->output, &w, &h); - - const auto TR = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)); - newBox.transform(TR, w, h); + const auto TR = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); + newBox.transform(TR, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); } glScissor(newBox.x, newBox.y, newBox.width, newBox.height); @@ -1008,18 +1186,18 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion box = &newBox; float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here + projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, + m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program); #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix); #endif @@ -1027,7 +1205,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r * col.a, col.g * col.a, col.b * col.a, col.a); CBox transformedBox = *box; - transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -1072,16 +1250,17 @@ void CHyprOpenGLImpl::renderTexture(SP tex, CBox* pBox, float alpha, i scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV, + SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true); + renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); scissor((CBox*)nullptr); } void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, - bool allowDim) { + bool allowDim, SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); @@ -1099,12 +1278,19 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB static auto PDT = CConfigValue("debug:damage_tracking"); // get transform - const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); float matrix[9]; projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); + + if (waitTimeline != nullptr) { + if (!waitForTimelinePoint(waitTimeline, waitPoint)) { + Debug::log(ERR, "renderTextureInternalWithDamage: failed to wait for explicit sync point {}", waitPoint); + return; + } + } CShader* shader = nullptr; @@ -1151,7 +1337,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB #ifndef GLES2 glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); #endif glUniform1i(shader->tex, 0); @@ -1187,7 +1373,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB } CBox transformedBox = newBox; - transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -1262,12 +1448,12 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { m_RenderData.renderModif.applyToBox(newBox); // get transform - const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); float matrix[9]; projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; @@ -1279,7 +1465,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { #ifndef GLES2 glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); #endif glUniform1i(shader->tex, 0); @@ -1316,12 +1502,12 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf m_RenderData.renderModif.applyToBox(newBox); // get transform - const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); float matrix[9]; projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE; @@ -1330,7 +1516,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf #ifndef GLES2 glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); #endif glUniform1i(shader->tex, 0); @@ -1374,13 +1560,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glDisable(GL_STENCIL_TEST); // get transforms for the full monitor - const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)); + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); float matrix[9]; CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; projectBox(matrix, MONITORBOX, TRANSFORM, 0, m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); // get the config settings static auto PBLURSIZE = CConfigValue("decoration:blur:size"); @@ -1390,9 +1576,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // prep damage CRegion damage{*originalDamage}; - wlr_region_transform(damage.pixman(), damage.pixman(), wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x, - m_RenderData.pMonitor->vecTransformedSize.y); - wlr_region_expand(damage.pixman(), damage.pixman(), *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES)); + damage.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + m_RenderData.pMonitor->vecTransformedSize.y); + damage.expand(*PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES)); // helper const auto PMIRRORFB = &m_RenderData.pCurrentMonData->mirrorFB; @@ -1419,7 +1605,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix); #endif glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST); @@ -1464,7 +1650,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o #ifndef GLES2 glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); #endif glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a @@ -1511,13 +1697,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // and draw for (int i = 1; i <= *PBLURPASSES; ++i) { - wlr_region_scale(tempDamage.pixman(), damage.pixman(), 1.f / (1 << i)); + tempDamage = damage.copy().scale(1.f / (1 << i)); drawPass(&m_RenderData.pCurrentMonData->m_shBLUR1, &tempDamage); // down } for (int i = *PBLURPASSES - 1; i >= 0; --i) { - wlr_region_scale(tempDamage.pixman(), damage.pixman(), 1.f / (1 << i)); // when upsampling we make the region twice as big - drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up + tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big + drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up } // finalize the image @@ -1541,7 +1727,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix); #endif glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE); @@ -1679,7 +1865,8 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { const auto POUTFB = blurMainFramebufferWithDamage(1, &fakeDamage); // render onto blurFB - m_RenderData.pCurrentMonData->blurFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->drmFormat); + m_RenderData.pCurrentMonData->blurFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, + m_RenderData.pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->blurFB.bind(); clear(CColor(0, 0, 0, 0)); @@ -1773,7 +1960,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float inverseOpaque = {0, 0, pBox->width, pBox->height}; } - wlr_region_scale(inverseOpaque.pixman(), inverseOpaque.pixman(), m_RenderData.pMonitor->scale); + inverseOpaque.scale(m_RenderData.pMonitor->scale); // vvv TODO: layered blur fbs? const bool USENEWOPTIMIZE = shouldUseNewBlurOptimizations(m_pCurrentLayer, m_pCurrentWindow.lock()) && !blockBlurOptimization; @@ -1872,11 +2059,11 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in round += round == 0 ? 0 : scaledBorderSize; float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here + projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, + m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); const auto BLEND = m_bBlend; blend(true); @@ -1886,7 +2073,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix); #endif @@ -1898,7 +2085,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); CBox transformedBox = *box; - transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -1949,14 +2136,14 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr // we need to "damage" the entire monitor // so that we render the entire window - // this is temporary, doesnt mess with the actual wlr damage + // this is temporary, doesnt mess with the actual damage CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y}; g_pHyprRenderer->makeEGLCurrent(); pFramebuffer->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); + pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, pFramebuffer); @@ -2000,7 +2187,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) { // we need to "damage" the entire monitor // so that we render the entire window - // this is temporary, doesnt mess with the actual wlr damage + // this is temporary, doesnt mess with the actual damage CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y}; PHLWINDOWREF ref{pWindow}; @@ -2009,7 +2196,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) { const auto PFRAMEBUFFER = &m_mWindowFramebuffers[ref]; - PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); + PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER); @@ -2049,14 +2236,14 @@ void CHyprOpenGLImpl::makeLayerSnapshot(PHLLS pLayer) { // we need to "damage" the entire monitor // so that we render the entire window - // this is temporary, doesnt mess with the actual wlr damage + // this is temporary, doesnt mess with the actual damage CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y}; g_pHyprRenderer->makeEGLCurrent(); const auto PFRAMEBUFFER = &m_mLayerFramebuffers[pLayer]; - PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); + PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER); @@ -2178,11 +2365,11 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const const auto col = color; float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here + projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, + m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); glEnable(GL_BLEND); @@ -2191,7 +2378,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix); #endif glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); @@ -2238,7 +2425,8 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const void CHyprOpenGLImpl::saveBufferForMirror(CBox* box) { if (!m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated()) - m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->drmFormat); + m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, + m_RenderData.pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->monitorMirrorFB.bind(); @@ -2270,11 +2458,11 @@ void CHyprOpenGLImpl::renderMirrored() { return; // replace monitor projection to undo the mirrored monitor's projection - wlr_matrix_identity(monitor->projMatrix.data()); - wlr_matrix_translate(monitor->projMatrix.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0); - wlr_matrix_transform(monitor->projMatrix.data(), monitor->transform); - wlr_matrix_transform(monitor->projMatrix.data(), wlr_output_transform_invert(mirrored->transform)); - wlr_matrix_translate(monitor->projMatrix.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0); + matrixIdentity(m_RenderData.monitorProjection.data()); + matrixTranslate(m_RenderData.monitorProjection.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0); + matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(monitor->transform)); + matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(invertTransform(mirrored->transform))); + matrixTranslate(m_RenderData.monitorProjection.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0); // clear stuff outside of mirrored area (e.g. when changing to mirrored) clear(CColor(0, 0, 0, 0)); @@ -2282,7 +2470,7 @@ void CHyprOpenGLImpl::renderMirrored() { renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false); // reset matrix for further drawing - monitor->updateMatrix(); + m_RenderData.monitorProjection = monitor->projMatrix; } void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) { @@ -2338,7 +2526,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { const auto PFB = &m_mMonitorBGFBs[pMonitor]; PFB->release(); - PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); + PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); Debug::log(LOG, "Allocated texture for BGTex"); // TODO: use relative paths to the installation @@ -2474,6 +2662,9 @@ void CHyprOpenGLImpl::clearWithTex() { void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { g_pHyprRenderer->makeEGLCurrent(); + if (!g_pHyprOpenGL) + return; + auto RESIT = g_pHyprOpenGL->m_mMonitorRenderResources.find(pMonitor); if (RESIT != g_pHyprOpenGL->m_mMonitorRenderResources.end()) { RESIT->second.mirrorFB.release(); @@ -2500,8 +2691,8 @@ void CHyprOpenGLImpl::saveMatrix() { } void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) { - wlr_matrix_scale(m_RenderData.projection, scale, scale); - wlr_matrix_translate(m_RenderData.projection, translate.x, translate.y); + matrixScale(m_RenderData.projection, scale, scale); + matrixTranslate(m_RenderData.projection, translate.x, translate.y); } void CHyprOpenGLImpl::restoreMatrix() { @@ -2533,29 +2724,63 @@ void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) { } uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { - GLint glf = -1, glt = -1, as = 0; - /*glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &glf); - glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &glt); - glGetIntegerv(GL_ALPHA_BITS, &as);*/ - - if (glf == 0 || glt == 0) { - glf = FormatUtils::drmFormatToGL(pMonitor->drmFormat); - glt = FormatUtils::glFormatToType(glf); - } - - if (const auto FMT = FormatUtils::getPixelFormatFromGL(glf, glt, as > 0); FMT) - return FMT->drmFormat; - - if (m_sExts.EXT_read_format_bgra) - return DRM_FORMAT_XRGB8888; - - return DRM_FORMAT_XBGR8888; + return pMonitor->output->state->state().drmFormat; } std::vector CHyprOpenGLImpl::getDRMFormats() { return drmFormats; } +SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { + std::vector attribs; + int dupFd = -1; + if (fenceFD > 0) { + int dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); + if (dupFd < 0) { + Debug::log(ERR, "createEGLSync: dup failed"); + return nullptr; + } + + attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); + attribs.push_back(dupFd); + attribs.push_back(EGL_NONE); + } + + EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data()); + if (sync == EGL_NO_SYNC_KHR) { + Debug::log(ERR, "eglCreateSyncKHR failed"); + if (dupFd >= 0) + close(dupFd); + return nullptr; + } + + auto eglsync = SP(new CEGLSync); + eglsync->sync = sync; + return eglsync; +} + +bool CHyprOpenGLImpl::waitForTimelinePoint(SP timeline, uint64_t point) { + int fd = timeline->exportAsSyncFileFD(point); + if (fd < 0) { + Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline"); + return false; + } + + auto sync = g_pHyprOpenGL->createEGLSync(fd); + close(fd); + if (!sync) { + Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline"); + return false; + } + + if (!sync->wait()) { + Debug::log(ERR, "waitForTimelinePoint: failed to wait on an eglsync from explicit timeline"); + return false; + } + + return true; +} + void SRenderModifData::applyToBox(CBox& box) { if (!enabled) return; @@ -2616,3 +2841,35 @@ float SRenderModifData::combinedScale() { } return scale; } + +CEGLSync::~CEGLSync() { + if (sync == EGL_NO_SYNC_KHR) + return; + + if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) + Debug::log(ERR, "eglDestroySyncKHR failed"); +} + +int CEGLSync::dupFenceFD() { + if (sync == EGL_NO_SYNC_KHR) + return -1; + + int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync); + if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + Debug::log(ERR, "eglDupNativeFenceFDANDROID failed"); + return -1; + } + + return fd; +} + +bool CEGLSync::wait() { + if (sync == EGL_NO_SYNC_KHR) + return false; + + if (g_pHyprOpenGL->m_sProc.eglWaitSyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync, 0) != EGL_TRUE) { + Debug::log(ERR, "eglWaitSyncKHR failed"); + return false; + } + return true; +} diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 814b80fe..712b87f3 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -6,6 +6,8 @@ #include "../helpers/Timer.hpp" #include "../helpers/math/Math.hpp" #include "../helpers/Format.hpp" +#include "../helpers/sync/SyncTimeline.hpp" +#include #include #include #include @@ -18,10 +20,14 @@ #include "Transformer.hpp" #include "Renderbuffer.hpp" +#include +#include #include +#include #include "../debug/TracyDefines.hpp" +struct gbm_device; class CHyprRenderer; inline const float fullVerts[] = { @@ -119,6 +125,21 @@ struct SCurrentRenderData { float discardOpacity = 0.f; }; +class CEGLSync { + public: + ~CEGLSync(); + + EGLSyncKHR sync = nullptr; + + int dupFenceFD(); + bool wait(); + + private: + CEGLSync() = default; + + friend class CHyprOpenGLImpl; +}; + class CGradientValueData; class CHyprOpenGLImpl { @@ -126,14 +147,15 @@ class CHyprOpenGLImpl { CHyprOpenGLImpl(); void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); - void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr); + void beginSimple(CMonitor*, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); void end(); void renderRect(CBox*, const CColor&, int round = 0); void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); void renderTexture(SP, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithDamage(SP, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(SP, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false, + SP waitTimeline = nullptr, uint64_t waitPoint = 0); void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); @@ -182,12 +204,19 @@ class CHyprOpenGLImpl { uint32_t getPreferredReadFormat(CMonitor* pMonitor); std::vector getDRMFormats(); - EGLImageKHR createEGLImage(const SDMABUFAttrs& attrs); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + SP createEGLSync(int fenceFD); + bool waitForTimelinePoint(SP timeline, uint64_t point); SCurrentRenderData m_RenderData; GLint m_iCurrentOutputFb = 0; + int m_iGBMFD = -1; + gbm_device* m_pGbmDevice = nullptr; + EGLContext m_pEglContext = nullptr; + EGLDisplay m_pEglDisplay = nullptr; + bool m_bReloadScreenShader = true; // at launch it can be set PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window @@ -205,12 +234,24 @@ class CHyprOpenGLImpl { PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr; PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr; PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr; + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr; + PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr; + PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr; + PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr; + PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr; + PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr; + PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr; + PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr; + PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr; } m_sProc; struct { bool EXT_read_format_bgra = false; bool EXT_image_dma_buf_import = false; bool EXT_image_dma_buf_import_modifiers = false; + bool KHR_display_reference = false; + bool IMG_context_priority = false; + bool EXT_create_context_robustness = false; } m_sExts; private: @@ -220,7 +261,7 @@ class CHyprOpenGLImpl { std::vector drmFormats; bool m_bHasModifiers = false; - int m_iDRMFD; + int m_iDRMFD = -1; std::string m_szExtensions; bool m_bFakeFrame = false; @@ -238,6 +279,7 @@ class CHyprOpenGLImpl { void createBGTextureForMonitor(CMonitor*); void initShaders(); void initDRMFormats(); + void initEGL(bool gbm); // std::optional> getModsForFormat(EGLint format); @@ -246,7 +288,7 @@ class CHyprOpenGLImpl { CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); void renderTextureInternalWithDamage(SP, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false, - bool allowCustomUV = false, bool allowDim = false); + bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); void renderTexturePrimitive(SP tex, CBox* pBox); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 3f591d13..58ed88d6 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -2,6 +2,8 @@ #include "OpenGL.hpp" #include "../Compositor.hpp" #include "../protocols/types/Buffer.hpp" +#include +#include #include @@ -15,58 +17,17 @@ CRenderbuffer::~CRenderbuffer() { m_sFramebuffer.release(); glDeleteRenderbuffers(1, &m_iRBO); - g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage); + g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_iImage); } -CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer), m_uDrmFormat(format) { - - // EVIL, but we can't include a hidden header because nixos is fucking special - static EGLImageKHR (*PWLREGLCREATEIMAGEFROMDMABUF)(wlr_egl*, wlr_dmabuf_attributes*, bool*); - static bool symbolFound = false; - if (!symbolFound) { - PWLREGLCREATEIMAGEFROMDMABUF = reinterpret_cast(dlsym(RTLD_DEFAULT, "wlr_egl_create_image_from_dmabuf")); - - symbolFound = true; - - RASSERT(PWLREGLCREATEIMAGEFROMDMABUF, "wlr_egl_create_image_from_dmabuf was not found in wlroots!"); - - Debug::log(LOG, "CRenderbuffer: wlr_egl_create_image_from_dmabuf found at {:x}", (uintptr_t)PWLREGLCREATEIMAGEFROMDMABUF); - } - // end evil hack - - struct wlr_dmabuf_attributes dmabuf = {0}; - if (!wlr_buffer_get_dmabuf(buffer, &dmabuf)) - throw std::runtime_error("wlr_buffer_get_dmabuf failed"); - - bool externalOnly; - m_iImage = PWLREGLCREATEIMAGEFROMDMABUF(g_pCompositor->m_sWLREGL, &dmabuf, &externalOnly); - if (m_iImage == EGL_NO_IMAGE_KHR) - throw std::runtime_error("wlr_egl_create_image_from_dmabuf failed"); - - glGenRenderbuffers(1, &m_iRBO); - glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); - g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - - glGenFramebuffers(1, &m_sFramebuffer.m_iFb); - m_sFramebuffer.m_vSize = {buffer->width, buffer->height}; - m_sFramebuffer.bind(); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - throw std::runtime_error("rbo: glCheckFramebufferStatus failed"); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - hyprListener_destroyBuffer.initCallback(&buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer"); -} - -CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) { +CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) { auto dma = buffer->dmabuf(); m_iImage = g_pHyprOpenGL->createEGLImage(dma); - if (m_iImage == EGL_NO_IMAGE_KHR) - throw std::runtime_error("createEGLImage failed"); + if (m_iImage == EGL_NO_IMAGE_KHR) { + Debug::log(ERR, "rb: createEGLImage failed"); + return; + } glGenRenderbuffers(1, &m_iRBO); glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); @@ -78,10 +39,20 @@ CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : m_pHLBuffe m_sFramebuffer.bind(); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - throw std::runtime_error("rbo: glCheckFramebufferStatus failed"); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + Debug::log(ERR, "rbo: glCheckFramebufferStatus failed"); + return; + } glBindFramebuffer(GL_FRAMEBUFFER, 0); + + listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) { g_pHyprRenderer->onRenderbufferDestroy(this); }); + + m_bGood = true; +} + +bool CRenderbuffer::good() { + return m_bGood; } void CRenderbuffer::bind() { diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index ed7050c5..e6bfa909 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -1,30 +1,35 @@ #pragma once +#include "../helpers/signal/Signal.hpp" +#include "../helpers/memory/Memory.hpp" +#include "../helpers/WLListener.hpp" #include "Framebuffer.hpp" +#include class CMonitor; -class IWLBuffer; class CRenderbuffer { public: - CRenderbuffer(wlr_buffer* buffer, uint32_t format); - CRenderbuffer(SP buffer, uint32_t format); + CRenderbuffer(SP buffer, uint32_t format); ~CRenderbuffer(); - void bind(); - void bindFB(); - void unbind(); - CFramebuffer* getFB(); - uint32_t getFormat(); + bool good(); + void bind(); + void bindFB(); + void unbind(); + CFramebuffer* getFB(); + uint32_t getFormat(); - wlr_buffer* m_pWlrBuffer = nullptr; - WP m_pHLBuffer = {}; - - DYNLISTENER(destroyBuffer); + WP m_pHLBuffer; private: - EGLImageKHR m_iImage = 0; + void* m_iImage = nullptr; GLuint m_iRBO = 0; CFramebuffer m_sFramebuffer; uint32_t m_uDrmFormat = 0; + bool m_bGood = false; + + struct { + CHyprSignalListener destroyBuffer; + } listeners; }; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a7f3c941..82dfc887 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2,6 +2,8 @@ #include "../Compositor.hpp" #include "../helpers/math/Math.hpp" #include +#include +#include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" #include "../managers/PointerManager.hpp" @@ -13,6 +15,10 @@ #include "../protocols/PresentationTime.hpp" #include "../protocols/core/DataDevice.hpp" #include "../protocols/core/Compositor.hpp" +#include "../protocols/DRMSyncobj.hpp" +#include "../protocols/LinuxDMABUF.hpp" +#include "../helpers/sync/SyncTimeline.hpp" +#include "debug/Log.hpp" extern "C" { #include @@ -25,11 +31,11 @@ static int cursorTicker(void* data) { } CHyprRenderer::CHyprRenderer() { - if (g_pCompositor->m_sWLRSession) { - wlr_device* dev; - wl_list_for_each(dev, &g_pCompositor->m_sWLRSession->devices, link) { - const auto DRMV = drmGetVersion(dev->fd); - + if (g_pCompositor->m_pAqBackend->hasSession()) { + for (auto& dev : g_pCompositor->m_pAqBackend->session->sessionDevices) { + const auto DRMV = drmGetVersion(dev->fd); + if (!DRMV) + continue; std::string name = std::string{DRMV->name, DRMV->name_len}; std::transform(name.begin(), name.end(), name.begin(), tolower); @@ -42,7 +48,7 @@ CHyprRenderer::CHyprRenderer() { drmFreeVersion(DRMV); } } else { - Debug::log(LOG, "m_sWLRSession is null, omitting full DRM node checks"); + Debug::log(LOG, "Aq backend has no session, omitting full DRM node checks"); const auto DRMV = drmGetVersion(g_pCompositor->m_iDRMFD); @@ -108,6 +114,14 @@ static void renderSurface(SP surface, int x, int y, void* da if (!TEXTURE->m_iTexID) return; + // explicit sync: wait for the timeline, if any + if (surface->syncobj && surface->syncobj->acquireTimeline) { + if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->acquireTimeline->timeline, surface->syncobj->acquirePoint)) { + Debug::log(ERR, "Renderer: failed to wait for explicit timeline"); + return; + } + } + TRACY_GPU_ZONE("RenderSurface"); double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y; @@ -167,12 +181,10 @@ static void renderSurface(SP surface, int x, int y, void* da if (windowBox.width <= 1 || windowBox.height <= 1) { if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - surface->frame(RDATA->when); - auto FEEDBACK = makeShared(surface); - FEEDBACK->attachMonitor(RDATA->pMonitor); - FEEDBACK->discarded(); - PROTO::presentation->queueData(FEEDBACK); + Debug::log(TRACE, "presentFeedback for invisible surface"); + surface->presentFeedback(RDATA->when, RDATA->pMonitor); } + return; // invisible } @@ -225,11 +237,8 @@ static void renderSurface(SP surface, int x, int y, void* da } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - surface->frame(RDATA->when); - auto FEEDBACK = makeShared(surface); - FEEDBACK->attachMonitor(RDATA->pMonitor); - FEEDBACK->presented(); - PROTO::presentation->queueData(FEEDBACK); + Debug::log(TRACE, "presentFeedback for visible surface"); + surface->presentFeedback(RDATA->when, RDATA->pMonitor); } g_pHyprOpenGL->blend(true); @@ -1079,53 +1088,6 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPmirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) - // return false; // do not DS if this monitor is being mirrored. Will break the functionality. - - // if (!wlr_output_is_direct_scanout_allowed(pMonitor->output)) - // return false; - - // const auto PCANDIDATE = pMonitor->solitaryClient.lock(); - - // if (!PCANDIDATE) - // return false; - - // const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); - - // if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform) - // return false; - - // // finally, we should be GTG. - // wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base); - - // if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) - // return false; - - // timespec now; - // clock_gettime(CLOCK_MONOTONIC, &now); - // PSURFACE->frame(&now); - // auto FEEDBACK = makeShared(PSURFACE); - // FEEDBACK->attachMonitor(pMonitor); - // FEEDBACK->presented(); - // FEEDBACK->setPresentationType(true); - // PROTO::presentation->queueData(FEEDBACK); - - // if (pMonitor->state.commit()) { - // if (m_pLastScanout.expired()) { - // m_pLastScanout = PCANDIDATE; - // Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); - // } - // } else { - // m_pLastScanout.reset(); - // return false; - // } - - // return true; -} - void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now(); @@ -1177,7 +1139,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->framesToSkip -= 1; if (!pMonitor->noFrameSchedule) - g_pCompositor->scheduleFrameForMonitor(pMonitor); + g_pCompositor->scheduleFrameForMonitor(pMonitor, Aquamarine::IOutput::AQ_SCHEDULE_RENDER_MONITOR); else Debug::log(LOG, "NoFrameSchedule hit for {}.", pMonitor->szName); @@ -1205,6 +1167,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID); } + if (!pMonitor->output->needsFrame && pMonitor->forceFullFrames == 0) + return; + // tearing and DS first bool shouldTear = false; if (pMonitor->tearingState.nextRenderTorn) { @@ -1230,11 +1195,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } if (!*PNODIRECTSCANOUT && !shouldTear) { - if (attemptDirectScanout(pMonitor)) { + if (pMonitor->attemptDirectScanout()) { return; - } else if (!m_pLastScanout.expired()) { + } else if (!pMonitor->lastScanout.expired()) { Debug::log(LOG, "Left a direct scanout."); - m_pLastScanout.reset(); + pMonitor->lastScanout.reset(); } } @@ -1249,7 +1214,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { clock_gettime(CLOCK_MONOTONIC, &now); // check the damage - bool hasChanged = pMonitor->output->needs_frame || pMonitor->damage.hasChanged(); + bool hasChanged = pMonitor->output->needsFrame || pMonitor->damage.hasChanged(); if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0) return; @@ -1295,7 +1260,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { CRegion damage, finalDamage; if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) { Debug::log(ERR, "renderer: couldn't beginRender()!"); - pMonitor->state.clear(); return; } @@ -1316,11 +1280,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think. // now, prep the damage, get the extended damage region - wlr_region_expand(damage.pixman(), damage.pixman(), BLURRADIUS); // expand for proper blurring + damage.expand(BLURRADIUS); // expand for proper blurring finalDamage = damage; - wlr_region_expand(damage.pixman(), damage.pixman(), BLURRADIUS); // expand for proper blurring 2 + damage.expand(BLURRADIUS); // expand for proper blurring } else finalDamage = damage; } @@ -1396,10 +1360,10 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { TRACY_GPU_COLLECT; if (!pMonitor->mirrors.empty()) { - CRegion frameDamage{}; + CRegion frameDamage{finalDamage}; - const auto TRANSFORM = wlr_output_transform_invert(pMonitor->output->transform); - wlr_region_transform(frameDamage.pixman(), finalDamage.pixman(), TRANSFORM, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y); + const auto TRANSFORM = invertTransform(pMonitor->transform); + frameDamage.transform(wlTransformToHyprutils(TRANSFORM), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR) frameDamage.add(0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y); @@ -1414,18 +1378,16 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { EMIT_HOOK_EVENT("render", RENDER_POST); - pMonitor->state.wlr()->tearing_page_flip = shouldTear; + pMonitor->output->state->setPresentationMode(shouldTear ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : + Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); - if (!pMonitor->state.commit()) { - pMonitor->damage.damageEntire(); - return; - } + commitPendingAndDoExplicitSync(pMonitor); if (shouldTear) pMonitor->tearingState.busy = true; if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame) - g_pCompositor->scheduleFrameForMonitor(pMonitor); + g_pCompositor->scheduleFrameForMonitor(pMonitor, Aquamarine::IOutput::AQ_SCHEDULE_RENDER_MONITOR); pMonitor->pendingFrame = false; @@ -1442,6 +1404,63 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } } +bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { + static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + + // apply timelines for explicit sync + pMonitor->output->state->resetExplicitFences(); + + bool anyExplicit = !explicitPresented.empty(); + if (anyExplicit) { + Debug::log(TRACE, "Explicit sync presented begin"); + auto inFence = pMonitor->inTimeline->exportAsSyncFileFD(pMonitor->lastWaitPoint); + if (inFence < 0) + Debug::log(ERR, "Export lastWaitPoint {} as sync explicitInFence failed", pMonitor->lastWaitPoint); + + pMonitor->output->state->setExplicitInFence(inFence); + + for (auto& e : explicitPresented) { + Debug::log(TRACE, "Explicit sync presented releasePoint {}", e->syncobj && e->syncobj->releaseTimeline ? e->syncobj->releasePoint : -1); + if (!e->syncobj || !e->syncobj->releaseTimeline) + continue; + e->syncobj->releaseTimeline->timeline->transfer(pMonitor->outTimeline, pMonitor->commitSeq, e->syncobj->releasePoint); + } + + explicitPresented.clear(); + auto outFence = pMonitor->outTimeline->exportAsSyncFileFD(pMonitor->commitSeq); + if (outFence < 0) + Debug::log(ERR, "Export commitSeq {} as sync explicitOutFence failed", pMonitor->commitSeq); + + pMonitor->output->state->setExplicitOutFence(outFence); + Debug::log(TRACE, "Explicit sync presented end"); + } + + pMonitor->lastWaitPoint = 0; + + bool ok = pMonitor->state.commit(); + if (!ok) { + Debug::log(TRACE, "Monitor state commit failed"); + // rollback the buffer to avoid writing to the front buffer that is being + // displayed + pMonitor->output->swapchain->rollback(); + pMonitor->damage.damageEntire(); + } + + if (!*PENABLEEXPLICIT) + return ok; + + if (pMonitor->output->state->state().explicitInFence >= 0) + close(pMonitor->output->state->state().explicitInFence); + + if (pMonitor->output->state->state().explicitOutFence >= 0) { + if (ok) + pMonitor->outTimeline->importFromSyncFileFD(pMonitor->commitSeq, pMonitor->output->state->state().explicitOutFence); + close(pMonitor->output->state->state().explicitOutFence); + } + + return ok; +} + void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry) { Vector2D translate = {geometry.x, geometry.y}; float scale = (float)geometry.width / pMonitor->vecPixelSize.x; @@ -1480,33 +1499,11 @@ void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE } } -void CHyprRenderer::setWindowScanoutMode(PHLWINDOW pWindow) { - // FIXME: fix when moved to new impl - // if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) - // return; +void CHyprRenderer::setSurfaceScanoutMode(SP surface, SP monitor) { + if (!PROTO::linuxDma) + return; - // if (!pWindow->m_bIsFullscreen) { - // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), nullptr); - // Debug::log(LOG, "Scanout mode OFF set for {}", pWindow); - // return; - // } - - // const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - - // const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = { - // .main_renderer = g_pCompositor->m_sWLRRenderer, - // .scanout_primary_output = PMONITOR->output, - // }; - - // wlr_linux_dmabuf_feedback_v1 feedback = {0}; - - // if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS)) - // return; - - // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), &feedback); - // wlr_linux_dmabuf_feedback_v1_finish(&feedback); - - // Debug::log(LOG, "Scanout mode ON set for {}", pWindow); + PROTO::linuxDma->updateScanoutTranche(surface, monitor); } // taken from Sway. @@ -1572,7 +1569,7 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorvecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; for (auto& ls : layerSurfaces) { - if (ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess) + if (!ls || ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess) continue; const auto PLAYER = ls->layerSurface; @@ -1708,7 +1705,7 @@ void CHyprRenderer::damageSurface(SP pSurface, double x, dou damageBox.scale(scale); // schedule frame events - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y)), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); if (damageBox.empty()) return; @@ -1820,13 +1817,13 @@ void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion monbox.x = (monitor->vecTransformedSize.x - monbox.w) / 2; monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2; - wlr_region_scale(transformed.pixman(), transformed.pixman(), scale); + transformed.scale(scale); transformed.transform(wlTransformToHyprutils(mirrored->transform), mirrored->vecPixelSize.x * scale, mirrored->vecPixelSize.y * scale); transformed.translate(Vector2D(monbox.x, monbox.y)); mirror->addDamage(&transformed); - g_pCompositor->scheduleFrameForMonitor(mirror); + g_pCompositor->scheduleFrameForMonitor(mirror, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } } @@ -1869,7 +1866,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // don't touch VR headsets - if (pMonitor->output->non_desktop) + if (pMonitor->output->nonDesktop) return true; if (!pMonitor->m_bEnabled) { @@ -1900,7 +1897,10 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // Needed in case we are switching from a custom modeline to a standard mode pMonitor->customDrmMode = {}; pMonitor->currentMode = nullptr; - bool autoScale = false; + + pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); + + bool autoScale = false; if (RULE->scale > 0.1) { pMonitor->scale = RULE->scale; @@ -1910,38 +1910,35 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->scale = DEFAULTSCALE; } - wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale); - pMonitor->setScale = pMonitor->scale; - - wlr_output_state_set_transform(pMonitor->state.wlr(), RULE->transform); + pMonitor->setScale = pMonitor->scale; pMonitor->transform = RULE->transform; - const auto WLRREFRESHRATE = (wlr_backend_is_wl(pMonitor->output->backend) || wlr_backend_is_x11(pMonitor->output->backend)) ? 0 : RULE->refreshRate * 1000; + const auto WLRREFRESHRATE = pMonitor->output->getBackend()->type() == Aquamarine::eBackendType::AQ_BACKEND_DRM ? RULE->refreshRate * 1000 : 0; // loop over modes and choose an appropriate one. if (RULE->resolution != Vector2D() && RULE->resolution != Vector2D(-1, -1) && RULE->resolution != Vector2D(-1, -2)) { - if (!wl_list_empty(&pMonitor->output->modes) && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) { - wlr_output_mode* mode; - bool found = false; + if (!pMonitor->output->modes.empty() && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) { + bool found = false; - wl_list_for_each(mode, &pMonitor->output->modes, link) { + for (auto& mode : pMonitor->output->modes) { // if delta of refresh rate, w and h chosen and mode is < 1 we accept it - if (DELTALESSTHAN(mode->width, RULE->resolution.x, 1) && DELTALESSTHAN(mode->height, RULE->resolution.y, 1) && - DELTALESSTHAN(mode->refresh / 1000.f, RULE->refreshRate, 1)) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); + if (DELTALESSTHAN(mode->pixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(mode->pixelSize.y, RULE->resolution.y, 1) && + DELTALESSTHAN(mode->refreshRate / 1000.f, RULE->refreshRate, 1)) { + pMonitor->output->state->setMode(mode); - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f); + if (!pMonitor->state.test()) { + Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y, + mode->refreshRate / 1000.f); continue; } Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, mode->width, mode->height, mode->refresh); + (float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate); found = true; - pMonitor->refreshRate = mode->refresh / 1000.f; - pMonitor->vecSize = Vector2D(mode->width, mode->height); + pMonitor->refreshRate = mode->refreshRate / 1000.f; + pMonitor->vecSize = mode->pixelSize; pMonitor->currentMode = mode; break; @@ -1949,14 +1946,14 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } if (!found) { - wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE); + pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); pMonitor->vecSize = RULE->resolution; pMonitor->refreshRate = RULE->refreshRate; - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { + if (!pMonitor->state.test()) { Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution, @@ -1965,13 +1962,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; pMonitor->currentMode = PREFERREDMODE; } else { Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate); @@ -1982,30 +1979,30 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR bool fail = false; if (RULE->drmMode.type == DRM_MODE_TYPE_USERDEF) { - if (!wlr_output_is_drm(pMonitor->output)) { + if (pMonitor->output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM) { Debug::log(ERR, "Tried to set custom modeline on non-DRM output"); fail = true; } else { - auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode); - if (mode) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - pMonitor->customDrmMode = RULE->drmMode; - } else { - Debug::log(ERR, "wlr_drm_connector_add_mode failed"); - fail = true; - } + // FIXME: + // auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode); + // if (mode) { + // wlr_output_state_set_mode(pMonitor->state.wlr(), mode); + // pMonitor->customDrmMode = RULE->drmMode; + // } else { + // Debug::log(ERR, "wlr_drm_connector_add_mode failed"); + // fail = true; + // } } - } else { - wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE); - } + } else + pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); pMonitor->vecSize = RULE->resolution; pMonitor->refreshRate = RULE->refreshRate; - if (fail || !wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { + if (fail || !pMonitor->state.test()) { Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->output->name, RULE->resolution, @@ -2014,48 +2011,47 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; pMonitor->customDrmMode = {}; - } else { + } else Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate); - } } } else if (RULE->resolution != Vector2D()) { - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; - float currentWidth = 0; - float currentHeight = 0; - float currentRefresh = 0; - bool success = false; + if (!pMonitor->output->modes.empty()) { + float currentWidth = 0; + float currentHeight = 0; + float currentRefresh = 0; + bool success = false; //(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution if (RULE->resolution == Vector2D(-1, -1)) { - wl_list_for_each(mode, &pMonitor->output->modes, link) { - if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || mode->refresh > (currentRefresh + 3000.f)) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - currentWidth = mode->width; - currentHeight = mode->height; - currentRefresh = mode->refresh; + for (auto& mode : pMonitor->output->modes) { + if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || + mode->refreshRate > (currentRefresh + 3000.f)) { + pMonitor->output->state->setMode(mode); + if (pMonitor->state.test()) { + currentWidth = mode->pixelSize.x; + currentHeight = mode->pixelSize.y; + currentRefresh = mode->refreshRate; success = true; } } } } else { - wl_list_for_each(mode, &pMonitor->output->modes, link) { - if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || - (mode->width > currentWidth && mode->height > currentHeight)) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - currentWidth = mode->width; - currentHeight = mode->height; - currentRefresh = mode->refresh; + for (auto& mode : pMonitor->output->modes) { + if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || + (mode->pixelSize.x > currentWidth && mode->pixelSize.y > currentHeight)) { + pMonitor->output->state->setMode(mode); + if (pMonitor->state.test()) { + currentWidth = mode->pixelSize.x; + currentHeight = mode->pixelSize.y; + currentRefresh = mode->refreshRate; success = true; } } @@ -2063,10 +2059,12 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } if (!success) { - Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, mode->width, mode->height, mode->refresh / 1000.f); + if (pMonitor->output->state->state().mode) + Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, + (float)RULE->refreshRate, pMonitor->output->state->state().mode->pixelSize.x, pMonitor->output->state->state().mode->pixelSize.y, + pMonitor->output->state->state().mode->refreshRate / 1000.f); - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution, (float)RULE->refreshRate); @@ -2074,13 +2072,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; pMonitor->currentMode = PREFERREDMODE; } else { @@ -2091,27 +2089,26 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } } } else { - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", pMonitor->output->name); - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; + if (!pMonitor->output->modes.empty()) { + for (auto& mode : pMonitor->output->modes) { + pMonitor->output->state->setMode(mode); - wl_list_for_each(mode, &pMonitor->output->modes, link) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f); + if (!pMonitor->state.test()) { + Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y, + mode->refreshRate / 1000.f); continue; } Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, mode->width, mode->height, mode->refresh); + (float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate); - pMonitor->refreshRate = mode->refresh / 1000.f; - pMonitor->vecSize = Vector2D(mode->width, mode->height); + pMonitor->refreshRate = mode->refreshRate / 1000.f; + pMonitor->vecSize = mode->pixelSize; pMonitor->currentMode = mode; break; @@ -2119,21 +2116,49 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } } else { // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; pMonitor->currentMode = PREFERREDMODE; Debug::log(LOG, "Setting preferred mode for {}", pMonitor->output->name); } } - pMonitor->vrrActive = pMonitor->state.wlr()->adaptive_sync_enabled // disabled here, will be tested in CConfigManager::ensureVRR() - || pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync + pMonitor->vrrActive = pMonitor->output->state->state().adaptiveSync // disabled here, will be tested in CConfigManager::ensureVRR() + || pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync pMonitor->vecPixelSize = pMonitor->vecSize; + // clang-format off + static const std::array>, 2> formats{ + std::vector>{ /* 10-bit */ + {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} + }, + std::vector>{ /* 8-bit */ + {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} + } + }; + // clang-format on + + bool set10bit = false; + + for (auto& fmt : formats[(int)!RULE->enable10bit]) { + pMonitor->output->state->setFormat(fmt.second); + + if (!pMonitor->state.test()) { + Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); + } else { + Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first); + if (RULE->enable10bit && fmt.first.contains("101010")) + set10bit = true; + break; + } + } + + pMonitor->enabled10bit = set10bit; + Vector2D logicalSize = pMonitor->vecPixelSize / pMonitor->scale; if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) { // invalid scale, will produce fractional pixels. @@ -2145,10 +2170,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR double scaleZero = searchScale / 120.0; Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero; - if (logicalZero == logicalZero.round()) { + if (logicalZero == logicalZero.round()) pMonitor->scale = scaleZero; - wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale); - } else { + else { for (size_t i = 1; i < 90; ++i) { double scaleUp = (searchScale + i) / 120.0; double scaleDown = (searchScale - i) / 120.0; @@ -2185,57 +2209,21 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } else pMonitor->scale = searchScale; } - - // for wlroots, that likes flooring, we have to do this. - double logicalX = std::round(pMonitor->vecPixelSize.x / pMonitor->scale); - logicalX += 0.1; - - wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->vecPixelSize.x / logicalX); } } - // clang-format off - static const std::array>, 2> formats{ - std::vector>{ /* 10-bit */ - {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} - }, - std::vector>{ /* 8-bit */ - {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} - } - }; - // clang-format on - - bool set10bit = false; - pMonitor->drmFormat = DRM_FORMAT_INVALID; - - for (auto& fmt : formats[(int)!RULE->enable10bit]) { - wlr_output_state_set_render_format(pMonitor->state.wlr(), fmt.second); - - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); - } else { - Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first); - if (RULE->enable10bit && fmt.first.contains("101010")) - set10bit = true; - - pMonitor->drmFormat = fmt.second; - break; - } - } - - pMonitor->enabled10bit = set10bit; + pMonitor->output->scheduleFrame(); if (!pMonitor->state.commit()) Debug::log(ERR, "Couldn't commit output named {}", pMonitor->output->name); - int x, y; - wlr_output_transformed_resolution(pMonitor->output, &x, &y); - pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).round(); - pMonitor->vecTransformedSize = Vector2D(x, y); + Vector2D xfmd = pMonitor->transform % 2 == 1 ? Vector2D{pMonitor->vecPixelSize.y, pMonitor->vecPixelSize.x} : pMonitor->vecPixelSize; + pMonitor->vecSize = (xfmd / pMonitor->scale).round(); + pMonitor->vecTransformedSize = xfmd; if (pMonitor->createdByUser) { CBox transformedBox = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y}; - transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->output->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); + transformedBox.transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height); } @@ -2245,7 +2233,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR if (WAS10B != pMonitor->enabled10bit || OLDRES != pMonitor->vecPixelSize) g_pHyprOpenGL->destroyMonitorResources(pMonitor); - // updato wlroots g_pCompositor->arrangeMonitors(); pMonitor->damage.setSize(pMonitor->vecTransformedSize); @@ -2260,9 +2247,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // updato us arrangeLayersForMonitor(pMonitor->ID); - // frame skip - pMonitor->framesToSkip = 1; - // reload to fix mirrors g_pConfigManager->m_bWantsMonitorReload = true; @@ -2329,7 +2313,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Hiding the cursor (hl-mandated)"); for (auto& m : g_pCompositor->m_vMonitors) { - if (m->output->software_cursor_locks == 0) + if (!g_pPointerManager->softwareLockedFor(m)) continue; g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? @@ -2341,7 +2325,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Showing the cursor (hl-mandated)"); for (auto& m : g_pCompositor->m_vMonitors) { - if (m->output->software_cursor_locks == 0) + if (!g_pPointerManager->softwareLockedFor(m)) continue; g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? @@ -2570,37 +2554,37 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { pMonitor->solitaryClient = PCANDIDATE; } -CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt) { - auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pWlrBuffer == buffer; }); - - if (it != m_vRenderbuffers.end()) - return it->get(); - - return m_vRenderbuffers.emplace_back(std::make_unique(buffer, fmt)).get(); -} - -CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { +SP CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; }); if (it != m_vRenderbuffers.end()) - return it->get(); + return *it; - return m_vRenderbuffers.emplace_back(std::make_unique(buffer, fmt)).get(); + auto buf = makeShared(buffer, fmt); + + if (!buf->good()) + return nullptr; + + m_vRenderbuffers.emplace_back(buf); + return buf; } void CHyprRenderer::makeEGLCurrent() { - if (!g_pCompositor) + if (!g_pCompositor || !g_pHyprOpenGL) return; - if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL)) - eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)); + if (eglGetCurrentContext() != g_pHyprOpenGL->m_pEglContext) + eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, g_pHyprOpenGL->m_pEglContext); } void CHyprRenderer::unsetEGL() { - eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!g_pHyprOpenGL) + return; + + eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { +bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { makeEGLCurrent(); @@ -2618,35 +2602,33 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return true; } - int bufferAge = 0; + /* This is a constant expression, as we always use double-buffering in our swapchain + TODO: Rewrite the CDamageRing to take advantage of that maybe? It's made to support longer swapchains atm because we used to do wlroots */ + static constexpr const int HL_BUFFER_AGE = 2; if (!buffer) { - if (!wlr_output_configure_primary_swapchain(pMonitor->output, pMonitor->state.wlr(), &pMonitor->output->swapchain)) { - Debug::log(ERR, "Failed to configure primary swapchain for {}", pMonitor->szName); - return false; - } - - m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &bufferAge); - if (!m_pCurrentWlrBuffer) { + m_pCurrentBuffer = pMonitor->output->swapchain->next(nullptr); + if (!m_pCurrentBuffer) { Debug::log(ERR, "Failed to acquire swapchain buffer for {}", pMonitor->szName); return false; } } else - m_pCurrentHLBuffer = buffer; + m_pCurrentBuffer = buffer; try { - if (m_pCurrentWlrBuffer) - m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat); - else - m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentHLBuffer.lock(), pMonitor->drmFormat); + m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentBuffer, pMonitor->output->state->state().drmFormat); } catch (std::exception& e) { Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName); - wlr_buffer_unlock(m_pCurrentWlrBuffer); + return false; + } + + if (!m_pCurrentRenderbuffer) { + Debug::log(ERR, "failed to start a render pass for output {}, no RBO could be obtained", pMonitor->szName); return false; } if (mode == RENDER_MODE_NORMAL) { - damage = pMonitor->damage.getBufferDamage(bufferAge); + damage = pMonitor->damage.getBufferDamage(HL_BUFFER_AGE); pMonitor->damage.rotate(); } @@ -2662,6 +2644,9 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode void CHyprRenderer::endRender() { const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor; static auto PNVIDIAANTIFLICKER = CConfigValue("opengl:nvidia_anti_flicker"); + static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + + PMONITOR->commitSeq++; if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY) g_pHyprOpenGL->end(); @@ -2674,29 +2659,57 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_FULL_FAKE) return; - if (isNvidia() && *PNVIDIAANTIFLICKER) - glFinish(); - else - glFlush(); - if (m_eRenderMode == RENDER_MODE_NORMAL) { - wlr_output_state_set_buffer(PMONITOR->state.wlr(), m_pCurrentWlrBuffer); - unsetEGL(); // flush the context - } + PMONITOR->output->state->setBuffer(m_pCurrentBuffer); - wlr_buffer_unlock(m_pCurrentWlrBuffer); + if (PMONITOR->inTimeline && *PENABLEEXPLICIT) { + auto sync = g_pHyprOpenGL->createEGLSync(-1); + if (!sync) { + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); + return; + } + + auto dupedfd = sync->dupFenceFD(); + sync.reset(); + if (dupedfd < 0) { + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + Debug::log(ERR, "renderer: couldn't dup an EGLSync fence for out in endRender"); + return; + } + + bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, dupedfd); + close(dupedfd); + if (!ok) { + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); + return; + } + } else { + if (isNvidia() && *PNVIDIAANTIFLICKER) + glFinish(); + else + glFlush(); + } + } m_pCurrentRenderbuffer->unbind(); m_pCurrentRenderbuffer = nullptr; - m_pCurrentWlrBuffer = nullptr; + m_pCurrentBuffer = nullptr; } void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) { std::erase_if(m_vRenderbuffers, [&](const auto& rbo) { return rbo.get() == rb; }); } -CRenderbuffer* CHyprRenderer::getCurrentRBO() { +SP CHyprRenderer::getCurrentRBO() { return m_pCurrentRenderbuffer; } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 8f404c88..72efe8c4 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -12,7 +12,7 @@ struct SMonitorRule; class CWorkspace; class CWindow; class CInputPopup; -class IWLBuffer; +class IHLBuffer; // TODO: add fuller damage tracking for updating only parts of a window enum DAMAGETRACKINGMODES { @@ -69,35 +69,35 @@ class CHyprRenderer { void setCursorSurface(SP surf, int hotspotX, int hotspotY, bool force = false); void setCursorFromName(const std::string& name, bool force = false); void onRenderbufferDestroy(CRenderbuffer* rb); - CRenderbuffer* getCurrentRBO(); + SP getCurrentRBO(); bool isNvidia(); void makeEGLCurrent(); void unsetEGL(); // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. - bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); - void endRender(); + bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); + void endRender(); - bool m_bBlockSurfaceFeedback = false; - bool m_bRenderingSnapshot = false; - PHLWINDOWREF m_pLastScanout; - CMonitor* m_pMostHzMonitor = nullptr; - bool m_bDirectScanoutBlocked = false; + bool m_bBlockSurfaceFeedback = false; + bool m_bRenderingSnapshot = false; + CMonitor* m_pMostHzMonitor = nullptr; + bool m_bDirectScanoutBlocked = false; DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); - bool attemptDirectScanout(CMonitor*); - void setWindowScanoutMode(PHLWINDOW); - void initiateManualCrash(); + void setSurfaceScanoutMode(SP surface, SP monitor); // nullptr monitor resets + void initiateManualCrash(); - bool m_bCrashingInProgress = false; - float m_fCrashingDistort = 0.5f; - wl_event_source* m_pCrashingLoop = nullptr; - wl_event_source* m_pCursorTicker = nullptr; + bool m_bCrashingInProgress = false; + float m_fCrashingDistort = 0.5f; + wl_event_source* m_pCrashingLoop = nullptr; + wl_event_source* m_pCursorTicker = nullptr; - CTimer m_tRenderTimer; + CTimer m_tRenderTimer; + + std::vector> explicitPresented; struct { int hotspotX; @@ -107,26 +107,27 @@ class CHyprRenderer { } m_sLastCursorData; private: - void arrangeLayerArray(CMonitor*, const std::vector&, bool, CBox*); - void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) - void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) - void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false); - void renderLayer(PHLLS, CMonitor*, timespec*, bool popups = false); - void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*); - void renderDragIcon(CMonitor*, timespec*); - void renderIMEPopup(CInputPopup*, CMonitor*, timespec*); - void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry); - void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything - void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); + void arrangeLayerArray(CMonitor*, const std::vector&, bool, CBox*); + void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) + void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) + void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false); + void renderLayer(PHLLS, CMonitor*, timespec*, bool popups = false); + void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*); + void renderDragIcon(CMonitor*, timespec*); + void renderIMEPopup(CInputPopup*, CMonitor*, timespec*); + void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry); + void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything + void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); - bool m_bCursorHidden = false; - bool m_bCursorHasSurface = false; - CRenderbuffer* m_pCurrentRenderbuffer = nullptr; - wlr_buffer* m_pCurrentWlrBuffer = nullptr; - WP m_pCurrentHLBuffer = {}; - eRenderMode m_eRenderMode = RENDER_MODE_NORMAL; + bool commitPendingAndDoExplicitSync(CMonitor* pMonitor); - bool m_bNvidia = false; + bool m_bCursorHidden = false; + bool m_bCursorHasSurface = false; + SP m_pCurrentRenderbuffer = nullptr; + SP m_pCurrentBuffer; + eRenderMode m_eRenderMode = RENDER_MODE_NORMAL; + + bool m_bNvidia = false; struct { bool hiddenOnTouch = false; @@ -134,9 +135,8 @@ class CHyprRenderer { bool hiddenOnKeyboard = false; } m_sCursorHiddenConditions; - CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt); - CRenderbuffer* getOrCreateRenderbuffer(SP buffer, uint32_t fmt); - std::vector> m_vRenderbuffers; + SP getOrCreateRenderbuffer(SP buffer, uint32_t fmt); + std::vector> m_vRenderbuffers; friend class CHyprOpenGLImpl; friend class CToplevelExportProtocolManager; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 46c501a0..0f5b4c4c 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -9,7 +9,7 @@ CTexture::CTexture() { } CTexture::~CTexture() { - if (m_bNonOwning || !g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer) + if (!g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer) return; g_pHyprRenderer->makeEGLCurrent(); @@ -17,6 +17,45 @@ CTexture::~CTexture() { } CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) { + createFromShm(drmFormat, pixels, stride, size_); +} + +CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) { + createFromDma(attrs, image); +} + +CTexture::CTexture(const SP buffer) { + if (!buffer) + return; + + auto attrs = buffer->dmabuf(); + + if (!attrs.success) { + // attempt shm + auto shm = buffer->shm(); + + if (!shm.success) { + Debug::log(ERR, "Cannot create a texture: buffer has no dmabuf or shm"); + return; + } + + auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); + + createFromShm(fmt, pixelData, bufLen, shm.size); + return; + } + + auto image = g_pHyprOpenGL->createEGLImage(buffer->dmabuf()); + + if (!image) { + Debug::log(ERR, "Cannot create a texture: failed to create an EGLImage"); + return; + } + + createFromDma(attrs, image); +} + +void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) { g_pHyprRenderer->makeEGLCurrent(); const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat); @@ -41,24 +80,7 @@ CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const V GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); } -CTexture::CTexture(wlr_texture* tex) { - RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!"); - wlr_gles2_texture_attribs attrs; - wlr_gles2_texture_get_attribs(tex, &attrs); - - m_iTarget = attrs.target; - m_iTexID = attrs.tex; - m_bNonOwning = true; - - if (m_iTarget == GL_TEXTURE_2D) - m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX; - else - m_iType = TEXTURE_EXTERNAL; - - m_vSize = Vector2D((int)tex->width, (int)tex->height); -} - -CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) { +void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) { if (!g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES) { Debug::log(ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES"); return; @@ -119,7 +141,7 @@ void CTexture::destroyTexture() { } if (m_pEglImage) - g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_pEglImage); + g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_pEglImage); m_pEglImage = nullptr; } diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index c80e943d..0da95300 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -1,9 +1,9 @@ #pragma once #include "../defines.hpp" +#include -class IWLBuffer; -struct SDMABUFAttrs; +class IHLBuffer; HYPRUTILS_FORWARD(Math, CRegion); enum TEXTURETYPE { @@ -23,10 +23,10 @@ class CTexture { CTexture(const CTexture&) = delete; CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); - CTexture(wlr_texture*); + CTexture(const SP buffer); // this ctor takes ownership of the eglImage. - CTexture(const SDMABUFAttrs&, void* image); + CTexture(const Aquamarine::SDMABUFAttrs&, void* image); ~CTexture(); void destroyTexture(); @@ -37,6 +37,9 @@ class CTexture { GLenum m_iTarget = GL_TEXTURE_2D; GLuint m_iTexID = 0; Vector2D m_vSize; - void* m_pEglImage = nullptr; - bool m_bNonOwning = false; // wlr + void* m_pEglImage = nullptr; + + private: + void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); + void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image); }; \ No newline at end of file diff --git a/src/signal-safe.hpp b/src/signal-safe.hpp index 70320ad1..3a38f043 100644 --- a/src/signal-safe.hpp +++ b/src/signal-safe.hpp @@ -1,6 +1,7 @@ #pragma once #include "defines.hpp" +#include template class MaxLengthCString { diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index e2dab412..3f4e7b43 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -18,12 +18,13 @@ #include #include #include +#include // TODO: cleanup static bool set_cloexec(int fd, bool cloexec) { int flags = fcntl(fd, F_GETFD); if (flags == -1) { - wlr_log_errno(WLR_ERROR, "fcntl failed"); + Debug::log(ERR, "fcntl failed"); return false; } if (cloexec) { @@ -32,7 +33,7 @@ static bool set_cloexec(int fd, bool cloexec) { flags = flags & ~FD_CLOEXEC; } if (fcntl(fd, F_SETFD, flags) == -1) { - wlr_log_errno(WLR_ERROR, "fcntl failed"); + Debug::log(ERR, "fcntl failed"); return false; } return true; @@ -44,7 +45,7 @@ static int openSocket(struct sockaddr_un* addr, size_t path_size) { fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to create socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + Debug::log(ERR, "failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); return -1; } if (!set_cloexec(fd, true)) { @@ -57,12 +58,12 @@ static int openSocket(struct sockaddr_un* addr, size_t path_size) { } if (bind(fd, (struct sockaddr*)addr, size) < 0) { rc = errno; - wlr_log_errno(WLR_ERROR, "Failed to bind socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + Debug::log(ERR, "failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); goto cleanup; } if (listen(fd, 1) < 0) { rc = errno; - wlr_log_errno(WLR_ERROR, "Failed to listen to socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + Debug::log(ERR, "failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); goto cleanup; } diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index b34d0cfe..b55df7fc 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -299,8 +299,8 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { auto id = e->data.data32[0]; auto resource = wl_client_get_object(g_pXWayland->pServer->xwaylandClient, id); if (resource) { - auto wlrSurface = CWLSurfaceResource::fromResource(resource); - associate(XSURF, wlrSurface); + auto surf = CWLSurfaceResource::fromResource(resource); + associate(XSURF, surf); } } else if (e->type == HYPRATOMS["WL_SURFACE_SERIAL"]) { if (XSURF->wlSerial) { @@ -755,7 +755,7 @@ void CXWM::getVisual() { } if (visualtype == NULL) { - wlr_log(WLR_DEBUG, "No 32 bit visualtype\n"); + Debug::log(LOG, "xwm: No 32-bit visualtype"); return; } @@ -768,7 +768,7 @@ void CXWM::getRenderFormat() { xcb_render_query_pict_formats_cookie_t cookie = xcb_render_query_pict_formats(connection); xcb_render_query_pict_formats_reply_t* reply = xcb_render_query_pict_formats_reply(connection, cookie, NULL); if (!reply) { - wlr_log(WLR_ERROR, "Did not get any reply from xcb_render_query_pict_formats"); + Debug::log(LOG, "xwm: No xcb_render_query_pict_formats_reply_t reply"); return; } xcb_render_pictforminfo_iterator_t iter = xcb_render_query_pict_formats_formats_iterator(reply); @@ -783,7 +783,7 @@ void CXWM::getRenderFormat() { } if (format == NULL) { - wlr_log(WLR_DEBUG, "No 32 bit render format"); + Debug::log(LOG, "xwm: No 32-bit render format"); free(reply); return; } diff --git a/subprojects/wlroots-hyprland b/subprojects/wlroots-hyprland deleted file mode 160000 index 422207db..00000000 --- a/subprojects/wlroots-hyprland +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 422207dbcf0949e28042403edab539159282885e From cf373d315e9fb060576ed407bd5ee2dfb8a6d2e2 Mon Sep 17 00:00:00 2001 From: khachbe Date: Sun, 21 Jul 2024 13:59:09 +0200 Subject: [PATCH 06/14] touch: add touch swipe invert config (#6940) --- src/config/ConfigManager.cpp | 1 + src/managers/input/Touch.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index a5f18693..6928a802 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -519,6 +519,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("gestures:workspace_swipe_forever", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_use_r", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_touch", Hyprlang::INT{0}); + m_pConfig->addConfigValue("gestures:workspace_swipe_touch_invert", Hyprlang::INT{0}); m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1}); m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0}); diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index a1f949c2..736a2ae5 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -103,7 +103,7 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { return; const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); - static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_invert"); + static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_touch_invert"); static auto PSWIPEDIST = CConfigValue("gestures:workspace_swipe_distance"); const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); // Handle the workspace swipe if there is one From 043b859ea2ec8173d8a0f1f90012fcca82275d22 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 16:42:43 +0200 Subject: [PATCH 07/14] hyprpm: init submodules after resets ref #6948 --- hyprpm/src/core/PluginManager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 7d7cc079..036609f3 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -172,6 +172,9 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n"; return false; } + ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); + if (m_bVerbose) + std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; } progress.m_iSteps = 1; @@ -226,6 +229,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); + + ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); + if (m_bVerbose) + std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; + + break; } } From efcbcd7297e2c9b06e3cd5d3296d47504f502cee Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 16:45:40 +0200 Subject: [PATCH 08/14] input: fix invalid usage of dev in setTouchDeviceConfigs ref #6943 --- src/managers/input/InputManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 255023b9..492d2805 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1488,9 +1488,9 @@ void CInputManager::newTouchDevice(SP pDevice) { } void CInputManager::setTouchDeviceConfigs(SP dev) { - auto setConfig = [&](SP PTOUCHDEV) -> void { - if (dev->aq() && dev->aq()->getLibinputHandle()) { - const auto LIBINPUTDEV = dev->aq()->getLibinputHandle(); + auto setConfig = [](SP PTOUCHDEV) -> void { + if (PTOUCHDEV->aq() && PTOUCHDEV->aq()->getLibinputHandle()) { + const auto LIBINPUTDEV = PTOUCHDEV->aq()->getLibinputHandle(); const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->hlName, "enabled", "input:touchdevice:enabled"); const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; From f7fb7e7e49e3b47f9b72c55fbf2d093e1a7981f5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 17:27:15 +0200 Subject: [PATCH 09/14] xwayland: avoid unfocusing on OR child focuses fixes #6698 --- src/xwayland/XWM.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index b55df7fc..0eaa16be 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -398,10 +398,10 @@ void CXWM::focusWindow(SP surf) { focusedSurface = surf; - // send state to all surfaces, sometimes we might lose some + // send state to all toplevel surfaces, sometimes we might lose some // that could still stick with the focused atom for (auto& s : mappedSurfaces) { - if (!s) + if (!s || s->overrideRedirect) continue; sendState(s.lock()); @@ -879,7 +879,7 @@ void CXWM::activateSurface(SP surf, bool activate) { if ((surf == focusedSurface && activate) || (surf && surf->overrideRedirect)) return; - if (!activate || !surf) { + if (!surf || (!activate || !surf->overrideRedirect /* if we are focusing on an OR child, don't unfocus parent */)) { setActiveWindow((uint32_t)XCB_WINDOW_NONE); focusWindow(nullptr); } else { From 7f624d2236162db847c70ce1caa12851e77e60eb Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 17:41:26 +0200 Subject: [PATCH 10/14] xwayland: fixup WM_SIZE_HINTS handling according to ICCCM --- src/managers/XWaylandManager.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index e702a172..f329dbe1 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -76,13 +76,21 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); if (SIZEHINTS && pWindow->m_iX11Type != 2) { - pbox->x = SIZEHINTS->x; - pbox->y = SIZEHINTS->y; - pbox->width = SIZEHINTS->width; - pbox->height = SIZEHINTS->height; - } else { + // WM_SIZE_HINTS' x,y,w,h is deprecated it seems. + // Source: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#wm_normal_hints_property + pbox->x = pWindow->m_pXWaylandSurface->geometry.x; + pbox->y = pWindow->m_pXWaylandSurface->geometry.y; + + if ((SIZEHINTS->flags & 0x2 /* ICCCM USSize */) || (SIZEHINTS->flags & 0x8 /* ICCCM PSize */)) { + pbox->w = SIZEHINTS->base_width; + pbox->h = SIZEHINTS->base_height; + } else { + pbox->w = pWindow->m_pXWaylandSurface->geometry.w; + pbox->h = pWindow->m_pXWaylandSurface->geometry.h; + } + } else *pbox = pWindow->m_pXWaylandSurface->geometry; - } + } else if (pWindow->m_pXDGSurface) *pbox = pWindow->m_pXDGSurface->current.geometry; } From faa157e1626fb56b5f01ac0597518cc41bf1c40b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 18 Jul 2024 21:18:07 +0300 Subject: [PATCH 11/14] gitignore: add CMake residual files --- .gitignore | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 3601f422..78f794fc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ cmake_install.cmake install_manifest.txt compile_commands.json CTestTestfile.cmake +CPackConfig.cmake +CPackSourceConfig.cmake +hyprland.pc _deps build/ @@ -15,6 +18,9 @@ result* /.idea/ .envrc .cache +.direnv +/.cmake/ +/.worktree/ *.o protocols/*.c* @@ -31,5 +37,3 @@ gmon.out PKGBUILD src/version.h - -.direnv From 928d1dd38a6e4a791d4a4374a4a3bf02311adbb2 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 18 Jul 2024 21:27:03 +0300 Subject: [PATCH 12/14] CMake, Meson, Nix: replace props.json with VERSION --- CMakeLists.txt | 4 ++-- VERSION | 1 + meson.build | 2 +- nix/overlays.nix | 5 ++--- props.json | 3 --- 5 files changed, 6 insertions(+), 9 deletions(-) create mode 100644 VERSION delete mode 100644 props.json diff --git a/CMakeLists.txt b/CMakeLists.txt index e951b874..b65d361e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,8 @@ include(CheckIncludeFile) include(GNUInstallDirs) # Get version -file(READ ${CMAKE_CURRENT_SOURCE_DIR}/props.json PROPS) -string(JSON VER GET ${PROPS} version) +file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) +string(STRIP ${VER_RAW} VER) project(Hyprland DESCRIPTION "A Modern C++ Wayland Compositor" diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..6599454d --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.41.2 diff --git a/meson.build b/meson.build index b8101f6c..4446ea0f 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('Hyprland', 'cpp', 'c', - version : run_command('jq', '-r', '.version', join_paths(meson.source_root(), 'props.json'), check: true).stdout().strip(), + version : run_command('cat', join_paths(meson.source_root(), 'VERSION'), check: true).stdout().strip(), default_options : [ 'warning_level=2', 'default_library=static', diff --git a/nix/overlays.nix b/nix/overlays.nix index 9d100d51..d8979b45 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -3,13 +3,12 @@ lib, inputs, }: let - props = builtins.fromJSON (builtins.readFile ../props.json); - mkDate = longDate: (lib.concatStringsSep "-" [ (builtins.substring 0 4 longDate) (builtins.substring 4 2 longDate) (builtins.substring 6 2 longDate) ]); + version = lib.removeSuffix "\n" (builtins.readFile ../VERSION); in { # Contains what a user is most likely to care about: # Hyprland itself, XDPH and the Share Picker. @@ -33,7 +32,7 @@ in { in { hyprland = final.callPackage ./default.nix { stdenv = final.gcc13Stdenv; - version = "${props.version}+date=${date}_${self.shortRev or "dirty"}"; + version = "${version}+date=${date}_${self.shortRev or "dirty"}"; commit = self.rev or ""; inherit date; }; diff --git a/props.json b/props.json deleted file mode 100644 index 2ff7562e..00000000 --- a/props.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "version": "0.41.2" -} \ No newline at end of file From db1f5cd13732bc440b8e5e353d87cdf7faaf1872 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 18 Jul 2024 21:27:41 +0300 Subject: [PATCH 13/14] CMake: fmt --- CMakeLists.txt | 427 +++++++++++++++++++++++++++---------------------- 1 file changed, 236 insertions(+), 191 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b65d361e..2bd4e0d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,10 @@ include(GNUInstallDirs) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) string(STRIP ${VER_RAW} VER) -project(Hyprland - DESCRIPTION "A Modern C++ Wayland Compositor" - VERSION ${VER} -) +project( + Hyprland + DESCRIPTION "A Modern C++ Wayland Compositor" + VERSION ${VER}) set(HYPRLAND_VERSION ${VER}) set(PREFIX ${CMAKE_INSTALL_PREFIX}) @@ -21,32 +21,30 @@ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") message(STATUS "Gathering git info") -# Get git info -# hash and branch -execute_process( - COMMAND ./scripts/generateVersion.sh - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) +# Get git info hash and branch +execute_process(COMMAND ./scripts/generateVersion.sh + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) # udis add_subdirectory("subprojects/udis86") if(CMAKE_BUILD_TYPE) - string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) - if(BUILDTYPE_LOWER STREQUAL "release") - # Pass. - elseif(BUILDTYPE_LOWER STREQUAL "debug") - # Pass. - elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo") - set(BUILDTYPE_LOWER "debugoptimized") - elseif(BUILDTYPE_LOWER STREQUAL "minsizerel") - set(BUILDTYPE_LOWER "minsize") - elseif(BUILDTYPE_LOWER STREQUAL "none") - set(BUILDTYPE_LOWER "plain") - else() - set(BUILDTYPE_LOWER "release") - endif() -else() + string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) + if(BUILDTYPE_LOWER STREQUAL "release") + # Pass. + elseif(BUILDTYPE_LOWER STREQUAL "debug") + # Pass. + elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo") + set(BUILDTYPE_LOWER "debugoptimized") + elseif(BUILDTYPE_LOWER STREQUAL "minsizerel") + set(BUILDTYPE_LOWER "minsize") + elseif(BUILDTYPE_LOWER STREQUAL "none") + set(BUILDTYPE_LOWER "plain") + else() set(BUILDTYPE_LOWER "release") + endif() +else() + set(BUILDTYPE_LOWER "release") endif() find_package(PkgConfig REQUIRED) @@ -58,22 +56,24 @@ message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) - message(STATUS "Configuring Hyprland in Debug with CMake") - add_compile_definitions(HYPRLAND_DEBUG) + message(STATUS "Configuring Hyprland in Debug with CMake") + add_compile_definitions(HYPRLAND_DEBUG) else() - add_compile_options(-O3) - message(STATUS "Configuring Hyprland in Release with CMake") + add_compile_options(-O3) + message(STATUS "Configuring Hyprland in Release with CMake") endif() -include_directories( - . - "src/" - "subprojects/udis86/" - "protocols/") +include_directories(. "src/" "subprojects/udis86/" "protocols/") set(CMAKE_CXX_STANDARD 23) -add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value - -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith - -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) +add_compile_options( + -Wall + -Wextra + -Wno-unused-parameter + -Wno-unused-value + -Wno-missing-field-initializers + -Wno-narrowing + -Wno-pointer-arith + -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE) set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) @@ -83,20 +83,39 @@ message(STATUS "Checking deps...") find_package(Threads REQUIRED) if(LEGACY_RENDERER) - set(GLES_VERSION "GLES2") + set(GLES_VERSION "GLES2") else() - set(GLES_VERSION "GLES3") + set(GLES_VERSION "GLES3") endif() find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET - aquamarine - xkbcommon uuid - wayland-server wayland-client wayland-cursor wayland-protocols - cairo pango pangocairo pixman-1 xcursor - libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.2.0 -) +pkg_check_modules( + deps + REQUIRED + IMPORTED_TARGET + aquamarine + xkbcommon + uuid + wayland-server + wayland-client + wayland-cursor + wayland-protocols + cairo + pango + pangocairo + pixman-1 + xcursor + libdrm + libinput + hwdata + libseat + libdisplay-info + libliftoff + libudev + gbm + hyprlang>=0.3.2 + hyprcursor>=0.1.7 + hyprutils>=0.2.0) find_package(hyprwayland-scanner 0.3.10 REQUIRED) @@ -104,8 +123,8 @@ file(GLOB_RECURSE SRCFILES "src/*.cpp") set(TRACY_CPP_FILES "") if(USE_TRACY) - set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp") - message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES}) + set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp") + message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES}) endif() add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) @@ -113,75 +132,88 @@ add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) set(USE_GPROF ON) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) - message(STATUS "Setting debug flags") + message(STATUS "Setting debug flags") - if (WITH_ASAN) - message(STATUS "Enabling ASan") + if(WITH_ASAN) + message(STATUS "Enabling ASan") - target_link_libraries(Hyprland asan) - target_compile_options(Hyprland PUBLIC -fsanitize=address) + target_link_libraries(Hyprland asan) + target_compile_options(Hyprland PUBLIC -fsanitize=address) + endif() + + if(USE_TRACY) + message(STATUS "Tracy is turned on") + + option(TRACY_ENABLE "" ON) + option(TRACY_ON_DEMAND "" ON) + add_subdirectory(subprojects/tracy) + + target_link_libraries(Hyprland Tracy::TracyClient) + + if(USE_TRACY_GPU) + message(STATUS "Tracy GPU Profiling is turned on") + add_compile_definitions(USE_TRACY_GPU) endif() + endif() - if(USE_TRACY) - message(STATUS "Tracy is turned on") - - option( TRACY_ENABLE "" ON) - option( TRACY_ON_DEMAND "" ON) - add_subdirectory (subprojects/tracy) - - target_link_libraries(Hyprland Tracy::TracyClient) - - if(USE_TRACY_GPU) - message(STATUS "Tracy GPU Profiling is turned on") - add_compile_definitions(USE_TRACY_GPU) - endif() - endif() - - add_compile_options(-fno-pie -fno-builtin) - add_link_options(-no-pie -fno-builtin) - if(USE_GPROF) - add_compile_options(-pg) - add_link_options(-pg) - endif() + add_compile_options(-fno-pie -fno-builtin) + add_link_options(-no-pie -fno-builtin) + if(USE_GPROF) + add_compile_options(-pg) + add_link_options(-pg) + endif() endif() check_include_file("execinfo.h" EXECINFOH) if(EXECINFOH) - message(STATUS "Configuration supports execinfo") - add_compile_definitions(HAS_EXECINFO) + message(STATUS "Configuration supports execinfo") + add_compile_definitions(HAS_EXECINFO) endif() include(CheckLibraryExists) check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO) if(HAVE_LIBEXECINFO) - target_link_libraries(Hyprland execinfo) + target_link_libraries(Hyprland execinfo) endif() check_include_file("sys/timerfd.h" HAS_TIMERFD) pkg_check_modules(epoll IMPORTED_TARGET epoll-shim) if(NOT HAS_TIMERFD AND epoll_FOUND) - target_link_libraries(Hyprland PkgConfig::epoll) + target_link_libraries(Hyprland PkgConfig::epoll) endif() if(LEGACY_RENDERER) - message(STATUS "Using the legacy GLES2 renderer!") - add_compile_definitions(LEGACY_RENDERER) + message(STATUS "Using the legacy GLES2 renderer!") + add_compile_definitions(LEGACY_RENDERER) endif() if(NO_XWAYLAND) - message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!") - add_compile_definitions(NO_XWAYLAND) + message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!") + add_compile_definitions(NO_XWAYLAND) else() - message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...") - pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh xcb-errors) - target_link_libraries(Hyprland PkgConfig::xdeps) + message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...") + pkg_check_modules( + xdeps + REQUIRED + IMPORTED_TARGET + xcb + xwayland + xcb-util + xcb-render + xcb-xfixes + xcb-icccm + xcb-composite + xcb-res + xcb-ewmh + xcb-errors) + target_link_libraries(Hyprland PkgConfig::xdeps) endif() if(NO_SYSTEMD) - message(STATUS "SYSTEMD support is disabled...") + message(STATUS "SYSTEMD support is disabled...") else() - message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") - add_compile_definitions(USES_SYSTEMD) + message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") + add_compile_definitions(USES_SYSTEMD) endif() set(CPACK_PROJECT_NAME ${PROJECT_NAME}) @@ -190,7 +222,8 @@ include(CPack) message(STATUS "Setting precompiled headers") -target_precompile_headers(Hyprland PRIVATE $<$:src/pch/pch.hpp>) +target_precompile_headers(Hyprland PRIVATE + $<$:src/pch/pch.hpp>) message(STATUS "Setting link libraries") @@ -200,104 +233,115 @@ target_link_libraries(Hyprland rt PkgConfig::deps) add_custom_target(generate-protocol-headers) function(protocol protoPath protoName external) - if (external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) - else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) - endif() + if(external) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + else() + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) + endif() - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h - COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c - COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) - target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h + COMMAND ${WaylandScanner} server-header ${path} + protocols/${protoName}-protocol.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c + COMMAND ${WaylandScanner} private-code ${path} + protocols/${protoName}-protocol.c + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources( + Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h + ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) + target_sources(generate-protocol-headers + PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) endfunction() -function(protocolNew protoPath protoName external) - if (external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) - else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) - endif() - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp - ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp - COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - target_sources(Hyprland PRIVATE protocols/${protoName}.cpp protocols/${protoName}.hpp) - target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp) +function(protocolnew protoPath protoName external) + if(external) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + else() + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) + endif() + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp + ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp + COMMAND hyprwayland-scanner ${path}/${protoName}.xml + ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}.cpp + protocols/${protoName}.hpp) + target_sources(generate-protocol-headers + PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp) endfunction() function(protocolWayland) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp - ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp - COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) - target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp + ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp + COMMAND hyprwayland-scanner --wayland-enums + ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) + target_sources(generate-protocol-headers + PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) endfunction() -target_link_libraries(Hyprland - OpenGL::EGL - OpenGL::GL - Threads::Threads - libudis86 - uuid -) +target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads + libudis86 uuid) -protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) -protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) -protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) -protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) +protocol("protocols/wlr-screencopy-unstable-v1.xml" + "wlr-screencopy-unstable-v1" true) +protocol( + "subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" + "hyprland-global-shortcuts-v1" true) +protocol( + "subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" + "hyprland-toplevel-export-v1" true) +protocol("unstable/text-input/text-input-unstable-v1.xml" + "text-input-unstable-v1" false) -protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) -protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) -protocolNew("protocols" "wlr-output-power-management-unstable-v1" true) -protocolNew("protocols" "virtual-keyboard-unstable-v1" true) -protocolNew("protocols" "wlr-virtual-pointer-unstable-v1" true) -protocolNew("protocols" "input-method-unstable-v2" true) -protocolNew("protocols" "wlr-output-management-unstable-v1" true) -protocolNew("protocols" "kde-server-decoration" true) -protocolNew("protocols" "wlr-data-control-unstable-v1" true) -protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true) -protocolNew("protocols" "wlr-layer-shell-unstable-v1" true) -protocolNew("protocols" "wayland-drm" true) -protocolNew("staging/tearing-control" "tearing-control-v1" false) -protocolNew("staging/fractional-scale" "fractional-scale-v1" false) -protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false) -protocolNew("staging/cursor-shape" "cursor-shape-v1" false) -protocolNew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false) -protocolNew("unstable/relative-pointer" "relative-pointer-unstable-v1" false) -protocolNew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false) -protocolNew("staging/alpha-modifier" "alpha-modifier-v1" false) -protocolNew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false) -protocolNew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false) -protocolNew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false) -protocolNew("unstable/text-input" "text-input-unstable-v3" false) -protocolNew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" false) -protocolNew("staging/xdg-activation" "xdg-activation-v1" false) -protocolNew("staging/ext-idle-notify" "ext-idle-notify-v1" false) -protocolNew("staging/ext-session-lock" "ext-session-lock-v1" false) -protocolNew("stable/tablet" "tablet-v2" false) -protocolNew("stable/presentation-time" "presentation-time" false) -protocolNew("stable/xdg-shell" "xdg-shell" false) -protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) -protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false) -protocolNew("stable/viewporter" "viewporter" false) -protocolNew("stable/linux-dmabuf" "linux-dmabuf-v1" false) -protocolNew("staging/drm-lease" "drm-lease-v1" false) -protocolNew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) +protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) +protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) +protocolnew("protocols" "wlr-output-power-management-unstable-v1" true) +protocolnew("protocols" "virtual-keyboard-unstable-v1" true) +protocolnew("protocols" "wlr-virtual-pointer-unstable-v1" true) +protocolnew("protocols" "input-method-unstable-v2" true) +protocolnew("protocols" "wlr-output-management-unstable-v1" true) +protocolnew("protocols" "kde-server-decoration" true) +protocolnew("protocols" "wlr-data-control-unstable-v1" true) +protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" + true) +protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolnew("protocols" "wayland-drm" true) +protocolnew("staging/tearing-control" "tearing-control-v1" false) +protocolnew("staging/fractional-scale" "fractional-scale-v1" false) +protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false) +protocolnew("staging/cursor-shape" "cursor-shape-v1" false) +protocolnew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false) +protocolnew("unstable/relative-pointer" "relative-pointer-unstable-v1" false) +protocolnew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false) +protocolnew("staging/alpha-modifier" "alpha-modifier-v1" false) +protocolnew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" + false) +protocolnew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false) +protocolnew("unstable/keyboard-shortcuts-inhibit" + "keyboard-shortcuts-inhibit-unstable-v1" false) +protocolnew("unstable/text-input" "text-input-unstable-v3" false) +protocolnew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" + false) +protocolnew("staging/xdg-activation" "xdg-activation-v1" false) +protocolnew("staging/ext-idle-notify" "ext-idle-notify-v1" false) +protocolnew("staging/ext-session-lock" "ext-session-lock-v1" false) +protocolnew("stable/tablet" "tablet-v2" false) +protocolnew("stable/presentation-time" "presentation-time" false) +protocolnew("stable/xdg-shell" "xdg-shell" false) +protocolnew("unstable/primary-selection" "primary-selection-unstable-v1" false) +protocolnew("staging/xwayland-shell" "xwayland-shell-v1" false) +protocolnew("stable/viewporter" "viewporter" false) +protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false) +protocolnew("staging/drm-lease" "drm-lease-v1" false) +protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) -protocolWayland() +protocolwayland() # tools add_subdirectory(hyprctl) @@ -306,12 +350,12 @@ add_subdirectory(hyprpm) # binary and symlink install(TARGETS Hyprland) -install(CODE "execute_process( \ +install( + CODE "execute_process( \ COMMAND ${CMAKE_COMMAND} -E create_symlink \ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \ ${CMAKE_INSTALL_FULL_BINDIR}/hyprland - )" -) + )") # session file install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop @@ -319,8 +363,7 @@ install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop # wallpapers file(GLOB_RECURSE WALLPAPERS "assets/wall*") -install(FILES ${WALLPAPERS} - DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) +install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) # default config install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf @@ -332,9 +375,7 @@ install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf # man pages file(GLOB_RECURSE MANPAGES "docs/*.1") -install(FILES ${MANPAGES} - DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) - +install(FILES ${MANPAGES} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) # pkgconfig entry install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc @@ -342,12 +383,16 @@ install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc # protocol headers set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols") -install(DIRECTORY ${HEADERS_PROTO} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland - FILES_MATCHING PATTERN "*.h*") +install( + DIRECTORY ${HEADERS_PROTO} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland + FILES_MATCHING + PATTERN "*.h*") # hyprland headers set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src") -install(DIRECTORY ${HEADERS_SRC} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland - FILES_MATCHING PATTERN "*.h*") +install( + DIRECTORY ${HEADERS_SRC} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland + FILES_MATCHING + PATTERN "*.h*") From e6fc9873b5e10e7ac00085da7d599776ed72f297 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 21 Jul 2024 19:31:36 +0300 Subject: [PATCH 14/14] flake.lock: update --- flake.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/flake.lock b/flake.lock index b2cc9703..f61f18a1 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1721487522, - "narHash": "sha256-aF3uwUwUK2CgbItoMe3IJF0yidIEWcDx47AiH5y8VKk=", + "lastModified": 1721571743, + "narHash": "sha256-hat7wggtDISBJD8kTo5MTrT+IsY/Ha2MwgjmqqijoCA=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "acfea3bd1d9e756c7152e639240d52c6628844b0", + "rev": "601f6cf95cbe4fef02dc7faf34bba58566c914e9", "type": "github" }, "original": { @@ -42,11 +42,11 @@ ] }, "locked": { - "lastModified": 1720108799, - "narHash": "sha256-AxRkTJlbB8r7aG6gvc7IaLhc2T9TO4/8uqanKRxukBQ=", + "lastModified": 1721330371, + "narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "a5c0d57325c5f0814c39110a70ca19c070ae9486", + "rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc", "type": "github" }, "original": { @@ -93,11 +93,11 @@ ] }, "locked": { - "lastModified": 1720381373, - "narHash": "sha256-lyC/EZdHULsaAKVryK11lgHY9u6pXr7qR4irnxNWC7k=", + "lastModified": 1721324361, + "narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "5df0174fd09de4ac5475233d65ffc703e89b82eb", + "rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086", "type": "github" }, "original": { @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1721071737, - "narHash": "sha256-qmC9jGfbE4+EIBbbSAkrfR/p49wShjpv4/KztgE/P54=", + "lastModified": 1721324102, + "narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "eb1ceff2b87f6820789249f63faa8e9dcb54d05f", + "rev": "962582a090bc233c4de9d9897f46794280288989", "type": "github" }, "original": { @@ -139,11 +139,11 @@ ] }, "locked": { - "lastModified": 1720215857, - "narHash": "sha256-JPdL+Qul+jEueAn8CARfcWP83eJgwkhMejQYfDvrgvU=", + "lastModified": 1721324119, + "narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "d5fa094ca27e0039be5e94c0a80ae433145af8bb", + "rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1720957393, - "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=", + "lastModified": 1721379653, + "narHash": "sha256-8MUgifkJ7lkZs3u99UDZMB4kbOxvMEXQZ31FO3SopZ0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "693bc46d169f5af9c992095736e82c3488bf7dbb", + "rev": "1d9c2c9b3e71b9ee663d11c5d298727dace8d374", "type": "github" }, "original": {