From 616ecbf6b44e7d18020b23aad642cfeba14a5598 Mon Sep 17 00:00:00 2001 From: Annika Date: Fri, 3 Jul 2026 02:27:00 -0700 Subject: [PATCH] Refactor into libwaymini library with public API, example, and standalone demo --- Makefile | 33 ++++++ example | Bin 0 -> 36880 bytes example.c | 53 +++++++++ libwaymini.a | Bin 0 -> 23038 bytes waymini | Bin 33344 -> 36896 bytes waymini.c | 231 +++++++++++++++++++----------------- waymini.h | 53 +++++++++ waymini.o | Bin 0 -> 13936 bytes waymini_standalone.c | 39 ++++++ xdg-shell-client-protocol.o | Bin 0 -> 8448 bytes 10 files changed, 299 insertions(+), 110 deletions(-) create mode 100644 Makefile create mode 100755 example create mode 100644 example.c create mode 100644 libwaymini.a create mode 100644 waymini.h create mode 100644 waymini.o create mode 100644 waymini_standalone.c create mode 100644 xdg-shell-client-protocol.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b7fd218 --- /dev/null +++ b/Makefile @@ -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 diff --git a/example b/example new file mode 100755 index 0000000000000000000000000000000000000000..2d2e3c77e110a3cc0334c8dac76d2bf85ad32ba9 GIT binary patch literal 36880 zcmeHw4Rl-8mF~5iA2$S9{DivvG=g!c1H@w|Ap}AiIkA&#aKH%(xDb#POOBPumat^v zH0i?BNr;{jFzu9~3^U`IcBW~ERXj|G7ifn%1VU&7bwj6R5h!j7MIunr0wMhBefylf z<*O5GX5PHF-n>~$$IIGxe|MjK_Sxs$bMHO(-hFOwXj&V1yXnvmXa(&4EZPcxN#F2Iy;cc+Z|Im+d);(S9b8ZhZjmJ=%VTY-Gk4*$`_-OO6a<(cg*{KyooQ7D_O z+Tcv=qUKw6&1!4Uw4o!N3%4B^U9juZ?ceL|>-+V~ul{KyymsE)KaB)uMZ#S@y|a4f z&zm)GZgo6bJzM3QfxM)T>|Rk)az}s3>30$K1^my#{|n!lv3uruJI@`uW#`^=Qt*t)O){t)`$zkgk4w96k)1iBM`zZM-=aAU+D?McLX68>-(l(YxhLKd)KI39}xHu>A4 zU0tEJ1VQnRPJb*KjT8_JbhU*d{_ap9sDyizs(jgaC{Uo7?r2X}Fwq^3QQi%qO>3ip z?qGgqv1nZ=;cr)E2tsB0L$`&x5^<;L?U9~%2LZ9}XzwO}AQ<#V$WdLPZbH}gw6}-4 z^UKhZRKjhc?sz!b<I#Ot){(Go zp6*TK=ZJNOVu9{Z&cSWb&R8@aPDID8LT8{m-VuoS+arN>aVr+;?v8e&PoO)rZSc2s zZ1A@S!V#;zI~1}yd%8LUF{@p>t3A=()72J8gsgZXh>l@(1|pGY8}i}|+Q$8r5e>AY=`Xgp-ay5Wg-t9@g4n6!r?)UDvD zw$7NQ8TJoG<(UO~5{#v=nhJT>TP9N%lIoOOWdi*df<3Ke*>!Tt-Z^ zK4R?5aQIZxJPE~+%$;g~spVn5=j<@9gk9D-Y=&I#$T&4TmrAp&`FuSrc#LtMf%`7g z^0t8wvM-tqd}N-MZ!z!zmTxui8kX-c@Me~e8F(w>y#`*xc%OmC7~f&weT)wn_%X%@ z4cx={ZUgr+K5XDajE@@l^L*cO%)tBFwcjkJ(k@=+g$n-pm0G^akbjx=*BH3>RxLl@ zz>l!J&%h5cZX3AhX*Te;SiZ%;KV-bsz(r4=fq%mCI}BXx88C3sbDx1vT%qebXy9it zzT3b@*gr!CK85A?82B{ChYfs`^^6+$=UD!jf%mQBc4sQ>>t$Z3;JJ1;;AzsJBAF+ObIV$T5skForSfs39O3|#b#8u(_` zlQ!_3j2|=bzFT#@P8j$-EN^w_{n9_>_$o8-LDu6j@OxQLg@OMi<6Z+FVm(y`{x>XN zW8e?+I62?I#Xmj+|32%n4P5jz8@T9cG4Ow3J*@^V{jkHpMNiDYf5>`z4P5l}8Mx@# zVc^fQo&f`w{(PT-AGlSw>!5-El=bX3aIt5|z{Q?D2L2N388&dybHKnw&!~aF!tHy^ zz5ms?4MQxf06MH z18=!iS1@Ma@3VZbftRq~`V734_3SY4Ni08L;BvijpMgug1`Ygd*0bBd#m_?qE_#Ly zyo&XV7`U~b8=9%vE@cKT?cyIt*O�*^Y^cwg&*3)O;qGyMJi=F`kzk~JMXW-)JK?4^( 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 literal 0 HcmV?d00001 diff --git a/example.c b/example.c new file mode 100644 index 0000000..72c9d0f --- /dev/null +++ b/example.c @@ -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 +#include +#include +#include + +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; +} diff --git a/libwaymini.a b/libwaymini.a new file mode 100644 index 0000000000000000000000000000000000000000..a5a964ab893fb2a78dffbe4d8d71b78c72b20f20 GIT binary patch literal 23038 zcmeI44|H5royTAPw1gBV0o09xGDy&LkuXCG1d1?e6Z(p&1ZX8nF_~s2&5%iEc4k6T zTMyBsf8I`uafLlSyZ(tQXDvru8ur;Mvin`iUaP8u1ql*ewr5u+(3U2oIz3=y% z`ORfU5O>$r-FwcPd++D{?(hEY@7{OcpZngNeR(v~KX^s`1;Nq~QdvK(e}lm#mt4#e zef5sxG&)Z8t6%!ocAw*vZX2VUh7%)+-u_HHnu|M<-4M_9ZcM~-gC%4zp4c#$D?!;@ zCJ`$wmrjhuli7k)Iup;vM~bCliEKKW>o00fr;^EnbSD01qw#F6w?CQ67S(14Q=`e4 z1!E+aNo{h*VjFtXsq|>NH!+fnX9lAEal>+{bTWQRJZa(Vs1dPfI+ac25~-1R#@exQ zxOaUt8&}l1!0t5FXXTPh3Z2?lPsW~~9gHWF=l3TQQuI+SidS z4i$aI`xZ*N6F;ppLhi)|J$)zam~nw#3auTT7{ zYIMN$lFf}B-d9}ji7rY8jmlM&Cnvqr-TJfKg|4@*xi0*jm-mEE@}#?qeu5;{m8V+C))r$`_(=F^f|l6vZ%_Q7 zI(L#gaciBEt3`XsUaIR7*W1!uM@@IVrOjOC^5)L)gT`m>u2-R<``{;bTvvV#$?v)d z-1Qz<s9FDj*4$h*f1%&piTi`D*GaDE zj3^}oQQ{o$uE4lC5}{iM*+&LC-NA+P!^@f|A1o3f`=Ux)W( z``g2_V$ZHSrqFudp~wGjpiqA6e8c2NsqNGO&yli5H~;0`klZ?-TfjYkk149aW*58P zUb;H($^YinMpF=-|{xJJ}2kkia zAM^9azd^fb9#!Ml#eCAz?mhoycp8&PsNH*N-(I+rrjDjAFW20*%KJta9mA1T-nacK zy#qAEG)$gKQ&o5#laN32xL%EGCZC4M_tGvJWk%dT)M<|L_Ln)@UGI^?=v+b5gkQ$Z zFXPq?k)M9nFzGKZ%+eeCJJ}R+ruxQ~BrFFG0sfB4(p3+ht6F;i-_IK@i1;x~=qTxf9 zAkGkF1UtO`vG)CsR=fG3o-Xg6X_D&lKDWnL*5M6pd0=9kGMHOBypK;(#6Fwdw~#X7 zBh>mrt?zutaXNhcPN2Tt(T!tmVh735%=x4I1d8Xc-(u!%ch_4e=eP}@zK=W{GFrVA zEhuI<9k1N28g=AXw2<%3T=^w5DLijVl8QEW;#rzX{K7+#uKZA_Bi~QcmhZ0iwSJ$q zuc349(=X_05*_Qve-6bv@eI)#dfOF3y&&cNAyK7Mx6*aQ+N+<>?seqTz+v z-#t(~f4ORj*Z
  • MNUqimXl?HtmE;KIp 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�V6951J literal 33344 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 DZ)N8z diff --git a/waymini.c b/waymini.c index 3ce4cc5..4916681 100644 --- a/waymini.c +++ b/waymini.c @@ -1,6 +1,8 @@ #define _GNU_SOURCE #define _POSIX_C_SOURCE 200809L +#include "waymini.h" + #include #include #include @@ -17,8 +19,6 @@ #include "xdg-shell-client-protocol.h" -enum fmt { FMT_RGBA32 = 4 }; - struct shm_state { int fd; size_t size; @@ -44,11 +44,11 @@ struct input_state { struct wl_seat *seat; struct wl_keyboard *keyboard; - void (*on_keycode)(void *user, uint32_t keycode, uint32_t state); + waymini_key_cb on_keycode; void *user; }; -struct app { +struct waymini { struct wl_display *display; struct wl_registry *registry; @@ -56,17 +56,17 @@ struct app { struct wl_shm *shm_iface; struct xdg_wm_base *wm_base; - struct wl_event_queue *queue; - struct shm_state shm; struct window_state win; struct input_state in; + + int should_close; }; 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); - app->win.configured = 1; + wm->win.configured = 1; } 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) { - (void)data; (void)toplevel; + (void)toplevel; + struct waymini *wm = data; + wm->should_close = 1; } 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); return; } - // Minimal: drain keymap then close. char *buf = malloc(size); if (buf) { size_t off = 0; @@ -116,7 +117,6 @@ static void on_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, } free(buf); } else { - // If alloc fails, still drain. (void)read(fd, buf, 0); } 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, uint32_t name, const char *interface, uint32_t version) { - struct app *app = data; + struct waymini *wm = data; (void)registry; 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) { - app->shm_iface = wl_registry_bind(app->registry, name, &wl_shm_interface, 1); - app->shm.shm_iface = app->shm_iface; + wm->shm_iface = wl_registry_bind(wm->registry, name, &wl_shm_interface, 1); + wm->shm.shm_iface = wm->shm_iface; } else if (strcmp(interface, "xdg_wm_base") == 0) { - app->wm_base = wl_registry_bind(app->registry, name, &xdg_wm_base_interface, 1); - xdg_wm_base_add_listener(app->wm_base, &wm_base_listener, app); + wm->wm_base = wl_registry_bind(wm->registry, name, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(wm->wm_base, &wm_base_listener, wm); } else if (strcmp(interface, "wl_seat") == 0) { - struct wl_seat *seat = wl_registry_bind(app->registry, name, &wl_seat_interface, version); - wl_seat_add_listener(seat, &seat_listener, &app->in); + struct wl_seat *seat = wl_registry_bind(wm->registry, name, &wl_seat_interface, version); + 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, }; -static void waymini_destroy(struct app *app); +static void waymini_destroy_internal(struct waymini *wm); -static int create_shm_buffer(struct app *app) { - struct shm_state *s = &app->shm; - struct window_state *w = &app->win; +static int create_shm_buffer(struct waymini *wm) { + struct shm_state *s = &wm->shm; + struct window_state *w = &wm->win; s->size = (size_t)w->stride * (size_t)w->height; s->fd = memfd_create("waymini-shm", MFD_CLOEXEC); @@ -234,122 +234,133 @@ static int create_shm_buffer(struct app *app) { return 0; } -static struct app *waymini_create(uint32_t width, uint32_t height, - void (*on_keycode)(void*, uint32_t, uint32_t), - void *user) { - struct app *app = calloc(1, sizeof(*app)); - if (!app) return NULL; +struct waymini *waymini_create(uint32_t width, uint32_t height, + waymini_key_cb key_cb, void *user) { + struct waymini *wm = calloc(1, sizeof(*wm)); + if (!wm) return NULL; - app->display = wl_display_connect(NULL); - if (!app->display) { fprintf(stderr, "wl_display_connect failed\n"); free(app); return NULL; } + wm->display = wl_display_connect(NULL); + if (!wm->display) { fprintf(stderr, "wl_display_connect failed\n"); free(wm); return NULL; } - app->registry = wl_display_get_registry(app->display); - wl_registry_add_listener(app->registry, ®istry_listener, app); - wl_display_roundtrip(app->display); + wm->registry = wl_display_get_registry(wm->display); + wl_registry_add_listener(wm->registry, ®istry_listener, wm); + 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"); - waymini_destroy(app); + waymini_destroy_internal(wm); return NULL; } - app->win.compositor = app->compositor; - app->win.surface = wl_compositor_create_surface(app->compositor); + wm->win.compositor = wm->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); - xdg_surface_add_listener(app->win.xdg_surface, &xdg_surface_listener, app); + wm->win.xdg_surface = xdg_wm_base_get_xdg_surface(wm->wm_base, wm->win.surface); + xdg_surface_add_listener(wm->win.xdg_surface, &xdg_surface_listener, wm); - app->win.xdg_toplevel = xdg_surface_get_toplevel(app->win.xdg_surface); - xdg_toplevel_add_listener(app->win.xdg_toplevel, &xdg_toplevel_listener, app); - xdg_toplevel_set_title(app->win.xdg_toplevel, "waymini"); - xdg_toplevel_set_app_id(app->win.xdg_toplevel, "waymini"); + wm->win.xdg_toplevel = xdg_surface_get_toplevel(wm->win.xdg_surface); + xdg_toplevel_add_listener(wm->win.xdg_toplevel, &xdg_toplevel_listener, wm); + xdg_toplevel_set_title(wm->win.xdg_toplevel, "waymini"); + xdg_toplevel_set_app_id(wm->win.xdg_toplevel, "waymini"); - app->in.on_keycode = on_keycode; - app->in.user = user; + wm->in.on_keycode = key_cb; + wm->in.user = user; - app->win.width = width; - app->win.height = height; - app->win.bpp = 4; - app->win.stride = width * app->win.bpp; + wm->win.width = width; + wm->win.height = height; + wm->win.bpp = 4; + wm->win.stride = width * wm->win.bpp; - /* Initial commit without a buffer, as required by xdg-shell. */ - wl_surface_commit(app->win.surface); + wl_surface_commit(wm->win.surface); - /* Wait for the first xdg_surface.configure. */ - while (!app->win.configured) { - if (wl_display_dispatch(app->display) < 0) { + while (!wm->win.configured) { + if (wl_display_dispatch(wm->display) < 0) { fprintf(stderr, "dispatch failed waiting for configure\n"); - waymini_destroy(app); + waymini_destroy_internal(wm); return NULL; } } - if (create_shm_buffer(app) < 0) { + if (create_shm_buffer(wm) < 0) { fprintf(stderr, "create_shm_buffer failed\n"); - waymini_destroy(app); + waymini_destroy_internal(wm); return NULL; } - return app; + return wm; } -static void waymini_present(struct app *app) { - if (!app->win.configured) return; - wl_surface_attach(app->win.surface, app->shm.wl_buffer, 0, 0); - wl_surface_commit(app->win.surface); +uint32_t waymini_get_width(const struct waymini *wm) { return wm ? wm->win.width : 0; } +uint32_t waymini_get_height(const struct waymini *wm) { return wm ? wm->win.height : 0; } +uint32_t waymini_get_stride(const struct waymini *wm) { return wm ? wm->win.stride : 0; } +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) { - if (!app) return; - - 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); +int waymini_dispatch(struct waymini *wm) { + if (!wm || !wm->display) return -1; + return wl_display_dispatch(wm->display); } -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 waymini_poll(struct waymini *wm) { + if (!wm || !wm->display) return -1; + wl_display_dispatch_pending(wm->display); + 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() { - uint32_t w = 800, h = 480; - struct app *app = waymini_create(w, h, on_keycode, NULL); - if (!app) return 1; - - // Fill RGBA-ish bytes, but we're attaching as XRGB8888; color order is compositor-dependent. - uint8_t *p = (uint8_t*)app->shm.map; - for (uint32_t y = 0; y < h; y++) { - for (uint32_t x = 0; x < w; x++) { - size_t i = (size_t)y * app->win.stride + (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; - } + int fd = wl_display_get_fd(wm->display); + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + struct timeval tv = { 0, 0 }; + ret = select(fd + 1, &rfds, NULL, NULL, &tv); + if (ret > 0) { + wl_display_read_events(wm->display); + wl_display_dispatch_pending(wm->display); + return 1; } - waymini_present(app); - - while (wl_display_dispatch(app->display) != -1) { - /* Optionally re-present here if content changes. */ - } - - waymini_destroy(app); + wl_display_cancel_read(wm->display); 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); +} + \ No newline at end of file diff --git a/waymini.h b/waymini.h new file mode 100644 index 0000000..74b8b34 --- /dev/null +++ b/waymini.h @@ -0,0 +1,53 @@ +#ifndef WAYMINI_H +#define WAYMINI_H + +#include +#include + +#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 */ diff --git a/waymini.o b/waymini.o new file mode 100644 index 0000000000000000000000000000000000000000..d469f0a906650768182a2f58d161ada0b030ebfa GIT binary patch literal 13936 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 kng~Qu&g08DgnQ_@(#U<>*J!s^`S;0j- +#include +#include + +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; +} diff --git a/xdg-shell-client-protocol.o b/xdg-shell-client-protocol.o new file mode 100644 index 0000000000000000000000000000000000000000..3d321b776c9445757893fa1ac32c6f07ec36df25 GIT binary patch literal 8448 zcmeI1PlzMO6~=3JH_keL*5i`CiO@?lDtxP zN8Q@h*oNqqIhlbFm{XXL90r0x$AJ)->uef7GkyHt{X{_>B1bZ%+MSy^&FaC6V7bM>#2?ajJ-%3X5fcBhf0*(h_Z zG}-EPM#I?kq&N>7?KFv<8^&3h_lll4ZMQmd?Km%n>9*?(qfM8NsNJoK3(X?U`tjYk zFJh5v_0v3_575|5M@c((&&e?N28~vfMVr08=*PKxK5}_nG_q(ICxv@4^p=+oF~9G;m6j*^PN+%Y4+HP0gP=6W8~-PhHlZoP;rd zyeB+v_s1t^ravN++b_NJy~@h%pS0&oAsCCC4#uN%+2ot!a&H!RrD4q35{U%5tLh zPo?%cn)tfb9p!cPn;QS7@}_=}kCpE#uPMK*{I|+0I#~~t|3UdgH^-)O2GCPwl zcAHV|S)OGV1NDI0pt$*|Z!uI)h>wN~{pG7iLr$r2d3IjNauM6;i+A3FSgd;xJCB0siL*Gs|0v+M z)ITN;9n(D_4xN|PKMnZ0`e($UbELj(I=qnsND{4M1Z;+)S8ap+7memCH|%J+z~&OUMI z%bmX)+;sMdv(5o=n9r!rG~jkW9}p2T9%%=L4fZKV}YSXcO^#;X5ALlZZI&sd&#xWh+f4US89lNfK zIO~jwBmOlVcM|YT*7&`EC(8GUL#Hk;lmp_>$u)i&a64}t66fnW zA`YEjsLpY~ZJtkvv(6cD==@4`9uS9V-wUip7~*YRRxXGm#kj3YjW~~cgE(}4r{mTG zZu`R;an@NU4xM*YXCvS?pH1Sd(oxak}aXPqf==)9*ohXJ>FJ|fOK$HbxYZ`C;o_!DT9a!Q73_+{k} zh_lW^;s||KvvyOdVwD@bPQ=@p?{}c7=0k`kJR-4XE)!CqUAX~2{ zan8raF&%rpb|@Y?SLB7VOPqD~h$H@%=CdDg+xHHLL#HAylqqpYysA2f0dFfmA`YDu zh)6jmj?j+Ap9I|I=ae{KR|R5HFh5`NR{3V*fIm&VrZ%|k0YJ8|gD(SUscQ}Xl-j7) z)DHF6iE}=7ZVmOD6#o^qQBBlFJaapjh1|{&;9u3gsHSR%@khitPgl*i2Zj7?Se3u0 z%DQV-5swR3ZAV4qs+)Q4s>2ixBIS2CapQjEn_)>~wV$@4e!yL|l@9!$UDYHl;;Q^8 zcQr5M|20?oon%y%pHi}TDF2jw{PH!Cz_mXSNYw-1T*PwuhB#pQ@i%L#&#Xlw?Efuk zz9_H%wf}ddFEnl664RHu)_r|$)b+8jEswg|;rMnwJ=5n3eNZa?eg5`+F|oDQ=g3># zFP7k;)?W}8Qn*%>%Vp)iuOXLk{9O$^(KxFrW@!D2)Q=j!iG`K2t`~~&@hf9E{-!X5 z)a1pb`DE!m%TR2Uo7H!Sap+sxpBZfHZ~RR$kXNuwZle9eyexm~552H2+NRonMH{gU o*q^Mw%|F7zxfkS4KaY3k-VPEDT)%fds{d3c?(I@$_8#{C01+W+z5oCK literal 0 HcmV?d00001