From dc97cc73c2faaf10b5a2d7b5b5f188e1e69c6a05 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Thu, 9 Jul 2020 22:50:43 +0000 Subject: [PATCH] Now there is a window --- src/main.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 213 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index 07b28e6..42f9532 100644 --- a/src/main.c +++ b/src/main.c @@ -7,13 +7,29 @@ #include #include #include +#include #include #include #include "xdg-shell.h" +#include "shm.h" + +struct buffer { + int width, height, stride; + size_t size; + enum wl_shm_format format; + struct wl_buffer* wl_buffer; + void* pixels; +}; struct window { - struct wl_surface* surface; + struct wl_surface* wl_surface; + struct xdg_surface* xdg_surface; + struct xdg_toplevel* xdg_toplevel; + + int width, height; + + struct buffer* buffer; }; static struct wl_display* wl_display; @@ -22,6 +38,9 @@ static struct wl_compositor* wl_compositor; static struct wl_shm* wl_shm; static struct xdg_wm_base* xdg_wm_base; +static enum wl_shm_format wl_shm_format; +static bool have_format = false; + static bool do_run = true; static void registry_add(void* data, struct wl_registry* registry, uint32_t id, @@ -47,12 +66,76 @@ static const struct wl_registry_listener registry_listener = { .global_remove = registry_remove, }; +static struct buffer* buffer_create(int width, int height, int stride, + enum wl_shm_format format) +{ + struct buffer* self = calloc(1, sizeof(*self)); + if (!self) + return NULL; + + self->width = width; + self->height = height; + self->stride = stride; + self->format = format; + + self->size = height * stride; + int fd = shm_alloc_fd(self->size); + if (fd < 0) + goto failure; + + self->pixels = mmap(NULL, self->size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (!self->pixels) + goto mmap_failure; + + struct wl_shm_pool* pool = wl_shm_create_pool(wl_shm, fd, self->size); + if (!pool) + goto pool_failure; + + self->wl_buffer = wl_shm_pool_create_buffer(pool, 0, width, height, + stride, format); + wl_shm_pool_destroy(pool); + if (!self->wl_buffer) + goto shm_failure; + + close(fd); + return self; + +shm_failure: +pool_failure: + munmap(self->pixels, self->size); +mmap_failure: + close(fd); +failure: + free(self); + return NULL; +} + +static void buffer_destroy(struct buffer* self) +{ + wl_buffer_destroy(self->wl_buffer); + munmap(self->pixels, self->size); + free(self); +} + static void shm_format(void* data, struct wl_shm* shm, uint32_t format) { (void)data; (void)wl_shm; - // TODO: Check formats + if (have_format) + return; + + switch (format) { + case WL_SHM_FORMAT_ARGB8888: + case WL_SHM_FORMAT_ABGR8888: + case WL_SHM_FORMAT_RGBA8888: + case WL_SHM_FORMAT_BGRA8888: + wl_shm_format = format; + have_format = true; + } + + // TODO: Try to get a preferred format? } static const struct wl_shm_listener shm_listener = { @@ -117,6 +200,127 @@ static int init_signal_handler(void) return rc; } +static void window_attach(struct window* w, int x, int y) +{ + wl_surface_attach(w->wl_surface, w->buffer->wl_buffer, x, y); +} + +static void window_commit(struct window* w) +{ + wl_surface_commit(w->wl_surface); +} + +static void window_damage(struct window* w, int x, int y, int width, int height) +{ + wl_surface_damage(w->wl_surface, x, y, width, height); +} + +static void window_clear(struct window* w) +{ + window_attach(w, 0, 0); + memset(w->buffer->pixels, 0x7f, w->buffer->size); + window_damage(w, 0, 0, w->width, w->height); + window_commit(w); +} + +static void window_configure(struct window* w) +{ + if (w->buffer && (w->width != w->buffer->width || + w->height != w->buffer->height)) { + buffer_destroy(w->buffer); + w->buffer = NULL; + } + + if (!w->buffer) + w->buffer = buffer_create(w->width, w->height, w->width * 4, + wl_shm_format); + + assert(w->buffer); + window_clear(w); +} + +static void xdg_surface_configure(void* data, struct xdg_surface* surface, + uint32_t serial) +{ + struct window* w = data; + xdg_surface_ack_configure(surface, serial); + window_configure(w); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_configure, +}; + +static void xdg_toplevel_configure(void* data, struct xdg_toplevel* toplevel, + int32_t width, int32_t height, struct wl_array* state) +{ +// struct window* w = data; +// w->width = width; +// w->height = height; +} + +static void xdg_toplevel_close(void* data, struct xdg_toplevel* toplevel) +{ + do_run = false; +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_configure, + .close = xdg_toplevel_close, +}; + +static struct window* window_create(int width, int height, const char* title) +{ + struct window* w = calloc(1, sizeof(*w)); + if (!w) + return NULL; + + w->width = width; + w->height = height; + + w->wl_surface = wl_compositor_create_surface(wl_compositor); + if (!w->wl_surface) + goto wl_surface_failure; + + w->xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, w->wl_surface); + if (!w->xdg_surface) + goto xdg_surface_failure; + + xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w); + + w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface); + if (!w->xdg_toplevel) + goto xdg_toplevel_failure; + + xdg_toplevel_add_listener(w->xdg_toplevel, &xdg_toplevel_listener, w); + + xdg_toplevel_set_title(w->xdg_toplevel, title); + wl_surface_commit(w->wl_surface); + + window_damage(w, 0, 0, width, height); + + return w; + +xdg_toplevel_failure: + xdg_surface_destroy(w->xdg_surface); +xdg_surface_failure: + wl_surface_destroy(w->wl_surface); +wl_surface_failure: + free(w); + return NULL; +} + +static void window_destroy(struct window* w) +{ + if (w->buffer) + buffer_destroy(w->buffer); + + xdg_toplevel_destroy(w->xdg_toplevel); + xdg_surface_destroy(w->xdg_surface); + wl_surface_destroy(w->wl_surface); + free(w); +} + int main(int argc, char* argv[]) { int rc = -1; @@ -152,11 +356,12 @@ int main(int argc, char* argv[]) xdg_wm_base_add_listener(xdg_wm_base, &xdg_wm_base_listener, NULL); wl_display_roundtrip(wl_display); - // TODO: Create window - // TODO: Create buffer - // TODO: Draw to buffer + struct window* window = window_create(512, 512, "wlvncc"); + if (!window) + goto window_failure; + + wl_display_dispatch(wl_display); -// wl_display_dispatch(wl_display); while (do_run) { wl_display_flush(wl_display); aml_poll(aml, -1); @@ -164,6 +369,8 @@ int main(int argc, char* argv[]) } rc = 0; + window_destroy(window); +window_failure: wl_compositor_destroy(wl_compositor); wl_shm_destroy(wl_shm); xdg_wm_base_destroy(xdg_wm_base);