From 9b889e14d4ff7ce089ac7cf43d7df7688f17c643 Mon Sep 17 00:00:00 2001 From: Andre Leiradella Date: Thu, 5 May 2016 09:48:50 -0300 Subject: [PATCH] http tasks can now be cancelled; on-demand thumbnail download working --- libretro-common/include/queues/task_queue.h | 9 +- libretro-common/queues/task_queue.c | 35 ++++++++ menu/drivers/xmb.c | 97 ++++++++++++++++++--- tasks/task_http.c | 12 +-- tasks/tasks_internal.h | 2 +- 5 files changed, 137 insertions(+), 18 deletions(-) diff --git a/libretro-common/include/queues/task_queue.h b/libretro-common/include/queues/task_queue.h index 7fc9e2b039..5ef6669c29 100644 --- a/libretro-common/include/queues/task_queue.h +++ b/libretro-common/include/queues/task_queue.h @@ -82,7 +82,12 @@ enum task_queue_ctl_state TASK_QUEUE_CTL_UNSET_THREADED, - TASK_QUEUE_CTL_IS_THREADED + TASK_QUEUE_CTL_IS_THREADED, + + /** + * Signals a task to end without waiting for + * it to complete. */ + TASK_QUEUE_CTL_CANCEL, }; typedef struct retro_task retro_task_t; @@ -148,6 +153,8 @@ void task_queue_push_progress(retro_task_t *task); bool task_queue_ctl(enum task_queue_ctl_state state, void *data); +void task_queue_cancel_task(void *task); + RETRO_END_DECLS #endif diff --git a/libretro-common/queues/task_queue.c b/libretro-common/queues/task_queue.c index 3c4940a24a..ec51a00904 100644 --- a/libretro-common/queues/task_queue.c +++ b/libretro-common/queues/task_queue.c @@ -39,6 +39,7 @@ typedef struct struct retro_task_impl { void (*push_running)(retro_task_t *); + void (*cancel)(void *); void (*reset)(void); void (*wait)(void); void (*gather)(void); @@ -167,6 +168,12 @@ static void retro_task_regular_push_running(retro_task_t *task) task_queue_put(&tasks_running, task); } +static void retro_task_regular_cancel(void *task) +{ + retro_task_t *t = task; + t->cancelled = true; +} + static void retro_task_regular_gather(void) { retro_task_t *task = NULL; @@ -232,6 +239,7 @@ static bool retro_task_regular_find(retro_task_finder_t func, void *user_data) static struct retro_task_impl impl_regular = { retro_task_regular_push_running, + retro_task_regular_cancel, retro_task_regular_reset, retro_task_regular_wait, retro_task_regular_gather, @@ -255,6 +263,24 @@ static void retro_task_threaded_push_running(retro_task_t *task) slock_unlock(running_lock); } +static void retro_task_threaded_cancel(void *task) +{ + retro_task_t *t; + + slock_lock(running_lock); + + for (t = tasks_running.front; t; t = t->next) + { + if (t == task) + { + t->cancelled = true; + break; + } + } + + slock_unlock(running_lock); +} + static void retro_task_threaded_gather(void) { retro_task_t *task = NULL; @@ -400,6 +426,7 @@ static void retro_task_threaded_deinit(void) static struct retro_task_impl impl_threaded = { retro_task_threaded_push_running, + retro_task_threaded_cancel, retro_task_threaded_reset, retro_task_threaded_wait, retro_task_threaded_gather, @@ -485,6 +512,9 @@ bool task_queue_ctl(enum task_queue_ctl_state state, void *data) case TASK_QUEUE_CTL_WAIT: impl_current->wait(); break; + case TASK_QUEUE_CTL_CANCEL: + impl_current->cancel(data); + break; case TASK_QUEUE_CTL_NONE: default: break; @@ -492,3 +522,8 @@ bool task_queue_ctl(enum task_queue_ctl_state state, void *data) return true; } + +void task_queue_cancel_task(void *task) +{ + task_queue_ctl(TASK_QUEUE_CTL_CANCEL, task); +} diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 65377e2ba6..a237e3202f 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1,6 +1,6 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2016 - Daniel De Matteis - * Copyright (C) 2014-2015 - Jean-André Santoni + * Copyright (C) 2014-2015 - Jean-André Santoni * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -47,6 +47,7 @@ #include "../../system.h" #include "../../tasks/tasks_internal.h" +#include #define XMB_RIBBON_ROWS 64 #define XMB_RIBBON_COLS 64 @@ -149,6 +150,7 @@ typedef struct xmb_handle uintptr_t thumbnail; float thumbnail_width; float thumbnail_height; + void *thumbnail_task; char background_file_path[PATH_MAX_LENGTH]; char thumbnail_file_path[PATH_MAX_LENGTH]; @@ -719,17 +721,91 @@ static void menu_display_handle_thumbnail_upload(void *task_data, free(img); } + +typedef struct +{ + xmb_handle_t *xmb; + char file_path[1]; +} +download_t; + +static void cb_thumbnail_download(void *task_data, void *user_data, const char *error) +{ + download_t *ud = user_data; + char output_path[PATH_MAX_LENGTH]; + http_transfer_data_t *data = (http_transfer_data_t*)task_data; + + if (!data || !data->data) + goto finished; + + ud->xmb->thumbnail_task = NULL; + + strncpy(output_path, ud->file_path, sizeof(output_path)); + output_path[sizeof(output_path) - 1] = 0; + path_basedir(output_path); + + if (!path_mkdir(output_path)) + { + RARCH_ERR("Error creating folders for file %s\n", ud->file_path); + goto finished; + } + + if (!filestream_write_file(ud->file_path, data->data, data->len)) + { + RARCH_ERR("Error writing file %s\n", ud->file_path); + goto finished; + } + + /* Only update the image on the menu if the user is still at the same entry */ + if (!strcmp(ud->file_path, ud->xmb->thumbnail_file_path)) + rarch_task_push_image_load(ud->file_path, "cb_menu_thumbnail", + menu_display_handle_thumbnail_upload, NULL); + +finished: + free(ud); +} + static void xmb_update_thumbnail_image(void *data) { xmb_handle_t *xmb = (xmb_handle_t*)data; + download_t *ud; + char buf[PATH_MAX_LENGTH]; + if (!xmb) return; + RARCH_LOG ("FILE: %s\n", xmb->thumbnail_file_path); + if (path_file_exists(xmb->thumbnail_file_path)) rarch_task_push_image_load(xmb->thumbnail_file_path, "cb_menu_thumbnail", menu_display_handle_thumbnail_upload, NULL); - else if (xmb->depth == 1) - xmb->thumbnail = 0; + else + { + ud = (download_t *)malloc(sizeof(*ud) + strlen(xmb->thumbnail_file_path)); + + if (!ud) + { + RARCH_ERR("Error allocating memory for the thumbnail download userdata\n"); + return; + } + + ud->xmb = xmb; + strcpy(ud->file_path, strdup(xmb->thumbnail_file_path)); + + snprintf(buf, sizeof(buf), "http://thumbnails.libretro.com/%s/%s/%s", + xmb->title_name, xmb_thumbnails_ident(), + path_basename(xmb->thumbnail_file_path)); + + RARCH_LOG ("URL: %s\n", buf); + + if (xmb->thumbnail_task) + task_queue_cancel_task(xmb->thumbnail_task); + + xmb->thumbnail_task = rarch_task_push_http_transfer(buf, "", cb_thumbnail_download, ud); + + if (xmb->depth == 1) + xmb->thumbnail = 0; + } } static void xmb_selection_pointer_changed( @@ -779,13 +855,6 @@ static void xmb_selection_pointer_changed( { ia = XMB_ITEM_ACTIVE_ALPHA; iz = XMB_ITEM_ACTIVE_ZOOM; - - depth = xmb_list_get_size(xmb, MENU_LIST_PLAIN); - if (strcmp(xmb_thumbnails_ident(), "OFF") && depth == 1) - { - xmb_update_thumbnail_path(xmb, i); - xmb_update_thumbnail_image(xmb); - } } if (real_iy < -threshold) @@ -2468,6 +2537,7 @@ static void *xmb_init(void **userdata) xmb->depth = 1; xmb->old_depth = 1; xmb->alpha = 0; + xmb->thumbnail_task = NULL; menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); /* TODO/FIXME - we don't use framebuffer at all @@ -2759,6 +2829,13 @@ static void xmb_navigation_set(void *data, bool scroll) { xmb_handle_t *xmb = (xmb_handle_t*)data; xmb_selection_pointer_changed(xmb, true); + + size_t selection; + if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection)) + return; + + xmb_update_thumbnail_path(xmb, selection); + xmb_update_thumbnail_image(xmb); } static void xmb_navigation_alphabet(void *data, size_t *unused) diff --git a/tasks/task_http.c b/tasks/task_http.c index c17d2c465d..f65dd6e43f 100644 --- a/tasks/task_http.c +++ b/tasks/task_http.c @@ -208,7 +208,7 @@ static bool rarch_task_http_finder(retro_task_t *task, void *user_data) return string_is_equal(http->connection.url, (const char*)user_data); } -bool rarch_task_push_http_transfer(const char *url, const char *type, +void *rarch_task_push_http_transfer(const char *url, const char *type, retro_task_callback_t cb, void *user_data) { char tmp[PATH_MAX_LENGTH]; @@ -218,7 +218,7 @@ bool rarch_task_push_http_transfer(const char *url, const char *type, http_handle_t *http = NULL; if (string_is_empty(url)) - return false; + return NULL; find_data.func = rarch_task_http_finder; find_data.userdata = (void*)url; @@ -227,13 +227,13 @@ bool rarch_task_push_http_transfer(const char *url, const char *type, if (task_queue_ctl(TASK_QUEUE_CTL_FIND, &find_data)) { RARCH_LOG("[http] '%s'' is already being downloaded.\n", url); - return false; + return NULL; } conn = net_http_connection_new(url); if (!conn) - return false; + return NULL; http = (http_handle_t*)calloc(1, sizeof(*http)); @@ -267,7 +267,7 @@ bool rarch_task_push_http_transfer(const char *url, const char *type, task_queue_ctl(TASK_QUEUE_CTL_PUSH, t); - return true; + return t; error: if (conn) @@ -277,5 +277,5 @@ error: if (http) free(http); - return false; + return NULL; } diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index 3fb56d67ce..29883e5cc5 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -34,7 +34,7 @@ typedef struct { size_t len; } http_transfer_data_t; -bool rarch_task_push_http_transfer(const char *url, const char *type, +void *rarch_task_push_http_transfer(const char *url, const char *type, retro_task_callback_t cb, void *userdata); #endif