~ubuntu-branches/ubuntu/hardy/gnome-applets/hardy-updates

« back to all changes in this revision

Viewing changes to trashapplet/src/trash-monitor.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-02-26 09:27:38 UTC
  • mto: This revision was merged to the branch mainline in revision 66.
  • Revision ID: james.westby@ubuntu.com-20080226092738-75jsq058qu9w4qwq
Tags: upstream-2.21.92
ImportĀ upstreamĀ versionĀ 2.21.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * trash-monitor.c: monitor the state of the trash directories.
3
 
 *
4
 
 * Copyright (C) 1999, 2000 Eazel, Inc.
5
 
 * Copyright (C) 2004 Canonical Ltd.
6
 
 *
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.
11
 
 *
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.
16
 
 *
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
20
 
 * 02111-1307, USA.
21
 
 */
22
 
 
23
 
#include "trash-monitor.h"
24
 
#include <string.h>
25
 
#include <libgnomevfs/gnome-vfs.h>
26
 
 
27
 
struct _TrashMonitor {
28
 
  GObject parent;
29
 
 
30
 
  GHashTable *volumes;
31
 
  gint total_item_count;
32
 
  gint notify_id;
33
 
};
34
 
 
35
 
struct _TrashMonitorClass {
36
 
  GObjectClass parent_class;
37
 
 
38
 
  void (* item_count_changed) (TrashMonitor *monitor);
39
 
};
40
 
 
41
 
typedef struct {
42
 
  TrashMonitor *monitor;
43
 
  GnomeVFSVolume *volume;
44
 
  gchar *trash_uri;
45
 
  GnomeVFSAsyncHandle *find_handle;
46
 
  GnomeVFSMonitorHandle *trash_change_monitor;
47
 
  gint item_count;
48
 
} VolumeInfo;
49
 
 
50
 
 
51
 
static void trash_monitor_init (TrashMonitor *monitor);
52
 
static void trash_monitor_class_init (TrashMonitorClass *class);
53
 
 
54
 
enum {
55
 
  ITEM_COUNT_CHANGED,
56
 
  LAST_SIGNAL
57
 
};
58
 
static GObjectClass *parent_class;
59
 
static guint signals[LAST_SIGNAL];
60
 
 
61
 
 
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);
68
 
 
69
 
static void add_volume    (TrashMonitor *monitor, GnomeVFSVolume *volume);
70
 
static void remove_volume (TrashMonitor *monitor, GnomeVFSVolume *volume);
71
 
 
72
 
static void trash_changed_queue_notify (TrashMonitor *monitor);
73
 
 
74
 
G_DEFINE_TYPE (TrashMonitor, trash_monitor, G_TYPE_OBJECT)
75
 
 
76
 
 
77
 
static void
78
 
trash_monitor_class_init (TrashMonitorClass *class)
79
 
{
80
 
  parent_class = g_type_class_peek_parent (class);
81
 
 
82
 
  signals[ITEM_COUNT_CHANGED] = g_signal_new
83
 
    ("item_count_changed",
84
 
     G_TYPE_FROM_CLASS (class),
85
 
     G_SIGNAL_RUN_LAST,
86
 
     G_STRUCT_OFFSET (TrashMonitorClass, item_count_changed),
87
 
     NULL, NULL,
88
 
     g_cclosure_marshal_VOID__VOID,
89
 
     G_TYPE_NONE, 0);
90
 
}
91
 
 
92
 
static void
93
 
trash_monitor_init (TrashMonitor *monitor)
94
 
{
95
 
  GnomeVFSVolumeMonitor *volume_monitor;
96
 
  GList *volumes, *tmp;
97
 
 
98
 
  monitor->volumes = g_hash_table_new (NULL, NULL);
99
 
  monitor->total_item_count = 0;
100
 
  monitor->notify_id = 0;
101
 
 
102
 
  volume_monitor = gnome_vfs_get_volume_monitor ();
103
 
  
104
 
  g_signal_connect_object (volume_monitor, "volume_mounted",
105
 
                           G_CALLBACK (volume_mounted_callback),
106
 
                           monitor, 0);
107
 
  g_signal_connect_object (volume_monitor, "volume_pre_unmount",
108
 
                           G_CALLBACK (volume_unmount_started_callback),
109
 
                           monitor, 0);
110
 
 
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;
114
 
 
115
 
    add_volume (monitor, volume);
116
 
    gnome_vfs_volume_unref (volume);
117
 
  }
118
 
  g_list_free (volumes);
119
 
}
120
 
 
121
 
TrashMonitor *
122
 
trash_monitor_get (void)
123
 
{
124
 
  static TrashMonitor *monitor;
125
 
 
126
 
  if (!monitor) {
127
 
    monitor = g_object_new (TRASH_TYPE_MONITOR, NULL);
128
 
  }
129
 
  return monitor;
130
 
}
131
 
 
132
 
static void
133
 
