shell-global: Make saving of persistent state asynchronous
This is an expensive operation that is best avoided in the main loop. Given
the call doesn't care much about returning error or status, it can just
be made async within.
Every operation on a given file will be destructive wrt previous
operations on the same file, so we just cancel any pending operation on
it before batching the current one.
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/815
(cherry picked from commit 86a00b6872
)
This commit is contained in:
parent
ac3738f4be
commit
20e7dd31a8
@ -87,6 +87,8 @@ struct _ShellGlobal {
|
|||||||
/* For sound notifications */
|
/* For sound notifications */
|
||||||
ca_context *sound_context;
|
ca_context *sound_context;
|
||||||
|
|
||||||
|
GHashTable *save_ops;
|
||||||
|
|
||||||
gboolean has_modal;
|
gboolean has_modal;
|
||||||
gboolean frame_timestamps;
|
gboolean frame_timestamps;
|
||||||
gboolean frame_finish_timestamp;
|
gboolean frame_finish_timestamp;
|
||||||
@ -322,6 +324,10 @@ shell_global_init (ShellGlobal *global)
|
|||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
g_strfreev (search_path);
|
g_strfreev (search_path);
|
||||||
|
|
||||||
|
global->save_ops = g_hash_table_new_full (g_file_hash,
|
||||||
|
(GEqualFunc) g_file_equal,
|
||||||
|
g_object_unref, g_object_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -341,6 +347,8 @@ shell_global_finalize (GObject *object)
|
|||||||
g_free (global->imagedir);
|
g_free (global->imagedir);
|
||||||
g_free (global->userdatadir);
|
g_free (global->userdatadir);
|
||||||
|
|
||||||
|
g_hash_table_unref (global->save_ops);
|
||||||
|
|
||||||
G_OBJECT_CLASS(shell_global_parent_class)->finalize (object);
|
G_OBJECT_CLASS(shell_global_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1757,20 +1765,77 @@ shell_global_get_session_mode (ShellGlobal *global)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
save_variant (GFile *dir,
|
delete_variant_cb (GObject *object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
ShellGlobal *global = user_data;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!g_file_delete_finish (G_FILE (object), result, &error))
|
||||||
|
{
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
g_warning ("Could not delete runtime/persistent state file: %s\n",
|
||||||
|
error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_remove (global->save_ops, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
replace_variant_cb (GObject *object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
ShellGlobal *global = user_data;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!g_file_replace_contents_finish (G_FILE (object), result, NULL, &error))
|
||||||
|
{
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
g_warning ("Could not replace runtime/persistent state file: %s\n",
|
||||||
|
error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_remove (global->save_ops, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
save_variant (ShellGlobal *global,
|
||||||
|
GFile *dir,
|
||||||
const char *property_name,
|
const char *property_name,
|
||||||
GVariant *variant)
|
GVariant *variant)
|
||||||
{
|
{
|
||||||
GFile *path = g_file_get_child (dir, property_name);
|
GFile *path = g_file_get_child (dir, property_name);
|
||||||
|
GCancellable *cancellable;
|
||||||
|
|
||||||
|
cancellable = g_hash_table_lookup (global->save_ops, path);
|
||||||
|
g_cancellable_cancel (cancellable);
|
||||||
|
|
||||||
|
cancellable = g_cancellable_new ();
|
||||||
|
g_hash_table_insert (global->save_ops, g_object_ref (path), cancellable);
|
||||||
|
|
||||||
if (variant == NULL || g_variant_get_data (variant) == NULL)
|
if (variant == NULL || g_variant_get_data (variant) == NULL)
|
||||||
(void) g_file_delete (path, NULL, NULL);
|
{
|
||||||
|
g_file_delete_async (path, G_PRIORITY_DEFAULT, cancellable,
|
||||||
|
delete_variant_cb, global);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gsize size = g_variant_get_size (variant);
|
g_file_replace_contents_async (path,
|
||||||
g_file_replace_contents (path, g_variant_get_data (variant), size,
|
g_variant_get_data (variant),
|
||||||
NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
|
g_variant_get_size (variant),
|
||||||
NULL, NULL, NULL);
|
NULL, FALSE,
|
||||||
|
G_FILE_CREATE_REPLACE_DESTINATION,
|
||||||
|
cancellable, replace_variant_cb, global);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_unref (path);
|
g_object_unref (path);
|
||||||
@ -1824,7 +1889,7 @@ shell_global_set_runtime_state (ShellGlobal *global,
|
|||||||
const char *property_name,
|
const char *property_name,
|
||||||
GVariant *variant)
|
GVariant *variant)
|
||||||
{
|
{
|
||||||
save_variant (global->runtime_state_path, property_name, variant);
|
save_variant (global, global->runtime_state_path, property_name, variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1859,7 +1924,7 @@ shell_global_set_persistent_state (ShellGlobal *global,
|
|||||||
const char *property_name,
|
const char *property_name,
|
||||||
GVariant *variant)
|
GVariant *variant)
|
||||||
{
|
{
|
||||||
save_variant (global->userdatadir_path, property_name, variant);
|
save_variant (global, global->userdatadir_path, property_name, variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user