decompose wl_backend.c: extract wl_handlers.c
This commit is contained in:
parent
189fde4a19
commit
e2f048a6a9
|
|
@ -192,13 +192,14 @@ wmaker_SOURCES += \
|
||||||
backend/wayland/wl_popup.c \
|
backend/wayland/wl_popup.c \
|
||||||
backend/wayland/wl_text_input.c \
|
backend/wayland/wl_text_input.c \
|
||||||
backend/wayland/wl_xdg_activation.c \
|
backend/wayland/wl_xdg_activation.c \
|
||||||
|
backend/wayland/wl_layer_shell.c \
|
||||||
backend/wayland/wl_output_mgmt.c \
|
backend/wayland/wl_output_mgmt.c \
|
||||||
backend/wayland/wl_output.c \
|
backend/wayland/wl_output.c \
|
||||||
backend/wayland/wl_xdg.c \
|
backend/wayland/wl_xdg.c \
|
||||||
backend/wayland/wl_xwayland.c \
|
backend/wayland/wl_xwayland.c \
|
||||||
backend/wayland/wl_dock.c \
|
backend/wayland/wl_dock.c \
|
||||||
backend/wayland/wl_layer_shell.c \
|
|
||||||
backend/wayland/wl_virtual_pointer.c \
|
backend/wayland/wl_virtual_pointer.c \
|
||||||
|
backend/wayland/wl_handlers.c \
|
||||||
backend/wayland/wl_input_fwd.c
|
backend/wayland/wl_input_fwd.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -304,11 +304,11 @@ extern struct wlr_surface *view_surface_at(int px, int py, double *sx_out,
|
||||||
/* Phase 24: client cursor-surface request handler. */
|
/* Phase 24: client cursor-surface request handler. */
|
||||||
extern 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. */
|
/* Phase 25: client clipboard selection request handler. */
|
||||||
static void handle_seat_request_set_selection(struct wl_listener *listener, void *data);
|
extern void handle_seat_request_set_selection(struct wl_listener *listener, void *data);
|
||||||
/* Phase 25b: drag-and-drop request handler. */
|
/* Phase 25b: drag-and-drop request handler. */
|
||||||
void handle_seat_request_start_drag(struct wl_listener *listener, void *data);
|
void handle_seat_request_start_drag(struct wl_listener *listener, void *data);
|
||||||
/* Phase 26: primary selection request handler. */
|
/* Phase 26: primary selection request handler. */
|
||||||
static void handle_seat_request_primary_selection(struct wl_listener *listener, void *data);
|
extern void handle_seat_request_primary_selection(struct wl_listener *listener, void *data);
|
||||||
/* Compositor-internal clipboard hooks for WINGs. */
|
/* Compositor-internal clipboard hooks for WINGs. */
|
||||||
void wl_clipboard_store_to_seat(const char *text, int len);
|
void wl_clipboard_store_to_seat(const char *text, int len);
|
||||||
char *wl_clipboard_fetch_from_seat(int *len_out);
|
char *wl_clipboard_fetch_from_seat(int *len_out);
|
||||||
|
|
@ -319,13 +319,13 @@ void wl_drag_icon_move(int x, int y);
|
||||||
void wl_drag_icon_hide(void);
|
void wl_drag_icon_hide(void);
|
||||||
void wl_drag_cursor_feedback(Bool accepted);
|
void wl_drag_cursor_feedback(Bool accepted);
|
||||||
/* Phase 28: idle inhibitor created/destroyed handler. */
|
/* Phase 28: idle inhibitor created/destroyed handler. */
|
||||||
static void handle_idle_new_inhibitor(struct wl_listener *listener, void *data);
|
extern void handle_idle_new_inhibitor(struct wl_listener *listener, void *data);
|
||||||
/* Phase 29: scroll-wheel axis event handler. */
|
/* Phase 29: scroll-wheel axis event handler. */
|
||||||
extern void handle_pointer_axis(struct wl_listener *listener, void *data);
|
extern void handle_pointer_axis(struct wl_listener *listener, void *data);
|
||||||
/* Phase 30: new pointer constraint handler. */
|
/* Phase 30: new pointer constraint handler. */
|
||||||
static void handle_new_pointer_constraint(struct wl_listener *listener, void *data);
|
extern void handle_new_pointer_constraint(struct wl_listener *listener, void *data);
|
||||||
/* Phase 31: new keyboard shortcuts inhibitor handler. */
|
/* Phase 31: new keyboard shortcuts inhibitor handler. */
|
||||||
static void handle_new_shortcuts_inhibitor(struct wl_listener *listener, void *data);
|
extern void handle_new_shortcuts_inhibitor(struct wl_listener *listener, void *data);
|
||||||
/* Phase 33: output management apply/test + output power set_mode handlers. */
|
/* Phase 33: output management apply/test + output power set_mode handlers. */
|
||||||
extern void handle_output_mgr_apply(struct wl_listener *listener, void *data);
|
extern void handle_output_mgr_apply(struct wl_listener *listener, void *data);
|
||||||
extern void handle_output_mgr_test(struct wl_listener *listener, void *data);
|
extern void handle_output_mgr_test(struct wl_listener *listener, void *data);
|
||||||
|
|
@ -337,11 +337,11 @@ extern void handle_virtual_keyboard_new(struct wl_listener *listener, void *data
|
||||||
/* Phase 35: xdg_activation request_activate handler. */
|
/* Phase 35: xdg_activation request_activate handler. */
|
||||||
extern void handle_xdg_activation_request(struct wl_listener *listener, void *data);
|
extern void handle_xdg_activation_request(struct wl_listener *listener, void *data);
|
||||||
/* Phase 36: layer shell new_surface handler. */
|
/* Phase 36: layer shell new_surface handler. */
|
||||||
static void handle_layer_shell_new_surface(struct wl_listener *listener, void *data);
|
extern void handle_layer_shell_new_surface(struct wl_listener *listener, void *data);
|
||||||
extern void handle_xdg_new_toplevel(struct wl_listener *listener, void *data);
|
extern void handle_xdg_new_toplevel(struct wl_listener *listener, void *data);
|
||||||
extern void handle_new_toplevel_decoration(struct wl_listener *listener, void *data);
|
extern void handle_new_toplevel_decoration(struct wl_listener *listener, void *data);
|
||||||
/* Phase 37: virtual pointer handler. */
|
/* Phase 37: virtual pointer handler. */
|
||||||
extern void handle_virtual_pointer_new(struct wl_listener *listener, void *data);
|
static void handle_virtual_pointer_new(struct wl_listener *listener, void *data);
|
||||||
/* Phase 17: XWayland new surface forward declaration. */
|
/* Phase 17: XWayland new surface forward declaration. */
|
||||||
extern void handle_xwayland_new_surface(struct wl_listener *listener, void *data);
|
extern void handle_xwayland_new_surface(struct wl_listener *listener, void *data);
|
||||||
extern void handle_xwayland_ready(struct wl_listener *listener, void *data);
|
extern void handle_xwayland_ready(struct wl_listener *listener, void *data);
|
||||||
|
|
@ -1595,471 +1595,6 @@ wl_event_loop_terminate(void)
|
||||||
* (i.e. Ctrl-C or other clipboard write). Forward to wlr_seat so the
|
* (i.e. Ctrl-C or other clipboard write). Forward to wlr_seat so the
|
||||||
* selection becomes available to the next client that reads it.
|
* selection becomes available to the next client that reads it.
|
||||||
*/
|
*/
|
||||||
static void
|
|
||||||
handle_seat_request_set_selection(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)listener;
|
|
||||||
struct wlr_seat_request_set_selection_event *ev = data;
|
|
||||||
if (!wl_state.seat)
|
|
||||||
return;
|
|
||||||
wlr_seat_set_selection(wl_state.seat, ev->source, ev->serial);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Phase 26: seat request_set_primary_selection — client writes to the
|
|
||||||
* primary selection buffer (e.g. by selecting text). Forward to
|
|
||||||
* wlr_seat so middle-click paste works in other clients.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
handle_seat_request_primary_selection(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)listener;
|
|
||||||
struct wlr_seat_request_set_primary_selection_event *ev = data;
|
|
||||||
if (!wl_state.seat)
|
|
||||||
return;
|
|
||||||
wlr_seat_set_primary_selection(wl_state.seat, ev->source, ev->serial);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Phase 28: idle_inhibit new_inhibitor — a client (e.g. mpv, a game) created
|
|
||||||
* an idle-inhibit object. wlroots tracks the inhibitor list internally;
|
|
||||||
* the compositor can query wl_state.idle_inhibit_mgr->inhibitors to decide
|
|
||||||
* whether to suppress screen blanking. For now we just log the event so
|
|
||||||
* the capability is advertised and the inhibitor object doesn't error out.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
handle_idle_new_inhibitor(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)listener;
|
|
||||||
struct wlr_idle_inhibitor_v1 *inhibitor = data;
|
|
||||||
(void)inhibitor;
|
|
||||||
wwarning("wl_backend: idle inhibitor created (client suppressing screen blank)");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Phase 29 (fix): scroll-wheel axis event handler.
|
|
||||||
* wlr_event_pointer_axis carries orientation (vertical/horizontal), delta,
|
|
||||||
* delta_discrete (notches), and source (wheel vs finger). Forward directly
|
|
||||||
* to the seat so the focused Wayland client receives wl_pointer.axis events.
|
|
||||||
* Without this, scrolling is silently dropped in every Wayland client.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
handle_pointer_axis(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)listener;
|
|
||||||
struct wlr_pointer_axis_event *ev = data;
|
|
||||||
if (!wl_state.seat)
|
|
||||||
return;
|
|
||||||
/* Drop axis events during a compositor grab so the grabbed window
|
|
||||||
* does not receive unexpected scroll events mid-move/resize. */
|
|
||||||
if (wl_state.grab_type)
|
|
||||||
return;
|
|
||||||
wlr_seat_pointer_notify_axis(wl_state.seat,
|
|
||||||
ev->time_msec,
|
|
||||||
ev->orientation,
|
|
||||||
ev->delta,
|
|
||||||
ev->delta_discrete,
|
|
||||||
ev->source,
|
|
||||||
ev->relative_direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Phase 30: new pointer constraint — a client requested pointer lock or
|
|
||||||
* pointer confinement (e.g. a game locking the cursor to its window).
|
|
||||||
* We activate the constraint immediately so the client gets confirmed.
|
|
||||||
* In headless mode the pointer is virtual so there is nothing physically
|
|
||||||
* to lock, but activating keeps the client happy.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
handle_new_pointer_constraint(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)listener;
|
|
||||||
struct wlr_pointer_constraint_v1 *constraint = data;
|
|
||||||
(void)constraint;
|
|
||||||
/* Activate immediately — in nested mode the real pointer is bounded
|
|
||||||
* by the host compositor's window anyway. */
|
|
||||||
wlr_pointer_constraint_v1_send_activated(constraint);
|
|
||||||
wwarning("wl_backend: pointer constraint activated");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Phase 31: new keyboard shortcuts inhibitor — a fullscreen app or remote
|
|
||||||
* desktop client wants to suppress WM keyboard shortcuts.
|
|
||||||
* Activate the inhibitor immediately so the client knows it is granted.
|
|
||||||
* The existing wWaylandKeyPress() dispatcher in handle_keyboard_key already
|
|
||||||
* forwards all non-shortcut keys; with the inhibitor active we should skip
|
|
||||||
* the shortcut check for that focused client. For now we simply activate
|
|
||||||
* and log; per-client inhibitor tracking can be refined later.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
handle_new_shortcuts_inhibitor(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)listener;
|
|
||||||
struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor = data;
|
|
||||||
wlr_keyboard_shortcuts_inhibitor_v1_activate(inhibitor);
|
|
||||||
wwarning("wl_backend: keyboard shortcuts inhibitor activated");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Phase 36: layer shell — panels, docks, wallpapers, overlays */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
#define LAYER_VIEW_FROM(l, field) \
|
|
||||||
((struct wl_layer_view *)((char *)(l) - offsetof(struct wl_layer_view, field)))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute the geometry for a layer surface given its anchor, margins,
|
|
||||||
* desired size and the output dimensions.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
layer_surface_compute_geometry(struct wlr_layer_surface_v1 *ls,
|
|
||||||
uint32_t ow, uint32_t oh,
|
|
||||||
uint32_t *out_w, uint32_t *out_h)
|
|
||||||
{
|
|
||||||
const struct wlr_layer_surface_v1_state *s = &ls->current;
|
|
||||||
uint32_t w = s->desired_width;
|
|
||||||
uint32_t h = s->desired_height;
|
|
||||||
|
|
||||||
bool anchor_lr = (s->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) &&
|
|
||||||
(s->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
|
|
||||||
bool anchor_tb = (s->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) &&
|
|
||||||
(s->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM);
|
|
||||||
|
|
||||||
if (w == 0 && anchor_lr)
|
|
||||||
w = ow - s->margin.left - s->margin.right;
|
|
||||||
if (h == 0 && anchor_tb)
|
|
||||||
h = oh - s->margin.top - s->margin.bottom;
|
|
||||||
|
|
||||||
/* Ensure minimum 1×1. */
|
|
||||||
*out_w = w > 0 ? w : 1;
|
|
||||||
*out_h = h > 0 ? h : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute the position of a layer surface on the output given its
|
|
||||||
* anchor, margins and final dimensions.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
layer_surface_compute_position(struct wlr_layer_surface_v1 *ls,
|
|
||||||
uint32_t ow, uint32_t oh,
|
|
||||||
uint32_t fw, uint32_t fh,
|
|
||||||
int *out_x, int *out_y)
|
|
||||||
{
|
|
||||||
const struct wlr_layer_surface_v1_state *s = &ls->current;
|
|
||||||
int x = 0, y = 0;
|
|
||||||
|
|
||||||
bool anchor_l = s->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
|
|
||||||
bool anchor_r = s->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
|
||||||
bool anchor_t = s->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
|
|
||||||
bool anchor_b = s->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
|
||||||
|
|
||||||
if (anchor_l && anchor_r)
|
|
||||||
x = s->margin.left;
|
|
||||||
else if (anchor_l)
|
|
||||||
x = s->margin.left;
|
|
||||||
else if (anchor_r)
|
|
||||||
x = (int)ow - (int)fw - s->margin.right;
|
|
||||||
else
|
|
||||||
x = ((int)ow - (int)fw) / 2;
|
|
||||||
|
|
||||||
if (anchor_t && anchor_b)
|
|
||||||
y = s->margin.top;
|
|
||||||
else if (anchor_t)
|
|
||||||
y = s->margin.top;
|
|
||||||
else if (anchor_b)
|
|
||||||
y = (int)oh - (int)fh - s->margin.bottom;
|
|
||||||
else
|
|
||||||
y = ((int)oh - (int)fh) / 2;
|
|
||||||
|
|
||||||
*out_x = x;
|
|
||||||
*out_y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
handle_layer_surface_map(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)data;
|
|
||||||
struct wl_layer_view *lv = LAYER_VIEW_FROM(listener, map_listener);
|
|
||||||
wwarning("wl_backend: layer surface mapped (layer=%d namespace=%s)",
|
|
||||||
lv->layer_surface->current.layer,
|
|
||||||
lv->layer_surface->namespace ? lv->layer_surface->namespace : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
handle_layer_surface_unmap(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)data;
|
|
||||||
struct wl_layer_view *lv = LAYER_VIEW_FROM(listener, unmap_listener);
|
|
||||||
wwarning("wl_backend: layer surface unmapped");
|
|
||||||
if (lv->scene_node) {
|
|
||||||
wlr_scene_node_destroy(&lv->scene_node->node);
|
|
||||||
lv->scene_node = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
handle_layer_surface_destroy(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)data;
|
|
||||||
struct wl_layer_view *lv = LAYER_VIEW_FROM(listener, destroy_listener);
|
|
||||||
wl_list_remove(&lv->map_listener.link);
|
|
||||||
wl_list_remove(&lv->unmap_listener.link);
|
|
||||||
wl_list_remove(&lv->destroy_listener.link);
|
|
||||||
if (lv->scene_node) {
|
|
||||||
wlr_scene_node_destroy(&lv->scene_node->node);
|
|
||||||
lv->scene_node = NULL;
|
|
||||||
}
|
|
||||||
wl_list_remove(&lv->link);
|
|
||||||
free(lv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* handle_layer_shell_new_surface — a client created a layer surface.
|
|
||||||
* Assign the output if unset, compute geometry, send configure, and
|
|
||||||
* wire map/unmap/destroy lifecycle.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
handle_layer_shell_new_surface(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)listener;
|
|
||||||
struct wlr_layer_surface_v1 *ls = data;
|
|
||||||
|
|
||||||
/* Assign output if client did not specify one. */
|
|
||||||
if (!ls->output && wl_state.output)
|
|
||||||
ls->output = wl_state.output;
|
|
||||||
|
|
||||||
struct wl_layer_view *lv = calloc(1, sizeof(*lv));
|
|
||||||
if (!lv) {
|
|
||||||
wlr_layer_surface_v1_destroy(ls);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lv->layer_surface = ls;
|
|
||||||
|
|
||||||
/* Add to scene graph in the correct level bucket.
|
|
||||||
* Layer-shell layer enum maps to WL_LAYER_* buckets:
|
|
||||||
* BACKGROUND -> WL_LAYER_BACKGROUND
|
|
||||||
* BOTTOM -> WL_LAYER_DESKTOP
|
|
||||||
* TOP -> WL_LAYER_DOCK
|
|
||||||
* OVERLAY -> WL_LAYER_OVERLAY */
|
|
||||||
if (wl_state.scene) {
|
|
||||||
int _lb;
|
|
||||||
switch (ls->pending.layer) {
|
|
||||||
case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND: _lb = WL_LAYER_BACKGROUND; break;
|
|
||||||
case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM: _lb = WL_LAYER_DESKTOP; break;
|
|
||||||
case ZWLR_LAYER_SHELL_V1_LAYER_TOP: _lb = WL_LAYER_DOCK; break;
|
|
||||||
case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY: _lb = WL_LAYER_OVERLAY; break;
|
|
||||||
default: _lb = WL_LAYER_NORMAL; break;
|
|
||||||
}
|
|
||||||
struct wlr_scene_tree *_lp = wl_state.level_trees[_lb]
|
|
||||||
? wl_state.level_trees[_lb] : &wl_state.scene->tree;
|
|
||||||
lv->scene_node = wlr_scene_subsurface_tree_create(_lp, ls->surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compute and send initial configure. */
|
|
||||||
uint32_t ow = 1920, oh = 1080;
|
|
||||||
if (ls->output) {
|
|
||||||
ow = ls->output->width > 0 ? (uint32_t)ls->output->width : 1920;
|
|
||||||
oh = ls->output->height > 0 ? (uint32_t)ls->output->height : 1080;
|
|
||||||
}
|
|
||||||
uint32_t fw, fh;
|
|
||||||
layer_surface_compute_geometry(ls, ow, oh, &fw, &fh);
|
|
||||||
wlr_layer_surface_v1_configure(ls, fw, fh);
|
|
||||||
|
|
||||||
/* Position the scene node. */
|
|
||||||
if (lv->scene_node) {
|
|
||||||
int sx, sy;
|
|
||||||
layer_surface_compute_position(ls, ow, oh, fw, fh, &sx, &sy);
|
|
||||||
wlr_scene_node_set_position(&lv->scene_node->node, sx, sy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wire lifecycle listeners. */
|
|
||||||
lv->map_listener.notify = handle_layer_surface_map;
|
|
||||||
lv->unmap_listener.notify = handle_layer_surface_unmap;
|
|
||||||
lv->destroy_listener.notify = handle_layer_surface_destroy;
|
|
||||||
wl_signal_add(&ls->surface->events.map, &lv->map_listener);
|
|
||||||
wl_signal_add(&ls->surface->events.unmap, &lv->unmap_listener);
|
|
||||||
wl_signal_add(&ls->events.destroy, &lv->destroy_listener);
|
|
||||||
|
|
||||||
wl_list_insert(&wl_state.layer_list, &lv->link);
|
|
||||||
|
|
||||||
wwarning("wl_backend: layer surface new layer=%d %ux%u namespace=%s",
|
|
||||||
ls->current.layer, fw, fh,
|
|
||||||
ls->namespace ? ls->namespace : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
void
|
|
||||||
handle_pointer_button(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)listener;
|
|
||||||
struct wlr_pointer_button_event *ev = data;
|
|
||||||
if (!wl_state.seat)
|
|
||||||
return;
|
|
||||||
/* Phase 22: any button release ends an active compositor grab (move/resize).
|
|
||||||
* Type 3 (WM policy grab) is NOT ended here — the policy code calls
|
|
||||||
* pointer_ungrab itself after processing the button release event. */
|
|
||||||
if (wl_state.grab_type && wl_state.grab_type != 3 &&
|
|
||||||
ev->state == WLR_BUTTON_RELEASED) {
|
|
||||||
wwarning("wl_backend: grab ended (button release) grab_type=%d", wl_state.grab_type);
|
|
||||||
wl_grab_end();
|
|
||||||
wl_update_pointer_focus(ev->time_msec);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Phase 24: click-to-focus — on button press, find the view under the
|
|
||||||
* pointer and focus + raise it via the WM policy layer.
|
|
||||||
* This mirrors what the X11 backend does via ButtonPress on frame windows. */
|
|
||||||
if (ev->state == WLR_BUTTON_PRESSED) {
|
|
||||||
double sx, sy;
|
|
||||||
struct wl_toplevel_view *view = NULL;
|
|
||||||
view_surface_at(wl_state.pointer_x, wl_state.pointer_y,
|
|
||||||
&sx, &sy, &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;
|
|
||||||
WScreen *scr = wScreenWithNumber(0);
|
|
||||||
wSetFocusTo(scr, wwin);
|
|
||||||
/* Raise entire window assembly via tree */
|
|
||||||
if (view->frame_id) {
|
|
||||||
struct wl_frame_buf *fb = frame_buf_find(view->frame_id);
|
|
||||||
if (fb && fb->tree)
|
|
||||||
wlr_scene_node_raise_to_top(&fb->tree->node);
|
|
||||||
} else if (view->scene_node) {
|
|
||||||
wlr_scene_node_raise_to_top(&view->scene_node->node);
|
|
||||||
}
|
|
||||||
/* Also raise it in our toplevel list so view_surface_at()
|
|
||||||
* returns it first on subsequent hits. */
|
|
||||||
wl_list_remove(&view->link);
|
|
||||||
wl_list_insert(&wl_state.toplevel_list, &view->link);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* No toplevel surface — check if a WINGs dialog frame_buf was clicked */
|
|
||||||
struct wl_frame_buf *hit = frame_buf_hit(wl_state.pointer_x,
|
|
||||||
wl_state.pointer_y);
|
|
||||||
if (hit) {
|
|
||||||
/* Walk up to the parent frame to find the WWindow */
|
|
||||||
WNativeWindow lookup = hit->parent_id ? hit->parent_id : hit->id;
|
|
||||||
WObjDescriptor *desc =
|
|
||||||
wm_backend->context_find(lookup, WM_CTX_CLIENT_WIN);
|
|
||||||
if (desc && desc->parent_type == WCLASS_WINDOW) {
|
|
||||||
WWindow *wwin = (WWindow *)desc->parent;
|
|
||||||
WScreen *scr = wScreenWithNumber(0);
|
|
||||||
wSetFocusTo(scr, wwin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Phase A: enqueue native WMEvent for WINGs */
|
|
||||||
WMScreen *wmscr = wl_get_wmscreen();
|
|
||||||
if (wmscr) {
|
|
||||||
WMEvent wev;
|
|
||||||
memset(&wev, 0, sizeof(wev));
|
|
||||||
wev.type = (ev->state == WLR_BUTTON_PRESSED)
|
|
||||||
? WME_BUTTON_PRESS : WME_BUTTON_RELEASE;
|
|
||||||
|
|
||||||
/* Hit-test: determine which WM window was clicked.
|
|
||||||
* Use frame_buf_hit so button sub-windows (invisible to the scene
|
|
||||||
* graph because their pixels are composited into the titlebar buffer)
|
|
||||||
* are resolved to their own window IDs, letting handleButtonPress
|
|
||||||
* route the event to buttonMouseDown instead of titlebarMouseDown. */
|
|
||||||
struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x,
|
|
||||||
wl_state.pointer_y);
|
|
||||||
if (fb) {
|
|
||||||
wev.window = fb->id;
|
|
||||||
wev.u.button.window = fb->id;
|
|
||||||
wev.u.button.x = wl_state.pointer_x - fb->x;
|
|
||||||
wev.u.button.y = wl_state.pointer_y - fb->y;
|
|
||||||
} else {
|
|
||||||
WScreen *scr0 = wScreenWithNumber(0);
|
|
||||||
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
|
|
||||||
wev.window = root;
|
|
||||||
wev.u.button.window = root;
|
|
||||||
wev.u.button.x = wl_state.pointer_x;
|
|
||||||
wev.u.button.y = wl_state.pointer_y;
|
|
||||||
}
|
|
||||||
wev.u.button.time = ev->time_msec;
|
|
||||||
wev.u.button.x_root = wl_state.pointer_x;
|
|
||||||
wev.u.button.y_root = wl_state.pointer_y;
|
|
||||||
/* Linux evdev BTN_LEFT=0x110, BTN_RIGHT=0x111, BTN_MIDDLE=0x112
|
|
||||||
* Button1=1(left), Button2=2(middle), Button3=3(right) */
|
|
||||||
switch (ev->button) {
|
|
||||||
case 0x110: wev.u.button.button = 1; break;
|
|
||||||
case 0x111: wev.u.button.button = 3; break;
|
|
||||||
case 0x112: wev.u.button.button = 2; break;
|
|
||||||
default: wev.u.button.button = (ev->button - 0x110) + 1; break;
|
|
||||||
}
|
|
||||||
/* For WINGs views, resolve the child widget at click coordinates */
|
|
||||||
struct W_View *target = 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) {
|
|
||||||
target = W_FindViewAtPoint(toplevel,
|
|
||||||
wev.u.button.x, wev.u.button.y);
|
|
||||||
if (!target)
|
|
||||||
target = toplevel;
|
|
||||||
/* Adjust event coordinates to target view's local space */
|
|
||||||
if (target != toplevel) {
|
|
||||||
W_View *p = target;
|
|
||||||
int ox = 0, oy = 0;
|
|
||||||
while (p && p != toplevel) {
|
|
||||||
ox += p->pos.x;
|
|
||||||
oy += p->pos.y;
|
|
||||||
p = p->parent;
|
|
||||||
}
|
|
||||||
wev.u.button.x -= ox;
|
|
||||||
wev.u.button.y -= oy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
W_WL_EnqueueEvent(wmscr, &wev, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Refresh pointer focus before delivering button event.
|
|
||||||
* The last wl_update_pointer_focus call was during the most recent
|
|
||||||
* motion event. If no motion happened since then, the XWayland
|
|
||||||
* surface might not have pointer focus, causing
|
|
||||||
* wlr_seat_pointer_notify_button to be a no-op. */
|
|
||||||
wl_update_pointer_focus(ev->time_msec);
|
|
||||||
|
|
||||||
wlr_seat_pointer_notify_button(wl_state.seat, ev->time_msec,
|
|
||||||
ev->button, ev->state);
|
|
||||||
wlr_seat_pointer_notify_frame(wl_state.seat);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
handle_pointer_frame(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
(void)listener; (void)data;
|
|
||||||
if (wl_state.seat)
|
|
||||||
wlr_seat_pointer_notify_frame(wl_state.seat);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Keyboard grabs */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* Screen internals */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
int wl_screen_replace_wm(WScreen *scr) { (void)scr; return 1; }
|
|
||||||
int wl_screen_select_input(WScreen *scr, long mask) { (void)scr; (void)mask; return 1; }
|
|
||||||
void wl_screen_set_root_cursor(WScreen *scr, int cursor_id) { (void)scr; (void)cursor_id; }
|
|
||||||
void wl_screen_set_icon_sizes(WScreen *scr, int min_size, int max_size) { (void)scr; (void)min_size; (void)max_size; }
|
|
||||||
void wl_screen_setup_noticeboard(WScreen *scr) { (void)scr; }
|
|
||||||
void
|
void
|
||||||
wl_screen_alloc_gcs(WScreen *scr)
|
wl_screen_alloc_gcs(WScreen *scr)
|
||||||
{
|
{
|
||||||
|
|
@ -2628,3 +2163,8 @@ wl_monitors_query(WScreen *scr, WHeadGeometry **heads_out, int *count_out)
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
int wl_screen_select_input(WScreen *scr, long mask) { (void)scr; (void)mask; return 1; }
|
||||||
|
void wl_screen_set_root_cursor(WScreen *scr, int cursor_id) { (void)scr; (void)cursor_id; }
|
||||||
|
void wl_screen_set_icon_sizes(WScreen *scr, int min_size, int max_size) { (void)scr; (void)min_size; (void)max_size; }
|
||||||
|
void wl_screen_setup_noticeboard(WScreen *scr) { (void)scr; }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,298 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
|
#include <wlr/types/wlr_pointer.h>
|
||||||
|
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
||||||
|
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
|
||||||
|
#include <wlr/types/wlr_data_device.h>
|
||||||
|
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
||||||
|
#include <wlr/types/wlr_primary_selection.h>
|
||||||
|
#include <wlr/types/wlr_scene.h>
|
||||||
|
#include <wlr/types/wlr_seat.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
#include "../../screen.h"
|
||||||
|
#include "wl_types.h"
|
||||||
|
#include "../../actions.h"
|
||||||
|
#include <WINGs/WINGsP.h>
|
||||||
|
|
||||||
|
void wl_grab_end(void);
|
||||||
|
void wl_update_pointer_focus(uint32_t time_msec);
|
||||||
|
struct wlr_surface *view_surface_at(int px, int py, double *sx_out, double *sy_out, struct wl_toplevel_view **view_out);
|
||||||
|
void wm_dock_app_remove(WNativeWindow id);
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_seat_request_set_selection(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
(void)listener;
|
||||||
|
struct wlr_seat_request_set_selection_event *ev = data;
|
||||||
|
if (!wl_state.seat)
|
||||||
|
return;
|
||||||
|
wlr_seat_set_selection(wl_state.seat, ev->source, ev->serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 26: seat request_set_primary_selection — client writes to the
|
||||||
|
* primary selection buffer (e.g. by selecting text). Forward to
|
||||||
|
* wlr_seat so middle-click paste works in other clients.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
handle_seat_request_primary_selection(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
(void)listener;
|
||||||
|
struct wlr_seat_request_set_primary_selection_event *ev = data;
|
||||||
|
if (!wl_state.seat)
|
||||||
|
return;
|
||||||
|
wlr_seat_set_primary_selection(wl_state.seat, ev->source, ev->serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 28: idle_inhibit new_inhibitor — a client (e.g. mpv, a game) created
|
||||||
|
* an idle-inhibit object. wlroots tracks the inhibitor list internally;
|
||||||
|
* the compositor can query wl_state.idle_inhibit_mgr->inhibitors to decide
|
||||||
|
* whether to suppress screen blanking. For now we just log the event so
|
||||||
|
* the capability is advertised and the inhibitor object doesn't error out.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
handle_idle_new_inhibitor(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
(void)listener;
|
||||||
|
struct wlr_idle_inhibitor_v1 *inhibitor = data;
|
||||||
|
(void)inhibitor;
|
||||||
|
wwarning("wl_backend: idle inhibitor created (client suppressing screen blank)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 29 (fix): scroll-wheel axis event handler.
|
||||||
|
* wlr_event_pointer_axis carries orientation (vertical/horizontal), delta,
|
||||||
|
* delta_discrete (notches), and source (wheel vs finger). Forward directly
|
||||||
|
* to the seat so the focused Wayland client receives wl_pointer.axis events.
|
||||||
|
* Without this, scrolling is silently dropped in every Wayland client.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
handle_pointer_axis(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
(void)listener;
|
||||||
|
struct wlr_pointer_axis_event *ev = data;
|
||||||
|
if (!wl_state.seat)
|
||||||
|
return;
|
||||||
|
/* Drop axis events during a compositor grab so the grabbed window
|
||||||
|
* does not receive unexpected scroll events mid-move/resize. */
|
||||||
|
if (wl_state.grab_type)
|
||||||
|
return;
|
||||||
|
wlr_seat_pointer_notify_axis(wl_state.seat,
|
||||||
|
ev->time_msec,
|
||||||
|
ev->orientation,
|
||||||
|
ev->delta,
|
||||||
|
ev->delta_discrete,
|
||||||
|
ev->source,
|
||||||
|
ev->relative_direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 30: new pointer constraint — a client requested pointer lock or
|
||||||
|
* pointer confinement (e.g. a game locking the cursor to its window).
|
||||||
|
* We activate the constraint immediately so the client gets confirmed.
|
||||||
|
* In headless mode the pointer is virtual so there is nothing physically
|
||||||
|
* to lock, but activating keeps the client happy.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
handle_new_pointer_constraint(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
(void)listener;
|
||||||
|
struct wlr_pointer_constraint_v1 *constraint = data;
|
||||||
|
(void)constraint;
|
||||||
|
/* Activate immediately — in nested mode the real pointer is bounded
|
||||||
|
* by the host compositor's window anyway. */
|
||||||
|
wlr_pointer_constraint_v1_send_activated(constraint);
|
||||||
|
wwarning("wl_backend: pointer constraint activated");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 31: new keyboard shortcuts inhibitor — a fullscreen app or remote
|
||||||
|
* desktop client wants to suppress WM keyboard shortcuts.
|
||||||
|
* Activate the inhibitor immediately so the client knows it is granted.
|
||||||
|
* The existing wWaylandKeyPress() dispatcher in handle_keyboard_key already
|
||||||
|
* forwards all non-shortcut keys; with the inhibitor active we should skip
|
||||||
|
* the shortcut check for that focused client. For now we simply activate
|
||||||
|
* and log; per-client inhibitor tracking can be refined later.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
handle_new_shortcuts_inhibitor(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
(void)listener;
|
||||||
|
struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor = data;
|
||||||
|
wlr_keyboard_shortcuts_inhibitor_v1_activate(inhibitor);
|
||||||
|
wwarning("wl_backend: keyboard shortcuts inhibitor activated");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_pointer_button(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
(void)listener;
|
||||||
|
struct wlr_pointer_button_event *ev = data;
|
||||||
|
if (!wl_state.seat)
|
||||||
|
return;
|
||||||
|
/* Phase 22: any button release ends an active compositor grab (move/resize).
|
||||||
|
* Type 3 (WM policy grab) is NOT ended here — the policy code calls
|
||||||
|
* pointer_ungrab itself after processing the button release event. */
|
||||||
|
if (wl_state.grab_type && wl_state.grab_type != 3 &&
|
||||||
|
ev->state == WLR_BUTTON_RELEASED) {
|
||||||
|
wwarning("wl_backend: grab ended (button release) grab_type=%d", wl_state.grab_type);
|
||||||
|
wl_grab_end();
|
||||||
|
wl_update_pointer_focus(ev->time_msec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Phase 24: click-to-focus — on button press, find the view under the
|
||||||
|
* pointer and focus + raise it via the WM policy layer.
|
||||||
|
* This mirrors what the X11 backend does via ButtonPress on frame windows. */
|
||||||
|
if (ev->state == WLR_BUTTON_PRESSED) {
|
||||||
|
double sx, sy;
|
||||||
|
struct wl_toplevel_view *view = NULL;
|
||||||
|
view_surface_at(wl_state.pointer_x, wl_state.pointer_y,
|
||||||
|
&sx, &sy, &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;
|
||||||
|
WScreen *scr = wScreenWithNumber(0);
|
||||||
|
wSetFocusTo(scr, wwin);
|
||||||
|
/* Raise entire window assembly via tree */
|
||||||
|
if (view->frame_id) {
|
||||||
|
struct wl_frame_buf *fb = frame_buf_find(view->frame_id);
|
||||||
|
if (fb && fb->tree)
|
||||||
|
wlr_scene_node_raise_to_top(&fb->tree->node);
|
||||||
|
} else if (view->scene_node) {
|
||||||
|
wlr_scene_node_raise_to_top(&view->scene_node->node);
|
||||||
|
}
|
||||||
|
/* Also raise it in our toplevel list so view_surface_at()
|
||||||
|
* returns it first on subsequent hits. */
|
||||||
|
wl_list_remove(&view->link);
|
||||||
|
wl_list_insert(&wl_state.toplevel_list, &view->link);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* No toplevel surface — check if a WINGs dialog frame_buf was clicked */
|
||||||
|
struct wl_frame_buf *hit = frame_buf_hit(wl_state.pointer_x,
|
||||||
|
wl_state.pointer_y);
|
||||||
|
if (hit) {
|
||||||
|
/* Walk up to the parent frame to find the WWindow */
|
||||||
|
WNativeWindow lookup = hit->parent_id ? hit->parent_id : hit->id;
|
||||||
|
WObjDescriptor *desc =
|
||||||
|
wm_backend->context_find(lookup, WM_CTX_CLIENT_WIN);
|
||||||
|
if (desc && desc->parent_type == WCLASS_WINDOW) {
|
||||||
|
WWindow *wwin = (WWindow *)desc->parent;
|
||||||
|
WScreen *scr = wScreenWithNumber(0);
|
||||||
|
wSetFocusTo(scr, wwin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Phase A: enqueue native WMEvent for WINGs */
|
||||||
|
WMScreen *wmscr = wl_get_wmscreen();
|
||||||
|
if (wmscr) {
|
||||||
|
WMEvent wev;
|
||||||
|
memset(&wev, 0, sizeof(wev));
|
||||||
|
wev.type = (ev->state == WLR_BUTTON_PRESSED)
|
||||||
|
? WME_BUTTON_PRESS : WME_BUTTON_RELEASE;
|
||||||
|
|
||||||
|
/* Hit-test: determine which WM window was clicked.
|
||||||
|
* Use frame_buf_hit so button sub-windows (invisible to the scene
|
||||||
|
* graph because their pixels are composited into the titlebar buffer)
|
||||||
|
* are resolved to their own window IDs, letting handleButtonPress
|
||||||
|
* route the event to buttonMouseDown instead of titlebarMouseDown. */
|
||||||
|
struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x,
|
||||||
|
wl_state.pointer_y);
|
||||||
|
if (fb) {
|
||||||
|
wev.window = fb->id;
|
||||||
|
wev.u.button.window = fb->id;
|
||||||
|
wev.u.button.x = wl_state.pointer_x - fb->x;
|
||||||
|
wev.u.button.y = wl_state.pointer_y - fb->y;
|
||||||
|
} else {
|
||||||
|
WScreen *scr0 = wScreenWithNumber(0);
|
||||||
|
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
|
||||||
|
wev.window = root;
|
||||||
|
wev.u.button.window = root;
|
||||||
|
wev.u.button.x = wl_state.pointer_x;
|
||||||
|
wev.u.button.y = wl_state.pointer_y;
|
||||||
|
}
|
||||||
|
wev.u.button.time = ev->time_msec;
|
||||||
|
wev.u.button.x_root = wl_state.pointer_x;
|
||||||
|
wev.u.button.y_root = wl_state.pointer_y;
|
||||||
|
/* Linux evdev BTN_LEFT=0x110, BTN_RIGHT=0x111, BTN_MIDDLE=0x112
|
||||||
|
* Button1=1(left), Button2=2(middle), Button3=3(right) */
|
||||||
|
switch (ev->button) {
|
||||||
|
case 0x110: wev.u.button.button = 1; break;
|
||||||
|
case 0x111: wev.u.button.button = 3; break;
|
||||||
|
case 0x112: wev.u.button.button = 2; break;
|
||||||
|
default: wev.u.button.button = (ev->button - 0x110) + 1; break;
|
||||||
|
}
|
||||||
|
/* For WINGs views, resolve the child widget at click coordinates */
|
||||||
|
struct W_View *target = 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) {
|
||||||
|
target = W_FindViewAtPoint(toplevel,
|
||||||
|
wev.u.button.x, wev.u.button.y);
|
||||||
|
if (!target)
|
||||||
|
target = toplevel;
|
||||||
|
/* Adjust event coordinates to target view's local space */
|
||||||
|
if (target != toplevel) {
|
||||||
|
W_View *p = target;
|
||||||
|
int ox = 0, oy = 0;
|
||||||
|
while (p && p != toplevel) {
|
||||||
|
ox += p->pos.x;
|
||||||
|
oy += p->pos.y;
|
||||||
|
p = p->parent;
|
||||||
|
}
|
||||||
|
wev.u.button.x -= ox;
|
||||||
|
wev.u.button.y -= oy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
W_WL_EnqueueEvent(wmscr, &wev, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Refresh pointer focus before delivering button event.
|
||||||
|
* The last wl_update_pointer_focus call was during the most recent
|
||||||
|
* motion event. If no motion happened since then, the XWayland
|
||||||
|
* surface might not have pointer focus, causing
|
||||||
|
* wlr_seat_pointer_notify_button to be a no-op. */
|
||||||
|
wl_update_pointer_focus(ev->time_msec);
|
||||||
|
|
||||||
|
wlr_seat_pointer_notify_button(wl_state.seat, ev->time_msec,
|
||||||
|
ev->button, ev->state);
|
||||||
|
wlr_seat_pointer_notify_frame(wl_state.seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_pointer_frame(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
(void)listener; (void)data;
|
||||||
|
if (wl_state.seat)
|
||||||
|
wlr_seat_pointer_notify_frame(wl_state.seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Keyboard grabs */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Screen internals */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
int wl_screen_replace_wm(WScreen *scr) { (void)scr; return 1; }
|
||||||
Loading…
Reference in New Issue