diff --git a/clients/simple-shm.c b/clients/simple-shm.c index a09ec910..5bc26bf7 100644 --- a/clients/simple-shm.c +++ b/clients/simple-shm.c @@ -42,22 +42,39 @@ struct display { uint32_t formats; }; +struct buffer { + struct wl_buffer *buffer; + void *shm_data; + int busy; +}; + struct window { struct display *display; int width, height; struct wl_surface *surface; struct wl_shell_surface *shell_surface; - struct wl_buffer *buffer; - void *shm_data; + struct buffer buffers[2]; + struct buffer *prev_buffer; struct wl_callback *callback; }; -static struct wl_buffer * -create_shm_buffer(struct display *display, - int width, int height, uint32_t format, void **data_out) +static void +buffer_release(void *data, struct wl_buffer *buffer) +{ + struct buffer *mybuf = data; + + mybuf->busy = 0; +} + +static const struct wl_buffer_listener buffer_listener = { + buffer_release +}; + +static int +create_shm_buffer(struct display *display, struct buffer *buffer, + int width, int height, uint32_t format) { struct wl_shm_pool *pool; - struct wl_buffer *buffer; int fd, size, stride; void *data; @@ -68,25 +85,27 @@ create_shm_buffer(struct display *display, if (fd < 0) { fprintf(stderr, "creating a buffer file for %d B failed: %m\n", size); - return NULL; + return -1; } data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { fprintf(stderr, "mmap failed: %m\n"); close(fd); - return NULL; + return -1; } pool = wl_shm_create_pool(display->shm, fd, size); - buffer = wl_shm_pool_create_buffer(pool, 0, - width, height, stride, format); + buffer->buffer = wl_shm_pool_create_buffer(pool, 0, + width, height, + stride, format); + wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer); wl_shm_pool_destroy(pool); close(fd); - *data_out = data; + buffer->shm_data = data; - return buffer; + return 0; } static void @@ -117,18 +136,10 @@ static struct window * create_window(struct display *display, int width, int height) { struct window *window; - - window = malloc(sizeof *window); - - window->buffer = create_shm_buffer(display, - width, height, - WL_SHM_FORMAT_XRGB8888, - &window->shm_data); - if (!window->buffer) { - free(window); + window = calloc(1, sizeof *window); + if (!window) return NULL; - } window->callback = NULL; window->display = display; @@ -155,12 +166,45 @@ destroy_window(struct window *window) if (window->callback) wl_callback_destroy(window->callback); - wl_buffer_destroy(window->buffer); + if (window->buffers[0].buffer) + wl_buffer_destroy(window->buffers[0].buffer); + if (window->buffers[1].buffer) + wl_buffer_destroy(window->buffers[1].buffer); + wl_shell_surface_destroy(window->shell_surface); wl_surface_destroy(window->surface); free(window); } +static struct buffer * +window_next_buffer(struct window *window) +{ + struct buffer *buffer; + int ret = 0; + + if (!window->buffers[0].busy) + buffer = &window->buffers[0]; + else if (!window->buffers[1].busy) + buffer = &window->buffers[1]; + else + return NULL; + + if (!buffer->buffer) { + ret = create_shm_buffer(window->display, buffer, + window->width, window->height, + WL_SHM_FORMAT_XRGB8888); + + if (ret < 0) + return NULL; + + /* paint the padding */ + memset(buffer->shm_data, 0xff, + window->width * window->height * 4); + } + + return buffer; +} + static void paint_pixels(void *image, int padding, int width, int height, uint32_t time) { @@ -213,8 +257,23 @@ static void redraw(void *data, struct wl_callback *callback, uint32_t time) { struct window *window = data; + struct buffer *buffer; + + buffer = window_next_buffer(window); + if (!buffer) { + fprintf(stderr, + !callback ? "Failed to create the first buffer.\n" : + "Both buffers busy at redraw(). Server bug?\n"); + abort(); + } + + paint_pixels(buffer->shm_data, 20, window->width, window->height, time); + + if (window->prev_buffer != buffer) { + wl_surface_attach(window->surface, buffer->buffer, 0, 0); + window->prev_buffer = buffer; + } - paint_pixels(window->shm_data, 20, window->width, window->height, time); wl_surface_damage(window->surface, 20, 20, window->width - 40, window->height - 40); @@ -224,6 +283,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time) window->callback = wl_surface_frame(window->surface); wl_callback_add_listener(window->callback, &frame_listener, window); wl_surface_commit(window->surface); + buffer->busy = 1; } static const struct wl_callback_listener frame_listener = { @@ -340,8 +400,9 @@ main(int argc, char **argv) sigint.sa_flags = SA_RESETHAND; sigaction(SIGINT, &sigint, NULL); - memset(window->shm_data, 0xff, window->width * window->height * 4); - wl_surface_attach(window->surface, window->buffer, 0, 0); + /* Initialise damage to full surface, so the padding gets painted */ + wl_surface_damage(window->surface, 0, 0, + window->width, window->height); redraw(window, NULL, 0);