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 (at) redhat.com> 21 */ 22 23 #include "config.h" 24 25 #include "glocaldirectorymonitor.h" 26 #include "gunixmounts.h" 27 #include "giomodule-priv.h" 28 #include "gfile.h" 29 #include "gioerror.h" 30 #include "glibintl.h" 31 32 #include <string.h> 33 34 #include "gioalias.h" 35 36 enum 37 { 38 PROP_0, 39 PROP_DIRNAME 40 }; 41 42 static gboolean g_local_directory_monitor_cancel (GFileMonitor *monitor); 43 static void mounts_changed (GUnixMountMonitor *mount_monitor, 44 gpointer user_data); 45 46 G_DEFINE_ABSTRACT_TYPE (GLocalDirectoryMonitor, g_local_directory_monitor, G_TYPE_FILE_MONITOR) 47 48 static void 49 g_local_directory_monitor_finalize (GObject *object) 50 { 51 GLocalDirectoryMonitor *local_monitor; 52 local_monitor = G_LOCAL_DIRECTORY_MONITOR (object); 53 54 g_free (local_monitor->dirname); 55 56 if (local_monitor->mount_monitor) 57 { 58 g_signal_handlers_disconnect_by_func (local_monitor->mount_monitor, mounts_changed, local_monitor); 59 g_object_unref (local_monitor->mount_monitor); 60 local_monitor->mount_monitor = NULL; 61 } 62 63 G_OBJECT_CLASS (g_local_directory_monitor_parent_class)->finalize (object); 64 } 65 66 static void 67 g_local_directory_monitor_set_property (GObject *object, 68 guint property_id, 69 const GValue *value, 70 GParamSpec *pspec) 71 { 72 switch (property_id) 73 { 74 case PROP_DIRNAME: 75 /* Do nothing */ 76 break; 77 default: 78 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 79 break; 80 } 81 } 82 83 static GObject * 84 g_local_directory_monitor_constructor (GType type, 85 guint n_construct_properties, 86 GObjectConstructParam *construct_properties) 87 { 88 GObject *obj; 89 GLocalDirectoryMonitorClass *klass; 90 GObjectClass *parent_class; 91 GLocalDirectoryMonitor *local_monitor; 92 const gchar *dirname = NULL; 93 gint i; 94 95 klass = G_LOCAL_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_LOCAL_DIRECTORY_MONITOR)); 96 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); 97 obj = parent_class->constructor (type, 98 n_construct_properties, 99 construct_properties); 100 101 local_monitor = G_LOCAL_DIRECTORY_MONITOR (obj); 102 103 for (i = 0; i < n_construct_properties; i++) 104 { 105 if (strcmp ("dirname", g_param_spec_get_name (construct_properties[i].pspec)) == 0) 106 { 107 g_warn_if_fail (G_VALUE_HOLDS_STRING (construct_properties[i].value)); 108 dirname = g_value_get_string (construct_properties[i].value); 109 break; 110 } 111 } 112 113 local_monitor->dirname = g_strdup (dirname); 114 115 if (!klass->mount_notify) 116 { 117 #ifdef G_OS_WIN32 118 /*claim everything was mounted */ 119 local_monitor->was_mounted = TRUE; 120 #else 121 GUnixMountEntry *mount; 122 123 /* Emulate unmount detection */ 124 125 mount = g_unix_mount_at (local_monitor->dirname, NULL); 126 127 local_monitor->was_mounted = mount != NULL; 128 129 if (mount) 130 g_unix_mount_free (mount); 131 132 local_monitor->mount_monitor = g_unix_mount_monitor_new (); 133 g_signal_connect_object (local_monitor->mount_monitor, "mounts-changed", 134 G_CALLBACK (mounts_changed), local_monitor, 0); 135 #endif 136 } 137 138 return obj; 139 } 140 141 static void 142 g_local_directory_monitor_class_init (GLocalDirectoryMonitorClass* klass) 143 { 144 GObjectClass* gobject_class = G_OBJECT_CLASS (klass); 145 GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass); 146 147 gobject_class->finalize = g_local_directory_monitor_finalize; 148 gobject_class->set_property = g_local_directory_monitor_set_property; 149 gobject_class->constructor = g_local_directory_monitor_constructor; 150 151 file_monitor_class->cancel = g_local_directory_monitor_cancel; 152 153 g_object_class_install_property (gobject_class, 154 PROP_DIRNAME, 155 g_param_spec_string ("dirname", 156 P_("Directory name"), 157 P_("Directory to monitor"), 158 NULL, 159 G_PARAM_CONSTRUCT_ONLY| 160 G_PARAM_WRITABLE| 161 G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); 162 163 klass->mount_notify = FALSE; 164 } 165 166 static void 167 g_local_directory_monitor_init (GLocalDirectoryMonitor *local_monitor) 168 { 169 } 170 171 static void 172 mounts_changed (GUnixMountMonitor *mount_monitor, 173 gpointer user_data) 174 { 175 GLocalDirectoryMonitor *local_monitor = user_data; 176 GUnixMountEntry *mount; 177 gboolean is_mounted; 178 GFile *file; 179 180 /* Emulate unmount detection */ 181 #ifdef G_OS_WIN32 182 mount = NULL; 183 /*claim everything was mounted */ 184 is_mounted = TRUE; 185 #else 186 mount = g_unix_mount_at (local_monitor->dirname, NULL); 187 188 is_mounted = mount != NULL; 189 190 if (mount) 191 g_unix_mount_free (mount); 192 #endif 193 194 if (local_monitor->was_mounted != is_mounted) 195 { 196 if (local_monitor->was_mounted && !is_mounted) 197 { 198 file = g_file_new_for_path (local_monitor->dirname); 199 g_file_monitor_emit_event (G_FILE_MONITOR (local_monitor), 200 file, NULL, 201 G_FILE_MONITOR_EVENT_UNMOUNTED); 202 g_object_unref (file); 203 } 204 local_monitor->was_mounted = is_mounted; 205 } 206 } 207 208 static gpointer 209 get_default_local_directory_monitor (gpointer data) 210 { 211 GLocalDirectoryMonitorClass *chosen_class; 212 GLocalDirectoryMonitorClass **ret = data; 213 GIOExtensionPoint *ep; 214 GList *extensions, *l; 215 216 _g_io_modules_ensure_loaded (); 217 218 ep = g_io_extension_point_lookup (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME); 219 220 extensions = g_io_extension_point_get_extensions (ep); 221 222 chosen_class = NULL; 223 for (l = extensions; l != NULL; l = l->next) 224 { 225 GIOExtension *extension = l->data; 226 GLocalDirectoryMonitorClass *klass; 227 228 klass = G_LOCAL_DIRECTORY_MONITOR_CLASS (g_io_extension_ref_class (extension)); 229 230 if (klass->is_supported ()) 231 { 232 chosen_class = klass; 233 break; 234 } 235 else 236 g_type_class_unref (klass); 237 } 238 239 if (chosen_class) 240 { 241 *ret = chosen_class; 242 return (gpointer)G_TYPE_FROM_CLASS (chosen_class); 243 } 244 else 245 return (gpointer)G_TYPE_INVALID; 246 } 247 248 /** 249 * _g_local_directory_monitor_new: 250 * @dirname: filename of the directory to monitor. 251 * @flags: #GFileMonitorFlags. 252 * 253 * Returns: new #GFileMonitor for the given @dirname. 254 **/ 255 GFileMonitor* 256 _g_local_directory_monitor_new (const char *dirname, 257 GFileMonitorFlags flags, 258 GError **error) 259 { 260 static GOnce once_init = G_ONCE_INIT; 261 GTypeClass *type_class; 262 GFileMonitor *monitor; 263 GType type; 264 265 type_class = NULL; 266 g_once (&once_init, get_default_local_directory_monitor, &type_class); 267 type = (GType)once_init.retval; 268 269 monitor = NULL; 270 if (type != G_TYPE_INVALID) 271 monitor = G_FILE_MONITOR (g_object_new (type, "dirname", dirname, NULL)); 272 else 273 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, 274 _("Unable to find default local directory monitor type")); 275 276 /* This is non-null on first pass here. Unref the class now. 277 * This is to avoid unloading the module and then loading it 278 * again which would happen if we unrefed the class 279 * before creating the monitor. 280 */ 281 282 if (type_class) 283 g_type_class_unref (type_class); 284 285 return monitor; 286 } 287 288 static gboolean 289 g_local_directory_monitor_cancel (GFileMonitor *monitor) 290 { 291 GLocalDirectoryMonitor *local_monitor = G_LOCAL_DIRECTORY_MONITOR (monitor); 292 293 if (local_monitor->mount_monitor) 294 { 295 g_signal_handlers_disconnect_by_func (local_monitor->mount_monitor, mounts_changed, local_monitor); 296 g_object_unref (local_monitor->mount_monitor); 297 local_monitor->mount_monitor = NULL; 298 } 299 300 return TRUE; 301 } 302 303 #define __G_LOCAL_DIRECTORY_MONITOR_C__ 304 #include "gioaliasdef.c" 305