From 2f719d8e071751615a0d6b91e15d9fc723061b8f Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 1 Jun 2026 16:58:28 +0000 Subject: [PATCH] Remove blocks --- plugins/gtkui/covermanager/albumartwidget.c | 79 +++-- plugins/gtkui/covermanager/covermanager.c | 166 +++++---- plugins/gtkui/covermanager/covermanager.h | 21 +- plugins/gtkui/fileman.c | 358 ++++++++++++-------- plugins/gtkui/gtkui.c | 40 ++- plugins/gtkui/gtkui.h | 2 +- plugins/gtkui/medialib/medialibwidget.c | 64 ++-- plugins/gtkui/playlist/playlistcontroller.c | 21 +- plugins/gtkui/prefwin/prefwinmedialib.c | 68 ++-- 9 files changed, 505 insertions(+), 314 deletions(-) diff --git a/plugins/gtkui/covermanager/albumartwidget.c b/plugins/gtkui/covermanager/albumartwidget.c index 90636d178..1dd53f610 100644 --- a/plugins/gtkui/covermanager/albumartwidget.c +++ b/plugins/gtkui/covermanager/albumartwidget.c @@ -30,7 +30,6 @@ #include "albumartwidget.h" #include "covermanager.h" #include "gobjcache.h" -#include #include "../gtkui.h" #define min(x, y) ((x) < (y) ? (x) : (y)) @@ -63,6 +62,42 @@ typedef struct { GtkWidget *mode_playing_or_selected_track; } w_albumart_t; +typedef struct { + w_albumart_t *w; + covermanager_t *cm; + GtkAllocation availableSize; + int64_t currentIndex; +} albumart_cover_callback_ctx_t; + +static void albumart_cover_callback(GdkPixbuf *img, void *user_ctx) { + albumart_cover_callback_ctx_t *ctx = (albumart_cover_callback_ctx_t *)user_ctx; + w_albumart_t *w = ctx->w; + covermanager_t *cm = ctx->cm; + GtkAllocation availableSize = ctx->availableSize; + int64_t currentIndex = ctx->currentIndex; + + if (currentIndex != w->request_index - 1) { + free(ctx); + return; + } + if (img != NULL) { + GtkAllocation originalSize = { 0 }; + originalSize.width = gdk_pixbuf_get_width(img); + originalSize.height = gdk_pixbuf_get_height(img); + GtkAllocation desired_size = covermanager_desired_size_for_image_size(cm, originalSize, availableSize); + GdkPixbuf *scaled_image = covermanager_create_scaled_image(cm, img, desired_size); + w->image = scaled_image; + } + else { + if (w->image != NULL) { + gobj_unref(w->image); + w->image = NULL; + } + } + gtk_widget_queue_draw(w->drawing_area); + free(ctx); +} + static gboolean _update (w_albumart_t *w) { if (w->plugin == NULL) { @@ -123,26 +158,16 @@ _update (w_albumart_t *w) { covermanager_t *cm = covermanager_shared (); - GdkPixbuf *image = covermanager_cover_for_track (cm, it, w->source_id, ^(GdkPixbuf *img) { - if (currentIndex != w->request_index - 1) { - return; - } - if (img != NULL) { - GtkAllocation originalSize = { 0 }; - originalSize.width = gdk_pixbuf_get_width (img); - originalSize.height = gdk_pixbuf_get_height (img); - GtkAllocation desired_size = covermanager_desired_size_for_image_size (cm, originalSize, availableSize); - GdkPixbuf *scaled_image = covermanager_create_scaled_image (cm, img, desired_size); - w->image = scaled_image; - } - else { - if (w->image != NULL) { - gobj_unref (w->image); - w->image = NULL; - } - } - gtk_widget_queue_draw (w->drawing_area); - }); + albumart_cover_callback_ctx_t *cb_ctx = malloc(sizeof(albumart_cover_callback_ctx_t)); + cb_ctx->w = w; + cb_ctx->cm = cm; + cb_ctx->availableSize = availableSize; + cb_ctx->currentIndex = currentIndex; + + GdkPixbuf *image = covermanager_cover_for_track( + cm, it, w->source_id, + albumart_cover_callback, cb_ctx + ); deadbeef->pl_item_unref (it); it = NULL; @@ -180,6 +205,10 @@ _size_did_change (GtkWidget *self, GdkEventConfigure *event, w_albumart_t *w) { return FALSE; } +static void throttled_update_cb(void *user_data) { + _throttled_update((w_albumart_t *)user_data); +} + static int _message (ddb_gtkui_widget_t *base, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) { w_albumart_t *w = (w_albumart_t *)base; @@ -190,9 +219,7 @@ _message (ddb_gtkui_widget_t *base, uint32_t id, uintptr_t ctx, uint32_t p1, uin case DB_EV_PLAYLISTCHANGED: case DB_EV_PLAYLISTSWITCHED: case DB_EV_CURSOR_MOVED: { - gtkui_dispatch_on_main (^{ - _throttled_update (w); - }); + gtkui_dispatch_on_main(throttled_update_cb, w); } break; } return 0; @@ -341,9 +368,7 @@ static void _artwork_listener (ddb_artwork_listener_event_t event, void *user_data, int64_t p1, int64_t p2) { w_albumart_t *w = (w_albumart_t *)user_data; if (event == DDB_ARTWORK_SETTINGS_DID_CHANGE) { - gtkui_dispatch_on_main (^{ - _throttled_update (w); - }); + gtkui_dispatch_on_main(throttled_update_cb, w); } } diff --git a/plugins/gtkui/covermanager/covermanager.c b/plugins/gtkui/covermanager/covermanager.c index cf732f691..8d7559e94 100644 --- a/plugins/gtkui/covermanager/covermanager.c +++ b/plugins/gtkui/covermanager/covermanager.c @@ -27,7 +27,6 @@ #include "../../artwork/artwork.h" #include "covermanager.h" #include "gobjcache.h" -#include #include "gtkui.h" #define min(x, y) ((x) < (y) ? (x) : (y)) @@ -40,7 +39,8 @@ extern DB_functions_t *deadbeef; typedef struct cover_completion_block_list_item_s { struct cover_completion_block_list_item_s *next; int want_default; - covermanager_completion_block_t completion_block; + void (*completion_func)(GdkPixbuf *, void *); + void *completion_ctx; } cover_completion_block_list_item_t; typedef struct { @@ -114,15 +114,29 @@ _settings_did_change_for_track (covermanager_t *manager, ddb_playItem_t *track) } } -static void -_artwork_listener (ddb_artwork_listener_event_t event, void *user_data, int64_t p1, int64_t p2) { - covermanager_t *manager = user_data; +typedef struct { + ddb_artwork_listener_event_t event; + covermanager_t *manager; + int64_t p1; +} artwork_listener_ctx_t; - gtkui_dispatch_on_main (^{ - if (event == DDB_ARTWORK_SETTINGS_DID_CHANGE) { - _settings_did_change_for_track (manager, (ddb_playItem_t *)p1); - } - }); +static gboolean +_artwork_listener_main_cb(gpointer data) { + artwork_listener_ctx_t *ctx = data; + if (ctx->event == DDB_ARTWORK_SETTINGS_DID_CHANGE) { + _settings_did_change_for_track(ctx->manager, (ddb_playItem_t *)ctx->p1); + } + g_free(ctx); + return FALSE; +} + +static void +_artwork_listener(ddb_artwork_listener_event_t event, void *user_data, int64_t p1, int64_t p2) { + artwork_listener_ctx_t *ctx = g_malloc(sizeof(artwork_listener_ctx_t)); + ctx->event = event; + ctx->manager = user_data; + ctx->p1 = p1; + g_idle_add(_artwork_listener_main_cb, ctx); } static char * @@ -250,7 +264,9 @@ _callback_and_cleanup (ddb_cover_query_t *query, ddb_cover_info_t *cover, GdkPix } } - item->completion_block (img); + if (item->completion_func) { + item->completion_func(img, item->completion_ctx); + } item = item->next; } } @@ -262,42 +278,73 @@ _callback_and_cleanup (ddb_cover_query_t *query, ddb_cover_info_t *cover, GdkPix _cleanup_query(query); - // Release the cover on background queue + // Release the cover (synchronously for simplicity with GCC compatibility) if (cover != NULL) { - dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - impl->plugin->cover_info_release (cover); - }); + impl->plugin->cover_info_release(cover); } } +typedef struct { + ddb_cover_query_t *query; + ddb_cover_info_t *cover; + GdkPixbuf *img; +} cover_callback_and_cleanup_ctx_t; + +static void +_callback_and_cleanup_cb(void *user_data) { + cover_callback_and_cleanup_ctx_t *ctx = user_data; + _callback_and_cleanup(ctx->query, ctx->cover, ctx->img); + free(ctx); +} + +typedef struct { + int error; + ddb_cover_query_t *query; + ddb_cover_info_t *cover; +} cover_loaded_ctx_t; + static void -_cover_loaded_callback (int error, ddb_cover_query_t *query, ddb_cover_info_t *cover) { +_cover_loaded_background(void *context) { + cover_loaded_ctx_t *ctx = context; + ddb_cover_query_t *query = ctx->query; + ddb_cover_info_t *cover = ctx->cover; query_userdata_t *user_data = query->user_data; covermanager_t *impl = user_data->impl; if (impl->is_terminating) { - _cleanup_query (query); + _cleanup_query(query); + free(ctx); return; } - // Load the image on background queue - dispatch_async (impl->loader_queue, ^{ - if (impl->is_terminating) { - _cleanup_query (query); - return; - } + GdkPixbuf *img = NULL; + if (!(query->flags & DDB_ARTWORK_FLAG_CANCELLED)) { + img = _load_image_from_cover(impl, cover); + } - __block GdkPixbuf *img = NULL; + cover_callback_and_cleanup_ctx_t *main_ctx = malloc(sizeof(cover_callback_and_cleanup_ctx_t)); + main_ctx->query = query; + main_ctx->cover = cover; + main_ctx->img = img; + gtkui_dispatch_on_main(_callback_and_cleanup_cb, main_ctx); + free(ctx); +} - if (!(query->flags & DDB_ARTWORK_FLAG_CANCELLED)) { - img = _load_image_from_cover (impl, cover); - } +static void +_cover_loaded_callback(int error, ddb_cover_query_t *query, ddb_cover_info_t *cover) { + query_userdata_t *user_data = query->user_data; + covermanager_t *impl = user_data->impl; + + if (impl->is_terminating) { + _cleanup_query(query); + return; + } - // Update the UI on main queue - gtkui_dispatch_on_main (^{ - _callback_and_cleanup (query, cover, img); - }); - }); + cover_loaded_ctx_t *ctx = malloc(sizeof(cover_loaded_ctx_t)); + ctx->error = error; + ctx->query = query; + ctx->cover = cover; + dispatch_async_f(impl->loader_queue, ctx, _cover_loaded_background); } covermanager_t * @@ -324,8 +371,7 @@ _cover_request_free(gpointer data) { cover_completion_block_list_item_t *item = req->completion_blocks; while (item != NULL) { cover_completion_block_list_item_t *next = item->next; - Block_release(item->completion_block); - free (item); + free(item); item = next; } free(req); @@ -398,9 +444,9 @@ covermanager_free (covermanager_t *impl) { } static gboolean -_add_pending_request (covermanager_t *impl, const char *key, covermanager_completion_block_t completion_block, int want_default) { +_add_pending_request(covermanager_t *impl, const char *key, void (*completion_func)(GdkPixbuf *, void *), void *completion_ctx, int want_default) { gboolean result = FALSE; - cover_request_t *request = g_hash_table_lookup (impl->pending_requests, key); + cover_request_t *request = g_hash_table_lookup(impl->pending_requests, key); if (request == NULL) { request = calloc(sizeof(cover_request_t), 1); g_hash_table_insert(impl->pending_requests, strdup(key), request); @@ -409,7 +455,8 @@ _add_pending_request (covermanager_t *impl, const char *key, covermanager_comple cover_completion_block_list_item_t *item = calloc(sizeof(cover_completion_block_list_item_t), 1); item->want_default = want_default; - item->completion_block = Block_copy(completion_block); + item->completion_func = completion_func; + item->completion_ctx = completion_ctx; item->next = request->completion_blocks; request->completion_blocks = item; @@ -417,69 +464,74 @@ _add_pending_request (covermanager_t *impl, const char *key, covermanager_comple } static GdkPixbuf * -_cover_for_track ( +_cover_for_track( covermanager_t *impl, int want_default, DB_playItem_t *track, int64_t source_id, - covermanager_completion_block_t completion_block) { + void (*completion_func)(GdkPixbuf *, void *), + void *completion_ctx) { if (!impl->plugin) { - completion_block (NULL); + if (completion_func) { + completion_func(NULL, completion_ctx); + } return NULL; } - char *key = _cache_key_for_track (impl, track); - GdkPixbuf *cover = GDK_PIXBUF (gobj_cache_get (impl->cache, key)); + char *key = _cache_key_for_track(impl, track); + GdkPixbuf *cover = GDK_PIXBUF(gobj_cache_get(impl->cache, key)); // FIXME: need to check whether the cache has NULL object for the key if (cover != NULL) { - // completion_block is not executed if the image is non-nil, to avoid double drawing. + // completion_func is not executed if the image is non-nil, to avoid double drawing. // The caller must release user data if the returned image is not nil. - free (key); + free(key); key = NULL; return cover; } - gboolean is_new_request = _add_pending_request (impl, key, completion_block, want_default); + gboolean is_new_request = _add_pending_request(impl, key, completion_func, completion_ctx, want_default); if (!is_new_request) { - free (key); + free(key); key = NULL; return NULL; } - ddb_cover_query_t *query = calloc (1, sizeof (ddb_cover_query_t)); - query->_size = sizeof (ddb_cover_query_t); + ddb_cover_query_t *query = calloc(1, sizeof(ddb_cover_query_t)); + query->_size = sizeof(ddb_cover_query_t); query->track = track; - deadbeef->pl_item_ref (track); + deadbeef->pl_item_ref(track); query->source_id = source_id; - query_userdata_t *data = calloc (1, sizeof (query_userdata_t)); + query_userdata_t *data = calloc(1, sizeof(query_userdata_t)); data->impl = impl; data->key = key; // transfer ownership here, no need to free query->user_data = (void *)data; key = NULL; - impl->plugin->cover_get (query, _cover_loaded_callback); + impl->plugin->cover_get(query, _cover_loaded_callback); return NULL; } GdkPixbuf * -covermanager_cover_for_track_no_default ( +covermanager_cover_for_track_no_default( covermanager_t *impl, DB_playItem_t *track, int64_t source_id, - covermanager_completion_block_t completion_block) { - return _cover_for_track (impl, 0, track, source_id, completion_block); + covermanager_completion_func_t completion_func, + void *completion_ctx) { + return _cover_for_track(impl, 0, track, source_id, completion_func, completion_ctx); } GdkPixbuf * -covermanager_cover_for_track ( +covermanager_cover_for_track( covermanager_t *impl, DB_playItem_t *track, int64_t source_id, - covermanager_completion_block_t completion_block) { - return _cover_for_track (impl, 1, track, source_id, completion_block); + covermanager_completion_func_t completion_func, + void *completion_ctx) { + return _cover_for_track(impl, 1, track, source_id, completion_func, completion_ctx); } GdkPixbuf * diff --git a/plugins/gtkui/covermanager/covermanager.h b/plugins/gtkui/covermanager/covermanager.h index f7f35689b..3c4933d26 100644 --- a/plugins/gtkui/covermanager/covermanager.h +++ b/plugins/gtkui/covermanager/covermanager.h @@ -31,9 +31,7 @@ typedef struct covermanager_s covermanager_t; -/// Called by @c covermanager_cover_for_track when the cover is ready. -/// The @c img argument is not retained, and will be released after the block completes. -typedef void (^covermanager_completion_block_t) (GdkPixbuf *img); +typedef void (*covermanager_completion_func_t)(GdkPixbuf *img, void *ctx); covermanager_t * covermanager_shared (void); @@ -51,15 +49,22 @@ void covermanager_free (covermanager_t *manager); /// Gets the cover from in-memory cache, or initiates asynchronous request to cache it. -/// -/// If the cover is immediately available -- it will be returned (retained), and the @c completion_block will not be called. -/// Otherwise the @c completion_block will be called when the requests completes. GdkPixbuf * -covermanager_cover_for_track (covermanager_t *manager, DB_playItem_t *track, int64_t source_id, covermanager_completion_block_t completion_block); +covermanager_cover_for_track( + covermanager_t *manager, + DB_playItem_t *track, + int64_t source_id, + covermanager_completion_func_t completion_func, + void *completion_ctx); /// Same as @c covermanager_cover_for_track but would not return default cover GdkPixbuf * -covermanager_cover_for_track_no_default (covermanager_t *impl, DB_playItem_t *track, int64_t source_id, covermanager_completion_block_t completion_block); +covermanager_cover_for_track_no_default( + covermanager_t *impl, + DB_playItem_t *track, + int64_t source_id, + covermanager_completion_func_t completion_func, + void *completion_ctx); /// Create scaled image with specified dimensions. Returns retained object. GdkPixbuf * diff --git a/plugins/gtkui/fileman.c b/plugins/gtkui/fileman.c index 5aad9c8da..38d391465 100644 --- a/plugins/gtkui/fileman.c +++ b/plugins/gtkui/fileman.c @@ -40,6 +40,61 @@ gtkpl_adddir_cb (gpointer data, gpointer userdata) { g_free (data); } +typedef struct { + ddb_playlist_t *plt_curr; + ddb_playlist_t *plt; + GSList *lst; +} gtkui_add_dirs_ctx_t; + +static void +gtkui_add_dirs_main(void *user_data) { + gtkui_add_dirs_ctx_t *ctx = user_data; + ddb_playItem_t *tail = deadbeef->plt_get_tail_item(ctx->plt_curr, PL_MAIN); + + ddb_undo->set_action_name(_("Add Folders")); + deadbeef->plt_move_all_items(ctx->plt_curr, ctx->plt, tail); + if (tail != NULL) { + deadbeef->pl_item_unref(tail); + } + + deadbeef->plt_save_config(ctx->plt_curr); + deadbeef->plt_add_files_end(ctx->plt_curr, 0); + deadbeef->plt_unref(ctx->plt_curr); + deadbeef->plt_unref(ctx->plt); + g_slist_free(ctx->lst); + free(ctx); +} + +static void +gtkui_add_dirs_bg(void *user_data) { + gtkui_add_dirs_ctx_t *ctx = user_data; + int is_empty = 0 == deadbeef->plt_get_item_count(ctx->plt_curr, PL_MAIN); + int is_single_item = g_slist_length(ctx->lst) == 1; + int is_autorename_enabled = deadbeef->conf_get_int("gtkui.name_playlist_from_folder", 1); + if (is_single_item && is_autorename_enabled) { + int is_default = 0; + + char *t = calloc(1, 1000); + if (!deadbeef->plt_get_title(ctx->plt_curr, t, 1000)) { + const char *def = _("New Playlist"); + is_default = is_empty || !strncmp(t, def, strlen(def)); + } + free(t); + t = NULL; + + if (is_default) { + const char *folder = strrchr((char*)ctx->lst->data, G_DIR_SEPARATOR); + if (!folder) { + folder = ctx->lst->data; + } + deadbeef->plt_set_title(ctx->plt_curr, folder+1); + } + } + g_slist_foreach(ctx->lst, gtkpl_adddir_cb, ctx->plt); + + gtkui_dispatch_on_main(gtkui_add_dirs_main, ctx); +} + static void gtkpl_addfile_cb (gpointer data, gpointer userdata) { ddb_playlist_t *plt = userdata; @@ -72,50 +127,49 @@ gtkui_add_dirs (GSList *lst) { return; } - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - int is_empty = 0 == deadbeef->plt_get_item_count (plt_curr, PL_MAIN); - int is_single_item = g_slist_length (lst) == 1; - int is_autorename_enabled = deadbeef->conf_get_int ("gtkui.name_playlist_from_folder", 1); - if (is_single_item && is_autorename_enabled) { - int is_default = 0; + typedef struct { + ddb_playlist_t *plt_curr; + ddb_playlist_t *plt; + GSList *lst; + } gtkui_add_dirs_ctx_t; - char *t = calloc(1, 1000); - if (!deadbeef->plt_get_title (plt_curr, t, 1000)) { - const char *def = _("New Playlist"); - is_default = is_empty || !strncmp (t, def, strlen (def)); - } - free (t); - t = NULL; + gtkui_add_dirs_ctx_t *ctx = malloc(sizeof(gtkui_add_dirs_ctx_t)); + ctx->plt_curr = plt_curr; + ctx->plt = plt; + ctx->lst = lst; - if (is_default) { - const char *folder = strrchr ((char*)lst->data, G_DIR_SEPARATOR); - if (!folder) { - folder = lst->data; - } - deadbeef->plt_set_title (plt_curr, folder+1); - } - } - g_slist_foreach(lst, gtkpl_adddir_cb, plt); - - - // TODO: handle cancel + dispatch_async_f(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ctx, gtkui_add_dirs_bg); +} - gtkui_dispatch_on_main(^{ - ddb_playItem_t *tail = deadbeef->plt_get_tail_item(plt_curr, PL_MAIN); +typedef struct { + ddb_playlist_t *plt_curr; + ddb_playlist_t *plt; + GSList *lst; +} gtkui_add_files_ctx_t; - ddb_undo->set_action_name (_("Add Folders")); - deadbeef->plt_move_all_items (plt_curr, plt, tail); - if (tail != NULL) { - deadbeef->pl_item_unref (tail); - } +static void +gtkui_add_files_main(void *user_data) { + gtkui_add_files_ctx_t *ctx = user_data; + ddb_playItem_t *tail = deadbeef->plt_get_tail_item(ctx->plt_curr, PL_MAIN); + ddb_undo->set_action_name(_("Add Files")); + deadbeef->plt_move_all_items(ctx->plt_curr, ctx->plt, tail); + if (tail != NULL) { + deadbeef->pl_item_unref(tail); + tail = NULL; + } + + deadbeef->plt_save_config(ctx->plt_curr); + deadbeef->plt_add_files_end(ctx->plt_curr, 0); + deadbeef->plt_unref(ctx->plt_curr); + deadbeef->plt_unref(ctx->plt); + free(ctx); +} - deadbeef->plt_save_config (plt_curr); - deadbeef->plt_add_files_end (plt_curr, 0); - deadbeef->plt_unref (plt_curr); - deadbeef->plt_unref (plt); - g_slist_free (lst); - }); - }); +static void +gtkui_add_files_bg(void *user_data) { + gtkui_add_files_ctx_t *ctx = user_data; + gtkpl_add_files(ctx->plt, ctx->lst); + gtkui_dispatch_on_main(gtkui_add_files_main, ctx); } void @@ -130,23 +184,12 @@ gtkui_add_files (struct _GSList *lst) { return; } - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - gtkpl_add_files (plt, lst); - gtkui_dispatch_on_main (^{ - ddb_playItem_t *tail = deadbeef->plt_get_tail_item (plt_curr, PL_MAIN); - ddb_undo->set_action_name (_("Add Files")); - deadbeef->plt_move_all_items (plt_curr, plt, tail); - if (tail != NULL) { - deadbeef->pl_item_unref (tail); - tail = NULL; - } + gtkui_add_files_ctx_t *ctx = malloc(sizeof(gtkui_add_files_ctx_t)); + ctx->plt_curr = plt_curr; + ctx->plt = plt; + ctx->lst = lst; - deadbeef->plt_save_config (plt_curr); - deadbeef->plt_add_files_end (plt_curr, 0); - deadbeef->plt_unref (plt_curr); - deadbeef->plt_unref (plt); - }); - }); + dispatch_async_f(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ctx, gtkui_add_files_bg); } void @@ -160,6 +203,68 @@ gtkui_open_files (struct _GSList *lst) { gtkui_add_files(lst); } +typedef struct { + ddb_playlist_t *plt_curr; + ddb_playlist_t *plt; + char *path_copy; + char *custom_title_copy; + DB_playItem_t *it; +} gtkui_add_location_ctx_t; + +static void +gtkui_add_location_main(void *user_data) { + gtkui_add_location_ctx_t *ctx = user_data; + if (ctx->custom_title_copy != NULL) { + deadbeef->pl_replace_meta(ctx->it, ":CUSTOM_TITLE", ctx->custom_title_copy); + } + + ddb_playItem_t *tail = deadbeef->plt_get_tail_item(ctx->plt_curr, PL_MAIN); + deadbeef->plt_move_all_items(ctx->plt_curr, ctx->plt, tail); + if (tail != NULL) { + deadbeef->pl_item_unref(tail); + } + + deadbeef->plt_save_config(ctx->plt_curr); + ddb_undo->set_action_name(_("Add Location")); + deadbeef->plt_add_files_end(ctx->plt_curr, 0); + + free(ctx->path_copy); + free(ctx->custom_title_copy); + deadbeef->pl_item_unref(ctx->it); + deadbeef->plt_unref(ctx->plt); + deadbeef->plt_unref(ctx->plt_curr); + free(ctx); +} + +static void +gtkui_add_location_bg(void *user_data) { + gtkui_add_location_ctx_t *ctx = user_data; + DB_playItem_t *tail = deadbeef->plt_get_last(ctx->plt, PL_MAIN); + DB_playItem_t *it = deadbeef->plt_insert_file2(0, ctx->plt, tail, ctx->path_copy, NULL, NULL, NULL); + + if (tail) { + deadbeef->pl_item_unref(tail); + tail = NULL; + } + + if (it == NULL) { + deadbeef->plt_add_files_end(ctx->plt_curr, 0); + + free(ctx->path_copy); + free(ctx->custom_title_copy); + deadbeef->plt_unref(ctx->plt); + deadbeef->plt_unref(ctx->plt_curr); + free(ctx); + + return; + } + + deadbeef->pl_item_ref(it); + ctx->it = it; + + gtkui_dispatch_on_main(gtkui_add_location_main, ctx); +} + void gtkui_add_location (const char *path, const char *custom_title) { ddb_playlist_t *plt_curr = deadbeef->plt_get_curr (); @@ -173,55 +278,18 @@ gtkui_add_location (const char *path, const char *custom_title) { char *custom_title_copy = NULL; if (custom_title != NULL) { - custom_title_copy = strdup (custom_title); + custom_title_copy = strdup(custom_title); } - char *path_copy = strdup (path); - - dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - DB_playItem_t *tail = deadbeef->plt_get_last (plt, PL_MAIN); - DB_playItem_t *it = deadbeef->plt_insert_file2 (0, plt, tail, path_copy, NULL, NULL, NULL); - - if (tail) { - deadbeef->pl_item_unref (tail); - tail = NULL; - } + char *path_copy = strdup(path); - if (it == NULL) { - deadbeef->plt_add_files_end (plt_curr, 0); + gtkui_add_location_ctx_t *ctx = malloc(sizeof(gtkui_add_location_ctx_t)); + ctx->plt_curr = plt_curr; + ctx->plt = plt; + ctx->path_copy = path_copy; + ctx->custom_title_copy = custom_title_copy; - free (path_copy); - free (custom_title_copy); - deadbeef->plt_unref (plt); - deadbeef->plt_unref (plt_curr); - - return; - } - - deadbeef->pl_item_ref (it); - - gtkui_dispatch_on_main (^{ - if (custom_title_copy != NULL) { - deadbeef->pl_replace_meta (it, ":CUSTOM_TITLE", custom_title_copy); - } - - ddb_playItem_t *tail = deadbeef->plt_get_tail_item (plt_curr, PL_MAIN); - deadbeef->plt_move_all_items (plt_curr, plt, tail); - if (tail != NULL) { - deadbeef->pl_item_unref (tail); - } - - deadbeef->plt_save_config (plt_curr); - ddb_undo->set_action_name (_("Add Location")); - deadbeef->plt_add_files_end (plt_curr, 0); - - free (path_copy); - free (custom_title_copy); - deadbeef->pl_item_unref (it); - deadbeef->plt_unref (plt); - deadbeef->plt_unref (plt_curr); - }); - }); + dispatch_async_f(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ctx, gtkui_add_location_bg); } void @@ -336,6 +404,56 @@ struct fmdrop_data { DB_playItem_t *drop_before; }; +typedef struct { + ddb_playlist_t *plt_curr; + ddb_playlist_t *plt; + struct fmdrop_data *data; + char *mem; + ddb_playItem_t *first; +} gtkui_fm_drop_ctx_t; + +static void +gtkui_fm_drop_main(void *user_data) { + gtkui_fm_drop_ctx_t *ctx = user_data; + ddb_undo->set_action_name(_("Drag & Drop")); + + ddb_playItem_t *after; + if (ctx->data->drop_before != NULL) { + after = deadbeef->pl_get_prev(ctx->data->drop_before, PL_MAIN); + } + else { + after = deadbeef->plt_get_last(ctx->plt_curr, PL_MAIN); + } + deadbeef->plt_move_all_items(ctx->plt_curr, ctx->plt, after); + if (after != NULL) { + deadbeef->pl_item_unref(after); + } + + deadbeef->plt_save_config(ctx->plt_curr); + deadbeef->plt_add_files_end(ctx->plt_curr, 0); + set_dnd_cursor(ctx->first); + + if (ctx->first != NULL) { + deadbeef->pl_item_unref(ctx->first); + } + if (ctx->data->drop_before) { + deadbeef->pl_item_unref(ctx->data->drop_before); + } + free(ctx->mem); + free(ctx->data); + deadbeef->plt_unref(ctx->plt); + deadbeef->plt_unref(ctx->plt_curr); + free(ctx); +} + +static void +gtkui_fm_drop_bg(void *user_data) { + gtkui_fm_drop_ctx_t *ctx = user_data; + ddb_playItem_t *first = gtkpl_add_fm_dropped_files(ctx->plt, NULL, ctx->data->mem, ctx->data->length); + ctx->first = first; + gtkui_dispatch_on_main(gtkui_fm_drop_main, ctx); +} + void gtkui_receive_fm_drop (DB_playItem_t *before, char *mem, int length) { struct fmdrop_data *data = calloc (1, sizeof (struct fmdrop_data)); @@ -360,41 +478,13 @@ gtkui_receive_fm_drop (DB_playItem_t *before, char *mem, int length) { return; } + gtkui_fm_drop_ctx_t *ctx = malloc(sizeof(gtkui_fm_drop_ctx_t)); + ctx->plt_curr = plt_curr; + ctx->plt = plt; + ctx->data = data; + ctx->mem = mem; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - ddb_playItem_t *first = gtkpl_add_fm_dropped_files (plt, NULL, data->mem, data->length); - - gtkui_dispatch_on_main(^{ - ddb_undo->set_action_name (_("Drag & Drop")); - - ddb_playItem_t *after; - if (data->drop_before != NULL) { - after = deadbeef->pl_get_prev(data->drop_before, PL_MAIN); - } - else { - after = deadbeef->plt_get_last(plt_curr, PL_MAIN); - } - deadbeef->plt_move_all_items (plt_curr, plt, after); - if (after != NULL) { - deadbeef->pl_item_unref (after); - } - - deadbeef->plt_save_config (plt_curr); - deadbeef->plt_add_files_end (plt_curr, 0); - set_dnd_cursor (first); - - if (first != NULL) { - deadbeef->pl_item_unref (first); - } - if (data->drop_before) { - deadbeef->pl_item_unref (data->drop_before); - } - free (mem); - free (data); - deadbeef->plt_unref (plt); - deadbeef->plt_unref (plt_curr); - }); - }); + dispatch_async_f(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ctx, gtkui_fm_drop_bg); } #if GTK_CHECK_VERSION(3,20,0) diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c index d832bebd2..d2518c625 100644 --- a/plugins/gtkui/gtkui.c +++ b/plugins/gtkui/gtkui.c @@ -28,7 +28,6 @@ # include #endif #include -#include #include #include #include @@ -147,18 +146,25 @@ init_widget_layout (void); static int sb_context_id = -1; static char sb_text[512]; +typedef struct { + void (*callback)(void *); + void *user_data; +} gtkui_dispatch_ctx_t; + static gboolean _dispatch_on_main_wrapper (void *context) { - void (^block) (void) = context; - block (); - Block_release (block); + gtkui_dispatch_ctx_t *ctx = (gtkui_dispatch_ctx_t *)context; + ctx->callback(ctx->user_data); + free(ctx); return FALSE; } void -gtkui_dispatch_on_main (void (^block) (void)) { - dispatch_block_t copy_block = Block_copy (block); - g_idle_add (_dispatch_on_main_wrapper, copy_block); +gtkui_dispatch_on_main (void (*callback)(void *), void *user_data) { + gtkui_dispatch_ctx_t *ctx = malloc(sizeof(gtkui_dispatch_ctx_t)); + ctx->callback = callback; + ctx->user_data = user_data; + g_idle_add (_dispatch_on_main_wrapper, ctx); } static void @@ -982,6 +988,17 @@ trackfocus_cb (gpointer data) { return FALSE; } +static void +undo_process_cb(void *user_data) { + deadbeef->undo_process(); +} + +static void +dspchain_changed_cb(void *user_data) { + eq_refresh(); + dsp_setup_chain_changed(); +} + static int gtkui_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) { if (!gtkui_accept_messages) { @@ -989,9 +1006,7 @@ gtkui_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) { } if (id == DB_EV_PLAYLISTCHANGED) { - gtkui_dispatch_on_main(^{ - deadbeef->undo_process(); - }); + gtkui_dispatch_on_main(undo_process_cb, NULL); } switch (id) { @@ -1057,10 +1072,7 @@ gtkui_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) { g_idle_add (add_mainmenu_actions_cb, NULL); break; case DB_EV_DSPCHAINCHANGED: - gtkui_dispatch_on_main(^{ - eq_refresh (); - dsp_setup_chain_changed (); - }); + gtkui_dispatch_on_main(dspchain_changed_cb, NULL); break; } return 0; diff --git a/plugins/gtkui/gtkui.h b/plugins/gtkui/gtkui.h index a47e93981..b6a29ec96 100644 --- a/plugins/gtkui/gtkui.h +++ b/plugins/gtkui/gtkui.h @@ -197,6 +197,6 @@ char * gtkui_trim_whitespace (char *p, size_t len); void -gtkui_dispatch_on_main (void (^block) (void)); +gtkui_dispatch_on_main (void (*callback)(void *), void *user_data); #endif diff --git a/plugins/gtkui/medialib/medialibwidget.c b/plugins/gtkui/medialib/medialibwidget.c index 0998233da..e15682cb0 100644 --- a/plugins/gtkui/medialib/medialibwidget.c +++ b/plugins/gtkui/medialib/medialibwidget.c @@ -726,29 +726,64 @@ tracks = NULL; } +typedef struct { + w_medialib_viewer_t *mlv; + GtkTreePath *path; + GdkPixbuf *scaled_img; + GdkPixbuf *img; +} receive_cover_data_t; + static void -_receive_cover (w_medialib_viewer_t *mlv, GtkTreePath *path, GdkPixbuf *img) { - g_object_ref (img); - dispatch_async (mlv->background_queue, ^{ - // scale - GtkAllocation a; - a.x = 0; - a.y = 0; - a.width = ML_CELL_RENDERER_PIXBUF_SIZE; - a.height = ML_CELL_RENDERER_PIXBUF_SIZE; - GdkPixbuf *scaled_img = covermanager_create_scaled_image (covermanager_shared (), img, a); - - gtkui_dispatch_on_main (^{ - GtkTreeStore *store = mlv->store; - GtkTreeIter iter; - GtkTreeModel *model = GTK_TREE_MODEL (mlv->store); - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_store_set (store, &iter, COL_ICON, scaled_img, -1); - g_object_unref (scaled_img); - gtk_tree_path_free (path); - g_object_unref (img); - }); - }); +_receive_cover_main_cb(void *user_data) { + receive_cover_data_t *data = user_data; + GtkTreeStore *store = data->mlv->store; + GtkTreeIter iter; + GtkTreeModel *model = GTK_TREE_MODEL(data->mlv->store); + gtk_tree_model_get_iter(model, &iter, data->path); + gtk_tree_store_set(store, &iter, COL_ICON, data->scaled_img, -1); + g_object_unref(data->scaled_img); + gtk_tree_path_free(data->path); + g_object_unref(data->img); + free(data); +} + +static void +_receive_cover_async_cb(void *user_data) { + receive_cover_data_t *data = user_data; + // scale + GtkAllocation a; + a.x = 0; + a.y = 0; + a.width = ML_CELL_RENDERER_PIXBUF_SIZE; + a.height = ML_CELL_RENDERER_PIXBUF_SIZE; + GdkPixbuf *scaled_img = covermanager_create_scaled_image(covermanager_shared(), data->img, a); + data->scaled_img = scaled_img; + gtkui_dispatch_on_main(_receive_cover_main_cb, data); +} + +static void +_receive_cover(w_medialib_viewer_t *mlv, GtkTreePath *path, GdkPixbuf *img) { + g_object_ref(img); + receive_cover_data_t *data = malloc(sizeof(receive_cover_data_t)); + data->mlv = mlv; + data->path = path; + data->img = img; + dispatch_async_f(mlv->background_queue, data, _receive_cover_async_cb); +} + +typedef struct { + w_medialib_viewer_t *mlv; + GtkTreePath *path; + int64_t reload_index; +} cover_callback_ctx_t; + +static void cover_callback_func(GdkPixbuf *img, void *user_ctx) { + cover_callback_ctx_t *ctx = (cover_callback_ctx_t *)user_ctx; + if (ctx->reload_index == ctx->mlv->reload_index && img != NULL) { + _receive_cover(ctx->mlv, ctx->path, img); + } + gtk_tree_path_free(ctx->path); + free(ctx); } static GdkPixbuf * @@ -794,15 +829,18 @@ } int64_t reload_index = mlv->reload_index; - GdkPixbuf *cached_cover = covermanager_cover_for_track_no_default ( - covermanager_shared (), + cover_callback_ctx_t *cb_ctx = malloc(sizeof(cover_callback_ctx_t)); + cb_ctx->mlv = mlv; + cb_ctx->path = gtk_tree_path_copy(path); + cb_ctx->reload_index = reload_index; + + GdkPixbuf *cached_cover = covermanager_cover_for_track_no_default( + covermanager_shared(), track, mlv->artwork_source_id, - ^(GdkPixbuf *img) { - if (reload_index == mlv->reload_index && img != NULL) { - _receive_cover (mlv, path, img); - } - }); + cover_callback_func, + cb_ctx + ); if (cached_cover != NULL) { _receive_cover (mlv, path, cached_cover); diff --git a/plugins/gtkui/playlist/playlistcontroller.c b/plugins/gtkui/playlist/playlistcontroller.c index fb39337e2..b7d16cad3 100644 --- a/plugins/gtkui/playlist/playlistcontroller.c +++ b/plugins/gtkui/playlist/playlistcontroller.c @@ -21,7 +21,6 @@ 3. This notice may not be removed or altered from any source distribution. */ -#include #include #include #include @@ -45,25 +44,15 @@ struct playlist_controller_s { }; static gboolean -_dispatch_on_main_wrapper (void *context) { - void (^block)(void) = context; - block (); - Block_release(block); +_artwork_listener_cb(gpointer user_data) { + playlist_controller_t *ctl = user_data; + ddb_listview_reset_artwork(ctl->listview); return FALSE; } static void -_dispatch_on_main(void (^block)(void)) { - dispatch_block_t copy_block = Block_copy(block); - g_idle_add(_dispatch_on_main_wrapper, copy_block); -} - -static void -_artwork_listener (ddb_artwork_listener_event_t event, void *user_data, int64_t p1, int64_t p2) { - _dispatch_on_main(^{ - playlist_controller_t *ctl = user_data; - ddb_listview_reset_artwork (ctl->listview); - }); +_artwork_listener(ddb_artwork_listener_event_t event, void *user_data, int64_t p1, int64_t p2) { + g_idle_add(_artwork_listener_cb, user_data); } playlist_controller_t * diff --git a/plugins/gtkui/playlist/playlistrenderer.c b/plugins/gtkui/playlist/playlistrenderer.c index 75e57ef39..83a33681b 100644 --- a/plugins/gtkui/playlist/playlistrenderer.c +++ b/plugins/gtkui/playlist/playlistrenderer.c @@ -265,6 +265,18 @@ cover_draw_cairo (GdkPixbuf *pixbuf, int x, int min_y, int max_y, int width, int cairo_restore(cr); } +typedef struct { + DdbListview *listview; + DB_playItem_t *it; +} playlist_cover_ctx_t; + +static void playlist_cover_callback(GdkPixbuf *img, void *ctx_) { + playlist_cover_ctx_t *ctx = (playlist_cover_ctx_t *)ctx_; + deadbeef->pl_item_unref(ctx->it); + gtk_widget_queue_draw(GTK_WIDGET(ctx->listview)); + free(ctx); +} + void pl_common_draw_album_art (DdbListview *listview, cairo_t *cr, DdbListviewGroup *grp, void *user_data, int min_y, int next_y, int x, int y, int width, int height, int alignment) { int art_width = width - ART_PADDING_HORZ * 2; @@ -282,13 +294,12 @@ pl_common_draw_album_art (DdbListview *listview, cairo_t *cr, DdbListviewGroup * GdkPixbuf *image = NULL; - deadbeef->pl_item_ref (it); - image = covermanager_cover_for_track(cm, it, 0, ^(GdkPixbuf *img) { // img only valid in this block - deadbeef->pl_item_unref (it); + deadbeef->pl_item_ref(it); + playlist_cover_ctx_t *cb_ctx = malloc(sizeof(playlist_cover_ctx_t)); + cb_ctx->listview = listview; + cb_ctx->it = it; + image = covermanager_cover_for_track(cm, it, 0, playlist_cover_callback, cb_ctx); - gtk_widget_queue_draw(GTK_WIDGET(listview)); - // FIXME: redraw only the group rect - }); if (image != NULL) { // completion block won't be called deadbeef->pl_item_unref (it); it = NULL; diff --git a/plugins/gtkui/prefwin/prefwinmedialib.c b/plugins/gtkui/prefwin/prefwinmedialib.c index 9258faf5b..550aa6b04 100644 --- a/plugins/gtkui/prefwin/prefwinmedialib.c +++ b/plugins/gtkui/prefwin/prefwinmedialib.c @@ -21,7 +21,6 @@ 3. This notice may not be removed or altered from any source distribution. */ -#include #ifdef HAVE_CONFIG_H # include #endif @@ -115,45 +114,44 @@ _remove_did_activate (GtkButton* self, gpointer user_data) { medialib_plugin->refresh (source); } +typedef struct { + ddb_mediasource_event_type_t event; +} listener_ctx_t; + static gboolean -_dispatch_on_main_wrapper (void *context) { - void (^block)(void) = context; - block (); - Block_release(block); - return FALSE; -} +_listener_on_main_cb(gpointer user_data) { + listener_ctx_t *ctx = user_data; + ddb_mediasource_source_t *source = gtkui_medialib_get_source(); + if ((int)ctx->event < 1000) { + switch (ctx->event) { + case DDB_MEDIASOURCE_EVENT_ENABLED_DID_CHANGE: + { + GtkWidget *enable_button = lookup_widget(prefwin, "toggle_medialib_on"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_button), medialib_plugin->is_source_enabled(source)); + } + break; + default: + break; + } + g_free(ctx); + return FALSE; + } -static void -_dispatch_on_main(void (^block)(void)) { - dispatch_block_t copy_block = Block_copy(block); - g_idle_add(_dispatch_on_main_wrapper, copy_block); + ddb_medialib_mediasource_event_type_t event = (ddb_medialib_mediasource_event_type_t)ctx->event; + switch (event) { + case DDB_MEDIALIB_MEDIASOURCE_EVENT_FOLDERS_DID_CHANGE: + _reload_data(); + break; + } + g_free(ctx); + return FALSE; } static void -_listener (ddb_mediasource_event_type_t _event, void *user_data) { - _dispatch_on_main(^{ - ddb_mediasource_source_t *source = gtkui_medialib_get_source(); - if ((int)_event < 1000) { - switch (_event) { - case DDB_MEDIASOURCE_EVENT_ENABLED_DID_CHANGE: - { - GtkWidget *enable_button = lookup_widget(prefwin, "toggle_medialib_on"); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_button), medialib_plugin->is_source_enabled(source)); - } - break; - default: - break; - } - return; - } - - ddb_medialib_mediasource_event_type_t event = (ddb_medialib_mediasource_event_type_t)_event; - switch (event) { - case DDB_MEDIALIB_MEDIASOURCE_EVENT_FOLDERS_DID_CHANGE: - _reload_data(); - break; - } - }); +_listener(ddb_mediasource_event_type_t _event, void *user_data) { + listener_ctx_t *ctx = g_malloc(sizeof(listener_ctx_t)); + ctx->event = _event; + g_idle_add(_listener_on_main_cb, ctx); } void