From 232ad43ee878d1d584eceeba0279489ac3ffcaa2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 5 May 2024 22:18:10 +0100 Subject: [PATCH] cursor: move to a hyprland impl This moves wlr_cursor to a completely new impl mostly under CPointerManager Also adds beginSimple to OpenGL for simple render passes (e.g. cursor) --- CMakeLists.txt | 2 +- src/Compositor.cpp | 98 ++-- src/Compositor.hpp | 4 +- src/config/ConfigManager.cpp | 3 + src/debug/HyprCtl.cpp | 4 +- src/debug/HyprDebugOverlay.cpp | 2 +- src/desktop/WLSurface.cpp | 2 +- src/desktop/Window.cpp | 2 +- src/devices/IHID.cpp | 5 + src/devices/IHID.hpp | 11 + src/devices/IKeyboard.cpp | 4 + src/devices/IKeyboard.hpp | 1 + src/devices/IPointer.cpp | 4 + src/devices/IPointer.hpp | 2 + src/devices/ITouch.cpp | 6 +- src/devices/ITouch.hpp | 8 +- src/devices/Mouse.cpp | 5 + src/devices/TouchDevice.cpp | 1 + src/devices/VirtualPointer.cpp | 5 + src/events/Devices.cpp | 80 --- src/events/Events.hpp | 27 - src/events/Monitors.cpp | 23 +- src/events/Windows.cpp | 6 +- src/helpers/Box.cpp | 20 +- src/helpers/Box.hpp | 5 +- src/helpers/Monitor.cpp | 36 +- src/helpers/Monitor.hpp | 4 + src/helpers/Region.cpp | 5 +- src/helpers/Vector2D.cpp | 8 +- src/helpers/Vector2D.hpp | 1 + src/hyprerror/HyprError.cpp | 2 +- src/includes.hpp | 2 - src/managers/CursorManager.cpp | 75 ++- src/managers/CursorManager.hpp | 13 +- src/managers/KeybindManager.cpp | 45 +- src/managers/KeybindManager.hpp | 7 +- src/managers/PointerManager.cpp | 864 ++++++++++++++++++++++++++++ src/managers/PointerManager.hpp | 158 +++++ src/managers/input/InputManager.cpp | 90 +-- src/managers/input/InputManager.hpp | 28 +- src/managers/input/Swipe.cpp | 14 +- src/managers/input/Tablets.cpp | 24 +- src/managers/input/Touch.cpp | 52 +- src/protocols/Screencopy.cpp | 22 +- src/protocols/Screencopy.hpp | 5 +- src/protocols/ToplevelExport.cpp | 19 +- src/render/OpenGL.cpp | 90 ++- src/render/OpenGL.hpp | 47 +- src/render/Renderbuffer.cpp | 8 +- src/render/Renderbuffer.hpp | 2 + src/render/Renderer.cpp | 72 +-- src/render/Renderer.hpp | 25 +- 52 files changed, 1551 insertions(+), 497 deletions(-) create mode 100644 src/devices/IHID.cpp create mode 100644 src/managers/PointerManager.cpp create mode 100644 src/managers/PointerManager.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ef077d8b..f491e100 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprwayland-scanner>=0.3.4 hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprwayland-scanner>=0.3.5 hyprlang>=0.3.2 hyprcursor>=0.1.7 ) file(GLOB_RECURSE SRCFILES "src/*.cpp") diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 96831751..14b43aca 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -3,6 +3,7 @@ #include "config/ConfigValue.hpp" #include "managers/CursorManager.hpp" #include "managers/TokenManager.hpp" +#include "managers/PointerManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" #include #include @@ -227,13 +228,8 @@ void CCompositor::initServer() { wlr_primary_selection_v1_device_manager_create(m_sWLDisplay); wlr_viewporter_create(m_sWLDisplay); - m_sWLROutputLayout = wlr_output_layout_create(m_sWLDisplay); - m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 6); - m_sWLRCursor = wlr_cursor_create(); - wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout); - m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0"); m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend); @@ -246,7 +242,7 @@ void CCompositor::initServer() { Debug::log(INFO, "VR will not be available"); } - m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay); + // m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay); m_sWLRForeignRegistry = wlr_xdg_foreign_registry_create(m_sWLDisplay); @@ -270,23 +266,6 @@ void CCompositor::initServer() { void CCompositor::initAllSignals() { addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend"); addWLSignal(&m_sWLRXDGShell->events.new_toplevel, &Events::listen_newXDGToplevel, m_sWLRXDGShell, "XDG Shell"); - addWLSignal(&m_sWLRCursor->events.motion, &Events::listen_mouseMove, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.motion_absolute, &Events::listen_mouseMoveAbsolute, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.button, &Events::listen_mouseButton, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.axis, &Events::listen_mouseAxis, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.frame, &Events::listen_mouseFrame, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.swipe_begin, &Events::listen_swipeBegin, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.swipe_update, &Events::listen_swipeUpdate, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.swipe_end, &Events::listen_swipeEnd, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.pinch_begin, &Events::listen_pinchBegin, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.pinch_update, &Events::listen_pinchUpdate, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.pinch_end, &Events::listen_pinchEnd, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.touch_down, &Events::listen_touchBegin, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.touch_up, &Events::listen_touchEnd, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.touch_motion, &Events::listen_touchUpdate, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.touch_frame, &Events::listen_touchFrame, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.hold_begin, &Events::listen_holdBegin, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.hold_end, &Events::listen_holdEnd, m_sWLRCursor, "WLRCursor"); addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend"); addWLSignal(&m_sSeat.seat->events.request_set_cursor, &Events::listen_requestMouse, &m_sSeat, "Seat"); addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); @@ -307,23 +286,6 @@ void CCompositor::initAllSignals() { void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_newOutput); removeWLSignal(&Events::listen_newXDGToplevel); - removeWLSignal(&Events::listen_mouseMove); - removeWLSignal(&Events::listen_mouseMoveAbsolute); - removeWLSignal(&Events::listen_mouseButton); - removeWLSignal(&Events::listen_mouseAxis); - removeWLSignal(&Events::listen_mouseFrame); - removeWLSignal(&Events::listen_swipeBegin); - removeWLSignal(&Events::listen_swipeUpdate); - removeWLSignal(&Events::listen_swipeEnd); - removeWLSignal(&Events::listen_pinchBegin); - removeWLSignal(&Events::listen_pinchUpdate); - removeWLSignal(&Events::listen_pinchEnd); - removeWLSignal(&Events::listen_touchBegin); - removeWLSignal(&Events::listen_touchEnd); - removeWLSignal(&Events::listen_touchUpdate); - removeWLSignal(&Events::listen_touchFrame); - removeWLSignal(&Events::listen_holdBegin); - removeWLSignal(&Events::listen_holdEnd); removeWLSignal(&Events::listen_newInput); removeWLSignal(&Events::listen_requestMouse); removeWLSignal(&Events::listen_requestSetSel); @@ -410,9 +372,6 @@ void CCompositor::cleanup() { g_pWatchdog.reset(); g_pXWaylandManager.reset(); - if (m_sWLRCursor) - wlr_cursor_destroy(m_sWLRCursor); - if (m_sSeat.seat) wlr_seat_destroy(m_sSeat.seat); @@ -461,6 +420,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pConfigManager->init(); g_pWatchdog = std::make_unique(); // requires config + + Debug::log(LOG, "Creating the PointerManager!"); + g_pPointerManager = std::make_unique(); } break; case STAGE_LATE: { Debug::log(LOG, "Creating the ThreadManager!"); @@ -644,24 +606,28 @@ CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) { } CMonitor* CCompositor::getMonitorFromCursor() { - const auto COORDS = Vector2D(m_sWLRCursor->x, m_sWLRCursor->y); - - return getMonitorFromVector(COORDS); + return getMonitorFromVector(g_pPointerManager->position()); } CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { - const auto OUTPUT = wlr_output_layout_output_at(m_sWLROutputLayout, point.x, point.y); + SP mon; + for (auto& m : m_vMonitors) { + if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) { + mon = m; + break; + } + } - if (!OUTPUT) { - float bestDistance = 0.f; - CMonitor* pBestMon = nullptr; + if (!mon) { + float bestDistance = 0.f; + SP pBestMon; for (auto& m : m_vMonitors) { float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize); if (dist < bestDistance || !pBestMon) { bestDistance = dist; - pBestMon = m.get(); + pBestMon = m; } } @@ -670,10 +636,10 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { return m_vMonitors.front().get(); } - return pBestMon; + return pBestMon.get(); } - return getMonitorFromOutput(OUTPUT); + return mon.get(); } void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { @@ -708,7 +674,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper const auto BB = w->getWindowBoxUnified(properties); CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA}; if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) { - if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) + if (box.containsPoint(g_pPointerManager->position())) return w; if (!w->m_bIsX11) { @@ -742,7 +708,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2) continue; - if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) { + if (box.containsPoint(g_pPointerManager->position())) { if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) { // Override Redirect @@ -1695,7 +1661,7 @@ void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) { } CMonitor* CCompositor::getMonitorInDirection(const char& dir) { - return this->getMonitorInDirection(m_pLastMonitor, dir); + return this->getMonitorInDirection(m_pLastMonitor.get(), dir); } CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const char& dir) { @@ -1709,7 +1675,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha CMonitor* longestIntersectMonitor = nullptr; for (auto& m : m_vMonitors) { - if (m.get() == m_pLastMonitor) + if (m == m_pLastMonitor) continue; const auto POSB = m->vecPosition; @@ -1987,7 +1953,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) CMonitor* CCompositor::getMonitorFromString(const std::string& name) { if (name == "current") - return g_pCompositor->m_pLastMonitor; + return g_pCompositor->m_pLastMonitor.get(); else if (isDirection(name)) return getMonitorInDirection(name[0]); else if (name[0] == '+' || name[0] == '-') { @@ -2008,7 +1974,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { int currentPlace = 0; for (int i = 0; i < (int)m_vMonitors.size(); i++) { - if (m_vMonitors[i].get() == m_pLastMonitor) { + if (m_vMonitors[i] == m_pLastMonitor) { currentPlace = i; break; } @@ -2134,7 +2100,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon } } - if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor) { // if it was active, preserve its' status. If it wasn't, don't. + if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor.get()) { // if it was active, preserve its' status. If it wasn't, don't. Debug::log(LOG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {}", pMonitor->activeWorkspaceID(), pWorkspace->m_iID); if (valid(pMonitor->activeWorkspace)) { @@ -2150,7 +2116,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon pWorkspace->m_bVisible = true; if (!noWarpCursor) - wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2); + g_pPointerManager->warpTo(pMonitor->vecPosition + pMonitor->vecTransformedSize / 2.F); g_pInputManager->sendMotionEventsToFocused(); } @@ -2415,10 +2381,10 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) { if (*PNOWARPS && !force) return; - wlr_cursor_warp(m_sWLRCursor, nullptr, pos.x, pos.y); + g_pPointerManager->warpTo(pos); const auto PMONITORNEW = getMonitorFromVector(pos); - if (PMONITORNEW != m_pLastMonitor) + if (PMONITORNEW != m_pLastMonitor.get()) setActiveMonitor(PMONITORNEW); } @@ -2563,11 +2529,11 @@ void CCompositor::renameWorkspace(const int& id, const std::string& name) { } void CCompositor::setActiveMonitor(CMonitor* pMonitor) { - if (m_pLastMonitor == pMonitor) + if (m_pLastMonitor.get() == pMonitor) return; if (!pMonitor) { - m_pLastMonitor = nullptr; + m_pLastMonitor.reset(); return; } @@ -2575,7 +2541,7 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) { g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + (PWORKSPACE ? PWORKSPACE->m_szName : "?")}); EMIT_HOOK_EVENT("focusedMon", pMonitor); - m_pLastMonitor = pMonitor; + m_pLastMonitor = pMonitor->self; } bool CCompositor::isWorkspaceSpecial(const int& id) { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 8be1956c..6fcdeb4a 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -51,10 +51,8 @@ class CCompositor { wlr_data_device_manager* m_sWLRDataDevMgr; wlr_drm* m_sWRLDRM; wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_output_layout* m_sWLROutputLayout; wlr_layer_shell_v1* m_sWLRLayerShell; wlr_xdg_shell* m_sWLRXDGShell; - wlr_cursor* m_sWLRCursor; wlr_presentation* m_sWLRPresentation; wlr_egl* m_sWLREGL; int m_iDRMFD; @@ -88,7 +86,7 @@ class CCompositor { wlr_surface* m_pLastFocus = nullptr; PHLWINDOWREF m_pLastWindow; - CMonitor* m_pLastMonitor = nullptr; + WP m_pLastMonitor; std::vector m_vWindowFocusHistory; // first element is the most recently focused. diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index c6c0ceaf..135a6a94 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -516,6 +516,9 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2}); + m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{1}); + m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:col.active_border", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xffffffff"}); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index d6e8608f..c0dc8d8e 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -115,7 +115,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { (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.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"), + (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)); } @@ -137,7 +137,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { (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.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), + (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)); } } diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index b5f7e1f2..37ccc67a 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -33,7 +33,7 @@ void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) { m_pMonitor = pMonitor; // anim data too - const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor; + const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor.get(); if (PMONITORFORTICKS) { if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate) m_dLastAnimationTicks.pop_front(); diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 9396bbdd..c09d8fda 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -122,7 +122,7 @@ void CWLSurface::destroy() { g_pCompositor->m_pLastFocus = nullptr; if (g_pInputManager && g_pInputManager->m_pLastMouseSurface == m_pWLRSurface) g_pInputManager->m_pLastMouseSurface = nullptr; - if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface) + if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == this) g_pHyprRenderer->m_sLastCursorData.surf.reset(); m_pWLRSurface = nullptr; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 00066b27..77dc2aae 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1169,7 +1169,7 @@ void CWindow::setSuspended(bool suspend) { bool CWindow::visibleOnMonitor(CMonitor* pMonitor) { CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()}; - return wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, wbox.pWlr()); + return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty(); } void CWindow::setAnimationsToMove() { diff --git a/src/devices/IHID.cpp b/src/devices/IHID.cpp new file mode 100644 index 00000000..2b7466dc --- /dev/null +++ b/src/devices/IHID.cpp @@ -0,0 +1,5 @@ +#include "IHID.hpp" + +eHIDType IHID::getType() { + return HID_TYPE_UNKNOWN; +} diff --git a/src/devices/IHID.hpp b/src/devices/IHID.hpp index c2b397c7..2830864b 100644 --- a/src/devices/IHID.hpp +++ b/src/devices/IHID.hpp @@ -10,13 +10,24 @@ enum eHIDCapabilityType : uint32_t { HID_INPUT_CAPABILITY_TOUCH = (1 << 2), }; +enum eHIDType { + HID_TYPE_UNKNOWN = 0, + HID_TYPE_POINTER, + HID_TYPE_KEYBOARD, + HID_TYPE_TOUCH, + HID_TYPE_TABLET, +}; + /* Base class for a HID device. This could be a keyboard, a mouse, or a touchscreen. */ class IHID { public: + virtual ~IHID() {} + virtual uint32_t getCapabilities() = 0; + virtual eHIDType getType(); struct { CSignal destroy; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 61c78f5b..3bd42eac 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -7,6 +7,10 @@ uint32_t IKeyboard::getCapabilities() { return HID_INPUT_CAPABILITY_KEYBOARD; } +eHIDType IKeyboard::getType() { + return HID_TYPE_KEYBOARD; +} + IKeyboard::~IKeyboard() { events.destroy.emit(); diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index 35ccd8cb..d90550da 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -13,6 +13,7 @@ class IKeyboard : public IHID { public: virtual ~IKeyboard(); virtual uint32_t getCapabilities(); + virtual eHIDType getType(); virtual bool isVirtual() = 0; virtual wlr_keyboard* wlr() = 0; diff --git a/src/devices/IPointer.cpp b/src/devices/IPointer.cpp index 9eb507b2..c2ac78c5 100644 --- a/src/devices/IPointer.cpp +++ b/src/devices/IPointer.cpp @@ -3,3 +3,7 @@ uint32_t IPointer::getCapabilities() { return HID_INPUT_CAPABILITY_POINTER; } + +eHIDType IPointer::getType() { + return HID_TYPE_POINTER; +} diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index eda7da2c..e2347c95 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -13,6 +13,7 @@ struct wlr_pointer; class IPointer : public IHID { public: virtual uint32_t getCapabilities(); + virtual eHIDType getType(); virtual bool isVirtual() = 0; virtual wlr_pointer* wlr() = 0; @@ -24,6 +25,7 @@ class IPointer : public IHID { struct SMotionAbsoluteEvent { uint32_t timeMs = 0; Vector2D absolute; // 0.0 - 1.0 + SP device; }; struct SButtonEvent { diff --git a/src/devices/ITouch.cpp b/src/devices/ITouch.cpp index 3fa347fd..72a9ade6 100644 --- a/src/devices/ITouch.cpp +++ b/src/devices/ITouch.cpp @@ -2,4 +2,8 @@ uint32_t ITouch::getCapabilities() { return HID_INPUT_CAPABILITY_TOUCH; -} \ No newline at end of file +} + +eHIDType ITouch::getType() { + return HID_TYPE_TOUCH; +} diff --git a/src/devices/ITouch.hpp b/src/devices/ITouch.hpp index 7a109bec..5929be02 100644 --- a/src/devices/ITouch.hpp +++ b/src/devices/ITouch.hpp @@ -10,13 +10,15 @@ struct wlr_touch; class ITouch : public IHID { public: virtual uint32_t getCapabilities(); + virtual eHIDType getType(); virtual bool isVirtual() = 0; virtual wlr_touch* wlr() = 0; struct SDownEvent { - uint32_t timeMs = 0; - int32_t touchID = 0; - Vector2D pos; + uint32_t timeMs = 0; + int32_t touchID = 0; + Vector2D pos; + SP device; }; struct SUpEvent { diff --git a/src/devices/Mouse.cpp b/src/devices/Mouse.cpp index e2a6f4ed..b860298c 100644 --- a/src/devices/Mouse.cpp +++ b/src/devices/Mouse.cpp @@ -36,6 +36,7 @@ CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) { pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ .timeMs = E->time_msec, .absolute = {E->x, E->y}, + .device = self.lock(), }); }, this, "CMouse"); @@ -62,6 +63,10 @@ CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) { }); }, this, "CMouse"); + hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) { + pointerEvents.frame.emit(); + }, this, "CMouse"); + hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) { auto E = (wlr_pointer_swipe_begin_event*)data; diff --git a/src/devices/TouchDevice.cpp b/src/devices/TouchDevice.cpp index e8e52dc2..64c521a2 100644 --- a/src/devices/TouchDevice.cpp +++ b/src/devices/TouchDevice.cpp @@ -27,6 +27,7 @@ CTouchDevice::CTouchDevice(wlr_touch* touch_) : touch(touch_) { .timeMs = E->time_msec, .touchID = E->touch_id, .pos = {E->x, E->y}, + .device = self.lock(), }); }, this, "CTouchDevice"); diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index 4ebf8865..c8ee3332 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -37,6 +37,7 @@ CVirtualPointer::CVirtualPointer(SP resource) : point pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ .timeMs = E->time_msec, .absolute = {E->x, E->y}, + .device = self.lock(), }); }, this, "CVirtualPointer"); @@ -63,6 +64,10 @@ CVirtualPointer::CVirtualPointer(SP resource) : point }); }, 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; diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index 1de1b768..f36a95de 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -4,7 +4,6 @@ #include "../helpers/WLClasses.hpp" #include "../managers/input/InputManager.hpp" #include "../render/Renderer.hpp" -#include "../protocols/PointerGestures.hpp" // ---------------------------------------------------- // // _____ ________ _______ _____ ______ _____ // @@ -16,26 +15,6 @@ // // // ---------------------------------------------------- // -void Events::listener_mouseFrame(wl_listener* listener, void* data) { - wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); -} - -void Events::listener_mouseMove(wl_listener* listener, void* data) { - g_pInputManager->onMouseMoved((wlr_pointer_motion_event*)data); -} - -void Events::listener_mouseMoveAbsolute(wl_listener* listener, void* data) { - g_pInputManager->onMouseWarp((wlr_pointer_motion_absolute_event*)data); -} - -void Events::listener_mouseButton(wl_listener* listener, void* data) { - g_pInputManager->onMouseButton((wlr_pointer_button_event*)data); -} - -void Events::listener_mouseAxis(wl_listener* listener, void* data) { - g_pInputManager->onMouseWheel((wlr_pointer_axis_event*)data); -} - void Events::listener_requestMouse(wl_listener* listener, void* data) { const auto EVENT = (wlr_seat_pointer_request_set_cursor_event*)data; @@ -75,62 +54,3 @@ void Events::listener_newInput(wl_listener* listener, void* data) { g_pInputManager->updateCapabilities(); } - -void Events::listener_swipeBegin(wl_listener* listener, void* data) { - const auto EVENT = (wlr_pointer_swipe_begin_event*)data; - - g_pInputManager->onSwipeBegin(EVENT); -} - -void Events::listener_swipeUpdate(wl_listener* listener, void* data) { - const auto EVENT = (wlr_pointer_swipe_update_event*)data; - - g_pInputManager->onSwipeUpdate(EVENT); -} - -void Events::listener_swipeEnd(wl_listener* listener, void* data) { - const auto EVENT = (wlr_pointer_swipe_end_event*)data; - - g_pInputManager->onSwipeEnd(EVENT); -} - -void Events::listener_pinchBegin(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_pinch_begin_event*)data; - PROTO::pointerGestures->pinchBegin(EV->time_msec, EV->fingers); -} - -void Events::listener_pinchUpdate(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_pinch_update_event*)data; - PROTO::pointerGestures->pinchUpdate(EV->time_msec, {EV->dx, EV->dy}, EV->scale, EV->rotation); -} - -void Events::listener_pinchEnd(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_pinch_end_event*)data; - PROTO::pointerGestures->pinchEnd(EV->time_msec, EV->cancelled); -} - -void Events::listener_touchBegin(wl_listener* listener, void* data) { - g_pInputManager->onTouchDown((wlr_touch_down_event*)data); -} - -void Events::listener_touchEnd(wl_listener* listener, void* data) { - g_pInputManager->onTouchUp((wlr_touch_up_event*)data); -} - -void Events::listener_touchUpdate(wl_listener* listener, void* data) { - g_pInputManager->onTouchMove((wlr_touch_motion_event*)data); -} - -void Events::listener_touchFrame(wl_listener* listener, void* data) { - wlr_seat_touch_notify_frame(g_pCompositor->m_sSeat.seat); -} - -void Events::listener_holdBegin(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_hold_begin_event*)data; - PROTO::pointerGestures->holdBegin(EV->time_msec, EV->fingers); -} - -void Events::listener_holdEnd(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_hold_end_event*)data; - PROTO::pointerGestures->holdEnd(EV->time_msec, EV->cancelled); -} \ No newline at end of file diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 830ca8d1..69da2d09 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -40,16 +40,6 @@ namespace Events { DYNLISTENFUNC(dissociateX11); DYNLISTENFUNC(ackConfigure); - // Window subsurfaces - // LISTENER(newSubsurfaceWindow); - - // Input events - LISTENER(mouseMove); - LISTENER(mouseMoveAbsolute); - LISTENER(mouseButton); - LISTENER(mouseAxis); - LISTENER(mouseFrame); - LISTENER(newInput); // Virt Ptr @@ -89,23 +79,6 @@ namespace Events { // session LISTENER(sessionActive); - // Touchpad shit - LISTENER(swipeBegin); - LISTENER(swipeEnd); - LISTENER(swipeUpdate); - LISTENER(pinchBegin); - LISTENER(pinchUpdate); - LISTENER(pinchEnd); - - // Touch - LISTENER(touchBegin); - LISTENER(touchEnd); - LISTENER(touchUpdate); - LISTENER(touchFrame); - - LISTENER(holdBegin); - LISTENER(holdEnd); - // Session Lock LISTENER(newSessionLock); }; diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 982dc941..ab8fc7b0 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -16,8 +16,7 @@ // // // --------------------------------------------------------- // -static void checkDefaultCursorWarp(SP* PNEWMONITORWRAP, std::string monitorName) { - const auto PNEWMONITOR = PNEWMONITORWRAP->get(); +static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { static auto PCURSORMONITOR = CConfigValue("general:default_cursor_monitor"); static auto firstMonitorAdded = std::chrono::system_clock::now(); @@ -61,18 +60,18 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { } // add it to real - SP* PNEWMONITORWRAP = nullptr; - - PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); + auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); if (std::string("HEADLESS-1") == OUTPUT->name) - g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get(); + g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); - (*PNEWMONITORWRAP)->output = OUTPUT; + PNEWMONITOR->output = OUTPUT; + PNEWMONITOR->self = PNEWMONITOR; const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false; - (*PNEWMONITORWRAP)->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name); - const auto PNEWMONITOR = PNEWMONITORWRAP->get(); + PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name); PNEWMONITOR->isUnsafeFallback = FALLBACK; + EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR); + if (!FALLBACK) PNEWMONITOR->onConnect(false); @@ -82,14 +81,14 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { // 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; + g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get(); g_pCompositor->m_bReadyToProcess = true; g_pConfigManager->m_bWantsMonitorReload = true; - g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR); + g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get()); - checkDefaultCursorWarp(PNEWMONITORWRAP, OUTPUT->name); + checkDefaultCursorWarp(PNEWMONITOR, OUTPUT->name); for (auto& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 8643a539..221348ff 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -54,10 +54,10 @@ void Events::listener_mapWindow(void* owner, void* data) { static auto PNEWTAKESOVERFS = CConfigValue("misc:new_window_takes_over_fullscreen"); static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); - auto PMONITOR = g_pCompositor->m_pLastMonitor; + auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!g_pCompositor->m_pLastMonitor) { g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({})); - PMONITOR = g_pCompositor->m_pLastMonitor; + PMONITOR = g_pCompositor->m_pLastMonitor.get(); } auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; PWINDOW->m_iMonitorID = PMONITOR->ID; @@ -330,7 +330,7 @@ void Events::listener_mapWindow(void* owner, void* data) { else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID) g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName); - PMONITOR = g_pCompositor->m_pLastMonitor; + PMONITOR = g_pCompositor->m_pLastMonitor.get(); } } else workspaceSilent = false; diff --git a/src/helpers/Box.cpp b/src/helpers/Box.cpp index 8470b509..77406ecf 100644 --- a/src/helpers/Box.cpp +++ b/src/helpers/Box.cpp @@ -121,7 +121,7 @@ CBox& CBox::noNegativeSize() { return *this; } -CBox CBox::intersection(const CBox other) const { +CBox CBox::intersection(const CBox& other) const { const float newX = std::max(x, other.x); const float newY = std::max(y, other.y); const float newBottom = std::min(y + h, other.y + other.h); @@ -137,6 +137,14 @@ CBox CBox::intersection(const CBox other) const { return {newX, newY, newW, newH}; } +bool CBox::overlaps(const CBox& other) const { + return (other.x + other.w >= x) && (x + w >= other.x) && (other.y + other.h >= y) && (y + h >= other.y); +} + +bool CBox::inside(const CBox& bound) const { + return bound.x < x && bound.y < y && x + w < bound.x + bound.w && y + h < bound.y + bound.h; +} + CBox CBox::roundInternal() { float newW = x + w - std::floor(x); float newH = y + h - std::floor(y); @@ -156,6 +164,16 @@ Vector2D CBox::size() const { return {w, h}; } +Vector2D CBox::closestPoint(const Vector2D& vec) const { + if (containsPoint(vec)) + return vec; + + Vector2D nv = vec; + nv.x = std::clamp(nv.x, x, x + w); + nv.y = std::clamp(nv.y, y, y + h); + return nv; +} + SWindowDecorationExtents CBox::extentsFrom(const CBox& small) { return {{small.x - x, small.y - y}, {w - small.w - (small.x - x), h - small.h - (small.y - y)}}; } diff --git a/src/helpers/Box.hpp b/src/helpers/Box.hpp index 98ba8d47..57df2154 100644 --- a/src/helpers/Box.hpp +++ b/src/helpers/Box.hpp @@ -54,13 +54,16 @@ class CBox { CBox& noNegativeSize(); CBox copy() const; - CBox intersection(const CBox other) const; + CBox intersection(const CBox& other) const; + bool overlaps(const CBox& other) const; + bool inside(const CBox& bound) const; SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box Vector2D middle() const; Vector2D pos() const; Vector2D size() const; + Vector2D closestPoint(const Vector2D& vec) const; bool containsPoint(const Vector2D& vec) const; bool empty() const; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 3c489d4b..d0e777ed 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -149,14 +149,14 @@ void CMonitor::onConnect(bool noRule) { for (const auto& PTOUCHDEV : g_pInputManager->m_vTouches) { if (matchesStaticSelector(PTOUCHDEV->boundOutput)) { Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->hlName, szName); - wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, output); + // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, output); } } for (const auto& PTABLET : g_pInputManager->m_lTablets) { if (matchesStaticSelector(PTABLET.boundOutput)) { Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName); - wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output); + // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output); } } @@ -203,7 +203,7 @@ void CMonitor::onConnect(bool noRule) { // verify last mon valid bool found = false; for (auto& m : g_pCompositor->m_vMonitors) { - if (m.get() == g_pCompositor->m_pLastMonitor) { + if (m == g_pCompositor->m_pLastMonitor) { found = true; break; } @@ -219,6 +219,7 @@ void CMonitor::onConnect(bool noRule) { PROTO::gamma->applyGammaToState(this); events.connect.emit(); + updateGlobal(); } void CMonitor::onDisconnect(bool destroy) { @@ -285,10 +286,11 @@ void CMonitor::onDisconnect(bool destroy) { m_bEnabled = false; m_bRenderingInitPassed = false; + updateGlobal(); + if (BACKUPMON) { // snap cursor - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, - BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f); + g_pCompositor->warpCursorTo(BACKUPMON->vecPosition + BACKUPMON->vecTransformedSize / 2.F, true); // move workspaces std::deque wspToMove; @@ -306,22 +308,19 @@ void CMonitor::onDisconnect(bool destroy) { } else { g_pCompositor->m_pLastFocus = nullptr; g_pCompositor->m_pLastWindow.reset(); - g_pCompositor->m_pLastMonitor = nullptr; + g_pCompositor->m_pLastMonitor.reset(); } if (activeWorkspace) activeWorkspace->m_bVisible = false; activeWorkspace.reset(); - if (!destroy) - wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output); - wlr_output_state_set_enabled(state.wlr(), false); if (!state.commit()) Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect"); - if (g_pCompositor->m_pLastMonitor == this) + if (g_pCompositor->m_pLastMonitor.get() == this) g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput); if (g_pHyprRenderer->m_pMostHzMonitor == this) { @@ -508,8 +507,6 @@ void CMonitor::setMirror(const std::string& mirrorOf) { activeWorkspace.reset(); - wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output); - vecPosition = PMIRRORMON->vecPosition; pMirrorOf = PMIRRORMON; @@ -728,9 +725,6 @@ void CMonitor::setSpecialWorkspace(const int& id) { void CMonitor::moveTo(const Vector2D& pos) { vecPosition = pos; - - if (!isMirror()) - wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y); } Vector2D CMonitor::middle() { @@ -749,10 +743,22 @@ void CMonitor::updateMatrix() { int64_t CMonitor::activeWorkspaceID() { return activeWorkspace ? activeWorkspace->m_iID : 0; } + int64_t CMonitor::activeSpecialWorkspaceID() { return activeSpecialWorkspace ? activeSpecialWorkspace->m_iID : 0; } +CBox CMonitor::logicalBox() { + return {vecPosition, vecSize}; +} + +void CMonitor::updateGlobal() { + if (output->width > 0 && output->height > 0 && m_bEnabled) + wlr_output_create_global(output, g_pCompositor->m_sWLDisplay); + else + wlr_output_destroy_global(output); +} + CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; wlr_output_state_init(&m_state); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index a93d23af..2d49aeb3 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -114,6 +114,8 @@ class CMonitor { SMonitorRule activeMonitorRule; + WP self; + // mirroring CMonitor* pMirrorOf = nullptr; std::vector mirrors; @@ -167,6 +169,8 @@ class CMonitor { void updateMatrix(); int64_t activeWorkspaceID(); int64_t activeSpecialWorkspaceID(); + CBox logicalBox(); + void updateGlobal(); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; diff --git a/src/helpers/Region.cpp b/src/helpers/Region.cpp index bcbf672d..20eaf452 100644 --- a/src/helpers/Region.cpp +++ b/src/helpers/Region.cpp @@ -142,6 +142,9 @@ bool CRegion::empty() const { } Vector2D CRegion::closestPoint(const Vector2D& vec) const { + if (containsPoint(vec)) + return vec; + double bestDist = __FLT_MAX__; Vector2D leader = vec; @@ -162,7 +165,7 @@ Vector2D CRegion::closestPoint(const Vector2D& vec) const { else y = vec.y; - double distance = sqrt(pow(x, 2) + pow(y, 2)); + double distance = pow(x, 2) + pow(y, 2); if (distance < bestDist) { bestDist = distance; leader = {x, y}; diff --git a/src/helpers/Vector2D.cpp b/src/helpers/Vector2D.cpp index c74da0b1..6f96d686 100644 --- a/src/helpers/Vector2D.cpp +++ b/src/helpers/Vector2D.cpp @@ -42,9 +42,11 @@ Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const { } double Vector2D::distance(const Vector2D& other) const { - double dx = x - other.x; - double dy = y - other.y; - return std::sqrt(dx * dx + dy * dy); + return std::sqrt(distanceSq(other)); +} + +double Vector2D::distanceSq(const Vector2D& other) const { + return (x - other.x) * (x - other.x) + (y - other.y) * (y - other.y); } double Vector2D::size() const { diff --git a/src/helpers/Vector2D.hpp b/src/helpers/Vector2D.hpp index 309ed3bc..0f1440c3 100644 --- a/src/helpers/Vector2D.hpp +++ b/src/helpers/Vector2D.hpp @@ -89,6 +89,7 @@ class Vector2D { } double distance(const Vector2D& other) const; + double distanceSq(const Vector2D& other) const; double size() const; Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D{-1, -1}) const; diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 7a9e9e87..4c7b6731 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -10,7 +10,7 @@ CHyprError::CHyprError() { if (!m_bIsCreated) return; - g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor); + g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor.get()); m_bMonitorChanged = true; }); diff --git a/src/includes.hpp b/src/includes.hpp index 6df38267..57ea5d54 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -39,7 +39,6 @@ extern "C" { #include #include #include -#include #include #include #include @@ -52,7 +51,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 3fcecfe4..4ee3adfc 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -1,6 +1,7 @@ #include "CursorManager.hpp" #include "Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "PointerManager.hpp" extern "C" { #include @@ -73,8 +74,8 @@ static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t fla if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) return false; - *data = cairo_image_surface_get_data(buffer->surface); - *stride = cairo_image_surface_get_stride(buffer->surface); + *data = buffer->pixelData ? buffer->pixelData : cairo_image_surface_get_data(buffer->surface); + *stride = buffer->stride; *format = DRM_FORMAT_ARGB8888; return true; } @@ -94,6 +95,14 @@ CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector 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() { @@ -104,18 +113,53 @@ wlr_buffer* CCursorManager::getCursorBuffer() { return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr; } -void CCursorManager::setCursorSurface(wlr_surface* surf, const Vector2D& hotspot) { - wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspot.x, hotspot.y); +void CCursorManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) { + if (!surf || !surf->wlr()) + g_pPointerManager->resetCursorImage(); + else + g_pPointerManager->setCursorSurface(surf, hotspot); m_bOurBufferConnected = false; } +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."); + g_pPointerManager->resetCursorImage(); + return; + } + + auto image = xcursor->images[0]; + + m_vCursorBuffers.emplace_back(std::make_unique(image->buffer, Vector2D{image->width, image->height}, Vector2D{image->hotspot_x, image->hotspot_y})); + + g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{image->hotspot_x, image->hotspot_y} / scale, scale); + if (m_vCursorBuffers.size() > 1) + wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); + + m_bOurBufferConnected = true; +} + void CCursorManager::setCursorFromName(const std::string& name) { static auto PUSEHYPRCURSOR = CConfigValue("misc:enable_hyprcursor"); if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR) { - wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, m_pWLRXCursorMgr, name.c_str()); + setXCursor(name); return; } @@ -142,7 +186,7 @@ void CCursorManager::setCursorFromName(const std::string& name) { if (m_sCurrentCursorShapeData.images.size() < 1) { Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName"); - wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, m_pWLRXCursorMgr, name.c_str()); + setXCursor(name); return; } } @@ -151,12 +195,10 @@ void CCursorManager::setCursorFromName(const std::string& name) { Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); - if (g_pCompositor->m_sWLRCursor) { - wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[0].hotspotX / m_fCursorScale, - m_sCurrentCursorShapeData.images[0].hotspotY / m_fCursorScale, m_fCursorScale); - if (m_vCursorBuffers.size() > 1) - wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); - } + 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); m_bOurBufferConnected = true; @@ -183,9 +225,10 @@ void CCursorManager::tickAnimatedCursor() { 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})); - if (g_pCompositor->m_sWLRCursor) - wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX / m_fCursorScale, - m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY / m_fCursorScale, m_fCursorScale); + g_pPointerManager->setCursorBuffer( + getCursorBuffer(), + Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale, + m_fCursorScale); wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay); } @@ -223,8 +266,6 @@ void CCursorManager::updateTheme() { highestScale = m->scale; } - highestScale = std::ceil(highestScale); - if (std::round(highestScale * m_iSize) == m_sCurrentStyleInfo.size) return; diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index 629f29e1..b4c5232a 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -9,6 +9,7 @@ struct wlr_buffer; struct wlr_xcursor_manager; struct wlr_xwayland; +class CWLSurface; class CCursorManager { public: @@ -18,7 +19,8 @@ class CCursorManager { wlr_buffer* getCursorBuffer(); void setCursorFromName(const std::string& name); - void setCursorSurface(wlr_surface* surf, const Vector2D& hotspot); + void setCursorSurface(CWLSurface* surf, const Vector2D& hotspot); + void setXCursor(const std::string& name); void changeTheme(const std::string& name, const int size); void updateTheme(); @@ -30,13 +32,16 @@ class CCursorManager { class CCursorBuffer { 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; + cairo_surface_t* surface = nullptr; + bool dropped = false; + CCursorBuffer* parent = nullptr; + uint8_t* pixelData = nullptr; + size_t stride = 0; } wlrBuffer; private: diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index c52fda17..62265e00 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -256,7 +256,7 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { if (!monitor) return false; - const auto LASTMONITOR = g_pCompositor->m_pLastMonitor; + const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get(); if (LASTMONITOR == monitor) { Debug::log(LOG, "Tried to move to active monitor"); return false; @@ -407,7 +407,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { return !suppressEvent && !mouseBindWasActive; } -bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) { +bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) { const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); static auto PDELAY = CConfigValue("binds:scroll_event_delay"); @@ -426,13 +426,13 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) { } bool found = false; - if (e->source == WL_POINTER_AXIS_SOURCE_WHEEL && e->orientation == WL_POINTER_AXIS_VERTICAL_SCROLL) { - if (e->delta < 0) + if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + if (e.delta < 0) found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true); else found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true); - } else if (e->source == WL_POINTER_AXIS_SOURCE_WHEEL && e->orientation == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - if (e->delta < 0) + } else if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + if (e.delta < 0) found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true); else found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true); @@ -444,18 +444,18 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) { return !found; } -bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) { +bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); bool suppressEvent = false; - m_uLastMouseCode = e->button; + m_uLastMouseCode = e.button; m_uLastCode = 0; - m_uTimeLastMs = e->time_msec; + m_uTimeLastMs = e.timeMs; bool mouseBindWasActive = ensureMouseBindState(); - const auto KEY_NAME = "mouse:" + std::to_string(e->button); + const auto KEY_NAME = "mouse:" + std::to_string(e.button); const auto KEY = SPressedKeyWithMods{ .keyName = KEY_NAME, @@ -468,7 +468,7 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) { m_pActiveKeybind = nullptr; } - if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { m_dPressedKeys.push_back(KEY); suppressEvent = handleKeybinds(MODS, KEY, true); @@ -501,12 +501,11 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) { return !suppressEvent && !mouseBindWasActive; } -void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) { - if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) { +void CKeybindManager::resizeWithBorder(const IPointer::SButtonEvent& e) { + if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) mouse("1resizewindow"); - } else { + else mouse("0resizewindow"); - } } void CKeybindManager::onSwitchEvent(const std::string& switchName) { @@ -965,7 +964,7 @@ void CKeybindManager::changeworkspace(std::string args) { static auto PALLOWWORKSPACECYCLES = CConfigValue("binds:allow_workspace_cycles"); static auto PWORKSPACECENTERON = CConfigValue("binds:workspace_center_on"); - const auto PMONITOR = g_pCompositor->m_pLastMonitor; + const auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!PMONITOR) return; @@ -1445,20 +1444,20 @@ void CKeybindManager::moveCursorToCorner(std::string arg) { switch (CORNER) { case 0: // bottom left - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y}, true); break; case 1: // bottom right - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, - PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y}, + true); break; case 2: // top right - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y}, true); break; case 3: // top left - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y}, true); break; } } @@ -1488,7 +1487,7 @@ void CKeybindManager::moveCursor(std::string args) { x = std::stoi(x_str); y = std::stoi(y_str); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, x, y); + g_pCompositor->warpCursorTo({x, y}, true); } void CKeybindManager::workspaceOpt(std::string args) { @@ -1624,7 +1623,7 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { return; } - const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor; + const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!PCURRMONITOR) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!"); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index c382f3eb..da98a749 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -5,6 +5,7 @@ #include "../Compositor.hpp" #include #include +#include "../devices/IPointer.hpp" class CInputManager; class CConfigManager; @@ -62,9 +63,9 @@ class CKeybindManager { ~CKeybindManager(); bool onKeyEvent(std::any, SP); - bool onAxisEvent(wlr_pointer_axis_event*); - bool onMouseEvent(wlr_pointer_button_event*); - void resizeWithBorder(wlr_pointer_button_event*); + bool onAxisEvent(const IPointer::SAxisEvent&); + bool onMouseEvent(const IPointer::SButtonEvent&); + void resizeWithBorder(const IPointer::SButtonEvent&); void onSwitchEvent(const std::string&); void onSwitchOnEvent(const std::string&); void onSwitchOffEvent(const std::string&); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp new file mode 100644 index 00000000..caff8d22 --- /dev/null +++ b/src/managers/PointerManager.cpp @@ -0,0 +1,864 @@ +#include "PointerManager.hpp" +#include "../Compositor.hpp" +#include "../config/ConfigValue.hpp" +#include "../protocols/PointerGestures.hpp" +#include "../protocols/FractionalScale.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; + } + } + + return output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888); +} + +CPointerManager::CPointerManager() { + hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) { + auto PMONITOR = std::any_cast>(data); + + onMonitorLayoutChange(); + + PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); + PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); + PMONITOR->events.destroy.registerStaticListener( + [this](void* owner, std::any data) { std::erase_if(monitorStates, [](const auto& other) { return other->monitor.expired(); }); }, nullptr); + }); +} + +void CPointerManager::lockSoftwareForMonitor(SP mon) { + auto state = stateFor(mon); + state->softwareLocks++; + + if (state->softwareLocks == 1) + updateCursorBackend(); +} + +void CPointerManager::unlockSoftwareForMonitor(SP mon) { + auto state = stateFor(mon); + state->softwareLocks--; + if (state->softwareLocks < 0) + state->softwareLocks = 0; + + if (state->softwareLocks == 0) + updateCursorBackend(); +} + +Vector2D CPointerManager::position() { + return pointerPos; +} + +bool CPointerManager::hasCursor() { + return currentCursorImage.pBuffer || currentCursorImage.surface; +} + +SP CPointerManager::stateFor(SP mon) { + auto it = std::find_if(monitorStates.begin(), monitorStates.end(), [mon](const auto& other) { return other->monitor == mon; }); + if (it == monitorStates.end()) + return monitorStates.emplace_back(makeShared(mon)); + return *it; +} + +void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale) { + if (buf == currentCursorImage.pBuffer) { + if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) { + currentCursorImage.hotspot = hotspot; + currentCursorImage.scale = scale; + updateCursorBackend(); + } + + return; + } + + 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.hotspot = hotspot; + currentCursorImage.scale = scale; + + updateCursorBackend(); +} + +void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) { + if (surf == currentCursorImage.surface) { + if (hotspot != currentCursorImage.hotspot || (surf && surf->wlr() ? surf->wlr()->current.scale : 1.F) != currentCursorImage.scale) { + currentCursorImage.hotspot = hotspot; + currentCursorImage.scale = surf && surf->wlr() ? surf->wlr()->current.scale : 1.F; + updateCursorBackend(); + } + + return; + } + + resetCursorImage(false); + + if (surf) { + currentCursorImage.size = {surf->wlr()->current.buffer_width, surf->wlr()->current.buffer_height}; + currentCursorImage.surface = surf; + currentCursorImage.scale = surf->wlr()->current.scale; + + currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); }); + currentCursorImage.hyprListener_commitSurface.initCallback( + &surf->wlr()->events.commit, + [this](void* owner, void* data) { + currentCursorImage.size = {currentCursorImage.surface->wlr()->current.buffer_width, currentCursorImage.surface->wlr()->current.buffer_height}; + currentCursorImage.scale = currentCursorImage.surface && currentCursorImage.surface->wlr() ? currentCursorImage.surface->wlr()->current.scale : 1.F; + recheckEnteredOutputs(); + updateCursorBackend(); + }, + nullptr, "CPointerManager"); + + if (surf->wlr()->current.buffer) { + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_surface_send_frame_done(surf->wlr(), &now); + } + } + + currentCursorImage.hotspot = hotspot; + + recheckEnteredOutputs(); + updateCursorBackend(); +} + +void CPointerManager::recheckEnteredOutputs() { + if (!hasCursor()) + return; + + auto box = getCursorBoxGlobal(); + + for (auto& s : monitorStates) { + if (s->monitor.expired() || s->monitor->isMirror() || !s->monitor->m_bEnabled) + continue; + + const bool overlaps = box.overlaps(s->monitor->logicalBox()); + + if (!s->entered && overlaps) { + s->entered = true; + + if (!currentCursorImage.surface) + continue; + + wlr_surface_send_enter(currentCursorImage.surface->wlr(), s->monitor->output); + PROTO::fractional->sendScale(currentCursorImage.surface->wlr(), s->monitor->scale); + g_pCompositor->setPreferredScaleForSurface(currentCursorImage.surface->wlr(), s->monitor->scale); + } else if (s->entered && !overlaps) { + s->entered = false; + + // 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 (!currentCursorImage.surface) + continue; + + wlr_surface_send_leave(currentCursorImage.surface->wlr(), s->monitor->output); + } + } +} + +void CPointerManager::resetCursorImage(bool apply) { + if (currentCursorImage.surface) { + for (auto& m : g_pCompositor->m_vMonitors) { + wlr_surface_send_leave(currentCursorImage.surface->wlr(), m->output); + } + + currentCursorImage.destroySurface.reset(); + currentCursorImage.hyprListener_commitSurface.removeCallback(); + currentCursorImage.surface = nullptr; + } else if (currentCursorImage.pBuffer) { + wlr_buffer_unlock(currentCursorImage.pBuffer); + currentCursorImage.hyprListener_destroyBuffer.removeCallback(); + currentCursorImage.pBuffer = nullptr; + } + + if (currentCursorImage.pBufferTexture) { + wlr_texture_destroy(currentCursorImage.pBufferTexture); + currentCursorImage.pBufferTexture = nullptr; + } + + currentCursorImage.scale = 1.F; + currentCursorImage.hotspot = {0, 0}; + + if (!apply) + return; + + for (auto& ms : monitorStates) { + 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); + ms->cursorFrontBuffer = nullptr; + } + } +} + +void CPointerManager::updateCursorBackend() { + static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); + + for (auto& m : g_pCompositor->m_vMonitors) { + auto state = stateFor(m); + + if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) { + Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); + state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); + state->hardwareFailed = true; + + if (state->hwApplied) + setHWCursorBuffer(state, nullptr); + + state->hwApplied = false; + continue; + } + + state->hardwareFailed = false; + } +} + +void CPointerManager::onCursorMoved() { + if (!hasCursor()) + return; + + for (auto& m : g_pCompositor->m_vMonitors) { + auto state = stateFor(m); + + state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); + + if (state->hardwareFailed || !state->entered) + continue; + + const auto CURSORPOS = getCursorPosForMonitor(m); + m->output->impl->move_cursor(m->output, CURSORPOS.x, CURSORPOS.y); + } +} + +bool CPointerManager::attemptHardwareCursor(SP state) { + auto output = state->monitor->output; + + if (!output->impl->set_cursor) + return false; + + const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock()); + state->monitor->output->impl->move_cursor(state->monitor->output, CURSORPOS.x, CURSORPOS.y); + + auto texture = getCurrentCursorTexture(); + + if (!texture) { + Debug::log(TRACE, "[pointer] no texture for hw cursor -> hiding"); + setHWCursorBuffer(state, nullptr); + return true; + } + + auto buffer = renderHWCursorBuffer(state, texture); + + if (!buffer) { + Debug::log(TRACE, "[pointer] hw cursor failed rendering"); + setHWCursorBuffer(state, nullptr); + return false; + } + + bool success = setHWCursorBuffer(state, buffer); + + if (!success) { + Debug::log(TRACE, "[pointer] hw cursor failed applying, hiding"); + setHWCursorBuffer(state, nullptr); + return false; + } else + state->hwApplied = true; + + return success; +} + +bool CPointerManager::setHWCursorBuffer(SP state, wlr_buffer* buf) { + if (!state->monitor->output->impl->set_cursor) + 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)) + return false; + + wlr_buffer_unlock(state->cursorFrontBuffer); + state->cursorFrontBuffer = buf; + + g_pCompositor->scheduleFrameForMonitor(state->monitor.get()); + + if (buf) + wlr_buffer_lock(buf); + + return true; +} + +wlr_buffer* CPointerManager::renderHWCursorBuffer(SP state, wlr_texture* texture) { + auto output = state->monitor->output; + + int w = currentCursorImage.size.x, h = currentCursorImage.size.y; + if (output->impl->get_cursor_size) { + output->impl->get_cursor_size(output, &w, &h); + + if (w < currentCursorImage.size.x || h < currentCursorImage.size.y) { + Debug::log(TRACE, "hardware cursor too big! {} > {}x{}", currentCursorImage.size, w, h); + return nullptr; + } + } + + if (w <= 0 || h <= 0) { + Debug::log(TRACE, "hw cursor for output {} failed the size checks ({}x{} is invalid)", state->monitor->szName, w, h); + 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"); + return nullptr; + } + + wlr_swapchain_destroy(output->cursor_swapchain); + output->cursor_swapchain = wlr_swapchain_create(output->allocator, w, h, &fmt); + wlr_drm_format_finish(&fmt); + + if (!output->cursor_swapchain) { + Debug::log(TRACE, "Failed to create cursor swapchain"); + return nullptr; + } + } + + wlr_buffer* buf = wlr_swapchain_acquire(output->cursor_swapchain, nullptr); + if (!buf) { + Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain"); + return nullptr; + } + + CRegion damage = {0, 0, INT16_MAX, INT16_MAX}; + + g_pHyprRenderer->makeEGLCurrent(); + g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); // has to be set cuz allocs + + 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}, + currentCursorImage.scale, state->monitor->scale, xbox.size()); + + g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F); + + g_pHyprOpenGL->end(); + glFlush(); + g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; + + g_pHyprRenderer->onRenderbufferDestroy(RBO); + + wlr_buffer_unlock(buf); + + return buf; +} + +void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* now, CRegion& damage, std::optional overridePos) { + if (!hasCursor()) + return; + + auto state = stateFor(pMonitor); + + if ((!state->hardwareFailed && state->softwareLocks == 0)) { + if (currentCursorImage.surface) + wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now); + return; + } + + auto box = state->box.copy(); + if (overridePos.has_value()) { + box.x = overridePos->x; + box.y = overridePos->y; + } + + if (box.intersection(CBox{{}, {pMonitor->vecSize}}).empty()) + return; + + auto texture = getCurrentCursorTexture(); + if (!texture) + return; + + box.scale(pMonitor->scale); + + g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F); + + if (currentCursorImage.surface) + wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now); +} + +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) + .pos() * + pMonitor->scale; +} + +Vector2D CPointerManager::transformedHotspot(SP pMonitor) { + return CBox{currentCursorImage.hotspot, {0, 0}} + .transform(wlr_output_transform_invert(pMonitor->transform), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height) + .pos(); +} + +CBox CPointerManager::getCursorBoxLogicalForMonitor(SP pMonitor) { + return getCursorBoxGlobal().translate(-pMonitor->vecPosition); +} + +CBox CPointerManager::getCursorBoxGlobal() { + return CBox{pointerPos, currentCursorImage.size / currentCursorImage.scale}.translate(-currentCursorImage.hotspot / currentCursorImage.scale); +} + +Vector2D CPointerManager::closestValid(const Vector2D& pos) { + static auto PADDING = CConfigValue("cursor:hotspot_padding"); + + auto CURSOR_PADDING = std::clamp((int)*PADDING, 1, 100); // 1px + CBox hotBox = {{pos.x - CURSOR_PADDING, pos.y - CURSOR_PADDING}, {2 * CURSOR_PADDING, 2 * CURSOR_PADDING}}; + + // + static auto INSIDE_LAYOUT = [this](const CBox& box) -> bool { + for (auto& b : currentMonitorLayout.monitorBoxes) { + if (box.inside(b)) + return true; + } + return false; + }; + + static auto INSIDE_LAYOUT_COORD = [this](const Vector2D& vec) -> bool { + for (auto& b : currentMonitorLayout.monitorBoxes) { + if (b.containsPoint(vec)) + return true; + } + return false; + }; + + static auto NEAREST_LAYOUT = [this](const Vector2D& vec) -> Vector2D { + Vector2D leader; + float distanceSq = __FLT_MAX__; + + for (auto& b : currentMonitorLayout.monitorBoxes) { + auto p = b.closestPoint(vec); + auto distSq = p.distanceSq(vec); + + if (distSq < distanceSq) { + leader = p; + distanceSq = distSq; + } + } + + if (distanceSq > 1337.69420e+20F) + return {0, 0}; // ??? + + return leader; + }; + + if (INSIDE_LAYOUT(hotBox)) + return pos; + + Vector2D leader = NEAREST_LAYOUT(pos); + + hotBox.x = leader.x - CURSOR_PADDING; + hotBox.y = leader.y - CURSOR_PADDING; + + // push the hotbox around so that it fits in the layout + + if (!INSIDE_LAYOUT_COORD(hotBox.middle() + Vector2D{CURSOR_PADDING, CURSOR_PADDING})) { + auto delta = NEAREST_LAYOUT(hotBox.middle() + Vector2D{CURSOR_PADDING, CURSOR_PADDING}) - (hotBox.middle() + Vector2D{CURSOR_PADDING, CURSOR_PADDING}); + hotBox.translate(delta); + } + + if (!INSIDE_LAYOUT_COORD(hotBox.middle() - Vector2D{CURSOR_PADDING, CURSOR_PADDING})) { + auto delta = NEAREST_LAYOUT(hotBox.middle() - Vector2D{CURSOR_PADDING, CURSOR_PADDING}) - (hotBox.middle() - Vector2D{CURSOR_PADDING, CURSOR_PADDING}); + hotBox.translate(delta); + } + + if (!INSIDE_LAYOUT_COORD(hotBox.middle() + Vector2D{CURSOR_PADDING, -CURSOR_PADDING})) { + auto delta = NEAREST_LAYOUT(hotBox.middle() + Vector2D{CURSOR_PADDING, -CURSOR_PADDING}) - (hotBox.middle() + Vector2D{CURSOR_PADDING, -CURSOR_PADDING}); + hotBox.translate(delta); + } + + if (!INSIDE_LAYOUT_COORD(hotBox.middle() + Vector2D{-CURSOR_PADDING, CURSOR_PADDING})) { + auto delta = NEAREST_LAYOUT(hotBox.middle() + Vector2D{-CURSOR_PADDING, CURSOR_PADDING}) - (hotBox.middle() + Vector2D{-CURSOR_PADDING, CURSOR_PADDING}); + hotBox.translate(delta); + } + + return hotBox.middle(); +} + +void CPointerManager::damageIfSoftware() { + auto b = getCursorBoxGlobal(); + + static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); + + for (auto& mw : monitorStates) { + if (mw->monitor.expired()) + continue; + + if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { + g_pHyprRenderer->damageBox(&b); + break; + } + } +} + +void CPointerManager::warpTo(const Vector2D& logical) { + damageIfSoftware(); + + pointerPos = closestValid(logical); + recheckEnteredOutputs(); + onCursorMoved(); + + damageIfSoftware(); +} + +void CPointerManager::move(const Vector2D& deltaLogical) { + const auto oldPos = pointerPos; + auto newPos = oldPos + deltaLogical; + + warpTo(newPos); +} + +void CPointerManager::warpAbsolute(const Vector2D& abs, SP dev) { + + SP currentMonitor = g_pCompositor->m_pLastMonitor.lock(); + + switch (dev->getType()) { + case HID_TYPE_TABLET: + //TODO: + break; + case HID_TYPE_TOUCH: { + auto TOUCH = SP(dev); + if (!TOUCH->boundOutput.empty()) { + const auto PMONITOR = g_pCompositor->getMonitorFromString(TOUCH->boundOutput); + if (PMONITOR) + currentMonitor = PMONITOR->self.lock(); + } + break; + } + default: break; + } + + if (!currentMonitor) + return; + + damageIfSoftware(); + + pointerPos = currentMonitor->vecPosition + currentMonitor->vecSize * abs; + onCursorMoved(); + recheckEnteredOutputs(); + + damageIfSoftware(); +} + +void CPointerManager::onMonitorLayoutChange() { + currentMonitorLayout.monitorBoxes.clear(); + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->isMirror() || !m->m_bEnabled) + continue; + + currentMonitorLayout.monitorBoxes.emplace_back(CBox{m->vecPosition, m->vecSize}); + } + + damageIfSoftware(); + + pointerPos = closestValid(pointerPos); + updateCursorBackend(); + recheckEnteredOutputs(); + + damageIfSoftware(); +} + +wlr_texture* CPointerManager::getCurrentCursorTexture() { + if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !wlr_surface_get_texture(currentCursorImage.surface->wlr()))) + return nullptr; + + if (currentCursorImage.pBuffer) { + if (!currentCursorImage.pBufferTexture) + currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer); + return currentCursorImage.pBufferTexture; + } + + return wlr_surface_get_texture(currentCursorImage.surface->wlr()); +} + +void CPointerManager::attachPointer(SP pointer) { + if (!pointer) + return; + + auto listener = pointerListeners.emplace_back(makeShared()); + + listener->pointer = pointer; + + // clang-format off + listener->destroy = pointer->events.destroy.registerListener([this] (std::any d) { + detachPointer(nullptr); + }); + + listener->motion = pointer->pointerEvents.motion.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onMouseMoved(E); + }); + + listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onMouseWarp(E); + }); + + listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onMouseButton(E); + }); + + listener->axis = pointer->pointerEvents.axis.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onMouseWheel(E); + }); + + listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) { + wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); + }); + + listener->swipeBegin = pointer->pointerEvents.swipeBegin.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onSwipeBegin(E); + }); + + listener->swipeEnd = pointer->pointerEvents.swipeEnd.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onSwipeEnd(E); + }); + + listener->swipeUpdate = pointer->pointerEvents.swipeUpdate.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onSwipeUpdate(E); + }); + + listener->pinchBegin = pointer->pointerEvents.pinchBegin.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->pinchBegin(E.timeMs, E.fingers); + }); + + listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->pinchEnd(E.timeMs, E.cancelled); + }); + + listener->pinchUpdate = pointer->pointerEvents.pinchUpdate.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->pinchUpdate(E.timeMs, E.delta, E.scale, E.rotation); + }); + + listener->holdBegin = pointer->pointerEvents.holdBegin.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->holdBegin(E.timeMs, E.fingers); + }); + + listener->holdEnd = pointer->pointerEvents.holdEnd.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->holdEnd(E.timeMs, E.cancelled); + }); + // clang-format on + + Debug::log(LOG, "Attached pointer {} to global", pointer->hlName); +} + +void CPointerManager::attachTouch(SP touch) { + if (!touch) + return; + + auto listener = touchListeners.emplace_back(makeShared()); + + listener->touch = touch; + + // clang-format off + listener->destroy = touch->events.destroy.registerListener([this] (std::any d) { + detachTouch(nullptr); + }); + + listener->down = touch->touchEvents.down.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTouchDown(E); + }); + + listener->up = touch->touchEvents.up.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTouchUp(E); + }); + + listener->motion = touch->touchEvents.motion.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTouchMove(E); + }); + + listener->cancel = touch->touchEvents.cancel.registerListener([this] (std::any e) { + // + }); + + listener->frame = touch->touchEvents.frame.registerListener([this] (std::any e) { + wlr_seat_touch_notify_frame(g_pCompositor->m_sSeat.seat); + }); + // clang-format on + + Debug::log(LOG, "Attached touch {} to global", touch->hlName); +} + +void CPointerManager::detachPointer(SP pointer) { + std::erase_if(pointerListeners, [pointer](const auto& e) { return e->pointer.expired() || e->pointer == pointer; }); +} + +void CPointerManager::detachTouch(SP touch) { + std::erase_if(touchListeners, [touch](const auto& e) { return e->touch.expired() || e->touch == touch; }); +} + +void CPointerManager::damageCursor(SP pMonitor) { + for (auto& mw : monitorStates) { + if (mw->monitor != pMonitor) + continue; + + auto b = getCursorBoxGlobal().intersection(pMonitor->logicalBox()); + + if (b.empty()) + return; + + g_pHyprRenderer->damageBox(&b); + + return; + } +} diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp new file mode 100644 index 00000000..2446cde7 --- /dev/null +++ b/src/managers/PointerManager.hpp @@ -0,0 +1,158 @@ +#pragma once + +#include "../devices/IPointer.hpp" +#include "../devices/ITouch.hpp" +#include "../helpers/Box.hpp" +#include "../helpers/Region.hpp" +#include "../desktop/WLSurface.hpp" +#include + +class CMonitor; +struct wlr_input_device; +class IHID; + +/* + The naming here is a bit confusing. + CPointerManager manages the _position_ and _displaying_ of the cursor, + but the CCursorManager _only_ manages the actual image (texture) and size + of the cursor. +*/ + +class CPointerManager { + public: + CPointerManager(); + + // pointers will move the cursor on their respective events + void attachPointer(SP pointer); + // touch inputs won't move the cursor, it needs to be done manually + void attachTouch(SP touch); + + void detachPointer(SP pointer); + void detachTouch(SP touch); + + // only clamps to the layout. + void warpTo(const Vector2D& logical); + void move(const Vector2D& deltaLogical); + void warpAbsolute(const Vector2D& abs, SP dev); + + void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale); + void setCursorSurface(CWLSurface* buf, const Vector2D& hotspot); + void resetCursorImage(bool apply = true); + + void lockSoftwareForMonitor(SP pMonitor); + void unlockSoftwareForMonitor(SP pMonitor); + + void renderSoftwareCursorsFor(SP pMonitor, timespec* now, CRegion& damage /* logical */, std::optional overridePos = {} /* monitor-local */); + + // this is needed e.g. during screensharing where + // the software cursors aren't locked during the cursor move, but they + // are rendered later. + void damageCursor(SP pMonitor); + + // + Vector2D position(); + + private: + void recheckPointerPosition(); + void onMonitorLayoutChange(); + void onMonitorDisconnect(); + void updateCursorBackend(); + void onCursorMoved(); + bool hasCursor(); + void damageIfSoftware(); + void recheckEnteredOutputs(); + + // closest valid point to a given one + Vector2D closestValid(const Vector2D& pos); + + // returns the thing in device coordinates. Is NOT offset by the hotspot, relies on set_cursor with hotspot. + Vector2D getCursorPosForMonitor(SP pMonitor); + // returns the thing in logical coordinates of the monitor + CBox getCursorBoxLogicalForMonitor(SP pMonitor); + // returns the thing in global coords + CBox getCursorBoxGlobal(); + + Vector2D transformedHotspot(SP pMonitor); + + wlr_texture* getCurrentCursorTexture(); + + struct SPointerListener { + CHyprSignalListener destroy; + CHyprSignalListener motion; + CHyprSignalListener motionAbsolute; + CHyprSignalListener button; + CHyprSignalListener axis; + CHyprSignalListener frame; + + CHyprSignalListener swipeBegin; + CHyprSignalListener swipeEnd; + CHyprSignalListener swipeUpdate; + + CHyprSignalListener pinchBegin; + CHyprSignalListener pinchEnd; + CHyprSignalListener pinchUpdate; + + CHyprSignalListener holdBegin; + CHyprSignalListener holdEnd; + + WP pointer; + }; + std::vector> pointerListeners; + + struct STouchListener { + CHyprSignalListener destroy; + CHyprSignalListener down; + CHyprSignalListener up; + CHyprSignalListener motion; + CHyprSignalListener cancel; + CHyprSignalListener frame; + + WP touch; + }; + std::vector> touchListeners; + + struct { + std::vector monitorBoxes; + } currentMonitorLayout; + + struct { + wlr_buffer* pBuffer = nullptr; + CWLSurface* surface = nullptr; + wlr_texture* pBufferTexture = nullptr; + + Vector2D hotspot; + Vector2D size; + float scale = 1.F; + + CHyprSignalListener destroySurface; + DYNLISTENER(commitSurface); + DYNLISTENER(destroyBuffer); + } 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) {} + WP monitor; + + int softwareLocks = 0; + bool hardwareFailed = false; + CBox box; // logical + bool entered = false; + bool hwApplied = false; + + wlr_buffer* cursorFrontBuffer = nullptr; + }; + + std::vector> monitorStates; + SP stateFor(SP mon); + bool attemptHardwareCursor(SP state); + wlr_buffer* renderHWCursorBuffer(SP state, wlr_texture* texture); + bool setHWCursorBuffer(SP state, wlr_buffer* buf); + + struct { + SP monitorAdded; + } hooks; +}; + +inline UP g_pPointerManager; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 6d493e5b..22fc24d4 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -20,6 +20,8 @@ #include "../../devices/VirtualKeyboard.hpp" #include "../../devices/TouchDevice.hpp" +#include "../../managers/PointerManager.hpp" + CInputManager::CInputManager() { m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) { if (!cursorImageUnlocked()) @@ -63,31 +65,31 @@ CInputManager::~CInputManager() { m_lSwitches.clear(); } -void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) { +void CInputManager::onMouseMoved(IPointer::SMotionEvent e) { static auto PSENS = CConfigValue("general:sensitivity"); static auto PNOACCEL = CConfigValue("input:force_no_accel"); static auto PSENSTORAW = CConfigValue("general:apply_sens_to_raw"); - const auto DELTA = *PNOACCEL == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y); + const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta; if (*PSENSTORAW == 1) - PROTO::relativePointer->sendRelativeMotion((uint64_t)e->time_msec * 1000, DELTA * *PSENS, Vector2D{e->unaccel_dx, e->unaccel_dy} * *PSENS); + PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA * *PSENS, e.unaccel * *PSENS); else - PROTO::relativePointer->sendRelativeMotion((uint64_t)e->time_msec * 1000, DELTA, Vector2D{e->unaccel_dx, e->unaccel_dy}); + PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel); - wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * *PSENS, DELTA.y * *PSENS); + g_pPointerManager->move(DELTA * *PSENS); - mouseMoveUnified(e->time_msec); + mouseMoveUnified(e.timeMs); m_tmrLastCursorMovement.reset(); m_bLastInputTouch = false; } -void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) { - wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, &e->pointer->base, e->x, e->y); +void CInputManager::onMouseWarp(IPointer::SMotionAbsoluteEvent e) { + g_pPointerManager->warpAbsolute(e.absolute, e.device); - mouseMoveUnified(e->time_msec); + mouseMoveUnified(e.timeMs); m_tmrLastCursorMovement.reset(); @@ -194,14 +196,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (SURF && CONSTRAINT) { if (CONSTRAINT->isLocked()) { const auto HINT = CONSTRAINT->logicPositionHint(); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, HINT.x, HINT.y); + g_pCompositor->warpCursorTo(HINT, true); } else { const auto RG = CONSTRAINT->logicConstraintRegion(); const auto CLOSEST = RG.closestPoint(mouseCoords); const auto BOX = SURF->getSurfaceBoxGlobal(); const auto CLOSESTLOCAL = (CLOSEST - (BOX.has_value() ? BOX->pos() : Vector2D{})) * (SURF->getWindow() ? SURF->getWindow()->m_fX11SurfaceScaledBy : 1.0); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, CLOSEST.x, CLOSEST.y); + g_pCompositor->warpCursorTo(CLOSEST, true); wlr_seat_pointer_send_motion(g_pCompositor->m_sSeat.seat, time, CLOSESTLOCAL.x, CLOSESTLOCAL.y); PROTO::relativePointer->sendRelativeMotion((uint64_t)time * 1000, {}, {}); } @@ -241,7 +243,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal()); - if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) + if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor.get() && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) g_pCompositor->setActiveMonitor(PMONITOR); if (g_pSessionLockManager->isSessionLocked()) { @@ -350,7 +352,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { 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) - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get()); if (!foundSurface) { if (!m_bEmptyFocusCursorSet) { @@ -491,19 +493,19 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); } -void CInputManager::onMouseButton(wlr_pointer_button_event* e) { +void CInputManager::onMouseButton(IPointer::SButtonEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("mouseButton", e); PROTO::idle->onActivity(); m_tmrLastCursorMovement.reset(); - if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) { - m_lCurrentlyHeldButtons.push_back(e->button); + if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { + m_lCurrentlyHeldButtons.push_back(e.button); } else { - if (std::find_if(m_lCurrentlyHeldButtons.begin(), m_lCurrentlyHeldButtons.end(), [&](const auto& other) { return other == e->button; }) == m_lCurrentlyHeldButtons.end()) + if (std::find_if(m_lCurrentlyHeldButtons.begin(), m_lCurrentlyHeldButtons.end(), [&](const auto& other) { return other == e.button; }) == m_lCurrentlyHeldButtons.end()) return; - std::erase_if(m_lCurrentlyHeldButtons, [&](const auto& other) { return other == e->button; }); + std::erase_if(m_lCurrentlyHeldButtons, [&](const auto& other) { return other == e.button; }); } switch (m_ecbClickBehavior) { @@ -512,7 +514,7 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) { default: break; } - if (m_bFocusHeldByButtons && m_lCurrentlyHeldButtons.empty() && e->state == WL_POINTER_BUTTON_STATE_RELEASED) { + if (m_bFocusHeldByButtons && m_lCurrentlyHeldButtons.empty() && e.state == WL_POINTER_BUTTON_STATE_RELEASED) { if (m_bRefocusHeldByButtons) refocus(); else @@ -549,7 +551,7 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even m_sCursorSurfaceInfo.name = ""; m_sCursorSurfaceInfo.inUse = true; - g_pHyprRenderer->setCursorSurface(e->surface, e->hotspot_x, e->hotspot_y); + g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, e->hotspot_x, e->hotspot_y); } } @@ -564,7 +566,7 @@ void CInputManager::restoreCursorIconToApp() { if (m_sCursorSurfaceInfo.name.empty()) { if (m_sCursorSurfaceInfo.wlSurface.exists()) - g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface.wlr(), m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y); + g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y); } else { g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name); } @@ -617,7 +619,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) { } } -void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { +void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { // notify the keybind manager static auto PPASSMOUSE = CConfigValue("binds:pass_mouse_when_bound"); @@ -639,7 +641,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { // clicking on border triggers resize // TODO detect click on LS properly - if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e->state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED) { if (w && !w->m_bIsFullscreen) { const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y}; const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA}; @@ -651,7 +653,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { } } - switch (e->state) { + switch (e.state) { case WL_POINTER_BUTTON_STATE_PRESSED: if (*PFOLLOWMOUSE == 3) // don't refocus on full loose break; @@ -679,14 +681,14 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { // notify app if we didnt handle it if (g_pCompositor->doesSeatAcceptInput(g_pCompositor->m_pLastFocus)) - wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, e->time_msec, e->button, e->state); + wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, e.timeMs, e.button, e.state); - if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor && PMON) + if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor.get() && PMON) g_pCompositor->setActiveMonitor(PMON); } -void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) { - switch (e->state) { +void CInputManager::processMouseDownKill(const IPointer::SButtonEvent& e) { + switch (e.state) { case WL_POINTER_BUTTON_STATE_PRESSED: { const auto PWINDOW = g_pCompositor->vectorToWindowUnified(getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); @@ -707,12 +709,12 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) { m_ecbClickBehavior = CLICKMODE_DEFAULT; } -void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) { +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"); - auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e->source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR); + auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR); const auto EMAP = std::unordered_map{{"event", e}}; EMIT_HOOK_EVENT_CANCELLABLE("mouseAxis", EMAP); @@ -742,20 +744,20 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) { const auto TEMPCURY = std::clamp(MOUSECOORDS.y, BOX.y, BOX.y + BOX.h - 1); if (*POFFWINDOWAXIS == 3) - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, TEMPCURX, TEMPCURY); + g_pCompositor->warpCursorTo({TEMPCURX, TEMPCURY}, true); - wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, TEMPCURX - BOX.x, TEMPCURY - BOX.y); + wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, TEMPCURX - BOX.x, TEMPCURY - BOX.y); wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); } } } - wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source, + wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e.timeMs, e.axis, factor * e.delta, std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); } Vector2D CInputManager::getMouseCoordsInternal() { - return Vector2D(g_pCompositor->m_sWLRCursor->x, g_pCompositor->m_sWLRCursor->y); + return g_pPointerManager->position(); } void CInputManager::newKeyboard(wlr_input_device* keyboard) { @@ -989,7 +991,7 @@ void CInputManager::setupMouse(SP mauz) { (int)libinput_device_config_accel_get_default_profile(LIBINPUTDEV)); } - wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, &mauz->wlr()->base); + g_pPointerManager->attachPointer(mauz); mauz->connected = true; @@ -1020,10 +1022,10 @@ void CInputManager::setPointerConfigs() { if (HASCONFIG) { const auto ENABLED = g_pConfigManager->getDeviceInt(devname, "enabled"); if (ENABLED && !m->connected) { - wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, &m->wlr()->base); + g_pPointerManager->attachPointer(m); m->connected = true; } else if (!ENABLED && m->connected) { - wlr_cursor_detach_input_device(g_pCompositor->m_sWLRCursor, &m->wlr()->base); + g_pPointerManager->detachPointer(m); m->connected = false; } } @@ -1386,7 +1388,7 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) { } setTouchDeviceConfigs(PNEWDEV); - wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice); + g_pPointerManager->attachTouch(PNEWDEV); PNEWDEV->events.destroy.registerStaticListener( [this](void* owner, std::any data) { @@ -1431,7 +1433,7 @@ void CInputManager::setTouchDeviceConfigs(SP dev) { const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr; if (PMONITOR) { Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->hlName, PMONITOR->szName); - wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, PMONITOR->output); + // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, PMONITOR->output); } else if (bound) Debug::log(ERR, "Failed to bind touch device {} to output '{}': monitor not found", PTOUCHDEV->hlName, output); } @@ -1468,17 +1470,17 @@ void CInputManager::setTabletConfigs() { const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT); if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) { Debug::log(LOG, "Binding tablet {} to output {}", t.name, PMONITOR->szName); - wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output); - wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr); + // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output); + // wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr); t.boundOutput = OUTPUT; } else if (!PMONITOR) Debug::log(ERR, "Failed to bind tablet {} to output '{}': monitor not found", t.name, OUTPUT); const auto REGION_POS = g_pConfigManager->getDeviceVec(t.name, "region_position", "input:tablet:region_position"); const auto REGION_SIZE = g_pConfigManager->getDeviceVec(t.name, "region_size", "input:tablet:region_size"); - auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y}; - if (!regionBox.empty()) - wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr()); + //auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y}; + // if (!regionBox.empty()) + // wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr()); const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(t.name, "active_area_size", "input:tablet:active_area_size"); const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(t.name, "active_area_position", "input:tablet:active_area_position"); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 7d78c133..a2caed46 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -7,15 +7,15 @@ #include "../../helpers/Timer.hpp" #include "InputMethodRelay.hpp" #include "../../helpers/signal/Listener.hpp" +#include "../../devices/IPointer.hpp" +#include "../../devices/ITouch.hpp" class CPointerConstraint; class CWindow; class CIdleInhibitor; class CVirtualKeyboardV1Resource; class CVirtualPointerV1Resource; -class IPointer; class IKeyboard; -class ITouch; enum eClickBehaviorMode { CLICKMODE_DEFAULT = 0, @@ -74,10 +74,10 @@ class CInputManager { CInputManager(); ~CInputManager(); - void onMouseMoved(wlr_pointer_motion_event*); - void onMouseWarp(wlr_pointer_motion_absolute_event*); - void onMouseButton(wlr_pointer_button_event*); - void onMouseWheel(wlr_pointer_axis_event*); + void onMouseMoved(IPointer::SMotionEvent); + void onMouseWarp(IPointer::SMotionAbsoluteEvent); + void onMouseButton(IPointer::SButtonEvent); + void onMouseWheel(IPointer::SAxisEvent); void onKeyboardKey(std::any, SP); void onKeyboardMod(SP); @@ -112,9 +112,9 @@ class CInputManager { eClickBehaviorMode getClickMode(); void processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e); - void onTouchDown(wlr_touch_down_event*); - void onTouchUp(wlr_touch_up_event*); - void onTouchMove(wlr_touch_motion_event*); + void onTouchDown(ITouch::SDownEvent); + void onTouchUp(ITouch::SUpEvent); + void onTouchMove(ITouch::SMotionEvent); STouchData m_sTouchData; @@ -153,9 +153,9 @@ class CInputManager { void newIdleInhibitor(std::any); void recheckIdleInhibitorStatus(); - void onSwipeBegin(wlr_pointer_swipe_begin_event*); - void onSwipeEnd(wlr_pointer_swipe_end_event*); - void onSwipeUpdate(wlr_pointer_swipe_update_event*); + void onSwipeBegin(IPointer::SSwipeBeginEvent); + void onSwipeEnd(IPointer::SSwipeEndEvent); + void onSwipeUpdate(IPointer::SSwipeUpdateEvent); SSwipeGesture m_sActiveSwipe; @@ -212,8 +212,8 @@ class CInputManager { void setupKeyboard(SP keeb); void setupMouse(SP mauz); - void processMouseDownNormal(wlr_pointer_button_event* e); - void processMouseDownKill(wlr_pointer_button_event* e); + void processMouseDownNormal(const IPointer::SButtonEvent& e); + void processMouseDownKill(const IPointer::SButtonEvent& e); bool cursorImageUnlocked(); diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 8c489af5..63adc8ca 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -2,14 +2,14 @@ #include "../../Compositor.hpp" #include "../../config/ConfigValue.hpp" -void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) { +void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) { static auto PSWIPE = CConfigValue("gestures:workspace_swipe"); static auto PSWIPEFINGERS = CConfigValue("gestures:workspace_swipe_fingers"); static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); EMIT_HOOK_EVENT_CANCELLABLE("swipeBegin", e); - if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked()) + if (e.fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked()) return; int onMonitor = 0; @@ -32,7 +32,7 @@ void CInputManager::beginWorkspaceSwipe() { m_sActiveSwipe.pWorkspaceBegin = PWORKSPACE; m_sActiveSwipe.delta = 0; - m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor; + m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor.get(); m_sActiveSwipe.avgSpeed = 0; m_sActiveSwipe.speedPoints = 0; @@ -43,7 +43,7 @@ void CInputManager::beginWorkspaceSwipe() { } } -void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) { +void CInputManager::onSwipeEnd(IPointer::SSwipeEndEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("swipeEnd", e); if (!m_sActiveSwipe.pWorkspaceBegin) @@ -198,7 +198,7 @@ void CInputManager::endWorkspaceSwipe() { } } -void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) { +void CInputManager::onSwipeUpdate(IPointer::SSwipeUpdateEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("swipeUpdate", e); if (!m_sActiveSwipe.pWorkspaceBegin) @@ -207,7 +207,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) { const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); - const double delta = m_sActiveSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx)); + const double delta = m_sActiveSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e.delta.y : e.delta.y) : (*PSWIPEINVR ? -e.delta.x : e.delta.x)); updateWorkspaceSwipe(delta); } @@ -348,7 +348,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) { if (*PSWIPEFOREVER) { if (abs(m_sActiveSwipe.delta) >= SWIPEDISTANCE) { - onSwipeEnd(nullptr); + onSwipeEnd({}); beginWorkspaceSwipe(); } } diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 979eb1a7..a0bd81ce 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -18,7 +18,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { Debug::log(LOG, "Attaching tablet to cursor!"); - wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice); + // wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice); PNEWTABLET->hyprListener_Destroy.initCallback( &pDevice->events.destroy, @@ -39,7 +39,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { switch (EVENT->tool->type) { case WLR_TABLET_TOOL_TYPE_MOUSE: - wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy); + // wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy); g_pInputManager->simulateMouseMovement(); g_pInputManager->focusTablet(PTAB, EVENT->tool, true); g_pInputManager->m_tmrLastCursorMovement.reset(); @@ -50,16 +50,16 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { double y = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->y : NAN; double dy = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->dy : NAN; - if (PTAB->relativeInput) - wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy); - else { - // Calculate transformations if active area is set - if (!PTAB->activeArea.empty()) { - x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x); - y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y); - } - wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y); - } + // if (PTAB->relativeInput) + // wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy); + // else { + // Calculate transformations if active area is set + // if (!PTAB->activeArea.empty()) { + // x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x); + // y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y); + // } + // wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y); + // } g_pInputManager->simulateMouseMovement(); g_pInputManager->focusTablet(PTAB, EVENT->tool, true); diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 7b0d6190..60d85aa6 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -4,7 +4,7 @@ #include "../../protocols/IdleNotify.hpp" #include "../../devices/ITouch.hpp" -void CInputManager::onTouchDown(wlr_touch_down_event* e) { +void CInputManager::onTouchDown(ITouch::SDownEvent e) { static auto PSWIPETOUCH = CConfigValue("gestures:workspace_swipe_touch"); static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); @@ -14,23 +14,18 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) { static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_invert"); EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e); - auto PMONITOR = g_pCompositor->getMonitorFromName(e->touch->output_name ? e->touch->output_name : ""); + auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : ""); - const auto PDEVIT = std::find_if(m_vTouches.begin(), m_vTouches.end(), [&](const auto& other) { return other->wlr() == e->touch; }); + PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor.get(); - if (PDEVIT != m_vTouches.end() && !(*PDEVIT)->boundOutput.empty()) - PMONITOR = g_pCompositor->getMonitorFromName((*PDEVIT)->boundOutput); - - PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor; - - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); + g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); refocus(); if (m_ecbClickBehavior == CLICKMODE_KILL) { - wlr_pointer_button_event e; + IPointer::SButtonEvent e; e.state = WL_POINTER_BUTTON_STATE_PRESSED; - g_pInputManager->processMouseDownKill(&e); + g_pInputManager->processMouseDownKill(e); return; } @@ -45,10 +40,10 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) { // TODO: support no_gaps_when_only? const double TARGETLEFT = ((VERTANIMS ? gapsOut.top : gapsOut.left) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x); const double TARGETRIGHT = 1 - (((VERTANIMS ? gapsOut.bottom : gapsOut.right) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x)); - const double POSITION = (VERTANIMS ? e->y : e->x); + const double POSITION = (VERTANIMS ? e.pos.y : e.pos.x); if (POSITION < TARGETLEFT || POSITION > TARGETRIGHT) { beginWorkspaceSwipe(); - m_sActiveSwipe.touch_id = e->touch_id; + m_sActiveSwipe.touch_id = e.touchID; // Set the initial direction based on which edge you started from if (POSITION > 0.5) m_sActiveSwipe.initialDirection = *PSWIPEINVR ? -1 : 1; @@ -78,34 +73,33 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) { local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusLS->geometry.pos(); m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local; - } else { + } else return; // oops, nothing found. - } - wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e->time_msec, e->touch_id, local.x, local.y); + wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e.timeMs, e.touchID, local.x, local.y); PROTO::idle->onActivity(); } -void CInputManager::onTouchUp(wlr_touch_up_event* e) { +void CInputManager::onTouchUp(ITouch::SUpEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e); if (m_sActiveSwipe.pWorkspaceBegin) { // If there was a swipe from this finger, end it. - if (e->touch_id == m_sActiveSwipe.touch_id) + if (e.touchID == m_sActiveSwipe.touch_id) endWorkspaceSwipe(); return; } if (m_sTouchData.touchFocusSurface) { - wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id); + wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID); } } -void CInputManager::onTouchMove(wlr_touch_motion_event* e) { +void CInputManager::onTouchMove(ITouch::SMotionEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e); if (m_sActiveSwipe.pWorkspaceBegin) { // Do nothing if this is using a different finger. - if (e->touch_id != m_sActiveSwipe.touch_id) + if (e.touchID != m_sActiveSwipe.touch_id) return; const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); @@ -116,37 +110,37 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) { if (m_sActiveSwipe.initialDirection == -1) { if (*PSWIPEINVR) // go from 0 to -SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * ((VERTANIMS ? e->y : e->x) - 1)); + updateWorkspaceSwipe(SWIPEDISTANCE * ((VERTANIMS ? e.pos.y : e.pos.x) - 1)); else // go from 0 to -SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * (-1 * (VERTANIMS ? e->y : e->x))); + updateWorkspaceSwipe(SWIPEDISTANCE * (-1 * (VERTANIMS ? e.pos.y : e.pos.x))); } else if (*PSWIPEINVR) // go from 0 to SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * (VERTANIMS ? e->y : e->x)); + updateWorkspaceSwipe(SWIPEDISTANCE * (VERTANIMS ? e.pos.y : e.pos.x)); else // go from 0 to SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * (1 - (VERTANIMS ? e->y : e->x))); + updateWorkspaceSwipe(SWIPEDISTANCE * (1 - (VERTANIMS ? e.pos.y : e.pos.x))); return; } if (validMapped(m_sTouchData.touchFocusWindow)) { const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); + g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin; if (m_sTouchData.touchFocusWindow->m_bIsX11) local = local * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; - wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y); + wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID, local.x, local.y); // wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); } else if (!m_sTouchData.touchFocusLS.expired()) { const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); + g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin; - wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y); + wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID, local.x, local.y); // wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); } } diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 476df0b8..a4d62506 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -1,5 +1,6 @@ #include "Screencopy.hpp" #include "../Compositor.hpp" +#include "../managers/PointerManager.hpp" #include @@ -183,6 +184,11 @@ void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force if (!frame) return; + if (frame->lockedSWCursors) { + g_pPointerManager->unlockSoftwareForMonitor(frame->pMonitor->self.lock()); + g_pPointerManager->damageCursor(frame->pMonitor->self.lock()); + } + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); wl_resource_set_user_data(frame->resource, nullptr); @@ -352,8 +358,11 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou m_vFramesAwaitingWrite.emplace_back(PFRAME); g_pHyprRenderer->m_bDirectScanoutBlocked = true; - if (PFRAME->overlayCursor) - g_pHyprRenderer->m_bSoftwareCursorsLocked = true; + if (PFRAME->overlayCursor && !PFRAME->lockedSWCursors) { + PFRAME->lockedSWCursors = true; + g_pPointerManager->lockSoftwareForMonitor(PFRAME->pMonitor->self.lock()); + g_pPointerManager->damageCursor(PFRAME->pMonitor->self.lock()); + } if (!PFRAME->withDamage) g_pHyprRenderer->damageMonitor(PFRAME->pMonitor); @@ -393,17 +402,8 @@ void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) { removeFrame(f); } - g_pHyprRenderer->m_bSoftwareCursorsLocked = false; - if (m_vFramesAwaitingWrite.empty()) { g_pHyprRenderer->m_bDirectScanoutBlocked = false; - } else { - for (auto& f : m_vFramesAwaitingWrite) { - if (f->overlayCursor) { - g_pHyprRenderer->m_bSoftwareCursorsLocked = true; - break; - } - } } } diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index c39152d8..7b9a5770 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -48,8 +48,9 @@ struct SScreencopyFrame { CBox box = {}; int shmStride = 0; - bool overlayCursor = false; - bool withDamage = false; + bool overlayCursor = false; + bool withDamage = false; + bool lockedSWCursors = false; wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 70f00fa1..d3b71a9e 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -1,6 +1,7 @@ #include "ToplevelExport.hpp" #include "../Compositor.hpp" #include "ForeignToplevelWlr.hpp" +#include "../managers/PointerManager.hpp" #include @@ -313,7 +314,7 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; - if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, geometry.pWlr())) + if (geometry.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty()) continue; shareFrame(f); @@ -382,8 +383,10 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times return false; } - if (frame->overlayCursor) - wlr_output_lock_software_cursors(PMONITOR->output, true); + if (frame->overlayCursor) { + g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); + g_pPointerManager->damageCursor(PMONITOR->self.lock()); + } g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); @@ -393,7 +396,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (frame->overlayCursor) - g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format); if (!PFORMAT) { @@ -419,8 +422,10 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times wlr_buffer_end_data_ptr_access(frame->buffer); - if (frame->overlayCursor) - wlr_output_lock_software_cursors(PMONITOR->output, false); + if (frame->overlayCursor) { + g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock()); + g_pPointerManager->damageCursor(PMONITOR->self.lock()); + } return true; } @@ -440,7 +445,7 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (frame->overlayCursor) - g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index cea49818..5cbac942 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -246,13 +246,10 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { return false; } -void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional finalDamage) { +void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRenderbuffer* rb, CFramebuffer* fb) { m_RenderData.pMonitor = pMonitor; - static auto PFORCEINTROSPECTION = CConfigValue("opengl:force_introspection"); - #ifndef GLES2 - const GLenum RESETSTATUS = glGetGraphicsResetStatus(); if (RESETSTATUS != GL_NO_ERROR) { std::string errStr = ""; @@ -265,7 +262,62 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu RASSERT(false, "Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented.", errStr); return; } +#endif + TRACY_GPU_ZONE("RenderBeginSimple"); + + const auto FBO = rb ? rb->getFB() : fb; + + glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + + matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + + wlr_matrix_identity(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); + } + + m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; + + if (!m_RenderData.pCurrentMonData->m_bShadersInitialized) + initShaders(); + + m_RenderData.damage.set(damage); + m_RenderData.finalDamage.set(damage); + + m_bFakeFrame = true; + + m_RenderData.currentFB = FBO; + FBO->bind(); + m_bOffloadedFramebuffer = false; + + m_RenderData.mainFB = m_RenderData.currentFB; + m_RenderData.outFB = FBO; + + m_RenderData.simplePass = true; +} + +void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional finalDamage) { + m_RenderData.pMonitor = pMonitor; + + static auto PFORCEINTROSPECTION = CConfigValue("opengl:force_introspection"); + +#ifndef GLES2 + const GLenum RESETSTATUS = glGetGraphicsResetStatus(); + if (RESETSTATUS != GL_NO_ERROR) { + std::string errStr = ""; + switch (RESETSTATUS) { + case GL_GUILTY_CONTEXT_RESET: errStr = "GL_GUILTY_CONTEXT_RESET"; break; + case GL_INNOCENT_CONTEXT_RESET: errStr = "GL_INNOCENT_CONTEXT_RESET"; break; + case GL_UNKNOWN_CONTEXT_RESET: errStr = "GL_UNKNOWN_CONTEXT_RESET"; break; + default: errStr = "UNKNOWN??"; break; + } + RASSERT(false, "Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented.", errStr); + return; + } #endif TRACY_GPU_ZONE("RenderBegin"); @@ -274,6 +326,8 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + m_RenderData.monitorProjection = pMonitor->projMatrix; + if (m_mMonitorRenderResources.contains(pMonitor) && m_mMonitorRenderResources.at(pMonitor).offloadFB.m_vSize != pMonitor->vecPixelSize) destroyMonitorResources(pMonitor); @@ -753,7 +807,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion float matrix[9]; wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot, - m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here + m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -814,6 +868,12 @@ void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, CBox* pBox, float alpha, i renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV); } +void CHyprOpenGLImpl::renderTextureWithDamage(wlr_texture* tex, CBox* pBox, CRegion* damage, float alpha, int round, bool allowCustomUV) { + RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); + + renderTextureWithDamage(CTexture(tex), pBox, damage, alpha, round, false, allowCustomUV); +} + void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); @@ -822,6 +882,14 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha scissor((CBox*)nullptr); } +void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { + RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); + + renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true); + + scissor((CBox*)nullptr); +} + void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, bool allowDim) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); @@ -843,7 +911,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* // get transform const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); float matrix[9]; - wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data()); + wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1006,7 +1074,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { // get transform const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); float matrix[9]; - wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data()); + wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1060,7 +1128,7 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame // get transform const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); float matrix[9]; - wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data()); + wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1119,7 +1187,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o const auto TRANSFORM = wlr_output_transform_invert(m_RenderData.pMonitor->transform); float matrix[9]; CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - wlr_matrix_project_box(matrix, MONITORBOX.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data()); + wlr_matrix_project_box(matrix, MONITORBOX.pWlr(), TRANSFORM, 0, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1615,7 +1683,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in float matrix[9]; wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot, - m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here + m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1921,7 +1989,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const float matrix[9]; wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot, - m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here + m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index bebf82bc..ca9eecc6 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -95,33 +95,35 @@ struct SMonitorRenderData { }; struct SCurrentRenderData { - CMonitor* pMonitor = nullptr; - PHLWORKSPACE pWorkspace = nullptr; - float projection[9]; - float savedProjection[9]; + CMonitor* pMonitor = nullptr; + PHLWORKSPACE pWorkspace = nullptr; + float projection[9]; + float savedProjection[9]; + std::array monitorProjection; - SMonitorRenderData* pCurrentMonData = nullptr; - CFramebuffer* currentFB = nullptr; // current rendering to - CFramebuffer* mainFB = nullptr; // main to render to - CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc) + SMonitorRenderData* pCurrentMonData = nullptr; + CFramebuffer* currentFB = nullptr; // current rendering to + CFramebuffer* mainFB = nullptr; // main to render to + CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc) - CRegion damage; - CRegion finalDamage; // damage used for funal off -> main + CRegion damage; + CRegion finalDamage; // damage used for funal off -> main - SRenderModifData renderModif; - float mouseZoomFactor = 1.f; - bool mouseZoomUseMouse = true; // true by default - bool useNearestNeighbor = false; - bool forceIntrospection = false; // cleaned in ::end() - bool blockScreenShader = false; + SRenderModifData renderModif; + float mouseZoomFactor = 1.f; + bool mouseZoomUseMouse = true; // true by default + bool useNearestNeighbor = false; + bool forceIntrospection = false; // cleaned in ::end() + bool blockScreenShader = false; + bool simplePass = false; - Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); - Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); + Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); + Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); - CBox clipBox = {}; // scaled coordinates + CBox clipBox = {}; // scaled coordinates - uint32_t discardMode = DISCARD_OPAQUE; - float discardOpacity = 0.f; + uint32_t discardMode = DISCARD_OPAQUE; + float discardOpacity = 0.f; }; class CGradientValueData; @@ -131,13 +133,16 @@ 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 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(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false); + void renderTextureWithDamage(wlr_texture*, CBox*, CRegion* damage, float a, int round = 0, bool allowCustomUV = false); void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(const CTexture&, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* 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 */); diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 9434c3f0..5003f600 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -8,16 +8,16 @@ CRenderbuffer::~CRenderbuffer() { if (!g_pCompositor) 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)); + g_pHyprRenderer->makeEGLCurrent(); + unbind(); m_sFramebuffer.release(); glDeleteRenderbuffers(1, &m_iRBO); g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage); } -CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer) { +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*); @@ -58,7 +58,7 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); hyprListener_destroyBuffer.initCallback( - &buffer->events.destroy, [](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy((CRenderbuffer*)owner); }, this, "CRenderbuffer"); + &buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer"); } void CRenderbuffer::bind() { diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index d8df8ca5..2a8bf250 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -13,6 +13,7 @@ class CRenderbuffer { void bindFB(); void unbind(); CFramebuffer* getFB(); + uint32_t getFormat(); wlr_buffer* m_pWlrBuffer = nullptr; @@ -22,4 +23,5 @@ class CRenderbuffer { EGLImageKHR m_iImage = 0; GLuint m_iRBO = 0; CFramebuffer m_sFramebuffer; + uint32_t m_uDrmFormat = 0; }; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index ee874589..a671bd40 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -5,6 +5,7 @@ #include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" +#include "../managers/PointerManager.hpp" #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/SessionLock.hpp" @@ -95,8 +96,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) TRACY_GPU_ZONE("RenderSurface"); - double outputX = 0, outputY = 0; - wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, RDATA->pMonitor->output, &outputX, &outputY); + double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y; auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface); @@ -217,9 +217,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) } bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, CMonitor* pMonitor) { - CBox geometry = pWindow->getFullWindowBoundingBox(); - - if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, geometry.pWlr())) + if (!pWindow->visibleOnMonitor(pMonitor)) return false; if (!pWindow->m_pWorkspace && !pWindow->m_bFadingOut) @@ -1209,10 +1207,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { EMIT_HOOK_EVENT("render", RENDER_PRE); - const bool UNLOCK_SC = g_pHyprRenderer->m_bSoftwareCursorsLocked; - if (UNLOCK_SC) - wlr_output_lock_software_cursors(pMonitor->output, true); - pMonitor->renderingActive = true; // we need to cleanup fading out when rendering the appropriate context @@ -1238,12 +1232,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { CRegion damage, finalDamage; if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) { Debug::log(ERR, "renderer: couldn't beginRender()!"); - - if (UNLOCK_SC) - wlr_output_lock_software_cursors(pMonitor->output, false); - pMonitor->state.clear(); - return; } @@ -1300,7 +1289,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { renderLockscreen(pMonitor, &now, renderBox); - if (pMonitor == g_pCompositor->m_pLastMonitor) { + if (pMonitor == g_pCompositor->m_pLastMonitor.get()) { g_pHyprNotificationOverlay->draw(pMonitor); g_pHyprError->draw(); } @@ -1338,11 +1327,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f; if (lockSoftware) { - wlr_output_lock_software_cursors(pMonitor->output, true); - g_pHyprRenderer->renderSoftwareCursors(pMonitor, g_pHyprOpenGL->m_RenderData.damage); - wlr_output_lock_software_cursors(pMonitor->output, false); + g_pPointerManager->lockSoftwareForMonitor(pMonitor->self.lock()); + g_pPointerManager->renderSoftwareCursorsFor(pMonitor->self.lock(), &now, g_pHyprOpenGL->m_RenderData.damage); + g_pPointerManager->unlockSoftwareForMonitor(pMonitor->self.lock()); } else - g_pHyprRenderer->renderSoftwareCursors(pMonitor, g_pHyprOpenGL->m_RenderData.damage); + g_pPointerManager->renderSoftwareCursorsFor(pMonitor->self.lock(), &now, g_pHyprOpenGL->m_RenderData.damage); } EMIT_HOOK_EVENT("render", RENDER_LAST_MOMENT); @@ -1373,21 +1362,13 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->state.wlr()->tearing_page_flip = shouldTear; if (!pMonitor->state.commit()) { - - if (UNLOCK_SC) - wlr_output_lock_software_cursors(pMonitor->output, false); - wlr_damage_ring_add_whole(&pMonitor->damage); - return; } if (shouldTear) pMonitor->tearingState.busy = true; - if (UNLOCK_SC) - wlr_output_lock_software_cursors(pMonitor->output, false); - if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame) g_pCompositor->scheduleFrameForMonitor(pMonitor); @@ -1843,6 +1824,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->onDisconnect(); pMonitor->events.modeChanged.emit(); + pMonitor->updateGlobal(); return true; } @@ -2248,11 +2230,12 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr); pMonitor->events.modeChanged.emit(); + pMonitor->updateGlobal(); return true; } -void CHyprRenderer::setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY, bool force) { +void CHyprRenderer::setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force) { m_bCursorHasSurface = surf; if (surf == m_sLastCursorData.surf && hotspotX == m_sLastCursorData.hotspotX && hotspotY == m_sLastCursorData.hotspotY && !force) @@ -2266,7 +2249,7 @@ void CHyprRenderer::setCursorSurface(wlr_surface* surf, int hotspotX, int hotspo if (m_bCursorHidden && !force) return; - wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspotX, hotspotY); + g_pCursorManager->setCursorSurface(surf, {hotspotX, hotspotY}); } void CHyprRenderer::setCursorFromName(const std::string& name, bool force) { @@ -2338,7 +2321,7 @@ void CHyprRenderer::setCursorHidden(bool hide) { m_bCursorHidden = hide; if (hide) { - wlr_cursor_unset_image(g_pCompositor->m_sWLRCursor); + g_pPointerManager->resetCursorImage(); return; } @@ -2544,23 +2527,6 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { pMonitor->solitaryClient = PCANDIDATE; } -void CHyprRenderer::renderSoftwareCursors(CMonitor* pMonitor, const CRegion& damage, std::optional overridePos) { - const auto CURSORPOS = overridePos.value_or(g_pInputManager->getMouseCoordsInternal() - pMonitor->vecPosition) * pMonitor->scale; - wlr_output_cursor* cursor; - wl_list_for_each(cursor, &pMonitor->output->cursors, link) { - if (!cursor->enabled || !cursor->visible || pMonitor->output->hardware_cursor == cursor) - continue; - - if (!cursor->texture) - continue; - - CBox cursorBox = CBox{CURSORPOS.x, CURSORPOS.y, cursor->width, cursor->height}.translate({-cursor->hotspot_x, -cursor->hotspot_y}); - - // TODO: NVIDIA doesn't like if we use renderTexturePrimitive here. Why? - g_pHyprOpenGL->renderTexture(cursor->texture, &cursorBox, 1.0); - } -} - 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; }); @@ -2582,7 +2548,7 @@ void CHyprRenderer::unsetEGL() { eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb) { +bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb, bool simple) { makeEGLCurrent(); @@ -2593,7 +2559,10 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode if (mode == RENDER_MODE_FULL_FAKE) { RASSERT(fb, "Cannot render FULL_FAKE without a provided fb!"); fb->bind(); - g_pHyprOpenGL->begin(pMonitor, damage, fb); + if (simple) + g_pHyprOpenGL->beginSimple(pMonitor, damage, nullptr, fb); + else + g_pHyprOpenGL->begin(pMonitor, damage, fb); return true; } @@ -2623,7 +2592,10 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode wlr_damage_ring_rotate_buffer(&pMonitor->damage, m_pCurrentWlrBuffer, damage.pixman()); m_pCurrentRenderbuffer->bind(); - g_pHyprOpenGL->begin(pMonitor, damage); + if (simple) + g_pHyprOpenGL->beginSimple(pMonitor, damage, m_pCurrentRenderbuffer); + else + g_pHyprOpenGL->begin(pMonitor, damage); return true; } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index b93af0b0..748a055f 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -64,9 +64,8 @@ class CHyprRenderer { void setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pWorkspace); // TODO: merge occlusion methods bool canSkipBackBufferClear(CMonitor* pMonitor); void recheckSolitaryForMonitor(CMonitor* pMonitor); - void setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY, bool force = false); + void setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force = false); void setCursorFromName(const std::string& name, bool force = false); - void renderSoftwareCursors(CMonitor* pMonitor, const CRegion& damage, std::optional overridePos = {}); void onRenderbufferDestroy(CRenderbuffer* rb); CRenderbuffer* getCurrentRBO(); bool isNvidia(); @@ -75,15 +74,14 @@ class CHyprRenderer { // 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, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr); - void endRender(); + bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr, bool simple = false); + void endRender(); - bool m_bBlockSurfaceFeedback = false; - bool m_bRenderingSnapshot = false; + bool m_bBlockSurfaceFeedback = false; + bool m_bRenderingSnapshot = false; PHLWINDOWREF m_pLastScanout; - CMonitor* m_pMostHzMonitor = nullptr; - bool m_bDirectScanoutBlocked = false; - bool m_bSoftwareCursorsLocked = false; + CMonitor* m_pMostHzMonitor = nullptr; + bool m_bDirectScanoutBlocked = false; DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); @@ -100,10 +98,10 @@ class CHyprRenderer { CTimer m_tRenderTimer; struct { - int hotspotX; - int hotspotY; - std::optional surf = nullptr; - std::string name; + int hotspotX; + int hotspotY; + std::optional surf = nullptr; + std::string name; } m_sLastCursorData; private: @@ -139,6 +137,7 @@ class CHyprRenderer { friend class CHyprOpenGLImpl; friend class CToplevelExportProtocolManager; friend class CInputManager; + friend class CPointerManager; }; inline std::unique_ptr g_pHyprRenderer;