mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-09 16:05:58 +01:00
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
This commit is contained in:
parent
328ab43165
commit
d72ea5f2a7
14 changed files with 282 additions and 386 deletions
|
@ -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<wlr_surface*, bool> 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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
121
src/desktop/Constraint.cpp
Normal file
121
src/desktop/Constraint.cpp
Normal file
|
@ -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;
|
||||
}
|
44
src/desktop/Constraint.hpp
Normal file
44
src/desktop/Constraint.hpp
Normal file
|
@ -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();
|
||||
};
|
|
@ -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<CBox> CWLSurface::getSurfaceBoxGlobal() {
|
|||
|
||||
return {};
|
||||
}
|
||||
|
||||
void CWLSurface::appendConstraint(wlr_pointer_constraint_v1* constraint) {
|
||||
m_pConstraint = std::make_unique<CConstraint>(constraint, this);
|
||||
}
|
||||
|
||||
void CWLSurface::onCommit() {
|
||||
if (m_pConstraint)
|
||||
m_pConstraint->onCommit();
|
||||
}
|
||||
|
||||
CConstraint* CWLSurface::constraint() {
|
||||
return m_pConstraint.get();
|
||||
}
|
||||
|
|
|
@ -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<CBox> 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;
|
||||
|
||||
//
|
||||
std::unique_ptr<CConstraint> m_pConstraint;
|
||||
|
||||
void destroy();
|
||||
void init();
|
||||
bool desktopComponent();
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(commit);
|
||||
|
||||
friend class CConstraint;
|
||||
};
|
|
@ -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};
|
||||
}
|
||||
if (!SURFACE) {
|
||||
Debug::log(ERR, "Refusing a constraint from an unassigned wl_surface {:x}", (uintptr_t)PCONSTRAINT->surface);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -65,10 +65,7 @@ namespace Events {
|
|||
DYNLISTENFUNC(keyboardMod);
|
||||
DYNLISTENFUNC(keyboardDestroy);
|
||||
|
||||
DYNLISTENFUNC(commitConstraint);
|
||||
LISTENER(newConstraint);
|
||||
DYNLISTENFUNC(setConstraintRegion);
|
||||
DYNLISTENFUNC(destroyConstraint);
|
||||
|
||||
// Various
|
||||
LISTENER(requestMouse);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -159,18 +159,12 @@ struct SKeyboard {
|
|||
struct SMouse {
|
||||
wlr_input_device* mouse = nullptr;
|
||||
|
||||
wlr_pointer_constraint_v1* currentConstraint = nullptr;
|
||||
bool constraintActive = false;
|
||||
|
||||
CRegion confinedTo;
|
||||
|
||||
std::string name = "";
|
||||
|
||||
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 {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <ranges>
|
||||
|
||||
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();
|
||||
if (SURF && CONSTRAINT) {
|
||||
if (CONSTRAINT->isLocked()) {
|
||||
const auto HINT = CONSTRAINT->logicPositionHint();
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, HINT.x, HINT.y);
|
||||
} 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();
|
||||
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 (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.
|
||||
} else {
|
||||
// we restrict the cursor to the confined region
|
||||
const auto REGION = PCONSTRAINT->getLogicCoordsRegion();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void Events::listener_commitConstraint(void* owner, void* data) {
|
||||
const auto PMOUSE = (SMouse*)owner;
|
||||
|
||||
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;
|
||||
c->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
bool CInputManager::isConstrained() {
|
||||
for (auto& c : m_vConstraints) {
|
||||
if (!c->active() || c->owner()->wlr() != g_pCompositor->m_pLastFocus)
|
||||
continue;
|
||||
|
||||
g_pInputManager->recheckConstraint(PMOUSE);
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
@ -124,7 +123,6 @@ class CInputManager {
|
|||
|
||||
SDrag m_sDrag;
|
||||
|
||||
std::list<SConstraint> m_lConstraints;
|
||||
std::list<SKeyboard> m_lKeyboards;
|
||||
std::list<SMouse> m_lMice;
|
||||
|
||||
|
@ -145,6 +143,9 @@ class CInputManager {
|
|||
// Exclusive layer surfaces
|
||||
std::deque<SLayerSurface*> m_dExclusiveLSes;
|
||||
|
||||
// constraints
|
||||
std::vector<CConstraint*> m_vConstraints;
|
||||
|
||||
void newTabletTool(wlr_input_device*);
|
||||
void newTabletPad(wlr_input_device*);
|
||||
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
|
||||
|
|
Loading…
Reference in a new issue