#include <config.h>
#include <glib/gi18n-lib.h>
#include "favorite-vfs-file.h"
#include "favorite-vfs-file-enumerator.h"
#include "favorite-vfs-file-monitor.h"
#define FAVORITES_SCHEMA "org.x.apps.favorites"
#define FAVORITE_DCONF_METADATA_KEY "root-metadata"
static GSettings *settings = NULL;
typedef struct
{
gchar *uri; // favorites://foo
XAppFavoriteInfo *info;
} FavoriteVfsFilePrivate;
struct _FavoriteVfsFile
{
GObject parent_instance;
FavoriteVfsFilePrivate *priv;
};
GList *_xapp_favorites_get_display_names (XAppFavorites *favorites);
static void favorite_vfs_file_gfile_iface_init (GFileIface *iface);
gchar *
path_to_fav_uri (const gchar *path)
{
g_return_val_if_fail (path != NULL, NULL);
return g_strconcat (ROOT_URI, path, NULL);
}
gchar *
fav_uri_to_display_name (const gchar *uri)
{
g_return_val_if_fail (uri != NULL, NULL);
g_return_val_if_fail (g_str_has_prefix (uri, ROOT_URI), NULL);
const gchar *ptr;
ptr = uri + strlen (ROOT_URI);
if (ptr[0] == '/')
{
ptr++;
}
return g_strdup (ptr);
}
G_DEFINE_TYPE_EXTENDED (FavoriteVfsFile,
favorite_vfs_file,
G_TYPE_OBJECT,
0,
G_ADD_PRIVATE (FavoriteVfsFile)
G_IMPLEMENT_INTERFACE (G_TYPE_FILE, favorite_vfs_file_gfile_iface_init))
static gboolean
is_root_file (FavoriteVfsFile *file)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (file);
return g_strcmp0 (priv->uri, ROOT_URI) == 0;
}
static GFile *
file_dup (GFile *file)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
return favorite_vfs_file_new_for_uri (priv->uri);
}
static guint
file_hash (GFile *file)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
return g_str_hash (priv->uri);
}
static gboolean
file_equal (GFile *file1,
GFile *file2)
{
FavoriteVfsFilePrivate *priv1 = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file1));
FavoriteVfsFilePrivate *priv2 = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file2));
return g_strcmp0 (priv1->uri, priv2->uri) == 0;
}
static gboolean
file_is_native (GFile *file)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file;
gboolean is_really_native;
real_file = g_file_new_for_uri (priv->info->uri);
is_really_native = g_file_is_native (real_file);
g_object_unref (real_file);
return is_really_native;
}
return FALSE;
}
static gboolean
file_has_uri_scheme (GFile *file,
const gchar *uri_scheme)
{
return g_strcmp0 (uri_scheme, URI_SCHEME) == 0;
}
static gchar *
file_get_uri_scheme (GFile *file)
{
return g_strdup (URI_SCHEME);
}
static gchar *
file_get_basename (GFile *file)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info == NULL)
{
return g_strdup ("/");
}
return g_strdup (priv->info->display_name);
}
static gchar *
file_get_path (GFile *file)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (file_is_native (file))
{
GFile *real_file;
gchar *ret;
real_file = g_file_new_for_uri (priv->info->uri);
// file can't be native without an info, so we don't need to check for null here
ret = g_file_get_path (real_file);
g_object_unref (real_file);
return ret;
}
// GtkFileChooser checks for a path (and not null) before allowing a shortcut to
// be added using gtk_file_chooser_add_shortcut_folder_uri(). Even though this / doesn't
// make much sense for favorites:/// it allows it to be added to the file chooser without
// being forced to override its 'local-only' property.
if (is_root_file (FAVORITE_VFS_FILE (file)))
{
return g_strdup ("/");
}
return NULL;
}
static gchar *
file_get_uri (GFile *file)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
return g_strdup (priv->uri);
}
static gchar *
file_get_parse_name (GFile *file)
{
return file_get_uri (file);
}
static GFile *
file_get_parent (GFile *file)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
// We're only ever one level deep.
if (priv->info != NULL)
{
return g_file_new_for_uri (ROOT_URI);
}
return NULL;
}
static gboolean
file_prefix_matches (GFile *parent,
GFile *descendant)
{
g_autofree gchar *puri = NULL;
g_autofree gchar *duri = NULL;
gchar *ptr = NULL;
puri = g_file_get_uri (parent);
duri = g_file_get_uri (descendant);
ptr = g_strstr_len (puri, -1, duri);
if ((ptr == puri) && ptr[strlen (duri) + 1] == '/')
{
return TRUE;
}
return FALSE;
}
static gchar *
file_get_relative_path (GFile *parent,
GFile *descendant)
{
g_autofree gchar *puri = NULL;
g_autofree gchar *duri = NULL;
g_autofree gchar *rpath = NULL;
gchar *ptr = NULL;
puri = g_file_get_uri (parent);
duri = g_file_get_uri (descendant);
ptr = g_strstr_len (puri, -1, duri);
if ((ptr == puri) && ptr[strlen (duri) + 1] == '/')
{
rpath = g_strdup (puri + strlen (duri) + 1);
return rpath;
}
return NULL;
}
static GFile *
file_resolve_relative_path (GFile *file,
const gchar *relative_path)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
GFile *relative_file;
gchar *uri;
if (g_path_is_absolute (relative_path))
{
return g_file_new_for_path (relative_path);
}
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file;
real_file = g_file_new_for_uri (priv->info->uri);
relative_file = g_file_resolve_relative_path (real_file,
relative_path);
g_object_unref (real_file);
return relative_file;
}
if (g_strcmp0 (relative_path, ".") == 0)
{
relative_file = file_dup (file);
return relative_file;
}
uri = path_to_fav_uri (relative_path);
relative_file = g_file_new_for_uri (uri);
g_free (uri);
return relative_file;
}
static GFile *
file_get_child_for_display_name (GFile *file,
const char *display_name,
GError **error)
{
return g_file_get_child (file, display_name);
}
static GFile *
file_set_display_name (GFile *file,
const gchar *display_name,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file;
GFile *ret;
real_file = g_file_new_for_uri (priv->info->uri);
ret = g_file_set_display_name (real_file,
display_name,
cancellable,
error);
g_object_unref (real_file);
return ret;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Can't rename file");
return NULL;
}
static GFileEnumerator *
file_enumerate_children(GFile *file,
const char *attributes,
GFileQueryInfoFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
GFileEnumerator *enumerator;
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file;
real_file = g_file_new_for_uri (priv->info->uri);
enumerator = g_file_enumerate_children (real_file,
attributes,
flags,
cancellable,
error);
g_object_unref (real_file);
return enumerator;
}
GList *uris;
uris = _xapp_favorites_get_display_names (xapp_favorites_get_default ());
enumerator = favorite_vfs_file_enumerator_new (file,
attributes,
flags,
uris);
g_list_free (uris);
return enumerator;
}
static GFileInfo *
file_query_info (GFile *file,
const char *attributes,
GFileQueryInfoFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
GFileInfo *info;
GIcon *icon;
if (priv->info != NULL)
{
if (!priv->info->uri)
{
if (error != NULL)
{
*error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "File not found");
}
return NULL;
}
GFile *real_file = g_file_new_for_uri (priv->info->uri);
info = g_file_query_info (real_file, attributes, flags, cancellable, error);
if (info != NULL)
{
gchar *local_path;
g_file_info_set_display_name (info, priv->info->display_name);
g_file_info_set_name (info, priv->info->display_name);
g_file_info_set_is_symlink (info, TRUE);
local_path = g_file_get_path (real_file);
if (local_path != NULL)
{
g_file_info_set_symlink_target (info, local_path);
g_free (local_path);
}
else
{
g_file_info_set_symlink_target (info, priv->info->uri);
}
// Recent sets this also. If it's set, this uri is used to display the "location"
// for the file (the directory in which real file resides).
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, priv->info->uri);
g_file_info_set_attribute_string (info, FAVORITE_AVAILABLE_METADATA_KEY, META_TRUE);
}
else
{
g_clear_error (error);
gchar *content_type;
info = g_file_info_new ();
g_file_info_set_display_name (info, priv->info->display_name);
g_file_info_set_name (info, priv->info->display_name);
g_file_info_set_is_symlink (info, TRUE);
g_file_info_set_symlink_target (info, priv->info->uri);
/* Prevent showing a 'thumbnailing' icon */
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED, TRUE);
/* This will keep the sort position the same for missing or unmounted files */
g_file_info_set_attribute_string (info, FAVORITE_METADATA_KEY, META_TRUE);
g_file_info_set_attribute_string (info, FAVORITE_AVAILABLE_METADATA_KEY, META_FALSE);
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, priv->info->uri);
content_type = g_content_type_from_mime_type (priv->info->cached_mimetype);
icon = g_content_type_get_icon (content_type);
g_file_info_set_icon (info, icon);
g_object_unref (icon);
icon = g_content_type_get_symbolic_icon (content_type);
g_file_info_set_symbolic_icon (info, icon);
g_object_unref (icon);
g_free (content_type);
}
g_object_unref (real_file);
return info;
}
if (is_root_file (FAVORITE_VFS_FILE (file)))
{
GFileAttributeMatcher *matcher = g_file_attribute_matcher_new (attributes);
info = g_file_info_new ();
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_NAME))
g_file_info_set_name (info, "/");
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME))
g_file_info_set_display_name (info, _("Favorites"));
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_TYPE))
g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_ICON))
{
icon = g_themed_icon_new ("xapp-favorites");
g_file_info_set_icon (info, icon);
g_object_unref (icon);
}
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON))
{
icon = g_themed_icon_new ("xapp-favorites-symbolic");
g_file_info_set_symbolic_icon (info, icon);
g_object_unref (icon);
}
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_GVFS_BACKEND))
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_GVFS_BACKEND, "favorites");
if (g_file_attribute_matcher_matches (matcher, FAVORITE_AVAILABLE_METADATA_KEY))
g_file_info_set_attribute_string (info, FAVORITE_AVAILABLE_METADATA_KEY, META_TRUE);
if (g_file_attribute_matcher_enumerate_namespace (matcher, "metadata"))
{
gchar **entries = g_settings_get_strv (settings, FAVORITE_DCONF_METADATA_KEY);
if (entries != NULL)
{
gint i;
for (i = 0; entries[i] != NULL; i++)
{
gchar **t_n_v;
t_n_v = g_strsplit (entries[i], "==", 3);
if (g_strv_length (t_n_v) == 3)
{
if (g_strcmp0 (t_n_v[0], "string") == 0)
{
g_file_info_set_attribute_string (info, t_n_v[1], t_n_v[2]);
}
else
if (g_strcmp0 (t_n_v[0], "strv") == 0)
{
gchar **members = g_strsplit (t_n_v[2], "|", -1);
g_file_info_set_attribute_stringv (info, t_n_v[1], members);
g_strfreev (members);
}
}
g_strfreev (t_n_v);
}
}
g_strfreev (entries);
}
g_file_attribute_matcher_unref (matcher);
}
return info;
}
GFileInfo *
file_query_filesystem_info (GFile *file,
const char *attributes,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFileInfo *info;
GFile *real_file;
real_file = g_file_new_for_uri (priv->info->uri);
info = g_file_query_filesystem_info (real_file,
attributes,
cancellable,
error);
g_object_unref (real_file);
return info;
}
GFileInfo *info;
GFileAttributeMatcher *matcher;
info = g_file_info_new ();
matcher = g_file_attribute_matcher_new (attributes);
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE))
{
g_file_info_set_attribute_string (info,
G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "favorites");
}
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
{
g_file_info_set_attribute_boolean (info,
G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
}
g_file_attribute_matcher_unref (matcher);
return info;
}
GMount *
file_find_enclosing_mount (GFile *file,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GMount *mount;
GFile *real_file;
real_file = g_file_new_for_uri (priv->info->uri);
mount = g_file_find_enclosing_mount (real_file,
cancellable,
error);
g_object_unref (real_file);
return mount;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Can't find favorite file enclosing mount");
return NULL;
}
GFileAttributeInfoList *
file_query_settable_attributes (GFile *file,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFileAttributeInfoList *list;
GFile *real_file;
real_file = g_file_new_for_uri (priv->info->uri);
list = g_file_query_settable_attributes (real_file,
cancellable,
error);
g_object_unref (real_file);
return list;
}
return g_file_attribute_info_list_new ();
}
GFileAttributeInfoList *
file_query_writable_namespaces (GFile *file,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
GFileAttributeInfoList *list;
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file;
real_file = g_file_new_for_uri (priv->info->uri);
list = g_file_query_writable_namespaces (real_file,
cancellable,
error);
g_object_unref (real_file);
return list;
}
list = g_file_attribute_info_list_new ();
g_file_attribute_info_list_add (list,
"metadata",
G_FILE_ATTRIBUTE_TYPE_STRING,
G_FILE_ATTRIBUTE_INFO_NONE);
return list;
}
static void
remove_root_metadata (const gchar *attr_name)
{
GPtrArray *new_array;
gchar **old_metadata, **new_metadata;
gint i;
old_metadata = g_settings_get_strv (settings, FAVORITE_DCONF_METADATA_KEY);
if (old_metadata == NULL)
{
return;
}
new_array = g_ptr_array_new ();
for (i = 0; old_metadata[i] != NULL; i++)
{
gchar **t_n_v;
t_n_v = g_strsplit (old_metadata[i], "==", 3);
if (g_strcmp0 (t_n_v[1], attr_name) != 0)
{
g_ptr_array_add (new_array, g_strdup (old_metadata[i]));
}
g_strfreev (t_n_v);
}
g_ptr_array_add (new_array, NULL);
g_strfreev (old_metadata);
new_metadata = (gchar **) g_ptr_array_free (new_array, FALSE);
g_settings_set_strv (settings, FAVORITE_DCONF_METADATA_KEY, (const gchar * const *) new_metadata);
g_strfreev (new_metadata);
}
static void
set_or_update_root_metadata (const gchar *attr_name,
const gpointer value,
GFileAttributeType type)
{
GPtrArray *new_array;
gchar **old_metadata, **new_metadata;
gint i;
gchar *entry;
gboolean exists;
old_metadata = g_settings_get_strv (settings, FAVORITE_DCONF_METADATA_KEY);
if (old_metadata == NULL)
{
return;
}
switch (type)
{
case G_FILE_ATTRIBUTE_TYPE_STRING:
{
entry = g_strdup_printf ("string==%s==%s", attr_name, (gchar *) value);
break;
}
case G_FILE_ATTRIBUTE_TYPE_STRINGV:
{
gchar *val_strv = g_strjoinv ("|", (gchar **) value);
entry = g_strdup_printf ("strv==%s==%s", attr_name, val_strv);
g_free (val_strv);
break;
}
default:
break;
}
exists = FALSE;
new_array = g_ptr_array_new ();
for (i = 0; old_metadata[i] != NULL; i++)
{
gchar **t_n_v;
t_n_v = g_strsplit (old_metadata[i], "==", 3);
if (g_strcmp0 (t_n_v[1], attr_name) == 0)
{
g_ptr_array_add (new_array, entry);
exists = TRUE;
}
else
{
g_ptr_array_add (new_array, g_strdup (old_metadata[i]));
}
g_strfreev (t_n_v);
}
if (!exists)
{
g_ptr_array_add (new_array, entry);
}
g_ptr_array_add (new_array, NULL);
g_strfreev (old_metadata);
new_metadata = (gchar **) g_ptr_array_free (new_array, FALSE);
g_settings_set_strv (settings, FAVORITE_DCONF_METADATA_KEY, (const gchar * const *) new_metadata);
g_strfreev (new_metadata);
}
gboolean
file_set_attribute (GFile *file,
const gchar *attribute,
GFileAttributeType type,
gpointer value_p,
GFileQueryInfoFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
gboolean ret;
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file;
gboolean ret;
real_file = g_file_new_for_uri (priv->info->uri);
ret = g_file_set_attribute (real_file,
attribute,
type,
value_p,
flags,
cancellable,
error);
g_object_unref (real_file);
return ret;
}
ret = FALSE;
if (!is_root_file (FAVORITE_VFS_FILE (file)))
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Can't set attributes for %s - only the root (favorites:///) is supported.", priv->uri);
}
else
{
if (g_str_has_prefix (attribute, "metadata"))
{
if (type == G_FILE_ATTRIBUTE_TYPE_INVALID || value_p == NULL || ((char *) value_p)[0] == '\0')
{
// unset metadata
remove_root_metadata (attribute);
ret = TRUE;
}
else
{
if (type == G_FILE_ATTRIBUTE_TYPE_STRING || type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
{
set_or_update_root_metadata (attribute, (gchar *) value_p, type);
ret = TRUE;
}
else
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Can't set attribute '%s' for favorites:/// file "
"(only string-type metadata are allowed).", attribute);
}
}
}
else
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Can't set attribute '%s' for favorites:/// file "
"(only 'metadata' namespace is allowed).", attribute);
}
}
return ret;
}
static gboolean
file_set_attributes_from_info (GFile *file,
GFileInfo *info,
GFileQueryInfoFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
gboolean res;
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file;
gboolean ret = FALSE;
real_file = g_file_new_for_uri (priv->info->uri);
ret = g_file_set_attributes_from_info (real_file, info, flags, cancellable, error);
g_object_unref (real_file);
return ret;
}
res = TRUE;
if (g_file_info_has_namespace (info, "metadata"))
{
GFileAttributeType type;
gchar **attributes;
gpointer value_p;
gint i;
attributes = g_file_info_list_attributes (info, "metadata");
for (i = 0; attributes[i] != NULL; i++)
{
if (g_file_info_get_attribute_data (info, attributes[i], &type, &value_p, NULL))
{
if (!file_set_attribute (file,
attributes[i],
type,
value_p,
flags,
cancellable,
error))
{
g_file_info_set_attribute_status (info, attributes[i], G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
error = NULL; // from gvfs gdaemonvfs.c - ignore subsequent errors iterating thru attribute list.
res = FALSE;
}
else
{
g_file_info_set_attribute_status (info, attributes[i], G_FILE_ATTRIBUTE_STATUS_SET);
}
}
}
g_strfreev (attributes);
}
return res;
}
static GFileInputStream *
file_read_fn (GFile *file,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file = g_file_new_for_uri (priv->info->uri);
GFileInputStream *stream;
stream = g_file_read (real_file, cancellable, error);
g_object_unref (real_file);
return stream;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return NULL;
}
GFileOutputStream *
file_append_to (GFile *file,
GFileCreateFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file = g_file_new_for_uri (priv->info->uri);
GFileOutputStream *stream;
stream = g_file_append_to (real_file,
flags,
cancellable,
error);
g_object_unref (real_file);
return stream;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return NULL;
}
GFileOutputStream *
file_create (GFile *file,
GFileCreateFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file = g_file_new_for_uri (priv->info->uri);
GFileOutputStream *stream;
stream = g_file_create (real_file,
flags,
cancellable,
error);
g_object_unref (real_file);
return stream;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return NULL;
}
static GFileOutputStream *
file_replace (GFile *file,
const char *etag,
gboolean make_backup,
GFileCreateFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file = g_file_new_for_uri (priv->info->uri);
GFileOutputStream *stream;
stream = g_file_replace (real_file,
etag,
make_backup,
flags,
cancellable,
error);
g_object_unref (real_file);
return stream;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return NULL;
}
static GFileIOStream *
file_open_readwrite (GFile *file,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFileIOStream *res;
GFile *real_file = g_file_new_for_uri (priv->info->uri);
res = g_file_open_readwrite (real_file,
cancellable,
error);
g_object_unref (real_file);
return res;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return NULL;
}
static GFileIOStream *
file_create_readwrite (GFile *file,
GFileCreateFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFileIOStream *res;
GFile *real_file = g_file_new_for_uri (priv->info->uri);
res = g_file_create_readwrite (real_file,
flags,
cancellable,
error);
g_object_unref (real_file);
return res;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return NULL;
}
static GFileIOStream *
file_replace_readwrite (GFile *file,
const char *etag,
gboolean make_backup,
GFileCreateFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFileIOStream *res;
GFile *real_file = g_file_new_for_uri (priv->info->uri);
res = g_file_replace_readwrite (real_file,
etag,
make_backup,
flags,
cancellable,
error);
g_object_unref (real_file);
return res;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return NULL;
}
static gboolean
file_delete (GFile *file,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
gboolean res;
GFile *real_file = g_file_new_for_uri (priv->info->uri);
res = g_file_delete (real_file,
cancellable,
error);
g_object_unref (real_file);
return res;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return FALSE;
}
static gboolean
file_trash (GFile *file,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
gboolean res;
GFile *real_file = g_file_new_for_uri (priv->info->uri);
res = g_file_trash (real_file,
cancellable,
error);
g_object_unref (real_file);
return res;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Not supported");
return FALSE;
}
gboolean
file_move (GFile *source,
GFile *destination,
GFileCopyFlags flags,
GCancellable *cancellable,
GFileProgressCallback progress_callback,
gpointer progress_callback_data,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (source));
if (priv->info != NULL && priv->info->uri != NULL)
{
gboolean res;
GFile *real_file = g_file_new_for_uri (priv->info->uri);
res = g_file_move (real_file,
destination,
flags,
cancellable,
progress_callback,
progress_callback_data,
error);
g_object_unref (real_file);
return res;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return FALSE;
}
static GFileMonitor *
file_monitor_dir (GFile *file,
GFileMonitorFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file;
GFileMonitor *monitor;
real_file = g_file_new_for_uri (priv->info->uri);
monitor = g_file_monitor_directory (real_file,
flags,
cancellable,
error);
g_object_unref (real_file);
return monitor;
}
else
if (is_root_file (FAVORITE_VFS_FILE (file)))
{
return favorite_vfs_file_monitor_new ();
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return NULL;
}
static GFileMonitor *
file_monitor_file (GFile *file,
GFileMonitorFlags flags,
GCancellable *cancellable,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
GFile *real_file;
GFileMonitor *monitor;
real_file = g_file_new_for_uri (priv->info->uri);
monitor = g_file_monitor_file (real_file,
flags,
cancellable,
error);
g_object_unref (real_file);
return monitor;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return NULL;
}
gboolean
file_measure_disk_usage (GFile *file,
GFileMeasureFlags flags,
GCancellable *cancellable,
GFileMeasureProgressCallback progress_callback,
gpointer progress_data,
guint64 *disk_usage,
guint64 *num_dirs,
guint64 *num_files,
GError **error)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
gboolean res;
GFile *real_file = g_file_new_for_uri (priv->info->uri);
res = g_file_measure_disk_usage (real_file,
flags,
cancellable,
progress_callback,
progress_data,
disk_usage,
num_dirs,
num_files,
error);
g_object_unref (real_file);
return res;
}
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return FALSE;
}
static void favorite_vfs_file_gfile_iface_init (GFileIface *iface)
{
iface->dup = file_dup;
iface->hash = file_hash;
iface->equal = file_equal;
iface->is_native = file_is_native;
iface->has_uri_scheme = file_has_uri_scheme;
iface->get_uri_scheme = file_get_uri_scheme;
iface->get_basename = file_get_basename;
iface->get_path = file_get_path;
iface->get_uri = file_get_uri;
iface->get_parse_name = file_get_parse_name;
iface->get_parent = file_get_parent;
iface->prefix_matches = file_prefix_matches;
iface->get_relative_path = file_get_relative_path;
iface->resolve_relative_path = file_resolve_relative_path;
iface->get_child_for_display_name = file_get_child_for_display_name;
iface->set_display_name = file_set_display_name;
iface->enumerate_children = file_enumerate_children;
iface->query_info = file_query_info;
iface->query_filesystem_info = file_query_filesystem_info;
iface->find_enclosing_mount = file_find_enclosing_mount;
iface->query_settable_attributes = file_query_settable_attributes;
iface->query_writable_namespaces = file_query_writable_namespaces;
iface->set_attribute = file_set_attribute;
iface->set_attributes_from_info = file_set_attributes_from_info;
iface->read_fn = file_read_fn;
iface->append_to = file_append_to;
iface->create = file_create;
iface->replace = file_replace;
iface->open_readwrite = file_open_readwrite;
iface->create_readwrite = file_create_readwrite;
iface->replace_readwrite = file_replace_readwrite;
iface->delete_file = file_delete;
iface->trash = file_trash;
// iface->make_directory = file_make_directory; ### Don't support
// iface->make_symbolic_link = file_make_symbolic_link; ### Don't support
iface->move = file_move;
iface->monitor_dir = file_monitor_dir;
iface->monitor_file = file_monitor_file;
iface->measure_disk_usage = file_measure_disk_usage;
iface->supports_thread_contexts = TRUE;
}
static void favorite_vfs_file_dispose (GObject *object)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (object));
if (priv->info != NULL)
{
xapp_favorite_info_free (priv->info);
priv->info = NULL;
}
g_clear_pointer (&priv->uri, g_free);
G_OBJECT_CLASS (favorite_vfs_file_parent_class)->dispose (object);
}
static void
ensure_metadata_store (FavoriteVfsFile *file)
{
if (is_root_file (file))
{
if (settings == NULL)
{
settings = g_settings_new (FAVORITES_SCHEMA);
g_object_add_weak_pointer (G_OBJECT (settings), (gpointer) &settings);
}
else
{
g_object_ref (settings);
}
}
}
static void favorite_vfs_file_class_init (FavoriteVfsFileClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = favorite_vfs_file_dispose;
}
static void favorite_vfs_file_init (FavoriteVfsFile *self)
{
}
GFile *_favorite_vfs_file_new_for_info (XAppFavoriteInfo *info)
{
FavoriteVfsFile *new_file;
new_file = g_object_new (FAVORITE_TYPE_VFS_FILE, NULL);
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (new_file));
priv->uri = path_to_fav_uri (info->display_name);
priv->info = xapp_favorite_info_copy (info);
ensure_metadata_store (new_file);
return G_FILE (new_file);
}
gchar *favorite_vfs_file_get_real_uri (GFile *file)
{
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
if (priv->info != NULL && priv->info->uri != NULL)
{
return g_strdup (priv->info->uri);
}
return NULL;
}
GFile *favorite_vfs_file_new_for_uri (const char *uri)
{
FavoriteVfsFile *new_file;
g_autofree gchar *basename = NULL;
new_file = g_object_new (FAVORITE_TYPE_VFS_FILE, NULL);
g_debug ("FavoriteVfsFile new for uri: %s", uri);
FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (new_file));
priv->uri = g_strdup (uri);
ensure_metadata_store (new_file);
if (g_strcmp0 (uri, ROOT_URI) == 0)
{
priv->info = NULL;
}
else
{
gchar *display_name;
display_name = fav_uri_to_display_name (uri);
XAppFavoriteInfo *info = xapp_favorites_find_by_display_name (xapp_favorites_get_default (),
display_name);
if (info != NULL)
{
priv->info = xapp_favorite_info_copy (info);
}
else
{
info = g_slice_new0 (XAppFavoriteInfo);
info->uri = g_strdup (NULL);
info->display_name = g_strdup (display_name);
info->cached_mimetype = NULL;
priv->info = info;
}
g_free (display_name);
}
return G_FILE (new_file);
}
GFile *favorite_vfs_file_new (void)
{
return favorite_vfs_file_new_for_uri (ROOT_URI);
}
static GFile *
favorite_vfs_lookup (GVfs *vfs,
const char *identifier,
gpointer user_data)
{
if (g_str_has_prefix (identifier, ROOT_URI))
{
return favorite_vfs_file_new_for_uri (identifier);
}
return NULL;
}
void
init_favorite_vfs (void)
{
GVfs *vfs;
vfs = g_vfs_get_default ();
g_vfs_register_uri_scheme (vfs, "favorites",
favorite_vfs_lookup, NULL, NULL,
favorite_vfs_lookup, NULL, NULL);
}