mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-17 21:13:48 -07:00
seatmgr: Add a grab class
This commit is contained in:
@@ -7,119 +7,7 @@
|
||||
#include <memory>
|
||||
#include <wayland-server.h>
|
||||
|
||||
// static void focus_grab_pointer_enter(wlr_seat_pointer_grab* grab, wlr_surface* surface, double sx, double sy) {
|
||||
// if (static_cast<CFocusGrab*>(grab->data)->isSurfaceComitted(surface))
|
||||
// wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
|
||||
// else
|
||||
// wlr_seat_pointer_clear_focus(grab->seat);
|
||||
// }
|
||||
|
||||
// static void focus_grab_pointer_clear_focus(wlr_seat_pointer_grab* grab) {
|
||||
// wlr_seat_pointer_clear_focus(grab->seat);
|
||||
// }
|
||||
|
||||
// static void focus_grab_pointer_motion(wlr_seat_pointer_grab* grab, uint32_t time, double sx, double sy) {
|
||||
// wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
|
||||
// }
|
||||
|
||||
// static uint32_t focus_grab_pointer_button(wlr_seat_pointer_grab* grab, uint32_t time, uint32_t button, wl_pointer_button_state state) {
|
||||
// uint32_t serial = wlr_seat_pointer_send_button(grab->seat, time, button, state);
|
||||
|
||||
// if (serial)
|
||||
// return serial;
|
||||
// else {
|
||||
// static_cast<CFocusGrab*>(grab->data)->finish(true);
|
||||
// return 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
// static void focus_grab_pointer_axis(wlr_seat_pointer_grab* grab, uint32_t time, enum wl_pointer_axis orientation, double value, int32_t value_discrete,
|
||||
// enum wl_pointer_axis_source source, enum wl_pointer_axis_relative_direction relative_direction) {
|
||||
// wlr_seat_pointer_send_axis(grab->seat, time, orientation, value, value_discrete, source, relative_direction);
|
||||
// }
|
||||
|
||||
// static void focus_grab_pointer_frame(wlr_seat_pointer_grab* grab) {
|
||||
// wlr_seat_pointer_send_frame(grab->seat);
|
||||
// }
|
||||
|
||||
// static void focus_grab_pointer_cancel(wlr_seat_pointer_grab* grab) {
|
||||
// static_cast<CFocusGrab*>(grab->data)->finish(true);
|
||||
// }
|
||||
|
||||
// static const wlr_pointer_grab_interface focus_grab_pointer_impl = {
|
||||
// .enter = focus_grab_pointer_enter,
|
||||
// .clear_focus = focus_grab_pointer_clear_focus,
|
||||
// .motion = focus_grab_pointer_motion,
|
||||
// .button = focus_grab_pointer_button,
|
||||
// .axis = focus_grab_pointer_axis,
|
||||
// .frame = focus_grab_pointer_frame,
|
||||
// .cancel = focus_grab_pointer_cancel,
|
||||
// };
|
||||
|
||||
// static void focus_grab_keyboard_enter(wlr_seat_keyboard_grab* grab, wlr_surface* surface, const uint32_t keycodes[], size_t num_keycodes, const wlr_keyboard_modifiers* modifiers) {
|
||||
// if (static_cast<CFocusGrab*>(grab->data)->isSurfaceComitted(surface))
|
||||
// wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers);
|
||||
|
||||
// // otherwise the last grabbed window should retain keyboard focus.
|
||||
// }
|
||||
|
||||
// static void focus_grab_keyboard_clear_focus(wlr_seat_keyboard_grab* grab) {
|
||||
// static_cast<CFocusGrab*>(grab->data)->finish(true);
|
||||
// }
|
||||
|
||||
// static void focus_grab_keyboard_key(wlr_seat_keyboard_grab* grab, uint32_t time, uint32_t key, uint32_t state) {
|
||||
// wlr_seat_keyboard_send_key(grab->seat, time, key, state);
|
||||
// }
|
||||
|
||||
// static void focus_grab_keyboard_modifiers(wlr_seat_keyboard_grab* grab, const wlr_keyboard_modifiers* modifiers) {
|
||||
// wlr_seat_keyboard_send_modifiers(grab->seat, modifiers);
|
||||
// }
|
||||
|
||||
// static void focus_grab_keyboard_cancel(wlr_seat_keyboard_grab* grab) {
|
||||
// static_cast<CFocusGrab*>(grab->data)->finish(true);
|
||||
// }
|
||||
|
||||
// static const wlr_keyboard_grab_interface focus_grab_keyboard_impl = {
|
||||
// .enter = focus_grab_keyboard_enter,
|
||||
// .clear_focus = focus_grab_keyboard_clear_focus,
|
||||
// .key = focus_grab_keyboard_key,
|
||||
// .modifiers = focus_grab_keyboard_modifiers,
|
||||
// .cancel = focus_grab_keyboard_cancel,
|
||||
// };
|
||||
|
||||
// static uint32_t focus_grab_touch_down(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) {
|
||||
// if (!static_cast<CFocusGrab*>(grab->data)->isSurfaceComitted(point->surface))
|
||||
// return 0;
|
||||
|
||||
// return wlr_seat_touch_send_down(grab->seat, point->surface, time, point->touch_id, point->sx, point->sy);
|
||||
// }
|
||||
|
||||
// static void focus_grab_touch_up(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) {
|
||||
// wlr_seat_touch_send_up(grab->seat, time, point->touch_id);
|
||||
// }
|
||||
|
||||
// static void focus_grab_touch_motion(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) {
|
||||
// wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx, point->sy);
|
||||
// }
|
||||
|
||||
// static void focus_grab_touch_enter(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) {}
|
||||
|
||||
// static void focus_grab_touch_frame(wlr_seat_touch_grab* grab) {
|
||||
// wlr_seat_touch_send_frame(grab->seat);
|
||||
// }
|
||||
|
||||
// static void focus_grab_touch_cancel(wlr_seat_touch_grab* grab) {
|
||||
// static_cast<CFocusGrab*>(grab->data)->finish(true);
|
||||
// }
|
||||
|
||||
// static const wlr_touch_grab_interface focus_grab_touch_impl = {
|
||||
// .down = focus_grab_touch_down,
|
||||
// .up = focus_grab_touch_up,
|
||||
// .motion = focus_grab_touch_motion,
|
||||
// .enter = focus_grab_touch_enter,
|
||||
// .frame = focus_grab_touch_frame,
|
||||
// .cancel = focus_grab_touch_cancel,
|
||||
// };
|
||||
#define LOGM PROTO::focusGrab->protoLog
|
||||
|
||||
CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface) {
|
||||
hyprListener_surfaceDestroy.initCallback(
|
||||
@@ -134,14 +22,10 @@ CFocusGrab::CFocusGrab(SP<CHyprlandFocusGrabV1> resource_) : resource(resource_)
|
||||
if (!resource->resource())
|
||||
return;
|
||||
|
||||
// m_sPointerGrab.interface = &focus_grab_pointer_impl;
|
||||
// m_sPointerGrab.data = this;
|
||||
|
||||
// m_sKeyboardGrab.interface = &focus_grab_keyboard_impl;
|
||||
// m_sKeyboardGrab.data = this;
|
||||
|
||||
// m_sTouchGrab.interface = &focus_grab_touch_impl;
|
||||
// m_sTouchGrab.data = this;
|
||||
grab = makeShared<CSeatGrab>();
|
||||
grab->keyboard = true;
|
||||
grab->pointer = true;
|
||||
grab->setCallback([this]() { finish(true); });
|
||||
|
||||
resource->setDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); });
|
||||
resource->setOnDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); });
|
||||
@@ -168,21 +52,8 @@ bool CFocusGrab::isSurfaceComitted(wlr_surface* surface) {
|
||||
|
||||
void CFocusGrab::start() {
|
||||
if (!m_bGrabActive) {
|
||||
// wlr_seat_pointer_start_grab(g_pCompositor->m_sSeat.seat, &m_sPointerGrab);
|
||||
// wlr_seat_keyboard_start_grab(g_pCompositor->m_sSeat.seat, &m_sKeyboardGrab);
|
||||
// wlr_seat_touch_start_grab(g_pCompositor->m_sSeat.seat, &m_sTouchGrab);
|
||||
m_bGrabActive = true;
|
||||
|
||||
// Ensure the grab ends if another grab begins, including from xdg_popup::grab.
|
||||
|
||||
// hyprListener_pointerGrabStarted.initCallback(
|
||||
// &g_pCompositor->m_sSeat.seat->events.pointer_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab");
|
||||
|
||||
// hyprListener_keyboardGrabStarted.initCallback(
|
||||
// &g_pCompositor->m_sSeat.seat->events.keyboard_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab");
|
||||
|
||||
// hyprListener_touchGrabStarted.initCallback(
|
||||
// &g_pCompositor->m_sSeat.seat->events.touch_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab");
|
||||
g_pSeatManager->setGrab(grab);
|
||||
}
|
||||
|
||||
// Ensure new surfaces are focused if under the mouse when comitted.
|
||||
@@ -193,59 +64,39 @@ void CFocusGrab::start() {
|
||||
void CFocusGrab::finish(bool sendCleared) {
|
||||
if (m_bGrabActive) {
|
||||
m_bGrabActive = false;
|
||||
// hyprListener_pointerGrabStarted.removeCallback();
|
||||
// hyprListener_keyboardGrabStarted.removeCallback();
|
||||
// hyprListener_touchGrabStarted.removeCallback();
|
||||
|
||||
// Only clear grabs that belong to this focus grab. When superseded by another grab
|
||||
// or xdg_popup grab we might not own the current grab.
|
||||
|
||||
bool hadGrab = false;
|
||||
// if (g_pCompositor->m_sSeat.seat->pointer_state.grab == &m_sPointerGrab) {
|
||||
// wlr_seat_pointer_end_grab(g_pCompositor->m_sSeat.seat);
|
||||
// hadGrab = true;
|
||||
// }
|
||||
|
||||
// if (g_pCompositor->m_sSeat.seat->keyboard_state.grab == &m_sKeyboardGrab) {
|
||||
// wlr_seat_keyboard_end_grab(g_pCompositor->m_sSeat.seat);
|
||||
// hadGrab = true;
|
||||
// }
|
||||
|
||||
// if (g_pCompositor->m_sSeat.seat->touch_state.grab == &m_sTouchGrab) {
|
||||
// wlr_seat_touch_end_grab(g_pCompositor->m_sSeat.seat);
|
||||
// hadGrab = true;
|
||||
// }
|
||||
if (g_pSeatManager->seatGrab == grab) {
|
||||
g_pSeatManager->setGrab(nullptr);
|
||||
}
|
||||
|
||||
grab->clear();
|
||||
m_mSurfaces.clear();
|
||||
|
||||
if (sendCleared)
|
||||
resource->sendCleared();
|
||||
|
||||
// Ensure surfaces under the mouse when the grab ends get focus.
|
||||
if (hadGrab)
|
||||
g_pInputManager->refocus();
|
||||
}
|
||||
}
|
||||
|
||||
void CFocusGrab::addSurface(wlr_surface* surface) {
|
||||
auto iter = m_mSurfaces.find(surface);
|
||||
if (iter == m_mSurfaces.end())
|
||||
if (iter == m_mSurfaces.end()) {
|
||||
m_mSurfaces.emplace(surface, std::make_unique<CFocusGrabSurfaceState>(this, surface));
|
||||
}
|
||||
}
|
||||
|
||||
void CFocusGrab::removeSurface(wlr_surface* surface) {
|
||||
auto iter = m_mSurfaces.find(surface);
|
||||
if (iter != m_mSurfaces.end()) {
|
||||
if (iter->second->state == CFocusGrabSurfaceState::PendingAddition)
|
||||
if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) {
|
||||
m_mSurfaces.erase(iter);
|
||||
else
|
||||
} else
|
||||
iter->second->state = CFocusGrabSurfaceState::PendingRemoval;
|
||||
}
|
||||
}
|
||||
|
||||
void CFocusGrab::eraseSurface(wlr_surface* surface) {
|
||||
removeSurface(surface);
|
||||
commit();
|
||||
commit(true);
|
||||
}
|
||||
|
||||
void CFocusGrab::refocusKeyboard() {
|
||||
@@ -264,22 +115,26 @@ void CFocusGrab::refocusKeyboard() {
|
||||
if (surface)
|
||||
g_pCompositor->focusSurface(surface);
|
||||
else
|
||||
Debug::log(ERR, "CFocusGrab::refocusKeyboard called with no committed surfaces. This should never happen.");
|
||||
LOGM(ERR, "CFocusGrab::refocusKeyboard called with no committed surfaces. This should never happen.");
|
||||
}
|
||||
|
||||
void CFocusGrab::commit() {
|
||||
void CFocusGrab::commit(bool removeOnly) {
|
||||
auto surfacesChanged = false;
|
||||
auto anyComitted = false;
|
||||
for (auto iter = m_mSurfaces.begin(); iter != m_mSurfaces.end();) {
|
||||
switch (iter->second->state) {
|
||||
case CFocusGrabSurfaceState::PendingRemoval:
|
||||
grab->remove(iter->first);
|
||||
iter = m_mSurfaces.erase(iter);
|
||||
surfacesChanged = true;
|
||||
continue;
|
||||
case CFocusGrabSurfaceState::PendingAddition:
|
||||
iter->second->state = CFocusGrabSurfaceState::Comitted;
|
||||
surfacesChanged = true;
|
||||
anyComitted = true;
|
||||
if (!removeOnly) {
|
||||
iter->second->state = CFocusGrabSurfaceState::Comitted;
|
||||
grab->add(iter->first);
|
||||
surfacesChanged = true;
|
||||
anyComitted = true;
|
||||
}
|
||||
break;
|
||||
case CFocusGrabSurfaceState::Comitted: anyComitted = true; break;
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <vector>
|
||||
|
||||
class CFocusGrab;
|
||||
class CSeatGrab;
|
||||
|
||||
class CFocusGrabSurfaceState {
|
||||
public:
|
||||
@@ -40,14 +41,13 @@ class CFocusGrab {
|
||||
void removeSurface(wlr_surface* surface);
|
||||
void eraseSurface(wlr_surface* surface);
|
||||
void refocusKeyboard();
|
||||
void commit();
|
||||
void commit(bool removeOnly = false);
|
||||
|
||||
SP<CHyprlandFocusGrabV1> resource;
|
||||
std::unordered_map<wlr_surface*, UP<CFocusGrabSurfaceState>> m_mSurfaces;
|
||||
// wlr_seat_pointer_grab m_sPointerGrab;
|
||||
// wlr_seat_keyboard_grab m_sKeyboardGrab;
|
||||
// wlr_seat_touch_grab m_sTouchGrab;
|
||||
bool m_bGrabActive = false;
|
||||
SP<CSeatGrab> grab;
|
||||
|
||||
bool m_bGrabActive = false;
|
||||
|
||||
DYNLISTENER(pointerGrabStarted);
|
||||
DYNLISTENER(keyboardGrabStarted);
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#include "XDGShell.hpp"
|
||||
#include <algorithm>
|
||||
#include "../Compositor.hpp"
|
||||
#include "../managers/SeatManager.hpp"
|
||||
#include "core/Seat.hpp"
|
||||
|
||||
#define LOGM PROTO::xdgShell->protoLog
|
||||
|
||||
@@ -14,12 +16,14 @@ CXDGPopupResource::CXDGPopupResource(SP<CXdgPopup> resource_, SP<CXDGSurfaceReso
|
||||
resource->setDestroy([this](CXdgPopup* r) {
|
||||
if (surface && surface->mapped)
|
||||
surface->events.unmap.emit();
|
||||
PROTO::xdgShell->onPopupDestroy(self);
|
||||
events.destroy.emit();
|
||||
PROTO::xdgShell->destroyResource(this);
|
||||
});
|
||||
resource->setOnDestroy([this](CXdgPopup* r) {
|
||||
if (surface && surface->mapped)
|
||||
surface->events.unmap.emit();
|
||||
PROTO::xdgShell->onPopupDestroy(self);
|
||||
events.destroy.emit();
|
||||
PROTO::xdgShell->destroyResource(this);
|
||||
});
|
||||
@@ -34,11 +38,17 @@ CXDGPopupResource::CXDGPopupResource(SP<CXdgPopup> resource_, SP<CXDGSurfaceReso
|
||||
events.reposition.emit();
|
||||
});
|
||||
|
||||
resource->setGrab([this](CXdgPopup* r, wl_resource* seat, uint32_t serial) {
|
||||
LOGM(LOG, "xdg_popup {:x} requests grab", (uintptr_t)this);
|
||||
PROTO::xdgShell->addOrStartGrab(self.lock());
|
||||
});
|
||||
|
||||
if (parent)
|
||||
taken = true;
|
||||
}
|
||||
|
||||
CXDGPopupResource::~CXDGPopupResource() {
|
||||
PROTO::xdgShell->onPopupDestroy(self);
|
||||
events.destroy.emit();
|
||||
}
|
||||
|
||||
@@ -85,6 +95,7 @@ void CXDGPopupResource::configure(const CBox& box) {
|
||||
}
|
||||
|
||||
void CXDGPopupResource::done() {
|
||||
events.dismissed.emit();
|
||||
resource->sendPopupDone();
|
||||
}
|
||||
|
||||
@@ -659,7 +670,15 @@ wl_client* CXDGWMBase::client() {
|
||||
}
|
||||
|
||||
CXDGShellProtocol::CXDGShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||
;
|
||||
grab = makeShared<CSeatGrab>();
|
||||
grab->keyboard = true;
|
||||
grab->pointer = true;
|
||||
grab->setCallback([this]() {
|
||||
for (auto& g : grabbed) {
|
||||
g->done();
|
||||
}
|
||||
grabbed.clear();
|
||||
});
|
||||
}
|
||||
|
||||
void CXDGShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||
@@ -695,3 +714,39 @@ void CXDGShellProtocol::destroyResource(CXDGToplevelResource* resource) {
|
||||
void CXDGShellProtocol::destroyResource(CXDGPopupResource* resource) {
|
||||
std::erase_if(m_vPopups, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CXDGShellProtocol::addOrStartGrab(SP<CXDGPopupResource> popup) {
|
||||
if (!grabOwner) {
|
||||
grabOwner = popup;
|
||||
grabbed.clear();
|
||||
grab->clear();
|
||||
grab->add(popup->surface->surface);
|
||||
if (popup->parent)
|
||||
grab->add(popup->parent->surface);
|
||||
g_pSeatManager->setGrab(grab);
|
||||
grabbed.emplace_back(popup);
|
||||
return;
|
||||
}
|
||||
|
||||
grabbed.emplace_back(popup);
|
||||
|
||||
grab->add(popup->surface->surface);
|
||||
|
||||
if (popup->parent)
|
||||
grab->add(popup->parent->surface);
|
||||
}
|
||||
|
||||
void CXDGShellProtocol::onPopupDestroy(WP<CXDGPopupResource> popup) {
|
||||
if (popup == grabOwner) {
|
||||
g_pSeatManager->setGrab(nullptr);
|
||||
for (auto& g : grabbed) {
|
||||
g->done();
|
||||
}
|
||||
grabbed.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
std::erase(grabbed, popup);
|
||||
if (popup->surface)
|
||||
grab->remove(popup->surface->surface);
|
||||
}
|
||||
|
@@ -59,6 +59,7 @@ class CXDGPopupResource {
|
||||
|
||||
struct {
|
||||
CSignal reposition;
|
||||
CSignal dismissed;
|
||||
CSignal destroy; // only the role
|
||||
} events;
|
||||
|
||||
@@ -198,10 +199,10 @@ class CXDGPositionerResource {
|
||||
|
||||
bool good();
|
||||
|
||||
SXDGPositionerState state;
|
||||
SXDGPositionerState state;
|
||||
|
||||
WP<CXDGWMBase> owner;
|
||||
WP<CXDGPositionerResource> self;
|
||||
WP<CXDGWMBase> owner;
|
||||
WP<CXDGPositionerResource> self;
|
||||
|
||||
private:
|
||||
SP<CXdgPositioner> resource;
|
||||
@@ -244,6 +245,14 @@ class CXDGShellProtocol : public IWaylandProtocol {
|
||||
std::vector<SP<CXDGToplevelResource>> m_vToplevels;
|
||||
std::vector<SP<CXDGPopupResource>> m_vPopups;
|
||||
|
||||
// current popup grab
|
||||
WP<CXDGPopupResource> grabOwner;
|
||||
SP<CSeatGrab> grab;
|
||||
std::vector<WP<CXDGPopupResource>> grabbed;
|
||||
|
||||
void addOrStartGrab(SP<CXDGPopupResource> popup);
|
||||
void onPopupDestroy(WP<CXDGPopupResource> popup);
|
||||
|
||||
friend class CXDGWMBase;
|
||||
friend class CXDGPositionerResource;
|
||||
friend class CXDGSurfaceResource;
|
||||
|
Reference in New Issue
Block a user