1 /* egg-recent-files-module.c: GnomeVFS module to browse recent files list
3 * Copyright (C) 2003 Independent kids, Inc., Kristian Rietveld
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include <libgnomevfs/gnome-vfs-context.h>
21 #include <libgnomevfs/gnome-vfs-method.h>
22 #include <libgnomevfs/gnome-vfs-module.h>
23 #include <libgnomevfs/gnome-vfs-utils.h>
24 #include <libgnomevfs/gnome-vfs-ops.h>
28 #include "egg-recent-model.h"
30 /* WARNING: there is some really evil code in here. Yes, I need to fix
31 * some of that code up someday
34 static gboolean
utf8_string_match (const gchar
*a
,
37 /* our shared EggRecentModel */
38 static EggRecentModel
*recent_model
= NULL
;
39 G_LOCK_DEFINE_STATIC (recent_model
);
41 /* la la la ... evil monitoring code */
42 static GList
*monitoring_handles
= NULL
;
43 static GList
*current_files
= NULL
;
44 G_LOCK_DEFINE_STATIC (monitoring_lock
);
48 monitoring_add_handle (gpointer handle
)
50 G_LOCK (monitoring_lock
);
51 monitoring_handles
= g_list_append (monitoring_handles
, handle
);
52 G_UNLOCK (monitoring_lock
);
56 monitoring_remove_handle (gpointer handle
)
58 G_LOCK (monitoring_lock
);
59 monitoring_handles
= g_list_remove (monitoring_handles
, handle
);
60 G_UNLOCK (monitoring_lock
);
63 /* called in monitoring_lock */
65 monitoring_refresh_current_files (void)
70 list
= egg_recent_model_get_list (recent_model
);
72 g_list_foreach (current_files
, (GFunc
)g_free
, NULL
);
73 g_list_free (current_files
);
76 for (i
= list
; i
; i
= i
->next
)
77 current_files
= g_list_prepend (current_files
,
78 egg_recent_item_get_uri_utf8 (i
->data
));
80 current_files
= g_list_reverse (current_files
);
82 EGG_RECENT_ITEM_LIST_UNREF (list
);
86 monitoring_handle_changed (EggRecentModel
*model
,
91 G_LOCK (monitoring_lock
);
93 for (i
= list
; i
; i
= i
->next
) {
96 gboolean handled
= FALSE
;
97 EggRecentItem
*item
= (EggRecentItem
*)i
->data
;
99 name
= egg_recent_item_get_uri_utf8 (item
);
101 for (j
= current_files
; j
; j
= j
->next
) {
102 if (utf8_string_match (name
, j
->data
)) {
104 current_files
= g_list_remove_link (current_files
, j
);
113 /* file was not in above list, a new file! */
118 tmp
= egg_recent_item_get_uri_utf8 (item
);
122 for (k
= l
- 1; k
>= 0; k
--)
126 name
= g_strdup_printf ("recent-files:///%s",
130 uri
= gnome_vfs_uri_new (name
);
134 for (j
= monitoring_handles
; j
; j
= j
->next
)
135 gnome_vfs_monitor_callback (j
->data
,
137 GNOME_VFS_MONITOR_EVENT_CREATED
);
139 gnome_vfs_uri_unref (uri
);
143 /* current_files now contains files which weren't handled above,
144 * so these files can be deleted
147 for (i
= current_files
; i
; i
= i
->next
) {
149 gchar
*tmp
= i
->data
;
156 for (k
= l
- 1; k
>= 0; k
--)
160 name
= g_strdup_printf ("recent-files:///%s", tmp
+ k
+ 1);
161 uri
= gnome_vfs_uri_new (name
);
164 for (j
= monitoring_handles
; j
; j
= j
->next
)
165 gnome_vfs_monitor_callback (j
->data
,
167 GNOME_VFS_MONITOR_EVENT_DELETED
);
169 gnome_vfs_uri_unref (uri
);
172 /* update current_files */
173 monitoring_refresh_current_files ();
175 G_UNLOCK (monitoring_lock
);
179 monitoring_setup (void)
181 /* we need to sort on MRU, else we won't get the 10 most recently
182 * used items here, according to mister snorp.
184 G_LOCK (recent_model
);
185 recent_model
= egg_recent_model_new (EGG_RECENT_MODEL_SORT_MRU
);
186 G_UNLOCK (recent_model
);
188 monitoring_refresh_current_files ();
190 G_LOCK (recent_model
);
191 g_signal_connect (recent_model
, "changed",
192 G_CALLBACK (monitoring_handle_changed
), NULL
);
193 G_UNLOCK (recent_model
);
197 monitoring_cleanup (void)
199 G_LOCK (recent_model
);
201 g_object_unref (G_OBJECT (recent_model
));
203 G_UNLOCK (recent_model
);
207 /* somewhat more sane code */
210 get_filename_from_uri (const GnomeVFSURI
*uri
)
215 path
= gnome_vfs_unescape_string (uri
->text
, G_DIR_SEPARATOR_S
);
220 if (path
[0] != G_DIR_SEPARATOR
) {
225 ret
= g_strdup (path
+ 1);
232 utf8_string_match (const gchar
*a
,
240 normalized_a
= g_utf8_normalize (a
, -1, G_NORMALIZE_ALL
);
241 normalized_b
= g_utf8_normalize (b
, -1, G_NORMALIZE_ALL
);
244 tmp
= strlen (normalized_b
) - strlen (normalized_a
);
246 ret
= !strcmp (normalized_b
+ tmp
, normalized_a
);
248 g_free (normalized_a
);
249 g_free (normalized_b
);
254 static EggRecentItem
*
255 get_recent_item_from_list (const gchar
*filename
)
259 G_LOCK (recent_model
);
260 list
= egg_recent_model_get_list (recent_model
);
261 G_UNLOCK (recent_model
);
266 for (i
= list
; i
; i
= i
->next
) {
268 EggRecentItem
*item
= (EggRecentItem
*)i
->data
;
270 name
= egg_recent_item_get_uri_for_display (item
);
272 if (!strncmp (name
, "recent-files:", 13)) {
273 /* continue here to avoid endless loops */
278 if (utf8_string_match (filename
, name
)) {
281 egg_recent_item_ref (item
);
282 EGG_RECENT_ITEM_LIST_UNREF (list
);
290 EGG_RECENT_ITEM_LIST_UNREF (list
);
296 get_real_uri_from_virtual_uri (const GnomeVFSURI
*uri
)
302 filename
= get_filename_from_uri (uri
);
306 item
= get_recent_item_from_list (filename
);
312 utf8_uri
= egg_recent_item_get_uri_utf8 (item
);
315 egg_recent_item_unref (item
);
322 static GnomeVFSResult
323 do_open (GnomeVFSMethod
*method
,
324 GnomeVFSMethodHandle
**method_handle
,
326 GnomeVFSOpenMode mode
,
327 GnomeVFSContext
*context
)
331 GnomeVFSHandle
*handle
= NULL
;
333 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle
!= NULL
);
334 _GNOME_VFS_METHOD_PARAM_CHECK (uri
!= NULL
);
336 text_uri
= get_real_uri_from_virtual_uri (uri
);
338 return GNOME_VFS_ERROR_INVALID_URI
;
340 res
= gnome_vfs_open (&handle
, text_uri
, mode
);
343 *method_handle
= (GnomeVFSMethodHandle
*)handle
;
348 static GnomeVFSResult
349 do_close (GnomeVFSMethod
*method
,
350 GnomeVFSMethodHandle
*method_handle
,
351 GnomeVFSContext
*context
)
353 GnomeVFSHandle
*handle
= (GnomeVFSHandle
*)method_handle
;
355 return gnome_vfs_close (handle
);
358 static GnomeVFSResult
359 do_read (GnomeVFSMethod
*method
,
360 GnomeVFSMethodHandle
*method_handle
,
362 GnomeVFSFileSize num_bytes
,
363 GnomeVFSFileSize
*bytes_read
,
364 GnomeVFSContext
*context
)
366 GnomeVFSHandle
*handle
= (GnomeVFSHandle
*)method_handle
;
368 return gnome_vfs_read (handle
, buffer
, num_bytes
, bytes_read
);
371 static GnomeVFSResult
372 do_write (GnomeVFSMethod
*method
,
373 GnomeVFSMethodHandle
*method_handle
,
374 gconstpointer buffer
,
375 GnomeVFSFileSize num_bytes
,
376 GnomeVFSFileSize
*bytes_written
,
377 GnomeVFSContext
*context
)
379 GnomeVFSHandle
*handle
= (GnomeVFSHandle
*)method_handle
;
381 return gnome_vfs_write (handle
, buffer
, num_bytes
, bytes_written
);
384 static GnomeVFSResult
385 do_seek (GnomeVFSMethod
*method
,
386 GnomeVFSMethodHandle
*method_handle
,
387 GnomeVFSSeekPosition whence
,
388 GnomeVFSFileOffset offset
,
389 GnomeVFSContext
*context
)
391 GnomeVFSHandle
*handle
= (GnomeVFSHandle
*)method_handle
;
393 return gnome_vfs_seek (handle
, whence
, offset
);
396 static GnomeVFSResult
397 do_tell (GnomeVFSMethod
*method
,
398 GnomeVFSMethodHandle
*method_handle
,
399 GnomeVFSFileSize
*offset_return
)
401 GnomeVFSHandle
*handle
= (GnomeVFSHandle
*)method_handle
;
403 return gnome_vfs_tell (handle
, offset_return
);
406 static GnomeVFSResult
407 do_truncate_handle (GnomeVFSMethod
*method
,
408 GnomeVFSMethodHandle
*method_handle
,
409 GnomeVFSFileSize where
,
410 GnomeVFSContext
*context
)
412 GnomeVFSHandle
*handle
= (GnomeVFSHandle
*)method_handle
;
414 return gnome_vfs_truncate_handle (handle
, where
);
421 GnomeVFSFileInfoOptions options
;
424 static DirectoryHandle
*
425 directory_handle_new (GnomeVFSFileInfoOptions options
)
427 DirectoryHandle
*handle
;
429 handle
= g_new0 (DirectoryHandle
, 1);
431 G_LOCK (recent_model
);
432 handle
->items
= egg_recent_model_get_list (recent_model
);
433 G_UNLOCK (recent_model
);
434 handle
->current
= handle
->items
;
435 handle
->options
= options
;
441 directory_handle_free (DirectoryHandle
*handle
)
443 EGG_RECENT_ITEM_LIST_UNREF (handle
->items
);
448 static GnomeVFSResult
449 do_open_directory (GnomeVFSMethod
*method
,
450 GnomeVFSMethodHandle
**method_handle
,
452 GnomeVFSFileInfoOptions options
,
453 GnomeVFSContext
*context
)
458 _GNOME_VFS_METHOD_PARAM_CHECK (uri
!= NULL
);
460 scheme
= gnome_vfs_uri_get_scheme (uri
);
461 if (strncmp (scheme
, "recent-files", 12))
462 return GNOME_VFS_ERROR_INVALID_URI
;
464 tmp
= uri
->text
; /* evil ? */
465 if (!tmp
|| strlen (tmp
) != 1 || tmp
[0] != GNOME_VFS_URI_PATH_CHR
)
466 return GNOME_VFS_ERROR_INVALID_URI
;
468 *method_handle
= (GnomeVFSMethodHandle
*)directory_handle_new (options
);
473 static GnomeVFSResult
474 do_close_directory (GnomeVFSMethod
*method
,
475 GnomeVFSMethodHandle
*method_handle
,
476 GnomeVFSContext
*context
)
478 DirectoryHandle
*handle
= (DirectoryHandle
*)method_handle
;
480 directory_handle_free (handle
);
485 static GnomeVFSResult
486 do_read_directory (GnomeVFSMethod
*method
,
487 GnomeVFSMethodHandle
*method_handle
,
488 GnomeVFSFileInfo
*file_info
,
489 GnomeVFSContext
*context
)
491 DirectoryHandle
*handle
= (DirectoryHandle
*)method_handle
;
495 if (!handle
->current
)
496 return GNOME_VFS_ERROR_EOF
;
498 uri
= egg_recent_item_get_uri ((EggRecentItem
*)handle
->current
->data
);
499 res
= gnome_vfs_get_file_info (uri
, file_info
, handle
->options
);
502 handle
->current
= handle
->current
->next
;
504 return res
; /* FIXME: or the res from _get_file_info? */
507 static GnomeVFSResult
508 do_get_file_info (GnomeVFSMethod
*method
,
510 GnomeVFSFileInfo
*file_info
,
511 GnomeVFSFileInfoOptions options
,
512 GnomeVFSContext
*context
)
517 _GNOME_VFS_METHOD_PARAM_CHECK (uri
!= NULL
);
519 if (strlen (uri
->text
) == 1 && uri
->text
[0] == GNOME_VFS_URI_PATH_CHR
) {
520 /* handle root directory */
521 file_info
->valid_fields
= 0;
523 g_free (file_info
->name
);
524 file_info
->name
= g_strdup ("Recent Files");
526 file_info
->type
= GNOME_VFS_FILE_TYPE_DIRECTORY
;
527 file_info
->valid_fields
|= GNOME_VFS_FILE_INFO_FIELDS_TYPE
;
529 g_free (file_info
->mime_type
);
530 file_info
->mime_type
= g_strdup ("x-directory/normal");
531 file_info
->valid_fields
|= GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
;
536 text_uri
= get_real_uri_from_virtual_uri (uri
);
538 return GNOME_VFS_ERROR_INVALID_URI
;
540 res
= gnome_vfs_get_file_info (text_uri
, file_info
, options
);
546 static GnomeVFSResult
547 do_get_file_info_from_handle (GnomeVFSMethod
*method
,
548 GnomeVFSMethodHandle
*method_handle
,
549 GnomeVFSFileInfo
*file_info
,
550 GnomeVFSFileInfoOptions options
,
551 GnomeVFSContext
*context
)
553 GnomeVFSHandle
*handle
= (GnomeVFSHandle
*)method_handle
;
555 return gnome_vfs_get_file_info_from_handle (handle
,
560 do_is_local (GnomeVFSMethod
*method
,
561 const GnomeVFSURI
*uri
)
564 GnomeVFSURI
*tmp_uri
;
567 _GNOME_VFS_METHOD_PARAM_CHECK (uri
!= NULL
);
569 text_uri
= get_real_uri_from_virtual_uri (uri
);
571 return GNOME_VFS_ERROR_INVALID_URI
;
573 tmp_uri
= gnome_vfs_uri_new (text_uri
);
576 return GNOME_VFS_ERROR_INTERNAL
;
578 ret
= gnome_vfs_uri_is_local (tmp_uri
);
579 gnome_vfs_uri_unref (tmp_uri
);
584 static GnomeVFSResult
585 do_unlink (GnomeVFSMethod
*method
,
587 GnomeVFSContext
*context
)
591 _GNOME_VFS_METHOD_PARAM_CHECK (uri
!= NULL
);
593 text_uri
= get_real_uri_from_virtual_uri (uri
);
595 return GNOME_VFS_ERROR_INVALID_URI
;
597 G_LOCK (recent_model
);
598 egg_recent_model_delete (recent_model
, text_uri
);
599 G_UNLOCK (recent_model
);
606 static GnomeVFSResult
607 do_check_same_fs (GnomeVFSMethod
*method
,
608 GnomeVFSURI
*source_uri
,
609 GnomeVFSURI
*target_uri
,
610 gboolean
*same_fs_return
,
611 GnomeVFSContext
*context
)
616 _GNOME_VFS_METHOD_PARAM_CHECK (source_uri
!= NULL
);
617 _GNOME_VFS_METHOD_PARAM_CHECK (target_uri
!= NULL
);
619 a
= get_real_uri_from_virtual_uri (source_uri
);
621 return GNOME_VFS_ERROR_INVALID_URI
;
623 b
= get_real_uri_from_virtual_uri (target_uri
);
626 return GNOME_VFS_ERROR_INVALID_URI
;
629 res
= gnome_vfs_check_same_fs (a
, b
, same_fs_return
);
637 static GnomeVFSResult
638 do_set_file_info (GnomeVFSMethod
*method
,
640 const GnomeVFSFileInfo
*info
,
641 GnomeVFSSetFileInfoMask mask
,
642 GnomeVFSContext
*context
)
647 _GNOME_VFS_METHOD_PARAM_CHECK (uri
!= NULL
);
649 text_uri
= get_real_uri_from_virtual_uri (uri
);
651 return GNOME_VFS_ERROR_INVALID_URI
;
653 res
= gnome_vfs_set_file_info (text_uri
, (GnomeVFSFileInfo
*)info
, mask
);
659 static GnomeVFSResult
660 do_truncate (GnomeVFSMethod
*method
,
662 GnomeVFSFileSize where
,
663 GnomeVFSContext
*context
)
668 _GNOME_VFS_METHOD_PARAM_CHECK (uri
!= NULL
);
670 text_uri
= get_real_uri_from_virtual_uri (uri
);
672 return GNOME_VFS_ERROR_INVALID_URI
;
674 res
= gnome_vfs_truncate (text_uri
, where
);
681 /* will prolly take up 4 bytes anyway ... */
683 } DummyMonitoringHandle
;
685 static GnomeVFSResult
686 do_monitor_add (GnomeVFSMethod
*method
,
687 GnomeVFSMethodHandle
**method_handle_return
,
689 GnomeVFSMonitorType monitor_type
)
694 _GNOME_VFS_METHOD_PARAM_CHECK (uri
!= NULL
);
696 scheme
= gnome_vfs_uri_get_scheme (uri
);
697 if (strncmp (scheme
, "recent-files", 12))
698 return GNOME_VFS_ERROR_INVALID_URI
;
700 tmp
= uri
->text
; /* evil? */
701 if (!tmp
|| strlen (tmp
) != 1 || tmp
[0] != GNOME_VFS_URI_PATH_CHR
)
702 return GNOME_VFS_ERROR_NOT_SUPPORTED
;
704 if (monitor_type
!= GNOME_VFS_MONITOR_DIRECTORY
)
705 return GNOME_VFS_ERROR_BAD_PARAMETERS
;
708 *method_handle_return
= (GnomeVFSMethodHandle
*)g_new (DummyMonitoringHandle
, 1);
710 monitoring_add_handle (*method_handle_return
);
715 static GnomeVFSResult
716 do_monitor_cancel (GnomeVFSMethod
*method
,
717 GnomeVFSMethodHandle
*method_handle
)
720 monitoring_remove_handle (method_handle
);
722 g_free (method_handle
);
727 static GnomeVFSResult
728 do_file_control (GnomeVFSMethod
*method
,
729 GnomeVFSMethodHandle
*method_handle
,
730 const char *operation
,
731 gpointer operation_data
,
732 GnomeVFSContext
*context
)
734 GnomeVFSHandle
*handle
= (GnomeVFSHandle
*)method_handle
;
736 return gnome_vfs_file_control (handle
, operation
, operation_data
);
739 static GnomeVFSMethod method
= {
740 sizeof (GnomeVFSMethod
),
742 NULL
, /* do_create */
753 do_get_file_info_from_handle
,
755 NULL
, /* do_make_directory */
756 NULL
, /* do_remove_directory */
762 NULL
, /* do_find_directory */
763 NULL
, /* do_create_symbolic_link */
767 NULL
, /* do_forget_cache */
768 NULL
/* do_get_freespace */
772 /* shouldn't need locking here IIRC */
774 vfs_module_init (const char *method_name
, const char *args
)
782 vfs_module_shutdown (GnomeVFSMethod
*method
)
784 monitoring_cleanup ();