decompose wl_backend.c: extract wl_shm.c

This commit is contained in:
Window Maker 2026-06-02 12:03:25 +02:00
parent e1c221948c
commit 5e5e4dbd02
4 changed files with 199 additions and 181 deletions

View File

@ -175,7 +175,8 @@ wmaker_SOURCES += \
backend/wayland/wl_extensions.c \
backend/wayland/wl_events.c \
backend/wayland/wl_focus.c \
backend/wayland/wl_screen.c
backend/wayland/wl_screen.c \
backend/wayland/wl_shm.c
endif
if USE_NESTED_FUNC

View File

@ -3320,186 +3320,6 @@ wl_event_loop_terminate(void)
}
}
/* ================================================================== */
/* Phase 29: WM-owned SHM surfaces (pixman rendering → wlroots scene) */
/* ================================================================== */
/*
* wm_shm_surface — a compositor-owned pixel buffer that plugs into the
* wlroots scene graph.
*
* Memory layout:
* wm_shm_surface embeds a wlr_buffer so wlroots can reference-count and
* upload its pixels as a GPU texture. The pixel array (ARGB8888) is
* malloc'd and wrapped by a pixman_image_t for drawing.
*
* Lifecycle:
* wm_shm_surface_create — alloc + pixman init
* wm_shm_surface_fill — draw into the pixman image (no upload yet)
* wm_shm_surface_commit — create/reposition the wlr_scene_buffer node
* wm_shm_surface_destroy — tear down scene node + drop wlr_buffer ref
* (shm_buf_destroy frees memory when ref = 0)
*
* Update model (Phase 29): surfaces are static after first commit.
* A re-draw path (drop + recreate scene node) will be added in Phase 30
* once the dock and title-bar code drives it.
*/
/* struct wm_shm_surface now in wl_types.h */
/* ---------- wlr_buffer implementation -------------------------------- */
static void
shm_buf_destroy(struct wlr_buffer *buf)
{
struct wm_shm_surface *s = wl_container_of(buf, s, wlr_buf);
if (s->image)
pixman_image_unref(s->image);
free(s->data);
free(s);
}
static bool
shm_buf_begin_data_ptr(struct wlr_buffer *buf, uint32_t flags,
void **out_data, uint32_t *out_fmt, size_t *out_stride)
{
struct wm_shm_surface *s = wl_container_of(buf, s, wlr_buf);
(void)flags;
*out_data = s->data;
*out_fmt = DRM_FORMAT_ARGB8888;
*out_stride = s->stride;
return true;
}
static void
shm_buf_end_data_ptr(struct wlr_buffer *buf)
{
(void)buf;
}
static const struct wlr_buffer_impl wm_shm_buf_impl = {
.destroy = shm_buf_destroy,
.begin_data_ptr_access = shm_buf_begin_data_ptr,
.end_data_ptr_access = shm_buf_end_data_ptr,
};
/* ---------- surface API ---------------------------------------------- */
struct wm_shm_surface *
wm_shm_surface_create(int width, int height)
{
if (width <= 0 || height <= 0)
return NULL;
struct wm_shm_surface *s = calloc(1, sizeof(*s));
if (!s)
return NULL;
s->width = width;
s->height = height;
s->stride = (size_t)width * 4;
s->data = calloc(1, (size_t)height * s->stride);
if (!s->data) {
free(s);
return NULL;
}
/* wlr_buffer init — producer holds one reference */
wlr_buffer_init(&s->wlr_buf, &wm_shm_buf_impl, width, height);
/* pixman image wrapping the same memory */
s->image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
width, height,
(uint32_t *)s->data,
(int)s->stride);
if (!s->image) {
/* wlr_buffer_drop triggers shm_buf_destroy → frees data + s */
wlr_buffer_drop(&s->wlr_buf);
return NULL;
}
return s;
}
/*
* Fill a rectangle with a solid ARGB colour.
* argb: 0xAARRGGBB — e.g. 0xFF4080C0 for opaque steel-blue.
*/
void
wm_shm_surface_fill(struct wm_shm_surface *s,
int x, int y, int w, int h,
uint32_t argb)
{
if (!s || !s->image)
return;
/* clamp to surface bounds */
if (x < 0) { w += x; x = 0; }
if (y < 0) { h += y; y = 0; }
if (x + w > s->width) w = s->width - x;
if (y + h > s->height) h = s->height - y;
if (w <= 0 || h <= 0)
return;
pixman_color_t c = {
.alpha = (uint16_t)(((argb >> 24) & 0xff) * 0x0101),
.red = (uint16_t)(((argb >> 16) & 0xff) * 0x0101),
.green = (uint16_t)(((argb >> 8) & 0xff) * 0x0101),
.blue = (uint16_t)(((argb >> 0) & 0xff) * 0x0101),
};
pixman_image_t *fill = pixman_image_create_solid_fill(&c);
if (!fill)
return;
pixman_image_composite32(PIXMAN_OP_SRC, fill, NULL, s->image,
0, 0, 0, 0, x, y, w, h);
pixman_image_unref(fill);
}
/*
* Commit the surface to the scene graph.
*
* parent — scene-graph parent node (e.g. &wl_state.scene->tree.node)
* x, y — position in the compositor coordinate space
*
* First call creates the scene_buffer node; subsequent calls just
* reposition it (pixel updates are uploaded lazily by wlroots on the
* next wlr_scene_output_commit).
*/
void
wm_shm_surface_commit(struct wm_shm_surface *s,
struct wlr_scene_tree *parent,
int x, int y)
{
if (!s)
return;
if (!s->scene_buf) {
s->scene_buf = wlr_scene_buffer_create(parent, &s->wlr_buf);
if (!s->scene_buf) {
wwarning("wm_shm_surface_commit: wlr_scene_buffer_create failed");
return;
}
wwarning("wl_backend: SHM surface %dx%d committed to scene at %d,%d",
s->width, s->height, x, y);
}
wlr_scene_node_set_position(&s->scene_buf->node, x, y);
}
/*
* Destroy a surface and remove it from the scene graph.
* After this call s is invalid — the memory is freed asynchronously
* by shm_buf_destroy once the scene node releases its lock.
*/
void
wm_shm_surface_destroy(struct wm_shm_surface *s)
{
if (!s)
return;
if (s->scene_buf) {
wlr_scene_node_destroy(&s->scene_buf->node);
s->scene_buf = NULL;
}
wlr_buffer_drop(&s->wlr_buf); /* producer done; shm_buf_destroy frees s */
}
/* ================================================================== */
/* Phase 30: WM dock panel (layer-anchored, pixman-rendered) */
/* ================================================================== */

