forked from sergiotarxz/mangareader
Merge branch 'main' into main
This commit is contained in:
commit
5c00c7e09c
@ -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)
|
||||
|
@ -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`
|
||||
|
@ -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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include <gtk/gtk.h>
|
||||
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);
|
||||
|
30
me.sergiotarxz.openmg.json
Normal file
30
me.sergiotarxz.openmg.json
Normal file
@ -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": "."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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: .
|
18
meson.build
18
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
|
||||
)
|
||||
|
2
meson_options.txt
Normal file
2
meson_options.txt
Normal file
@ -0,0 +1,2 @@
|
||||
option('images', type : 'boolean', value : true)
|
||||
option('windows', type : 'boolean', value : false)
|
36
openmg.supp
Normal file
36
openmg.supp
Normal file
@ -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
|
||||
...
|
||||
}
|
1
sqlite
1
sqlite
@ -1 +0,0 @@
|
||||
Subproject commit 855a165fecc25da50cb20525ddf5b9e60a67d18f
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -1,4 +1,6 @@
|
||||
#ifndef _WIN32
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <adwaita.h>
|
||||
@ -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);
|
||||
|
@ -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 *
|
||||
|
@ -6,18 +6,14 @@
|
||||
#include <openmg/view/list_view_manga.h>
|
||||
|
||||
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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user