decompose wl_backend.c: extract wl_client.c
This commit is contained in:
parent
36cdc48f23
commit
cbc9fa5a84
|
|
@ -163,7 +163,8 @@ wmaker_SOURCES += \
|
|||
backend/wayland/wl_stacking.c \
|
||||
backend/wayland/wl_overlay.c \
|
||||
backend/wayland/wl_window.c \
|
||||
backend/wayland/wl_props.c
|
||||
backend/wayland/wl_props.c \
|
||||
backend/wayland/wl_client.c
|
||||
endif
|
||||
|
||||
if USE_NESTED_FUNC
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ static int wl_catch_xwayland_error(Display *edpy, XErrorEvent *error);
|
|||
/* Phase 43: forward declaration — defined in the focus section below. */
|
||||
static void wl_focus_set(WNativeWindow win, int revert_to, unsigned long timestamp);
|
||||
/* Phase 50: forward declaration — defined in client section below. */
|
||||
static int wl_client_get_pid(WNativeWindow win);
|
||||
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);
|
||||
static void wl_pointer_warp_to(int x, int y);
|
||||
|
|
@ -4002,7 +4002,7 @@ static void frame_buf_end_data_ptr_access(struct wlr_buffer *wlr_buf)
|
|||
(void)wlr_buf;
|
||||
}
|
||||
|
||||
static const struct wlr_buffer_impl frame_buf_impl = {
|
||||
const struct wlr_buffer_impl frame_buf_impl = {
|
||||
.destroy = frame_buf_destroy,
|
||||
.begin_data_ptr_access = frame_buf_begin_data_ptr_access,
|
||||
.end_data_ptr_access = frame_buf_end_data_ptr_access,
|
||||
|
|
@ -4044,7 +4044,7 @@ static void fb_tree_destroy_handler(struct wl_listener *l, void *d)
|
|||
* will fire too and NULL fb->scene_buf separately. */
|
||||
wl_list_remove(&fb->tree_destroy.link);
|
||||
}
|
||||
static void fb_attach_scene_buf_listener(struct wl_frame_buf *fb)
|
||||
void fb_attach_scene_buf_listener(struct wl_frame_buf *fb)
|
||||
{
|
||||
if (!fb || !fb->scene_buf) return;
|
||||
fb->scene_buf_destroy.notify = fb_scene_buf_destroy_handler;
|
||||
|
|
@ -6276,473 +6276,6 @@ wl_noop_screen_get_head_usable_area(WScreen *scr, int head,
|
|||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Client */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int
|
||||
wl_window_get_client_attrs(WNativeWindow win, WClientAttributes *out)
|
||||
{
|
||||
/* Phase 42: return real map_state and geometry from XDG surface.
|
||||
* Phase 17: XWayland path uses xw_surface->mapped and width/height. */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
memset(out, 0, sizeof(*out));
|
||||
if (v && v->xw_surface) {
|
||||
if (v->xw_surface->surface) {
|
||||
out->map_state = WCLIENT_VIEWABLE;
|
||||
out->width = v->xw_surface->width >= 64 ? v->xw_surface->width : 640;
|
||||
out->height = v->xw_surface->height >= 64 ? v->xw_surface->height : 480;
|
||||
} else {
|
||||
out->map_state = WCLIENT_UNMAPPED;
|
||||
}
|
||||
} else if (v && v->xdg_surface && v->xdg_surface->surface) {
|
||||
out->map_state = WCLIENT_VIEWABLE;
|
||||
out->width = v->xdg_surface->surface->current.width;
|
||||
out->height = v->xdg_surface->surface->current.height;
|
||||
} else {
|
||||
out->map_state = WCLIENT_UNMAPPED;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_client_get_visual_attrs(WNativeWindow win, WClientVisual *out)
|
||||
{
|
||||
(void)win;
|
||||
out->depth = 24; out->visual = NULL; out->colormap = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_client_adopt_attributes(WNativeWindow win, unsigned long event_mask)
|
||||
{ (void)win; (void)event_mask; }
|
||||
|
||||
static void
|
||||
wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y)
|
||||
{
|
||||
/* Toplevel view reparented into a frame_buf — record the association
|
||||
* so wl_window_move can keep them in sync. */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(client);
|
||||
if (v) {
|
||||
v->frame_id = new_parent;
|
||||
v->frame_rel_x = x;
|
||||
v->frame_rel_y = y;
|
||||
/* Position the client surface relative to the frame */
|
||||
struct wl_frame_buf *parent_fb = frame_buf_find(new_parent);
|
||||
if (parent_fb) {
|
||||
v->x = parent_fb->x + x;
|
||||
v->y = parent_fb->y + y;
|
||||
if (v->scene_node) {
|
||||
/* Move client's scene tree under the frame's tree */
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_reparent(&v->scene_node->node, parent_fb->tree);
|
||||
/* Position at relative offset within the tree */
|
||||
wlr_scene_node_set_position(&v->scene_node->node, x, y);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For WINGs internal windows: create a child frame_buf so the dialog
|
||||
* content is visible in the scene graph. */
|
||||
if (client >= 0x20000000 && new_parent >= 0x10000000) {
|
||||
/* client is a WINGs view ID, new_parent is a frame_buf */
|
||||
struct wl_frame_buf *parent_fb = frame_buf_find(new_parent);
|
||||
if (!parent_fb) return;
|
||||
|
||||
/* Check if we already have a frame_buf for this client */
|
||||
struct wl_frame_buf *existing = frame_buf_find(client);
|
||||
if (existing) {
|
||||
/* Just update parent and position */
|
||||
existing->parent_id = new_parent;
|
||||
existing->rel_x = x;
|
||||
existing->rel_y = y;
|
||||
existing->x = parent_fb->x + x;
|
||||
existing->y = parent_fb->y + y;
|
||||
if (existing->scene_buf) {
|
||||
/* Ensure it's under the parent frame's tree, then position
|
||||
* at relative offset within the tree. */
|
||||
if (parent_fb->tree &&
|
||||
existing->scene_buf->node.parent != parent_fb->tree) {
|
||||
wlr_scene_node_reparent(&existing->scene_buf->node,
|
||||
parent_fb->tree);
|
||||
}
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_set_position(&existing->scene_buf->node, x, y);
|
||||
else
|
||||
wlr_scene_node_set_position(&existing->scene_buf->node,
|
||||
existing->x, existing->y);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a new frame_buf for this WINGs view.
|
||||
* Get size from the view itself. */
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
W_View *view = W_GetViewForWindow((unsigned long)client);
|
||||
int w = view ? view->size.width : parent_fb->width;
|
||||
int h = view ? view->size.height : (parent_fb->height - y);
|
||||
if (w <= 0) w = 1;
|
||||
if (h <= 0) h = 1;
|
||||
|
||||
struct wl_frame_buf *fb = wmalloc(sizeof(*fb));
|
||||
memset(fb, 0, sizeof(*fb));
|
||||
|
||||
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0);
|
||||
if (!fb->image) { wfree(fb); return; }
|
||||
|
||||
wlr_buffer_init(&fb->base, &frame_buf_impl, w, h);
|
||||
|
||||
fb->id = client; /* use the WINGs view ID directly */
|
||||
fb->parent_id = new_parent;
|
||||
fb->rel_x = x;
|
||||
fb->rel_y = y;
|
||||
fb->x = parent_fb->x + x;
|
||||
fb->y = parent_fb->y + y;
|
||||
fb->width = w;
|
||||
fb->height = h;
|
||||
|
||||
if (wl_state.scene) {
|
||||
/* Place the WINGs content under the parent frame's tree so it
|
||||
* moves with the WM-managed dialog decorations. */
|
||||
struct wlr_scene_tree *_wp = parent_fb->tree
|
||||
? parent_fb->tree
|
||||
: (wl_state.level_trees[WL_LAYER_FLOATING]
|
||||
? wl_state.level_trees[WL_LAYER_FLOATING]
|
||||
: &wl_state.scene->tree);
|
||||
fb->scene_buf = wlr_scene_buffer_create(_wp, &fb->base);
|
||||
if (fb->scene_buf) {
|
||||
fb_attach_scene_buf_listener(fb);
|
||||
/* If under the frame tree, use relative coords; otherwise absolute. */
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, x, y);
|
||||
else
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
||||
}
|
||||
}
|
||||
|
||||
wl_list_insert(&wl_state.frame_list, &fb->link);
|
||||
|
||||
/* Connect the WINGs view's backing store to this frame_buf's image */
|
||||
extern void W_SetViewBacking(unsigned long id, void *img);
|
||||
W_SetViewBacking((unsigned long)client, fb->image);
|
||||
}
|
||||
/* Reparent an existing frame_buf into a new parent */
|
||||
else if (client >= 0x10000000 && new_parent >= 0x10000000) {
|
||||
struct wl_frame_buf *fb = frame_buf_find(client);
|
||||
struct wl_frame_buf *parent_fb = frame_buf_find(new_parent);
|
||||
fprintf(stderr, "reparent_framebuf: client=0x%lx fb=%p new_parent=0x%lx parent_fb=%p\n",
|
||||
(unsigned long)client, (void*)fb,
|
||||
(unsigned long)new_parent, (void*)parent_fb);
|
||||
if (fb) fprintf(stderr, " fb: tree=%p scene_buf=%p pos=(%d,%d)\n",
|
||||
(void*)fb->tree, (void*)fb->scene_buf,
|
||||
fb->tree ? fb->tree->node.x : -1,
|
||||
fb->tree ? fb->tree->node.y : -1);
|
||||
if (parent_fb) fprintf(stderr, " parent_fb: tree=%p pos=(%d,%d)\n",
|
||||
(void*)parent_fb->tree,
|
||||
parent_fb->tree ? parent_fb->tree->node.x : -1,
|
||||
parent_fb->tree ? parent_fb->tree->node.y : -1);
|
||||
if (fb && parent_fb) {
|
||||
fb->parent_id = new_parent;
|
||||
fb->rel_x = x;
|
||||
fb->rel_y = y;
|
||||
fb->x = parent_fb->x + x;
|
||||
fb->y = parent_fb->y + y;
|
||||
if (fb->tree) {
|
||||
/* This frame_buf has a tree (e.g. fake_leader): reparent
|
||||
* the whole tree so all children move with it. */
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_reparent(&fb->tree->node, parent_fb->tree);
|
||||
wlr_scene_node_set_position(&fb->tree->node, x, y);
|
||||
} else if (fb->scene_buf) {
|
||||
/* Plain frame_buf (no tree): reparent scene_buf directly. */
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_reparent(&fb->scene_buf->node, parent_fb->tree);
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, x, y);
|
||||
}
|
||||
/* Update absolute tracking recursively for all descendants */
|
||||
frame_buf_update_children_abs(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Called by WINGs after a view repaints — commit its frame_buf to scene graph */
|
||||
void wl_view_commit_backing_impl(unsigned long id)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id);
|
||||
WNativeWindow saved_parent_id = 0;
|
||||
int saved_rel_x = 0, saved_rel_y = 0;
|
||||
/* If the view was resized, the old frame_buf's image is stale. */
|
||||
if (fb) {
|
||||
extern void *W_GetViewBacking(unsigned long id);
|
||||
void *current = W_GetViewBacking((unsigned long)id);
|
||||
if (current != (void *)fb->image) {
|
||||
/* Save parent relation before destroying — the new frame_buf
|
||||
* must be positioned within the same parent tree so dialog
|
||||
* content reparented via wl_client_reparent stays visible. */
|
||||
saved_parent_id = fb->parent_id;
|
||||
saved_rel_x = fb->rel_x;
|
||||
saved_rel_y = fb->rel_y;
|
||||
wlr_scene_node_destroy(&fb->scene_buf->node);
|
||||
wl_list_remove(&fb->link);
|
||||
wlr_buffer_drop(&fb->base);
|
||||
wfree(fb);
|
||||
fb = NULL;
|
||||
}
|
||||
}
|
||||
if (!fb) {
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
extern void *W_GetViewBacking(unsigned long id);
|
||||
W_View *view = W_GetViewForWindow((unsigned long)id);
|
||||
if (view && view->flags.topLevel) {
|
||||
fb = wmalloc(sizeof(*fb));
|
||||
memset(fb, 0, sizeof(*fb));
|
||||
fb->id = id;
|
||||
fb->parent_id = saved_parent_id;
|
||||
fb->rel_x = saved_rel_x;
|
||||
fb->rel_y = saved_rel_y;
|
||||
fb->x = view->pos.x;
|
||||
fb->y = view->pos.y;
|
||||
fb->width = view->size.width;
|
||||
fb->height = view->size.height;
|
||||
fb->image = (pixman_image_t *)W_GetViewBacking(id);
|
||||
if (fb->image) {
|
||||
pixman_image_ref(fb->image);
|
||||
wlr_buffer_init(&fb->base, &frame_buf_impl,
|
||||
pixman_image_get_width(fb->image),
|
||||
pixman_image_get_height(fb->image));
|
||||
if (wl_state.scene) {
|
||||
struct wlr_scene_tree *parent = NULL;
|
||||
/* Re-parent under the saved parent's tree so
|
||||
* dialogs reparented via wl_client_reparent stay
|
||||
* correctly positioned within their frame. */
|
||||
if (saved_parent_id) {
|
||||
struct wl_frame_buf *pfb =
|
||||
frame_buf_find(saved_parent_id);
|
||||
if (pfb && pfb->tree)
|
||||
parent = pfb->tree;
|
||||
}
|
||||
if (!parent)
|
||||
parent = wl_state.level_trees[WL_LAYER_FLOATING]
|
||||
? wl_state.level_trees[WL_LAYER_FLOATING]
|
||||
: &wl_state.scene->tree;
|
||||
fb->scene_buf = wlr_scene_buffer_create(parent, &fb->base);
|
||||
if (fb->scene_buf) {
|
||||
fb_attach_scene_buf_listener(fb);
|
||||
/* Position relative to parent's tree or absolute */
|
||||
if (parent != &wl_state.scene->tree && saved_parent_id)
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node,
|
||||
saved_rel_x, saved_rel_y);
|
||||
else
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node,
|
||||
fb->x, fb->y);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
||||
}
|
||||
}
|
||||
wl_list_insert(&wl_state.frame_list, &fb->link);
|
||||
} else {
|
||||
wfree(fb);
|
||||
fb = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fb && fb->scene_buf) {
|
||||
/* Sync position from the WINGs view — it may have moved since
|
||||
* the frame_buf was created (e.g. switch panel is positioned
|
||||
* after widget creation via WMMoveWidget).
|
||||
* When reparented (parent_id set), use the relative offset
|
||||
* instead of the view's absolute position. */
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
W_View *v = W_GetViewForWindow((unsigned long)id);
|
||||
if (v && !fb->parent_id) {
|
||||
if (fb->x != v->pos.x || fb->y != v->pos.y) {
|
||||
fb->x = v->pos.x;
|
||||
fb->y = v->pos.y;
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node,
|
||||
fb->x, fb->y);
|
||||
}
|
||||
}
|
||||
/* Only enable the scene node if the view is still mapped.
|
||||
* If the view was unmapped (e.g. move ended), wl_unmap disables
|
||||
* it via W_ViewSceneNodeSetEnabledFn — don't re-enable here. */
|
||||
if (!v || v->flags.mapped) {
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
wl_view_scene_node_set_enabled(unsigned long id, int enabled)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id);
|
||||
if (fb && fb->scene_buf)
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, !!enabled);
|
||||
}
|
||||
|
||||
|
||||
void wl_view_destroy_backing_impl(unsigned long id)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id);
|
||||
if (!fb) return;
|
||||
wl_list_remove(&fb->link);
|
||||
/* fb->scene_buf may have been auto-destroyed by wlroots already if a
|
||||
* parent tree was destroyed earlier (e.g. wl_frame_destroy on the
|
||||
* surrounding WMaker frame). The destroy listener NULLs scene_buf
|
||||
* in that case. */
|
||||
if (fb->scene_buf)
|
||||
wlr_scene_node_destroy(&fb->scene_buf->node);
|
||||
wlr_buffer_drop(&fb->base);
|
||||
}
|
||||
|
||||
static void
|
||||
wl_client_synth_configure(WNativeWindow client_win,
|
||||
int x, int y, int width, int height,
|
||||
int border_width, WNativeWindow above)
|
||||
{
|
||||
/* Phase 44: send an XDG configure with the new size to the client.
|
||||
* Phase 13: also record the WM-assigned position in the view so
|
||||
* pointer hit-testing (view_surface_at) uses current coordinates.
|
||||
* Phase 17: XWayland uses wlr_xwayland_surface_configure instead. */
|
||||
(void)border_width; (void)above;
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(client_win);
|
||||
if (!v) return;
|
||||
v->x = x;
|
||||
v->y = y;
|
||||
/* Update relative offset so frame_configure keeps us in sync. */
|
||||
if (v->frame_id) {
|
||||
struct wl_frame_buf *pfb = frame_buf_find(v->frame_id);
|
||||
if (pfb) {
|
||||
v->frame_rel_x = x - pfb->x;
|
||||
v->frame_rel_y = y - pfb->y;
|
||||
}
|
||||
/* Scene node is child of frame tree — use relative coords */
|
||||
if (v->scene_node)
|
||||
wlr_scene_node_set_position(&v->scene_node->node,
|
||||
v->frame_rel_x, v->frame_rel_y);
|
||||
} else {
|
||||
/* No frame — use absolute coords */
|
||||
if (v->scene_node)
|
||||
wlr_scene_node_set_position(&v->scene_node->node, x, y);
|
||||
}
|
||||
if (v->xw_surface) {
|
||||
wlr_xwayland_surface_configure(v->xw_surface,
|
||||
(int16_t)x, (int16_t)y,
|
||||
width > 0 ? (uint16_t)width : v->xw_surface->width,
|
||||
height > 0 ? (uint16_t)height : v->xw_surface->height);
|
||||
return;
|
||||
}
|
||||
if (!v->xdg_surface || !v->xdg_surface->toplevel) return;
|
||||
if (width > 0 && height > 0)
|
||||
wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)width, (uint32_t)height);
|
||||
wlr_xdg_surface_schedule_configure(v->xdg_surface);
|
||||
}
|
||||
|
||||
static void wl_client_add_to_save_set(WNativeWindow win) { (void)win; }
|
||||
static void wl_client_remove_from_save_set(WNativeWindow win) { (void)win; }
|
||||
|
||||
static void
|
||||
wl_client_close(WNativeWindow win)
|
||||
{
|
||||
/* Phase 46: ask the surface to close.
|
||||
* Phase 17: XWayland uses wlr_xwayland_surface_close. */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v) return;
|
||||
if (v->xw_surface) {
|
||||
wlr_xwayland_surface_close(v->xw_surface);
|
||||
} else if (v->xdg_surface && v->xdg_surface->toplevel) {
|
||||
wlr_xdg_toplevel_send_close(v->xdg_surface->toplevel);
|
||||
/* Flush so the in-process client receives the close event,
|
||||
* then dispatch so it processes it on this iteration. */
|
||||
wl_display_flush_clients(wl_state.display);
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_client_query_shaped(WNativeWindow win, int *shaped_out)
|
||||
{ (void)win; *shaped_out = 0; }
|
||||
|
||||
static int
|
||||
wl_client_get_gnustep_attrs(WNativeWindow win, GNUstepWMAttributes **attr_out)
|
||||
{ (void)win; *attr_out = NULL; return 0; }
|
||||
|
||||
static int wl_client_get_pid(WNativeWindow win)
|
||||
{
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v) return 0;
|
||||
/* Phase 17: XWayland surfaces have a direct pid field. */
|
||||
if (v->xw_surface)
|
||||
return (int)v->xw_surface->pid;
|
||||
if (!v->xdg_surface || !v->xdg_surface->resource)
|
||||
return 0;
|
||||
struct wl_client *client = wl_resource_get_client(v->xdg_surface->resource);
|
||||
if (!client) return 0;
|
||||
pid_t pid = 0; uid_t uid = 0; gid_t gid = 0;
|
||||
wl_client_get_credentials(client, &pid, &uid, &gid);
|
||||
return (int)pid;
|
||||
}
|
||||
|
||||
static RImage *
|
||||
wl_client_snapshot(WScreen *scr, WNativeWindow client_win, WNativeWindow frame_win)
|
||||
{
|
||||
(void)frame_win;
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(client_win);
|
||||
if (!v) return NULL;
|
||||
|
||||
/* XWayland: capture via XGetImage on the WM's X display */
|
||||
if (v->xw_surface && wl_state.x_display) {
|
||||
Window xid = (Window)v->xw_surface->window_id;
|
||||
XWindowAttributes attr;
|
||||
if (!XGetWindowAttributes(wl_state.x_display, xid, &attr))
|
||||
return NULL;
|
||||
XImage *img = XGetImage(wl_state.x_display, xid,
|
||||
0, 0, attr.width, attr.height,
|
||||
AllPlanes, ZPixmap);
|
||||
if (!img) return NULL;
|
||||
RImage *res = RCreateImageFromXImage(scr->rcontext, img, NULL);
|
||||
XDestroyImage(img);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Native Wayland: read pixels from last committed surface buffer */
|
||||
if (!v->xdg_surface || !v->xdg_surface->surface) return NULL;
|
||||
struct wlr_surface *s = v->xdg_surface->surface;
|
||||
if (!s->buffer) return NULL;
|
||||
struct wlr_buffer *buf = &s->buffer->base;
|
||||
|
||||
uint32_t fmt;
|
||||
void *data;
|
||||
size_t stride;
|
||||
if (!wlr_buffer_begin_data_ptr_access(buf, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &fmt, &stride))
|
||||
return NULL;
|
||||
|
||||
int w = s->current.width;
|
||||
int h = s->current.height;
|
||||
if (w <= 0 || h <= 0) {
|
||||
wlr_buffer_end_data_ptr_access(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create RImage and copy pixels (ARGB32 → RGBA byte order swap) */
|
||||
RImage *res = RCreateImage(w, h, True);
|
||||
if (res) {
|
||||
unsigned char *src = (unsigned char *)data;
|
||||
unsigned char *dst = res->data;
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int si = y * stride + x * 4;
|
||||
int di = (y * w + x) * 4;
|
||||
dst[di + 0] = src[si + 2]; /* B → R */
|
||||
dst[di + 1] = src[si + 1]; /* G → G */
|
||||
dst[di + 2] = src[si + 0]; /* R → B */
|
||||
dst[di + 3] = src[si + 3]; /* A → A */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wlr_buffer_end_data_ptr_access(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
wl_coords_translate(WNativeWindow src, WNativeWindow dst,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,489 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/xwayland.h>
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
#include "../../screen.h"
|
||||
#include "wl_types.h"
|
||||
#include <WINGs/WINGsP.h>
|
||||
|
||||
/* Forward declarations from sibling modules. */
|
||||
extern const struct wlr_buffer_impl frame_buf_impl;
|
||||
void fb_attach_scene_buf_listener(struct wl_frame_buf *fb);
|
||||
|
||||
struct wl_frame_buf *frame_buf_find(WNativeWindow id);
|
||||
struct wl_toplevel_view *wl_find_view_by_id(WNativeWindow id);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Client */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int
|
||||
wl_window_get_client_attrs(WNativeWindow win, WClientAttributes *out)
|
||||
{
|
||||
/* Phase 42: return real map_state and geometry from XDG surface.
|
||||
* Phase 17: XWayland path uses xw_surface->mapped and width/height. */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
memset(out, 0, sizeof(*out));
|
||||
if (v && v->xw_surface) {
|
||||
if (v->xw_surface->surface) {
|
||||
out->map_state = WCLIENT_VIEWABLE;
|
||||
out->width = v->xw_surface->width >= 64 ? v->xw_surface->width : 640;
|
||||
out->height = v->xw_surface->height >= 64 ? v->xw_surface->height : 480;
|
||||
} else {
|
||||
out->map_state = WCLIENT_UNMAPPED;
|
||||
}
|
||||
} else if (v && v->xdg_surface && v->xdg_surface->surface) {
|
||||
out->map_state = WCLIENT_VIEWABLE;
|
||||
out->width = v->xdg_surface->surface->current.width;
|
||||
out->height = v->xdg_surface->surface->current.height;
|
||||
} else {
|
||||
out->map_state = WCLIENT_UNMAPPED;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
wl_client_get_visual_attrs(WNativeWindow win, WClientVisual *out)
|
||||
{
|
||||
(void)win;
|
||||
out->depth = 24; out->visual = NULL; out->colormap = 0;
|
||||
}
|
||||
|
||||
void
|
||||
wl_client_adopt_attributes(WNativeWindow win, unsigned long event_mask)
|
||||
{ (void)win; (void)event_mask; }
|
||||
|
||||
void
|
||||
wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y)
|
||||
{
|
||||
/* Toplevel view reparented into a frame_buf — record the association
|
||||
* so wl_window_move can keep them in sync. */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(client);
|
||||
if (v) {
|
||||
v->frame_id = new_parent;
|
||||
v->frame_rel_x = x;
|
||||
v->frame_rel_y = y;
|
||||
/* Position the client surface relative to the frame */
|
||||
struct wl_frame_buf *parent_fb = frame_buf_find(new_parent);
|
||||
if (parent_fb) {
|
||||
v->x = parent_fb->x + x;
|
||||
v->y = parent_fb->y + y;
|
||||
if (v->scene_node) {
|
||||
/* Move client's scene tree under the frame's tree */
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_reparent(&v->scene_node->node, parent_fb->tree);
|
||||
/* Position at relative offset within the tree */
|
||||
wlr_scene_node_set_position(&v->scene_node->node, x, y);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For WINGs internal windows: create a child frame_buf so the dialog
|
||||
* content is visible in the scene graph. */
|
||||
if (client >= 0x20000000 && new_parent >= 0x10000000) {
|
||||
/* client is a WINGs view ID, new_parent is a frame_buf */
|
||||
struct wl_frame_buf *parent_fb = frame_buf_find(new_parent);
|
||||
if (!parent_fb) return;
|
||||
|
||||
/* Check if we already have a frame_buf for this client */
|
||||
struct wl_frame_buf *existing = frame_buf_find(client);
|
||||
if (existing) {
|
||||
/* Just update parent and position */
|
||||
existing->parent_id = new_parent;
|
||||
existing->rel_x = x;
|
||||
existing->rel_y = y;
|
||||
existing->x = parent_fb->x + x;
|
||||
existing->y = parent_fb->y + y;
|
||||
if (existing->scene_buf) {
|
||||
/* Ensure it's under the parent frame's tree, then position
|
||||
* at relative offset within the tree. */
|
||||
if (parent_fb->tree &&
|
||||
existing->scene_buf->node.parent != parent_fb->tree) {
|
||||
wlr_scene_node_reparent(&existing->scene_buf->node,
|
||||
parent_fb->tree);
|
||||
}
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_set_position(&existing->scene_buf->node, x, y);
|
||||
else
|
||||
wlr_scene_node_set_position(&existing->scene_buf->node,
|
||||
existing->x, existing->y);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a new frame_buf for this WINGs view.
|
||||
* Get size from the view itself. */
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
W_View *view = W_GetViewForWindow((unsigned long)client);
|
||||
int w = view ? view->size.width : parent_fb->width;
|
||||
int h = view ? view->size.height : (parent_fb->height - y);
|
||||
if (w <= 0) w = 1;
|
||||
if (h <= 0) h = 1;
|
||||
|
||||
struct wl_frame_buf *fb = wmalloc(sizeof(*fb));
|
||||
memset(fb, 0, sizeof(*fb));
|
||||
|
||||
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0);
|
||||
if (!fb->image) { wfree(fb); return; }
|
||||
|
||||
wlr_buffer_init(&fb->base, &frame_buf_impl, w, h);
|
||||
|
||||
fb->id = client; /* use the WINGs view ID directly */
|
||||
fb->parent_id = new_parent;
|
||||
fb->rel_x = x;
|
||||
fb->rel_y = y;
|
||||
fb->x = parent_fb->x + x;
|
||||
fb->y = parent_fb->y + y;
|
||||
fb->width = w;
|
||||
fb->height = h;
|
||||
|
||||
if (wl_state.scene) {
|
||||
/* Place the WINGs content under the parent frame's tree so it
|
||||
* moves with the WM-managed dialog decorations. */
|
||||
struct wlr_scene_tree *_wp = parent_fb->tree
|
||||
? parent_fb->tree
|
||||
: (wl_state.level_trees[WL_LAYER_FLOATING]
|
||||
? wl_state.level_trees[WL_LAYER_FLOATING]
|
||||
: &wl_state.scene->tree);
|
||||
fb->scene_buf = wlr_scene_buffer_create(_wp, &fb->base);
|
||||
if (fb->scene_buf) {
|
||||
fb_attach_scene_buf_listener(fb);
|
||||
/* If under the frame tree, use relative coords; otherwise absolute. */
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, x, y);
|
||||
else
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
||||
}
|
||||
}
|
||||
|
||||
wl_list_insert(&wl_state.frame_list, &fb->link);
|
||||
|
||||
/* Connect the WINGs view's backing store to this frame_buf's image */
|
||||
extern void W_SetViewBacking(unsigned long id, void *img);
|
||||
W_SetViewBacking((unsigned long)client, fb->image);
|
||||
}
|
||||
/* Reparent an existing frame_buf into a new parent */
|
||||
else if (client >= 0x10000000 && new_parent >= 0x10000000) {
|
||||
struct wl_frame_buf *fb = frame_buf_find(client);
|
||||
struct wl_frame_buf *parent_fb = frame_buf_find(new_parent);
|
||||
fprintf(stderr, "reparent_framebuf: client=0x%lx fb=%p new_parent=0x%lx parent_fb=%p\n",
|
||||
(unsigned long)client, (void*)fb,
|
||||
(unsigned long)new_parent, (void*)parent_fb);
|
||||
if (fb) fprintf(stderr, " fb: tree=%p scene_buf=%p pos=(%d,%d)\n",
|
||||
(void*)fb->tree, (void*)fb->scene_buf,
|
||||
fb->tree ? fb->tree->node.x : -1,
|
||||
fb->tree ? fb->tree->node.y : -1);
|
||||
if (parent_fb) fprintf(stderr, " parent_fb: tree=%p pos=(%d,%d)\n",
|
||||
(void*)parent_fb->tree,
|
||||
parent_fb->tree ? parent_fb->tree->node.x : -1,
|
||||
parent_fb->tree ? parent_fb->tree->node.y : -1);
|
||||
if (fb && parent_fb) {
|
||||
fb->parent_id = new_parent;
|
||||
fb->rel_x = x;
|
||||
fb->rel_y = y;
|
||||
fb->x = parent_fb->x + x;
|
||||
fb->y = parent_fb->y + y;
|
||||
if (fb->tree) {
|
||||
/* This frame_buf has a tree (e.g. fake_leader): reparent
|
||||
* the whole tree so all children move with it. */
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_reparent(&fb->tree->node, parent_fb->tree);
|
||||
wlr_scene_node_set_position(&fb->tree->node, x, y);
|
||||
} else if (fb->scene_buf) {
|
||||
/* Plain frame_buf (no tree): reparent scene_buf directly. */
|
||||
if (parent_fb->tree)
|
||||
wlr_scene_node_reparent(&fb->scene_buf->node, parent_fb->tree);
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, x, y);
|
||||
}
|
||||
/* Update absolute tracking recursively for all descendants */
|
||||
frame_buf_update_children_abs(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Called by WINGs after a view repaints — commit its frame_buf to scene graph */
|
||||
void wl_view_commit_backing_impl(unsigned long id)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id);
|
||||
WNativeWindow saved_parent_id = 0;
|
||||
int saved_rel_x = 0, saved_rel_y = 0;
|
||||
/* If the view was resized, the old frame_buf's image is stale. */
|
||||
if (fb) {
|
||||
extern void *W_GetViewBacking(unsigned long id);
|
||||
void *current = W_GetViewBacking((unsigned long)id);
|
||||
if (current != (void *)fb->image) {
|
||||
/* Save parent relation before destroying — the new frame_buf
|
||||
* must be positioned within the same parent tree so dialog
|
||||
* content reparented via wl_client_reparent stays visible. */
|
||||
saved_parent_id = fb->parent_id;
|
||||
saved_rel_x = fb->rel_x;
|
||||
saved_rel_y = fb->rel_y;
|
||||
wlr_scene_node_destroy(&fb->scene_buf->node);
|
||||
wl_list_remove(&fb->link);
|
||||
wlr_buffer_drop(&fb->base);
|
||||
wfree(fb);
|
||||
fb = NULL;
|
||||
}
|
||||
}
|
||||
if (!fb) {
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
extern void *W_GetViewBacking(unsigned long id);
|
||||
W_View *view = W_GetViewForWindow((unsigned long)id);
|
||||
if (view && view->flags.topLevel) {
|
||||
fb = wmalloc(sizeof(*fb));
|
||||
memset(fb, 0, sizeof(*fb));
|
||||
fb->id = id;
|
||||
fb->parent_id = saved_parent_id;
|
||||
fb->rel_x = saved_rel_x;
|
||||
fb->rel_y = saved_rel_y;
|
||||
fb->x = view->pos.x;
|
||||
fb->y = view->pos.y;
|
||||
fb->width = view->size.width;
|
||||
fb->height = view->size.height;
|
||||
fb->image = (pixman_image_t *)W_GetViewBacking(id);
|
||||
if (fb->image) {
|
||||
pixman_image_ref(fb->image);
|
||||
wlr_buffer_init(&fb->base, &frame_buf_impl,
|
||||
pixman_image_get_width(fb->image),
|
||||
pixman_image_get_height(fb->image));
|
||||
if (wl_state.scene) {
|
||||
struct wlr_scene_tree *parent = NULL;
|
||||
/* Re-parent under the saved parent's tree so
|
||||
* dialogs reparented via wl_client_reparent stay
|
||||
* correctly positioned within their frame. */
|
||||
if (saved_parent_id) {
|
||||
struct wl_frame_buf *pfb =
|
||||
frame_buf_find(saved_parent_id);
|
||||
if (pfb && pfb->tree)
|
||||
parent = pfb->tree;
|
||||
}
|
||||
if (!parent)
|
||||
parent = wl_state.level_trees[WL_LAYER_FLOATING]
|
||||
? wl_state.level_trees[WL_LAYER_FLOATING]
|
||||
: &wl_state.scene->tree;
|
||||
fb->scene_buf = wlr_scene_buffer_create(parent, &fb->base);
|
||||
if (fb->scene_buf) {
|
||||
fb_attach_scene_buf_listener(fb);
|
||||
/* Position relative to parent's tree or absolute */
|
||||
if (parent != &wl_state.scene->tree && saved_parent_id)
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node,
|
||||
saved_rel_x, saved_rel_y);
|
||||
else
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node,
|
||||
fb->x, fb->y);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
||||
}
|
||||
}
|
||||
wl_list_insert(&wl_state.frame_list, &fb->link);
|
||||
} else {
|
||||
wfree(fb);
|
||||
fb = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fb && fb->scene_buf) {
|
||||
/* Sync position from the WINGs view — it may have moved since
|
||||
* the frame_buf was created (e.g. switch panel is positioned
|
||||
* after widget creation via WMMoveWidget).
|
||||
* When reparented (parent_id set), use the relative offset
|
||||
* instead of the view's absolute position. */
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
W_View *v = W_GetViewForWindow((unsigned long)id);
|
||||
if (v && !fb->parent_id) {
|
||||
if (fb->x != v->pos.x || fb->y != v->pos.y) {
|
||||
fb->x = v->pos.x;
|
||||
fb->y = v->pos.y;
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node,
|
||||
fb->x, fb->y);
|
||||
}
|
||||
}
|
||||
/* Only enable the scene node if the view is still mapped.
|
||||
* If the view was unmapped (e.g. move ended), wl_unmap disables
|
||||
* it via W_ViewSceneNodeSetEnabledFn — don't re-enable here. */
|
||||
if (!v || v->flags.mapped) {
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
wl_view_scene_node_set_enabled(unsigned long id, int enabled)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id);
|
||||
if (fb && fb->scene_buf)
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, !!enabled);
|
||||
}
|
||||
|
||||
|
||||
void wl_view_destroy_backing_impl(unsigned long id)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id);
|
||||
if (!fb) return;
|
||||
wl_list_remove(&fb->link);
|
||||
/* fb->scene_buf may have been auto-destroyed by wlroots already if a
|
||||
* parent tree was destroyed earlier (e.g. wl_frame_destroy on the
|
||||
* surrounding WMaker frame). The destroy listener NULLs scene_buf
|
||||
* in that case. */
|
||||
if (fb->scene_buf)
|
||||
wlr_scene_node_destroy(&fb->scene_buf->node);
|
||||
wlr_buffer_drop(&fb->base);
|
||||
}
|
||||
|
||||
void
|
||||
wl_client_synth_configure(WNativeWindow client_win,
|
||||
int x, int y, int width, int height,
|
||||
int border_width, WNativeWindow above)
|
||||
{
|
||||
/* Phase 44: send an XDG configure with the new size to the client.
|
||||
* Phase 13: also record the WM-assigned position in the view so
|
||||
* pointer hit-testing (view_surface_at) uses current coordinates.
|
||||
* Phase 17: XWayland uses wlr_xwayland_surface_configure instead. */
|
||||
(void)border_width; (void)above;
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(client_win);
|
||||
if (!v) return;
|
||||
v->x = x;
|
||||
v->y = y;
|
||||
/* Update relative offset so frame_configure keeps us in sync. */
|
||||
if (v->frame_id) {
|
||||
struct wl_frame_buf *pfb = frame_buf_find(v->frame_id);
|
||||
if (pfb) {
|
||||
v->frame_rel_x = x - pfb->x;
|
||||
v->frame_rel_y = y - pfb->y;
|
||||
}
|
||||
/* Scene node is child of frame tree — use relative coords */
|
||||
if (v->scene_node)
|
||||
wlr_scene_node_set_position(&v->scene_node->node,
|
||||
v->frame_rel_x, v->frame_rel_y);
|
||||
} else {
|
||||
/* No frame — use absolute coords */
|
||||
if (v->scene_node)
|
||||
wlr_scene_node_set_position(&v->scene_node->node, x, y);
|
||||
}
|
||||
if (v->xw_surface) {
|
||||
wlr_xwayland_surface_configure(v->xw_surface,
|
||||
(int16_t)x, (int16_t)y,
|
||||
width > 0 ? (uint16_t)width : v->xw_surface->width,
|
||||
height > 0 ? (uint16_t)height : v->xw_surface->height);
|
||||
return;
|
||||
}
|
||||
if (!v->xdg_surface || !v->xdg_surface->toplevel) return;
|
||||
if (width > 0 && height > 0)
|
||||
wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)width, (uint32_t)height);
|
||||
wlr_xdg_surface_schedule_configure(v->xdg_surface);
|
||||
}
|
||||
|
||||
void wl_client_add_to_save_set(WNativeWindow win) { (void)win; }
|
||||
void wl_client_remove_from_save_set(WNativeWindow win) { (void)win; }
|
||||
|
||||
void
|
||||
wl_client_close(WNativeWindow win)
|
||||
{
|
||||
/* Phase 46: ask the surface to close.
|
||||
* Phase 17: XWayland uses wlr_xwayland_surface_close. */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v) return;
|
||||
if (v->xw_surface) {
|
||||
wlr_xwayland_surface_close(v->xw_surface);
|
||||
} else if (v->xdg_surface && v->xdg_surface->toplevel) {
|
||||
wlr_xdg_toplevel_send_close(v->xdg_surface->toplevel);
|
||||
/* Flush so the in-process client receives the close event,
|
||||
* then dispatch so it processes it on this iteration. */
|
||||
wl_display_flush_clients(wl_state.display);
|
||||
}
|
||||
}
|
||||
|
||||
void wl_client_query_shaped(WNativeWindow win, int *shaped_out)
|
||||
{ (void)win; *shaped_out = 0; }
|
||||
|
||||
int
|
||||
wl_client_get_gnustep_attrs(WNativeWindow win, GNUstepWMAttributes **attr_out)
|
||||
{ (void)win; *attr_out = NULL; return 0; }
|
||||
|
||||
int wl_client_get_pid(WNativeWindow win)
|
||||
{
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v) return 0;
|
||||
/* Phase 17: XWayland surfaces have a direct pid field. */
|
||||
if (v->xw_surface)
|
||||
return (int)v->xw_surface->pid;
|
||||
if (!v->xdg_surface || !v->xdg_surface->resource)
|
||||
return 0;
|
||||
struct wl_client *client = wl_resource_get_client(v->xdg_surface->resource);
|
||||
if (!client) return 0;
|
||||
pid_t pid = 0; uid_t uid = 0; gid_t gid = 0;
|
||||
wl_client_get_credentials(client, &pid, &uid, &gid);
|
||||
return (int)pid;
|
||||
}
|
||||
|
||||
RImage *
|
||||
wl_client_snapshot(WScreen *scr, WNativeWindow client_win, WNativeWindow frame_win)
|
||||
{
|
||||
(void)frame_win;
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(client_win);
|
||||
if (!v) return NULL;
|
||||
|
||||
/* XWayland: capture via XGetImage on the WM's X display */
|
||||
if (v->xw_surface && wl_state.x_display) {
|
||||
Window xid = (Window)v->xw_surface->window_id;
|
||||
XWindowAttributes attr;
|
||||
if (!XGetWindowAttributes(wl_state.x_display, xid, &attr))
|
||||
return NULL;
|
||||
XImage *img = XGetImage(wl_state.x_display, xid,
|
||||
0, 0, attr.width, attr.height,
|
||||
AllPlanes, ZPixmap);
|
||||
if (!img) return NULL;
|
||||
RImage *res = RCreateImageFromXImage(scr->rcontext, img, NULL);
|
||||
XDestroyImage(img);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Native Wayland: read pixels from last committed surface buffer */
|
||||
if (!v->xdg_surface || !v->xdg_surface->surface) return NULL;
|
||||
struct wlr_surface *s = v->xdg_surface->surface;
|
||||
if (!s->buffer) return NULL;
|
||||
struct wlr_buffer *buf = &s->buffer->base;
|
||||
|
||||
uint32_t fmt;
|
||||
void *data;
|
||||
size_t stride;
|
||||
if (!wlr_buffer_begin_data_ptr_access(buf, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &fmt, &stride))
|
||||
return NULL;
|
||||
|
||||
int w = s->current.width;
|
||||
int h = s->current.height;
|
||||
if (w <= 0 || h <= 0) {
|
||||
wlr_buffer_end_data_ptr_access(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create RImage and copy pixels (ARGB32 → RGBA byte order swap) */
|
||||
RImage *res = RCreateImage(w, h, True);
|
||||
if (res) {
|
||||
unsigned char *src = (unsigned char *)data;
|
||||
unsigned char *dst = res->data;
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int si = y * stride + x * 4;
|
||||
int di = (y * w + x) * 4;
|
||||
dst[di + 0] = src[si + 2]; /* B → R */
|
||||
dst[di + 1] = src[si + 1]; /* G → G */
|
||||
dst[di + 2] = src[si + 0]; /* R → B */
|
||||
dst[di + 3] = src[si + 3]; /* A → A */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wlr_buffer_end_data_ptr_access(buf);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -461,3 +461,17 @@ int wl_prop_has_wmaker_menu(WNativeWindow win);
|
|||
int wl_prop_has_gtk_object_path(WNativeWindow win);
|
||||
void wl_prop_set_wm_state(WNativeWindow win, const long *data, int n);
|
||||
int wl_prop_get_wm_state(WNativeWindow win, long **data_out);
|
||||
|
||||
/* Client module declarations (extracted to wl_client.c) */
|
||||
int wl_window_get_client_attrs(WNativeWindow win, WClientAttributes *out);
|
||||
void wl_client_get_visual_attrs(WNativeWindow win, WClientVisual *out);
|
||||
void wl_client_adopt_attributes(WNativeWindow win, unsigned long event_mask);
|
||||
void wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y);
|
||||
void wl_client_synth_configure(WNativeWindow client_win, int x, int y, int width, int height, int border_width, WNativeWindow above);
|
||||
void wl_client_add_to_save_set(WNativeWindow win);
|
||||
void wl_client_remove_from_save_set(WNativeWindow win);
|
||||
void wl_client_close(WNativeWindow win);
|
||||
void wl_client_query_shaped(WNativeWindow win, int *shaped_out);
|
||||
int wl_client_get_gnustep_attrs(WNativeWindow win, GNUstepWMAttributes **attr_out);
|
||||
int wl_client_get_pid(WNativeWindow win);
|
||||
RImage *wl_client_snapshot(WScreen *scr, WNativeWindow client_win, WNativeWindow frame_win);
|
||||
|
|
|
|||
Loading…
Reference in New Issue