mirror of
https://gitlab.gnome.org/GNOME/nautilus
synced 2024-11-04 19:08:23 +00:00
internal-place-file: Mount network:/// on ready request
The whole application freezes the first time `x-network-view:///` is visited during a session (or after `killall gvfsd-network`). This happens because GDaemonFile makes sync DBus calls to mount the `network:///` location when we call `g_file_monitor_directory()`[0], which is done by the view when the ready callback is invoked. In order to avoid this, ensure the `network:///` location is mounted before invoking the ready callback for the `x-network-view:///` file. (This achieves a result which is similar to accessing `network:///` directly, or any other location which is slow to mount: the location is not changed until after the mount succeeds. I don't think this is good UX, but it's an entirely different problem which is not specific to the Network view at all.) [0] More context on https://gitlab.gnome.org/GNOME/gvfs/-/issues/455
This commit is contained in:
parent
f0d250d0cc
commit
41c0c1f624
1 changed files with 89 additions and 1 deletions
|
@ -9,6 +9,7 @@
|
|||
#include "nautilus-internal-place-file.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "nautilus-file-private.h"
|
||||
#include "nautilus-scheme.h"
|
||||
|
@ -18,6 +19,9 @@
|
|||
struct _NautilusInternalPlaceFile
|
||||
{
|
||||
NautilusFile parent_instance;
|
||||
|
||||
GList *callbacks;
|
||||
GCancellable *network_mount_cancellable;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (NautilusInternalPlaceFile, nautilus_internal_place_file, NAUTILUS_TYPE_FILE);
|
||||
|
@ -36,13 +40,79 @@ real_monitor_remove (NautilusFile *file,
|
|||
{
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NautilusFileCallback callback;
|
||||
gpointer callback_data;
|
||||
} InternalPlaceFileCallback;
|
||||
|
||||
static void
|
||||
network_mount_callback (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
NautilusInternalPlaceFile *self = NAUTILUS_INTERNAL_PLACE_FILE (data);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
(void) g_file_mount_enclosing_volume_finish (G_FILE (source_object), result, &error);
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear cancellable and steal callbacks list because call_when_ready() may
|
||||
* be called again inside the `for` loop. */
|
||||
g_clear_object (&self->network_mount_cancellable);
|
||||
|
||||
GList *callbacks = g_steal_pointer (&self->callbacks);
|
||||
for (GList *l = callbacks; l != NULL; l = l->next)
|
||||
{
|
||||
InternalPlaceFileCallback *callback = l->data;
|
||||
|
||||
(*callback->callback)(NAUTILUS_FILE (self), callback->callback_data);
|
||||
}
|
||||
g_list_free_full (callbacks, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
real_call_when_ready (NautilusFile *file,
|
||||
NautilusFileAttributes file_attributes,
|
||||
NautilusFileCallback callback,
|
||||
gpointer callback_data)
|
||||
{
|
||||
if (callback != NULL)
|
||||
NautilusInternalPlaceFile *self = NAUTILUS_INTERNAL_PLACE_FILE (file);
|
||||
|
||||
if (NAUTILUS_IS_NETWORK_DIRECTORY (file->details->directory))
|
||||
{
|
||||
/* WORKAROUND:
|
||||
* We must ensure network:/// is mounted before calling it "ready",
|
||||
* otherwise GDaemonFile makes sync D-Bus calls to mount network://
|
||||
* when the view tries do add a monitor, blocking the main thread and
|
||||
* freezing the UI.
|
||||
* See: https://gitlab.gnome.org/GNOME/gvfs/-/issues/455
|
||||
*/
|
||||
|
||||
if (callback != NULL)
|
||||
{
|
||||
InternalPlaceFileCallback data = {callback, callback_data};
|
||||
self->callbacks = g_list_prepend (self->callbacks,
|
||||
g_memdup2 (&data, sizeof (data)));
|
||||
}
|
||||
|
||||
/* If there is a cancellable, we are already mounting */
|
||||
if (self->network_mount_cancellable == NULL)
|
||||
{
|
||||
g_autoptr (GFile) network_backend = g_file_new_for_uri (SCHEME_NETWORK ":///");
|
||||
|
||||
self->network_mount_cancellable = g_cancellable_new ();
|
||||
g_file_mount_enclosing_volume (network_backend,
|
||||
G_MOUNT_MOUNT_NONE,
|
||||
NULL,
|
||||
self->network_mount_cancellable,
|
||||
network_mount_callback, self);
|
||||
}
|
||||
}
|
||||
else if (callback != NULL)
|
||||
{
|
||||
/* Internal place attributes are static, so its always ready. */
|
||||
(*callback)(file, callback_data);
|
||||
|
@ -54,6 +124,11 @@ real_cancel_call_when_ready (NautilusFile *file,
|
|||
NautilusFileCallback callback,
|
||||
gpointer callback_data)
|
||||
{
|
||||
NautilusInternalPlaceFile *self = NAUTILUS_INTERNAL_PLACE_FILE (file);
|
||||
|
||||
g_clear_list (&self->callbacks, g_free);
|
||||
g_cancellable_cancel (self->network_mount_cancellable);
|
||||
g_clear_object (&self->network_mount_cancellable);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -93,6 +168,18 @@ nautilus_internal_place_file_constructed (GObject *object)
|
|||
file->details->file_info_is_up_to_date = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
nautilus_internal_place_file_dispose (GObject *object)
|
||||
{
|
||||
NautilusInternalPlaceFile *self = NAUTILUS_INTERNAL_PLACE_FILE (object);
|
||||
|
||||
g_clear_list (&self->callbacks, g_free);
|
||||
g_cancellable_cancel (self->network_mount_cancellable);
|
||||
g_clear_object (&self->network_mount_cancellable);
|
||||
|
||||
G_OBJECT_CLASS (nautilus_internal_place_file_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
nautilus_internal_place_file_class_init (NautilusInternalPlaceFileClass *klass)
|
||||
{
|
||||
|
@ -101,6 +188,7 @@ nautilus_internal_place_file_class_init (NautilusInternalPlaceFileClass *klass)
|
|||
|
||||
/* We need to know the parent directory, which is a construction property.*/
|
||||
object_class->constructed = nautilus_internal_place_file_constructed;
|
||||
object_class->dispose = nautilus_internal_place_file_dispose;
|
||||
|
||||
file_class->default_file_type = G_FILE_TYPE_DIRECTORY;
|
||||
|
||||
|
|
Loading…
Reference in a new issue