sdgui: load dictionaries asynchronously
This is a must when loading huge dictionaries, where not even parallelization helps much.
This commit is contained in:
parent
7ef502759e
commit
27dcf87a64
96
src/sdgui.c
96
src/sdgui.c
|
@ -42,6 +42,8 @@ static struct
|
||||||
gint last; ///< The last dictionary index
|
gint last; ///< The last dictionary index
|
||||||
GPtrArray *dictionaries; ///< All open dictionaries
|
GPtrArray *dictionaries; ///< All open dictionaries
|
||||||
|
|
||||||
|
gboolean loading; ///< Dictionaries are being loaded
|
||||||
|
|
||||||
gboolean watch_selection; ///< Following X11 PRIMARY?
|
gboolean watch_selection; ///< Following X11 PRIMARY?
|
||||||
}
|
}
|
||||||
g;
|
g;
|
||||||
|
@ -49,19 +51,19 @@ g;
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init (gchar **filenames)
|
load_from_filenames (GPtrArray *out, gchar **filenames)
|
||||||
{
|
{
|
||||||
for (gsize i = 0; filenames[i]; i++)
|
for (gsize i = 0; filenames[i]; i++)
|
||||||
{
|
{
|
||||||
Dictionary *dict = g_malloc0 (sizeof *dict);
|
Dictionary *dict = g_malloc0 (sizeof *dict);
|
||||||
dict->filename = g_strdup (filenames[i]);
|
dict->filename = g_strdup (filenames[i]);
|
||||||
g_ptr_array_add (g.dictionaries, dict);
|
g_ptr_array_add (out, dict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: try to deduplicate, similar to app_load_config_values()
|
// TODO: try to deduplicate, similar to app_load_config_values()
|
||||||
static gboolean
|
static gboolean
|
||||||
init_from_key_file (GKeyFile *kf, GError **error)
|
load_from_key_file (GPtrArray *out, GKeyFile *kf, GError **error)
|
||||||
{
|
{
|
||||||
const gchar *dictionaries = "Dictionaries";
|
const gchar *dictionaries = "Dictionaries";
|
||||||
gchar **names = g_key_file_get_keys (kf, dictionaries, NULL, NULL);
|
gchar **names = g_key_file_get_keys (kf, dictionaries, NULL, NULL);
|
||||||
|
@ -72,13 +74,13 @@ init_from_key_file (GKeyFile *kf, GError **error)
|
||||||
{
|
{
|
||||||
Dictionary *dict = g_malloc0 (sizeof *dict);
|
Dictionary *dict = g_malloc0 (sizeof *dict);
|
||||||
dict->name = names[i];
|
dict->name = names[i];
|
||||||
g_ptr_array_add (g.dictionaries, dict);
|
g_ptr_array_add (out, dict);
|
||||||
}
|
}
|
||||||
g_free (names);
|
g_free (names);
|
||||||
|
|
||||||
for (gsize i = 0; i < g.dictionaries->len; i++)
|
for (gsize i = 0; i < out->len; i++)
|
||||||
{
|
{
|
||||||
Dictionary *dict = g_ptr_array_index (g.dictionaries, i);
|
Dictionary *dict = g_ptr_array_index (out, i);
|
||||||
gchar *path =
|
gchar *path =
|
||||||
g_key_file_get_string (kf, dictionaries, dict->name, error);
|
g_key_file_get_string (kf, dictionaries, dict->name, error);
|
||||||
if (!path)
|
if (!path)
|
||||||
|
@ -95,13 +97,13 @@ init_from_key_file (GKeyFile *kf, GError **error)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
init_from_config (GError **error)
|
load_from_config (GPtrArray *out, GError **error)
|
||||||
{
|
{
|
||||||
GKeyFile *key_file = load_project_config_file (error);
|
GKeyFile *key_file = load_project_config_file (error);
|
||||||
if (!key_file)
|
if (!key_file)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
gboolean result = init_from_key_file (key_file, error);
|
gboolean result = load_from_key_file (out, key_file, error);
|
||||||
g_key_file_free (key_file);
|
g_key_file_free (key_file);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +113,8 @@ search (Dictionary *dict)
|
||||||
{
|
{
|
||||||
GtkEntryBuffer *buf = gtk_entry_get_buffer (GTK_ENTRY (g.entry));
|
GtkEntryBuffer *buf = gtk_entry_get_buffer (GTK_ENTRY (g.entry));
|
||||||
const gchar *input_utf8 = gtk_entry_buffer_get_text (buf);
|
const gchar *input_utf8 = gtk_entry_buffer_get_text (buf);
|
||||||
|
if (!dict->dict)
|
||||||
|
return;
|
||||||
|
|
||||||
StardictIterator *iterator =
|
StardictIterator *iterator =
|
||||||
stardict_dict_search (dict->dict, input_utf8, NULL);
|
stardict_dict_search (dict->dict, input_utf8, NULL);
|
||||||
|
@ -295,20 +299,68 @@ show_error_dialog (GError *error)
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
reload_dictionaries (GPtrArray *new_dictionaries, GError **error)
|
on_new_dictionaries_loaded (G_GNUC_UNUSED GObject* source_object,
|
||||||
|
GAsyncResult* res, G_GNUC_UNUSED gpointer user_data)
|
||||||
{
|
{
|
||||||
if (!load_dictionaries (new_dictionaries, error))
|
g.loading = FALSE;
|
||||||
return FALSE;
|
|
||||||
|
GError *error = NULL;
|
||||||
|
GPtrArray *new_dictionaries =
|
||||||
|
g_task_propagate_pointer (G_TASK (res), &error);
|
||||||
|
if (!new_dictionaries)
|
||||||
|
{
|
||||||
|
show_error_dialog (error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (gtk_notebook_get_n_pages (GTK_NOTEBOOK (g.notebook)))
|
while (gtk_notebook_get_n_pages (GTK_NOTEBOOK (g.notebook)))
|
||||||
gtk_notebook_remove_page (GTK_NOTEBOOK (g.notebook), -1);
|
gtk_notebook_remove_page (GTK_NOTEBOOK (g.notebook), -1);
|
||||||
|
|
||||||
g.dictionary = -1;
|
g.dictionary = -1;
|
||||||
stardict_view_set_position (STARDICT_VIEW (g.view), NULL, 0);
|
if (g.dictionaries)
|
||||||
g_ptr_array_free (g.dictionaries, TRUE);
|
g_ptr_array_free (g.dictionaries, TRUE);
|
||||||
|
|
||||||
|
stardict_view_set_position (STARDICT_VIEW (g.view), NULL, 0);
|
||||||
g.dictionaries = new_dictionaries;
|
g.dictionaries = new_dictionaries;
|
||||||
init_tabs ();
|
init_tabs ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_reload_dictionaries_task (GTask *task, G_GNUC_UNUSED gpointer source_object,
|
||||||
|
gpointer task_data, G_GNUC_UNUSED GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
if (load_dictionaries (task_data, &error))
|
||||||
|
{
|
||||||
|
g_task_return_pointer (task,
|
||||||
|
g_ptr_array_ref (task_data), (GDestroyNotify) g_ptr_array_unref);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
g_task_return_error (task, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
reload_dictionaries (GPtrArray *new_dictionaries, GError **error)
|
||||||
|
{
|
||||||
|
// TODO: We could cancel that task.
|
||||||
|
if (g.loading)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"already loading dictionaries");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Some other kind of indication.
|
||||||
|
// Note that "action widgets" aren't visible without GtkNotebook tabs.
|
||||||
|
g.loading = TRUE;
|
||||||
|
|
||||||
|
GTask *task = g_task_new (NULL, NULL, on_new_dictionaries_loaded, NULL);
|
||||||
|
g_task_set_name (task, __func__);
|
||||||
|
g_task_set_task_data (task,
|
||||||
|
new_dictionaries, (GDestroyNotify) g_ptr_array_unref);
|
||||||
|
g_task_run_in_thread (task, on_reload_dictionaries_task);
|
||||||
|
g_object_unref (task);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,19 +481,19 @@ main (int argc, char *argv[])
|
||||||
|
|
||||||
gtk_window_set_default_icon_name (PROJECT_NAME);
|
gtk_window_set_default_icon_name (PROJECT_NAME);
|
||||||
|
|
||||||
g.dictionaries =
|
GPtrArray *new_dictionaries =
|
||||||
g_ptr_array_new_with_free_func ((GDestroyNotify) dictionary_destroy);
|
g_ptr_array_new_with_free_func ((GDestroyNotify) dictionary_destroy);
|
||||||
if (filenames)
|
if (filenames)
|
||||||
init (filenames);
|
{
|
||||||
else if (!init_from_config (&error) && error)
|
load_from_filenames (new_dictionaries, filenames);
|
||||||
die_with_dialog (error->message);
|
|
||||||
g_strfreev (filenames);
|
g_strfreev (filenames);
|
||||||
|
}
|
||||||
|
else if (!load_from_config (new_dictionaries, &error) && error)
|
||||||
|
die_with_dialog (error->message);
|
||||||
|
|
||||||
if (!g.dictionaries->len)
|
if (!new_dictionaries->len)
|
||||||
die_with_dialog (_("No dictionaries found either in "
|
die_with_dialog (_("No dictionaries found either in "
|
||||||
"the configuration or on the command line"));
|
"the configuration or on the command line"));
|
||||||
if (!load_dictionaries (g.dictionaries, &error))
|
|
||||||
die_with_dialog (error->message);
|
|
||||||
|
|
||||||
// Some Adwaita stupidity, plus defaults for our own widget.
|
// Some Adwaita stupidity, plus defaults for our own widget.
|
||||||
// All the named colours have been there since GNOME 3.4
|
// All the named colours have been there since GNOME 3.4
|
||||||
|
@ -530,7 +582,6 @@ main (int argc, char *argv[])
|
||||||
|
|
||||||
g.view = stardict_view_new ();
|
g.view = stardict_view_new ();
|
||||||
gtk_box_pack_end (GTK_BOX (superbox), g.view, TRUE, TRUE, 0);
|
gtk_box_pack_end (GTK_BOX (superbox), g.view, TRUE, TRUE, 0);
|
||||||
init_tabs ();
|
|
||||||
|
|
||||||
GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
|
GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
|
||||||
g_signal_connect (clipboard, "owner-change",
|
g_signal_connect (clipboard, "owner-change",
|
||||||
|
@ -544,6 +595,9 @@ main (int argc, char *argv[])
|
||||||
g_signal_connect (g.view, "send",
|
g_signal_connect (g.view, "send",
|
||||||
G_CALLBACK (on_send), NULL);
|
G_CALLBACK (on_send), NULL);
|
||||||
|
|
||||||
|
if (!reload_dictionaries (new_dictionaries, &error))
|
||||||
|
die_with_dialog (error->message);
|
||||||
|
|
||||||
gtk_widget_show_all (g.window);
|
gtk_widget_show_all (g.window);
|
||||||
gtk_main ();
|
gtk_main ();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -269,7 +269,6 @@ load_dictionaries_sequentially (GPtrArray *dictionaries, GError **e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parallelize dictionary loading if possible, because of collation reindexing
|
// Parallelize dictionary loading if possible, because of collation reindexing
|
||||||
#if GLIB_CHECK_VERSION (2, 36, 0)
|
|
||||||
static void
|
static void
|
||||||
load_worker (gpointer data, gpointer user_data)
|
load_worker (gpointer data, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
@ -304,10 +303,3 @@ load_dictionaries (GPtrArray *dictionaries, GError **e)
|
||||||
g_async_queue_unref (error_queue);
|
g_async_queue_unref (error_queue);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#else // GLib < 2.36
|
|
||||||
gboolean
|
|
||||||
load_dictionaries (GPtrArray *dictionaries, GError **e)
|
|
||||||
{
|
|
||||||
return load_dictionaries_sequentially (dictionaries, e);
|
|
||||||
}
|
|
||||||
#endif // GLib < 2.36
|
|
||||||
|
|
Loading…
Reference in New Issue