volume_mounted_callback (GnomeVFSVolumeMonitor *volume_monitor,
134
 
                         GnomeVFSVolume *volume,
135
 
                         TrashMonitor *monitor)
136
 
{
137
 
  add_volume (monitor, volume);
138
 
}
139
 
 
140
 
static void
141
 
volume_unmount_started_callback (GnomeVFSVolumeMonitor *volume_monitor,
142
 
                                 GnomeVFSVolume *volume,
143
 
                                 TrashMonitor *monitor)
144
 
{
145
 
  remove_volume (monitor, volume);
146
 
}
147
 
 
148
 
static void
149
 
trash_dir_changed (GnomeVFSMonitorHandle *handle,
150
 
                   const gchar *monitor_uri,
151
 
                   const gchar *info_uri,
152
 
                   GnomeVFSMonitorEventType type,
153
 
                   gpointer user_data)
154
 
{
155
 
  VolumeInfo *volinfo;
156
 
  GnomeVFSResult res;
157
 
  GList *dirlist, *tmp;
158
 
  gint count = 0;
159
 
  
160
 
  volinfo = user_data;
161
 
  
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));
166
 
    return;
167
 
  }
168
 
 
169
 
  for (tmp = dirlist; tmp != NULL; tmp = tmp->next) {
170
 
    GnomeVFSFileInfo *info = tmp->data;
171
 
 
172
 
    if (!strcmp (info->name, ".") || !strcmp (info->name, ".."))
173
 
      continue;
174
 
    count++;
175
 
  }
176
 
  gnome_vfs_file_info_list_free (dirlist);
177
 
  
178
 
  if (count != volinfo->item_count) {
179
 
    volinfo->item_count = count;
180
 
    trash_changed_queue_notify (volinfo->monitor);
181
 
  }
182
 
}
183
 
 
184
 
static void
185
 
find_directory_callback (GnomeVFSAsyncHandle *handle,
186
 
                         GList *results,
187
 
                         gpointer callback_data)
188
 
{
189
 
  VolumeInfo *volinfo;
190
 
  GnomeVFSFindDirectoryResult *result;
191
 
  GnomeVFSResult res;
192
 
 
193
 
  volinfo = callback_data;
194
 
 
195
 
  /* we are done finding the volume */
196
 
  volinfo->find_handle = NULL;
197
 
 
198
 
  /* If we can't find the trash, ignore it silently. */
199
 
  result = results->data;
200
 
  if (result->result != GNOME_VFS_OK)
201
 
    return;
202
 
 
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); */
206
 
 
207
 
  /* simulate a change to update the directory count */
208
 
  trash_dir_changed (NULL, NULL, NULL, GNOME_VFS_MONITOR_EVENT_CHANGED,
209
 
                     volinfo);
210
 
 
211
 
  res = gnome_vfs_monitor_add (&volinfo->trash_change_monitor,
212
 
                               volinfo->trash_uri, GNOME_VFS_MONITOR_DIRECTORY,
213
 
                               trash_dir_changed,
214
 
                               volinfo);
215
 
 
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;
219
 
  }
220
 
}
221
 
 
222
 
static gboolean
223
 
get_trash_volume (TrashMonitor *monitor,
224
 
                  GnomeVFSVolume *volume,
225
 
                  VolumeInfo **volinfo,
226
 
                  GnomeVFSURI **mount_uri)
227
 
{
228
 
  char *uri_str;
229
 
 
230
 
  *volinfo = g_hash_table_lookup (monitor->volumes, volume);
231
 
 
232
 
  if (*volinfo != NULL && (*volinfo)->trash_uri != NULL)
233
 
    return FALSE;
234
 
 
235
 
  if (!gnome_vfs_volume_handles_trash (volume))
236
 
    return FALSE;
237
 
 
238
 
  uri_str = gnome_vfs_volume_get_activation_uri (volume);
239
 
  *mount_uri = gnome_vfs_uri_new (uri_str);
240
 
  g_free (uri_str);
241
 
 
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);
247
 
  }
248
 
 
249
 
  return TRUE;
250
 
}
251
 
 
252
 
static void
253
 
add_volume (TrashMonitor *monitor, GnomeVFSVolume *volume)
254
 
{
255
 
  VolumeInfo *volinfo;
256
 
  GnomeVFSURI *mount_uri;
257
 
  GList vfs_uri_as_list;
258
 
 
259
 
  if (!get_trash_volume (monitor, volume, &volinfo, &mount_uri))
260
 
    return;
261
 
 
262
 
  if (volinfo->find_handle) {
263
 
    /* already searchinf for trash */
264
 
    gnome_vfs_uri_unref (mount_uri);
265
 
    return;
266
 
  }
267
 
 
268
 
  
269
 
  vfs_uri_as_list.data = mount_uri;
270
 
  vfs_uri_as_list.next = NULL;
271
 
  vfs_uri_as_list.prev = NULL;
272
 
 
273
 
  gnome_vfs_async_find_directory (&volinfo->find_handle, &vfs_uri_as_list,
274
 
                                  GNOME_VFS_DIRECTORY_KIND_TRASH,
275
 
                                  FALSE, TRUE, 0777,
276
 
                                  GNOME_VFS_PRIORITY_DEFAULT,
277
 
                                  find_directory_callback, volinfo);
278
 
  gnome_vfs_uri_unref (mount_uri);
279
 
}
280
 
 
281
 
