diff options
| author | Přemysl Eric Janouch <p@janouch.name> | 2022-09-04 13:16:40 +0200 | 
|---|---|---|
| committer | Přemysl Eric Janouch <p@janouch.name> | 2022-09-04 13:16:40 +0200 | 
| commit | 27dcf87a642f6b5d63a1a4e5884d7a319a7601a2 (patch) | |
| tree | d3a2b78fda398d4e63e389be5a388280f042973a | |
| parent | 7ef502759e5f4cbcf0afa8ce8623ec386f419f90 (diff) | |
| download | tdv-27dcf87a642f6b5d63a1a4e5884d7a319a7601a2.tar.gz tdv-27dcf87a642f6b5d63a1a4e5884d7a319a7601a2.tar.xz tdv-27dcf87a642f6b5d63a1a4e5884d7a319a7601a2.zip | |
sdgui: load dictionaries asynchronously
This is a must when loading huge dictionaries,
where not even parallelization helps much.
| -rw-r--r-- | src/sdgui.c | 96 | ||||
| -rw-r--r-- | src/utils.c | 8 | 
2 files changed, 75 insertions, 29 deletions
| diff --git a/src/sdgui.c b/src/sdgui.c index 81d17db..993d1f5 100644 --- a/src/sdgui.c +++ b/src/sdgui.c @@ -42,6 +42,8 @@ static struct  	gint          last;              ///< The last dictionary index  	GPtrArray    *dictionaries;      ///< All open dictionaries +	gboolean      loading;           ///< Dictionaries are being loaded +  	gboolean      watch_selection;   ///< Following X11 PRIMARY?  }  g; @@ -49,19 +51,19 @@ g;  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  static void -init (gchar **filenames) +load_from_filenames (GPtrArray *out, gchar **filenames)  {  	for (gsize i = 0; filenames[i]; i++)  	{  		Dictionary *dict = g_malloc0 (sizeof *dict);  		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()  static gboolean -init_from_key_file (GKeyFile *kf, GError **error) +load_from_key_file (GPtrArray *out, GKeyFile *kf, GError **error)  {  	const gchar *dictionaries = "Dictionaries";  	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);  		dict->name = names[i]; -		g_ptr_array_add (g.dictionaries, dict); +		g_ptr_array_add (out, dict);  	}  	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 =  			g_key_file_get_string (kf, dictionaries, dict->name, error);  		if (!path) @@ -95,13 +97,13 @@ init_from_key_file (GKeyFile *kf, GError **error)  }  static gboolean -init_from_config (GError **error) +load_from_config (GPtrArray *out, GError **error)  {  	GKeyFile *key_file = load_project_config_file (error);  	if (!key_file)  		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);  	return result;  } @@ -111,6 +113,8 @@ search (Dictionary *dict)  {  	GtkEntryBuffer *buf = gtk_entry_get_buffer (GTK_ENTRY (g.entry));  	const gchar *input_utf8 = gtk_entry_buffer_get_text (buf); +	if (!dict->dict) +		return;  	StardictIterator *iterator =  		stardict_dict_search (dict->dict, input_utf8, NULL); @@ -295,20 +299,68 @@ show_error_dialog (GError *error)  	g_error_free (error);  } -static gboolean -reload_dictionaries (GPtrArray *new_dictionaries, GError **error) +static void +on_new_dictionaries_loaded (G_GNUC_UNUSED GObject* source_object, +	GAsyncResult* res, G_GNUC_UNUSED gpointer user_data)  { -	if (!load_dictionaries (new_dictionaries, error)) -		return FALSE; +	g.loading = 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)))  		gtk_notebook_remove_page (GTK_NOTEBOOK (g.notebook), -1);  	g.dictionary = -1; +	if (g.dictionaries) +		g_ptr_array_free (g.dictionaries, TRUE); +  	stardict_view_set_position (STARDICT_VIEW (g.view), NULL, 0); -	g_ptr_array_free (g.dictionaries, TRUE);  	g.dictionaries = new_dictionaries;  	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;  } @@ -429,19 +481,19 @@ main (int argc, char *argv[])  	gtk_window_set_default_icon_name (PROJECT_NAME); -	g.dictionaries = +	GPtrArray *new_dictionaries =  		g_ptr_array_new_with_free_func ((GDestroyNotify) dictionary_destroy);  	if (filenames) -		init (filenames); -	else if (!init_from_config (&error) && error) +	{ +		load_from_filenames (new_dictionaries, filenames); +		g_strfreev (filenames); +	} +	else if (!load_from_config (new_dictionaries, &error) && error)  		die_with_dialog (error->message); -	g_strfreev (filenames); -	if (!g.dictionaries->len) +	if (!new_dictionaries->len)  		die_with_dialog (_("No dictionaries found either in "  			"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.  	// 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 ();  	gtk_box_pack_end (GTK_BOX (superbox), g.view, TRUE, TRUE, 0); -	init_tabs ();  	GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);  	g_signal_connect (clipboard, "owner-change", @@ -544,6 +595,9 @@ main (int argc, char *argv[])  	g_signal_connect (g.view, "send",  		G_CALLBACK (on_send), NULL); +	if (!reload_dictionaries (new_dictionaries, &error)) +		die_with_dialog (error->message); +  	gtk_widget_show_all (g.window);  	gtk_main ();  	return 0; diff --git a/src/utils.c b/src/utils.c index 6a32bda..5542202 100644 --- a/src/utils.c +++ b/src/utils.c @@ -269,7 +269,6 @@ load_dictionaries_sequentially (GPtrArray *dictionaries, GError **e)  }  // Parallelize dictionary loading if possible, because of collation reindexing -#if GLIB_CHECK_VERSION (2, 36, 0)  static void  load_worker (gpointer data, gpointer user_data)  { @@ -304,10 +303,3 @@ load_dictionaries (GPtrArray *dictionaries, GError **e)  	g_async_queue_unref (error_queue);  	return result;  } -#else  // GLib < 2.36 -gboolean -load_dictionaries (GPtrArray *dictionaries, GError **e) -{ -	return load_dictionaries_sequentially (dictionaries, e); -} -#endif  // GLib < 2.36 | 
