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 #include <string.h> 25 26 #include "gpollfilemonitor.h" 27 #include "gfile.h" 28 #include "gfilemonitor.h" 29 #include "gfileinfo.h" 30 31 #include "gioalias.h" 32 33 static gboolean g_poll_file_monitor_cancel (GFileMonitor* monitor); 34 static void schedule_poll_timeout (GPollFileMonitor* poll_monitor); 35 36 struct _GPollFileMonitor 37 { 38 GFileMonitor parent_instance; 39 GFile *file; 40 GFileInfo *last_info; 41 guint timeout; 42 }; 43 44 #define POLL_TIME_SECS 5 45 46 #define g_poll_file_monitor_get_type _g_poll_file_monitor_get_type 47 G_DEFINE_TYPE (GPollFileMonitor, g_poll_file_monitor, G_TYPE_FILE_MONITOR) 48 49 static void 50 g_poll_file_monitor_finalize (GObject* object) 51 { 52 GPollFileMonitor* poll_monitor; 53 54 poll_monitor = G_POLL_FILE_MONITOR (object); 55 56 g_object_unref (poll_monitor->file); 57 58 G_OBJECT_CLASS (g_poll_file_monitor_parent_class)->finalize (object); 59 } 60 61 62 static void 63 g_poll_file_monitor_class_init (GPollFileMonitorClass* klass) 64 { 65 GObjectClass* gobject_class = G_OBJECT_CLASS (klass); 66 GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass); 67 68 gobject_class->finalize = g_poll_file_monitor_finalize; 69 70 file_monitor_class->cancel = g_poll_file_monitor_cancel; 71 } 72 73 static void 74 g_poll_file_monitor_init (GPollFileMonitor* poll_monitor) 75 { 76 } 77 78 static int 79 safe_strcmp (const char *a, 80 const char *b) 81 { 82 if (a == NULL && b == NULL) 83 return 0; 84 if (a == NULL) 85 return -1; 86 if (b == NULL) 87 return 1; 88 89 return strcmp (a, b); 90 } 91 92 static int 93 calc_event_type (GFileInfo *last, 94 GFileInfo *new) 95 { 96 if (last == NULL && new == NULL) 97 return -1; 98 99 if (last == NULL && new != NULL) 100 return G_FILE_MONITOR_EVENT_CREATED; 101 102 if (last != NULL && new == NULL) 103 return G_FILE_MONITOR_EVENT_DELETED; 104 105 if (safe_strcmp (g_file_info_get_etag (last), 106 g_file_info_get_etag (new))) 107 return G_FILE_MONITOR_EVENT_CHANGED; 108 109 if (g_file_info_get_size (last) != 110 g_file_info_get_size (new)) 111 return G_FILE_MONITOR_EVENT_CHANGED; 112 113 return -1; 114 } 115 116 static void 117 got_new_info (GObject *source_object, 118 GAsyncResult *res, 119 gpointer user_data) 120 { 121 GPollFileMonitor* poll_monitor = user_data; 122 GFileInfo *info; 123 int event; 124 125 info = g_file_query_info_finish (poll_monitor->file, res, NULL); 126 127 if (!g_file_monitor_is_cancelled (G_FILE_MONITOR (poll_monitor))) 128 { 129 event = calc_event_type (poll_monitor->last_info, info); 130 131 if (event != -1) 132 { 133 g_file_monitor_emit_event (G_FILE_MONITOR (poll_monitor), 134 poll_monitor->file, 135 NULL, event); 136 /* We're polling so slowly anyway, so always emit the done hint */ 137 if (event == G_FILE_MONITOR_EVENT_CHANGED) 138 g_file_monitor_emit_event (G_FILE_MONITOR (poll_monitor), 139 poll_monitor->file, 140 NULL, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT); 141 } 142 143 if (poll_monitor->last_info) 144 { 145 g_object_unref (poll_monitor->last_info); 146 poll_monitor->last_info = NULL; 147 } 148 149 if (info) 150 poll_monitor->last_info = g_object_ref (info); 151 152 schedule_poll_timeout (poll_monitor); 153 } 154 155 if (info) 156 g_object_unref (info); 157 158 g_object_unref (poll_monitor); 159 } 160 161 static gboolean 162 poll_file_timeout (gpointer data) 163 { 164 GPollFileMonitor* poll_monitor = data; 165 166 poll_monitor->timeout = FALSE; 167 168 g_file_query_info_async (poll_monitor->file, G_FILE_ATTRIBUTE_ETAG_VALUE "," G_FILE_ATTRIBUTE_STANDARD_SIZE, 169 0, 0, NULL, got_new_info, g_object_ref (poll_monitor)); 170 171 return FALSE; 172 } 173 174 static void 175 schedule_poll_timeout (GPollFileMonitor* poll_monitor) 176 { 177 poll_monitor->timeout = g_timeout_add_seconds (POLL_TIME_SECS, poll_file_timeout, poll_monitor); 178 } 179 180 static void 181 got_initial_info (GObject *source_object, 182 GAsyncResult *res, 183 gpointer user_data) 184 { 185 GPollFileMonitor* poll_monitor = user_data; 186 GFileInfo *info; 187 188 info = g_file_query_info_finish (poll_monitor->file, res, NULL); 189 190 poll_monitor->last_info = info; 191 192 if (!g_file_monitor_is_cancelled (G_FILE_MONITOR (poll_monitor))) 193 schedule_poll_timeout (poll_monitor); 194 195 g_object_unref (poll_monitor); 196 } 197 198 /** 199 * g_poll_file_monitor_new: 200 * @file: a #GFile. 201 * 202 * Polls @file for changes. 203 * 204 * Returns: a new #GFileMonitor for the given #GFile. 205 **/ 206 GFileMonitor* 207 _g_poll_file_monitor_new (GFile *file) 208 { 209 GPollFileMonitor* poll_monitor; 210 211 poll_monitor = g_object_new (G_TYPE_POLL_FILE_MONITOR, NULL); 212 213 poll_monitor->file = g_object_ref (file); 214 215 g_file_query_info_async (file, G_FILE_ATTRIBUTE_ETAG_VALUE "," G_FILE_ATTRIBUTE_STANDARD_SIZE, 216 0, 0, NULL, got_initial_info, g_object_ref (poll_monitor)); 217 218 return G_FILE_MONITOR (poll_monitor); 219 } 220 221 static gboolean 222 g_poll_file_monitor_cancel (GFileMonitor* monitor) 223 { 224 GPollFileMonitor *poll_monitor = G_POLL_FILE_MONITOR (monitor); 225 226 if (poll_monitor->timeout) 227 { 228 g_source_remove (poll_monitor->timeout); 229 poll_monitor->timeout = 0; 230 } 231 232 return TRUE; 233 } 234