~ubuntu-branches/ubuntu/raring/thunar/raring-proposed

« back to all changes in this revision

Viewing changes to thunar/thunar-device.c

  • Committer: Package Import Robot
  • Author(s): Lionel Le Folgoc
  • Date: 2012-12-03 13:13:58 UTC
  • mfrom: (1.3.4)
  • Revision ID: package-import@ubuntu.com-20121203131358-zk6tkel37d732wh6
Tags: 1.6.0-0ubuntu1
* Upload to raring.
* Remaining Ubuntu change:
  - debian/control: recommend udisks2 for mounting devices. lp: #1014632
* Drop obsolete Ubuntu changes:
  - debian/patches/02_guard-for-no-supported-vfs-schemas.patch,
    debian/patches/xubuntu_fix-duplicate-volumes.patch: included upstream.
* Bugs fixed:
  - "Thunar: sendto_printer broken" lp: #1061846
  - "segfault when a specific html file is selected" lp: #751739
  - "can't book mark remote shares" lp: #778268
  - "Thunar crashed with SIGSEGV in thunarx_menu_provider_get_file_actions()
    thinking a directory was a file" lp: #852410
  - "Left or right-clicking on 3MB or bigger svg file is unresponsive"
    lp: #893330
  - "Thunar crashed with SIGSEGV in fast_validate()" lp: #913041
  - "Thunar crashed with SIGSEGV in thunar_file_get_display_name()"
    lp: #931101
  - "Thunar crashed with SIGSEGV in sort_by_mime_type()" lp: #931842
  - "Thunar crashed with SIGSEGV in thunar_util_parse_parent()" lp: #969222
  - "thunar crashed with SIGSEGV in thunar_standard_view_cancel_thumbnailing()"
    lp: #1059397
  - "Does not unmount USB drive when you try first time" lp: #1059997
  - "regression: thunar no longer shows all unmounted, but mountable, volumes
    in sidepane" lp: #1068947
  - "Thunar shows folder sizes wrong" lp: #59235
  - "Right-click "Open With" list not refreshing" lp: #107392
  - "no thunar contextmenu with GTK setting "gtk-menu-popup-delay = 0""
    lp: #127372
  - "rename folder, still active but answers not on 'Enter'" lp: #479975
  - "Thunar hangs on first launch of each session" lp: #775117
  - "emblems disappear on rename" lp: #877755
  - "Remote Deleted file in Thunar remains visible until resfresh" lp: #999824
  - "Incorrect alphabetical sort order in thunar with non-latin (eg. cyrillic)
    file names" lp: #684317
  - "Thunar does not display current folder name" lp: #875193
  - "Thunar crashed with SIGSEGV in g_file_equal()" lp: #900306
  - "Hard to see, if volume is mounted or not" lp: #838917

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 2012 Nick Schermer <nick@xfce.org>
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License as published by the Free
 
6
 * Software Foundation; either version 2 of the License, or (at your option)
 
7
 * any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
12
 * more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License along with
 
15
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
16
 * Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 */
 
18
 
 
19
#ifdef HAVE_CONFIG_H
 
20
#include <config.h>
 
21
#endif
 
22
 
 
23
#include <thunar/thunar-device.h>
 
24
#include <thunar/thunar-device-monitor.h>
 
25
#include <thunar/thunar-private.h>
 
26
#include <thunar/thunar-file.h>
 
27
#include <thunar/thunar-notify.h>
 
28
 
 
29
 
 
30
 
 
31
typedef gboolean   (*AsyncCallbackFinish) (GObject       *object,
 
32
                                           GAsyncResult  *result,
 
33
                                           GError       **error);
 
34
 
 
35
 
 
36
 
 
37
enum
 
38
{
 
39
  PROP_0,
 
40
  PROP_DEVICE,
 
41
  PROP_HIDDEN,
 
42
  PROP_KIND
 
43
};
 
44
 
 
45
 
 
46
 
 
47
static void           thunar_device_finalize               (GObject                *object);
 
