From d72ea5f2a7fdb0d0a7bf914412327195b05199b0 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 2 Mar 2024 21:04:55 +0000 Subject: [PATCH] input: Rewritten pointer constraints (#4889) * rewritten constraints * send pointer enter on activate if not pointer focus * minor cleanup * simulate movement on commit * don't ignore oneshot prop * various fixes * dont send motion on confined * update pos hint on region change --- src/Compositor.cpp | 43 ++---- src/Compositor.hpp | 1 - src/desktop/Constraint.cpp | 121 +++++++++++++++++ src/desktop/Constraint.hpp | 44 ++++++ src/desktop/WLSurface.cpp | 22 +++ src/desktop/WLSurface.hpp | 18 ++- src/events/Devices.cpp | 40 +----- src/events/Events.hpp | 3 - src/events/Layers.cpp | 7 +- src/events/Windows.cpp | 7 +- src/helpers/WLClasses.cpp | 76 ----------- src/helpers/WLClasses.hpp | 37 +---- src/managers/input/InputManager.cpp | 204 ++++------------------------ src/managers/input/InputManager.hpp | 45 +++--- 14 files changed, 282 insertions(+), 386 deletions(-) create mode 100644 src/desktop/Constraint.cpp create mode 100644 src/desktop/Constraint.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index ee38764a..37626da9 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1040,13 +1040,6 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) { if (pWindow->m_phForeignToplevel) wlr_foreign_toplevel_handle_v1_set_activated(pWindow->m_phForeignToplevel, true); - if (!pWindow->m_bIsX11) { - const auto PCONSTRAINT = wlr_pointer_constraints_v1_constraint_for_surface(m_sWLRPointerConstraints, pWindow->m_uSurface.xdg->surface, m_sSeat.seat); - - if (PCONSTRAINT) - g_pInputManager->constrainMouse(m_sSeat.mouse, PCONSTRAINT); - } - g_pInputManager->recheckIdleInhibitorStatus(); // move to front of the window history @@ -1069,6 +1062,8 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) { if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface)) return; + const auto PLASTSURF = m_pLastFocus; + // Unfocus last surface if should if (m_pLastFocus && !pWindowOwner) g_pXWaylandManager->activateSurface(m_pLastFocus, false); @@ -1103,6 +1098,15 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) { m_pLastFocus = pSurface; EMIT_HOOK_EVENT("keyboardFocus", pSurface); + + const auto SURF = CWLSurface::surfaceFromWlr(pSurface); + const auto OLDSURF = CWLSurface::surfaceFromWlr(PLASTSURF); + + if (OLDSURF && OLDSURF->constraint()) + OLDSURF->constraint()->deactivate(); + + if (SURF && SURF->constraint()) + SURF->constraint()->activate(); } bool CCompositor::windowValidMapped(CWindow* pWindow) { @@ -1770,31 +1774,6 @@ void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) { pair->second = pair->second || pSurface == pair->first; } -CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) { - if (!pMouse->currentConstraint) - return nullptr; - - const auto PSURFACE = pMouse->currentConstraint->surface; - - for (auto& w : m_vWindows) { - if (w->isHidden() || !w->m_bIsMapped || !w->m_pWLSurface.exists()) - continue; - - if (w->m_bIsX11) { - if (PSURFACE == w->m_pWLSurface.wlr()) - return w.get(); - } else { - std::pair check = {PSURFACE, false}; - wlr_surface_for_each_surface(w->m_uSurface.xdg->surface, checkFocusSurfaceIter, &check); - - if (check.second) - return w.get(); - } - } - - return nullptr; -} - CMonitor* CCompositor::getMonitorInDirection(const char& dir) { return this->getMonitorInDirection(m_pLastMonitor, dir); } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index e9edae04..5d75b199 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -166,7 +166,6 @@ class CCompositor { int getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); - CWindow* getConstraintWindow(SMouse*); CMonitor* getMonitorInDirection(const char&); CMonitor* getMonitorInDirection(CMonitor*, const char&); void updateAllWindowsAnimatedDecorationValues(); diff --git a/src/desktop/Constraint.cpp b/src/desktop/Constraint.cpp new file mode 100644 index 00000000..ea89037f --- /dev/null +++ b/src/desktop/Constraint.cpp @@ -0,0 +1,121 @@ +#include "Constraint.hpp" +#include "WLSurface.hpp" +#include "../Compositor.hpp" + +CConstraint::CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner) : m_pOwner(owner), m_pConstraint(constraint) { + initSignals(); + + m_vCursorPosOnActivate = g_pInputManager->getMouseCoordsInternal(); + + g_pInputManager->m_vConstraints.push_back(this); + + if (g_pCompositor->m_pLastFocus == m_pOwner->wlr()) + activate(); +} + +CConstraint::~CConstraint() { + std::erase(g_pInputManager->m_vConstraints, this); +} + +static void onConstraintDestroy(void* owner, void* data) { + const auto CONSTRAINT = (CConstraint*)owner; + CONSTRAINT->onDestroy(); +} + +static void onConstraintSetRegion(void* owner, void* data) { + const auto CONSTRAINT = (CConstraint*)owner; + CONSTRAINT->onSetRegion(); +} + +void CConstraint::initSignals() { + hyprListener_setConstraintRegion.initCallback(&m_pConstraint->events.set_region, ::onConstraintSetRegion, this, "CConstraint"); + hyprListener_destroyConstraint.initCallback(&m_pConstraint->events.destroy, ::onConstraintDestroy, this, "CConstraint"); +} + +void CConstraint::onDestroy() { + if (active()) + deactivate(); + + // this is us + m_pOwner->m_pConstraint.reset(); +} + +void CConstraint::onSetRegion() { + if (!m_bActive) + return; + + m_rRegion.set(&m_pConstraint->region); + m_vPositionHint = m_rRegion.closestPoint(m_vPositionHint); + g_pInputManager->simulateMouseMovement(); // to warp the cursor if anything's amiss +} + +void CConstraint::onCommit() { + if (!m_bActive) + return; + + const auto COMMITTED = m_pConstraint->current.committed; + + if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) { + m_bHintSet = true; + m_vPositionHint = {m_pConstraint->current.cursor_hint.x, m_pConstraint->current.cursor_hint.y}; + g_pInputManager->simulateMouseMovement(); + } + + if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_REGION) + onSetRegion(); +} + +CRegion CConstraint::logicConstraintRegion() { + CRegion rg = m_rRegion; + const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal(); + const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{}; + rg.translate(CONSTRAINTPOS); + return rg; +} + +CWLSurface* CConstraint::owner() { + return m_pOwner; +} + +bool CConstraint::isLocked() { + return m_pConstraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED; +} + +Vector2D CConstraint::logicPositionHint() { + const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal(); + const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{}; + + return m_bHintSet ? CONSTRAINTPOS + m_vPositionHint : m_vCursorPosOnActivate; +} + +void CConstraint::deactivate() { + if (!m_bActive) + return; + + wlr_pointer_constraint_v1_send_deactivated(m_pConstraint); + m_bActive = false; + g_pCompositor->warpCursorTo(logicPositionHint(), true); + + if (m_pConstraint->lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT) + m_bDead = true; +} + +void CConstraint::activate() { + if (m_bActive || m_bDead) + return; + + // TODO: hack, probably not a super duper great idea + if (g_pCompositor->m_sSeat.seat->pointer_state.focused_surface != m_pOwner->wlr()) { + const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal(); + const auto LOCAL = SURFBOX.has_value() ? logicPositionHint() - SURFBOX->pos() : Vector2D{}; + wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, m_pOwner->wlr(), LOCAL.x, LOCAL.y); + } + + g_pCompositor->warpCursorTo(logicPositionHint(), true); + wlr_pointer_constraint_v1_send_activated(m_pConstraint); + m_bActive = true; +} + +bool CConstraint::active() { + return m_bActive; +} diff --git a/src/desktop/Constraint.hpp b/src/desktop/Constraint.hpp new file mode 100644 index 00000000..34690217 --- /dev/null +++ b/src/desktop/Constraint.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "../includes.hpp" +#include "../helpers/Region.hpp" +#include "../helpers/WLListener.hpp" + +class CWLSurface; + +class CConstraint { + public: + CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner); + ~CConstraint(); + + void onCommit(); + void onDestroy(); + void onSetRegion(); + CRegion logicConstraintRegion(); + bool isLocked(); + Vector2D logicPositionHint(); + + void deactivate(); + void activate(); + bool active(); + + CWLSurface* owner(); + + private: + bool m_bActive = false; + CWLSurface* m_pOwner = nullptr; + wlr_pointer_constraint_v1* m_pConstraint; + + CRegion m_rRegion; + bool m_bHintSet = false; + Vector2D m_vPositionHint = {-1, -1}; + Vector2D m_vCursorPosOnActivate = {-1, -1}; + + // for oneshot constraints that have been activated once + bool m_bDead = false; + + DYNLISTENER(destroyConstraint); + DYNLISTENER(setConstraintRegion); + + void initSignals(); +}; \ No newline at end of file diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 9ec121bb..b102c5ce 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -103,7 +103,10 @@ void CWLSurface::destroy() { if (!m_pWLRSurface) return; + m_pConstraint.reset(); + hyprListener_destroy.removeCallback(); + hyprListener_commit.removeCallback(); m_pWLRSurface->data = nullptr; m_pWindowOwner = nullptr; m_pLayerOwner = nullptr; @@ -123,6 +126,11 @@ void CWLSurface::destroy() { Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this); } +static void onCommit(void* owner, void* data) { + const auto SURF = (CWLSurface*)owner; + SURF->onCommit(); +} + void CWLSurface::init() { if (!m_pWLRSurface) return; @@ -133,6 +141,7 @@ void CWLSurface::init() { hyprListener_destroy.initCallback( &m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface"); + hyprListener_commit.initCallback(&m_pWLRSurface->events.commit, ::onCommit, this, "CWLSurface"); Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this); } @@ -172,3 +181,16 @@ std::optional CWLSurface::getSurfaceBoxGlobal() { return {}; } + +void CWLSurface::appendConstraint(wlr_pointer_constraint_v1* constraint) { + m_pConstraint = std::make_unique(constraint, this); +} + +void CWLSurface::onCommit() { + if (m_pConstraint) + m_pConstraint->onCommit(); +} + +CConstraint* CWLSurface::constraint() { + return m_pConstraint.get(); +} diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 3e04b4b2..b9306eea 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -2,6 +2,7 @@ #include "../defines.hpp" #include "../helpers/Region.hpp" +#include "Constraint.hpp" class CWindow; struct SLayerSurface; @@ -32,6 +33,7 @@ class CWLSurface { Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces Vector2D getViewporterCorrectedSize() const; CRegion logicalDamage() const; + void onCommit(); // getters for owners. CWindow* getWindow(); @@ -41,6 +43,8 @@ class CWLSurface { // desktop components misc utils std::optional getSurfaceBoxGlobal(); + void appendConstraint(wlr_pointer_constraint_v1* constraint); + CConstraint* constraint(); // allow stretching. Useful for plugins. bool m_bFillIgnoreSmall = false; @@ -72,6 +76,8 @@ class CWLSurface { } static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) { + if (!pSurface) + return nullptr; return (CWLSurface*)pSurface->data; } @@ -85,9 +91,15 @@ class CWLSurface { CPopup* m_pPopupOwner = nullptr; CSubsurface* m_pSubsurfaceOwner = nullptr; - void destroy(); - void init(); - bool desktopComponent(); + // + std::unique_ptr m_pConstraint; + + void destroy(); + void init(); + bool desktopComponent(); DYNLISTENER(destroy); + DYNLISTENER(commit); + + friend class CConstraint; }; \ No newline at end of file diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index 1ba6cad4..64050320 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -97,44 +97,14 @@ void Events::listener_newConstraint(wl_listener* listener, void* data) { Debug::log(LOG, "New mouse constraint at {:x}", (uintptr_t)PCONSTRAINT); - g_pInputManager->m_lConstraints.emplace_back(); - const auto CONSTRAINT = &g_pInputManager->m_lConstraints.back(); + const auto SURFACE = CWLSurface::surfaceFromWlr(PCONSTRAINT->surface); - CONSTRAINT->pMouse = g_pCompositor->m_sSeat.mouse; - CONSTRAINT->constraint = PCONSTRAINT; - - CONSTRAINT->hyprListener_destroyConstraint.initCallback(&PCONSTRAINT->events.destroy, &Events::listener_destroyConstraint, CONSTRAINT, "Constraint"); - CONSTRAINT->hyprListener_setConstraintRegion.initCallback(&PCONSTRAINT->events.set_region, &Events::listener_setConstraintRegion, CONSTRAINT, "Constraint"); - - if (g_pCompositor->m_pLastFocus == PCONSTRAINT->surface) { - g_pInputManager->constrainMouse(CONSTRAINT->pMouse, PCONSTRAINT); - - if (!CONSTRAINT->hintSet) - CONSTRAINT->positionHint = Vector2D{-1, -1}; - } -} - -void Events::listener_destroyConstraint(void* owner, void* data) { - const auto PCONSTRAINT = (SConstraint*)owner; - - if (PCONSTRAINT->pMouse->currentConstraint == PCONSTRAINT->constraint) { - PCONSTRAINT->pMouse->hyprListener_commitConstraint.removeCallback(); - - const auto PWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse); - - if (PWINDOW && PCONSTRAINT->active && PCONSTRAINT->constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) - g_pInputManager->warpMouseToConstraintMiddle(PCONSTRAINT); - - PCONSTRAINT->pMouse->currentConstraint = nullptr; + if (!SURFACE) { + Debug::log(ERR, "Refusing a constraint from an unassigned wl_surface {:x}", (uintptr_t)PCONSTRAINT->surface); + return; } - Debug::log(LOG, "Unconstrained mouse from {:x}", (uintptr_t)PCONSTRAINT->constraint); - - g_pInputManager->m_lConstraints.remove(*PCONSTRAINT); -} - -void Events::listener_setConstraintRegion(void* owner, void* data) { - // no + SURFACE->appendConstraint(PCONSTRAINT); } void Events::listener_newVirtPtr(wl_listener* listener, void* data) { diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 69faf6c1..a105846e 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -65,10 +65,7 @@ namespace Events { DYNLISTENFUNC(keyboardMod); DYNLISTENFUNC(keyboardDestroy); - DYNLISTENFUNC(commitConstraint); LISTENER(newConstraint); - DYNLISTENFUNC(setConstraintRegion); - DYNLISTENFUNC(destroyConstraint); // Various LISTENER(requestMouse); diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp index 2d94f1ed..ad65f8fb 100644 --- a/src/events/Layers.cpp +++ b/src/events/Layers.cpp @@ -144,7 +144,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) { const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && // don't focus if constrained - (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint); + (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained()); if (GRABSFOCUS) { g_pCompositor->focusSurface(layersurface->layerSurface->surface); @@ -340,8 +340,7 @@ void Events::listener_commitLayerSurface(void* owner, void* data) { layersurface->realSize.setValueAndWarp(layersurface->geometry.size()); } - if (layersurface->layerSurface->current.keyboard_interactive && - (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) // don't focus if constrained + if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained()) // don't focus if constrained && !layersurface->keyboardExclusive && layersurface->mapped) { g_pCompositor->focusSurface(layersurface->layerSurface->surface); @@ -349,7 +348,7 @@ void Events::listener_commitLayerSurface(void* owner, void* data) { g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y); - } else if (!layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) && + } else if (!layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained()) && layersurface->keyboardExclusive) { g_pInputManager->refocus(); } diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 83a37ec3..778b857e 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -476,8 +476,9 @@ void Events::listener_mapWindow(void* owner, void* data) { } if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus && - (PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent && - (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW)) { + (PWINDOW->m_iX11Type != 2 || + (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->window_type_len > 0 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && + !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(**PACTIVEALPHA); PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : **PDIMSTRENGTH); @@ -645,7 +646,7 @@ void Events::listener_mapWindow(void* owner, void* data) { g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale); g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform); - if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->constraintActive) + if (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained()) g_pInputManager->sendMotionEventsToFocused(); // fix some xwayland apps that don't behave nicely diff --git a/src/helpers/WLClasses.cpp b/src/helpers/WLClasses.cpp index 3cf170bf..8964ba59 100644 --- a/src/helpers/WLClasses.cpp +++ b/src/helpers/WLClasses.cpp @@ -167,82 +167,6 @@ bool SLayerSurface::isFadedOut() { return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated(); } -CRegion SConstraint::getLogicCoordsRegion() { - CRegion result; - - if (!constraint) - return result; - - const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface); - - if (!PWINDOWOWNER) - return result; - - result.add(&constraint->region); // surface-local coords - - if (!PWINDOWOWNER->m_bIsX11) { - result.translate(PWINDOWOWNER->m_vRealPosition.goal()); - return result; - } - - const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goal() : - g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y}); - - const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : g_pCompositor->getMonitorFromVector(COORDS); - - if (!PMONITOR) - return CRegion{}; - - result.scale(PMONITOR->xwaylandScale); - - result.translate(COORDS); - - return result; -} - -Vector2D SConstraint::getLogicConstraintPos() { - if (!constraint) - return {}; - - const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface); - - if (!PWINDOWOWNER) - return {}; - - if (!PWINDOWOWNER->m_bIsX11) - return PWINDOWOWNER->m_vRealPosition.goal(); - - const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goal() : - g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y}); - - return COORDS; -} - -Vector2D SConstraint::getLogicConstraintSize() { - if (!constraint) - return {}; - - const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface); - - if (!PWINDOWOWNER) - return {}; - - if (!PWINDOWOWNER->m_bIsX11) - return PWINDOWOWNER->m_vRealSize.goal(); - - const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? - g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : - g_pCompositor->getMonitorFromVector(g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y})); - - if (!PMONITOR) - return {}; - - const auto SIZE = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealSize.goal() : - Vector2D{PWINDOWOWNER->m_uSurface.xwayland->width, PWINDOWOWNER->m_uSurface.xwayland->height} * PMONITOR->xwaylandScale; - - return SIZE; -} - void SKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { xkb_state_unref(xkbTranslationState); diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index b1c6c9d7..5fc2692a 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -157,20 +157,14 @@ struct SKeyboard { }; struct SMouse { - wlr_input_device* mouse = nullptr; + wlr_input_device* mouse = nullptr; - wlr_pointer_constraint_v1* currentConstraint = nullptr; - bool constraintActive = false; + std::string name = ""; - CRegion confinedTo; + bool virt = false; - std::string name = ""; + bool connected = false; // means connected to the cursor - bool virt = false; - - bool connected = false; // means connected to the cursor - - DYNLISTENER(commitConstraint); DYNLISTENER(destroyMouse); bool operator==(const SMouse& b) const { @@ -178,29 +172,6 @@ struct SMouse { } }; -struct SConstraint { - SMouse* pMouse = nullptr; - wlr_pointer_constraint_v1* constraint = nullptr; - - bool active = false; - - bool hintSet = false; - Vector2D positionHint = {-1, -1}; // the position hint, but will use cursorPosOnActivate if unset - Vector2D cursorPosOnActivate = {-1, -1}; - - DYNLISTENER(setConstraintRegion); - DYNLISTENER(destroyConstraint); - - CRegion getLogicCoordsRegion(); - Vector2D getLogicConstraintPos(); - Vector2D getLogicConstraintSize(); - - // - bool operator==(const SConstraint& b) const { - return constraint == b.constraint; - } -}; - class CMonitor; struct SSeat { diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 989d863a..c634037c 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -4,7 +4,7 @@ #include CInputManager::~CInputManager() { - m_lConstraints.clear(); + m_vConstraints.clear(); m_lKeyboards.clear(); m_lMice.clear(); m_lTablets.clear(); @@ -56,7 +56,7 @@ void CInputManager::simulateMouseMovement() { } void CInputManager::sendMotionEventsToFocused() { - if (!g_pCompositor->m_pLastFocus) + if (!g_pCompositor->m_pLastFocus || isConstrained()) return; // todo: this sucks ass @@ -139,56 +139,27 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } // constraints - // All constraints TODO: multiple mice? - if (g_pCompositor->m_sSeat.mouse && g_pCompositor->m_sSeat.mouse->currentConstraint && !g_pCompositor->m_sSeat.exclusiveClient && !g_pSessionLockManager->isSessionLocked()) { - // XWayland windows sometimes issue constraints weirdly. - // TODO: We probably should search their parent. wlr_xwayland_surface->parent - const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse); - const auto PCONSTRAINT = constraintFromWlr(g_pCompositor->m_sSeat.mouse->currentConstraint); + if (g_pCompositor->m_sSeat.mouse && isConstrained()) { + const auto SURF = CWLSurface::surfaceFromWlr(g_pCompositor->m_pLastFocus); + const auto CONSTRAINT = SURF->constraint(); - if (!CONSTRAINTWINDOW || !PCONSTRAINT) { - unconstrainMouse(); - } else { - // Native Wayland apps know how 2 constrain themselves. - // XWayland, we just have to accept them. Might cause issues, but thats XWayland for ya. - const auto CONSTRAINTPOS = PCONSTRAINT->getLogicConstraintPos(); - const auto CONSTRAINTSIZE = PCONSTRAINT->getLogicConstraintSize(); - - if (g_pCompositor->m_sSeat.mouse->currentConstraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) { - // we just snap the cursor to where it should be. - - if (PCONSTRAINT->hintSet) - wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, CONSTRAINTPOS.x + PCONSTRAINT->positionHint.x, - CONSTRAINTPOS.y + PCONSTRAINT->positionHint.y); - - return; // don't process anything else, the cursor is locked. The surface should not receive any further events. - // these are usually FPS games. They will use the relative motion. + if (SURF && CONSTRAINT) { + if (CONSTRAINT->isLocked()) { + const auto HINT = CONSTRAINT->logicPositionHint(); + wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, HINT.x, HINT.y); } else { - // we restrict the cursor to the confined region - const auto REGION = PCONSTRAINT->getLogicCoordsRegion(); + 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{}); - if (!REGION.containsPoint(mouseCoords)) { - if (g_pCompositor->m_sSeat.mouse->constraintActive) { - const auto CLOSEST = REGION.closestPoint(mouseCoords); - wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, NULL, CLOSEST.x, CLOSEST.y); - mouseCoords = getMouseCoordsInternal(); - } - } else { - if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) { - g_pCompositor->m_sSeat.mouse->constraintActive = true; - } - } + wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, CLOSEST.x, CLOSEST.y); } - if (CONSTRAINTWINDOW->m_bIsX11) { - foundSurface = CONSTRAINTWINDOW->m_pWLSurface.wlr(); - surfacePos = CONSTRAINTWINDOW->m_vRealPosition.value(); - } else { - g_pCompositor->vectorWindowToSurface(mouseCoords, CONSTRAINTWINDOW, surfaceCoords); - } + return; - pFoundWindow = CONSTRAINTWINDOW; - } + } else + Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF, (uintptr_t)CONSTRAINT); } // update stuff @@ -641,7 +612,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { if (**PFOLLOWMOUSE == 3) // don't refocus on full loose break; - if ((!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) /* No constraints */ + if ((!g_pCompositor->m_sSeat.mouse || !isConstrained()) /* No constraints */ && (w && g_pCompositor->m_pLastWindow != w) /* window should change */) { // a bit hacky // if we only pressed one button, allow us to refocus. m_lCurrentlyHeldButtons.size() > 0 will stick the focus @@ -1278,133 +1249,27 @@ void CInputManager::updateDragIcon() { } } -void CInputManager::recheckConstraint(SMouse* pMouse) { - if (!pMouse->currentConstraint) - return; - - const auto PREGION = &pMouse->currentConstraint->region; - - if (pMouse->currentConstraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) - pMouse->confinedTo.set(PREGION); - else - pMouse->confinedTo.clear(); -} - -void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* constraint) { - - if (pMouse->currentConstraint == constraint) - return; - - const auto MOUSECOORDS = getMouseCoordsInternal(); - const auto PCONSTRAINT = constraintFromWlr(constraint); - - pMouse->hyprListener_commitConstraint.removeCallback(); - - if (pMouse->currentConstraint) - wlr_pointer_constraint_v1_send_deactivated(pMouse->currentConstraint); - - if (const auto PWINDOW = g_pCompositor->getWindowFromSurface(constraint->surface); PWINDOW) { - const auto RELATIVETO = PWINDOW->m_bIsX11 ? - (PWINDOW->m_bIsMapped ? PWINDOW->m_vRealPosition.goal() : - g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y})) : - PWINDOW->m_vRealPosition.goal(); - - PCONSTRAINT->cursorPosOnActivate = (MOUSECOORDS - RELATIVETO) * PWINDOW->m_fX11SurfaceScaledBy; - } - - if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) { - PCONSTRAINT->hintSet = true; - PCONSTRAINT->positionHint = {constraint->current.cursor_hint.x, constraint->current.cursor_hint.y}; - } - - if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT && constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) - warpMouseToConstraintMiddle(PCONSTRAINT); - - pMouse->currentConstraint = constraint; - pMouse->constraintActive = true; - - if (pixman_region32_not_empty(&constraint->current.region)) - pixman_region32_intersect(&constraint->region, &constraint->surface->input_region, &constraint->current.region); - else - pixman_region32_copy(&constraint->region, &constraint->surface->input_region); - - // warp to the constraint - recheckConstraint(pMouse); - - PCONSTRAINT->active = true; - - wlr_pointer_constraint_v1_send_activated(pMouse->currentConstraint); - - pMouse->hyprListener_commitConstraint.initCallback(&pMouse->currentConstraint->surface->events.commit, &Events::listener_commitConstraint, pMouse, "Mouse constraint commit"); - - Debug::log(LOG, "Constrained mouse to {:x}", (uintptr_t)pMouse->currentConstraint); -} - -void CInputManager::warpMouseToConstraintMiddle(SConstraint* pConstraint) { - - if (!pConstraint) - return; - - const auto PWINDOW = g_pCompositor->getWindowFromSurface(pConstraint->constraint->surface); - - if (PWINDOW) { - const auto RELATIVETO = pConstraint->getLogicConstraintPos(); - const auto HINTSCALE = PWINDOW->m_fX11SurfaceScaledBy; - - auto HINT = pConstraint->hintSet ? pConstraint->positionHint : pConstraint->cursorPosOnActivate; - - if (HINT == Vector2D{-1, -1}) - HINT = pConstraint->getLogicConstraintSize() / 2.f; - - if (HINT != Vector2D{-1, -1}) { - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, RELATIVETO.x + HINT.x / HINTSCALE, RELATIVETO.y + HINT.y / HINTSCALE); - wlr_seat_pointer_warp(pConstraint->constraint->seat, pConstraint->constraint->current.cursor_hint.x, pConstraint->constraint->current.cursor_hint.y); - } - } -} - void CInputManager::unconstrainMouse() { - if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) + if (!g_pCompositor->m_sSeat.mouse) return; - const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse); + for (auto& c : m_vConstraints) { + if (!c->active()) + continue; - if (CONSTRAINTWINDOW) - g_pXWaylandManager->activateSurface(CONSTRAINTWINDOW->m_pWLSurface.wlr(), false); - - wlr_pointer_constraint_v1_send_deactivated(g_pCompositor->m_sSeat.mouse->currentConstraint); - - const auto PCONSTRAINT = constraintFromWlr(g_pCompositor->m_sSeat.mouse->currentConstraint); - if (PCONSTRAINT) - PCONSTRAINT->active = false; - - g_pCompositor->m_sSeat.mouse->constraintActive = false; - - // TODO: its better to somehow detect the workspace... - g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr; - - g_pCompositor->m_sSeat.mouse->hyprListener_commitConstraint.removeCallback(); + c->deactivate(); + } } -void Events::listener_commitConstraint(void* owner, void* data) { - const auto PMOUSE = (SMouse*)owner; +bool CInputManager::isConstrained() { + for (auto& c : m_vConstraints) { + if (!c->active() || c->owner()->wlr() != g_pCompositor->m_pLastFocus) + continue; - if (PMOUSE->currentConstraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) { - const auto PCONSTRAINT = g_pInputManager->constraintFromWlr(PMOUSE->currentConstraint); - if (PCONSTRAINT) { // should never be null but who knows - PCONSTRAINT->positionHint = Vector2D(PMOUSE->currentConstraint->current.cursor_hint.x, PMOUSE->currentConstraint->current.cursor_hint.y); - PCONSTRAINT->hintSet = true; - } + return true; } - if (PMOUSE->currentConstraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_REGION) { - if (pixman_region32_not_empty(&PMOUSE->currentConstraint->current.region)) - pixman_region32_intersect(&PMOUSE->currentConstraint->region, &PMOUSE->currentConstraint->surface->input_region, &PMOUSE->currentConstraint->current.region); - else - pixman_region32_copy(&PMOUSE->currentConstraint->region, &PMOUSE->currentConstraint->surface->input_region); - - g_pInputManager->recheckConstraint(PMOUSE); - } + return false; } void CInputManager::updateCapabilities() { @@ -1670,15 +1535,6 @@ std::string CInputManager::getNameForNewDevice(std::string internalName) { return proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); } -SConstraint* CInputManager::constraintFromWlr(wlr_pointer_constraint_v1* constraint) { - for (auto& c : m_lConstraints) { - if (c.constraint == constraint) - return &c; - } - - return nullptr; -} - void CInputManager::releaseAllMouseButtons() { const auto buttonsCopy = m_lCurrentlyHeldButtons; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index e32e27f8..cef8386f 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -7,6 +7,8 @@ #include "../../helpers/Timer.hpp" #include "InputMethodRelay.hpp" +class CConstraint; + enum eClickBehaviorMode { CLICKMODE_DEFAULT = 0, CLICKMODE_KILL @@ -80,11 +82,8 @@ class CInputManager { void destroyMouse(wlr_input_device*); void destroySwitch(SSwitchDevice*); - void constrainMouse(SMouse*, wlr_pointer_constraint_v1*); - void warpMouseToConstraintMiddle(SConstraint*); - void recheckConstraint(SMouse*); void unconstrainMouse(); - SConstraint* constraintFromWlr(wlr_pointer_constraint_v1*); + bool isConstrained(); std::string getActiveLayoutForKeyboard(SKeyboard*); Vector2D getMouseCoordsInternal(); @@ -120,13 +119,12 @@ class CInputManager { bool m_bWasDraggingWindow = false; // for refocus to be forced - CWindow* m_pForcedFocus = nullptr; + CWindow* m_pForcedFocus = nullptr; - SDrag m_sDrag; + SDrag m_sDrag; - std::list m_lConstraints; - std::list m_lKeyboards; - std::list m_lMice; + std::list m_lKeyboards; + std::list m_lMice; // tablets std::list m_lTablets; @@ -145,25 +143,28 @@ class CInputManager { // Exclusive layer surfaces std::deque m_dExclusiveLSes; - void newTabletTool(wlr_input_device*); - void newTabletPad(wlr_input_device*); - void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false); - void newIdleInhibitor(wlr_idle_inhibitor_v1*); - void recheckIdleInhibitorStatus(); + // constraints + std::vector m_vConstraints; - void onSwipeBegin(wlr_pointer_swipe_begin_event*); - void onSwipeEnd(wlr_pointer_swipe_end_event*); - void onSwipeUpdate(wlr_pointer_swipe_update_event*); + void newTabletTool(wlr_input_device*); + void newTabletPad(wlr_input_device*); + void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false); + void newIdleInhibitor(wlr_idle_inhibitor_v1*); + void recheckIdleInhibitorStatus(); - SSwipeGesture m_sActiveSwipe; + void onSwipeBegin(wlr_pointer_swipe_begin_event*); + void onSwipeEnd(wlr_pointer_swipe_end_event*); + void onSwipeUpdate(wlr_pointer_swipe_update_event*); - SKeyboard* m_pActiveKeyboard = nullptr; + SSwipeGesture m_sActiveSwipe; - CTimer m_tmrLastCursorMovement; + SKeyboard* m_pActiveKeyboard = nullptr; - CInputMethodRelay m_sIMERelay; + CTimer m_tmrLastCursorMovement; - void updateKeyboardsLeds(wlr_input_device* pKeyboard); + CInputMethodRelay m_sIMERelay; + + void updateKeyboardsLeds(wlr_input_device* pKeyboard); // for shared mods uint32_t accumulateModsFromAllKBs();