gio/ docs/reference/gio Merged gio-standalone into glib.
[platform/upstream/glib.git] / gio / gunionvolumemonitor.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library 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 GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include <config.h>
24
25 #include <string.h>
26
27 #include <glib.h>
28 #include "gunionvolumemonitor.h"
29 #include "gvolumeprivate.h"
30 #include "giomodule.h"
31 #ifdef G_OS_UNIX
32 #include "gunixvolumemonitor.h"
33 #endif
34 #include "gnativevolumemonitor.h"
35
36 #include "glibintl.h"
37
38 struct _GUnionVolumeMonitor {
39   GVolumeMonitor parent;
40
41   GList *monitors;
42 };
43
44 static void g_union_volume_monitor_remove_monitor (GUnionVolumeMonitor *union_monitor,
45                                                    GVolumeMonitor *child_monitor);
46
47
48 G_DEFINE_TYPE (GUnionVolumeMonitor, g_union_volume_monitor, G_TYPE_VOLUME_MONITOR);
49
50
51 G_LOCK_DEFINE_STATIC(the_volume_monitor);
52 static GUnionVolumeMonitor *the_volume_monitor = NULL;
53
54 static void
55 g_union_volume_monitor_finalize (GObject *object)
56 {
57   GUnionVolumeMonitor *monitor;
58   
59   monitor = G_UNION_VOLUME_MONITOR (object);
60
61   while (monitor->monitors != NULL)
62     g_union_volume_monitor_remove_monitor (monitor,
63                                            monitor->monitors->data);
64   
65   if (G_OBJECT_CLASS (g_union_volume_monitor_parent_class)->finalize)
66     (*G_OBJECT_CLASS (g_union_volume_monitor_parent_class)->finalize) (object);
67 }
68
69 static void
70 g_union_volume_monitor_dispose (GObject *object)
71 {
72   GUnionVolumeMonitor *monitor;
73   
74   monitor = G_UNION_VOLUME_MONITOR (object);
75
76   G_LOCK (the_volume_monitor);
77   the_volume_monitor = NULL;
78   G_UNLOCK (the_volume_monitor);
79   
80   if (G_OBJECT_CLASS (g_union_volume_monitor_parent_class)->dispose)
81     (*G_OBJECT_CLASS (g_union_volume_monitor_parent_class)->dispose) (object);
82 }
83
84 static GList *
85 get_mounted_volumes (GVolumeMonitor *volume_monitor)
86 {
87   GUnionVolumeMonitor *monitor;
88   GVolumeMonitor *child_monitor;
89   GList *res;
90   GList *l;
91   
92   monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
93
94   res = NULL;
95   
96   G_LOCK (the_volume_monitor);
97
98   for (l = monitor->monitors; l != NULL; l = l->next)
99     {
100       child_monitor = l->data;
101
102       res = g_list_concat (res,
103                            g_volume_monitor_get_mounted_volumes (child_monitor));
104     }
105   
106   G_UNLOCK (the_volume_monitor);
107
108   return res;
109 }
110
111 static GList *
112 get_connected_drives (GVolumeMonitor *volume_monitor)
113 {
114   GUnionVolumeMonitor *monitor;
115   GVolumeMonitor *child_monitor;
116   GList *res;
117   GList *l;
118   
119   monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
120
121   res = NULL;
122   
123   G_LOCK (the_volume_monitor);
124
125   for (l = monitor->monitors; l != NULL; l = l->next)
126     {
127       child_monitor = l->data;
128
129       res = g_list_concat (res,
130                            g_volume_monitor_get_connected_drives (child_monitor));
131     }
132   
133   G_UNLOCK (the_volume_monitor);
134
135   return res;
136 }
137
138 static void
139 g_union_volume_monitor_class_init (GUnionVolumeMonitorClass *klass)
140 {
141   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
142   GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
143   
144   gobject_class->finalize = g_union_volume_monitor_finalize;
145   gobject_class->dispose = g_union_volume_monitor_dispose;
146
147   monitor_class->get_mounted_volumes = get_mounted_volumes;
148   monitor_class->get_connected_drives = get_connected_drives;
149 }
150
151 static void
152 child_volume_mounted (GVolumeMonitor *child_monitor,
153                       GVolume *child_volume,
154                       GUnionVolumeMonitor *union_monitor)
155 {
156   g_signal_emit_by_name (union_monitor,
157                          "volume_mounted",
158                          child_volume);
159 }
160
161 static void
162 child_volume_pre_unmount (GVolumeMonitor *child_monitor,
163                           GVolume *child_volume,
164                           GUnionVolumeMonitor *union_monitor)
165 {
166   g_signal_emit_by_name (union_monitor,
167                          "volume_pre_unmount",
168                          child_volume);
169 }
170
171 static void
172 child_volume_unmounted (GVolumeMonitor *child_monitor,
173                         GVolume *child_volume,
174                         GUnionVolumeMonitor *union_monitor)
175 {
176   g_signal_emit_by_name (union_monitor,
177                          "volume_unmounted",
178                          child_volume);
179 }
180
181 static void
182 child_drive_connected (GVolumeMonitor *child_monitor,
183                        GDrive *child_drive,
184                        GUnionVolumeMonitor *union_monitor)
185 {
186   g_signal_emit_by_name (union_monitor,
187                          "drive_connected",
188                          child_drive);
189 }
190
191 static void
192 child_drive_disconnected (GVolumeMonitor *child_monitor,
193                           GDrive *child_drive,
194                           GUnionVolumeMonitor *union_monitor)
195 {
196   g_signal_emit_by_name (union_monitor,
197                          "drive_disconnected",
198                          child_drive);
199 }
200
201 static void
202 g_union_volume_monitor_add_monitor (GUnionVolumeMonitor *union_monitor,
203                                     GVolumeMonitor *volume_monitor)
204 {
205   if (g_list_find (union_monitor->monitors, volume_monitor))
206     return;
207
208   union_monitor->monitors =
209     g_list_prepend (union_monitor->monitors,
210                     g_object_ref (volume_monitor));
211
212   g_signal_connect (volume_monitor, "volume_mounted", (GCallback)child_volume_mounted, union_monitor);
213   g_signal_connect (volume_monitor, "volume_pre_unmount", (GCallback)child_volume_pre_unmount, union_monitor);
214   g_signal_connect (volume_monitor, "volume_unmounted", (GCallback)child_volume_unmounted, union_monitor);
215   g_signal_connect (volume_monitor, "drive_connected", (GCallback)child_drive_connected, union_monitor);
216   g_signal_connect (volume_monitor, "drive_disconnected", (GCallback)child_drive_disconnected, union_monitor);
217 }
218
219 static void
220 g_union_volume_monitor_remove_monitor (GUnionVolumeMonitor *union_monitor,
221                                        GVolumeMonitor *child_monitor)
222 {
223   GList *l;
224
225   l = g_list_find (union_monitor->monitors, child_monitor);
226   if (l == NULL)
227     return;
228
229   union_monitor->monitors = g_list_delete_link (union_monitor->monitors, l);
230
231   g_signal_handlers_disconnect_by_func (child_monitor, child_volume_mounted, union_monitor);
232   g_signal_handlers_disconnect_by_func (child_monitor, child_volume_pre_unmount, union_monitor);
233   g_signal_handlers_disconnect_by_func (child_monitor, child_volume_unmounted, union_monitor);
234   g_signal_handlers_disconnect_by_func (child_monitor, child_drive_connected, union_monitor);
235   g_signal_handlers_disconnect_by_func (child_monitor, child_drive_disconnected, union_monitor);
236 }
237
238 static gpointer
239 get_default_native_type (gpointer data)
240 {
241   GNativeVolumeMonitorClass *klass;
242   GType *monitors;
243   guint n_monitors;
244   GType native_type;
245   GType *ret = (GType *) data;
246   int native_prio;
247   int i;
248       
249 #ifdef G_OS_UNIX
250   /* Ensure GUnixVolumeMonitor type is available */
251   {
252     volatile GType unix_type;
253     /* volatile is required to avoid any G_GNUC_CONST optimizations */
254     unix_type = g_unix_volume_monitor_get_type ();
255   }
256 #endif
257       
258   /* Ensure vfs in modules loaded */
259   g_io_modules_ensure_loaded (GIO_MODULE_DIR);
260       
261   monitors = g_type_children (G_TYPE_NATIVE_VOLUME_MONITOR, &n_monitors);
262   native_type = 0;
263   native_prio = -1;
264   
265   for (i = 0; i < n_monitors; i++)
266     {
267       klass = G_NATIVE_VOLUME_MONITOR_CLASS (g_type_class_ref (monitors[i]));
268       if (klass->priority > native_prio)
269         {
270           native_prio = klass->priority;
271           native_type = monitors[i];
272         }
273
274       g_type_class_unref (klass);
275     }
276       
277   g_free (monitors);
278
279   *ret = native_type;
280
281   return NULL;
282 }
283
284 static GType
285 get_native_type (void)
286 {
287   static GOnce once_init = G_ONCE_INIT;
288   static GType type = G_TYPE_INVALID;
289
290   g_once (&once_init, get_default_native_type, &type);
291   
292   return type;
293 }
294
295 static void
296 g_union_volume_monitor_init (GUnionVolumeMonitor *union_monitor)
297 {
298   GVolumeMonitor *monitor;
299   GType *monitors;
300   guint n_monitors;
301   GType native_type;
302   int i;
303
304   native_type = get_native_type ();
305
306   if (native_type != G_TYPE_INVALID)
307     {
308       monitor = g_object_new (native_type, NULL);
309       g_union_volume_monitor_add_monitor (union_monitor, monitor);
310       g_object_unref (monitor);
311     }
312   
313   monitors = g_type_children (G_TYPE_VOLUME_MONITOR, &n_monitors);
314   
315   for (i = 0; i < n_monitors; i++)
316     {
317       if (monitors[i] == G_TYPE_UNION_VOLUME_MONITOR ||
318           g_type_is_a (monitors[i], G_TYPE_NATIVE_VOLUME_MONITOR))
319         continue;
320       
321       monitor = g_object_new (monitors[i], NULL);
322       g_union_volume_monitor_add_monitor (union_monitor, monitor);
323       g_object_unref (monitor);
324     }
325       
326   g_free (monitors);
327 }
328
329 static GUnionVolumeMonitor *
330 g_union_volume_monitor_new (void)
331 {
332   GUnionVolumeMonitor *monitor;
333
334   monitor = g_object_new (G_TYPE_UNION_VOLUME_MONITOR, NULL);
335   
336   return monitor;
337 }
338
339
340 /**
341  * g_volume_monitor_get:
342  * 
343  * Returns: a #GVolumeMonitor.
344  **/
345 GVolumeMonitor *
346 g_volume_monitor_get (void)
347 {
348   GVolumeMonitor *vm;
349   
350   G_LOCK (the_volume_monitor);
351
352   if (the_volume_monitor )
353     vm = G_VOLUME_MONITOR (g_object_ref (the_volume_monitor));
354   else
355     {
356       the_volume_monitor = g_union_volume_monitor_new ();
357       vm = G_VOLUME_MONITOR (the_volume_monitor);
358     }
359   
360   G_UNLOCK (the_volume_monitor);
361
362   return vm;
363 }
364
365 /**
366  * g_volume_get_for_mount_path:
367  * @mountpoint: a string.
368  * 
369  * Returns: a #GVolume for given @mountpoint or %NULL.  
370  **/
371 GVolume *
372 g_volume_get_for_mount_path (const char *mountpoint)
373 {
374   GType native_type;
375   GNativeVolumeMonitorClass *klass;
376   GVolume *volume;
377   
378   native_type = get_native_type ();
379
380   if (native_type == G_TYPE_INVALID)
381     return NULL;
382
383   volume = NULL;
384   
385   klass = G_NATIVE_VOLUME_MONITOR_CLASS (g_type_class_ref (native_type));
386   if (klass->get_volume_for_mountpoint)
387     volume = klass->get_volume_for_mountpoint (mountpoint);
388   
389   g_type_class_unref (klass);
390
391   return volume;
392 }