48
static void           thunar_device_get_property           (GObject                 *object,
 
49
                                                            guint                    prop_id,
 
50
                                                            GValue                  *value,
 
51
                                                            GParamSpec              *pspec);
 
52
static void           thunar_device_set_property           (GObject                 *object,
 
53
                                                            guint                    prop_id,
 
54
                                                            const GValue            *value,
 
55
                                                            GParamSpec              *pspec);
 
56
 
 
57
 
 
58
 
 
59
struct _ThunarDeviceClass
 
60
{
 
61
  GObjectClass __parent__;
 
62
};
 
63
 
 
64
struct _ThunarDevice
 
65
{
 
66
  GObject __parent__;
 
67
 
 
68
  /* a GVolume/GMount/GDrive */
 
69
  gpointer          device;
 
70
 
 
71
  ThunarDeviceKind  kind;
 
72
 
 
73
  /* if the device is the list of hidden names */
 
74
  guint             hidden : 1;
 
75
 
 
76
  /* added time for sorting */
 
77
  gint64            stamp;
 
78
};
 
79
 
 
80
typedef struct
 
81
{
 
82
  /* the device the operation is working on */
 
83
  ThunarDevice         *device;
 
84
 
 
85
  /* finish function for the async callback */
 
86
  AsyncCallbackFinish   callback_finish;
 
87
 
 
88
  /* callback for the user */
 
89
  ThunarDeviceCallback  callback;
 
90
  gpointer              user_data;
 
91
}
 
92
ThunarDeviceOperation;
 
93
 
 
94
 
 
95
 
 
96
G_DEFINE_TYPE (ThunarDevice, thunar_device, G_TYPE_OBJECT)
 
97
 
 
98
 
 
99
 
 
100
static void
 
101
thunar_device_class_init (ThunarDeviceClass *klass)
 
102
{
 
103
  GObjectClass *gobject_class;
 
104
 
 
105
  gobject_class = G_OBJECT_CLASS (klass);
 
106
  gobject_class->finalize = thunar_device_finalize;
 
107
  gobject_class->get_property = thunar_device_get_property;
 
108
  gobject_class->set_property = thunar_device_set_property;
 
109
 
 
110
  g_object_class_install_property (gobject_class,
 
111
                                   PROP_DEVICE,
 
112
                                   g_param_spec_object ("device",
 
113
                                                        "device",
 
114
                                                        "device",
 
115
                                                        G_TYPE_OBJECT,
 
116
                                                        EXO_PARAM_READWRITE
 
117
                                                        | G_PARAM_CONSTRUCT_ONLY));
 
118
 
 
119
  g_object_class_install_property (gobject_class,
 
120
                                   PROP_HIDDEN,
 
121
                                   g_param_spec_boolean ("hidden",
 
122
                                                         "hidden",
 
123
                                                         "hidden",
 
124
                                                         FALSE,
 
125
                                                         EXO_PARAM_READWRITE));
 
126
 
 
127
  g_object_class_install_property (gobject_class,
 
128
                                   PROP_KIND,
 
129
                                   g_param_spec_uint ("kind",
 
130
                                                      "kind",
 
131
                                                      "kind",
 
132
                                                      THUNAR_DEVICE_KIND_VOLUME,
 
133
                                                      THUNAR_DEVICE_KIND_MOUNT_REMOTE,
 
134
                                                      THUNAR_DEVICE_KIND_VOLUME,
 
135
                                                      EXO_PARAM_READWRITE
 
136
                                                      | G_PARAM_CONSTRUCT_ONLY));
 
137
}
 
138
 
 
139
 
 
140
 
 
141
static void
 
142
thunar_device_init (ThunarDevice *device)
 
143
{
 
144
  device->kind = THUNAR_DEVICE_KIND_VOLUME;
 
145
  device->stamp = g_get_real_time ();
 
146
}
 
147
 
 
148
 
 
149
 
 
150
static void
 
151
thunar_device_finalize (GObject *object)
 
