From cc6982a792e45edbe637c15d7e5df09b86c3dafc Mon Sep 17 00:00:00 2001 From: Frederic Plourde Date: Tue, 4 Feb 2014 10:27:28 -0500 Subject: smoke-buffers.c modifications --- clients/Makefile.am | 8 + clients/smoke-buffers.c | 726 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 659 insertions(+), 75 deletions(-) diff --git a/clients/Makefile.am b/clients/Makefile.am index cad0d405..42e74621 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -59,6 +59,7 @@ clients_programs = \ cliptest \ dnd \ smoke \ + smoke-buffers \ resizor \ eventdemo \ clickdot \ @@ -86,6 +87,8 @@ libtoytoolkit_la_SOURCES = \ text-cursor-position-client-protocol.h \ subsurface-protocol.c \ subsurface-client-protocol.h \ + videosurface-protocol.c \ + videosurface-client-protocol.h \ workspaces-protocol.c \ workspaces-client-protocol.h @@ -119,6 +122,9 @@ dnd_LDADD = libtoytoolkit.la smoke_SOURCES = smoke.c smoke_LDADD = libtoytoolkit.la +smoke_buffers_SOURCES = smoke-buffers.c +smoke_buffers_LDADD = + resizor_SOURCES = resizor.c resizor_LDADD = libtoytoolkit.la @@ -212,6 +218,8 @@ BUILT_SOURCES = \ tablet-shell-protocol.c \ subsurface-client-protocol.h \ subsurface-protocol.c \ + videosurface-client-protocol.h \ + videosurface-protocol.c \ workspaces-client-protocol.h \ workspaces-protocol.c diff --git a/clients/smoke-buffers.c b/clients/smoke-buffers.c index 5d7333de..91a42d73 100644 --- a/clients/smoke-buffers.c +++ b/clients/smoke-buffers.c @@ -1,5 +1,6 @@ /* * Copyright © 2010 Kristian Høgsberg + * Copyright © 2013-2014 Collabora, Ltd. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -20,6 +21,7 @@ * OF THIS SOFTWARE. */ +#include #include #include #include @@ -28,23 +30,270 @@ #include #include #include +#include +#include "window.h" #include -#include "window.h" +#include "videosurface-client-protocol.h" + +#define SMOKE_NB_POOL_BUFFERS 30 + +struct display { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_videocompositor *videocompositor; + struct wl_shell *shell; + struct wl_shm *shm; + uint32_t formats; +}; -struct smoke { +struct Window { struct display *display; - struct window *window; - struct widget *widget; int width, height; - int current; - uint32_t time; + struct wl_surface *surface; + struct wl_shell_surface *shell_surface; + struct wl_videosurface *video_surface; + struct buffer buffers[SMOKE_NB_POOL_BUFFERS]; + struct wl_list free_buffers_list; + cairo_surface_t *surfaces[SMOKE_NB_POOL_BUFFERS]; + struct wl_callback *callback; + void *user_data; +}; + +struct buffer { + struct wl_list link; + struct wl_list *free_buffers_list; + struct wl_buffer *buffer; + struct smoke *smoke; + cairo_surface_t *surface; + void *map; +}; + +struct shm_pool { + struct wl_shm_pool *pool; + size_t size; + size_t used; + void *data; +}; + +struct smoke { + struct display *display; + struct Window *window; + struct shm_pool *pool; + uint32_t cur_time, start_time, anim; struct { float *d, *u, *v; } b[2]; + pthread_t smoker_thread; + pthread_mutex_t smoke_mutex; +}; + +/* forward declarations */ +struct smoke; +static void display_add_input(struct display *d, uint32_t id); + +static void +buffer_release(void *data, struct wl_buffer *buffer) +{ + struct buffer *buf = data; + + wl_list_insert(buf->free_buffers_list, &buf->link); +} + +static const struct wl_buffer_listener buffer_listener = { + buffer_release +}; + +//static const struct wl_videosurface_listener video_surface_listener = { + /* Write the event listeners here when we've got some */ +//}; + +static void +handle_ping(void *data, struct wl_shell_surface *shell_surface, + uint32_t serial) +{ + wl_shell_surface_pong(shell_surface, serial); +} + +static void +handle_configure(void *data, struct wl_shell_surface *shell_surface, + uint32_t edges, int32_t width, int32_t height) +{ +} + +static void +handle_popup_done(void *data, struct wl_shell_surface *shell_surface) +{ +} + +static const struct wl_shell_surface_listener shell_surface_listener = { + handle_ping, + handle_configure, + handle_popup_done }; +static struct Window * +create_window(struct display *display, int width, int height) +{ + struct Window *window; + + window = calloc(1, sizeof *window); + if (!window) + return NULL; + + window->callback = NULL; + window->display = display; + window->width = width; + window->height = height; + window->surface = wl_compositor_create_surface(display->compositor); + + if (window->surface) { + + window->video_surface = wl_videocompositor_get_videosurface( + display->videocompositor, window->surface); + /* TODO: + * Someday, we'll have some events to listen to... + + if (window->video_surface) + wl_video_surface_add_listener(window->video_surface, + &video_surface_listener, window); + */ + + window->shell_surface = wl_shell_get_shell_surface(display->shell, + window->surface); + + if (window->shell_surface) + wl_shell_surface_add_listener(window->shell_surface, + &shell_surface_listener, window); + + wl_shell_surface_set_title(window->shell_surface, "Smoky buffer queues"); + wl_shell_surface_set_toplevel(window->shell_surface); + } + + return window; +} + +static void +destroy_window(struct window *window, struct smoke *smoke) +{ + int i; + + if (window->callback) + wl_callback_destroy(window->callback); + + for (i = 0; i < SMOKE_NB_POOL_BUFFERS; i++) { + if (smoke->buffers[i].buffer) + wl_buffer_destroy(smoke->buffers[i].buffer); + } + + wl_shell_surface_destroy(window->shell_surface); + wl_surface_destroy(window->surface); + free(window); +} + +static void +shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) +{ + struct display *d = data; + + d->formats |= (1 << format); +} + +struct wl_shm_listener shm_listenter = { + shm_format +}; + +static void +registry_handle_global(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t version) +{ + struct display *d = data; + + if (strcmp(interface, "wl_compositor") == 0) { + d->compositor = + wl_registry_bind(registry, + id, &wl_compositor_interface, 1); + } else if (strcmp(interface, "wl_shell") == 0) { + d->shell = wl_registry_bind(registry, + id, &wl_shell_interface, 1); + } else if (strcmp(interface, "wl_seat") == 0) { + display_add_input(d, id); + } else if (strcmp(interface, "wl_shm") == 0) { + d->shm = wl_registry_bind(registry, + id, &wl_shm_interface, 1); + wl_shm_add_listener(d->shm, &shm_listenter, d); + } else if (strcmp(interface, "wl_videocompositor") == 0) { + d->videocompositor = + wl_registry_bind(registry, id, + &wl_videocompositor_interface, 1); + } +} + +static void +registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static struct display * +create_display(void) +{ + struct display *display; + + display = malloc(sizeof *display); + display->display = wl_display_connect(NULL); + assert(display->display); + + display->formats = 0; + display->registry = wl_display_get_registry(display->display); + wl_registry_add_listener(display->registry, + ®istry_listener, display); + wl_display_roundtrip(display->display); + if (display->shm == NULL) { + fprintf(stderr, "No wl_shm global\n"); + exit(1); + } + + wl_display_roundtrip(display->display); + + if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888))) { + fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n"); + exit(1); + } + + wl_display_get_fd(display->display); + + return display; +} + +static void +destroy_display(struct display *display) +{ + if (display->shm) + wl_shm_destroy(display->shm); + + if (display->shell) + wl_shell_destroy(display->shell); + + if (display->compositor) + wl_compositor_destroy(display->compositor); + + wl_registry_destroy(display->registry); + wl_display_flush(display->display); + wl_display_disconnect(display->display); + free(display); +} + static void diffuse(struct smoke *smoke, uint32_t time, float *source, float *dest) { + /* time is NOT used atm... but should be set to + * the time in msecs since last render... that will + * let us "scale" the animation time (if not, it will be too fast) */ float *s, *d; int x, y, k, stride; float t, a = 0.0002; @@ -67,6 +316,9 @@ static void diffuse(struct smoke *smoke, uint32_t time, static void advect(struct smoke *smoke, uint32_t time, float *uu, float *vv, float *source, float *dest) { + /* time is NOT used atm... but should be set to + * the time in msecs since last render... that will + * let us "scale" the animation time (if not, it will be too fast) */ float *s, *d; float *u, *v; int x, y, stride; @@ -105,6 +357,9 @@ static void advect(struct smoke *smoke, uint32_t time, static void project(struct smoke *smoke, uint32_t time, float *u, float *v, float *p, float *div) { + /* time is NOT used atm... but should be set to + * the time in msecs since last render... that will + * let us "scale" the animation time (if not, it will be too fast) */ int x, y, k, l, s; float h; @@ -155,7 +410,7 @@ static void render(struct smoke *smoke, cairo_surface_t *surface) stride = cairo_image_surface_get_stride(surface); for (y = 1; y < height - 1; y++) { - s = smoke->b[smoke->current].d + y * smoke->height; + s = smoke->b[0].d + y * smoke->height; d = (uint32_t *) (dest + y * stride); for (x = 1; x < width - 1; x++) { c = (int) (s[x] * 800); @@ -169,69 +424,107 @@ static void render(struct smoke *smoke, cairo_surface_t *surface) } } +static const struct wl_callback_listener frame_listener; + +static void +window_set_user_data(struct window *window, void *data) +{ + window->user_data = data; +} + +static void * +window_get_user_data(struct window *window) +{ + return window->user_data; +} + static void -frame_callback(void *data, struct wl_callback *callback, uint32_t time) +frame_handle_redraw(void *data, struct wl_callback *callback, uint32_t time) { - struct smoke *smoke = data; + /* TODO: This will mostly all go away (except for time udpate) + * and be relocated inside a idle-spinning loop (another thread) + */ + struct window *window = data; + //struct smoke *smoke = (struct smoke*) window_get_user_data(window); - window_schedule_redraw(smoke->window); - smoke->time = time; + /* The rendering part was here formely */ if (callback) wl_callback_destroy(callback); + + window->callback = wl_surface_frame(window->surface); + wl_callback_add_listener(window->callback, &frame_listener, window); } -static const struct wl_callback_listener listener = { - frame_callback, +static const struct wl_callback_listener frame_listener = { + frame_handle_redraw }; static void -redraw_handler(struct widget *widget, void *data) +seat_handle_capabilities(void *data, struct wl_seat *seat, + enum wl_seat_capability caps) { - struct smoke *smoke = data; - uint32_t time = smoke->time; - struct wl_callback *callback; - cairo_surface_t *surface; - - diffuse(smoke, time / 30, smoke->b[0].u, smoke->b[1].u); - diffuse(smoke, time / 30, smoke->b[0].v, smoke->b[1].v); - project(smoke, time / 30, - smoke->b[1].u, smoke->b[1].v, - smoke->b[0].u, smoke->b[0].v); - advect(smoke, time / 30, - smoke->b[1].u, smoke->b[1].v, - smoke->b[1].u, smoke->b[0].u); - advect(smoke, time / 30, - smoke->b[1].u, smoke->b[1].v, - smoke->b[1].v, smoke->b[0].v); - project(smoke, time / 30, - smoke->b[0].u, smoke->b[0].v, - smoke->b[1].u, smoke->b[1].v); - - diffuse(smoke, time / 30, smoke->b[0].d, smoke->b[1].d); - advect(smoke, time / 30, - smoke->b[0].u, smoke->b[0].v, - smoke->b[1].d, smoke->b[0].d); - - surface = window_get_surface(smoke->window); + struct input *input = data; + + /* We are only interested in POINTER events */ + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) { + input->pointer = wl_seat_get_pointer(seat); + wl_pointer_set_user_data(input->pointer, input); + wl_pointer_add_listener(input->pointer, &pointer_listener, + input); + } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) { + wl_pointer_destroy(input->pointer); + input->pointer = NULL; + } +} - render(smoke, surface); +static const struct wl_seat_listener seat_listener = { + seat_handle_capabilities, +}; - window_damage(smoke->window, 0, 0, smoke->width, smoke->height); - cairo_surface_destroy(surface); +static void +pointer_handle_enter(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t sx_w, wl_fixed_t sy_w) +{ +} - callback = wl_surface_frame(window_get_wl_surface(smoke->window)); - wl_callback_add_listener(callback, &listener, smoke); - wl_surface_commit(window_get_wl_surface(smoke->window)); +static void +pointer_handle_leave(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface) +{ } -static int -smoke_motion_handler(struct widget *widget, struct input *input, - uint32_t time, float x, float y, void *data) +static void +pointer_handle_motion(void *data, struct wl_pointer *pointer, + uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) { - struct smoke *smoke = data; + struct input *input = data; + struct window *window = input->pointer_focus; + struct smoke *smoke = (struct smoke*) window_get_user_data(window); int i, i0, i1, j, j0, j1, k, d = 5; + float sx = wl_fixed_to_double(sx_w); + float sy = wl_fixed_to_double(sy_w); + + if (!window) + return; + + /* TODO: + * let's TAKE OWNERSHIP of a MUTEX here on the values used by both + * motion_handler and render in the smoker thread. We have to prevent + * the two from reading/updating b[x] at the same time... + * so I guess just a nice pthread_mutex_lock/unlock will do the trick + * ... + * ... + */ + + /* We clear the buffer queue */ + wl_videosurface_clear_queue(window->video_surface); + + /* FIXME: Here, add x = sx; y = sx, but in a 3-equality style */ + input->sx = sx; + input->sy = sy; if (x - d < 1) i0 = 1; @@ -259,45 +552,319 @@ smoke_motion_handler(struct widget *widget, struct input *input, smoke->b[0].d[k] += 1; } - return CURSOR_HAND1; + smoke->anim = 0; +} + +static void +pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state_w) +{ +} + +static void +pointer_handle_axis(void *data, struct wl_pointer *pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) +{ +} + +static const struct wl_pointer_listener pointer_listener = { + pointer_handle_enter, + pointer_handle_leave, + pointer_handle_motion, + pointer_handle_button, + pointer_handle_axis, +}; + +static void +display_add_input(struct display *d, uint32_t id) +{ + struct input *input; + + input = malloc(sizeof *input); + if (input == NULL) + return; + + memset(input, 0, sizeof *input); + input->display = d; + input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1); + input->pointer_focus = NULL; + input->keyboard_focus = NULL; + wl_list_insert(d->input_list.prev, &input->link); + + wl_seat_add_listener(input->seat, &seat_listener, input); + wl_seat_set_user_data(input->seat, input); + + input->data_device = + wl_data_device_manager_get_data_device(d->data_device_manager, + input->seat); + wl_data_device_add_listener(input->data_device, &data_device_listener, + input); + + input->pointer_surface = wl_compositor_create_surface(d->compositor); + + input->repeat_timer_fd = timerfd_create(CLOCK_MONOTONIC, + TFD_CLOEXEC | TFD_NONBLOCK); + input->repeat_task.run = keyboard_repeat_func; + display_watch_fd(d, input->repeat_timer_fd, + EPOLLIN, &input->repeat_task); } static void -resize_handler(struct widget *widget, - int32_t width, int32_t height, void *data) +input_destroy(struct input *input) { - struct smoke *smoke = data; + input_remove_keyboard_focus(input); + input_remove_pointer_focus(input); + + if (input->drag_offer) + data_offer_destroy(input->drag_offer); + + if (input->selection_offer) + data_offer_destroy(input->selection_offer); + + wl_data_device_destroy(input->data_device); + fini_xkb(input); - /* Dont resize me */ - widget_set_size(smoke->widget, smoke->width, smoke->height); + wl_surface_destroy(input->pointer_surface); + + wl_list_remove(&input->link); + wl_seat_destroy(input->seat); + close(input->repeat_timer_fd); + free(input); +} + +static struct buffer * +get_next_pool_buffer(struct smoke *smoke) +{ + if (!wl_list_empty(&smoke->free_buffers_list)) + return container_of(smoke->free_buffers_list.next, struct buffer, link); + else + return NULL; +} + +static void * +smoker_thread_run(void *arg) +{ + struct timespec ts; + struct buffer *buffer; + uint32_t timestamp; + struct smoke *smoke = (struct smoke *) arg; + cairo_surface_t *surface; + + /* TODO: + * let's take MUTEX here on the b[] values + * ... + * ... + */ + + if (anim == 0) { + clock_gettime(CLOCK_MONOTONIC, &ts); + smoke->start_time = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + } + + /* time is NOT used atm... but should be set to + * the time in msecs since last render... that will + * let us "scale" the animation time (if not, it will be too fast) */ + + diffuse(smoke, smoke->cur_time / 30, smoke->b[0].u, smoke->b[1].u); + diffuse(smoke, smoke->cur_time / 30, smoke->b[0].v, smoke->b[1].v); + project(smoke, smoke->cur_time / 30, + smoke->b[1].u, smoke->b[1].v, + smoke->b[0].u, smoke->b[0].v); + advect(smoke, smoke->cur_time / 30, + smoke->b[1].u, smoke->b[1].v, + smoke->b[1].u, smoke->b[0].u); + advect(smoke, smoke->cur_time / 30, + smoke->b[1].u, smoke->b[1].v, + smoke->b[1].v, smoke->b[0].v); + project(smoke, smoke->cur_time / 30, + smoke->b[0].u, smoke->b[0].v, + smoke->b[1].u, smoke->b[1].v); + + diffuse(smoke, smoke->cur_time / 30, smoke->b[0].d, smoke->b[1].d); + advect(smoke, smoke->cur_time / 30, + smoke->b[0].u, smoke->b[0].v, + smoke->b[1].d, smoke->b[0].d); + + /* Get the next available buffer */ + buffer = get_next_pool_buffer(smoke); + + render(smoke, buffer->surface); + + /* FIXME: This 1000/60 IMPLIES scanout at 60 FPS !!*/ + timestamp = smoke->start_time + (1000 * smoke->anim / 60); + wl_videosurface_queue_buffer(&smoke->window->video_surface, buffer->buffer, ); + + smoke->anim++; +} + +/* The smoker thread will render smoke frames as fast as it can + * and queue buffers in the compositor as they are ready. The output + * part will then be overtaken by the compositor itself. No need to + * .attach or .commit the contents on the window's surface + * + * note : the thread's scheduling policy is IDLE + */ +static int +create_smoker_thread(struct smoke *smoke) +{ + pthread_attr_t attr; + struct sched_param schedparam; + int s; + + s = pthread_attr_init(&attr); + schedparam.sched_priority = 0; + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + + if (pthread_attr_setschedparam(&attr, &schedparam) != 0) { + printf("Error! Could not set scheduler parameters\n"); + return -1; + } + + s = pthread_create(&window->smoker_thread, + &attr, smoker_thread_run, (void *) smoke); + if (s != 0) { + printf("Error! Could not create smoker thread\n"); + return -1; + } + + if (pthread_attr_destroy(&attr) != 0) { + printf("Error! Could not destroy thread attributes\n"); + return -1; + } + + return 0; +} + +static struct wl_shm_pool * +make_shm_pool(struct display *display, int size, void **data) +{ + struct wl_shm_pool *pool; + int fd; + + fd = os_create_anonymous_file(size); + if (fd < 0) { + fprintf(stderr, "creating a buffer file for %d B failed: %m\n", + size); + return NULL; + } + + *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; + } + + pool = wl_shm_create_pool(display->shm, fd, size); + + close(fd); + + return pool; +} + +static struct shm_pool * +shm_pool_create(struct display *display, size_t size) +{ + struct shm_pool *pool = malloc(sizeof *pool); + + if (!pool) + return NULL; + + pool->pool = make_shm_pool(display, size, &pool->data); + if (!pool->pool) { + free(pool); + return NULL; + } + + pool->size = size; + pool->used = 0; + + return pool; +} + +static int +data_length_for_shm_surface(struct rectangle *rect) +{ + int stride; + + stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, + rect->width); + return stride * rect->height; +} + +static int +create_shm_pool(struct smoke *smoke) +{ + int i, ret = 0; + struct rect; + struct shm_pool *pool; + cairo_surface_t *surface; + uint32_t offset; + int stride; + + rect.width = smoke->width; + rect.height = smoke->height; + + stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, rect.width); + pool = shm_pool_create(smoke->display, SMOKE_NB_POOL_BUFFERS * stride * rect.height); + if (!pool) + ret = 1; + else { + for (i = 0; i < SMOKE_NB_POOL_BUFFERS; i++) { + offset = i * rect.width * rect.height; + smoke->buffers[i].smoke = smoke; + smoke->buffers[i].buffer = wl_shm_pool_create_buffer(pool->pool, + offset, rect.width, + rect.height, stride, WL_SHM_FORMAT_XRGB8888); + smoke->buffers[i].map = (void *) pool->data + offset; + smoke->buffers[i].free_buffers_list = &smoke->free_buffers_list; + wl_list_insert(&smoke->free_buffers_list, &smoke->buffers[i].link); + wl_buffer_add_listener(smoke->buffers[i].buffer, &buffer_listener, buffer); + + surface = cairo_image_surface_create_for_data (smoke->buffers[i].map, + CAIRO_FORMAT_ARGB32, rect->width, rect->height, + stride); + + smoke->buffers[i].surface = surface; + } + } + + return ret; } int main(int argc, char *argv[]) { struct timespec ts; struct smoke smoke; - struct display *d; + struct display *display = NULL; + struct Window *window = NULL; + struct shm_pool *pool; int size; - d = display_create(&argc, argv); - if (d == NULL) { + display = create_display(); + if (display == NULL) { fprintf(stderr, "failed to create display: %m\n"); - return -1; + return 1; + } + smoke.display = display; + + window = create_window(display, 200, 200); + if (window == NULL) { + fprintf(stderr, "failed to create window: %m\n"); + return 1; } + smoke.window = window; - smoke.width = 200; - smoke.height = 200; - smoke.display = d; - smoke.window = window_create(d); - smoke.widget = window_add_widget(smoke.window, &smoke); - window_set_title(smoke.window, "smoke"); + wl_list_init(&smoke.free_buffers_list); + if (create_pool_and_buffers(smoke) != 0) + return 1; - window_set_buffer_type(smoke.window, WINDOW_BUFFER_TYPE_SHM); clock_gettime(CLOCK_MONOTONIC, &ts); srandom(ts.tv_nsec); + smoke->cur_time = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; - smoke.current = 0; - size = smoke.height * smoke.width; + size = smoke.window->height * smoke.window->width; smoke.b[0].d = calloc(size, sizeof(float)); smoke.b[0].u = calloc(size, sizeof(float)); smoke.b[0].v = calloc(size, sizeof(float)); @@ -305,15 +872,24 @@ int main(int argc, char *argv[]) smoke.b[1].u = calloc(size, sizeof(float)); smoke.b[1].v = calloc(size, sizeof(float)); - widget_set_motion_handler(smoke.widget, smoke_motion_handler); - widget_set_resize_handler(smoke.widget, resize_handler); - widget_set_redraw_handler(smoke.widget, redraw_handler); - window_set_user_data(smoke.window, &smoke); - widget_schedule_resize(smoke.widget, smoke.width, smoke.height); + /* Initialise damage to full surface, so the padding gets painted */ + wl_surface_damage(window->surface, 0, 0, window->width, window->height); + + /* FIXME: do we put 0 here for time, or ts ? */ + frame_handle_redraw(window, NULL, 0); + + /* Create our smoke-rendering thread */ + if (create_smoker_thread(&smoke) != 0) + return 1; + + while (running && ret != -1) + ret = wl_display_dispatch(display->display); - display_run(d); + fprintf(stderr, "simple-shm exiting\n"); + destroy_window(window, &smoke); + destroy_display(display); return 0; } -- cgit v1.2.3