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;
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
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;
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)
{
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);
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 = {
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);