152
{
 
153
  ThunarDevice *device = THUNAR_DEVICE (object);
 
154
 
 
155
  if (device->device != NULL)
 
156
    g_object_unref (G_OBJECT (device->device));
 
157
 
 
158
  (*G_OBJECT_CLASS (thunar_device_parent_class)->finalize) (object);
 
159
}
 
160
 
 
161
 
 
162
 
 
163
static void
 
164
thunar_device_get_property (GObject    *object,
 
165
                            guint       prop_id,
 
166
                            GValue     *value,
 
167
                            GParamSpec *pspec)
 
168
{
 
169
  ThunarDevice *device = THUNAR_DEVICE (object);
 
170
 
 
171
  switch (prop_id)
 
172
    {
 
173
    case PROP_DEVICE:
 
174
      g_value_set_object (value, device->device);
 
175
      break;
 
176
 
 
177
    case PROP_HIDDEN:
 
178
      g_value_set_boolean (value, device->hidden);
 
179
      break;
 
180
 
 
181
    case PROP_KIND:
 
182
      g_value_set_uint (value, device->kind);
 
183
      break;
 
184
 
 
185
    default:
 
186
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
187
      break;
 
188
    }
 
189
}
 
190
 
 
191
 
 
192
 
 
193
static void
 
194
thunar_device_set_property (GObject      *object,
 
195
                            guint         prop_id,
 
196
                            const GValue *value,
 
197
                            GParamSpec   *pspec)
 
198
{
 
199
  ThunarDevice *device = THUNAR_DEVICE (object);
 
200
 
 
201
  switch (prop_id)
 
202
    {
 
203
    case PROP_DEVICE:
 
204
      device->device = g_value_dup_object (value);
 
205
      _thunar_assert (G_IS_VOLUME (device->device) || G_IS_MOUNT (device->device));
 
206
      break;
 
207
 
 
208
    case PROP_HIDDEN:
 
209
      device->hidden = g_value_get_boolean (value);
 
210
      break;
 
211
 
 
212
    case PROP_KIND:
 
213
      device->kind = g_value_get_uint (value);
 
214
      break;
 
215
 
 
216
    default:
 
217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
218
      break;
 
219
    }
 
220
}
 
221
 
 
222
 
 
223
 
 
224
static ThunarDeviceOperation *
 
225
thunar_device_operation_new (ThunarDevice         *device,
 
226
                             ThunarDeviceCallback  callback,
 
227
                             gpointer              user_data,
 
228
                             gpointer              callback_finish)
 
229
{
 
230
  ThunarDeviceOperation *op;
 
231
 
 
232
  op = g_slice_new0 (ThunarDeviceOperation);
 
233
  op->device = g_object_ref (device);
 
234
  op->callback = callback;
 
235
  op->callback_finish = callback_finish;
 
236
  op->user_data = user_data;
 
237
 
 
238
  return op;
 
239
}
 
240
 
 
241
 
 
242
 
 
243
static void
 
244
thunar_device_operation_finish (GObject      *object,
 
245
                                GAsyncResult *result,
 
246
                                gpointer      user_data)
 
247
{
 
248
  ThunarDeviceOperation *op = user_data;
 
249
  GError                *error = NULL;
 
250
  
 
251
  _thunar_return_if_fail (G_IS_OBJECT (object));
 
252
  _thunar_return_if_fail (G_IS_ASYNC_RESULT (result));
 
253
 
 
254
  /* remove notification */
 
255
  thunar_notify_finish (op->device);
 
256
 
 
257
  /* finish the operation */
 
258
  if (!(op->callback_finish) (object, result, &error))
 
259
    {
 
260
      /* unset the error if a helper program has already interacted with the user */
 
261
      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED))
 
262
        g_clear_error (&error);
 
263
 
 
264
      if (op->callback_finish == (AsyncCallbackFinish) g_volume_mount_finish)
 
265
        {
 
266
          /* special handling for mount operation */
 
267
          if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_ALREADY_MOUNTED)
 
268
              || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
 
269
            g_clear_error (&error);
 
270
        }
 
271
    }
 
272
 
 
273
  /* user callback */
 