static void
282
 
remove_volume (TrashMonitor *monitor, GnomeVFSVolume *volume)
283
 
{
284
 
  VolumeInfo *volinfo;
285
 
 
286
 
  volinfo = g_hash_table_lookup (monitor->volumes, volume);
287
 
  if (volinfo != NULL) {
288
 
    g_hash_table_remove (monitor->volumes, volume);
289
 
 
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);
295
 
 
296
 
    if (volinfo->trash_uri)
297
 
      g_free (volinfo->trash_uri);
298
 
 
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);
303
 
 
304
 
    gnome_vfs_volume_unref (volinfo->volume);
305
 
    g_free (volinfo);
306
 
  }
307
 
}
308
 
 
309
 
/* --- */
310
 
 
311
 
static void
312
 
readd_volumes (gpointer key, gpointer value, gpointer user_data)
313
 
{
314
 
  TrashMonitor *monitor = user_data;
315
 
  GnomeVFSVolume *volume;
316
 
 
317
 
  volume = key;
318
 
  add_volume (monitor, volume);
319
 
}
320
 
void
321
 
trash_monitor_recheck_trash_dirs (TrashMonitor *monitor)
322
 
{
323
 
  /* call add_volume() on each volume, to add trash dirs where missing */
324
 
  g_hash_table_foreach (monitor->volumes, readd_volumes, monitor);
325
 
}
326
 
 
327
 
/* --- */
328
 
 
329
 
void
330
 
trash_monitor_empty_trash (TrashMonitor *monitor,
331
 
                           GnomeVFSAsyncHandle **handle,
332
 
                           GnomeVFSAsyncXferProgressCallback func,
333
 
                           gpointer user_data)
334
 
{
335
 
  GList *trash_dirs = NULL, *volumes, *tmp;
336
 
  GnomeVFSVolume *volume;
337
 
  GnomeVFSURI *mount_uri, *trash_uri;
338
 
  gchar *uri_str;
339
 
 
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) {
343
 
    volume = tmp->data;
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);
348
 
      g_free (uri_str);
349
 
 
350
 
      g_assert (mount_uri != NULL);
351
 
 
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);
358
 
      }
359
 
      gnome_vfs_uri_unref (mount_uri);
360
 
    }
361
 
    gnome_vfs_volume_unref (volume);
362
 
  }
363
 
  g_list_free (volumes);
364
 
 
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);
373
 
}
374
 
 
375
 
 
376
 
/* --- */
377
 
 
378
 
static void
379
 
count_items (gpointer key, gpointer value, gpointer user_data)
380
 
{
381
 
  VolumeInfo *volinfo;
382
 
  gint *item_count;
383
 
 
384
 
  volinfo = value;
385
 
  item_count = user_data;
386
 
  *item_count += volinfo->item_count;
387
 
}
388
 
 
389
 
static gboolean
390
 
trash_changed_notify (gpointer user_data)
391
 
{
392
 
  TrashMonitor *monitor = user_data;
393
 
  gint item_count;
394
 
 
395
 
  /* reset notification id */
396
 
  monitor->notify_id = 0;
397
 
 
398
 
  /* count the volumes */
399
 
  item_count = 0;
400
 
  g_hash_table_foreach (monitor->volumes, count_items, &item_count);
401
 
 
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);
407
 
  }
408
 
 
409
 
  return FALSE;
410
 
}
411
 
 
412
 
static void
413
 
trash_changed_queue_notify (TrashMonitor *monitor)
414
 
{
415
 
  /* already queued */
416
 
  if (monitor->notify_id != 0)
417
 
    return;
418
 
 
419
 
  monitor->notify_id = g_idle_add (trash_changed_notify, monitor);
420
 
}
421
 
 
422
 
int
423
 
trash_monitor_get_item_count (TrashMonitor *monitor)
424
 
{
425
 
  return monitor->total_item_count;
426
 
}
427
 
 
428
 
/* --- */
429
 
 
430
 
#ifdef TEST_TRASH_MONITOR
431
 
int
432
 
main (int argc, char **argv)
433
 
{
434
 
  TrashMonitor *monitor;
435
 
 
436
 
  if (!gnome_vfs_init ()) {
437
 
    g_printerr ("Can not initialise gnome-vfs.\n");
438
 
    return 1;
439
 
  }
440
 
 
441
 
  monitor = trash_monitor_get ();
442
 
 
443
 
  g_main_loop_run (g_main_loop_new (NULL, FALSE));
444
 
 
445
 
  return 0;
446
 
}
447
 
#endif