View File

@ -0,0 +1,193 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/interfaces/wlr_buffer.h>
#include <libdrm/drm_fourcc.h>
#include <pixman.h>
#include "wl_types.h"
/* ================================================================== */
/* Phase 29: WM-owned SHM surfaces (pixman rendering → wlroots scene) */
/* ================================================================== */
/*
* wm_shm_surface — a compositor-owned pixel buffer that plugs into the
* wlroots scene graph.
*
* Memory layout:
* wm_shm_surface embeds a wlr_buffer so wlroots can reference-count and
* upload its pixels as a GPU texture. The pixel array (ARGB8888) is
* malloc'd and wrapped by a pixman_image_t for drawing.
*
* Lifecycle:
* wm_shm_surface_create — alloc + pixman init
* wm_shm_surface_fill — draw into the pixman image (no upload yet)
* wm_shm_surface_commit — create/reposition the wlr_scene_buffer node
* wm_shm_surface_destroy — tear down scene node + drop wlr_buffer ref
* (shm_buf_destroy frees memory when ref = 0)
*
* Update model (Phase 29): surfaces are static after first commit.
* A re-draw path (drop + recreate scene node) will be added in Phase 30
* once the dock and title-bar code drives it.
*/
/* struct wm_shm_surface now in wl_types.h */
/* ---------- wlr_buffer implementation -------------------------------- */
void
shm_buf_destroy(struct wlr_buffer *buf)
{
struct wm_shm_surface *s = wl_container_of(buf, s, wlr_buf);
if (s->image)
pixman_image_unref(s->image);
free(s->data);
free(s);
}
bool
shm_buf_begin_data_ptr(struct wlr_buffer *buf, uint32_t flags,
void **out_data, uint32_t *out_fmt, size_t *out_stride)
{
struct wm_shm_surface *s = wl_container_of(buf, s, wlr_buf);
(void)flags;
*out_data = s->data;
*out_fmt = DRM_FORMAT_ARGB8888;
*out_stride = s->stride;
return true;
}
void
shm_buf_end_data_ptr(struct wlr_buffer *buf)
{
(void)buf;
}
const struct wlr_buffer_impl wm_shm_buf_impl = {
.destroy = shm_buf_destroy,
.begin_data_ptr_access = shm_buf_begin_data_ptr,
.end_data_ptr_access = shm_buf_end_data_ptr,
};
/* ---------- surface API ---------------------------------------------- */
struct wm_shm_surface *
wm_shm_surface_create(int width, int height)
{
if (width <= 0 || height <= 0)
return NULL;
struct wm_shm_surface *s = calloc(1, sizeof(*s));
if (!s)
return NULL;
s->width = width;
s->height = height;
s->stride = (size_t)width * 4;
s->data = calloc(1, (size_t)height * s->stride);
if (!s->data) {
free(s);
return NULL;
}
/* wlr_buffer init — producer holds one reference */
wlr_buffer_init(&s->wlr_buf, &wm_shm_buf_impl, width, height);
/* pixman image wrapping the same memory */
s->image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
width, height,
(uint32_t *)s->data,
(int)s->stride);
if (!s->image) {
/* wlr_buffer_drop triggers shm_buf_destroy → frees data + s */
wlr_buffer_drop(&s->wlr_buf);
return NULL;
}
return s;
}
/*
* Fill a rectangle with a solid ARGB colour.
* argb: 0xAARRGGBB — e.g. 0xFF4080C0 for opaque steel-blue.
*/
void
wm_shm_surface_fill(struct wm_shm_surface *s,
int x, int y, int w, int h,
uint32_t argb)
{
if (!s || !s->image)
return;
/* clamp to surface bounds */
if (x < 0) { w += x; x = 0; }
if (y < 0) { h += y; y = 0; }
if (x + w > s->width) w = s->width - x;
if (y + h > s->height) h = s->height - y;
if (w <= 0 || h <= 0)
return;
pixman_color_t c = {
.alpha = (uint16_t)(((argb >> 24) & 0xff) * 0x0101),
.red = (uint16_t)(((argb >> 16) & 0xff) * 0x0101),
.green = (uint16_t)(((argb >> 8) & 0xff) * 0x0101),
.blue = (uint16_t)(((argb >> 0) & 0xff) * 0x0101),
};
pixman_image_t *fill = pixman_image_create_solid_fill(&c);
if (!fill)
return;
pixman_image_composite32(PIXMAN_OP_SRC, fill, NULL, s->image,
0, 0, 0, 0, x, y, w, h);
pixman_image_unref(fill);
}
/*
* Commit the surface to the scene graph.
*
* parent — scene-graph parent node (e.g. &wl_state.scene->tree.node)
* x, y — position in the compositor coordinate space
*
* First call creates the scene_buffer node; subsequent calls just
* reposition it (pixel updates are uploaded lazily by wlroots on the
* next wlr_scene_output_commit).
*/
void
wm_shm_surface_commit(struct wm_shm_surface *s,
struct wlr_scene_tree *parent,
int x, int y)
{
if (!s)
return;
if (!s->scene_buf) {
s->scene_buf = wlr_scene_buffer_create(parent, &s->wlr_buf);
if (!s->scene_buf) {
wwarning("wm_shm_surface_commit: wlr_scene_buffer_create failed");
return;
}
wwarning("wl_backend: SHM surface %dx%d committed to scene at %d,%d",
s->width, s->height, x, y);
}
wlr_scene_node_set_position(&s->scene_buf->node, x, y);
}
/*
* Destroy a surface and remove it from the scene graph.
* After this call s is invalid — the memory is freed asynchronously
* by shm_buf_destroy once the scene node releases its lock.
*/
void
wm_shm_surface_destroy(struct wm_shm_surface *s)
{
if (!s)
return;
if (s->scene_buf) {
wlr_scene_node_destroy(&s->scene_buf->node);
s->scene_buf = NULL;
}
wlr_buffer_drop(&s->wlr_buf); /* producer done; shm_buf_destroy frees s */
}

View File

@ -548,3 +548,7 @@ void wl_screen_open(WScreen *scr);
void wl_screen_close(WScreen *scr);
int wl_screen_init_display(WScreen *scr, int screen_number);
int wl_show_crash_dialog(int sig);
struct wm_shm_surface *wm_shm_surface_create(int width, int height);
void wm_shm_surface_fill(struct wm_shm_surface *s, int x, int y, int w, int h, uint32_t argb);
void wm_shm_surface_commit(struct wm_shm_surface *s, struct wlr_scene_tree *parent, int x, int y);
void wm_shm_surface_destroy(struct wm_shm_surface *s);