274
  (op->callback) (op->device, error, op->user_data);
 
275
 
 
276
  /* cleanup */
 
277
  g_clear_error (&error);
 
278
  g_object_unref (G_OBJECT (op->device));
 
279
  g_slice_free (ThunarDeviceOperation, op);
 
280
}
 
281
 
 
282
 
 
283
 
 
284
static void
 
285
thunar_device_emit_pre_unmount (ThunarDevice *device,
 
286
                                gboolean      all_volumes)
 
287
{
 
288
  ThunarDeviceMonitor *monitor;
 
289
  GFile               *root_file;
 
290
 
 
291
  root_file = thunar_device_get_root (device);
 
292
  if (root_file != NULL)
 
293
    {
 
294
      /* make sure the pre-unmount event is emitted, this is important
 
295
       * for the interface */
 
296
      monitor = thunar_device_monitor_get ();
 
297
      g_signal_emit_by_name (monitor, "device-pre-unmount", device, root_file);
 
298
      g_object_unref (monitor);
 
299
      g_object_unref (root_file);
 
300
    }
 
301
}
 
302
 
 
303
 
 
304
 
 
305
gchar *
 
306
thunar_device_get_name (const ThunarDevice *device)
 
307
{
 
308
  GFile *mount_point;
 
309
  gchar *display_name = NULL;
 
310
 
 
311
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), NULL);
 
312
 
 
313
  if (G_IS_VOLUME (device->device))
 
314
    {
 
315
      return g_volume_get_name (device->device);
 
316
    }
 
317
  else if (G_IS_MOUNT (device->device))
 
318
    {
 
319
      /* probably we can make a nicer name for this mount */
 
320
      mount_point = thunar_device_get_root (device);
 
321
      if (mount_point != NULL)
 
322
        {
 
323
          display_name = thunar_g_file_get_display_name_remote (mount_point);
 
324
          g_object_unref (mount_point);
 
325
        }
 
326
 
 
327
      if (display_name == NULL)
 
328
        display_name = g_mount_get_name (device->device);
 
329
 
 
330
      return display_name;
 
331
    }
 
332
  else
 
333
    _thunar_assert_not_reached ();
 
334
 
 
335
  return NULL;
 
336
}
 
337
 
 
338
 
 
339
 
 
340
GIcon *
 
341
thunar_device_get_icon (const ThunarDevice *device)
 
342
{
 
343
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), NULL);
 
344
 
 
345
  if (G_IS_VOLUME (device->device))
 
346
    return g_volume_get_icon (device->device);
 
347
  else if (G_IS_MOUNT (device->device))
 
348
   return g_mount_get_icon (device->device);
 
349
  else
 
350
    _thunar_assert_not_reached ();
 
351
 
 
352
  return NULL;
 
353
}
 
354
 
 
355
 
 
356
 
 
357
ThunarDeviceKind
 
358
thunar_device_get_kind (const ThunarDevice *device)
 
359
{
 
360
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), THUNAR_DEVICE_KIND_VOLUME);
 
361
  return device->kind;
 
362
}
 
363
 
 
364
 
 
365
 
 
366
gchar *
 
367
thunar_device_get_identifier (const ThunarDevice *device)
 
368
{
 
369
  gchar *ident = NULL;
 
370
 
 
371
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), NULL);
 
372
 
 
373
  if (G_IS_VOLUME (device->device))
 
374
    {
 
375
      ident = g_volume_get_uuid (device->device);
 
376
      if (ident == NULL)
 
377
        ident = g_volume_get_identifier (device->device, G_VOLUME_IDENTIFIER_KIND_UUID);
 
378
      if (ident == NULL)
 
379
        ident = g_volume_get_name (device->device);
 
380
    }
 
381
  else if (G_IS_MOUNT (device->device))
 
382
    {
 
383
      ident = g_mount_get_uuid (device->device);
 
384
      if (ident == NULL)
 
385
        ident = g_mount_get_name (device->device);
 
386
    }
 
387
  else
 
388
    _thunar_assert_not_reached ();
 
