1 #include <config.h>
2 #include <glib/gi18n-lib.h>
3
4 #include "favorite-vfs-file.h"
5 #include "favorite-vfs-file-enumerator.h"
6 #include "favorite-vfs-file-monitor.h"
7
8 #define DEBUG_FLAG XAPP_DEBUG_FAVORITE_VFS
9 #include "xapp-debug.h"
10
11 #define FAVORITES_SCHEMA "org.x.apps.favorites"
12 #define FAVORITE_DCONF_METADATA_KEY "root-metadata"
13
14 static GSettings *settings = NULL;
15
16 typedef struct
17 {
18 gchar *uri; // favorites://foo
19
20 XAppFavoriteInfo *info;
21 } FavoriteVfsFilePrivate;
22
23 struct _FavoriteVfsFile
24 {
25 GObject parent_instance;
26 FavoriteVfsFilePrivate *priv;
27 };
28
29 GList *_xapp_favorites_get_display_names (XAppFavorites *favorites);
30 static void favorite_vfs_file_gfile_iface_init (GFileIface *iface);
31
32 gchar *
path_to_fav_uri(const gchar * path)33 path_to_fav_uri (const gchar *path)
34 {
35 g_return_val_if_fail (path != NULL, NULL);
36
37 return g_strconcat (ROOT_URI, path, NULL);
38 }
39
40 gchar *
fav_uri_to_display_name(const gchar * uri)41 fav_uri_to_display_name (const gchar *uri)
42 {
43 g_return_val_if_fail (uri != NULL, NULL);
44 g_return_val_if_fail (g_str_has_prefix (uri, ROOT_URI), NULL);
45
46 const gchar *ptr;
47
48 ptr = uri + strlen (ROOT_URI);
49
50 if (ptr[0] == '/')
51 {
52 ptr++;
53 }
54
55 return g_strdup (ptr);
56 }
57
58 G_DEFINE_TYPE_EXTENDED (FavoriteVfsFile,
59 favorite_vfs_file,
60 G_TYPE_OBJECT,
61 0,
62 G_ADD_PRIVATE (FavoriteVfsFile)
63 G_IMPLEMENT_INTERFACE (G_TYPE_FILE, favorite_vfs_file_gfile_iface_init))
64
65 static gboolean
is_root_file(FavoriteVfsFile * file)66 is_root_file (FavoriteVfsFile *file)
67 {
68 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (file);
69
70 return g_strcmp0 (priv->uri, ROOT_URI) == 0;
71 }
72
73 static GFile *
file_dup(GFile * file)74 file_dup (GFile *file)
75 {
76 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
77
78 return favorite_vfs_file_new_for_uri (priv->uri);
79 }
80
81 static guint
file_hash(GFile * file)82 file_hash (GFile *file)
83 {
84 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
85
86 return g_str_hash (priv->uri);
87 }
88
89 static gboolean
file_equal(GFile * file1,GFile * file2)90 file_equal (GFile *file1,
91 GFile *file2)
92 {
93 FavoriteVfsFilePrivate *priv1 = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file1));
94 FavoriteVfsFilePrivate *priv2 = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file2));
95
96 return g_strcmp0 (priv1->uri, priv2->uri) == 0;
97 }
98
99 static gboolean
file_is_native(GFile * file)100 file_is_native (GFile *file)
101 {
102 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
103
104 if (priv->info != NULL && priv->info->uri != NULL)
105 {
106 GFile *real_file;
107 gboolean is_really_native;
108
109 real_file = g_file_new_for_uri (priv->info->uri);
110 is_really_native = g_file_is_native (real_file);
111
112 g_object_unref (real_file);
113 return is_really_native;
114 }
115
116 return FALSE;
117 }
118
119 static gboolean
file_has_uri_scheme(GFile * file,const gchar * uri_scheme)120 file_has_uri_scheme (GFile *file,
121 const gchar *uri_scheme)
122 {
123 return g_strcmp0 (uri_scheme, URI_SCHEME) == 0;
124 }
125
126 static gchar *
file_get_uri_scheme(GFile * file)127 file_get_uri_scheme (GFile *file)
128 {
129 return g_strdup (URI_SCHEME);
130 }
131
132 static gchar *
file_get_basename(GFile * file)133 file_get_basename (GFile *file)
134 {
135 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
136
137 if (priv->info == NULL)
138 {
139 return g_strdup ("/");
140 }
141
142 return g_strdup (priv->info->display_name);
143 }
144
145 static gchar *
file_get_path(GFile * file)146 file_get_path (GFile *file)
147 {
148 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
149
150 if (file_is_native (file))
151 {
152 GFile *real_file;
153 gchar *ret;
154
155 real_file = g_file_new_for_uri (priv->info->uri);
156
157 // file can't be native without an info, so we don't need to check for null here
158 ret = g_file_get_path (real_file);
159 g_object_unref (real_file);
160
161 return ret;
162 }
163
164 // GtkFileChooser checks for a path (and not null) before allowing a shortcut to
165 // be added using gtk_file_chooser_add_shortcut_folder_uri(). Even though this / doesn't
166 // make much sense for favorites:/// it allows it to be added to the file chooser without
167 // being forced to override its 'local-only' property.
168 if (is_root_file (FAVORITE_VFS_FILE (file)))
169 {
170 return g_strdup ("/");
171 }
172
173 return NULL;
174 }
175
176 static gchar *
file_get_uri(GFile * file)177 file_get_uri (GFile *file)
178 {
179 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
180
181 return g_strdup (priv->uri);
182 }
183
184 static gchar *
file_get_parse_name(GFile * file)185 file_get_parse_name (GFile *file)
186 {
187 return file_get_uri (file);
188 }
189
190 static GFile *
file_get_parent(GFile * file)191 file_get_parent (GFile *file)
192 {
193 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
194
195 // We're only ever one level deep.
196 if (priv->info != NULL)
197 {
198 return g_file_new_for_uri (ROOT_URI);
199 }
200
201 return NULL;
202 }
203
204 static gboolean
file_prefix_matches(GFile * parent,GFile * descendant)205 file_prefix_matches (GFile *parent,
206 GFile *descendant)
207 {
208 g_autofree gchar *puri = NULL;
209 g_autofree gchar *duri = NULL;
210 gchar *ptr = NULL;
211
212 puri = g_file_get_uri (parent);
213 duri = g_file_get_uri (descendant);
214
215 ptr = g_strstr_len (puri, -1, duri);
216
217 if ((ptr == puri) && ptr[strlen (duri) + 1] == '/')
218 {
219 return TRUE;
220 }
221
222 return FALSE;
223 }
224
225 static gchar *
file_get_relative_path(GFile * parent,GFile * descendant)226 file_get_relative_path (GFile *parent,
227 GFile *descendant)
228 {
229 g_autofree gchar *puri = NULL;
230 g_autofree gchar *duri = NULL;
231 g_autofree gchar *rpath = NULL;
232 gchar *ptr = NULL;
233
234 puri = g_file_get_uri (parent);
235 duri = g_file_get_uri (descendant);
236
237 ptr = g_strstr_len (puri, -1, duri);
238
239 if ((ptr == puri) && ptr[strlen (duri) + 1] == '/')
240 {
241 rpath = g_strdup (puri + strlen (duri) + 1);
242
243 return rpath;
244 }
245
246 return NULL;
247 }
248
249 static GFile *
file_resolve_relative_path(GFile * file,const gchar * relative_path)250 file_resolve_relative_path (GFile *file,
251 const gchar *relative_path)
252 {
253 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
254 GFile *relative_file;
255 gchar *uri;
256
257 if (g_path_is_absolute (relative_path))
258 {
259 return g_file_new_for_path (relative_path);
260 }
261
262 if (priv->info != NULL && priv->info->uri != NULL)
263 {
264 GFile *real_file;
265 real_file = g_file_new_for_uri (priv->info->uri);
266
267 relative_file = g_file_resolve_relative_path (real_file,
268 relative_path);
269
270 g_object_unref (real_file);
271 return relative_file;
272 }
273
274 if (g_strcmp0 (relative_path, ".") == 0)
275 {
276 relative_file = file_dup (file);
277
278 return relative_file;
279 }
280
281 uri = path_to_fav_uri (relative_path);
282
283 relative_file = g_file_new_for_uri (uri);
284 g_free (uri);
285
286 return relative_file;
287 }
288
289 static GFile *
file_get_child_for_display_name(GFile * file,const char * display_name,GError ** error)290 file_get_child_for_display_name (GFile *file,
291 const char *display_name,
292 GError **error)
293 {
294 return g_file_get_child (file, display_name);
295 }
296
297 static GFile *
file_set_display_name(GFile * file,const gchar * display_name,GCancellable * cancellable,GError ** error)298 file_set_display_name (GFile *file,
299 const gchar *display_name,
300 GCancellable *cancellable,
301 GError **error)
302 {
303 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
304
305 if (priv->info != NULL && priv->info->uri != NULL)
306 {
307 GFile *real_file;
308 GFile *ret;
309
310 real_file = g_file_new_for_uri (priv->info->uri);
311 ret = g_file_set_display_name (real_file,
312 display_name,
313 cancellable,
314 error);
315 g_object_unref (real_file);
316
317 return ret;
318 }
319
320 g_set_error_literal (error, G_IO_ERROR,
321 G_IO_ERROR_NOT_SUPPORTED,
322 "Can't rename file");
323
324 return NULL;
325 }
326
327 static GFileEnumerator *
file_enumerate_children(GFile * file,const char * attributes,GFileQueryInfoFlags flags,GCancellable * cancellable,GError ** error)328 file_enumerate_children(GFile *file,
329 const char *attributes,
330 GFileQueryInfoFlags flags,
331 GCancellable *cancellable,
332 GError **error)
333 {
334 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
335 GFileEnumerator *enumerator;
336
337 if (priv->info != NULL && priv->info->uri != NULL)
338 {
339 GFile *real_file;
340 real_file = g_file_new_for_uri (priv->info->uri);
341
342 enumerator = g_file_enumerate_children (real_file,
343 attributes,
344 flags,
345 cancellable,
346 error);
347
348 g_object_unref (real_file);
349 return enumerator;
350 }
351
352 GList *uris;
353
354 uris = _xapp_favorites_get_display_names (xapp_favorites_get_default ());
355 enumerator = favorite_vfs_file_enumerator_new (file,
356 attributes,
357 flags,
358 uris);
359
360 g_list_free (uris);
361
362 return enumerator;
363 }
364
365 static GFileInfo *
file_query_info(GFile * file,const char * attributes,GFileQueryInfoFlags flags,GCancellable * cancellable,GError ** error)366 file_query_info (GFile *file,
367 const char *attributes,
368 GFileQueryInfoFlags flags,
369 GCancellable *cancellable,
370 GError **error)
371 {
372 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
373 GFileInfo *info;
374 GIcon *icon;
375
376 info = NULL;
377
378 if (priv->info != NULL)
379 {
380 if (!priv->info->uri)
381 {
382 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "File not found");
383 return NULL;
384 }
385
386 GFile *real_file = g_file_new_for_uri (priv->info->uri);
387
388 info = g_file_query_info (real_file, attributes, flags, cancellable, error);
389
390 if (info != NULL)
391 {
392 gchar *local_path;
393
394 g_file_info_set_display_name (info, priv->info->display_name);
395 g_file_info_set_name (info, priv->info->display_name);
396 g_file_info_set_is_symlink (info, TRUE);
397
398 local_path = g_file_get_path (real_file);
399
400 if (local_path != NULL)
401 {
402 g_file_info_set_symlink_target (info, local_path);
403 g_free (local_path);
404 }
405 else
406 {
407 g_file_info_set_symlink_target (info, priv->info->uri);
408 }
409
410 // Recent sets this also. If it's set, this uri is used to display the "location"
411 // for the file (the directory in which real file resides).
412 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, priv->info->uri);
413
414 g_file_info_set_attribute_string (info, FAVORITE_AVAILABLE_METADATA_KEY, META_TRUE);
415 }
416 else
417 {
418 // This file is still in our favorites list but doesn't exist (currently).
419 g_clear_error (error);
420 gchar *content_type;
421
422 info = g_file_info_new ();
423
424 g_file_info_set_display_name (info, priv->info->display_name);
425 g_file_info_set_name (info, priv->info->display_name);
426 g_file_info_set_file_type (info, G_FILE_TYPE_SYMBOLIC_LINK);
427 g_file_info_set_is_symlink (info, TRUE);
428 g_file_info_set_symlink_target (info, priv->info->uri);
429 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, priv->info->uri);
430
431 /* Prevent showing a 'thumbnailing' icon */
432 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED, TRUE);
433
434 /* This will keep the sort position the same for missing or unmounted files */
435 g_file_info_set_attribute_string (info, FAVORITE_METADATA_KEY, META_TRUE);
436 g_file_info_set_attribute_string (info, FAVORITE_AVAILABLE_METADATA_KEY, META_FALSE);
437
438 content_type = g_content_type_from_mime_type (priv->info->cached_mimetype);
439
440 icon = g_content_type_get_icon (content_type);
441 g_file_info_set_icon (info, icon);
442 g_object_unref (icon);
443
444 icon = g_content_type_get_symbolic_icon (content_type);
445 g_file_info_set_symbolic_icon (info, icon);
446 g_object_unref (icon);
447
448 g_free (content_type);
449 }
450
451 g_object_unref (real_file);
452
453 return info;
454 }
455
456 if (is_root_file (FAVORITE_VFS_FILE (file)))
457 {
458 GFileAttributeMatcher *matcher = g_file_attribute_matcher_new (attributes);
459
460 info = g_file_info_new ();
461
462 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_NAME))
463 g_file_info_set_name (info, "/");
464
465 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME))
466 g_file_info_set_display_name (info, _("Favorites"));
467
468 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_TYPE))
469 g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
470
471 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_ICON))
472 {
473 icon = g_themed_icon_new ("xapp-user-favorites");
474 g_file_info_set_icon (info, icon);
475
476 g_object_unref (icon);
477 }
478
479 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON))
480 {
481 icon = g_themed_icon_new ("xapp-user-favorites-symbolic");
482 g_file_info_set_symbolic_icon (info, icon);
483 g_object_unref (icon);
484 }
485
486 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_GVFS_BACKEND))
487 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_GVFS_BACKEND, "favorites");
488
489 if (g_file_attribute_matcher_matches (matcher, FAVORITE_AVAILABLE_METADATA_KEY))
490 g_file_info_set_attribute_string (info, FAVORITE_AVAILABLE_METADATA_KEY, META_TRUE);
491
492 if (g_file_attribute_matcher_enumerate_namespace (matcher, "metadata"))
493 {
494 gchar **entries = g_settings_get_strv (settings, FAVORITE_DCONF_METADATA_KEY);
495
496 if (entries != NULL)
497 {
498 gint i;
499
500 for (i = 0; entries[i] != NULL; i++)
501 {
502 gchar **t_n_v;
503
504 t_n_v = g_strsplit (entries[i], "==", 3);
505
506 if (g_strv_length (t_n_v) == 3)
507 {
508 if (g_strcmp0 (t_n_v[0], "string") == 0)
509 {
510 g_file_info_set_attribute_string (info, t_n_v[1], t_n_v[2]);
511 }
512 else
513 if (g_strcmp0 (t_n_v[0], "strv") == 0)
514 {
515 gchar **members = g_strsplit (t_n_v[2], "|", -1);
516
517 g_file_info_set_attribute_stringv (info, t_n_v[1], members);
518
519 g_strfreev (members);
520 }
521 }
522
523 g_strfreev (t_n_v);
524 }
525 }
526
527 g_strfreev (entries);
528 }
529
530 g_file_attribute_matcher_unref (matcher);
531 }
532 else
533 {
534 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't retrieve info for favorite file");
535 }
536
537 return info;
538 }
539
540 GFileInfo *
file_query_filesystem_info(GFile * file,const char * attributes,GCancellable * cancellable,GError ** error)541 file_query_filesystem_info (GFile *file,
542 const char *attributes,
543 GCancellable *cancellable,
544 GError **error)
545 {
546 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
547 GFileInfo *info;
548 GFileAttributeMatcher *matcher;
549
550 matcher = g_file_attribute_matcher_new (attributes);
551
552 if (priv->info != NULL && priv->info->uri != NULL)
553 {
554 GFileInfo *info;
555 GFile *real_file;
556 real_file = g_file_new_for_uri (priv->info->uri);
557
558 info = g_file_query_filesystem_info (real_file,
559 attributes,
560 cancellable,
561 error);
562
563 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
564 {
565 g_file_info_set_attribute_boolean (info,
566 G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
567 }
568
569 g_object_unref (real_file);
570 return info;
571 }
572
573 info = g_file_info_new ();
574
575 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE))
576 {
577 g_file_info_set_attribute_string (info,
578 G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "favorites");
579 }
580
581 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
582 {
583 g_file_info_set_attribute_boolean (info,
584 G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
585 }
586
587 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW))
588 {
589 g_file_info_set_attribute_uint32 (info,
590 G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW,
591 G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL);
592 }
593
594 g_file_attribute_matcher_unref (matcher);
595
596 return info;
597 }
598
599 GMount *
file_find_enclosing_mount(GFile * file,GCancellable * cancellable,GError ** error)600 file_find_enclosing_mount (GFile *file,
601 GCancellable *cancellable,
602 GError **error)
603 {
604 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
605
606 if (priv->info != NULL && priv->info->uri != NULL)
607 {
608 GMount *mount;
609 GFile *real_file;
610 real_file = g_file_new_for_uri (priv->info->uri);
611
612 mount = g_file_find_enclosing_mount (real_file,
613 cancellable,
614 error);
615
616 g_object_unref (real_file);
617 return mount;
618 }
619
620 g_set_error_literal (error, G_IO_ERROR,
621 G_IO_ERROR_NOT_SUPPORTED,
622 "Can't find favorite file enclosing mount");
623
624 return NULL;
625 }
626
627 GFileAttributeInfoList *
file_query_settable_attributes(GFile * file,GCancellable * cancellable,GError ** error)628 file_query_settable_attributes (GFile *file,
629 GCancellable *cancellable,
630 GError **error)
631 {
632 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
633
634 if (priv->info != NULL && priv->info->uri != NULL)
635 {
636 GFileAttributeInfoList *list;
637 GFile *real_file;
638 real_file = g_file_new_for_uri (priv->info->uri);
639
640 list = g_file_query_settable_attributes (real_file,
641 cancellable,
642 error);
643
644 g_object_unref (real_file);
645 return list;
646 }
647
648 return g_file_attribute_info_list_new ();
649 }
650
651 GFileAttributeInfoList *
file_query_writable_namespaces(GFile * file,GCancellable * cancellable,GError ** error)652 file_query_writable_namespaces (GFile *file,
653 GCancellable *cancellable,
654 GError **error)
655 {
656 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
657 GFileAttributeInfoList *list;
658
659 if (priv->info != NULL && priv->info->uri != NULL)
660 {
661 GFile *real_file;
662 real_file = g_file_new_for_uri (priv->info->uri);
663
664 list = g_file_query_writable_namespaces (real_file,
665 cancellable,
666 error);
667
668 g_object_unref (real_file);
669 return list;
670 }
671
672 list = g_file_attribute_info_list_new ();
673
674 g_file_attribute_info_list_add (list,
675 "metadata",
676 G_FILE_ATTRIBUTE_TYPE_STRING,
677 G_FILE_ATTRIBUTE_INFO_NONE);
678
679 return list;
680 }
681
682 static void
remove_root_metadata(const gchar * attr_name)683 remove_root_metadata (const gchar *attr_name)
684 {
685 GPtrArray *new_array;
686 gchar **old_metadata, **new_metadata;
687 gint i;
688
689 old_metadata = g_settings_get_strv (settings, FAVORITE_DCONF_METADATA_KEY);
690
691 if (old_metadata == NULL)
692 {
693 return;
694 }
695
696 new_array = g_ptr_array_new ();
697
698 for (i = 0; old_metadata[i] != NULL; i++)
699 {
700 gchar **t_n_v;
701
702 t_n_v = g_strsplit (old_metadata[i], "==", 3);
703
704 if (g_strcmp0 (t_n_v[1], attr_name) != 0)
705 {
706 g_ptr_array_add (new_array, g_strdup (old_metadata[i]));
707 }
708
709 g_strfreev (t_n_v);
710 }
711
712 g_ptr_array_add (new_array, NULL);
713 g_strfreev (old_metadata);
714
715 new_metadata = (gchar **) g_ptr_array_free (new_array, FALSE);
716
717 g_settings_set_strv (settings, FAVORITE_DCONF_METADATA_KEY, (const gchar * const *) new_metadata);
718 g_strfreev (new_metadata);
719 }
720
721 static void
set_or_update_root_metadata(const gchar * attr_name,const gpointer value,GFileAttributeType type)722 set_or_update_root_metadata (const gchar *attr_name,
723 const gpointer value,
724 GFileAttributeType type)
725 {
726 GPtrArray *new_array;
727 gchar **old_metadata, **new_metadata;
728 gint i;
729 gchar *entry;
730 gboolean exists;
731
732 old_metadata = g_settings_get_strv (settings, FAVORITE_DCONF_METADATA_KEY);
733
734 if (old_metadata == NULL)
735 {
736 return;
737 }
738
739 switch (type)
740 {
741 case G_FILE_ATTRIBUTE_TYPE_STRING:
742 {
743 entry = g_strdup_printf ("string==%s==%s", attr_name, (gchar *) value);
744 break;
745 }
746 case G_FILE_ATTRIBUTE_TYPE_STRINGV:
747 {
748 gchar *val_strv = g_strjoinv ("|", (gchar **) value);
749 entry = g_strdup_printf ("strv==%s==%s", attr_name, val_strv);
750 g_free (val_strv);
751 break;
752 }
753 default:
754 g_warn_if_reached ();
755 g_strfreev (old_metadata);
756 return;
757 }
758
759 exists = FALSE;
760 new_array = g_ptr_array_new ();
761
762 for (i = 0; old_metadata[i] != NULL; i++)
763 {
764 gchar **t_n_v;
765
766 t_n_v = g_strsplit (old_metadata[i], "==", 3);
767
768 if (g_strcmp0 (t_n_v[1], attr_name) == 0)
769 {
770 g_ptr_array_add (new_array, entry);
771 exists = TRUE;
772 }
773 else
774 {
775 g_ptr_array_add (new_array, g_strdup (old_metadata[i]));
776 }
777
778 g_strfreev (t_n_v);
779 }
780
781 if (!exists)
782 {
783 g_ptr_array_add (new_array, entry);
784 }
785
786 g_ptr_array_add (new_array, NULL);
787 g_strfreev (old_metadata);
788
789 new_metadata = (gchar **) g_ptr_array_free (new_array, FALSE);
790
791 g_settings_set_strv (settings, FAVORITE_DCONF_METADATA_KEY, (const gchar * const *) new_metadata);
792 g_strfreev (new_metadata);
793 }
794
795 gboolean
file_set_attribute(GFile * file,const gchar * attribute,GFileAttributeType type,gpointer value_p,GFileQueryInfoFlags flags,GCancellable * cancellable,GError ** error)796 file_set_attribute (GFile *file,
797 const gchar *attribute,
798 GFileAttributeType type,
799 gpointer value_p,
800 GFileQueryInfoFlags flags,
801 GCancellable *cancellable,
802 GError **error)
803 {
804 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
805 gboolean ret;
806
807 if (priv->info != NULL && priv->info->uri != NULL)
808 {
809 GFile *real_file;
810 gboolean ret;
811 real_file = g_file_new_for_uri (priv->info->uri);
812
813 ret = g_file_set_attribute (real_file,
814 attribute,
815 type,
816 value_p,
817 flags,
818 cancellable,
819 error);
820
821 g_object_unref (real_file);
822 return ret;
823 }
824
825 ret = FALSE;
826
827 if (!is_root_file (FAVORITE_VFS_FILE (file)))
828 {
829 g_set_error (error, G_IO_ERROR,
830 G_IO_ERROR_NOT_SUPPORTED,
831 "Can't set attributes for %s - only the root (favorites:///) is supported.", priv->uri);
832 }
833 else
834 {
835 if (g_str_has_prefix (attribute, "metadata"))
836 {
837 if (type == G_FILE_ATTRIBUTE_TYPE_INVALID || value_p == NULL || ((char *) value_p)[0] == '\0')
838 {
839 // unset metadata
840 remove_root_metadata (attribute);
841 ret = TRUE;
842 }
843 else
844 {
845 if (type == G_FILE_ATTRIBUTE_TYPE_STRING || type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
846 {
847 set_or_update_root_metadata (attribute, (gchar *) value_p, type);
848 ret = TRUE;
849 }
850 else
851 {
852 g_set_error (error, G_IO_ERROR,
853 G_IO_ERROR_NOT_SUPPORTED,
854 "Can't set attribute '%s' for favorites:/// file "
855 "(only string-type metadata are allowed).", attribute);
856 }
857 }
858 }
859 else
860 {
861 g_set_error (error, G_IO_ERROR,
862 G_IO_ERROR_NOT_SUPPORTED,
863 "Can't set attribute '%s' for favorites:/// file "
864 "(only 'metadata' namespace is allowed).", attribute);
865 }
866 }
867
868 return ret;
869 }
870
871 static gboolean
file_set_attributes_from_info(GFile * file,GFileInfo * info,GFileQueryInfoFlags flags,GCancellable * cancellable,GError ** error)872 file_set_attributes_from_info (GFile *file,
873 GFileInfo *info,
874 GFileQueryInfoFlags flags,
875 GCancellable *cancellable,
876 GError **error)
877 {
878 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
879 gboolean res;
880
881 if (priv->info != NULL && priv->info->uri != NULL)
882 {
883 GFile *real_file;
884 gboolean ret = FALSE;
885 real_file = g_file_new_for_uri (priv->info->uri);
886
887 ret = g_file_set_attributes_from_info (real_file, info, flags, cancellable, error);
888
889 g_object_unref (real_file);
890 return ret;
891 }
892
893 res = TRUE;
894
895 if (g_file_info_has_namespace (info, "metadata"))
896 {
897 GFileAttributeType type;
898 gchar **attributes;
899 gpointer value_p;
900 gint i;
901
902 attributes = g_file_info_list_attributes (info, "metadata");
903
904 for (i = 0; attributes[i] != NULL; i++)
905 {
906 if (g_file_info_get_attribute_data (info, attributes[i], &type, &value_p, NULL))
907 {
908 if (!file_set_attribute (file,
909 attributes[i],
910 type,
911 value_p,
912 flags,
913 cancellable,
914 error))
915 {
916 g_file_info_set_attribute_status (info, attributes[i], G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
917 error = NULL; // from gvfs gdaemonvfs.c - ignore subsequent errors iterating thru attribute list.
918 res = FALSE;
919 }
920 else
921 {
922 g_file_info_set_attribute_status (info, attributes[i], G_FILE_ATTRIBUTE_STATUS_SET);
923 }
924 }
925 }
926
927 g_strfreev (attributes);
928 }
929
930 return res;
931 }
932
933 static GFileInputStream *
file_read_fn(GFile * file,GCancellable * cancellable,GError ** error)934 file_read_fn (GFile *file,
935 GCancellable *cancellable,
936 GError **error)
937 {
938 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
939
940 if (priv->info != NULL && priv->info->uri != NULL)
941 {
942 GFile *real_file = g_file_new_for_uri (priv->info->uri);
943
944 GFileInputStream *stream;
945
946 stream = g_file_read (real_file, cancellable, error);
947
948 g_object_unref (real_file);
949 return stream;
950 }
951
952 g_set_error_literal (error, G_IO_ERROR,
953 G_IO_ERROR_NOT_SUPPORTED,
954 _("Operation not supported"));
955
956 return NULL;
957 }
958
959 GFileOutputStream *
file_append_to(GFile * file,GFileCreateFlags flags,GCancellable * cancellable,GError ** error)960 file_append_to (GFile *file,
961 GFileCreateFlags flags,
962 GCancellable *cancellable,
963 GError **error)
964 {
965 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
966
967 if (priv->info != NULL && priv->info->uri != NULL)
968 {
969 GFile *real_file = g_file_new_for_uri (priv->info->uri);
970
971 GFileOutputStream *stream;
972
973 stream = g_file_append_to (real_file,
974 flags,
975 cancellable,
976 error);
977
978 g_object_unref (real_file);
979 return stream;
980 }
981
982 g_set_error_literal (error, G_IO_ERROR,
983 G_IO_ERROR_NOT_SUPPORTED,
984 _("Operation not supported"));
985 return NULL;
986 }
987
988 static GFileOutputStream *
file_replace(GFile * file,const char * etag,gboolean make_backup,GFileCreateFlags flags,GCancellable * cancellable,GError ** error)989 file_replace (GFile *file,
990 const char *etag,
991 gboolean make_backup,
992 GFileCreateFlags flags,
993 GCancellable *cancellable,
994 GError **error)
995 {
996 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
997
998 if (priv->info != NULL && priv->info->uri != NULL)
999 {
1000 GFile *real_file = g_file_new_for_uri (priv->info->uri);
1001
1002 GFileOutputStream *stream;
1003
1004 stream = g_file_replace (real_file,
1005 etag,
1006 make_backup,
1007 flags,
1008 cancellable,
1009 error);
1010
1011 g_object_unref (real_file);
1012 return stream;
1013 }
1014
1015 g_set_error_literal (error, G_IO_ERROR,
1016 G_IO_ERROR_NOT_SUPPORTED,
1017 _("Operation not supported"));
1018
1019 return NULL;
1020 }
1021
1022 static GFileIOStream *
file_open_readwrite(GFile * file,GCancellable * cancellable,GError ** error)1023 file_open_readwrite (GFile *file,
1024 GCancellable *cancellable,
1025 GError **error)
1026 {
1027 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
1028
1029 if (priv->info != NULL && priv->info->uri != NULL)
1030 {
1031 GFileIOStream *res;
1032 GFile *real_file = g_file_new_for_uri (priv->info->uri);
1033
1034 res = g_file_open_readwrite (real_file,
1035 cancellable,
1036 error);
1037
1038 g_object_unref (real_file);
1039 return res;
1040 }
1041
1042 g_set_error_literal (error, G_IO_ERROR,
1043 G_IO_ERROR_NOT_SUPPORTED,
1044 _("Operation not supported"));
1045
1046 return NULL;
1047 }
1048
1049 static GFileIOStream *
file_replace_readwrite(GFile * file,const char * etag,gboolean make_backup,GFileCreateFlags flags,GCancellable * cancellable,GError ** error)1050 file_replace_readwrite (GFile *file,
1051 const char *etag,
1052 gboolean make_backup,
1053 GFileCreateFlags flags,
1054 GCancellable *cancellable,
1055 GError **error)
1056 {
1057 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
1058
1059 if (priv->info != NULL && priv->info->uri != NULL)
1060 {
1061 GFileIOStream *res;
1062 GFile *real_file = g_file_new_for_uri (priv->info->uri);
1063
1064 res = g_file_replace_readwrite (real_file,
1065 etag,
1066 make_backup,
1067 flags,
1068 cancellable,
1069 error);
1070
1071 g_object_unref (real_file);
1072 return res;
1073 }
1074
1075 g_set_error_literal (error, G_IO_ERROR,
1076 G_IO_ERROR_NOT_SUPPORTED,
1077 _("Operation not supported"));
1078
1079 return NULL;
1080 }
1081
1082 static gboolean
file_delete(GFile * file,GCancellable * cancellable,GError ** error)1083 file_delete (GFile *file,
1084 GCancellable *cancellable,
1085 GError **error)
1086 {
1087 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
1088
1089 if (!is_root_file (FAVORITE_VFS_FILE (file)))
1090 {
1091 if (priv->info != NULL && priv->info->uri != NULL)
1092 {
1093 xapp_favorites_remove (xapp_favorites_get_default (), priv->info->uri);
1094 }
1095 else
1096 {
1097 xapp_favorites_remove (xapp_favorites_get_default (), priv->uri);
1098 }
1099
1100 return TRUE;
1101 }
1102
1103 g_set_error_literal (error, G_IO_ERROR,
1104 G_IO_ERROR_NOT_SUPPORTED,
1105 _("Operation not supported"));
1106
1107 return FALSE;
1108 }
1109
1110 static gboolean
file_trash(GFile * file,GCancellable * cancellable,GError ** error)1111 file_trash (GFile *file,
1112 GCancellable *cancellable,
1113 GError **error)
1114 {
1115 return file_delete (file, cancellable, error);
1116 }
1117
1118 gboolean
file_copy(GFile * source,GFile * destination,GFileCopyFlags flags,GCancellable * cancellable,GFileProgressCallback progress_callback,gpointer progress_callback_data,GError ** error)1119 file_copy (GFile *source,
1120 GFile *destination,
1121 GFileCopyFlags flags,
1122 GCancellable *cancellable,
1123 GFileProgressCallback progress_callback,
1124 gpointer progress_callback_data,
1125 GError **error)
1126 {
1127 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (source));
1128
1129 if (priv->info != NULL && priv->info->uri != NULL)
1130 {
1131 gboolean res;
1132 GFile *real_file = g_file_new_for_uri (priv->info->uri);
1133
1134 res = g_file_copy (real_file,
1135 destination,
1136 flags,
1137 cancellable,
1138 progress_callback,
1139 progress_callback_data,
1140 error);
1141
1142 g_object_unref (real_file);
1143 return res;
1144 }
1145
1146 g_set_error_literal (error, G_IO_ERROR,
1147 G_IO_ERROR_NOT_SUPPORTED,
1148 _("Operation not supported"));
1149
1150 return FALSE;
1151 }
1152
1153 static GFileMonitor *
file_monitor_dir(GFile * file,GFileMonitorFlags flags,GCancellable * cancellable,GError ** error)1154 file_monitor_dir (GFile *file,
1155 GFileMonitorFlags flags,
1156 GCancellable *cancellable,
1157 GError **error)
1158 {
1159 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
1160
1161 if (priv->info != NULL && priv->info->uri != NULL)
1162 {
1163 GFile *real_file;
1164 GFileMonitor *monitor;
1165
1166 real_file = g_file_new_for_uri (priv->info->uri);
1167 monitor = g_file_monitor_directory (real_file,
1168 flags,
1169 cancellable,
1170 error);
1171 g_object_unref (real_file);
1172
1173 return monitor;
1174 }
1175 else
1176 if (is_root_file (FAVORITE_VFS_FILE (file)))
1177 {
1178 return favorite_vfs_file_monitor_new ();
1179 }
1180
1181 g_set_error_literal (error, G_IO_ERROR,
1182 G_IO_ERROR_NOT_SUPPORTED,
1183 _("Operation not supported"));
1184
1185 return NULL;
1186 }
1187
1188 static GFileMonitor *
file_monitor_file(GFile * file,GFileMonitorFlags flags,GCancellable * cancellable,GError ** error)1189 file_monitor_file (GFile *file,
1190 GFileMonitorFlags flags,
1191 GCancellable *cancellable,
1192 GError **error)
1193 {
1194 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
1195
1196 if (priv->info != NULL && priv->info->uri != NULL)
1197 {
1198 GFile *real_file;
1199 GFileMonitor *monitor;
1200
1201 real_file = g_file_new_for_uri (priv->info->uri);
1202 monitor = g_file_monitor_file (real_file,
1203 flags,
1204 cancellable,
1205 error);
1206 g_object_unref (real_file);
1207
1208 return monitor;
1209 }
1210
1211 g_set_error_literal (error, G_IO_ERROR,
1212 G_IO_ERROR_NOT_SUPPORTED,
1213 _("Operation not supported"));
1214
1215 return NULL;
1216 }
1217
1218 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)1219 file_measure_disk_usage (GFile *file,
1220 GFileMeasureFlags flags,
1221 GCancellable *cancellable,
1222 GFileMeasureProgressCallback progress_callback,
1223 gpointer progress_data,
1224 guint64 *disk_usage,
1225 guint64 *num_dirs,
1226 guint64 *num_files,
1227 GError **error)
1228 {
1229 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
1230
1231 if (priv->info != NULL && priv->info->uri != NULL)
1232 {
1233 gboolean res;
1234 GFile *real_file = g_file_new_for_uri (priv->info->uri);
1235
1236 res = g_file_measure_disk_usage (real_file,
1237 flags,
1238 cancellable,
1239 progress_callback,
1240 progress_data,
1241 disk_usage,
1242 num_dirs,
1243 num_files,
1244 error);
1245
1246 g_object_unref (real_file);
1247 return res;
1248 }
1249
1250 g_set_error_literal (error, G_IO_ERROR,
1251 G_IO_ERROR_NOT_SUPPORTED,
1252 _("Operation not supported"));
1253
1254 return FALSE;
1255 }
1256
favorite_vfs_file_gfile_iface_init(GFileIface * iface)1257 static void favorite_vfs_file_gfile_iface_init (GFileIface *iface)
1258 {
1259 iface->dup = file_dup;
1260 iface->hash = file_hash;
1261 iface->equal = file_equal;
1262 iface->is_native = file_is_native;
1263 iface->has_uri_scheme = file_has_uri_scheme;
1264 iface->get_uri_scheme = file_get_uri_scheme;
1265 iface->get_basename = file_get_basename;
1266 iface->get_path = file_get_path;
1267 iface->get_uri = file_get_uri;
1268 iface->get_parse_name = file_get_parse_name;
1269 iface->get_parent = file_get_parent;
1270 iface->prefix_matches = file_prefix_matches;
1271 iface->get_relative_path = file_get_relative_path;
1272 iface->resolve_relative_path = file_resolve_relative_path;
1273 iface->get_child_for_display_name = file_get_child_for_display_name;
1274 iface->set_display_name = file_set_display_name;
1275 iface->enumerate_children = file_enumerate_children;
1276 iface->query_info = file_query_info;
1277 iface->query_filesystem_info = file_query_filesystem_info;
1278 iface->find_enclosing_mount = file_find_enclosing_mount;
1279 iface->query_settable_attributes = file_query_settable_attributes;
1280 iface->query_writable_namespaces = file_query_writable_namespaces;
1281 iface->set_attribute = file_set_attribute;
1282 iface->set_attributes_from_info = file_set_attributes_from_info;
1283 iface->read_fn = file_read_fn;
1284 iface->append_to = file_append_to;
1285 // iface->create = file_create; ### Don't support
1286 iface->replace = file_replace;
1287 iface->open_readwrite = file_open_readwrite;
1288 // iface->create_readwrite = file_create_readwrite; ### Don't support
1289 iface->replace_readwrite = file_replace_readwrite;
1290 iface->delete_file = file_delete;
1291 iface->trash = file_trash;
1292 // iface->make_directory = file_make_directory; ### Don't support
1293 // iface->make_symbolic_link = file_make_symbolic_link; ### Don't support
1294 iface->copy = file_copy;
1295 iface->monitor_dir = file_monitor_dir;
1296 iface->monitor_file = file_monitor_file;
1297 iface->measure_disk_usage = file_measure_disk_usage;
1298 iface->supports_thread_contexts = TRUE;
1299 }
1300
favorite_vfs_file_dispose(GObject * object)1301 static void favorite_vfs_file_dispose (GObject *object)
1302 {
1303 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (object));
1304
1305 if (priv->info != NULL)
1306 {
1307 xapp_favorite_info_free (priv->info);
1308 priv->info = NULL;
1309 }
1310
1311 G_OBJECT_CLASS (favorite_vfs_file_parent_class)->dispose (object);
1312 }
1313
favorite_vfs_file_finalize(GObject * object)1314 static void favorite_vfs_file_finalize (GObject *object)
1315 {
1316 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (object));
1317
1318 g_clear_pointer (&priv->uri, g_free);
1319
1320 G_OBJECT_CLASS (favorite_vfs_file_parent_class)->finalize (object);
1321 }
1322
1323 static void
ensure_metadata_store(FavoriteVfsFile * file)1324 ensure_metadata_store (FavoriteVfsFile *file)
1325 {
1326 if (is_root_file (file))
1327 {
1328 if (settings == NULL)
1329 {
1330 settings = g_settings_new (FAVORITES_SCHEMA);
1331 g_object_add_weak_pointer (G_OBJECT (settings), (gpointer) &settings);
1332 }
1333 else
1334 {
1335 g_object_ref (settings);
1336 }
1337 }
1338 }
1339
favorite_vfs_file_class_init(FavoriteVfsFileClass * klass)1340 static void favorite_vfs_file_class_init (FavoriteVfsFileClass *klass)
1341 {
1342 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1343
1344 gobject_class->dispose = favorite_vfs_file_dispose;
1345 gobject_class->finalize = favorite_vfs_file_finalize;
1346 }
1347
favorite_vfs_file_init(FavoriteVfsFile * self)1348 static void favorite_vfs_file_init (FavoriteVfsFile *self)
1349 {
1350 }
1351
_favorite_vfs_file_new_for_info(XAppFavoriteInfo * info)1352 GFile *_favorite_vfs_file_new_for_info (XAppFavoriteInfo *info)
1353 {
1354 FavoriteVfsFile *new_file;
1355
1356 new_file = g_object_new (FAVORITE_TYPE_VFS_FILE, NULL);
1357
1358 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (new_file));
1359
1360 priv->uri = path_to_fav_uri (info->display_name);
1361 priv->info = xapp_favorite_info_copy (info);
1362 ensure_metadata_store (new_file);
1363
1364 return G_FILE (new_file);
1365 }
1366
favorite_vfs_file_get_real_uri(GFile * file)1367 gchar *favorite_vfs_file_get_real_uri (GFile *file)
1368 {
1369 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (file));
1370
1371 if (priv->info != NULL && priv->info->uri != NULL)
1372 {
1373 return g_strdup (priv->info->uri);
1374 }
1375
1376 return NULL;
1377 }
1378
favorite_vfs_file_new_for_uri(const char * uri)1379 GFile *favorite_vfs_file_new_for_uri (const char *uri)
1380 {
1381 FavoriteVfsFile *new_file;
1382 g_autofree gchar *basename = NULL;
1383
1384 new_file = g_object_new (FAVORITE_TYPE_VFS_FILE, NULL);
1385
1386 DEBUG ("FavoriteVfsFile new for uri: %s", uri);
1387
1388 FavoriteVfsFilePrivate *priv = favorite_vfs_file_get_instance_private (FAVORITE_VFS_FILE (new_file));
1389
1390 priv->uri = g_strdup (uri);
1391 ensure_metadata_store (new_file);
1392
1393 if (g_strcmp0 (uri, ROOT_URI) == 0)
1394 {
1395 priv->info = NULL;
1396 }
1397 else
1398 {
1399 gchar *display_name;
1400
1401 display_name = fav_uri_to_display_name (uri);
1402 XAppFavoriteInfo *info = xapp_favorites_find_by_display_name (xapp_favorites_get_default (),
1403 display_name);
1404
1405 if (info != NULL)
1406 {
1407 priv->info = xapp_favorite_info_copy (info);
1408 }
1409 else
1410 {
1411 info = g_slice_new0 (XAppFavoriteInfo);
1412 info->uri = g_strdup (NULL);
1413 info->display_name = g_strdup (display_name);
1414 info->cached_mimetype = NULL;
1415
1416 priv->info = info;
1417 }
1418
1419 g_free (display_name);
1420 }
1421
1422 return G_FILE (new_file);
1423 }
1424
favorite_vfs_file_new(void)1425 GFile *favorite_vfs_file_new (void)
1426 {
1427 return favorite_vfs_file_new_for_uri (ROOT_URI);
1428 }
1429
1430 static GFile *
favorite_vfs_lookup(GVfs * vfs,const char * identifier,gpointer user_data)1431 favorite_vfs_lookup (GVfs *vfs,
1432 const char *identifier,
1433 gpointer user_data)
1434 {
1435 if (g_str_has_prefix (identifier, ROOT_URI))
1436 {
1437 return favorite_vfs_file_new_for_uri (identifier);
1438 }
1439
1440 return NULL;
1441 }
1442
1443 void
init_favorite_vfs(void)1444 init_favorite_vfs (void)
1445 {
1446 static gsize once_init_value = 0;
1447
1448 if (g_once_init_enter (&once_init_value))
1449 {
1450 GVfs *vfs;
1451 vfs = g_vfs_get_default ();
1452
1453 g_vfs_register_uri_scheme (vfs, "favorites",
1454 favorite_vfs_lookup, NULL, NULL,
1455 favorite_vfs_lookup, NULL, NULL);
1456
1457 g_once_init_leave (&once_init_value, 1);
1458 }
1459 }
1460