Refactor into libwaymini library with public API, example, and standalone demo
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
CC ?= gcc
|
||||||
|
CFLAGS := -Wall -Wextra -O2 $(shell pkg-config --cflags wayland-client 2>/dev/null)
|
||||||
|
LDFLAGS := $(shell pkg-config --libs wayland-client 2>/dev/null)
|
||||||
|
|
||||||
|
# Fallback if pkg-config is unavailable or returns nothing.
|
||||||
|
ifeq ($(LDFLAGS),)
|
||||||
|
LDFLAGS := -lwayland-client -lm
|
||||||
|
endif
|
||||||
|
|
||||||
|
LIB_SRC := waymini.c xdg-shell-client-protocol.c
|
||||||
|
LIB_OBJ := $(LIB_SRC:.c=.o)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: libwaymini.a example waymini
|
||||||
|
|
||||||
|
libwaymini.a: $(LIB_OBJ)
|
||||||
|
ar rcs $@ $^
|
||||||
|
|
||||||
|
example: example.c libwaymini.a
|
||||||
|
$(CC) $(CFLAGS) -o $@ example.c -L. -lwaymini $(LDFLAGS)
|
||||||
|
|
||||||
|
waymini: waymini_standalone.c waymini.c xdg-shell-client-protocol.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ waymini_standalone.c waymini.c xdg-shell-client-protocol.c $(LDFLAGS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(LIB_OBJ) libwaymini.a example waymini
|
||||||
|
|
||||||
|
xdg-shell-client-protocol.c xdg-shell-client-protocol.h: gen-protocols.sh
|
||||||
|
bash gen-protocols.sh
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/* Example program that links against the waymini library.
|
||||||
|
* No external dependencies beyond waymini itself and the C standard library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "waymini.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void on_key(void *user, uint32_t keycode, uint32_t state) {
|
||||||
|
(void)user;
|
||||||
|
const char *label = state ? "down" : "up ";
|
||||||
|
printf("key %s: %u\n", label, keycode);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
uint32_t w = 320, h = 200;
|
||||||
|
|
||||||
|
struct waymini *wm = waymini_create(w, h, on_key, NULL);
|
||||||
|
if (!wm) return 1;
|
||||||
|
|
||||||
|
printf("surface: %ux%u stride=%u\n",
|
||||||
|
waymini_get_width(wm), waymini_get_height(wm), waymini_get_stride(wm));
|
||||||
|
|
||||||
|
uint8_t *pixels = (uint8_t *)waymini_get_pixels(wm);
|
||||||
|
if (!pixels) {
|
||||||
|
waymini_destroy(wm);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill a simple gradient. Each row is stride bytes. */
|
||||||
|
for (uint32_t y = 0; y < h; y++) {
|
||||||
|
for (uint32_t x = 0; x < w; x++) {
|
||||||
|
size_t i = (size_t)y * waymini_get_stride(wm) + (size_t)x * 4;
|
||||||
|
pixels[i + 0] = 0x20; /* B */
|
||||||
|
pixels[i + 1] = (uint8_t)(y * 255 / h); /* G */
|
||||||
|
pixels[i + 2] = (uint8_t)(x * 255 / w); /* R */
|
||||||
|
pixels[i + 3] = 0xff; /* A (ignored for XRGB) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waymini_present(wm);
|
||||||
|
|
||||||
|
while (!waymini_should_close(wm)) {
|
||||||
|
if (waymini_dispatch(wm) < 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
waymini_destroy(wm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -1,6 +1,8 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include "waymini.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -17,8 +19,6 @@
|
|||||||
|
|
||||||
#include "xdg-shell-client-protocol.h"
|
#include "xdg-shell-client-protocol.h"
|
||||||
|
|
||||||
enum fmt { FMT_RGBA32 = 4 };
|
|
||||||
|
|
||||||
struct shm_state {
|
struct shm_state {
|
||||||
int fd;
|
int fd;
|
||||||
size_t size;
|
size_t size;
|
||||||
@@ -44,11 +44,11 @@ struct input_state {
|
|||||||
struct wl_seat *seat;
|
struct wl_seat *seat;
|
||||||
struct wl_keyboard *keyboard;
|
struct wl_keyboard *keyboard;
|
||||||
|
|
||||||
void (*on_keycode)(void *user, uint32_t keycode, uint32_t state);
|
waymini_key_cb on_keycode;
|
||||||
void *user;
|
void *user;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct app {
|
struct waymini {
|
||||||
struct wl_display *display;
|
struct wl_display *display;
|
||||||
struct wl_registry *registry;
|
struct wl_registry *registry;
|
||||||
|
|
||||||
@@ -56,17 +56,17 @@ struct app {
|
|||||||
struct wl_shm *shm_iface;
|
struct wl_shm *shm_iface;
|
||||||
struct xdg_wm_base *wm_base;
|
struct xdg_wm_base *wm_base;
|
||||||
|
|
||||||
struct wl_event_queue *queue;
|
|
||||||
|
|
||||||
struct shm_state shm;
|
struct shm_state shm;
|
||||||
struct window_state win;
|
struct window_state win;
|
||||||
struct input_state in;
|
struct input_state in;
|
||||||
|
|
||||||
|
int should_close;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void on_xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) {
|
static void on_xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) {
|
||||||
struct app *app = data;
|
struct waymini *wm = data;
|
||||||
xdg_surface_ack_configure(xdg_surface, serial);
|
xdg_surface_ack_configure(xdg_surface, serial);
|
||||||
app->win.configured = 1;
|
wm->win.configured = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||||
@@ -80,7 +80,9 @@ static void on_toplevel_configure(void *data, struct xdg_toplevel *toplevel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void on_toplevel_close(void *data, struct xdg_toplevel *toplevel) {
|
static void on_toplevel_close(void *data, struct xdg_toplevel *toplevel) {
|
||||||
(void)data; (void)toplevel;
|
(void)toplevel;
|
||||||
|
struct waymini *wm = data;
|
||||||
|
wm->should_close = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||||
@@ -105,7 +107,6 @@ static void on_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format,
|
|||||||
close(fd);
|
close(fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Minimal: drain keymap then close.
|
|
||||||
char *buf = malloc(size);
|
char *buf = malloc(size);
|
||||||
if (buf) {
|
if (buf) {
|
||||||
size_t off = 0;
|
size_t off = 0;
|
||||||
@@ -116,7 +117,6 @@ static void on_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format,
|
|||||||
}
|
}
|
||||||
free(buf);
|
free(buf);
|
||||||
} else {
|
} else {
|
||||||
// If alloc fails, still drain.
|
|
||||||
(void)read(fd, buf, 0);
|
(void)read(fd, buf, 0);
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -183,20 +183,20 @@ static const struct wl_seat_listener seat_listener = {
|
|||||||
|
|
||||||
static void on_registry_global(void *data, struct wl_registry *registry,
|
static void on_registry_global(void *data, struct wl_registry *registry,
|
||||||
uint32_t name, const char *interface, uint32_t version) {
|
uint32_t name, const char *interface, uint32_t version) {
|
||||||
struct app *app = data;
|
struct waymini *wm = data;
|
||||||
(void)registry;
|
(void)registry;
|
||||||
|
|
||||||
if (strcmp(interface, "wl_compositor") == 0) {
|
if (strcmp(interface, "wl_compositor") == 0) {
|
||||||
app->compositor = wl_registry_bind(app->registry, name, &wl_compositor_interface, 4);
|
wm->compositor = wl_registry_bind(wm->registry, name, &wl_compositor_interface, 4);
|
||||||
} else if (strcmp(interface, "wl_shm") == 0) {
|
} else if (strcmp(interface, "wl_shm") == 0) {
|
||||||
app->shm_iface = wl_registry_bind(app->registry, name, &wl_shm_interface, 1);
|
wm->shm_iface = wl_registry_bind(wm->registry, name, &wl_shm_interface, 1);
|
||||||
app->shm.shm_iface = app->shm_iface;
|
wm->shm.shm_iface = wm->shm_iface;
|
||||||
} else if (strcmp(interface, "xdg_wm_base") == 0) {
|
} else if (strcmp(interface, "xdg_wm_base") == 0) {
|
||||||
app->wm_base = wl_registry_bind(app->registry, name, &xdg_wm_base_interface, 1);
|
wm->wm_base = wl_registry_bind(wm->registry, name, &xdg_wm_base_interface, 1);
|
||||||
xdg_wm_base_add_listener(app->wm_base, &wm_base_listener, app);
|
xdg_wm_base_add_listener(wm->wm_base, &wm_base_listener, wm);
|
||||||
} else if (strcmp(interface, "wl_seat") == 0) {
|
} else if (strcmp(interface, "wl_seat") == 0) {
|
||||||
struct wl_seat *seat = wl_registry_bind(app->registry, name, &wl_seat_interface, version);
|
struct wl_seat *seat = wl_registry_bind(wm->registry, name, &wl_seat_interface, version);
|
||||||
wl_seat_add_listener(seat, &seat_listener, &app->in);
|
wl_seat_add_listener(seat, &seat_listener, &wm->in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,11 +209,11 @@ static const struct wl_registry_listener registry_listener = {
|
|||||||
.global_remove = on_registry_global_remove,
|
.global_remove = on_registry_global_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void waymini_destroy(struct app *app);
|
static void waymini_destroy_internal(struct waymini *wm);
|
||||||
|
|
||||||
static int create_shm_buffer(struct app *app) {
|
static int create_shm_buffer(struct waymini *wm) {
|
||||||
struct shm_state *s = &app->shm;
|
struct shm_state *s = &wm->shm;
|
||||||
struct window_state *w = &app->win;
|
struct window_state *w = &wm->win;
|
||||||
|
|
||||||
s->size = (size_t)w->stride * (size_t)w->height;
|
s->size = (size_t)w->stride * (size_t)w->height;
|
||||||
s->fd = memfd_create("waymini-shm", MFD_CLOEXEC);
|
s->fd = memfd_create("waymini-shm", MFD_CLOEXEC);
|
||||||
@@ -234,122 +234,133 @@ static int create_shm_buffer(struct app *app) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct app *waymini_create(uint32_t width, uint32_t height,
|
struct waymini *waymini_create(uint32_t width, uint32_t height,
|
||||||
void (*on_keycode)(void*, uint32_t, uint32_t),
|
waymini_key_cb key_cb, void *user) {
|
||||||
void *user) {
|
struct waymini *wm = calloc(1, sizeof(*wm));
|
||||||
struct app *app = calloc(1, sizeof(*app));
|
if (!wm) return NULL;
|
||||||
if (!app) return NULL;
|
|
||||||
|
|
||||||
app->display = wl_display_connect(NULL);
|
wm->display = wl_display_connect(NULL);
|
||||||
if (!app->display) { fprintf(stderr, "wl_display_connect failed\n"); free(app); return NULL; }
|
if (!wm->display) { fprintf(stderr, "wl_display_connect failed\n"); free(wm); return NULL; }
|
||||||
|
|
||||||
app->registry = wl_display_get_registry(app->display);
|
wm->registry = wl_display_get_registry(wm->display);
|
||||||
wl_registry_add_listener(app->registry, ®istry_listener, app);
|
wl_registry_add_listener(wm->registry, ®istry_listener, wm);
|
||||||
wl_display_roundtrip(app->display);
|
wl_display_roundtrip(wm->display);
|
||||||
|
|
||||||
if (!app->compositor || !app->shm_iface || !app->wm_base) {
|
if (!wm->compositor || !wm->shm_iface || !wm->wm_base) {
|
||||||
fprintf(stderr, "missing globals\n");
|
fprintf(stderr, "missing globals\n");
|
||||||
waymini_destroy(app);
|
waymini_destroy_internal(wm);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
app->win.compositor = app->compositor;
|
wm->win.compositor = wm->compositor;
|
||||||
app->win.surface = wl_compositor_create_surface(app->compositor);
|
wm->win.surface = wl_compositor_create_surface(wm->compositor);
|
||||||
|
|
||||||
app->win.xdg_surface = xdg_wm_base_get_xdg_surface(app->wm_base, app->win.surface);
|
wm->win.xdg_surface = xdg_wm_base_get_xdg_surface(wm->wm_base, wm->win.surface);
|
||||||
xdg_surface_add_listener(app->win.xdg_surface, &xdg_surface_listener, app);
|
xdg_surface_add_listener(wm->win.xdg_surface, &xdg_surface_listener, wm);
|
||||||
|
|
||||||
app->win.xdg_toplevel = xdg_surface_get_toplevel(app->win.xdg_surface);
|
wm->win.xdg_toplevel = xdg_surface_get_toplevel(wm->win.xdg_surface);
|
||||||
xdg_toplevel_add_listener(app->win.xdg_toplevel, &xdg_toplevel_listener, app);
|
xdg_toplevel_add_listener(wm->win.xdg_toplevel, &xdg_toplevel_listener, wm);
|
||||||
xdg_toplevel_set_title(app->win.xdg_toplevel, "waymini");
|
xdg_toplevel_set_title(wm->win.xdg_toplevel, "waymini");
|
||||||
xdg_toplevel_set_app_id(app->win.xdg_toplevel, "waymini");
|
xdg_toplevel_set_app_id(wm->win.xdg_toplevel, "waymini");
|
||||||
|
|
||||||
app->in.on_keycode = on_keycode;
|
wm->in.on_keycode = key_cb;
|
||||||
app->in.user = user;
|
wm->in.user = user;
|
||||||
|
|
||||||
app->win.width = width;
|
wm->win.width = width;
|
||||||
app->win.height = height;
|
wm->win.height = height;
|
||||||
app->win.bpp = 4;
|
wm->win.bpp = 4;
|
||||||
app->win.stride = width * app->win.bpp;
|
wm->win.stride = width * wm->win.bpp;
|
||||||
|
|
||||||
/* Initial commit without a buffer, as required by xdg-shell. */
|
wl_surface_commit(wm->win.surface);
|
||||||
wl_surface_commit(app->win.surface);
|
|
||||||
|
|
||||||
/* Wait for the first xdg_surface.configure. */
|
while (!wm->win.configured) {
|
||||||
while (!app->win.configured) {
|
if (wl_display_dispatch(wm->display) < 0) {
|
||||||
if (wl_display_dispatch(app->display) < 0) {
|
|
||||||
fprintf(stderr, "dispatch failed waiting for configure\n");
|
fprintf(stderr, "dispatch failed waiting for configure\n");
|
||||||
waymini_destroy(app);
|
waymini_destroy_internal(wm);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_shm_buffer(app) < 0) {
|
if (create_shm_buffer(wm) < 0) {
|
||||||
fprintf(stderr, "create_shm_buffer failed\n");
|
fprintf(stderr, "create_shm_buffer failed\n");
|
||||||
waymini_destroy(app);
|
waymini_destroy_internal(wm);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return app;
|
return wm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void waymini_present(struct app *app) {
|
uint32_t waymini_get_width(const struct waymini *wm) { return wm ? wm->win.width : 0; }
|
||||||
if (!app->win.configured) return;
|
uint32_t waymini_get_height(const struct waymini *wm) { return wm ? wm->win.height : 0; }
|
||||||
wl_surface_attach(app->win.surface, app->shm.wl_buffer, 0, 0);
|
uint32_t waymini_get_stride(const struct waymini *wm) { return wm ? wm->win.stride : 0; }
|
||||||
wl_surface_commit(app->win.surface);
|
void *waymini_get_pixels(const struct waymini *wm) { return wm ? wm->shm.map : NULL; }
|
||||||
|
|
||||||
|
void waymini_present(struct waymini *wm) {
|
||||||
|
if (!wm || !wm->win.configured) return;
|
||||||
|
wl_surface_attach(wm->win.surface, wm->shm.wl_buffer, 0, 0);
|
||||||
|
wl_surface_commit(wm->win.surface);
|
||||||
|
wl_display_flush(wm->display);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void waymini_destroy(struct app *app) {
|
int waymini_dispatch(struct waymini *wm) {
|
||||||
if (!app) return;
|
if (!wm || !wm->display) return -1;
|
||||||
|
return wl_display_dispatch(wm->display);
|
||||||
if (app->in.keyboard) wl_keyboard_destroy(app->in.keyboard);
|
|
||||||
if (app->in.seat) wl_seat_destroy(app->in.seat);
|
|
||||||
|
|
||||||
if (app->shm.wl_buffer) wl_buffer_destroy(app->shm.wl_buffer);
|
|
||||||
if (app->shm.map && app->shm.size) munmap(app->shm.map, app->shm.size);
|
|
||||||
if (app->shm.fd >= 0) close(app->shm.fd);
|
|
||||||
|
|
||||||
if (app->win.xdg_toplevel) xdg_toplevel_destroy(app->win.xdg_toplevel);
|
|
||||||
if (app->win.xdg_surface) xdg_surface_destroy(app->win.xdg_surface);
|
|
||||||
if (app->win.surface) wl_surface_destroy(app->win.surface);
|
|
||||||
|
|
||||||
if (app->wm_base) xdg_wm_base_destroy(app->wm_base);
|
|
||||||
if (app->compositor) wl_compositor_destroy(app->compositor);
|
|
||||||
if (app->shm_iface) wl_shm_destroy(app->shm_iface);
|
|
||||||
|
|
||||||
if (app->registry) wl_registry_destroy(app->registry);
|
|
||||||
if (app->display) wl_display_disconnect(app->display);
|
|
||||||
free(app);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_keycode(void *user, uint32_t keycode, uint32_t state) {
|
int waymini_poll(struct waymini *wm) {
|
||||||
(void)user;
|
if (!wm || !wm->display) return -1;
|
||||||
printf("key=%u state=%u\n", keycode, state);
|
wl_display_dispatch_pending(wm->display);
|
||||||
fflush(stdout);
|
wl_display_flush(wm->display);
|
||||||
}
|
int ret = wl_display_prepare_read(wm->display);
|
||||||
|
if (ret < 0) return wl_display_dispatch_pending(wm->display) >= 0 ? 1 : -1;
|
||||||
|
|
||||||
int main() {
|
int fd = wl_display_get_fd(wm->display);
|
||||||
uint32_t w = 800, h = 480;
|
fd_set rfds;
|
||||||
struct app *app = waymini_create(w, h, on_keycode, NULL);
|
FD_ZERO(&rfds);
|
||||||
if (!app) return 1;
|
FD_SET(fd, &rfds);
|
||||||
|
struct timeval tv = { 0, 0 };
|
||||||
// Fill RGBA-ish bytes, but we're attaching as XRGB8888; color order is compositor-dependent.
|
ret = select(fd + 1, &rfds, NULL, NULL, &tv);
|
||||||
uint8_t *p = (uint8_t*)app->shm.map;
|
if (ret > 0) {
|
||||||
for (uint32_t y = 0; y < h; y++) {
|
wl_display_read_events(wm->display);
|
||||||
for (uint32_t x = 0; x < w; x++) {
|
wl_display_dispatch_pending(wm->display);
|
||||||
size_t i = (size_t)y * app->win.stride + (size_t)x * 4;
|
return 1;
|
||||||
p[i + 0] = 0x20;
|
|
||||||
p[i + 1] = (uint8_t)(y * 255 / h);
|
|
||||||
p[i + 2] = (uint8_t)(x * 255 / w);
|
|
||||||
p[i + 3] = 0xff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
waymini_present(app);
|
wl_display_cancel_read(wm->display);
|
||||||
|
|
||||||
while (wl_display_dispatch(app->display) != -1) {
|
|
||||||
/* Optionally re-present here if content changes. */
|
|
||||||
}
|
|
||||||
|
|
||||||
waymini_destroy(app);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void waymini_request_close(struct waymini *wm) {
|
||||||
|
if (wm) wm->should_close = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int waymini_should_close(const struct waymini *wm) {
|
||||||
|
return wm ? wm->should_close : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waymini_destroy_internal(struct waymini *wm) {
|
||||||
|
if (!wm) return;
|
||||||
|
|
||||||
|
if (wm->in.keyboard) wl_keyboard_destroy(wm->in.keyboard);
|
||||||
|
if (wm->in.seat) wl_seat_destroy(wm->in.seat);
|
||||||
|
|
||||||
|
if (wm->shm.wl_buffer) wl_buffer_destroy(wm->shm.wl_buffer);
|
||||||
|
if (wm->shm.map && wm->shm.size) munmap(wm->shm.map, wm->shm.size);
|
||||||
|
if (wm->shm.fd >= 0) close(wm->shm.fd);
|
||||||
|
|
||||||
|
if (wm->win.xdg_toplevel) xdg_toplevel_destroy(wm->win.xdg_toplevel);
|
||||||
|
if (wm->win.xdg_surface) xdg_surface_destroy(wm->win.xdg_surface);
|
||||||
|
if (wm->win.surface) wl_surface_destroy(wm->win.surface);
|
||||||
|
|
||||||
|
if (wm->wm_base) xdg_wm_base_destroy(wm->wm_base);
|
||||||
|
if (wm->compositor) wl_compositor_destroy(wm->compositor);
|
||||||
|
if (wm->shm_iface) wl_shm_destroy(wm->shm_iface);
|
||||||
|
|
||||||
|
if (wm->registry) wl_registry_destroy(wm->registry);
|
||||||
|
if (wm->display) wl_display_disconnect(wm->display);
|
||||||
|
free(wm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void waymini_destroy(struct waymini *wm) {
|
||||||
|
waymini_destroy_internal(wm);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef WAYMINI_H
|
||||||
|
#define WAYMINI_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct waymini;
|
||||||
|
|
||||||
|
typedef void (*waymini_key_cb)(void *user, uint32_t keycode, uint32_t state);
|
||||||
|
|
||||||
|
/* Create a Wayland surface of the requested dimensions.
|
||||||
|
* key_cb may be NULL if keyboard input is not needed.
|
||||||
|
*/
|
||||||
|
struct waymini *waymini_create(uint32_t width, uint32_t height,
|
||||||
|
waymini_key_cb key_cb, void *user);
|
||||||
|
|
||||||
|
/* Dimensions and pixel access. */
|
||||||
|
uint32_t waymini_get_width(const struct waymini *wm);
|
||||||
|
uint32_t waymini_get_height(const struct waymini *wm);
|
||||||
|
uint32_t waymini_get_stride(const struct waymini *wm);
|
||||||
|
void *waymini_get_pixels(const struct waymini *wm);
|
||||||
|
|
||||||
|
/* Mark the SHM buffer as changed and commit it to the compositor. */
|
||||||
|
void waymini_present(struct waymini *wm);
|
||||||
|
|
||||||
|
/* Dispatch one or more Wayland events. Returns 0 on success, -1 on error.
|
||||||
|
* Blocks until at least one event is processed.
|
||||||
|
*/
|
||||||
|
int waymini_dispatch(struct waymini *wm);
|
||||||
|
|
||||||
|
/* Non-blocking poll for events. Returns 1 if events were dispatched, 0 if no
|
||||||
|
* events were available, and -1 on error.
|
||||||
|
*/
|
||||||
|
int waymini_poll(struct waymini *wm);
|
||||||
|
|
||||||
|
/* Request a graceful close (e.g. from the toplevel close button). */
|
||||||
|
void waymini_request_close(struct waymini *wm);
|
||||||
|
|
||||||
|
/* Returns non-zero when the compositor asked us to close. */
|
||||||
|
int waymini_should_close(const struct waymini *wm);
|
||||||
|
|
||||||
|
/* Clean up. */
|
||||||
|
void waymini_destroy(struct waymini *wm);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* WAYMINI_H */
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/* Standalone demo equivalent to the original waymini.c main(). */
|
||||||
|
|
||||||
|
#include "waymini.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static void on_keycode(void *user, uint32_t keycode, uint32_t state) {
|
||||||
|
(void)user;
|
||||||
|
printf("key=%u state=%u\n", keycode, state);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
uint32_t w = 320, h = 200;
|
||||||
|
struct waymini *wm = waymini_create(w, h, on_keycode, NULL);
|
||||||
|
if (!wm) return 1;
|
||||||
|
|
||||||
|
uint8_t *p = (uint8_t *)waymini_get_pixels(wm);
|
||||||
|
for (uint32_t y = 0; y < h; y++) {
|
||||||
|
for (uint32_t x = 0; x < w; x++) {
|
||||||
|
size_t i = (size_t)y * waymini_get_stride(wm) + (size_t)x * 4;
|
||||||
|
p[i + 0] = 0x20;
|
||||||
|
p[i + 1] = (uint8_t)(y * 255 / h);
|
||||||
|
p[i + 2] = (uint8_t)(x * 255 / w);
|
||||||
|
p[i + 3] = 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waymini_present(wm);
|
||||||
|
|
||||||
|
while (!waymini_should_close(wm)) {
|
||||||
|
if (waymini_dispatch(wm) < 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
waymini_destroy(wm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Binary file not shown.
Reference in New Issue
Block a user