389
 
 
390
  return ident;
 
391
}
 
392
 
 
393
 
 
394
 
 
395
gboolean
 
396
thunar_device_get_hidden (const ThunarDevice *device)
 
397
{
 
398
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), FALSE);
 
399
  return device->hidden;
 
400
}
 
401
 
 
402
 
 
403
 
 
404
/**
 
405
 * thunar_device_can_eject:
 
406
 *
 
407
 * If the user should see the option to eject this device.
 
408
 **/
 
409
gboolean
 
410
thunar_device_can_eject (const ThunarDevice *device)
 
411
{
 
412
  gboolean  can_eject = FALSE;
 
413
  GMount   *volume_mount;
 
414
  GDrive   *drive;
 
415
 
 
416
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), FALSE);
 
417
 
 
418
  if (G_IS_VOLUME (device->device))
 
419
    {
 
420
      drive = g_volume_get_drive (device->device);
 
421
      if (drive != NULL)
 
422
        {
 
423
          can_eject = g_drive_can_eject (drive) || g_drive_can_stop (drive);
 
424
          g_object_unref (drive);
 
425
        }
 
426
 
 
427
      if (!can_eject)
 
428
        {
 
429
          /* check if the volume can eject */
 
430
          can_eject = g_volume_can_eject (device->device);
 
431
          if (!can_eject)
 
432
            {
 
433
              /* check if the mount can eject/unmount */
 
434
              volume_mount = g_volume_get_mount (device->device);
 
435
              if (volume_mount != NULL)
 
436
                {
 
437
                  can_eject = g_mount_can_eject (volume_mount) || g_mount_can_unmount (volume_mount);
 
438
                  g_object_unref (volume_mount);
 
439
                }
 
440
            }
 
441
        }
 
442
    }
 
443
  else if (G_IS_MOUNT (device->device))
 
444
    {
 
445
      /* eject or unmount because thats for the user the same
 
446
       * because we prefer volumes over mounts as devices */
 
447
      can_eject = g_mount_can_eject (device->device) || g_mount_can_unmount (device->device);
 
448
    }
 
449
  else
 
450
    _thunar_assert_not_reached ();
 
451
 
 
452
  return can_eject;
 
453
}
 
454
 
 
455
 
 
456
 
 
457
/**
 
458
 * thunar_device_can_mount:
 
459
 *
 
460
 * If the user should see the option to mount this device.
 
461
 **/
 
462
gboolean
 
463
thunar_device_can_mount (const ThunarDevice *device)
 
464
{
 
465
  gboolean  can_mount = FALSE;
 
466
  GMount   *volume_mount;
 
467
 
 
468
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), FALSE);
 
469
 
 
470
  if (G_IS_VOLUME (device->device))
 
471
    {
 
472
      /* only volumes without a mountpoint and mount capability */
 
473
      volume_mount = g_volume_get_mount (device->device);
 
474
      if (volume_mount == NULL)
 
475
        can_mount = g_volume_can_mount (device->device);
 
476
      else
 
477
        g_object_unref (volume_mount);
 
478
    }
 
479
  else if (G_IS_MOUNT (device->device))
 
480
    {
 
481
      /* a mount is already mounted... */
 
482
      can_mount = FALSE;
 
483
    }
 
484
  else
 
485
    _thunar_assert_not_reached ();
 
486
 
 
487
  return can_mount;
 
488
}
 
489
 
 
490
 
 
491
 
 
492
/**
 
493
 * thunar_device_can_unmount:
 
494
 *
 
495
 * If the user should see the option to unmount this device.
 
496
 **/
 
497
gboolean
 
498
thunar_device_can_unmount (const ThunarDevice *device)
 
499
{
 
500
  gboolean  can_unmount = FALSE;
 
501
  GMount   *volume_mount;
 
502
 
 
503
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), FALSE);
 
504
 
 
505
  if (G_IS_VOLUME (device->device))
 
