decompose wl_backend.c: extract wl_grab.c

This commit is contained in:
Window Maker 2026-06-02 15:42:02 +02:00
parent b06e9417ca
commit 6df031f834
3 changed files with 207 additions and 213 deletions

View File

@ -186,7 +186,8 @@ wmaker_SOURCES += \
backend/wayland/wl_grabstate.c \
backend/wayland/wl_dragicon.c \
backend/wayland/wl_pointer_motion.c \
backend/wayland/wl_pointer_focus.c
backend/wayland/wl_pointer_focus.c \
backend/wayland/wl_grab.c
endif
if USE_NESTED_FUNC

View File

@ -350,6 +350,10 @@ static void handle_output_frame(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);
extern void wl_grab_begin_move(struct wl_toplevel_view *view);
extern void wl_grab_begin_resize(struct wl_toplevel_view *view, uint32_t edges);
extern void wl_grab_end(void);
extern const char *resize_edges_to_cursor(uint32_t edges);
/* Phase 41: look up the view for a given synthetic Window ID. */
struct wl_toplevel_view *
@ -415,219 +419,7 @@ wl_set_cursor_image(const char *name)
wlr_cursor_set_xcursor(wl_state.cursor, wl_state.xcursor_mgr, name);
}
/*
* Phase 23: map WL_SHELL_SURFACE_RESIZE_* edge bitmask to an xcursor name.
*/
static const char *
resize_edges_to_cursor(uint32_t edges)
{
switch (edges & (WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_BOTTOM |
WL_SHELL_SURFACE_RESIZE_LEFT | WL_SHELL_SURFACE_RESIZE_RIGHT)) {
case WL_SHELL_SURFACE_RESIZE_TOP: return "n-resize";
case WL_SHELL_SURFACE_RESIZE_BOTTOM: return "s-resize";
case WL_SHELL_SURFACE_RESIZE_LEFT: return "w-resize";
case WL_SHELL_SURFACE_RESIZE_RIGHT: return "e-resize";
case WL_SHELL_SURFACE_RESIZE_TOP_LEFT: return "nw-resize";
case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: return "ne-resize";
case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: return "sw-resize";
case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: return "se-resize";
default: return "se-resize";
}
}
/*
* Phase 22: interactive grab helpers.
*
* wl_grab_begin_move — called from handle_toplevel_request_move to start
* a compositor-side move grab. Records the pointer position and window
* origin so that subsequent motion events can compute the displacement.
*
* wl_grab_begin_resize — same for resize; additionally records the window
* size and the edge bitmask so we know which sides to stretch.
*
* wl_grab_end — clears the grab state (called on button release).
*
* wl_grab_apply_motion — called from both pointer motion handlers to
* update the window position or size while the grab is active.
*/
static void
wl_grab_end(void)
{
wl_state.grab_type = 0;
wl_state.grab_view = NULL;
/* Phase 23: restore default arrow cursor when grab ends. */
wl_set_cursor_image("left_ptr");
}
static void
wl_grab_begin_move(struct wl_toplevel_view *view)
{
int w, h;
if (!view) return;
/* Retrieve current window geometry. */
if (view->xw_surface) {
w = view->xw_surface->width;
h = view->xw_surface->height;
} else if (view->xdg_surface && view->xdg_surface->surface) {
w = view->xdg_surface->surface->current.width;
h = view->xdg_surface->surface->current.height;
} else { w = 1; h = 1; }
wl_state.grab_type = 1; /* MOVE */
wl_state.grab_view = view;
wl_state.grab_start_ptr_x = wl_state.pointer_x;
wl_state.grab_start_ptr_y = wl_state.pointer_y;
wl_state.grab_start_win_x = view->x;
wl_state.grab_start_win_y = view->y;
wl_state.grab_start_win_w = w;
wl_state.grab_start_win_h = h;
wwarning("wl_backend: move grab started for id=0x%lx at ptr=%d,%d win=%d,%d",
view->id, wl_state.pointer_x, wl_state.pointer_y, view->x, view->y);
/* Clear seat pointer focus so motion events are not delivered to the
* client while we are repositioning it. */
if (wl_state.seat)
wlr_seat_pointer_clear_focus(wl_state.seat);
/* Phase 23: show a move cursor during the grab. */
wl_set_cursor_image("fleur");
}
static void
wl_grab_begin_resize(struct wl_toplevel_view *view, uint32_t edges)
{
int w, h;
if (!view) return;
if (view->xw_surface) {
w = view->xw_surface->width;
h = view->xw_surface->height;
} else if (view->xdg_surface && view->xdg_surface->surface) {
w = view->xdg_surface->surface->current.width;
h = view->xdg_surface->surface->current.height;
} else { w = 1; h = 1; }
wl_state.grab_type = 2; /* RESIZE */
wl_state.grab_view = view;
wl_state.grab_start_ptr_x = wl_state.pointer_x;
wl_state.grab_start_ptr_y = wl_state.pointer_y;
wl_state.grab_start_win_x = view->x;
wl_state.grab_start_win_y = view->y;
wl_state.grab_start_win_w = w;
wl_state.grab_start_win_h = h;
wl_state.grab_resize_edges = edges;
wwarning("wl_backend: resize grab started for id=0x%lx edges=0x%x size=%dx%d",
view->id, edges, w, h);
if (wl_state.seat)
wlr_seat_pointer_clear_focus(wl_state.seat);
/* Phase 23: show an appropriate resize cursor during the grab. */
wl_set_cursor_image(resize_edges_to_cursor(edges));
}
/* Called from both pointer-motion handlers (relative + absolute). */
void
wl_grab_apply_motion(void)
{
if (!wl_state.grab_type || !wl_state.grab_view)
return;
struct wl_toplevel_view *v = wl_state.grab_view;
int dx = wl_state.pointer_x - wl_state.grab_start_ptr_x;
int dy = wl_state.pointer_y - wl_state.grab_start_ptr_y;
if (wl_state.grab_type == 1) {
/* MOVE: simply reposition the window. */
int nx = wl_state.grab_start_win_x + dx;
int ny = wl_state.grab_start_win_y + dy;
v->x = nx; v->y = ny;
if (v->frame_id) {
/* Framed window: move the frame tree. The client scene_node
* is a child of the tree and moves with it automatically. */
struct wl_frame_buf *fb = frame_buf_find(v->frame_id);
if (fb && fb->tree) {
int frame_x = nx - v->frame_rel_x;
int frame_y = ny - v->frame_rel_y;
fb->x = frame_x;
fb->y = frame_y;
wlr_scene_node_set_position(&fb->tree->node, frame_x, frame_y);
/* Update child absolute tracking */
struct wl_frame_buf *child;
wl_list_for_each(child, &wl_state.frame_list, link) {
if (child->parent_id == v->frame_id) {
child->x = fb->x + child->rel_x;
child->y = fb->y + child->rel_y;
}
}
}
} else if (v->scene_node) {
wlr_scene_node_set_position(&v->scene_node->node, nx, ny);
}
if (v->xw_surface)
wlr_xwayland_surface_configure(v->xw_surface,
(int16_t)nx, (int16_t)ny,
v->xw_surface->width, v->xw_surface->height);
} else if (wl_state.grab_type == 2) {
/* RESIZE: compute new size (and origin for left/top edges). */
uint32_t edges = wl_state.grab_resize_edges;
int nx = wl_state.grab_start_win_x;
int ny = wl_state.grab_start_win_y;
int nw = wl_state.grab_start_win_w;
int nh = wl_state.grab_start_win_h;
if (edges & WL_SHELL_SURFACE_RESIZE_RIGHT)
nw = wl_state.grab_start_win_w + dx;
if (edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
nw = wl_state.grab_start_win_w - dx;
nx = wl_state.grab_start_win_x + dx;
}
if (edges & WL_SHELL_SURFACE_RESIZE_BOTTOM)
nh = wl_state.grab_start_win_h + dy;
if (edges & WL_SHELL_SURFACE_RESIZE_TOP) {
nh = wl_state.grab_start_win_h - dy;
ny = wl_state.grab_start_win_y + dy;
}
if (nw < 32) { nw = 32; }
if (nh < 32) { nh = 32; }
/* Use wWindowConfigure to update the WM frame (titlebar/resizebar)
* along with the client surface. */
WObjDescriptor *desc = wm_backend->context_find(v->id, WM_CTX_CLIENT_WIN);
if (desc && desc->parent_type == WCLASS_WINDOW) {
WWindow *wwin = (WWindow *)desc->parent;
/* Ensure client scene_node is parented under frame tree */
if (v->scene_node && v->frame_id) {
struct wl_frame_buf *ffb = frame_buf_find(v->frame_id);
if (ffb && ffb->tree) {
if (v->scene_node->node.parent != ffb->tree) {
wwarning("REPARENT FIX: scene_node parent=%p tree=%p",
(void*)v->scene_node->node.parent, (void*)ffb->tree);
wlr_scene_node_reparent(&v->scene_node->node, ffb->tree);
wlr_scene_node_set_position(&v->scene_node->node,
v->frame_rel_x, v->frame_rel_y);
}
}
}
int frame_x = nx;
int frame_y = ny;
if (wwin->frame)
frame_y = ny - wwin->frame->top_width;
wWindowConfigure(wwin, frame_x, frame_y, nw, nh);
} else {
/* Fallback for unmanaged surfaces: direct scene manipulation. */
v->x = nx; v->y = ny;
if (v->scene_node)
wlr_scene_node_set_position(&v->scene_node->node, nx, ny);
if (v->xw_surface) {
wlr_xwayland_surface_configure(v->xw_surface,
(int16_t)nx, (int16_t)ny, (uint16_t)nw, (uint16_t)nh);
} else if (v->xdg_surface) {
wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)nw, (uint32_t)nh);
wlr_xdg_surface_schedule_configure(v->xdg_surface);
}
}
}
}
/*
* Phase 15/22: xdg_toplevel request_move — client requests interactive move.

View File

@ -0,0 +1,201 @@
#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_scene.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/xwayland.h>
#include <wlr/util/log.h>
#include "../../screen.h"
#include "window.h"
#include "wl_types.h"
#include <WINGs/WINGsP.h>
#include "../../framewin.h"
/* Forward declarations for functions defined in other wl_*.c files */
void wl_set_cursor_image(const char *name);
/* Map wlr_edges bitmask to xcursor name for interactive resize */
const char *
resize_edges_to_cursor(uint32_t edges)
{
switch (edges & (WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_BOTTOM |
WL_SHELL_SURFACE_RESIZE_LEFT | WL_SHELL_SURFACE_RESIZE_RIGHT)) {
case WL_SHELL_SURFACE_RESIZE_TOP: return "n-resize";
case WL_SHELL_SURFACE_RESIZE_BOTTOM: return "s-resize";
case WL_SHELL_SURFACE_RESIZE_LEFT: return "w-resize";
case WL_SHELL_SURFACE_RESIZE_RIGHT: return "e-resize";
case WL_SHELL_SURFACE_RESIZE_TOP_LEFT: return "nw-resize";
case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: return "ne-resize";
case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: return "sw-resize";
case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: return "se-resize";
default: return "se-resize";
}
}
/* Called from both pointer-motion handlers (relative + absolute). */
void
wl_grab_apply_motion(void)
{
if (!wl_state.grab_type || !wl_state.grab_view)
return;
struct wl_toplevel_view *v = wl_state.grab_view;
int dx = wl_state.pointer_x - wl_state.grab_start_ptr_x;
int dy = wl_state.pointer_y - wl_state.grab_start_ptr_y;
if (wl_state.grab_type == 1) {
/* MOVE: simply reposition the window. */
int nx = wl_state.grab_start_win_x + dx;
int ny = wl_state.grab_start_win_y + dy;
v->x = nx; v->y = ny;
if (v->frame_id) {
struct wl_frame_buf *fb = frame_buf_find(v->frame_id);
if (fb && fb->tree) {
int frame_x = nx - v->frame_rel_x;
int frame_y = ny - v->frame_rel_y;
fb->x = frame_x;
fb->y = frame_y;
wlr_scene_node_set_position(&fb->tree->node, frame_x, frame_y);
struct wl_frame_buf *child;
wl_list_for_each(child, &wl_state.frame_list, link) {
if (child->parent_id == v->frame_id) {
child->x = fb->x + child->rel_x;
child->y = fb->y + child->rel_y;
}
}
}
} else if (v->scene_node) {
wlr_scene_node_set_position(&v->scene_node->node, nx, ny);
}
if (v->xw_surface)
wlr_xwayland_surface_configure(v->xw_surface,
(int16_t)nx, (int16_t)ny,
v->xw_surface->width, v->xw_surface->height);
} else if (wl_state.grab_type == 2) {
uint32_t edges = wl_state.grab_resize_edges;
int nx = wl_state.grab_start_win_x;
int ny = wl_state.grab_start_win_y;
int nw = wl_state.grab_start_win_w;
int nh = wl_state.grab_start_win_h;
if (edges & WL_SHELL_SURFACE_RESIZE_RIGHT)
nw = wl_state.grab_start_win_w + dx;
if (edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
nw = wl_state.grab_start_win_w - dx;
nx = wl_state.grab_start_win_x + dx;
}
if (edges & WL_SHELL_SURFACE_RESIZE_BOTTOM)
nh = wl_state.grab_start_win_h + dy;
if (edges & WL_SHELL_SURFACE_RESIZE_TOP) {
nh = wl_state.grab_start_win_h - dy;
ny = wl_state.grab_start_win_y + dy;
}
if (nw < 32) { nw = 32; }
if (nh < 32) { nh = 32; }
WObjDescriptor *desc = wm_backend->context_find(v->id, WM_CTX_CLIENT_WIN);
if (desc && desc->parent_type == WCLASS_WINDOW) {
WWindow *wwin = (WWindow *)desc->parent;
if (v->scene_node && v->frame_id) {
struct wl_frame_buf *ffb = frame_buf_find(v->frame_id);
if (ffb && ffb->tree) {
if (v->scene_node->node.parent != ffb->tree) {
wlr_scene_node_reparent(&v->scene_node->node, ffb->tree);
wlr_scene_node_set_position(&v->scene_node->node,
v->frame_rel_x, v->frame_rel_y);
}
}
}
int frame_x = nx;
int frame_y = ny;
if (wwin->frame)
frame_y = ny - wwin->frame->top_width;
wWindowConfigure(wwin, frame_x, frame_y, nw, nh);
} else {
v->x = nx; v->y = ny;
if (v->scene_node)
wlr_scene_node_set_position(&v->scene_node->node, nx, ny);
if (v->xw_surface) {
wlr_xwayland_surface_configure(v->xw_surface,
(int16_t)nx, (int16_t)ny, (uint16_t)nw, (uint16_t)nh);
} else if (v->xdg_surface) {
wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)nw, (uint32_t)nh);
wlr_xdg_surface_schedule_configure(v->xdg_surface);
}
}
}
}
void
wl_grab_end(void)
{
wl_state.grab_type = 0;
wl_state.grab_view = NULL;
wl_set_cursor_image("left_ptr");
}
void
wl_grab_begin_move(struct wl_toplevel_view *view)
{
int w, h;
if (!view) return;
if (view->xw_surface) {
w = view->xw_surface->width;
h = view->xw_surface->height;
} else if (view->xdg_surface && view->xdg_surface->surface) {
w = view->xdg_surface->surface->current.width;
h = view->xdg_surface->surface->current.height;
} else { w = 1; h = 1; }
wl_state.grab_type = 1; /* MOVE */
wl_state.grab_view = view;
wl_state.grab_start_ptr_x = wl_state.pointer_x;
wl_state.grab_start_ptr_y = wl_state.pointer_y;
wl_state.grab_start_win_x = view->x;
wl_state.grab_start_win_y = view->y;
wl_state.grab_start_win_w = w;
wl_state.grab_start_win_h = h;
wwarning("wl_backend: move grab started for id=0x%lx at ptr=%d,%d win=%d,%d",
view->id, wl_state.pointer_x, wl_state.pointer_y, view->x, view->y);
if (wl_state.seat)
wlr_seat_pointer_clear_focus(wl_state.seat);
wl_set_cursor_image("fleur");
}
void
wl_grab_begin_resize(struct wl_toplevel_view *view, uint32_t edges)
{
int w, h;
if (!view) return;
if (view->xw_surface) {
w = view->xw_surface->width;
h = view->xw_surface->height;
} else if (view->xdg_surface && view->xdg_surface->surface) {
w = view->xdg_surface->surface->current.width;
h = view->xdg_surface->surface->current.height;
} else { w = 1; h = 1; }
wl_state.grab_type = 2; /* RESIZE */
wl_state.grab_view = view;
wl_state.grab_start_ptr_x = wl_state.pointer_x;
wl_state.grab_start_ptr_y = wl_state.pointer_y;
wl_state.grab_start_win_x = view->x;
wl_state.grab_start_win_y = view->y;
wl_state.grab_start_win_w = w;
wl_state.grab_start_win_h = h;
wl_state.grab_resize_edges = edges;
wwarning("wl_backend: resize grab started for id=0x%lx edges=0x%x size=%dx%d",
view->id, edges, w, h);
if (wl_state.seat)
wlr_seat_pointer_clear_focus(wl_state.seat);
wl_set_cursor_image(resize_edges_to_cursor(edges));
}