wl_backend: implement client_snapshot via buffer read (XWayland: XGetImage, native: wlr_buffer)

This commit is contained in:
Ollie 2026-05-28 22:56:39 +02:00
parent d548b2a1b0
commit 8a4e3954a0
2 changed files with 66 additions and 10 deletions

View File

@ -63,15 +63,13 @@ XWayland bridge auto-syncs. Needs verification.
### 1.4 Remaining Vtable Stubs
These vtable slots are stubs or partial implementations:
| Slot | Purpose | Needed For |
|------|---------|------------|
| `overlay_draw_*` | Pixman animation buffer | Iconify zoom animation |
| `client_snapshot` | Window thumbnail capture | Switch panel thumbnails, icon preview |
| `window_set_border` | Scene rect border nodes | Window borders |
| `client_synth_configure` | XDG configure scheduling | Resize negotiation |
| `pointer_change_grab` | Grab parameter update | Menu tracking |
| Slot | Status |
|------|--------|
| `overlay_draw_*` | ✅ Done — real pixman overlay implementation |
| `client_snapshot` | ❌ Stub — needs last-committed texture → RImage |
| `window_set_border` | ✅ No-op (borders drawn into frame buffer) |
| `client_synth_configure` | ✅ Done — XDG configure + XWayland configure |
| `pointer_change_grab` | ⚠️ No-op — menu tracking may need this |
---

View File

@ -7882,7 +7882,65 @@ static int wl_client_get_pid(WNativeWindow win)
static RImage *
wl_client_snapshot(WScreen *scr, WNativeWindow client_win, WNativeWindow frame_win)
{ (void)scr; (void)client_win; (void)frame_win; return NULL; }
{
(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,