pathbar: Handle webdav where is the root is a path

Our webdav server has a root which is davs://mynextcloud/remote.php/webdav
When once creates a GFile out of or out of a subdirectory, and one call
g_file_get_parent(), it recurses too far up and try to query
davs://mynextcloud/remote.php which fails, resulting in a broken pathbar.

To fix that, before querying the metadata of each element of the path,
I query the "enclosing mount", then use it's root to compare the GFile
against.

With the right GMount, we can also fix the icon drawing code in the
pathbar for network drives.
This commit is contained in:
Olivier Crête 2023-04-13 16:09:48 -06:00
parent 64a1969293
commit c271cd1a3f

View File

@ -125,6 +125,7 @@ struct _ButtonData
GCancellable *cancellable;
guint ignore_changes : 1;
guint file_is_hidden : 1;
GMount *mount;
};
/* This macro is used to check if a button can be used as a fake root.
* All buttons in front of a fake root are automatically hidden when in a
@ -417,30 +418,30 @@ set_button_image (GtkPathBar *path_bar,
ButtonData *button_data)
{
struct SetButtonImageData *data;
GMount *mount;
switch (button_data->type)
{
case ROOT_BUTTON:
if (path_bar->root_icon != NULL)
GIcon *root_icon = NULL;
if (!button_data->mount && path_bar->root_icon != NULL &&
g_file_is_native (button_data->file))
{
gtk_image_set_from_gicon (GTK_IMAGE (button_data->image), path_bar->root_icon);
break;
}
break;
}
mount = g_file_find_enclosing_mount (button_data->file, NULL, NULL);
if (!mount && g_file_is_native (button_data->file))
path_bar->root_icon = g_themed_icon_new ("drive-harddisk-symbolic");
else if (mount)
path_bar->root_icon = g_mount_get_symbolic_icon (mount);
if (!button_data->mount && g_file_is_native (button_data->file))
root_icon = path_bar->root_icon = g_object_ref (g_themed_icon_new ("drive-harddisk-symbolic"));
else if (button_data->mount)
root_icon = g_mount_get_symbolic_icon (button_data->mount);
else
path_bar->root_icon = NULL;
root_icon = NULL;
g_clear_object (&mount);
gtk_image_set_from_gicon (GTK_IMAGE (button_data->image), root_icon);
gtk_image_set_from_gicon (GTK_IMAGE (button_data->image), path_bar->root_icon);
g_clear_object (&root_icon);
break;
@ -515,6 +516,7 @@ static void
button_data_free (ButtonData *button_data)
{
g_clear_object (&button_data->file);
g_clear_object (&button_data->mount);
g_free (button_data->dir_name);
g_free (button_data);
}
@ -571,11 +573,11 @@ file_is_recent_uri (GFile *file)
}
static ButtonType
find_button_type (GtkPathBar *path_bar,
GFile *file)
find_button_type (GtkPathBar *path_bar,
GFile *file,
GFile *root_file)
{
if (path_bar->root_file != NULL &&
g_file_equal (file, path_bar->root_file))
if (root_file != NULL && g_file_equal (file, root_file))
return ROOT_BUTTON;
if (path_bar->home_file != NULL &&
g_file_equal (file, path_bar->home_file))
@ -593,6 +595,8 @@ static ButtonData *
make_directory_button (GtkPathBar *path_bar,
const char *dir_name,
GFile *file,
GMount *mount,
GFile *root_file,
gboolean current_dir,
gboolean file_is_hidden)
{
@ -604,17 +608,26 @@ make_directory_button (GtkPathBar *path_bar,
file_is_hidden = !! file_is_hidden;
/* Is it a special button? */
button_data = g_new0 (ButtonData, 1);
button_data->type = find_button_type (path_bar, file);
button_data->type = find_button_type (path_bar, file, root_file);
button_data->button = gtk_toggle_button_new ();
gtk_widget_set_focus_on_click (button_data->button, FALSE);
switch (button_data->type)
{
case ROOT_BUTTON:
button_data->image = gtk_image_new ();
child = button_data->image;
button_data->label = NULL;
break;
if (mount)
{
button_data->dir_name = g_mount_get_name (mount);
button_data->mount = g_object_ref (mount);
}
else
{
button_data->image = gtk_image_new ();
child = button_data->image;
button_data->label = NULL;
break;
}
G_GNUC_FALLTHROUGH;
case HOME_BUTTON:
case DESKTOP_BUTTON:
case RECENT_BUTTON:
@ -631,7 +644,8 @@ make_directory_button (GtkPathBar *path_bar,
button_data->image = NULL;
}
button_data->dir_name = g_strdup (dir_name);
if (button_data->dir_name == NULL)
button_data->dir_name = g_strdup (dir_name);
button_data->file = g_object_ref (file);
button_data->file_is_hidden = file_is_hidden;
@ -715,6 +729,8 @@ gtk_path_bar_check_parent_path (GtkPathBar *path_bar,
struct SetFileInfo
{
GFile *file;
GMount *mount;
GFile *root_file;
GFile *parent_file;
GtkPathBar *path_bar;
GList *new_buttons;
@ -762,10 +778,15 @@ gtk_path_bar_set_file_finish (struct SetFileInfo *info,
g_object_unref (info->file);
if (info->parent_file)
g_object_unref (info->parent_file);
if (info->root_file)
g_object_unref (info->root_file);
if (info->mount)
g_object_unref (info->mount);
g_free (info);
}
static void
gtk_path_bar_get_info_callback (GObject *source,
GAsyncResult *result,
@ -802,6 +823,8 @@ gtk_path_bar_get_info_callback (GObject *source,
button_data = make_directory_button (file_info->path_bar, display_name,
file_info->file,
file_info->mount,
file_info->root_file,
file_info->first_directory, is_hidden);
g_clear_object (&file_info->file);
@ -824,7 +847,54 @@ gtk_path_bar_get_info_callback (GObject *source,
return;
}
file_info->parent_file = g_file_get_parent (file_info->file);
if (g_file_equal (file_info->file, file_info->root_file))
file_info->parent_file = NULL;
else
file_info->parent_file = g_file_get_parent (file_info->file);
/* Recurse asynchronously */
file_info->cancellable = g_cancellable_new ();
file_info->path_bar->get_info_cancellable = file_info->cancellable;
g_file_query_info_async (file_info->file,
"standard::display-name,"
"standard::is-hidden,"
"standard::is-backup",
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_DEFAULT,
file_info->cancellable,
gtk_path_bar_get_info_callback,
file_info);
add_cancellable (file_info->path_bar, file_info->cancellable);
}
static void
gtk_path_bar_get_mount_callback (GObject *source,
GAsyncResult *result,
gpointer data)
{
GFile *file = G_FILE (source);
struct SetFileInfo *file_info = data;
file_info->mount = g_file_find_enclosing_mount_finish (file, result, NULL);
if (file_info->mount)
file_info->root_file = g_mount_get_root (file_info->mount);
g_assert (GTK_IS_PATH_BAR (file_info->path_bar));
g_assert (G_OBJECT (file_info->path_bar)->ref_count > 0);
if (file_info->root_file == NULL)
file_info->root_file = g_object_ref (file_info->path_bar->root_file);
if (g_file_equal (file_info->file, file_info->root_file))
file_info->parent_file = NULL;
else
file_info->parent_file = g_file_get_parent (file_info->file);
cancellable_async_done (file_info->path_bar, file_info->cancellable);
if (file_info->path_bar->get_info_cancellable == file_info->cancellable)
file_info->path_bar->get_info_cancellable = NULL;
file_info->cancellable = NULL;
/* Recurse asynchronously */
file_info->cancellable = g_cancellable_new ();
@ -861,22 +931,36 @@ _gtk_path_bar_set_file (GtkPathBar *path_bar,
info->file = g_object_ref (file);
info->path_bar = path_bar;
info->first_directory = TRUE;
info->parent_file = g_file_get_parent (info->file);
if (path_bar->get_info_cancellable)
cancel_cancellable (path_bar, path_bar->get_info_cancellable);
info->cancellable = g_cancellable_new ();
path_bar->get_info_cancellable = info->cancellable;
g_file_query_info_async (info->file,
"standard::display-name,"
"standard::is-hidden,"
"standard::is-backup",
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_DEFAULT,
info->cancellable,
gtk_path_bar_get_info_callback,
info);
if (g_file_is_native (info->file))
{
info->root_file = g_object_ref (path_bar->root_file);
info->parent_file = g_file_get_parent (info->file);
g_file_query_info_async (info->file,
"standard::display-name,"
"standard::is-hidden,"
"standard::is-backup",
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_DEFAULT,
info->cancellable,
gtk_path_bar_get_info_callback,
info);
}
else
{
g_file_find_enclosing_mount_async (info->file,
G_PRIORITY_DEFAULT,
info->cancellable,
gtk_path_bar_get_mount_callback,
info);
}
add_cancellable (path_bar, info->cancellable);
}