mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-26 04:45:58 +01:00
protocols: add hyprland_focus_grab_v1 implementation (#5850)
* protocols: add hyprland_focus_grab_v1 implementation
* protocols/focus_grab: fix keyboard focus staying on unlisted windows
When creating a focus grab with layershell surfaces, the last active
toplevel kept keyboard focus.
* protocols/focus_grab: fix formatting
* protocols/focus_grab: try to pick surface for keyboard focus
* focus_grab: update keyboard focus to match spec
* Revert "protocols/focus_grab: try to pick surface for keyboard focus"
This reverts commit 090358d0d1
.
* protocols/focus_grab: fix issues and match new spec
* kde-server-decoration: move to new impl
* protocols/focus_grab: review fixup
* Update hyprland-protocols
---------
Co-authored-by: Vaxry <vaxry@vaxry.net>
This commit is contained in:
parent
62eadad20f
commit
aaf35b9f1f
7 changed files with 410 additions and 4 deletions
|
@ -266,6 +266,7 @@ protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer
|
||||||
protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true)
|
protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true)
|
||||||
protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true)
|
protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true)
|
||||||
protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true)
|
protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true)
|
||||||
|
protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-v1" true)
|
||||||
protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false)
|
protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false)
|
||||||
protocolNew("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
|
protocolNew("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
|
||||||
protocolNew("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false)
|
protocolNew("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false)
|
||||||
|
|
|
@ -36,11 +36,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1691753796,
|
"lastModified": 1714869498,
|
||||||
"narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=",
|
"narHash": "sha256-vbLVOWvQqo4n1yvkg/Q70VTlPbMmTiCQfNTgcWDCfJM=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprland-protocols",
|
"repo": "hyprland-protocols",
|
||||||
"rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03",
|
"rev": "e06482e0e611130cd1929f75e8c1cf679e57d161",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -43,6 +43,7 @@ new_protocols = [
|
||||||
['wlr-virtual-pointer-unstable-v1.xml'],
|
['wlr-virtual-pointer-unstable-v1.xml'],
|
||||||
['wlr-output-management-unstable-v1.xml'],
|
['wlr-output-management-unstable-v1.xml'],
|
||||||
['kde-server-decoration.xml'],
|
['kde-server-decoration.xml'],
|
||||||
|
[hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'],
|
||||||
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
|
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
|
||||||
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
|
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
|
||||||
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "../protocols/VirtualPointer.hpp"
|
#include "../protocols/VirtualPointer.hpp"
|
||||||
#include "../protocols/OutputManagement.hpp"
|
#include "../protocols/OutputManagement.hpp"
|
||||||
#include "../protocols/ServerDecorationKDE.hpp"
|
#include "../protocols/ServerDecorationKDE.hpp"
|
||||||
|
#include "../protocols/FocusGrab.hpp"
|
||||||
|
|
||||||
CProtocolManager::CProtocolManager() {
|
CProtocolManager::CProtocolManager() {
|
||||||
|
|
||||||
|
@ -51,6 +52,7 @@ CProtocolManager::CProtocolManager() {
|
||||||
PROTO::virtualPointer = std::make_unique<CVirtualPointerProtocol>(&zwlr_virtual_pointer_manager_v1_interface, 2, "VirtualPointer");
|
PROTO::virtualPointer = std::make_unique<CVirtualPointerProtocol>(&zwlr_virtual_pointer_manager_v1_interface, 2, "VirtualPointer");
|
||||||
PROTO::outputManagement = std::make_unique<COutputManagementProtocol>(&zwlr_output_manager_v1_interface, 4, "OutputManagement");
|
PROTO::outputManagement = std::make_unique<COutputManagementProtocol>(&zwlr_output_manager_v1_interface, 4, "OutputManagement");
|
||||||
PROTO::serverDecorationKDE = std::make_unique<CServerDecorationKDEProtocol>(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE");
|
PROTO::serverDecorationKDE = std::make_unique<CServerDecorationKDEProtocol>(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE");
|
||||||
|
PROTO::focusGrab = std::make_unique<CFocusGrabProtocol>(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab");
|
||||||
|
|
||||||
// Old protocol implementations.
|
// Old protocol implementations.
|
||||||
// TODO: rewrite them to use hyprwayland-scanner.
|
// TODO: rewrite them to use hyprwayland-scanner.
|
||||||
|
|
325
src/protocols/FocusGrab.cpp
Normal file
325
src/protocols/FocusGrab.cpp
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
#include "FocusGrab.hpp"
|
||||||
|
#include "Compositor.hpp"
|
||||||
|
#include <hyprland-focus-grab-v1.hpp>
|
||||||
|
#include <managers/input/InputManager.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#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,
|
||||||
|
};
|
||||||
|
|
||||||
|
CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface) {
|
||||||
|
hyprListener_surfaceDestroy.initCallback(
|
||||||
|
&surface->events.destroy, [=](void*, void*) { grab->eraseSurface(surface); }, this, "CFocusGrab");
|
||||||
|
}
|
||||||
|
|
||||||
|
CFocusGrabSurfaceState::~CFocusGrabSurfaceState() {
|
||||||
|
hyprListener_surfaceDestroy.removeCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
resource->setDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); });
|
||||||
|
resource->setOnDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); });
|
||||||
|
resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(wlr_surface_from_resource(surface)); });
|
||||||
|
resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(wlr_surface_from_resource(surface)); });
|
||||||
|
resource->setCommit([this](CHyprlandFocusGrabV1* pMgr) { commit(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
CFocusGrab::~CFocusGrab() {
|
||||||
|
finish(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFocusGrab::good() {
|
||||||
|
return resource->resource();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFocusGrab::isSurfaceComitted(wlr_surface* surface) {
|
||||||
|
auto iter = m_mSurfaces.find(surface);
|
||||||
|
if (iter == m_mSurfaces.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return iter->second->state == CFocusGrabSurfaceState::Comitted;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure new surfaces are focused if under the mouse when comitted.
|
||||||
|
g_pInputManager->simulateMouseMovement();
|
||||||
|
refocusKeyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
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)
|
||||||
|
m_mSurfaces.erase(iter);
|
||||||
|
else
|
||||||
|
iter->second->state = CFocusGrabSurfaceState::PendingRemoval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFocusGrab::eraseSurface(wlr_surface* surface) {
|
||||||
|
removeSurface(surface);
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFocusGrab::refocusKeyboard() {
|
||||||
|
auto keyboardSurface = g_pCompositor->m_sSeat.seat->keyboard_state.focused_surface;
|
||||||
|
if (keyboardSurface != nullptr && isSurfaceComitted(keyboardSurface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
wlr_surface* surface = nullptr;
|
||||||
|
for (auto& [surf, state] : m_mSurfaces) {
|
||||||
|
if (state->state == CFocusGrabSurfaceState::Comitted) {
|
||||||
|
surface = surf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surface)
|
||||||
|
g_pCompositor->focusSurface(surface);
|
||||||
|
else
|
||||||
|
Debug::log(ERR, "CFocusGrab::refocusKeyboard called with no committed surfaces. This should never happen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFocusGrab::commit() {
|
||||||
|
auto surfacesChanged = false;
|
||||||
|
auto anyComitted = false;
|
||||||
|
for (auto iter = m_mSurfaces.begin(); iter != m_mSurfaces.end();) {
|
||||||
|
switch (iter->second->state) {
|
||||||
|
case CFocusGrabSurfaceState::PendingRemoval:
|
||||||
|
iter = m_mSurfaces.erase(iter);
|
||||||
|
surfacesChanged = true;
|
||||||
|
continue;
|
||||||
|
case CFocusGrabSurfaceState::PendingAddition:
|
||||||
|
iter->second->state = CFocusGrabSurfaceState::Comitted;
|
||||||
|
surfacesChanged = true;
|
||||||
|
anyComitted = true;
|
||||||
|
break;
|
||||||
|
case CFocusGrabSurfaceState::Comitted: anyComitted = true; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surfacesChanged) {
|
||||||
|
if (anyComitted)
|
||||||
|
start();
|
||||||
|
else
|
||||||
|
finish(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFocusGrabProtocol::CFocusGrabProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFocusGrabProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||||
|
const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CHyprlandFocusGrabManagerV1>(client, ver, id)).get();
|
||||||
|
RESOURCE->setOnDestroy([this](CHyprlandFocusGrabManagerV1* p) { onManagerResourceDestroy(p->resource()); });
|
||||||
|
|
||||||
|
RESOURCE->setDestroy([this](CHyprlandFocusGrabManagerV1* p) { onManagerResourceDestroy(p->resource()); });
|
||||||
|
RESOURCE->setCreateGrab([this](CHyprlandFocusGrabManagerV1* pMgr, uint32_t id) { onCreateGrab(pMgr, id); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFocusGrabProtocol::onManagerResourceDestroy(wl_resource* res) {
|
||||||
|
std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFocusGrabProtocol::destroyGrab(CFocusGrab* grab) {
|
||||||
|
std::erase_if(m_vGrabs, [&](const auto& other) { return other.get() == grab; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFocusGrabProtocol::onCreateGrab(CHyprlandFocusGrabManagerV1* pMgr, uint32_t id) {
|
||||||
|
m_vGrabs.push_back(std::make_unique<CFocusGrab>(std::make_shared<CHyprlandFocusGrabV1>(pMgr->client(), pMgr->version(), id)));
|
||||||
|
const auto RESOURCE = m_vGrabs.back().get();
|
||||||
|
|
||||||
|
if (!RESOURCE->good()) {
|
||||||
|
pMgr->noMemory();
|
||||||
|
m_vGrabs.pop_back();
|
||||||
|
}
|
||||||
|
}
|
77
src/protocols/FocusGrab.hpp
Normal file
77
src/protocols/FocusGrab.hpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WaylandProtocol.hpp"
|
||||||
|
#include "hyprland-focus-grab-v1.hpp"
|
||||||
|
#include "macros.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CFocusGrab;
|
||||||
|
|
||||||
|
class CFocusGrabSurfaceState {
|
||||||
|
public:
|
||||||
|
CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface);
|
||||||
|
~CFocusGrabSurfaceState();
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
PendingAddition,
|
||||||
|
PendingRemoval,
|
||||||
|
Comitted,
|
||||||
|
} state = PendingAddition;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DYNLISTENER(surfaceDestroy);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CFocusGrab {
|
||||||
|
public:
|
||||||
|
CFocusGrab(SP<CHyprlandFocusGrabV1> resource_);
|
||||||
|
~CFocusGrab();
|
||||||
|
|
||||||
|
bool good();
|
||||||
|
bool isSurfaceComitted(wlr_surface* surface);
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void finish(bool sendCleared);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addSurface(wlr_surface* surface);
|
||||||
|
void removeSurface(wlr_surface* surface);
|
||||||
|
void eraseSurface(wlr_surface* surface);
|
||||||
|
void refocusKeyboard();
|
||||||
|
void commit();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
DYNLISTENER(pointerGrabStarted);
|
||||||
|
DYNLISTENER(keyboardGrabStarted);
|
||||||
|
DYNLISTENER(touchGrabStarted);
|
||||||
|
friend class CFocusGrabSurfaceState;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CFocusGrabProtocol : public IWaylandProtocol {
|
||||||
|
public:
|
||||||
|
CFocusGrabProtocol(const wl_interface* iface, const int& var, const std::string& name);
|
||||||
|
|
||||||
|
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onManagerResourceDestroy(wl_resource* res);
|
||||||
|
void destroyGrab(CFocusGrab* grab);
|
||||||
|
void onCreateGrab(CHyprlandFocusGrabManagerV1* pMgr, uint32_t id);
|
||||||
|
|
||||||
|
std::vector<UP<CHyprlandFocusGrabManagerV1>> m_vManagers;
|
||||||
|
std::vector<UP<CFocusGrab>> m_vGrabs;
|
||||||
|
|
||||||
|
friend class CFocusGrab;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace PROTO {
|
||||||
|
inline UP<CFocusGrabProtocol> focusGrab;
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0c2ce70625cb30aef199cb388f99e19a61a6ce03
|
Subproject commit e06482e0e611130cd1929f75e8c1cf679e57d161
|
Loading…
Reference in a new issue