wings(wayland-client): wl_shm buffers + xdg_toplevel surfaces
Tasks 3 + 4. wclient_wl.c grows a memfd+mmap-backed wl_shm buffer allocator that wraps the mapped region as a pixman_image_t. Painting into the pixman image writes directly into the buffer the compositor will read on commit, so no copy is needed. wl_buffer.release marks the buffer as released for future reuse (currently we just realloc on resize, so the flag is informational). Each top-level W_View now acquires a WLClientToplevel with a wl_surface, xdg_surface, and xdg_toplevel. The first xdg_surface.configure event acks and attaches the buffer; subsequent configures with non-zero dimensions realloc the backing. xdg_toplevel.close sets a want_close flag (closure event synthesis is in the next pass). wview_wl.c now calls three function-pointer hooks for top-level views: W_WLClientToplevelRealizeFn(view, w, h) -> pixman_image_t * W_WLClientToplevelResizeFn(view, w, h) W_WLClientToplevelDestroyFn(view) When the hooks are NULL (compositor-internal mode or X11), wview_wl.c falls back to plain pixman_image_create_bits — preserving every existing behaviour. When wclient_wl.c installs them, the same paints end up on a wl_shm buffer attached to a real Wayland surface. W_ViewCommitBackingFn and W_ViewDestroyBackingFn are also installed by W_WLClientInit so wview_wl.c's existing redisplay/destroy plumbing drives wl_surface_attach / damage / commit / surface destruction. No input handling yet; that's task 5.
This commit is contained in:
parent
12ae1e48fb
commit
97b2d03a34
|
|
@ -509,6 +509,15 @@ void W_WL_SetLoopDispatch(struct W_Screen *scr,
|
|||
Bool W_WLClientInit(struct W_Screen *scrPtr, const char *display);
|
||||
void W_WLClientShutdown(struct W_Screen *scrPtr);
|
||||
|
||||
/* Hooks set by wclient_wl.c (Wayland-client mode) so that wview_wl.c
|
||||
* routes top-level view backing creation/resize/destroy through the
|
||||
* libwayland-client surface management. When NULL (compositor mode
|
||||
* or X11), the default pixman allocation path runs. */
|
||||
struct W_View;
|
||||
extern void *(*W_WLClientToplevelRealizeFn)(struct W_View *view, int width, int height);
|
||||
extern void (*W_WLClientToplevelResizeFn)(struct W_View *view, int width, int height);
|
||||
extern void (*W_WLClientToplevelDestroyFn)(struct W_View *view);
|
||||
|
||||
|
||||
/* ---[ wfont.c ]--------------------------------------------------------- */
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include <pixman.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
|
@ -67,6 +69,409 @@ typedef struct WLClientCtx {
|
|||
struct W_Screen *scr;
|
||||
} WLClientCtx;
|
||||
|
||||
/* Storage for the active context — for now we only support one screen. */
|
||||
static WLClientCtx *g_wlclient_ctx = NULL;
|
||||
|
||||
/* Forward decl — defined in wview_wl.c */
|
||||
extern void W_SetViewBacking(Window id, void *img);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* wl_shm-backed buffer allocator */
|
||||
/* */
|
||||
/* A WLClientShmBuffer pairs a wl_buffer with the pixman_image_t that */
|
||||
/* shares the same memfd-mapped region. Painting into the pixman */
|
||||
/* image touches the same memory the compositor will read on commit, */
|
||||
/* so no copy is needed. wl_buffer.release marks the buffer as */
|
||||
/* available for reuse — the surface code may then double-buffer if */
|
||||
/* it wants, or re-attach the same buffer. */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
typedef struct WLClientShmBuffer {
|
||||
struct wl_buffer *wl_buf;
|
||||
pixman_image_t *image;
|
||||
void *map;
|
||||
size_t map_size;
|
||||
int width;
|
||||
int height;
|
||||
int stride; /* bytes per row */
|
||||
int busy; /* 1 = still owned by compositor */
|
||||
} WLClientShmBuffer;
|
||||
|
||||
static void
|
||||
shm_buffer_release(void *data, struct wl_buffer *wl_buf)
|
||||
{
|
||||
(void)wl_buf;
|
||||
WLClientShmBuffer *b = data;
|
||||
if (b) b->busy = 0;
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener shm_buffer_listener = {
|
||||
.release = shm_buffer_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* Create an anonymous, sealed memfd of the given size. We use memfd_create
|
||||
* with MFD_CLOEXEC because shm_open + unlink is slower and the resulting
|
||||
* file lingers in /dev/shm. This requires Linux >= 3.17, kernel default
|
||||
* everywhere we care about.
|
||||
*/
|
||||
static int
|
||||
shm_create_memfd(size_t size)
|
||||
{
|
||||
int fd = memfd_create("wings-wl-shm", MFD_CLOEXEC);
|
||||
if (fd < 0) return -1;
|
||||
if (ftruncate(fd, size) < 0) {
|
||||
int saved = errno;
|
||||
close(fd);
|
||||
errno = saved;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static WLClientShmBuffer *
|
||||
wlclient_create_shm_buffer(WLClientCtx *ctx, int width, int height)
|
||||
{
|
||||
if (!ctx || !ctx->shm || width <= 0 || height <= 0) return NULL;
|
||||
|
||||
int stride = width * 4; /* ARGB32, 4 bytes/pixel */
|
||||
size_t size = (size_t)stride * (size_t)height;
|
||||
int fd = shm_create_memfd(size);
|
||||
if (fd < 0) {
|
||||
wwarning(_("WINGs: memfd_create failed: %s"), strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (map == MAP_FAILED) {
|
||||
wwarning(_("WINGs: mmap of shm pool failed: %s"), strerror(errno));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wl_shm_pool *pool = wl_shm_create_pool(ctx->shm, fd, size);
|
||||
if (!pool) {
|
||||
munmap(map, size);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
/* WL_SHM_FORMAT_ARGB8888 matches PIXMAN_a8r8g8b8 byte-for-byte on
|
||||
* little-endian. WINGs is little-endian-only in practice. */
|
||||
struct wl_buffer *wl_buf = wl_shm_pool_create_buffer(pool, 0,
|
||||
width, height, stride, WL_SHM_FORMAT_ARGB8888);
|
||||
/* Pool can be destroyed immediately after creating the buffer; the
|
||||
* compositor keeps the fd mapping alive on its side. */
|
||||
wl_shm_pool_destroy(pool);
|
||||
/* The fd is duplicated by the compositor; we close ours. */
|
||||
close(fd);
|
||||
|
||||
if (!wl_buf) {
|
||||
munmap(map, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WLClientShmBuffer *b = wmalloc(sizeof(*b));
|
||||
memset(b, 0, sizeof(*b));
|
||||
b->wl_buf = wl_buf;
|
||||
b->map = map;
|
||||
b->map_size = size;
|
||||
b->width = width;
|
||||
b->height = height;
|
||||
b->stride = stride;
|
||||
b->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height,
|
||||
(uint32_t *)map, stride);
|
||||
if (!b->image) {
|
||||
wl_buffer_destroy(wl_buf);
|
||||
munmap(map, size);
|
||||
wfree(b);
|
||||
return NULL;
|
||||
}
|
||||
wl_buffer_add_listener(wl_buf, &shm_buffer_listener, b);
|
||||
return b;
|
||||
}
|
||||
|
||||
static void
|
||||
wlclient_destroy_shm_buffer(WLClientShmBuffer *b)
|
||||
{
|
||||
if (!b) return;
|
||||
if (b->image) pixman_image_unref(b->image);
|
||||
if (b->wl_buf) wl_buffer_destroy(b->wl_buf);
|
||||
if (b->map && b->map != MAP_FAILED) munmap(b->map, b->map_size);
|
||||
wfree(b);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Per-toplevel state */
|
||||
/* */
|
||||
/* One WLClientToplevel per top-level W_View. Holds the wl_surface, */
|
||||
/* xdg_surface, xdg_toplevel, and a single shm-backed buffer that */
|
||||
/* doubles as the view's pixman backing image. */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
typedef struct WLClientToplevel {
|
||||
WLClientCtx *ctx;
|
||||
struct W_View *view;
|
||||
|
||||
struct wl_surface *surface;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
|
||||
WLClientShmBuffer *buf; /* current backing */
|
||||
|
||||
int pending_w;
|
||||
int pending_h;
|
||||
int configured; /* received first xdg_surface.configure */
|
||||
int mapped; /* surface has at least one buffer */
|
||||
int want_close;
|
||||
} WLClientToplevel;
|
||||
|
||||
#define WLC_TOPTABLE_SIZE 128
|
||||
static struct {
|
||||
Window id;
|
||||
WLClientToplevel *top;
|
||||
} wlc_toptable[WLC_TOPTABLE_SIZE];
|
||||
|
||||
static void
|
||||
wlc_top_put(Window id, WLClientToplevel *top)
|
||||
{
|
||||
unsigned idx = ((unsigned)id) % WLC_TOPTABLE_SIZE;
|
||||
for (int i = 0; i < WLC_TOPTABLE_SIZE; i++) {
|
||||
unsigned slot = (idx + i) % WLC_TOPTABLE_SIZE;
|
||||
if (wlc_toptable[slot].id == 0 || wlc_toptable[slot].id == id) {
|
||||
wlc_toptable[slot].id = id;
|
||||
wlc_toptable[slot].top = top;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static WLClientToplevel *
|
||||
wlc_top_find(Window id)
|
||||
{
|
||||
unsigned idx = ((unsigned)id) % WLC_TOPTABLE_SIZE;
|
||||
for (int i = 0; i < WLC_TOPTABLE_SIZE; i++) {
|
||||
unsigned slot = (idx + i) % WLC_TOPTABLE_SIZE;
|
||||
if (wlc_toptable[slot].id == id) return wlc_toptable[slot].top;
|
||||
if (wlc_toptable[slot].id == 0) return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
wlc_top_remove(Window id)
|
||||
{
|
||||
unsigned idx = ((unsigned)id) % WLC_TOPTABLE_SIZE;
|
||||
for (int i = 0; i < WLC_TOPTABLE_SIZE; i++) {
|
||||
unsigned slot = (idx + i) % WLC_TOPTABLE_SIZE;
|
||||
if (wlc_toptable[slot].id == id) {
|
||||
wlc_toptable[slot].id = 0;
|
||||
wlc_toptable[slot].top = NULL;
|
||||
return;
|
||||
}
|
||||
if (wlc_toptable[slot].id == 0) return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Forward declarations */
|
||||
static void wl_client_toplevel_commit_locked(WLClientToplevel *top);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* xdg_surface listener */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void
|
||||
xdg_surface_handle_configure(void *data, struct xdg_surface *xs, uint32_t serial)
|
||||
{
|
||||
WLClientToplevel *top = data;
|
||||
xdg_surface_ack_configure(xs, serial);
|
||||
top->configured = 1;
|
||||
|
||||
/* If the compositor configured a new size, resize our backing.
|
||||
* (Pending size of 0 means "you decide" — keep current.) */
|
||||
if (top->pending_w > 0 && top->pending_h > 0 &&
|
||||
(top->pending_w != top->buf->width ||
|
||||
top->pending_h != top->buf->height)) {
|
||||
WLClientShmBuffer *nb =
|
||||
wlclient_create_shm_buffer(top->ctx, top->pending_w, top->pending_h);
|
||||
if (nb) {
|
||||
wlclient_destroy_shm_buffer(top->buf);
|
||||
top->buf = nb;
|
||||
/* Tell WINGs the backing pointer changed so subsequent
|
||||
* draws hit the new buffer. */
|
||||
W_SetViewBacking(top->view->window, nb->image);
|
||||
top->view->size.width = top->pending_w;
|
||||
top->view->size.height = top->pending_h;
|
||||
}
|
||||
}
|
||||
/* On the very first configure, attach the buffer and commit so
|
||||
* the surface becomes mapped. */
|
||||
wl_client_toplevel_commit_locked(top);
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
.configure = xdg_surface_handle_configure,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* xdg_toplevel listener */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void
|
||||
xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *xt,
|
||||
int32_t width, int32_t height,
|
||||
struct wl_array *states)
|
||||
{
|
||||
(void)xt; (void)states;
|
||||
WLClientToplevel *top = data;
|
||||
/* Width/height of 0 means the compositor leaves sizing to us. */
|
||||
top->pending_w = width > 0 ? width : top->buf ? top->buf->width : top->view->size.width;
|
||||
top->pending_h = height > 0 ? height : top->buf ? top->buf->height : top->view->size.height;
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xt)
|
||||
{
|
||||
(void)xt;
|
||||
WLClientToplevel *top = data;
|
||||
top->want_close = 1;
|
||||
/* TODO: synthesize a WMEvent close so the WINGs app can shut down
|
||||
* gracefully. For now we just exit on next event-loop turn. */
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_handle_configure_bounds(void *data, struct xdg_toplevel *xt,
|
||||
int32_t width, int32_t height)
|
||||
{
|
||||
(void)data; (void)xt; (void)width; (void)height;
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_handle_wm_capabilities(void *data, struct xdg_toplevel *xt,
|
||||
struct wl_array *capabilities)
|
||||
{
|
||||
(void)data; (void)xt; (void)capabilities;
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||
.configure = xdg_toplevel_handle_configure,
|
||||
.close = xdg_toplevel_handle_close,
|
||||
.configure_bounds = xdg_toplevel_handle_configure_bounds,
|
||||
.wm_capabilities = xdg_toplevel_handle_wm_capabilities,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Commit / realize / resize / destroy */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void
|
||||
wl_client_toplevel_commit_locked(WLClientToplevel *top)
|
||||
{
|
||||
if (!top || !top->configured || !top->buf || !top->buf->wl_buf)
|
||||
return;
|
||||
wl_surface_attach(top->surface, top->buf->wl_buf, 0, 0);
|
||||
wl_surface_damage_buffer(top->surface, 0, 0,
|
||||
top->buf->width, top->buf->height);
|
||||
wl_surface_commit(top->surface);
|
||||
top->buf->busy = 1;
|
||||
top->mapped = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_client_view_commit(unsigned long id)
|
||||
{
|
||||
WLClientToplevel *top = wlc_top_find((Window)id);
|
||||
if (top) wl_client_toplevel_commit_locked(top);
|
||||
}
|
||||
|
||||
static void
|
||||
wl_client_view_destroy_backing(unsigned long id)
|
||||
{
|
||||
WLClientToplevel *top = wlc_top_find((Window)id);
|
||||
if (!top) return;
|
||||
if (top->xdg_toplevel) xdg_toplevel_destroy(top->xdg_toplevel);
|
||||
if (top->xdg_surface) xdg_surface_destroy(top->xdg_surface);
|
||||
if (top->surface) wl_surface_destroy(top->surface);
|
||||
if (top->buf) wlclient_destroy_shm_buffer(top->buf);
|
||||
wlc_top_remove((Window)id);
|
||||
wfree(top);
|
||||
}
|
||||
|
||||
static void *
|
||||
wl_client_toplevel_realize(struct W_View *view, int width, int height)
|
||||
{
|
||||
WLClientCtx *ctx = g_wlclient_ctx;
|
||||
if (!ctx || !ctx->compositor || !ctx->wm_base) return NULL;
|
||||
|
||||
WLClientToplevel *top = wmalloc(sizeof(*top));
|
||||
memset(top, 0, sizeof(*top));
|
||||
top->ctx = ctx;
|
||||
top->view = view;
|
||||
top->pending_w = width;
|
||||
top->pending_h = height;
|
||||
|
||||
top->buf = wlclient_create_shm_buffer(ctx, width, height);
|
||||
if (!top->buf) goto fail;
|
||||
|
||||
top->surface = wl_compositor_create_surface(ctx->compositor);
|
||||
if (!top->surface) goto fail;
|
||||
|
||||
top->xdg_surface = xdg_wm_base_get_xdg_surface(ctx->wm_base, top->surface);
|
||||
if (!top->xdg_surface) goto fail;
|
||||
xdg_surface_add_listener(top->xdg_surface, &xdg_surface_listener, top);
|
||||
|
||||
top->xdg_toplevel = xdg_surface_get_toplevel(top->xdg_surface);
|
||||
if (!top->xdg_toplevel) goto fail;
|
||||
xdg_toplevel_add_listener(top->xdg_toplevel, &xdg_toplevel_listener, top);
|
||||
|
||||
/* Default app_id; the application can override via xdg_toplevel_set_app_id.
|
||||
* WPrefs and friends ought to call WMSetApplicationIconImage / set_title;
|
||||
* we'll plumb that next. */
|
||||
xdg_toplevel_set_app_id(top->xdg_toplevel, "WINGs");
|
||||
xdg_toplevel_set_title(top->xdg_toplevel, "WINGs Application");
|
||||
|
||||
/* Initial commit with no buffer so the compositor sends the first
|
||||
* configure. We attach a real buffer in the configure handler. */
|
||||
wl_surface_commit(top->surface);
|
||||
|
||||
/* view->window may not be assigned yet at this point — wl_realize sets
|
||||
* it AFTER allocating the backing. We register the toplevel under
|
||||
* view->window here using a deferred-association: the caller sets the
|
||||
* window field first. Actually wview_wl.c assigns view->window BEFORE
|
||||
* calling W_WLClientToplevelRealizeFn, so we can use it now. */
|
||||
wlc_top_put((Window)view->window, top);
|
||||
return top->buf->image;
|
||||
|
||||
fail:
|
||||
if (top->xdg_toplevel) xdg_toplevel_destroy(top->xdg_toplevel);
|
||||
if (top->xdg_surface) xdg_surface_destroy(top->xdg_surface);
|
||||
if (top->surface) wl_surface_destroy(top->surface);
|
||||
if (top->buf) wlclient_destroy_shm_buffer(top->buf);
|
||||
wfree(top);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_client_toplevel_resize(struct W_View *view, int width, int height)
|
||||
{
|
||||
WLClientToplevel *top = wlc_top_find((Window)view->window);
|
||||
if (!top) return;
|
||||
|
||||
if (top->buf && top->buf->width == width && top->buf->height == height)
|
||||
return;
|
||||
|
||||
WLClientShmBuffer *nb = wlclient_create_shm_buffer(top->ctx, width, height);
|
||||
if (!nb) return;
|
||||
if (top->buf) wlclient_destroy_shm_buffer(top->buf);
|
||||
top->buf = nb;
|
||||
W_SetViewBacking(view->window, nb->image);
|
||||
}
|
||||
|
||||
static void
|
||||
wl_client_toplevel_destroy(struct W_View *view)
|
||||
{
|
||||
wl_client_view_destroy_backing((unsigned long)view->window);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* xdg_wm_base ping */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
@ -171,9 +576,6 @@ wlclient_dispatch(int timeout_ms, void *userdata)
|
|||
/* Public API */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* Storage for the active context — for now we only support one screen. */
|
||||
static WLClientCtx *g_wlclient_ctx = NULL;
|
||||
|
||||
Bool
|
||||
W_WLClientInit(struct W_Screen *scrPtr, const char *display)
|
||||
{
|
||||
|
|
@ -212,6 +614,19 @@ W_WLClientInit(struct W_Screen *scrPtr, const char *display)
|
|||
wlclient_dispatch,
|
||||
ctx);
|
||||
|
||||
/* Wire surface lifecycle into wview_wl.c: top-level views will
|
||||
* acquire wl_surface + xdg_toplevel on realize, attach + commit on
|
||||
* paint, and tear down on destroy. */
|
||||
W_WLClientToplevelRealizeFn = wl_client_toplevel_realize;
|
||||
W_WLClientToplevelResizeFn = wl_client_toplevel_resize;
|
||||
W_WLClientToplevelDestroyFn = wl_client_toplevel_destroy;
|
||||
{
|
||||
extern void (*W_ViewCommitBackingFn)(unsigned long id);
|
||||
extern void (*W_ViewDestroyBackingFn)(unsigned long id);
|
||||
W_ViewCommitBackingFn = wl_client_view_commit;
|
||||
W_ViewDestroyBackingFn = wl_client_view_destroy_backing;
|
||||
}
|
||||
|
||||
g_wlclient_ctx = ctx;
|
||||
return True;
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,14 @@ static void wl_create_root(void *vctx, W_View *view)
|
|||
view->size.height = 1080;
|
||||
}
|
||||
|
||||
/* Optional hook set by wclient_wl.c (Wayland-client mode) so that
|
||||
* top-level views allocate their backing as wl_shm-mapped pixman images
|
||||
* paired with a wl_surface + xdg_toplevel. When NULL (compositor mode
|
||||
* or X11), wl_realize falls back to a free-floating pixman image. */
|
||||
void *(*W_WLClientToplevelRealizeFn)(W_View *view, int width, int height) = NULL;
|
||||
void (*W_WLClientToplevelResizeFn)(W_View *view, int width, int height) = NULL;
|
||||
void (*W_WLClientToplevelDestroyFn)(W_View *view) = NULL;
|
||||
|
||||
static void wl_realize(void *vctx, W_View *view)
|
||||
{
|
||||
(void)vctx;
|
||||
|
|
@ -163,7 +171,11 @@ static void wl_realize(void *vctx, W_View *view)
|
|||
/* Allocate a backing pixman image for this view */
|
||||
int w = view->size.width > 0 ? view->size.width : 1;
|
||||
int h = view->size.height > 0 ? view->size.height : 1;
|
||||
pixman_image_t *img = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0);
|
||||
pixman_image_t *img = NULL;
|
||||
if (view->flags.topLevel && W_WLClientToplevelRealizeFn)
|
||||
img = (pixman_image_t *)W_WLClientToplevelRealizeFn(view, w, h);
|
||||
if (!img)
|
||||
img = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0);
|
||||
W_SetViewBacking(view->window, img);
|
||||
}
|
||||
|
||||
|
|
@ -310,14 +322,21 @@ static void wl_resize(void *vctx, W_View *view, unsigned int w, unsigned int h)
|
|||
view->size.width = w;
|
||||
view->size.height = h;
|
||||
|
||||
/* Reallocate backing pixman buffer */
|
||||
pixman_image_t *old = (pixman_image_t *)W_GetViewBacking(view->window);
|
||||
if (old)
|
||||
pixman_image_unref(old);
|
||||
int bw = w > 0 ? (int)w : 1;
|
||||
int bh = h > 0 ? (int)h : 1;
|
||||
pixman_image_t *img = pixman_image_create_bits(PIXMAN_a8r8g8b8, bw, bh, NULL, 0);
|
||||
W_SetViewBacking(view->window, img);
|
||||
|
||||
if (view->flags.topLevel && W_WLClientToplevelResizeFn) {
|
||||
/* Wayland-client mode: backend swaps to a freshly allocated
|
||||
* shm-backed pixman image and updates the surface. */
|
||||
W_WLClientToplevelResizeFn(view, bw, bh);
|
||||
} else {
|
||||
/* Default path: free old image, allocate a new one. */
|
||||
pixman_image_t *old = (pixman_image_t *)W_GetViewBacking(view->window);
|
||||
if (old)
|
||||
pixman_image_unref(old);
|
||||
pixman_image_t *img = pixman_image_create_bits(PIXMAN_a8r8g8b8, bw, bh, NULL, 0);
|
||||
W_SetViewBacking(view->window, img);
|
||||
}
|
||||
|
||||
if (view->flags.mapped)
|
||||
wl_redisplay(vctx, view);
|
||||
|
|
@ -358,6 +377,8 @@ static void wl_destroy(void *vctx, W_View *view)
|
|||
{
|
||||
(void)vctx;
|
||||
W_WL_InvalidateView(view->screen, view);
|
||||
if (view->flags.topLevel && W_WLClientToplevelDestroyFn)
|
||||
W_WLClientToplevelDestroyFn(view);
|
||||
if (view->flags.topLevel && W_ViewDestroyBackingFn)
|
||||
W_ViewDestroyBackingFn((unsigned long)view->window);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue