diff options
| author | Vaxry <vaxry@vaxry.net> | 2024-05-11 01:02:57 +0100 |
|---|---|---|
| committer | Vaxry <vaxry@vaxry.net> | 2024-05-14 23:13:33 +0100 |
| commit | fc72df8e58bc127442a245f2f29a3246acf77cce (patch) | |
| tree | be68c03888760af0c2a13bad4aed224fd6adfaa3 /src/managers | |
| parent | 0cfdde3d1acbfbf698af17f6986fbc4d644214da (diff) | |
seatmgr: Add a grab class
Diffstat (limited to 'src/managers')
| -rw-r--r-- | src/managers/SeatManager.cpp | 73 | ||||
| -rw-r--r-- | src/managers/SeatManager.hpp | 37 | ||||
| -rw-r--r-- | src/managers/input/InputManager.cpp | 26 | ||||
| -rw-r--r-- | src/managers/input/InputManager.hpp | 6 |
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; |
