decompose wl_backend.c: extract wl_pointer_focus.c
This commit is contained in:
parent
2e22c290ac
commit
b06e9417ca
|
|
@ -185,7 +185,8 @@ wmaker_SOURCES += \
|
|||
backend/wayland/wl_grabs.c \
|
||||
backend/wayland/wl_grabstate.c \
|
||||
backend/wayland/wl_dragicon.c \
|
||||
backend/wayland/wl_pointer_motion.c
|
||||
backend/wayland/wl_pointer_motion.c \
|
||||
backend/wayland/wl_pointer_focus.c
|
||||
endif
|
||||
|
||||
if USE_NESTED_FUNC
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ void wmaker_popup_apply(struct wl_toplevel_view *view);
|
|||
/* Phase 14: pointer event handler forward declarations. */
|
||||
extern void handle_pointer_motion(struct wl_listener *listener, void *data);
|
||||
/* Phase 24: click-to-focus helper — defined in Phase 13 pointer section. */
|
||||
static struct wlr_surface *view_surface_at(int px, int py, double *sx_out,
|
||||
extern struct wlr_surface *view_surface_at(int px, int py, double *sx_out,
|
||||
double *sy_out, struct wl_toplevel_view **view_out);
|
||||
/* Phase 24: client cursor-surface request handler. */
|
||||
extern void handle_seat_request_cursor(struct wl_listener *listener, void *data);
|
||||
|
|
@ -4207,251 +4207,6 @@ handle_pointer_frame(struct wl_listener *listener, void *data)
|
|||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Phase 13: pointer focus delivery to Wayland surfaces */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/*
|
||||
* Find the topmost mapped view whose surface contains screen point (px, py).
|
||||
* Returns the wlr_surface and sets sx,sy to surface-local coordinates.
|
||||
* Iterates toplevel_list in reverse-insertion order (last = topmost).
|
||||
*/
|
||||
static struct wlr_surface *
|
||||
view_surface_at(int px, int py, double *sx_out, double *sy_out,
|
||||
struct wl_toplevel_view **view_out)
|
||||
{
|
||||
/* Use wlr_scene_node_at as the authority on what is visually
|
||||
* topmost at (px,py). The old geometry-scan loop over
|
||||
* toplevel_list caused toggling focus on overlapping windows
|
||||
* because toplevel_list order diverged from scene Z-order. */
|
||||
if (!wl_state.scene) return NULL;
|
||||
|
||||
double _sx, _sy;
|
||||
struct wlr_scene_node *node = wlr_scene_node_at(
|
||||
&wl_state.scene->tree.node, (double)px, (double)py, &_sx, &_sy);
|
||||
if (!node) return NULL;
|
||||
|
||||
/* Walk up until parent is a level_tree bucket: that node is
|
||||
* fb->tree (framed) or v->scene_node (unframed). */
|
||||
struct wlr_scene_node *n = node;
|
||||
while (n->parent && &n->parent->node != &wl_state.scene->tree.node) {
|
||||
int _bucket = 0, _li;
|
||||
for (_li = 0; _li < WL_NUM_LEVEL_BUCKETS; _li++) {
|
||||
if (wl_state.level_trees[_li] && n->parent == wl_state.level_trees[_li])
|
||||
{ _bucket = 1; break; }
|
||||
}
|
||||
if (_bucket) break;
|
||||
n = &n->parent->node;
|
||||
}
|
||||
|
||||
struct wl_toplevel_view *v;
|
||||
wl_list_for_each(v, &wl_state.toplevel_list, link) {
|
||||
/* Framed window: resolve via the fb->tree node. */
|
||||
int match = 0;
|
||||
if (v->frame_id) {
|
||||
struct wl_frame_buf *_fb = frame_buf_find(v->frame_id);
|
||||
match = (_fb && _fb->tree && &_fb->tree->node == n);
|
||||
} else {
|
||||
match = (v->scene_node && &v->scene_node->node == n);
|
||||
}
|
||||
if (!match) continue;
|
||||
|
||||
if (v->xw_surface && v->xw_surface->surface) {
|
||||
double sx = px - (double)v->x;
|
||||
double sy = py - (double)v->y;
|
||||
if (sx_out) *sx_out = sx;
|
||||
if (sy_out) *sy_out = sy;
|
||||
if (view_out) *view_out = v;
|
||||
return v->xw_surface->surface;
|
||||
}
|
||||
if (v->xdg_surface) {
|
||||
double sx = px - (double)v->x;
|
||||
double sy = py - (double)v->y;
|
||||
double sub_sx, sub_sy;
|
||||
struct wlr_surface *sub = wlr_xdg_surface_surface_at(
|
||||
v->xdg_surface, sx, sy, &sub_sx, &sub_sy);
|
||||
if (sub) {
|
||||
if (sx_out) *sx_out = sub_sx;
|
||||
if (sy_out) *sy_out = sub_sy;
|
||||
if (view_out) *view_out = v;
|
||||
return sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the seat's pointer focus to the surface at the current virtual
|
||||
* pointer position. Called after every pointer position change so clients
|
||||
* receive wl_pointer.enter / wl_pointer.leave events correctly.
|
||||
*/
|
||||
void
|
||||
wl_update_pointer_focus(uint32_t time_msec)
|
||||
{
|
||||
if (!wl_state.seat)
|
||||
return;
|
||||
|
||||
double sx, sy;
|
||||
struct wl_toplevel_view *view = NULL;
|
||||
struct wlr_surface *surface = NULL;
|
||||
|
||||
/* If pointer is over an internal frame_buf (menu, titlebar, etc.),
|
||||
* don't send pointer events to any client surface — UNLESS the
|
||||
* pointer is actually over the client content area within the frame. */
|
||||
struct wl_frame_buf *fb = frame_buf_at(wl_state.pointer_x, wl_state.pointer_y);
|
||||
if (fb) {
|
||||
/* Check if this frame_buf has a client surface (toplevel view)
|
||||
* and the pointer is over the client area, not the decorations. */
|
||||
struct wl_toplevel_view *v = NULL;
|
||||
struct wlr_surface *cs = view_surface_at(
|
||||
wl_state.pointer_x, wl_state.pointer_y, &sx, &sy, &v);
|
||||
if (cs) {
|
||||
surface = cs;
|
||||
view = v;
|
||||
fb = NULL; /* not over decorations */
|
||||
}
|
||||
}
|
||||
if (!fb && !surface) {
|
||||
surface = view_surface_at(
|
||||
wl_state.pointer_x, wl_state.pointer_y, &sx, &sy, &view);
|
||||
}
|
||||
|
||||
static struct wlr_surface *last_focused_surface = NULL;
|
||||
if (surface) {
|
||||
if (surface != last_focused_surface) {
|
||||
last_focused_surface = surface;
|
||||
}
|
||||
wlr_seat_pointer_notify_enter(wl_state.seat, surface, sx, sy);
|
||||
wlr_seat_pointer_notify_motion(wl_state.seat, time_msec, sx, sy);
|
||||
wlr_seat_pointer_notify_frame(wl_state.seat);
|
||||
} else {
|
||||
if (last_focused_surface) {
|
||||
last_focused_surface = NULL;
|
||||
}
|
||||
wlr_seat_pointer_clear_focus(wl_state.seat);
|
||||
/* When pointer leaves all surfaces, reset to default arrow.
|
||||
* Don't reset during grabs — the grab system manages the cursor. */
|
||||
if (!wl_state.grab_type)
|
||||
wl_set_cursor_image("left_ptr");
|
||||
}
|
||||
/* Phase 29 (FFP): focus-follows-pointer — when the pointer enters a new
|
||||
* managed view, deliver WM keyboard focus without raising.
|
||||
* Only fires when wPreferences.focus_mode == WKF_SLOPPY. */
|
||||
{
|
||||
static struct wl_toplevel_view *last_ffp_view = NULL;
|
||||
if (view != last_ffp_view) {
|
||||
last_ffp_view = view;
|
||||
if (view) {
|
||||
WObjDescriptor *desc =
|
||||
wm_backend->context_find(view->id, WM_CTX_CLIENT_WIN);
|
||||
if (desc && desc->parent_type == WCLASS_WINDOW) {
|
||||
WWindow *wwin = (WWindow *)desc->parent;
|
||||
if (wPreferences.focus_mode == WKF_SLOPPY) {
|
||||
wSetFocusTo(wScreenWithNumber(0), wwin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wl_pointer_warp(int dx, int dy)
|
||||
{
|
||||
/* Phase 54: relative warp — clamp to output bounds. */
|
||||
int ow = wl_state.output ? (int)wl_state.output->width : 1920;
|
||||
int oh = wl_state.output ? (int)wl_state.output->height : 1080;
|
||||
wl_state.pointer_x += dx;
|
||||
wl_state.pointer_y += dy;
|
||||
if (wl_state.pointer_x < 0) wl_state.pointer_x = 0;
|
||||
if (wl_state.pointer_y < 0) wl_state.pointer_y = 0;
|
||||
if (wl_state.pointer_x >= ow) wl_state.pointer_x = ow - 1;
|
||||
if (wl_state.pointer_y >= oh) wl_state.pointer_y = oh - 1;
|
||||
/* Phase 23: update hardware cursor position. */
|
||||
if (wl_state.cursor)
|
||||
wlr_cursor_warp(wl_state.cursor, NULL,
|
||||
(double)wl_state.pointer_x, (double)wl_state.pointer_y);
|
||||
/* Phase 13: update pointer focus after relative warp */
|
||||
wl_update_pointer_focus(0);
|
||||
}
|
||||
|
||||
void
|
||||
wl_pointer_warp_to(int x, int y)
|
||||
{
|
||||
/* Phase 54: absolute warp — clamp to output bounds. */
|
||||
int ow = wl_state.output ? (int)wl_state.output->width : 1920;
|
||||
int oh = wl_state.output ? (int)wl_state.output->height : 1080;
|
||||
if (x < 0) x = 0;
|
||||
if (y < 0) y = 0;
|
||||
if (x >= ow) x = ow - 1;
|
||||
if (y >= oh) y = oh - 1;
|
||||
wl_state.pointer_x = x;
|
||||
wl_state.pointer_y = y;
|
||||
/* Phase 23: update hardware cursor position. */
|
||||
if (wl_state.cursor)
|
||||
wlr_cursor_warp(wl_state.cursor, NULL, (double)x, (double)y);
|
||||
/* Phase 13: update pointer focus after absolute warp */
|
||||
wl_update_pointer_focus(0);
|
||||
}
|
||||
|
||||
int
|
||||
wl_pointer_query(WNativeWindow root, int *root_x, int *root_y)
|
||||
{
|
||||
/* Phase 54: return tracked virtual pointer position. */
|
||||
(void)root;
|
||||
*root_x = wl_state.pointer_x;
|
||||
*root_y = wl_state.pointer_y;
|
||||
return wl_state.started ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
wl_pointer_query_full(WNativeWindow root,
|
||||
WNativeWindow *child_out,
|
||||
int *root_x, int *root_y,
|
||||
unsigned int *buttons_out)
|
||||
{
|
||||
/* Phase 54: return tracked virtual pointer position. */
|
||||
(void)root;
|
||||
if (child_out) *child_out = WNATIVE_NONE;
|
||||
if (root_x) *root_x = wl_state.pointer_x;
|
||||
if (root_y) *root_y = wl_state.pointer_y;
|
||||
if (buttons_out) *buttons_out = 0;
|
||||
return wl_state.started ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
wl_pointer_change_grab(unsigned int event_mask, int cursor_id,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
(void)event_mask; (void)timestamp;
|
||||
/* If no grab is active, start a WM policy grab (type 3) so that
|
||||
* wl_update_pointer_focus doesn't reset the cursor on every motion
|
||||
* event when the pointer is over frame decorations.
|
||||
* This handles the opaque-move path where moveres.c calls
|
||||
* pointer_change_grab without first calling pointer_grab. */
|
||||
if (!wl_state.grab_type) {
|
||||
wl_state.grab_type = 3;
|
||||
wl_state.grab_view = NULL;
|
||||
if (wl_state.seat)
|
||||
wlr_seat_pointer_clear_focus(wl_state.seat);
|
||||
wwarning("wl_backend: grab established via pointer_change_grab");
|
||||
}
|
||||
/* Map WCUR_* cursor IDs to xcursor names */
|
||||
const char *name;
|
||||
switch (cursor_id) {
|
||||
case WCUR_MOVE: name = "fleur"; break;
|
||||
case WCUR_WAIT: name = "watch"; break;
|
||||
case WCUR_TOPLEFTRESIZE: name = "nw-resize"; break;
|
||||
case WCUR_TOPRIGHTRESIZE: name = "ne-resize"; break;
|
||||
case WCUR_BOTTOMLEFTRESIZE: name = "sw-resize"; break;
|
||||
case WCUR_BOTTOMRIGHTRESIZE: name = "se-resize"; break;
|
||||
case WCUR_VERTICALRESIZE: name = "n-resize"; break;
|
||||
case WCUR_HORIZONRESIZE: name = "e-resize"; break;
|
||||
default: name = "left_ptr"; break;
|
||||
}
|
||||
wl_set_cursor_image(name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Keyboard grabs */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,265 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/xwayland.h>
|
||||
#include "../../actions.h"
|
||||
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "../../screen.h"
|
||||
#include "wl_types.h"
|
||||
#include <WINGs/WINGsP.h>
|
||||
|
||||
/* Forward declarations for functions defined in other wl_*.c files */
|
||||
void wl_set_cursor_image(const char *name);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Phase 13: pointer focus delivery to Wayland surfaces */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/*
|
||||
* Find the topmost mapped view whose surface contains screen point (px, py).
|
||||
* Returns the wlr_surface and sets sx,sy to surface-local coordinates.
|
||||
* Iterates toplevel_list in reverse-insertion order (last = topmost).
|
||||
*/
|
||||
struct wlr_surface *
|
||||
view_surface_at(int px, int py, double *sx_out, double *sy_out,
|
||||
struct wl_toplevel_view **view_out)
|
||||
{
|
||||
/* Use wlr_scene_node_at as the authority on what is visually
|
||||
* topmost at (px,py). The old geometry-scan loop over
|
||||
* toplevel_list caused toggling focus on overlapping windows
|
||||
* because toplevel_list order diverged from scene Z-order. */
|
||||
if (!wl_state.scene) return NULL;
|
||||
|
||||
double _sx, _sy;
|
||||
struct wlr_scene_node *node = wlr_scene_node_at(
|
||||
&wl_state.scene->tree.node, (double)px, (double)py, &_sx, &_sy);
|
||||
if (!node) return NULL;
|
||||
|
||||
/* Walk up until parent is a level_tree bucket: that node is
|
||||
* fb->tree (framed) or v->scene_node (unframed). */
|
||||
struct wlr_scene_node *n = node;
|
||||
while (n->parent && &n->parent->node != &wl_state.scene->tree.node) {
|
||||
int _bucket = 0, _li;
|
||||
for (_li = 0; _li < WL_NUM_LEVEL_BUCKETS; _li++) {
|
||||
if (wl_state.level_trees[_li] && n->parent == wl_state.level_trees[_li])
|
||||
{ _bucket = 1; break; }
|
||||
}
|
||||
if (_bucket) break;
|
||||
n = &n->parent->node;
|
||||
}
|
||||
|
||||
struct wl_toplevel_view *v;
|
||||
wl_list_for_each(v, &wl_state.toplevel_list, link) {
|
||||
/* Framed window: resolve via the fb->tree node. */
|
||||
int match = 0;
|
||||
if (v->frame_id) {
|
||||
struct wl_frame_buf *_fb = frame_buf_find(v->frame_id);
|
||||
match = (_fb && _fb->tree && &_fb->tree->node == n);
|
||||
} else {
|
||||
match = (v->scene_node && &v->scene_node->node == n);
|
||||
}
|
||||
if (!match) continue;
|
||||
|
||||
if (v->xw_surface && v->xw_surface->surface) {
|
||||
double sx = px - (double)v->x;
|
||||
double sy = py - (double)v->y;
|
||||
if (sx_out) *sx_out = sx;
|
||||
if (sy_out) *sy_out = sy;
|
||||
if (view_out) *view_out = v;
|
||||
return v->xw_surface->surface;
|
||||
}
|
||||
if (v->xdg_surface) {
|
||||
double sx = px - (double)v->x;
|
||||
double sy = py - (double)v->y;
|
||||
double sub_sx, sub_sy;
|
||||
struct wlr_surface *sub = wlr_xdg_surface_surface_at(
|
||||
v->xdg_surface, sx, sy, &sub_sx, &sub_sy);
|
||||
if (sub) {
|
||||
if (sx_out) *sx_out = sub_sx;
|
||||
if (sy_out) *sy_out = sub_sy;
|
||||
if (view_out) *view_out = v;
|
||||
return sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the seat's pointer focus to the surface at the current virtual
|
||||
* pointer position. Called after every pointer position change so clients
|
||||
* receive wl_pointer.enter / wl_pointer.leave events correctly.
|
||||
*/
|
||||
void
|
||||
wl_update_pointer_focus(uint32_t time_msec)
|
||||
{
|
||||
if (!wl_state.seat)
|
||||
return;
|
||||
|
||||
double sx, sy;
|
||||
struct wl_toplevel_view *view = NULL;
|
||||
struct wlr_surface *surface = NULL;
|
||||
|
||||
/* If pointer is over an internal frame_buf (menu, titlebar, etc.),
|
||||
* don't send pointer events to any client surface — UNLESS the
|
||||
* pointer is actually over the client content area within the frame. */
|
||||
struct wl_frame_buf *fb = frame_buf_at(wl_state.pointer_x, wl_state.pointer_y);
|
||||
if (fb) {
|
||||
/* Check if this frame_buf has a client surface (toplevel view)
|
||||
* and the pointer is over the client area, not the decorations. */
|
||||
struct wl_toplevel_view *v = NULL;
|
||||
struct wlr_surface *cs = view_surface_at(
|
||||
wl_state.pointer_x, wl_state.pointer_y, &sx, &sy, &v);
|
||||
if (cs) {
|
||||
surface = cs;
|
||||
view = v;
|
||||
fb = NULL; /* not over decorations */
|
||||
}
|
||||
}
|
||||
if (!fb && !surface) {
|
||||
surface = view_surface_at(
|
||||
wl_state.pointer_x, wl_state.pointer_y, &sx, &sy, &view);
|
||||
}
|
||||
|
||||
static struct wlr_surface *last_focused_surface = NULL;
|
||||
if (surface) {
|
||||
if (surface != last_focused_surface) {
|
||||
last_focused_surface = surface;
|
||||
}
|
||||
wlr_seat_pointer_notify_enter(wl_state.seat, surface, sx, sy);
|
||||
wlr_seat_pointer_notify_motion(wl_state.seat, time_msec, sx, sy);
|
||||
wlr_seat_pointer_notify_frame(wl_state.seat);
|
||||
} else {
|
||||
if (last_focused_surface) {
|
||||
last_focused_surface = NULL;
|
||||
}
|
||||
wlr_seat_pointer_clear_focus(wl_state.seat);
|
||||
/* When pointer leaves all surfaces, reset to default arrow.
|
||||
* Don't reset during grabs — the grab system manages the cursor. */
|
||||
if (!wl_state.grab_type)
|
||||
wl_set_cursor_image("left_ptr");
|
||||
}
|
||||
/* Phase 29 (FFP): focus-follows-pointer — when the pointer enters a new
|
||||
* managed view, deliver WM keyboard focus without raising.
|
||||
* Only fires when wPreferences.focus_mode == WKF_SLOPPY. */
|
||||
{
|
||||
static struct wl_toplevel_view *last_ffp_view = NULL;
|
||||
if (view != last_ffp_view) {
|
||||
last_ffp_view = view;
|
||||
if (view) {
|
||||
WObjDescriptor *desc =
|
||||
wm_backend->context_find(view->id, WM_CTX_CLIENT_WIN);
|
||||
if (desc && desc->parent_type == WCLASS_WINDOW) {
|
||||
WWindow *wwin = (WWindow *)desc->parent;
|
||||
if (wPreferences.focus_mode == WKF_SLOPPY) {
|
||||
wSetFocusTo(wScreenWithNumber(0), wwin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wl_pointer_warp(int dx, int dy)
|
||||
{
|
||||
/* Phase 54: relative warp — clamp to output bounds. */
|
||||
int ow = wl_state.output ? (int)wl_state.output->width : 1920;
|
||||
int oh = wl_state.output ? (int)wl_state.output->height : 1080;
|
||||
wl_state.pointer_x += dx;
|
||||
wl_state.pointer_y += dy;
|
||||
if (wl_state.pointer_x < 0) wl_state.pointer_x = 0;
|
||||
if (wl_state.pointer_y < 0) wl_state.pointer_y = 0;
|
||||
if (wl_state.pointer_x >= ow) wl_state.pointer_x = ow - 1;
|
||||
if (wl_state.pointer_y >= oh) wl_state.pointer_y = oh - 1;
|
||||
/* Phase 23: update hardware cursor position. */
|
||||
if (wl_state.cursor)
|
||||
wlr_cursor_warp(wl_state.cursor, NULL,
|
||||
(double)wl_state.pointer_x, (double)wl_state.pointer_y);
|
||||
/* Phase 13: update pointer focus after relative warp */
|
||||
wl_update_pointer_focus(0);
|
||||
}
|
||||
|
||||
void
|
||||
wl_pointer_warp_to(int x, int y)
|
||||
{
|
||||
/* Phase 54: absolute warp — clamp to output bounds. */
|
||||
int ow = wl_state.output ? (int)wl_state.output->width : 1920;
|
||||
int oh = wl_state.output ? (int)wl_state.output->height : 1080;
|
||||
if (x < 0) x = 0;
|
||||
if (y < 0) y = 0;
|
||||
if (x >= ow) x = ow - 1;
|
||||
if (y >= oh) y = oh - 1;
|
||||
wl_state.pointer_x = x;
|
||||
wl_state.pointer_y = y;
|
||||
/* Phase 23: update hardware cursor position. */
|
||||
if (wl_state.cursor)
|
||||
wlr_cursor_warp(wl_state.cursor, NULL, (double)x, (double)y);
|
||||
/* Phase 13: update pointer focus after absolute warp */
|
||||
wl_update_pointer_focus(0);
|
||||
}
|
||||
|
||||
int
|
||||
wl_pointer_query(WNativeWindow root, int *root_x, int *root_y)
|
||||
{
|
||||
/* Phase 54: return tracked virtual pointer position. */
|
||||
(void)root;
|
||||
*root_x = wl_state.pointer_x;
|
||||
*root_y = wl_state.pointer_y;
|
||||
return wl_state.started ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
wl_pointer_query_full(WNativeWindow root,
|
||||
WNativeWindow *child_out,
|
||||
int *root_x, int *root_y,
|
||||
unsigned int *buttons_out)
|
||||
{
|
||||
/* Phase 54: return tracked virtual pointer position. */
|
||||
(void)root;
|
||||
if (child_out) *child_out = WNATIVE_NONE;
|
||||
if (root_x) *root_x = wl_state.pointer_x;
|
||||
if (root_y) *root_y = wl_state.pointer_y;
|
||||
if (buttons_out) *buttons_out = 0;
|
||||
return wl_state.started ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
wl_pointer_change_grab(unsigned int event_mask, int cursor_id,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
(void)event_mask; (void)timestamp;
|
||||
/* If no grab is active, start a WM policy grab (type 3) so that
|
||||
* wl_update_pointer_focus doesn't reset the cursor on every motion
|
||||
* event when the pointer is over frame decorations.
|
||||
* This handles the opaque-move path where moveres.c calls
|
||||
* pointer_change_grab without first calling pointer_grab. */
|
||||
if (!wl_state.grab_type) {
|
||||
wl_state.grab_type = 3;
|
||||
wl_state.grab_view = NULL;
|
||||
if (wl_state.seat)
|
||||
wlr_seat_pointer_clear_focus(wl_state.seat);
|
||||
wwarning("wl_backend: grab established via pointer_change_grab");
|
||||
}
|
||||
/* Map WCUR_* cursor IDs to xcursor names */
|
||||
const char *name;
|
||||
switch (cursor_id) {
|
||||
case WCUR_MOVE: name = "fleur"; break;
|
||||
case WCUR_WAIT: name = "watch"; break;
|
||||
case WCUR_TOPLEFTRESIZE: name = "nw-resize"; break;
|
||||
case WCUR_TOPRIGHTRESIZE: name = "ne-resize"; break;
|
||||
case WCUR_BOTTOMLEFTRESIZE: name = "sw-resize"; break;
|
||||
case WCUR_BOTTOMRIGHTRESIZE: name = "se-resize"; break;
|
||||
case WCUR_VERTICALRESIZE: name = "n-resize"; break;
|
||||
case WCUR_HORIZONRESIZE: name = "e-resize"; break;
|
||||
default: name = "left_ptr"; break;
|
||||
}
|
||||
wl_set_cursor_image(name);
|
||||
}
|
||||
Loading…
Reference in New Issue