decompose wl_backend.c: extract wl_pointer_motion.c
This commit is contained in:
parent
28fb61668f
commit
2e22c290ac
|
|
@ -184,7 +184,8 @@ wmaker_SOURCES += \
|
|||
backend/wayland/wl_dnd.c \
|
||||
backend/wayland/wl_grabs.c \
|
||||
backend/wayland/wl_grabstate.c \
|
||||
backend/wayland/wl_dragicon.c
|
||||
backend/wayland/wl_dragicon.c \
|
||||
backend/wayland/wl_pointer_motion.c
|
||||
endif
|
||||
|
||||
if USE_NESTED_FUNC
|
||||
|
|
|
|||
|
|
@ -291,17 +291,17 @@ void wl_focus_set(WNativeWindow win, int revert_to, unsigned long timestamp);
|
|||
/* Phase 50: forward declaration — defined in client section below. */
|
||||
int wl_client_get_pid(WNativeWindow win);
|
||||
/* Phase 13: forward declarations — defined in pointer section below. */
|
||||
static void wl_update_pointer_focus(uint32_t time_msec);
|
||||
void wl_update_pointer_focus(uint32_t time_msec);
|
||||
void wl_pointer_warp_to(int x, int y);
|
||||
/* wmaker-popup-v1 helper — defined in protocol section below. */
|
||||
void wmaker_popup_apply(struct wl_toplevel_view *view);
|
||||
/* Phase 14: pointer event handler forward declarations. */
|
||||
static void handle_pointer_motion(struct wl_listener *listener, void *data);
|
||||
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,
|
||||
double *sy_out, struct wl_toplevel_view **view_out);
|
||||
/* Phase 24: client cursor-surface request handler. */
|
||||
static void handle_seat_request_cursor(struct wl_listener *listener, void *data);
|
||||
extern void handle_seat_request_cursor(struct wl_listener *listener, void *data);
|
||||
/* Phase 25: client clipboard selection request handler. */
|
||||
static void handle_seat_request_set_selection(struct wl_listener *listener, void *data);
|
||||
/* Phase 25b: drag-and-drop request handler. */
|
||||
|
|
@ -347,7 +347,7 @@ static void handle_backend_new_input(struct wl_listener *listener, void *data);
|
|||
/* Phase 18: output lifecycle and frame rendering forward declarations. */
|
||||
static void handle_backend_new_output(struct wl_listener *listener, void *data);
|
||||
static void handle_output_frame(struct wl_listener *listener, void *data);
|
||||
static void handle_pointer_motion_absolute(struct wl_listener *listener, void *data);
|
||||
extern void handle_pointer_motion_absolute(struct wl_listener *listener, void *data);
|
||||
static void handle_pointer_button(struct wl_listener *listener, void *data);
|
||||
static void handle_pointer_frame(struct wl_listener *listener, void *data);
|
||||
|
||||
|
|
@ -524,7 +524,7 @@ wl_grab_begin_resize(struct wl_toplevel_view *view, uint32_t edges)
|
|||
}
|
||||
|
||||
/* Called from both pointer-motion handlers (relative + absolute). */
|
||||
static void
|
||||
void
|
||||
wl_grab_apply_motion(void)
|
||||
{
|
||||
if (!wl_state.grab_type || !wl_state.grab_view)
|
||||
|
|
@ -3586,223 +3586,6 @@ wm_dock_app_remove(WNativeWindow id)
|
|||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Frame buffer (pixman + wlr_scene_buffer) */
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Phase 14: pointer input event handlers */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void
|
||||
handle_pointer_motion(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)listener;
|
||||
struct wlr_pointer_motion_event *ev = data;
|
||||
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 += (int)ev->delta_x;
|
||||
wl_state.pointer_y += (int)ev->delta_y;
|
||||
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 A: enqueue motion event for WINGs.
|
||||
* Use frame_buf_hit so button sub-windows (which have no active scene_buf
|
||||
* buffer and are invisible to wlr_scene_node_at) are resolved correctly. */
|
||||
WMScreen *wmscr = wl_get_wmscreen();
|
||||
if (wmscr) {
|
||||
WMEvent wev;
|
||||
memset(&wev, 0, sizeof(wev));
|
||||
wev.type = WME_MOTION;
|
||||
struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x,
|
||||
wl_state.pointer_y);
|
||||
WNativeWindow new_id;
|
||||
if (fb) {
|
||||
wev.window = fb->id;
|
||||
wev.u.motion.window = fb->id;
|
||||
wev.u.motion.x = wl_state.pointer_x - fb->x;
|
||||
wev.u.motion.y = wl_state.pointer_y - fb->y;
|
||||
new_id = fb->id;
|
||||
} else {
|
||||
WScreen *scr0 = wScreenWithNumber(0);
|
||||
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
|
||||
wev.window = root;
|
||||
wev.u.motion.window = root;
|
||||
wev.u.motion.x = wl_state.pointer_x;
|
||||
wev.u.motion.y = wl_state.pointer_y;
|
||||
new_id = root;
|
||||
}
|
||||
wev.u.motion.time = ev->time_msec;
|
||||
wev.u.motion.x_root = wl_state.pointer_x;
|
||||
wev.u.motion.y_root = wl_state.pointer_y;
|
||||
/* Resolve WINGs child view (slider, etc.) at pointer for
|
||||
* motion routing during drag operations. */
|
||||
struct W_View *mtarget = NULL;
|
||||
if (fb && fb->id >= 0x20000000) {
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
extern struct W_View *W_FindViewAtPoint(struct W_View *parent, int x, int y);
|
||||
W_View *toplevel = W_GetViewForWindow((unsigned long)fb->id);
|
||||
if (toplevel) {
|
||||
mtarget = W_FindViewAtPoint(toplevel,
|
||||
wev.u.motion.x, wev.u.motion.y);
|
||||
/* Adjust event coordinates to target view's local space */
|
||||
if (mtarget && mtarget != toplevel) {
|
||||
W_View *p = mtarget;
|
||||
int ox = 0, oy = 0;
|
||||
while (p && p != toplevel) {
|
||||
ox += p->pos.x;
|
||||
oy += p->pos.y;
|
||||
p = p->parent;
|
||||
}
|
||||
wev.u.motion.x -= ox;
|
||||
wev.u.motion.y -= oy;
|
||||
}
|
||||
}
|
||||
}
|
||||
W_WL_EnqueueEvent(wmscr, &wev, mtarget);
|
||||
/* Emit synthetic LEAVE/ENTER when pointer crosses WM sub-window
|
||||
* boundaries (titlebar ↔ button, etc.). These feed the inner
|
||||
* press-track loop in framewin.c:buttonMouseDown so the cancel-
|
||||
* on-leave behaviour works correctly. */
|
||||
if (new_id != wl_state.last_hovered_id) {
|
||||
WMEvent xev;
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
if (wl_state.last_hovered_id) {
|
||||
xev.type = WME_LEAVE;
|
||||
xev.window = wl_state.last_hovered_id;
|
||||
xev.u.crossing.window = wl_state.last_hovered_id;
|
||||
xev.u.crossing.x_root = wl_state.pointer_x;
|
||||
xev.u.crossing.y_root = wl_state.pointer_y;
|
||||
xev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
xev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(wmscr, &xev, NULL);
|
||||
}
|
||||
xev.type = WME_ENTER;
|
||||
xev.window = new_id;
|
||||
xev.u.crossing.window = new_id;
|
||||
xev.u.crossing.x_root = wl_state.pointer_x;
|
||||
xev.u.crossing.y_root = wl_state.pointer_y;
|
||||
xev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
xev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(wmscr, &xev, NULL);
|
||||
wl_state.last_hovered_id = new_id;
|
||||
}
|
||||
}
|
||||
/* Phase 22: apply grab before updating normal pointer focus. */
|
||||
if (wl_state.grab_type) { wl_grab_apply_motion(); return; }
|
||||
wl_update_pointer_focus(ev->time_msec);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_pointer_motion_absolute(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)listener;
|
||||
struct wlr_pointer_motion_absolute_event *ev = data;
|
||||
/* Phase 23: use wlr_cursor_warp_absolute so wlroots maps the 0..1
|
||||
* device-normalized coordinates to layout pixels and updates the
|
||||
* hardware cursor in the nested window automatically. */
|
||||
if (wl_state.cursor) {
|
||||
wlr_cursor_warp_absolute(wl_state.cursor, &ev->pointer->base, ev->x, ev->y);
|
||||
wl_state.pointer_x = (int)wl_state.cursor->x;
|
||||
wl_state.pointer_y = (int)wl_state.cursor->y;
|
||||
} else {
|
||||
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 = (int)(ev->x * (double)ow);
|
||||
wl_state.pointer_y = (int)(ev->y * (double)oh);
|
||||
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 A: enqueue motion event for WINGs.
|
||||
* Use frame_buf_hit so button sub-windows (which have no active scene_buf
|
||||
* buffer and are invisible to wlr_scene_node_at) are resolved correctly. */
|
||||
WMScreen *wmscr2 = wl_get_wmscreen();
|
||||
if (wmscr2) {
|
||||
WMEvent wev;
|
||||
memset(&wev, 0, sizeof(wev));
|
||||
wev.type = WME_MOTION;
|
||||
struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x,
|
||||
wl_state.pointer_y);
|
||||
WNativeWindow new_id;
|
||||
if (fb) {
|
||||
wev.window = fb->id;
|
||||
wev.u.motion.window = fb->id;
|
||||
wev.u.motion.x = wl_state.pointer_x - fb->x;
|
||||
wev.u.motion.y = wl_state.pointer_y - fb->y;
|
||||
new_id = fb->id;
|
||||
} else {
|
||||
WScreen *scr0 = wScreenWithNumber(0);
|
||||
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
|
||||
wev.window = root;
|
||||
wev.u.motion.window = root;
|
||||
wev.u.motion.x = wl_state.pointer_x;
|
||||
wev.u.motion.y = wl_state.pointer_y;
|
||||
new_id = root;
|
||||
}
|
||||
wev.u.motion.time = ev->time_msec;
|
||||
wev.u.motion.x_root = wl_state.pointer_x;
|
||||
wev.u.motion.y_root = wl_state.pointer_y;
|
||||
W_WL_EnqueueEvent(wmscr2, &wev, NULL);
|
||||
/* Emit synthetic LEAVE/ENTER on sub-window boundary crossings. */
|
||||
if (new_id != wl_state.last_hovered_id) {
|
||||
WMEvent xev;
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
if (wl_state.last_hovered_id) {
|
||||
xev.type = WME_LEAVE;
|
||||
xev.window = wl_state.last_hovered_id;
|
||||
xev.u.crossing.window = wl_state.last_hovered_id;
|
||||
xev.u.crossing.x_root = wl_state.pointer_x;
|
||||
xev.u.crossing.y_root = wl_state.pointer_y;
|
||||
xev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
xev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(wmscr2, &xev, NULL);
|
||||
}
|
||||
xev.type = WME_ENTER;
|
||||
xev.window = new_id;
|
||||
xev.u.crossing.window = new_id;
|
||||
xev.u.crossing.x_root = wl_state.pointer_x;
|
||||
xev.u.crossing.y_root = wl_state.pointer_y;
|
||||
xev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
xev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(wmscr2, &xev, NULL);
|
||||
wl_state.last_hovered_id = new_id;
|
||||
}
|
||||
}
|
||||
/* Phase 22: apply grab before updating normal pointer focus. */
|
||||
if (wl_state.grab_type) { wl_grab_apply_motion(); return; }
|
||||
wl_update_pointer_focus(ev->time_msec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Phase 24: seat request_set_cursor — client wants to set a custom cursor
|
||||
* image (e.g. I-beam in a text field, hand over a link). Validate that
|
||||
* the request comes from the currently focused pointer client, then hand
|
||||
* the surface to wlr_cursor so the hardware cursor is updated on all
|
||||
* outputs (which in nested mode sends wl_pointer.set_cursor to the host).
|
||||
*/
|
||||
static void
|
||||
handle_seat_request_cursor(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)listener;
|
||||
struct wlr_seat_pointer_request_set_cursor_event *ev = data;
|
||||
if (!wl_state.seat || !wl_state.cursor)
|
||||
return;
|
||||
/* Only honour cursor requests from the client that currently has
|
||||
* pointer focus; reject requests from unfocused clients. */
|
||||
struct wlr_seat_client *focused =
|
||||
wl_state.seat->pointer_state.focused_client;
|
||||
if (ev->seat_client != focused)
|
||||
return;
|
||||
wlr_cursor_set_surface(wl_state.cursor, ev->surface,
|
||||
ev->hotspot_x, ev->hotspot_y);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Drag icon overlay for WINGs compositor-internal DND */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
@ -4503,7 +4286,7 @@ view_surface_at(int px, int py, double *sx_out, double *sy_out,
|
|||
* pointer position. Called after every pointer position change so clients
|
||||
* receive wl_pointer.enter / wl_pointer.leave events correctly.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
wl_update_pointer_focus(uint32_t time_msec)
|
||||
{
|
||||
if (!wl_state.seat)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,232 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_pointer.h>
|
||||
#include <wlr/types/wlr_seat.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 W_WL_EnqueueEvent(struct W_Screen *scr, const WMEvent *ev, struct W_View *target);
|
||||
void wl_grab_apply_motion(void);
|
||||
void wl_update_pointer_focus(uint32_t time_msec);
|
||||
WMScreen *wl_get_wmscreen(void);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Phase 14: pointer input event handlers */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
void
|
||||
handle_pointer_motion(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)listener;
|
||||
struct wlr_pointer_motion_event *ev = data;
|
||||
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 += (int)ev->delta_x;
|
||||
wl_state.pointer_y += (int)ev->delta_y;
|
||||
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 A: enqueue motion event for WINGs.
|
||||
* Use frame_buf_hit so button sub-windows (which have no active scene_buf
|
||||
* buffer and are invisible to wlr_scene_node_at) are resolved correctly. */
|
||||
WMScreen *wmscr = wl_get_wmscreen();
|
||||
if (wmscr) {
|
||||
WMEvent wev;
|
||||
memset(&wev, 0, sizeof(wev));
|
||||
wev.type = WME_MOTION;
|
||||
struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x,
|
||||
wl_state.pointer_y);
|
||||
WNativeWindow new_id;
|
||||
if (fb) {
|
||||
wev.window = fb->id;
|
||||
wev.u.motion.window = fb->id;
|
||||
wev.u.motion.x = wl_state.pointer_x - fb->x;
|
||||
wev.u.motion.y = wl_state.pointer_y - fb->y;
|
||||
new_id = fb->id;
|
||||
} else {
|
||||
WScreen *scr0 = wScreenWithNumber(0);
|
||||
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
|
||||
wev.window = root;
|
||||
wev.u.motion.window = root;
|
||||
wev.u.motion.x = wl_state.pointer_x;
|
||||
wev.u.motion.y = wl_state.pointer_y;
|
||||
new_id = root;
|
||||
}
|
||||
wev.u.motion.time = ev->time_msec;
|
||||
wev.u.motion.x_root = wl_state.pointer_x;
|
||||
wev.u.motion.y_root = wl_state.pointer_y;
|
||||
/* Resolve WINGs child view (slider, etc.) at pointer for
|
||||
* motion routing during drag operations. */
|
||||
struct W_View *mtarget = NULL;
|
||||
if (fb && fb->id >= 0x20000000) {
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
extern struct W_View *W_FindViewAtPoint(struct W_View *parent, int x, int y);
|
||||
W_View *toplevel = W_GetViewForWindow((unsigned long)fb->id);
|
||||
if (toplevel) {
|
||||
mtarget = W_FindViewAtPoint(toplevel,
|
||||
wev.u.motion.x, wev.u.motion.y);
|
||||
/* Adjust event coordinates to target view's local space */
|
||||
if (mtarget && mtarget != toplevel) {
|
||||
W_View *p = mtarget;
|
||||
int ox = 0, oy = 0;
|
||||
while (p && p != toplevel) {
|
||||
ox += p->pos.x;
|
||||
oy += p->pos.y;
|
||||
p = p->parent;
|
||||
}
|
||||
wev.u.motion.x -= ox;
|
||||
wev.u.motion.y -= oy;
|
||||
}
|
||||
}
|
||||
}
|
||||
W_WL_EnqueueEvent(wmscr, &wev, mtarget);
|
||||
/* Emit synthetic LEAVE/ENTER when pointer crosses WM sub-window
|
||||
* boundaries (titlebar ↔ button, etc.). These feed the inner
|
||||
* press-track loop in framewin.c:buttonMouseDown so the cancel-
|
||||
* on-leave behaviour works correctly. */
|
||||
if (new_id != wl_state.last_hovered_id) {
|
||||
WMEvent xev;
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
if (wl_state.last_hovered_id) {
|
||||
xev.type = WME_LEAVE;
|
||||
xev.window = wl_state.last_hovered_id;
|
||||
xev.u.crossing.window = wl_state.last_hovered_id;
|
||||
xev.u.crossing.x_root = wl_state.pointer_x;
|
||||
xev.u.crossing.y_root = wl_state.pointer_y;
|
||||
xev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
xev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(wmscr, &xev, NULL);
|
||||
}
|
||||
xev.type = WME_ENTER;
|
||||
xev.window = new_id;
|
||||
xev.u.crossing.window = new_id;
|
||||
xev.u.crossing.x_root = wl_state.pointer_x;
|
||||
xev.u.crossing.y_root = wl_state.pointer_y;
|
||||
xev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
xev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(wmscr, &xev, NULL);
|
||||
wl_state.last_hovered_id = new_id;
|
||||
}
|
||||
}
|
||||
/* Phase 22: apply grab before updating normal pointer focus. */
|
||||
if (wl_state.grab_type) { wl_grab_apply_motion(); return; }
|
||||
wl_update_pointer_focus(ev->time_msec);
|
||||
}
|
||||
|
||||
void
|
||||
handle_pointer_motion_absolute(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)listener;
|
||||
struct wlr_pointer_motion_absolute_event *ev = data;
|
||||
/* Phase 23: use wlr_cursor_warp_absolute so wlroots maps the 0..1
|
||||
* device-normalized coordinates to layout pixels and updates the
|
||||
* hardware cursor in the nested window automatically. */
|
||||
if (wl_state.cursor) {
|
||||
wlr_cursor_warp_absolute(wl_state.cursor, &ev->pointer->base, ev->x, ev->y);
|
||||
wl_state.pointer_x = (int)wl_state.cursor->x;
|
||||
wl_state.pointer_y = (int)wl_state.cursor->y;
|
||||
} else {
|
||||
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 = (int)(ev->x * (double)ow);
|
||||
wl_state.pointer_y = (int)(ev->y * (double)oh);
|
||||
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 A: enqueue motion event for WINGs.
|
||||
* Use frame_buf_hit so button sub-windows (which have no active scene_buf
|
||||
* buffer and are invisible to wlr_scene_node_at) are resolved correctly. */
|
||||
WMScreen *wmscr2 = wl_get_wmscreen();
|
||||
if (wmscr2) {
|
||||
WMEvent wev;
|
||||
memset(&wev, 0, sizeof(wev));
|
||||
wev.type = WME_MOTION;
|
||||
struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x,
|
||||
wl_state.pointer_y);
|
||||
WNativeWindow new_id;
|
||||
if (fb) {
|
||||
wev.window = fb->id;
|
||||
wev.u.motion.window = fb->id;
|
||||
wev.u.motion.x = wl_state.pointer_x - fb->x;
|
||||
wev.u.motion.y = wl_state.pointer_y - fb->y;
|
||||
new_id = fb->id;
|
||||
} else {
|
||||
WScreen *scr0 = wScreenWithNumber(0);
|
||||
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
|
||||
wev.window = root;
|
||||
wev.u.motion.window = root;
|
||||
wev.u.motion.x = wl_state.pointer_x;
|
||||
wev.u.motion.y = wl_state.pointer_y;
|
||||
new_id = root;
|
||||
}
|
||||
wev.u.motion.time = ev->time_msec;
|
||||
wev.u.motion.x_root = wl_state.pointer_x;
|
||||
wev.u.motion.y_root = wl_state.pointer_y;
|
||||
W_WL_EnqueueEvent(wmscr2, &wev, NULL);
|
||||
/* Emit synthetic LEAVE/ENTER on sub-window boundary crossings. */
|
||||
if (new_id != wl_state.last_hovered_id) {
|
||||
WMEvent xev;
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
if (wl_state.last_hovered_id) {
|
||||
xev.type = WME_LEAVE;
|
||||
xev.window = wl_state.last_hovered_id;
|
||||
xev.u.crossing.window = wl_state.last_hovered_id;
|
||||
xev.u.crossing.x_root = wl_state.pointer_x;
|
||||
xev.u.crossing.y_root = wl_state.pointer_y;
|
||||
xev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
xev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(wmscr2, &xev, NULL);
|
||||
}
|
||||
xev.type = WME_ENTER;
|
||||
xev.window = new_id;
|
||||
xev.u.crossing.window = new_id;
|
||||
xev.u.crossing.x_root = wl_state.pointer_x;
|
||||
xev.u.crossing.y_root = wl_state.pointer_y;
|
||||
xev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
xev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(wmscr2, &xev, NULL);
|
||||
wl_state.last_hovered_id = new_id;
|
||||
}
|
||||
}
|
||||
/* Phase 22: apply grab before updating normal pointer focus. */
|
||||
if (wl_state.grab_type) { wl_grab_apply_motion(); return; }
|
||||
wl_update_pointer_focus(ev->time_msec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Phase 24: seat request_set_cursor — client wants to set a custom cursor
|
||||
* image (e.g. I-beam in a text field, hand over a link). Validate that
|
||||
* the request comes from the currently focused pointer client, then hand
|
||||
* the surface to wlr_cursor so the hardware cursor is updated on all
|
||||
* outputs (which in nested mode sends wl_pointer.set_cursor to the host).
|
||||
*/
|
||||
void
|
||||
handle_seat_request_cursor(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)listener;
|
||||
struct wlr_seat_pointer_request_set_cursor_event *ev = data;
|
||||
if (!wl_state.seat || !wl_state.cursor)
|
||||
return;
|
||||
/* Only honour cursor requests from the client that currently has
|
||||
* pointer focus; reject requests from unfocused clients. */
|
||||
struct wlr_seat_client *focused =
|
||||
wl_state.seat->pointer_state.focused_client;
|
||||
if (ev->seat_client != focused)
|
||||
return;
|
||||
wlr_cursor_set_surface(wl_state.cursor, ev->surface,
|
||||
ev->hotspot_x, ev->hotspot_y);
|
||||
}
|
||||
Loading…
Reference in New Issue