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