2
* trash-monitor.c: monitor the state of the trash directories.
4
* Copyright (C) 1999, 2000 Eazel, Inc.
5
* Copyright (C) 2004 Canonical Ltd.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License as
9
* published by the Free Software Foundation; either version 2 of the
10
* License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23
#include "trash-monitor.h"
25
#include <libgnomevfs/gnome-vfs.h>
27
struct _TrashMonitor {
31
gint total_item_count;
35
struct _TrashMonitorClass {
36
GObjectClass parent_class;
38
void (* item_count_changed) (TrashMonitor *monitor);
42
TrashMonitor *monitor;
43
GnomeVFSVolume *volume;
45
GnomeVFSAsyncHandle *find_handle;
46
GnomeVFSMonitorHandle *trash_change_monitor;
51
static void trash_monitor_init (TrashMonitor *monitor);
52
static void trash_monitor_class_init (TrashMonitorClass *class);
58
static GObjectClass *parent_class;
59
static guint signals[LAST_SIGNAL];
62
static void volume_mounted_callback (GnomeVFSVolumeMonitor *volume_monitor,
63
GnomeVFSVolume *volume,
64
TrashMonitor *monitor);
65
static void volume_unmount_started_callback (GnomeVFSVolumeMonitor *volume_monitor,
66
GnomeVFSVolume *volume,
67
TrashMonitor *monitor);
69
static void add_volume (TrashMonitor *monitor, GnomeVFSVolume *volume);
70
static void remove_volume (TrashMonitor *monitor, GnomeVFSVolume *volume);
72
static void trash_changed_queue_notify (TrashMonitor *monitor);
74
G_DEFINE_TYPE (TrashMonitor, trash_monitor, G_TYPE_OBJECT)
78
trash_monitor_class_init (TrashMonitorClass *class)
80
parent_class = g_type_class_peek_parent (class);
82
signals[ITEM_COUNT_CHANGED] = g_signal_new
83
("item_count_changed",
84
G_TYPE_FROM_CLASS (class),
86
G_STRUCT_OFFSET (TrashMonitorClass, item_count_changed),
88
g_cclosure_marshal_VOID__VOID,
93
trash_monitor_init (TrashMonitor *monitor)
95
GnomeVFSVolumeMonitor *volume_monitor;
98
monitor->volumes = g_hash_table_new (NULL, NULL);
99
monitor->total_item_count = 0;
100
monitor->notify_id = 0;
102
volume_monitor = gnome_vfs_get_volume_monitor ();
104
g_signal_connect_object (volume_monitor, "volume_mounted",
105
G_CALLBACK (volume_mounted_callback),
107
g_signal_connect_object (volume_monitor, "volume_pre_unmount",
108
G_CALLBACK (volume_unmount_started_callback),
111
volumes = gnome_vfs_volume_monitor_get_mounted_volumes (volume_monitor);
112
for (tmp = volumes; tmp != NULL; tmp = tmp->next) {
113
GnomeVFSVolume *volume = tmp->data;
115
add_volume (monitor, volume);
116
gnome_vfs_volume_unref (volume);
118
g_list_free (volumes);
122
trash_monitor_get (void)
124
static TrashMonitor *monitor;
127
monitor = g_object_new (TRASH_TYPE_MONITOR, NULL);
133
volume_mounted_callback (GnomeVFSVolumeMonitor *volume_monitor,
134
GnomeVFSVolume *volume,
135
TrashMonitor *monitor)
137
add_volume (monitor, volume);
141
volume_unmount_started_callback (GnomeVFSVolumeMonitor *volume_monitor,
142
GnomeVFSVolume *volume,
143
TrashMonitor *monitor)
145
remove_volume (monitor, volume);
149
trash_dir_changed (GnomeVFSMonitorHandle *handle,
150
const gchar *monitor_uri,
151
const gchar *info_uri,
152
GnomeVFSMonitorEventType type,
157
GList *dirlist, *tmp;
162
res = gnome_vfs_directory_list_load (&dirlist, volinfo->trash_uri,
163
GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
164
if (res != GNOME_VFS_OK) {
165
g_warning("GNOME VFS Error: %s", gnome_vfs_result_to_string (res));
169
for (tmp = dirlist; tmp != NULL; tmp = tmp->next) {
170
GnomeVFSFileInfo *info = tmp->data;
172
if (!strcmp (info->name, ".") || !strcmp (info->name, ".."))
176
gnome_vfs_file_info_list_free (dirlist);
178
if (count != volinfo->item_count) {
179
volinfo->item_count = count;
180
trash_changed_queue_notify (volinfo->monitor);
185
find_directory_callback (GnomeVFSAsyncHandle *handle,
187
gpointer callback_data)
190
GnomeVFSFindDirectoryResult *result;
193
volinfo = callback_data;
195
/* we are done finding the volume */
196
volinfo->find_handle = NULL;
198
/* If we can't find the trash, ignore it silently. */
199
result = results->data;
200
if (result->result != GNOME_VFS_OK)
203
volinfo->trash_uri = gnome_vfs_uri_to_string (result->uri,
204
GNOME_VFS_URI_HIDE_NONE);
205
/* g_message ("found trash dir: %s", volinfo->trash_uri); */
207
/* simulate a change to update the directory count */
208
trash_dir_changed (NULL, NULL, NULL, GNOME_VFS_MONITOR_EVENT_CHANGED,
211
res = gnome_vfs_monitor_add (&volinfo->trash_change_monitor,
212
volinfo->trash_uri, GNOME_VFS_MONITOR_DIRECTORY,
216
if (res != GNOME_VFS_OK) {
217
g_warning("GNOME VFS Error: %s", gnome_vfs_result_to_string (res));
218
volinfo->trash_change_monitor = NULL;
223
get_trash_volume (TrashMonitor *monitor,
224
GnomeVFSVolume *volume,
225
VolumeInfo **volinfo,
226
GnomeVFSURI **mount_uri)
230
*volinfo = g_hash_table_lookup (monitor->volumes, volume);
232
if (*volinfo != NULL && (*volinfo)->trash_uri != NULL)
235
if (!gnome_vfs_volume_handles_trash (volume))
238
uri_str = gnome_vfs_volume_get_activation_uri (volume);
239
*mount_uri = gnome_vfs_uri_new (uri_str);
242
if (*volinfo == NULL) {
243
*volinfo = g_new0 (VolumeInfo, 1);
244
(*volinfo)->monitor = monitor;
245
(*volinfo)->volume = gnome_vfs_volume_ref (volume);
246
g_hash_table_insert (monitor->volumes, volume, *volinfo);
253
add_volume (TrashMonitor *monitor, GnomeVFSVolume *volume)
256
GnomeVFSURI *mount_uri;
257
GList vfs_uri_as_list;
259
if (!get_trash_volume (monitor, volume, &volinfo, &mount_uri))
262
if (volinfo->find_handle) {
263
/* already searchinf for trash */
264
gnome_vfs_uri_unref (mount_uri);
269
vfs_uri_as_list.data = mount_uri;
270
vfs_uri_as_list.next = NULL;
271
vfs_uri_as_list.prev = NULL;
273
gnome_vfs_async_find_directory (&volinfo->find_handle, &vfs_uri_as_list,
274
GNOME_VFS_DIRECTORY_KIND_TRASH,
276
GNOME_VFS_PRIORITY_DEFAULT,
277
find_directory_callback, volinfo);
278
gnome_vfs_uri_unref (mount_uri);
282
remove_volume (TrashMonitor *monitor, GnomeVFSVolume *volume)
286
volinfo = g_hash_table_lookup (monitor->volumes, volume);
287
if (volinfo != NULL) {
288
g_hash_table_remove (monitor->volumes, volume);
290
/* g_message ("removing volume %s", volinfo->trash_uri); */
291
if (volinfo->find_handle != NULL)
292
gnome_vfs_async_cancel (volinfo->find_handle);
293
if (volinfo->trash_change_monitor != NULL)
294
gnome_vfs_monitor_cancel (volinfo->trash_change_monitor);
296
if (volinfo->trash_uri)
297
g_free (volinfo->trash_uri);
299
/* if this volume contained some trash, then notify that the trash
300
* state has changed */
301
if (volinfo->item_count != 0)
302
trash_changed_queue_notify (monitor);
304
gnome_vfs_volume_unref (volinfo->volume);
312
readd_volumes (gpointer key, gpointer value, gpointer user_data)
314
TrashMonitor *monitor = user_data;
315
GnomeVFSVolume *volume;
318
add_volume (monitor, volume);
321
trash_monitor_recheck_trash_dirs (TrashMonitor *monitor)
323
/* call add_volume() on each volume, to add trash dirs where missing */
324
g_hash_table_foreach (monitor->volumes, readd_volumes, monitor);
330
trash_monitor_empty_trash (TrashMonitor *monitor,
331
GnomeVFSAsyncHandle **handle,
332
GnomeVFSAsyncXferProgressCallback func,
335
GList *trash_dirs = NULL, *volumes, *tmp;
336
GnomeVFSVolume *volume;
337
GnomeVFSURI *mount_uri, *trash_uri;
340
/* collect the trash directories */
341
volumes = gnome_vfs_volume_monitor_get_mounted_volumes (gnome_vfs_get_volume_monitor ());
342
for (tmp = volumes; tmp != NULL; tmp = tmp->next) {
344
if (gnome_vfs_volume_handles_trash (volume)) {
345
/* get the mount point for this volume */
346
uri_str = gnome_vfs_volume_get_activation_uri (volume);
347
mount_uri = gnome_vfs_uri_new (uri_str);
350
g_assert (mount_uri != NULL);
352
/* Look for the trash directory. Since we tell it not to create or
353
* look for the dir, it doesn't block. */
354
if (gnome_vfs_find_directory (mount_uri,
355
GNOME_VFS_DIRECTORY_KIND_TRASH, &trash_uri,
356
FALSE, FALSE, 0777) == GNOME_VFS_OK) {
357
trash_dirs = g_list_prepend (trash_dirs, trash_uri);
359
gnome_vfs_uri_unref (mount_uri);
361
gnome_vfs_volume_unref (volume);
363
g_list_free (volumes);
365
if (trash_dirs != NULL)
366
gnome_vfs_async_xfer (handle, trash_dirs, NULL,
367
GNOME_VFS_XFER_EMPTY_DIRECTORIES,
368
GNOME_VFS_XFER_ERROR_MODE_ABORT,
369
GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
370
GNOME_VFS_PRIORITY_DEFAULT,
371
func, user_data, NULL, NULL);
372
gnome_vfs_uri_list_free (trash_dirs);
379
count_items (gpointer key, gpointer value, gpointer user_data)
385
item_count = user_data;
386
*item_count += volinfo->item_count;
390
trash_changed_notify (gpointer user_data)
392
TrashMonitor *monitor = user_data;
395
/* reset notification id */
396
monitor->notify_id = 0;
398
/* count the volumes */
400
g_hash_table_foreach (monitor->volumes, count_items, &item_count);
402
/* if the item count has changed ... */
403
if (item_count != monitor->total_item_count) {
404
monitor->total_item_count = item_count;
405
/* g_message ("item count is %d", item_count); */
406
g_signal_emit (monitor, signals[ITEM_COUNT_CHANGED], 0);
413
trash_changed_queue_notify (TrashMonitor *monitor)
416
if (monitor->notify_id != 0)
419
monitor->notify_id = g_idle_add (trash_changed_notify, monitor);
423
trash_monitor_get_item_count (TrashMonitor *monitor)
425
return monitor->total_item_count;
430
#ifdef TEST_TRASH_MONITOR
432
main (int argc, char **argv)
434
TrashMonitor *monitor;
436
if (!gnome_vfs_init ()) {
437
g_printerr ("Can not initialise gnome-vfs.\n");
441
monitor = trash_monitor_get ();
443
g_main_loop_run (g_main_loop_new (NULL, FALSE));