diff --git a/AUTHORS.md b/AUTHORS.md index bb44edc..9f5b816 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,2 +1,5 @@ -Sergiotarxz sergiotarxz@posteo.net Project leader and developer [Gitea](https://gitea.sergiotarxz.freemyip.com/sergiotarxz) -Germe.db FOSSgerme.deb@tuta.io Author of the icon openmg.svg. [sr.ht](https://sr.ht/~germe-fur/) +Sergiotarxz sergiotarxz@posteo.net Project leader and developer. [Gitea](https://gitea.sergiotarxz.freemyip.com/sergiotarxz) + +Germe.db FOSSgerme.deb@tuta.io Designer and icons creator. [sr.ht](https://sr.ht/~germe-fur/) + +Endes endes@disroot.org Developer. [Github](https://github.com/endes0) diff --git a/README.md b/README.md index 6b4b284..01b9257 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ ## Installing the app. +First fine tune the options in `me.sergiotarxz.openmg.json` for +meson you want to have, for example preview images, complete list is +on `meson_options.txt` + ```shell flatpak --user remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo flatpak install org.gnome.Sdk//master @@ -15,3 +19,7 @@ flatpak-builder --install --user build me.sergiotarxz.openmg.yml me.sergiotarxz. ```shell flatpak run me.sergiotarxz.openmg ``` + +## Donations welcome: + +btc: `bc1q0apxdedrm5vjn3zr0hxswnruk2x2uecwqrusmj` diff --git a/include/openmg/view/controls.h b/include/openmg/view/controls.h index 422f791..9b85571 100644 --- a/include/openmg/view/controls.h +++ b/include/openmg/view/controls.h @@ -9,6 +9,9 @@ typedef struct { AdwHeaderBar *header; AdwLeaflet *views_leaflet; AdwViewStack *view_stack; + GCancellable **image_threads; + size_t image_threads_len; + bool avoid_list_image_downloads; GtkButton *previous; gboolean is_set_previous; } ControlsAdwaita; diff --git a/include/openmg/view/picture.h b/include/openmg/view/picture.h index 6ab6451..69e273a 100644 --- a/include/openmg/view/picture.h +++ b/include/openmg/view/picture.h @@ -1,6 +1,6 @@ #pragma once #include -void +GtkPicture * create_picture_from_url (const char *const url, gint picture_size, GAsyncReadyCallback ready, gpointer source_object, - gpointer callback_data); + gpointer callback_data, bool do_not_download); diff --git a/me.sergiotarxz.openmg.json b/me.sergiotarxz.openmg.json new file mode 100644 index 0000000..e441792 --- /dev/null +++ b/me.sergiotarxz.openmg.json @@ -0,0 +1,30 @@ +{ + "app-id": "me.sergiotarxz.openmg", + "runtime": "org.gnome.Platform", + "runtime-version": "master", + "sdk": "org.gnome.Sdk", + "command": "openmg", + "finish-args": [ + "--share=ipc", + "--socket=x11", + "--socket=wayland", + "--socket=session-bus", + "--share=network", + "--device=dri" + ], + "modules": [ + { + "name": "openmg", + "buildsystem": "meson", + "config-opts": [ + "-Dimages=true" + ], + "sources": [ + { + "type": "dir", + "path": "." + } + ] + } + ] +} diff --git a/me.sergiotarxz.openmg.yml b/me.sergiotarxz.openmg.yml deleted file mode 100644 index 889076e..0000000 --- a/me.sergiotarxz.openmg.yml +++ /dev/null @@ -1,20 +0,0 @@ - -app-id: me.sergiotarxz.openmg -runtime: org.gnome.Platform -runtime-version: master -sdk: org.gnome.Sdk -sdk-version: master -command: openmg -finish-args: - - "--share=ipc" - - "--socket=x11" - - "--socket=wayland" - - "--socket=session-bus" - - "--share=network" - - "--device=dri" -modules: - - name: openmg - buildsystem: meson - sources: - - type: dir - path: . diff --git a/meson.build b/meson.build index 9753e8b..e193194 100644 --- a/meson.build +++ b/meson.build @@ -36,14 +36,26 @@ sources = [ ] link_arguments = [ - '-ldl', '-lm' ] - + +images_on_lists = get_option('images') +is_windows = get_option('windows') + +if not is_windows + link_arguments += ['-ldl'] +endif + +cArgs = [] +if images_on_lists + cArgs += ['-DLIST_IMAGES'] +endif + executable('openmg', sources, dependencies : openmgdeps, include_directories : inc, install : true, - link_args : link_arguments + link_args : link_arguments, + c_args: cArgs ) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..084c599 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,2 @@ +option('images', type : 'boolean', value : true) +option('windows', type : 'boolean', value : false) diff --git a/openmg.supp b/openmg.supp new file mode 100644 index 0000000..97e8055 --- /dev/null +++ b/openmg.supp @@ -0,0 +1,36 @@ +# +# Valgrind suppression file for mangareader. +# Warning: This file is very generic, so a real memory leak might be suppressed. +# Also, some false positives are still captured +# +# Format specification: +# http://valgrind.org/docs/manual/manual-core.html#manual-core.suppress +# +{ + gtk4 + Memcheck:Leak + ... + obj:/usr/lib/x86_64-linux-gnu/libgtk-4.so.1.600.0 + ... +} +{ + glib + Memcheck:Leak + ... + obj:/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7100.0 + ... +} +{ + fontconfig + Memcheck:Leak + ... + obj:/usr/lib/x86_64-linux-gnu/libfontconfig.so.1.12.0 + ... +} +{ + gallium + Memcheck:Leak + ... + obj:/usr/lib/x86_64-linux-gnu/GL/default/lib/dri/libgallium_dri.so + ... +} diff --git a/sqlite b/sqlite deleted file mode 160000 index 855a165..0000000 --- a/sqlite +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 855a165fecc25da50cb20525ddf5b9e60a67d18f diff --git a/src/backend/readmng.c b/src/backend/readmng.c index 74fdd96..243bcfa 100644 --- a/src/backend/readmng.c +++ b/src/backend/readmng.c @@ -66,7 +66,8 @@ mg_backend_readmng_loop_li_chapter ( MgBackendReadmng *self, xmlNodePtr li); static char * -mg_backend_readmng_fetch_search (MgBackendReadmng *self, const char *search_query); +mg_backend_readmng_fetch_search (MgBackendReadmng *self, + const char *search_query, size_t *response_len); static GListModel * mg_backend_readmng_parse_page (MgBackendReadmng *self, xmlDocPtr html_document); @@ -235,15 +236,21 @@ mg_backend_readmng_fetch_page_url (MgBackendReadmng *self, GListStore * mg_backend_readmng_search (MgBackendReadmng *self, const char *search_query) { - char *response = mg_backend_readmng_fetch_search (self, search_query); + size_t response_len = 0; + char *response = mg_backend_readmng_fetch_search (self, search_query, + &response_len); JsonParser *parser = json_parser_new (); - GListStore *mangas = g_list_store_new(MG_TYPE_MANGA); + GListStore *mangas = g_list_store_new (MG_TYPE_MANGA); GError *error = NULL; JsonNode *root = NULL; JsonArray *mangas_json_array = NULL; guint mangas_json_array_len = 0; - json_parser_load_from_data (parser, response, -1, &error); + if (!response) { + g_warning ("Json search response is null."); + goto cleanup_mg_backend_readmng_search; + } + json_parser_load_from_data (parser, response, response_len, &error); if (error) { g_warning ("Unable to parse json: %s.", error->message); g_clear_error (&error); @@ -256,7 +263,7 @@ mg_backend_readmng_search (MgBackendReadmng *self, mangas_json_array = json_node_get_array (root); mangas_json_array_len = json_array_get_length ( mangas_json_array); - for (guint i = 0; i < mangas_json_array_len; i++) { + for (guint i = 0; i < mangas_json_array_len && i < 19; i++) { JsonObject *manga_json_object = json_array_get_object_element (mangas_json_array, i); char *id_manga = NULL; @@ -280,14 +287,14 @@ cleanup_mg_backend_readmng_search: } static char * -mg_backend_readmng_fetch_search (MgBackendReadmng *self, const char *search_query) { +mg_backend_readmng_fetch_search (MgBackendReadmng *self, + const char *search_query, size_t *response_len) { MgUtilSoup *util_soup; MgUtilString *string_util; char *request_url; size_t request_url_len; - size_t response_len = 0; util_soup = mg_util_soup_new (); string_util = mg_util_string_new (); @@ -328,7 +335,7 @@ mg_backend_readmng_fetch_search (MgBackendReadmng *self, const char *search_quer size_t body_len = sizeof body / sizeof *body; char *text_response = mg_util_soup_post_request_url_encoded (util_soup, - request_url, body, body_len, headers, headers_len, &response_len); + request_url, body, body_len, headers, headers_len, response_len); g_free (request_url); g_free (phrase); @@ -357,7 +364,7 @@ mg_backend_readmng_retrieve_manga_details (MgBackendReadmng *self, MgManga *manga) { MgUtilXML *xml_utils; - xmlDocPtr html_document; + xmlDocPtr html_document = NULL; xmlNodePtr *movie_detail = NULL; xmlXPathObjectPtr xpath_result = NULL; xmlNodeSetPtr node_set = NULL; @@ -402,6 +409,9 @@ cleanup_mg_backend_readmng_retrieve_manga_details: if (movie_detail) { g_free (movie_detail); } + if (html_document) { + xmlFreeDoc(html_document); + } } static GListStore * @@ -446,6 +456,9 @@ cleanup_mg_backend_readmng_recover_chapter_list: xmlXPathFreeObject(xpath_result); } if (uls) { + for (size_t i = 0; i < ul_len; i++) { + xmlFreeNode(uls[i]); + } g_free (uls); } return return_value; @@ -581,6 +594,7 @@ mg_backend_readmng_parse_main_page (MgBackendReadmng *self, const xmlDocPtr html xmlFreeNode (current_li); li[i] = NULL; } + xmlFreeNode(slides); g_free (li); return mangas; } @@ -636,6 +650,11 @@ cleanup_mg_backend_readmng_retrieve_slides: xmlXPathFreeObject(xpath_result); } if (nodes) { + for (size_t i = 1; i < matching_classes_len; i++) + { + xmlFreeNode(nodes[i]); + } + g_free (nodes); } return slides; diff --git a/src/util/soup.c b/src/util/soup.c index bdc8342..5841a2f 100644 --- a/src/util/soup.c +++ b/src/util/soup.c @@ -54,7 +54,6 @@ mg_util_soup_get_request (MgUtilSoup *self, const char *url, gsize *size_respons g_value_unset (&response); g_clear_object (&soup_session); g_clear_object (&msg); - return return_value; } diff --git a/src/view/chapter_view.c b/src/view/chapter_view.c index eed3269..e773de5 100644 --- a/src/view/chapter_view.c +++ b/src/view/chapter_view.c @@ -167,8 +167,14 @@ set_image_zoomable_picture_container (ChapterVisorData *chapter_visor_data) { strlen(url_image_not_owned) + 1, 0, strlen (url_image_not_owned)); - create_picture_from_url (url_image, 0, picture_ready_manga_page, - zoomable_picture_container, chapter_visor_data); + GtkPicture *picture = create_picture_from_url (url_image, 0, picture_ready_manga_page, + zoomable_picture_container, chapter_visor_data, false); + if (picture) { + chapter_visor_data->current_picture = GTK_PICTURE (picture); + g_signal_connect (G_OBJECT (picture), "map", + G_CALLBACK (image_page_show), chapter_visor_data); + gtk_scrolled_window_set_child (zoomable_picture_container, GTK_WIDGET (picture)); + } g_free (url_image); g_clear_object (&string_util); } diff --git a/src/view/detail_manga.c b/src/view/detail_manga.c index 37e7378..5089218 100644 --- a/src/view/detail_manga.c +++ b/src/view/detail_manga.c @@ -89,8 +89,8 @@ create_detail_view (MgManga *manga, ControlsAdwaita *controls) { ("network-transmit-receive-symbolic")); GtkListView *chapter_list = NULL; char *url_image = mg_manga_get_image_url(manga); - create_picture_from_url (url_image, 200, - picture_ready_manga_detail, avatar_title_box, NULL); + GtkPicture *picture = create_picture_from_url (url_image, 200, + picture_ready_manga_detail, avatar_title_box, NULL, false); char *manga_title_text = mg_manga_get_title (manga); char *title_text = mg_util_xml_get_title_text ( xml_util, manga_title_text); @@ -116,6 +116,9 @@ create_detail_view (MgManga *manga, ControlsAdwaita *controls) { gtk_widget_set_size_request (GTK_WIDGET (manga_description), 200, -1); gtk_label_set_use_markup (GTK_LABEL (manga_title), 1); + if (picture) { + gtk_box_append (avatar_title_box, GTK_WIDGET (picture)); + } gtk_box_append (avatar_title_box, GTK_WIDGET (manga_title)); gtk_box_append (foldable_manga_data, GTK_WIDGET (avatar_title_box)); diff --git a/src/view/list_view_manga.c b/src/view/list_view_manga.c index 1273cd5..57c370a 100644 --- a/src/view/list_view_manga.c +++ b/src/view/list_view_manga.c @@ -26,6 +26,15 @@ manga_selected (GtkListView *list_view, guint position, gpointer user_data) { ControlsAdwaita *controls = (ControlsAdwaita *) user_data; + controls->avoid_list_image_downloads = true;; + for (size_t i = 0; i < controls->image_threads_len; i++) { + g_cancellable_cancel (controls->image_threads[i]); + } + if (controls->image_threads) { + g_free (controls->image_threads); + } + controls->image_threads = NULL; + controls->image_threads_len = 0; AdwLeaflet *views_leaflet = controls->views_leaflet; GtkSingleSelection *selection = GTK_SINGLE_SELECTION (gtk_list_view_get_model (list_view)); @@ -44,8 +53,10 @@ manga_selected (GtkListView *list_view, GtkBox *detail_view = create_detail_view (manga, controls); adw_leaflet_append (views_leaflet, GTK_WIDGET (detail_view)); adw_leaflet_navigate (views_leaflet, ADW_NAVIGATION_DIRECTION_FORWARD); + controls->avoid_list_image_downloads = false; } +#ifdef LIST_IMAGES static void picture_ready_manga_preview (GObject *source_object, GAsyncResult *res, @@ -58,21 +69,37 @@ picture_ready_manga_preview (GObject *source_object, gtk_box_prepend (box, picture); } } +#endif static void setup_list_view_mangas (GtkSignalListItemFactory *factory, GtkListItem *list_item, gpointer user_data) { + ControlsAdwaita *controls = (ControlsAdwaita *) user_data; MgManga *manga = gtk_list_item_get_item (list_item); GtkBox *box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); char *manga_title = mg_manga_get_title (manga); char *image_url = mg_manga_get_image_url (manga); GtkWidget *label = gtk_label_new (manga_title); - create_picture_from_url (image_url, 100, - picture_ready_manga_preview, box, NULL); + GtkPicture *picture = NULL; +#ifdef LIST_IMAGES + GCancellable *cancellable = g_cancellable_new (); + picture = create_picture_from_url (image_url, 100, + picture_ready_manga_preview, box, cancellable, + controls->avoid_list_image_downloads); + controls->image_threads_len++; + controls->image_threads = g_realloc (controls->image_threads, + controls->image_threads_len * sizeof *(controls->image_threads)); + controls->image_threads[controls->image_threads_len-1] = cancellable; +#endif g_object_set_property_int (G_OBJECT(box), "height-request", 100); +#ifdef LIST_IMAGES + if (picture) { + gtk_box_append (box, GTK_WIDGET (picture)); + } +#endif gtk_box_append (box, label); gtk_list_item_set_child (list_item, GTK_WIDGET (box)); @@ -82,14 +109,13 @@ setup_list_view_mangas (GtkSignalListItemFactory *factory, GtkListView * create_list_view_mangas (GListStore *mangas, ControlsAdwaita *controls) { - AdwLeaflet *views_leaflet = controls->views_leaflet; GtkSingleSelection *selection = gtk_single_selection_new (G_LIST_MODEL (mangas)); GtkListItemFactory *factory = gtk_signal_list_item_factory_new (); GtkListView *list_view_manga = NULL; g_signal_connect (G_OBJECT (factory), "bind", G_CALLBACK (setup_list_view_mangas), - views_leaflet); + controls); list_view_manga = GTK_LIST_VIEW (gtk_list_view_new (GTK_SELECTION_MODEL (selection), factory)); diff --git a/src/view/main_view.c b/src/view/main_view.c index 0d3bcbd..675566a 100644 --- a/src/view/main_view.c +++ b/src/view/main_view.c @@ -1,4 +1,6 @@ +#ifndef _WIN32 #include +#endif #include #include @@ -37,6 +39,7 @@ activate (AdwApplication *app, AdwLeaflet *views_leaflet_search; AdwHeaderBar *header_bar; +#ifndef _WIN32 swipe_back_t swipe_back = (swipe_back_t) dlsym (NULL, "adw_leaflet_set_can_navigate_back"); @@ -44,11 +47,16 @@ activate (AdwApplication *app, swipe_back = (swipe_back_t) dlsym (NULL, "adw_leaflet_set_can_swipe_back"); } +#else + swipe_back_t swipe_back = adw_leaflet_set_can_navigate_back; +#endif controls->is_set_previous = 0; controls->header = NULL; controls->view_stack = view_stack; - + controls->image_threads_len = 0; + controls->image_threads = NULL; + controls->avoid_list_image_downloads = false; views_leaflet_explore = create_explore_leaflet (controls, swipe_back); views_leaflet_search = create_search_leaflet (controls, swipe_back); diff --git a/src/view/picture.c b/src/view/picture.c index 9e2d3e1..07615f2 100644 --- a/src/view/picture.c +++ b/src/view/picture.c @@ -16,6 +16,7 @@ const char *const IMAGE_CACHE_FORMAT_STRING = typedef struct { char *url; gint picture_size; + GFile *image; } PictureThreadAttributes; static char * @@ -30,7 +31,7 @@ threaded_picture_recover (GTask *task, gpointer source_object, const char *url = attrs->url; gint picture_size = attrs->picture_size; GFileIOStream *iostream = NULL; - GFile *image = NULL; + GFile *image = attrs->image; GError *error = NULL; GdkTexture *texture = NULL; GtkPicture *picture = NULL; @@ -39,15 +40,12 @@ threaded_picture_recover (GTask *task, gpointer source_object, char *downloaded_image = NULL; MgUtilSoup *util_soup = mg_util_soup_new (); + downloaded_image = mg_util_soup_get_request (util_soup, + url, &size_downloaded_image); static GMutex mutex; g_mutex_lock (&mutex); - image = get_image_for_url (url); - g_mutex_unlock (&mutex); if (!g_file_query_exists (image, NULL)) { - downloaded_image = - mg_util_soup_get_request - (util_soup, - url, &size_downloaded_image); + g_info ("Storing %s", url); iostream = g_file_create_readwrite (image, G_FILE_CREATE_NONE, NULL, &error); if (error) { @@ -63,9 +61,11 @@ threaded_picture_recover (GTask *task, gpointer source_object, goto cleanup_create_picture_from_url; } } + g_mutex_unlock (&mutex); texture = gdk_texture_new_from_file (image, &error); if (error) { - fprintf (stderr, "Texture malformed."); + g_warning ("Texture malformed."); + g_clear_error (&error); goto cleanup_create_picture_from_url; } picture = GTK_PICTURE (gtk_picture_new_for_paintable (GDK_PAINTABLE (texture))); @@ -93,21 +93,44 @@ free_picture_thread_attributes (gpointer user_data) { g_free (attrs); } -void +GtkPicture * create_picture_from_url (const char *const url, gint picture_size, GAsyncReadyCallback ready, gpointer source_object, - gpointer callback_data) { - GTask *task = g_task_new (source_object, NULL, ready, callback_data); + gpointer callback_data, bool do_not_download) { + GtkPicture *picture = NULL; + GFile *image = NULL; + GdkTexture *texture = NULL; + GError *error = NULL; + + image = get_image_for_url (url); size_t url_len = strlen (url) + 1; - PictureThreadAttributes *attrs = g_malloc (sizeof *attrs); - - attrs->url = g_malloc (url_len * sizeof *url); - snprintf (attrs->url, url_len, "%s", url); - attrs->picture_size = picture_size; - g_task_set_task_data (task, attrs, free_picture_thread_attributes); - g_task_run_in_thread (task, threaded_picture_recover); + if (g_file_query_exists (image, NULL)) { + texture = gdk_texture_new_from_file (image, &error); + if (error) { + g_warning ("Texture malformed."); + g_clear_error (&error); + goto cleanup_create_picture_from_url; + } + picture = GTK_PICTURE (gtk_picture_new_for_paintable (GDK_PAINTABLE (texture))); + if (GTK_IS_WIDGET (picture)) { + g_object_set_property_int (G_OBJECT(picture), "height-request", picture_size); + g_object_set_property_int (G_OBJECT(picture), "width-request", picture_size); + } + } else if (!do_not_download) { + GTask *task = g_task_new (source_object, NULL, ready, callback_data); + PictureThreadAttributes *attrs = g_malloc (sizeof *attrs); + attrs->url = g_malloc (url_len * sizeof *url); + snprintf (attrs->url, url_len, "%s", url); + attrs->image = image; + attrs->picture_size = picture_size; + g_task_set_task_data (task, attrs, free_picture_thread_attributes); + g_task_set_return_on_cancel (task, true); + g_task_run_in_thread (task, threaded_picture_recover); + } +cleanup_create_picture_from_url: + return picture; } GFile * diff --git a/src/view/search.c b/src/view/search.c index c0e4de2..9157615 100644 --- a/src/view/search.c +++ b/src/view/search.c @@ -6,18 +6,14 @@ #include static void -search_text_changed (GtkEditable *self, - gpointer user_data); -static void -async_search_manga (GTask *task, - gpointer source_object, - gpointer task_data, - GCancellable *cancellable); -static void -set_mangas_to_list_view (GObject *source_object, - GAsyncResult *res, +search_text_changed (GtkEntry *entry, gpointer user_data); +typedef struct { + GtkListView *list_view_mangas; + ControlsAdwaita *controls; +} SearchTextData; + GtkWidget * create_search_view (ControlsAdwaita *controls) { GtkWidget *search_view = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); @@ -26,12 +22,15 @@ create_search_view (ControlsAdwaita *controls) { GtkWidget *scroll = gtk_scrolled_window_new (); GListStore *mangas = g_list_store_new(MG_TYPE_MANGA); GtkListView *list_view_mangas; + SearchTextData *search_text_data = g_malloc (sizeof *search_text_data); gtk_box_append (GTK_BOX (search_view), search_entry); list_view_mangas = create_list_view_mangas (mangas, controls); - g_signal_connect (search_entry, "changed", - G_CALLBACK (search_text_changed), list_view_mangas); + search_text_data->list_view_mangas = list_view_mangas; + search_text_data ->controls = controls; + g_signal_connect (search_entry, "activate", + G_CALLBACK (search_text_changed), search_text_data); gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scroll), GTK_WIDGET (list_view_mangas)); @@ -42,43 +41,29 @@ create_search_view (ControlsAdwaita *controls) { return search_view; } -static GCancellable *cancellable = NULL; - static void -search_text_changed (GtkEditable *editable, +search_text_changed (GtkEntry *entry, gpointer user_data) { - if (cancellable) { - g_cancellable_cancel (cancellable); - } - cancellable = g_cancellable_new (); - GtkListView *list_view_mangas = GTK_LIST_VIEW (user_data); - GTask *task = g_task_new (editable, cancellable, set_mangas_to_list_view,list_view_mangas); - g_task_set_return_on_cancel (task, true); - g_task_run_in_thread (task, async_search_manga); -} - -static void -set_mangas_to_list_view (GObject *source_object, - GAsyncResult *res, - gpointer user_data) { - GListStore *mangas = G_LIST_STORE (g_task_propagate_pointer (G_TASK (res), NULL)); - if (!mangas) return; - GtkListView *list_view_mangas = GTK_LIST_VIEW (user_data); - GtkSingleSelection *selection = GTK_SINGLE_SELECTION ( - gtk_list_view_get_model (list_view_mangas)); - gtk_single_selection_set_model (selection, - G_LIST_MODEL (mangas)); -} - -static void -async_search_manga (GTask *task, - gpointer source_object, - gpointer task_data, - GCancellable *cancellable) { - GtkEntry *entry = GTK_ENTRY (source_object); + SearchTextData *search_text_data = (SearchTextData *) user_data; + ControlsAdwaita *controls = search_text_data->controls; + GtkListView *list_view_mangas = search_text_data->list_view_mangas; GtkEntryBuffer *buffer = gtk_entry_get_buffer (entry); MgBackendReadmng *readmng = mg_backend_readmng_new (); const char *search_string = gtk_entry_buffer_get_text (buffer); GListStore *mangas = mg_backend_readmng_search (readmng, search_string); - g_task_return_pointer (task, mangas, g_object_unref); + for (size_t i = 0; i < controls->image_threads_len; i++) { + g_cancellable_cancel (controls->image_threads[i]); + } + if (controls->image_threads) { + g_free (controls->image_threads); + } + controls->image_threads = NULL; + controls->image_threads_len = 0; + controls->avoid_list_image_downloads = true; + if (!mangas) return; + GtkSingleSelection *selection = GTK_SINGLE_SELECTION ( + gtk_list_view_get_model (list_view_mangas)); + controls->avoid_list_image_downloads = false; + gtk_single_selection_set_model (selection, + G_LIST_MODEL (mangas)); }