506
    {
 
507
      /* only volumes with a mountpoint and unmount capability */
 
508
      volume_mount = g_volume_get_mount (device->device);
 
509
      if (volume_mount != NULL)
 
510
        {
 
511
          can_unmount = g_mount_can_unmount (volume_mount);
 
512
          g_object_unref (volume_mount);
 
513
        }
 
514
    }
 
515
  else if (G_IS_MOUNT (device->device))
 
516
    {
 
517
      /* check if the mount can unmount */
 
518
      can_unmount = g_mount_can_unmount (device->device);
 
519
    }
 
520
  else
 
521
    _thunar_assert_not_reached ();
 
522
 
 
523
  return can_unmount;
 
524
}
 
525
 
 
526
 
 
527
 
 
528
gboolean
 
529
thunar_device_is_mounted (const ThunarDevice *device)
 
530
{
 
531
  gboolean  is_mounted = FALSE;
 
532
  GMount   *volume_mount;
 
533
 
 
534
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), FALSE);
 
535
 
 
536
  if (G_IS_VOLUME (device->device))
 
537
    {
 
538
      /* a volume with a mount point is mounted */
 
539
      volume_mount = g_volume_get_mount (device->device);
 
540
      if (volume_mount != NULL)
 
541
        {
 
542
          is_mounted = TRUE;
 
543
          g_object_unref (volume_mount);
 
544
        }
 
545
    }
 
546
  else if (G_IS_MOUNT (device->device))
 
547
    {
 
548
      /* mounter are always mounted... */
 
549
      is_mounted = TRUE;
 
550
    }
 
551
  else
 
552
    _thunar_assert_not_reached ();
 
553
 
 
554
  return is_mounted;
 
555
}
 
556
 
 
557
 
 
558
 
 
559
GFile *
 
560
thunar_device_get_root (const ThunarDevice *device)
 
561
{
 
562
  GFile  *root = NULL;
 
563
  GMount *volume_mount;
 
564
 
 
565
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device), NULL);
 
566
 
 
567
  if (G_IS_VOLUME (device->device))
 
568
    {
 
569
      volume_mount = g_volume_get_mount (device->device);
 
570
      if (volume_mount != NULL)
 
571
        {
 
572
          root = g_mount_get_root (volume_mount);
 
573
          g_object_unref (volume_mount);
 
574
        }
 
575
 
 
576
      if (root == NULL)
 
577
        root = g_volume_get_activation_root (device->device);
 
578
    }
 
579
  else if (G_IS_MOUNT (device->device))
 
580
    {
 
581
      root = g_mount_get_root (device->device);
 
582
    }
 
583
  else
 
584
    _thunar_assert_not_reached ();
 
585
 
 
586
  return root;
 
587
}
 
588
 
 
589
 
 
590
 
 
591
gint
 
592
thunar_device_sort (const ThunarDevice *device1,
 
593
                    const ThunarDevice *device2)
 
594
{
 
595
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device1), 0);
 
596
  _thunar_return_val_if_fail (THUNAR_IS_DEVICE (device2), 0);
 
597
 
 
598
  /* sort volumes above mounts */
 
599
  if (G_OBJECT_TYPE (device1->device) != G_OBJECT_TYPE (device2->device))
 
600
    return G_IS_VOLUME (device1->device) ? 1 : -1;
 
601
 
 
602
  /* sort by detect stamp */
 
603
  return device1->stamp > device2->stamp ? 1 : -1;
 
604
}
 
605
 
 
606
 
 
607
 
 
608
void
 
609
thunar_device_mount (ThunarDevice         *device,
 
610
                     GMountOperation      *mount_operation,
 
611
                     GCancellable         *cancellable,
 
612
                     ThunarDeviceCallback  callback,
 
613
                     gpointer              user_data)
 
614
{
 
615
  ThunarDeviceOperation *op;
 
616
 
 
617
  _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
 
618
  _thunar_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation));
 
619
  _thunar_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
620
  _thunar_return_if_fail (callback != NULL);
 
621
 
 
622
  if (G_IS_VOLUME (device->device))
 
623
    {
 
624
      op = thunar_device_operation_new (device, callback, user_data,
 
625
                                        g_volume_mount_finish);
 
626
      g_volume_mount (G_VOLUME (device->device),
 
627
                      G_MOUNT_MOUNT_NONE,
 
628
                      mount_operation,
 
629
                      cancellable,
 
630
                      thunar_device_operation_finish,
 
631
                      op);
 
632
    }
 
633
}
 
634
 
 
635
 
 
636
 
 
637
/**
 
638
 * thunar_device_unmount:
 
639
 *
 
640
 * Unmount a #ThunarDevice. Don't try to eject.
 
641
 **/
 
642
void
 
643
thunar_device_unmount (ThunarDevice         *device,
 
644
                       GMountOperation      *mount_operation,
 
645
                       GCancellable         *cancellable,
 
646
                       ThunarDeviceCallback  callback,
 
647
                       gpointer              user_data)
 
648
{
 
649
  ThunarDeviceOperation *op;
 
650
  GMount                *mount;
 
651
 
 
652
  _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
 
653
  _thunar_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation));
 
654
  _thunar_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
655
  _thunar_return_if_fail (callback != NULL);
 
656
 
 
657
  /* get the mount from the volume or use existing mount */
 
658
  if (G_IS_VOLUME (device->device))
 
659
    mount = g_volume_get_mount (device->device);
 
660
  else if (G_IS_MOUNT (device->device))
 
661
    mount = g_object_ref (device->device);
 
662
  else
 
663
    mount = NULL;
 
664
 
 
665
  if (G_LIKELY (mount != NULL))
 
666
    {
 
667
      /* only handle mounts that can be unmounted here */
 
668
      if (g_mount_can_unmount (mount))
 
669
        {
 
670
          /* inform user */
 
671
          thunar_notify_unmount (device);
 
672
 
 
673
          /* try unmounting the mount */
 
674
          thunar_device_emit_pre_unmount (device, FALSE);
 
675
          op = thunar_device_operation_new (device, callback, user_data,
 
676
                                            g_mount_unmount_with_operation_finish);
 
677
          g_mount_unmount_with_operation (mount,
 
678
                                          G_MOUNT_UNMOUNT_NONE,
 
679
                                          mount_operation,
 
680
                                          cancellable,
 
681
                                          thunar_device_operation_finish,
 
682
                                          op);
 
683
        }
 
684
 
 
685
      g_object_unref (G_OBJECT (mount));
 
686
    }
 
687
}
 
688
 
 
689
 
 
690
 
 
691
/**
 
692
 * thunar_device_unmount:
 
693
 *
 
694
 * Try to eject a #ThunarDevice, fall-back to unmounting
 
695
 **/
 
696
void
 
697
thunar_device_eject (ThunarDevice         *device,
 
698
                     GMountOperation      *mount_operation,
 
699
                     GCancellable         *cancellable,
 
700
                     ThunarDeviceCallback  callback,
 
701
                     gpointer              user_data)
 
