mirror of
https://gitlab.gnome.org/GNOME/nautilus
synced 2024-10-02 14:03:39 +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
|
@ -9,6 +9,7 @@
|
||||||
#include "nautilus-internal-place-file.h"
|
#include "nautilus-internal-place-file.h"
|
||||||
|
|
||||||
#include <glib/gi18n.h>
|
#include <glib/gi18n.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
#include "nautilus-file-private.h"
|
#include "nautilus-file-private.h"
|
||||||
#include "nautilus-scheme.h"
|
#include "nautilus-scheme.h"
|
||||||
|
@ -18,6 +19,9 @@
|
||||||
struct _NautilusInternalPlaceFile
|
struct _NautilusInternalPlaceFile
|
||||||
{
|
{
|
||||||
NautilusFile parent_instance;
|
NautilusFile parent_instance;
|
||||||
|
|
||||||
|
GList *callbacks;
|
||||||
|
GCancellable *network_mount_cancellable;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (NautilusInternalPlaceFile, nautilus_internal_place_file, NAUTILUS_TYPE_FILE);
|
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
|
static void
|
||||||
real_call_when_ready (NautilusFile *file,
|
real_call_when_ready (NautilusFile *file,
|
||||||
NautilusFileAttributes file_attributes,
|
NautilusFileAttributes file_attributes,
|
||||||
NautilusFileCallback callback,
|
NautilusFileCallback callback,
|
||||||
gpointer callback_data)
|
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. */
|
/* Internal place attributes are static, so its always ready. */
|
||||||
(*callback)(file, callback_data);
|
(*callback)(file, callback_data);
|
||||||
|
@ -54,6 +124,11 @@ real_cancel_call_when_ready (NautilusFile *file,
|
||||||
NautilusFileCallback callback,
|
NautilusFileCallback callback,
|
||||||
gpointer callback_data)
|
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
|
static gboolean
|
||||||
|
@ -93,6 +168,18 @@ nautilus_internal_place_file_constructed (GObject *object)
|
||||||
file->details->file_info_is_up_to_date = TRUE;
|
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
|
static void
|
||||||
nautilus_internal_place_file_class_init (NautilusInternalPlaceFileClass *klass)
|
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.*/
|
/* We need to know the parent directory, which is a construction property.*/
|
||||||
object_class->constructed = nautilus_internal_place_file_constructed;
|
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;
|
file_class->default_file_type = G_FILE_TYPE_DIRECTORY;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue