summaryrefslogtreecommitdiff
path: root/src/managers
diff options
context:
space:
mode:
authorVaxry <vaxry@vaxry.net>2024-05-11 01:02:57 +0100
committerVaxry <vaxry@vaxry.net>2024-05-14 23:13:33 +0100
commitfc72df8e58bc127442a245f2f29a3246acf77cce (patch)
treebe68c03888760af0c2a13bad4aed224fd6adfaa3 /src/managers
parent0cfdde3d1acbfbf698af17f6986fbc4d644214da (diff)
seatmgr: Add a grab class
Diffstat (limited to 'src/managers')
-rw-r--r--src/managers/SeatManager.cpp73
-rw-r--r--src/managers/SeatManager.hpp37
-rw-r--r--src/managers/input/InputManager.cpp26
-rw-r--r--src/managers/input/InputManager.hpp6
4 files changed, 140 insertions, 2 deletions
diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp
index f9d394b5..d962dd84 100644
--- a/src/managers/SeatManager.cpp
+++ b/src/managers/SeatManager.cpp
@@ -371,6 +371,40 @@ void CSeatManager::sendTouchOrientation(int32_t id, double angle) {
}
}
+void CSeatManager::refocusGrab() {
+ if (!seatGrab)
+ return;
+
+ if (seatGrab->surfs.size() > 0) {
+ // try to find a surf in focus first
+ const auto MOUSE = g_pInputManager->getMouseCoordsInternal();
+ for (auto& s : seatGrab->surfs) {
+ auto hlSurf = CWLSurface::surfaceFromWlr(s);
+ if (!hlSurf)
+ continue;
+
+ auto b = hlSurf->getSurfaceBoxGlobal();
+ if (!b.has_value())
+ continue;
+
+ if (!b->containsPoint(MOUSE))
+ continue;
+
+ if (seatGrab->keyboard)
+ setKeyboardFocus(s);
+ if (seatGrab->pointer)
+ setPointerFocus(s, MOUSE - b->pos());
+ return;
+ }
+
+ wlr_surface* surf = seatGrab->surfs.at(0);
+ if (seatGrab->keyboard)
+ setKeyboardFocus(surf);
+ if (seatGrab->pointer)
+ setPointerFocus(surf, {});
+ }
+}
+
void CSeatManager::onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot) {
if (!state.pointerFocusResource || !seatResource || seatResource->client() != state.pointerFocusResource->client()) {
Debug::log(LOG, "[seatmgr] Rejecting a setCursor because the client ain't in focus");
@@ -389,3 +423,42 @@ void CSeatManager::onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial
SP<CWLSeatResource> CSeatManager::seatResourceForClient(wl_client* client) {
return PROTO::seat->seatResourceForClient(client);
}
+
+void CSeatManager::setGrab(SP<CSeatGrab> grab) {
+ if (seatGrab) {
+ auto oldGrab = seatGrab;
+ seatGrab.reset();
+ g_pInputManager->refocus();
+ if (oldGrab->onEnd)
+ oldGrab->onEnd();
+ }
+
+ if (!grab)
+ return;
+
+ seatGrab = grab;
+
+ refocusGrab();
+}
+
+bool CSeatGrab::accepts(wlr_surface* surf) {
+ return std::find(surfs.begin(), surfs.end(), surf) != surfs.end();
+}
+
+void CSeatGrab::add(wlr_surface* surf) {
+ surfs.push_back(surf);
+}
+
+void CSeatGrab::remove(wlr_surface* surf) {
+ std::erase(surfs, surf);
+ if ((keyboard && g_pSeatManager->state.keyboardFocus == surf) || (pointer && g_pSeatManager->state.pointerFocus == surf))
+ g_pSeatManager->refocusGrab();
+}
+
+void CSeatGrab::setCallback(std::function<void()> onEnd_) {
+ onEnd = onEnd_;
+}
+
+void CSeatGrab::clear() {
+ surfs.clear();
+}
diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp
index ef114024..16f11ffd 100644
--- a/src/managers/SeatManager.hpp
+++ b/src/managers/SeatManager.hpp
@@ -14,6 +14,37 @@ class CWLSeatResource;
class IPointer;
class IKeyboard;
+/*
+ A seat grab defines a restricted set of surfaces that can be focused.
+ Only one grab can be active at a time
+
+ when a grab is removed, refocus() will happen
+
+ Different from a constraint.
+
+ When first set with setGrab, SeatManager will try to find a surface that is at the mouse pointer to focus,
+ from first added to last added. If none are, first is focused.
+*/
+class CSeatGrab {
+ public:
+ bool accepts(wlr_surface* surf);
+ void add(wlr_surface* surf);
+ void remove(wlr_surface* surf);
+ void setCallback(std::function<void()> onEnd_);
+ void clear();
+
+ bool keyboard = false;
+ bool pointer = false;
+ bool touch = false;
+
+ bool removeOnInput = true; // on hard input e.g. click outside, remove
+
+ private:
+ std::vector<wlr_surface*> surfs; // read-only
+ std::function<void()> onEnd;
+ friend class CSeatManager;
+};
+
class CSeatManager {
public:
CSeatManager();
@@ -76,6 +107,9 @@ class CSeatManager {
WP<IPointer> mouse;
WP<IKeyboard> keyboard;
+ void setGrab(SP<CSeatGrab> grab); // nullptr removes
+ SP<CSeatGrab> seatGrab;
+
private:
struct SSeatResourceContainer {
SSeatResourceContainer(SP<CWLSeatResource>);
@@ -92,6 +126,8 @@ class CSeatManager {
void onNewSeatResource(SP<CWLSeatResource> resource);
SP<SSeatResourceContainer> containerForResource(SP<CWLSeatResource> seatResource);
+ void refocusGrab();
+
struct {
CHyprSignalListener newSeatResource;
} listeners;
@@ -101,6 +137,7 @@ class CSeatManager {
DYNLISTENER(touchSurfaceDestroy);
friend struct SSeatResourceContainer;
+ friend class CSeatGrab;
};
inline UP<CSeatManager> g_pSeatManager;
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index bb0ab65a..fe19c98f 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -358,6 +358,26 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0)
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get());
+ // grabs
+ if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(foundSurface)) {
+ if (m_bHardInput || refocus) {
+ g_pSeatManager->setGrab(nullptr);
+ return; // setGrab will refocus
+ } else {
+ // we need to grab the last surface.
+ foundSurface = g_pSeatManager->state.pointerFocus;
+
+ auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface);
+
+ if (HLSurface) {
+ const auto BOX = HLSurface->getSurfaceBoxGlobal();
+
+ if (BOX.has_value())
+ surfacePos = BOX->pos();
+ }
+ }
+ }
+
if (!foundSurface) {
if (!m_bEmptyFocusCursorSet) {
if (*PRESIZEONBORDER && *PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) {
@@ -678,6 +698,12 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) {
if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor.get() && PMON)
g_pCompositor->setActiveMonitor(PMON);
+
+ if (g_pSeatManager->seatGrab && e.state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ m_bHardInput = true;
+ simulateMouseMovement();
+ m_bHardInput = false;
+ }
}
void CInputManager::processMouseDownKill(const IPointer::SButtonEvent& e) {
diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp
index 42c9d3da..85efecb8 100644
--- a/src/managers/input/InputManager.hpp
+++ b/src/managers/input/InputManager.hpp
@@ -188,10 +188,12 @@ class CInputManager {
void releaseAllMouseButtons();
// for some bugs in follow mouse 0
- bool m_bLastFocusOnLS = false;
-
+ bool m_bLastFocusOnLS = false;
bool m_bLastFocusOnIMEPopup = false;
+ // for hard input e.g. clicks
+ bool m_bHardInput = false;
+
// for hiding cursor on touch
bool m_bLastInputTouch = false;