From f4305c11aa617e4151385af13bd9e7f7e7ceafb0 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Sun, 20 Jan 2019 19:36:15 +0000 Subject: imv_source: Use callbacks, not SDL to return async results --- src/backend_freeimage.c | 47 +++++++++++++++++++++++++++++++---------------- src/imv.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- src/source.h | 20 ++++++++++++++++++++ 3 files changed, 95 insertions(+), 19 deletions(-) diff --git a/src/backend_freeimage.c b/src/backend_freeimage.c index a0908c5..65a768e 100644 --- a/src/backend_freeimage.c +++ b/src/backend_freeimage.c @@ -7,7 +7,6 @@ #include #include -#include struct private { FREE_IMAGE_FORMAT format; @@ -64,22 +63,36 @@ static struct imv_bitmap *to_imv_bitmap(FIBITMAP *in_bmp) static void report_error(struct imv_source *src) { - SDL_Event event; - SDL_zero(event); - event.type = src->error_event_id; - event.user.data1 = strdup(src->name); - SDL_PushEvent(&event); + if (!src->callback) { + fprintf(stderr, "imv_source(%s) has no callback configured. " + "Discarding error.\n", src->name); + return; + } + + struct imv_source_message msg; + msg.source = src; + msg.user_data = src->user_data; + msg.bitmap = NULL; + msg.error = "Internal error"; + + src->callback(&msg); } -static void send_bitmap(struct imv_source *src, FIBITMAP *fibitmap, int is_new_image) +static void send_bitmap(struct imv_source *src, FIBITMAP *fibitmap) { - SDL_Event event; - SDL_zero(event); - event.type = src->image_event_id; - event.user.data1 = to_imv_bitmap(fibitmap); - event.user.code = is_new_image; - FreeImage_Unload(fibitmap); - SDL_PushEvent(&event); + if (!src->callback) { + fprintf(stderr, "imv_source(%s) has no callback configured. " + "Discarding result.\n", src->name); + return; + } + + struct imv_source_message msg; + msg.source = src; + msg.user_data = src->user_data; + msg.bitmap = to_imv_bitmap(fibitmap); + msg.error = NULL; + + src->callback(&msg); } static void first_frame(struct imv_source *src) @@ -128,7 +141,7 @@ static void first_frame(struct imv_source *src) src->width = FreeImage_GetWidth(bmp); src->height = FreeImage_GetWidth(bmp); - send_bitmap(src, bmp, 1 /* is new image */); + send_bitmap(src, bmp); private->last_frame = bmp; } @@ -136,7 +149,7 @@ static void next_frame(struct imv_source *src) { struct private *private = src->private; if (src->num_frames == 1) { - send_bitmap(private->last_frame, 0 /* not a new image */); + send_bitmap(src, private->last_frame); return; } @@ -166,6 +179,8 @@ static enum backend_result open_path(const char *path, struct imv_source **src) source->time_passed = &time_passed; source->time_left = &time_left; source->free = &source_free; + source->callback = NULL; + source->user_data = NULL; source->private = private; *src = source; diff --git a/src/imv.c b/src/imv.c index 8d01b35..a90082e 100644 --- a/src/imv.c +++ b/src/imv.c @@ -79,6 +79,7 @@ struct imv { struct imv_navigator *navigator; struct imv_backend *backend; struct imv_source *source; + struct imv_source *last_source; struct imv_commands *commands; struct imv_image *image; struct imv_viewport *view; @@ -217,6 +218,40 @@ static bool add_bind(struct imv *imv, const char *keys, const char *commands) return success; } +static void source_callback(struct imv_source_message *msg) +{ + struct imv *imv = msg->user_data; + if (msg->source != imv->source) { + /* We received a message from an old source, tidy up contents + * as required, but ignore it. + */ + if (msg->bitmap) { + imv_bitmap_free(msg->bitmap); + } + return; + } + + SDL_Event event; + SDL_zero(event); + + if (msg->bitmap) { + event.type = imv->events.NEW_IMAGE; + event.user.data1 = msg->bitmap; + + /* Keep track of the last source to send us a bitmap in order to detect + * when we're getting a new image, as opposed to a new frame from the + * same image. + */ + event.user.code = msg->source != imv->last_source; + imv->last_source = msg->source; + } else { + event.type = imv->events.BAD_IMAGE; + event.user.data1 = strdup(msg->error); + } + + SDL_PushEvent(&event); +} + struct imv *imv_create(void) { struct imv *imv = malloc(sizeof(struct imv)); @@ -243,6 +278,7 @@ struct imv *imv_create(void) imv->navigator = imv_navigator_create(); imv->backend = imv_backend_freeimage(); imv->source = NULL; + imv->last_source = NULL; imv->commands = imv_commands_create(); imv->stdin_image_data = NULL; imv->stdin_image_data_len = 0; @@ -642,10 +678,15 @@ int imv_run(struct imv *imv) const char *current_path = imv_navigator_selection(imv->navigator); /* check we got a path back */ if(strcmp("", current_path)) { - enum backend_result result = imv->backend->open_path(current_path, &imv->source); + struct imv_source *new_source; + enum backend_result result = imv->backend->open_path(current_path, &new_source); if (result == BACKEND_SUCCESS) { - imv->source->image_event_id = imv->events.NEW_IMAGE; - imv->source->error_event_id = imv->events.BAD_IMAGE; + if (imv->source) { + imv->source->free(imv->source); + } + imv->source = new_source; + imv->source->callback = &source_callback; + imv->source->user_data = imv; imv->source->load_first_frame(imv->source); } diff --git a/src/source.h b/src/source.h index 6f051e3..80b1e81 100644 --- a/src/source.h +++ b/src/source.h @@ -4,6 +4,20 @@ #include #include "bitmap.h" +struct imv_source_message { + /* Pointer to sender of message */ + struct imv_source *source; + + /* User-supplied pointer */ + void *user_data; + + /* Receiver is responsible for destroying bitmap */ + struct imv_bitmap *bitmap; + + /* Error message if bitmap was NULL */ + const char *error; +}; + /* Generic source of one or more bitmaps. Essentially a single image file */ struct imv_source { /* usually the path of the image this is the source of */ @@ -41,6 +55,12 @@ struct imv_source { */ void (*free)(struct imv_source *src); + /* User-specified callback for returning messages */ + void (*callback)(struct imv_source_message *message); + + /* User-specified pointer, included in returned messages */ + void *user_data; + /* Implementation private data */ void *private; }; -- cgit v1.2.3