702
{
 
703
  ThunarDeviceOperation *op;
 
704
  GMount                *mount = NULL;
 
705
  GVolume               *volume;
 
706
  GDrive                *drive;
 
707
 
 
708
  _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
 
709
  _thunar_return_if_fail (G_IS_MOUNT_OPERATION (mount_operation));
 
710
  _thunar_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
711
  _thunar_return_if_fail (callback != NULL);
 
712
 
 
713
  if (G_IS_VOLUME (device->device))
 
714
    {
 
715
      volume = device->device;
 
716
      drive = g_volume_get_drive (volume);
 
717
 
 
718
      if (drive != NULL)
 
719
        {
 
720
          if (g_drive_can_stop (drive))
 
721
            {
 
722
              /* inform user */
 
723
              thunar_notify_eject (device);
 
724
 
 
725
              /* try to stop the drive */
 
726
              thunar_device_emit_pre_unmount (device, TRUE);
 
727
              op = thunar_device_operation_new (device, callback, user_data,
 
728
                                                g_drive_stop_finish);
 
729
              g_drive_stop (drive,
 
730
                            G_MOUNT_UNMOUNT_NONE,
 
731
                            mount_operation,
 
732
                            cancellable,
 
733
                            thunar_device_operation_finish,
 
734
                            op);
 
735
 
 
736
              g_object_unref (drive);
 
737
 
 
738
              /* done */
 
739
              return;
 
740
            }
 
741
          else if (g_drive_can_eject (drive))
 
742
            {
 
743
              /* inform user */
 
744
              thunar_notify_eject (device);
 
745
 
 
746
              /* try to stop the drive */
 
747
              thunar_device_emit_pre_unmount (device, TRUE);
 
748
              op = thunar_device_operation_new (device, callback, user_data,
 
749
                                                g_drive_eject_with_operation_finish);
 
750
              g_drive_eject_with_operation (drive,
 
751
                                            G_MOUNT_UNMOUNT_NONE,
 
752
                                            mount_operation,
 
753
                                            cancellable,
 
754
                                            thunar_device_operation_finish,
 
755
                                            op);
 
756
 
 
757
              g_object_unref (drive);
 
758
 
 
759
              /* done */
 
760
              return;
 
761
            }
 
762
 
 
763
          g_object_unref (drive);
 
764
        }
 
765
 
 
766
      if (g_volume_can_eject (volume))
 
767
        {
 
768
          /* inform user */
 
769
          thunar_notify_eject (device);
 
770
 
 
771
          /* try ejecting the volume */
 
772
          thunar_device_emit_pre_unmount (device, TRUE);
 
773
          op = thunar_device_operation_new (device, callback, user_data,
 
774
                                            g_volume_eject_with_operation_finish);
 
775
          g_volume_eject_with_operation (volume,
 
776
                                         G_MOUNT_UNMOUNT_NONE,
 
777
                                         mount_operation,
 
778
                                         cancellable,
 
779
                                         thunar_device_operation_finish,
 
780
                                         op);
 
781
 
 
782
          /* done */
 
783
          return;
 
784
        }
 
785
      else
 
786
        {
 
787
          /* get the mount and fall-through */
 
788
          mount = g_volume_get_mount (volume);
 
789
        }
 
790
    }
 
791
  else if (G_IS_MOUNT (device->device))
 
792
    {
 
793
      /* set the mount and fall-through */
 
794
      mount = g_object_ref (device->device);
 
795
    }
 
796
 
 
797
  /* handle mounts */
 
798
  if (mount != NULL)
 
799
    {
 
800
      /* distinguish between ejectable and unmountable mounts */
 
801
      if (g_mount_can_eject (mount))
 
802
        {
 
803
          /* inform user */
 
804
          thunar_notify_eject (device);
 
805
 
 
806
          /* try ejecting the mount */
 
807
          thunar_device_emit_pre_unmount (device, FALSE);
 
808
          op = thunar_device_operation_new (device, callback, user_data,
 
809
                                            g_mount_eject_with_operation_finish);
 
810
          g_mount_eject_with_operation (mount,
 
811
                                        G_MOUNT_UNMOUNT_NONE,
 
812
                                        mount_operation,
 
813
                                        cancellable,
 
814
                                        thunar_device_operation_finish,
 
815
                                        op);
 
816
        }
 
817
      else if (g_mount_can_unmount (mount))
 
818
        {
 
819
          /* inform user */
 
820
          thunar_notify_unmount (device);
 
821
 
 
822
          /* try unmounting the mount */
 
823
          thunar_device_emit_pre_unmount (device, FALSE);
 
824
          op = thunar_device_operation_new (device, callback, user_data,
 
825
                                            g_mount_unmount_with_operation_finish);
 
826
          g_mount_unmount_with_operation (mount,
 
827
                                          G_MOUNT_UNMOUNT_NONE,
 
828
                                          mount_operation,
 
829
                                          cancellable,
 
830
                                          thunar_device_operation_finish,
 
831
                                          op);
 
832
        }
 
833
 
 
834
      g_object_unref (G_OBJECT (mount));
 
835
    }
 
836
}