Bumps documentation to 93% symbol coverage, touching most
[platform/upstream/glib.git] / gio / gfilemonitor.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 #include <string.h>
25
26 #include "gfilemonitor.h"
27 #include "gio-marshal.h"
28 #include "gvfs.h"
29 #include "glibintl.h"
30
31 /**
32  * SECTION:gfilemonitor
33  * @short_description: File Monitor
34  * @see_also: #GDirectoryMonitor
35  *
36  * Monitors a file for changes.
37  * 
38  **/
39
40 enum {
41   CHANGED,
42   LAST_SIGNAL
43 };
44
45 G_DEFINE_ABSTRACT_TYPE (GFileMonitor, g_file_monitor, G_TYPE_OBJECT);
46
47 struct _GFileMonitorPrivate {
48   gboolean cancelled;
49   int rate_limit_msec;
50
51   /* Rate limiting change events */
52   guint32 last_sent_change_time; /* Some monitonic clock in msecs */
53   GFile *last_sent_change_file;
54   
55   guint send_delayed_change_timeout;
56
57   /* Virtual CHANGES_DONE_HINT emission */
58   GSource *virtual_changes_done_timeout;
59   GFile *virtual_changes_done_file;
60 };
61
62 #define DEFAULT_RATE_LIMIT_MSECS 800
63 #define DEFAULT_VIRTUAL_CHANGES_DONE_DELAY_SECS 2
64
65 static guint signals[LAST_SIGNAL] = { 0 };
66
67 static void
68 g_file_monitor_finalize (GObject *object)
69 {
70   GFileMonitor *monitor;
71
72   monitor = G_FILE_MONITOR (object);
73
74   if (monitor->priv->last_sent_change_file)
75     g_object_unref (monitor->priv->last_sent_change_file);
76
77   if (monitor->priv->send_delayed_change_timeout != 0)
78     g_source_remove (monitor->priv->send_delayed_change_timeout);
79
80   if (monitor->priv->virtual_changes_done_file)
81     g_object_unref (monitor->priv->virtual_changes_done_file);
82
83   if (monitor->priv->virtual_changes_done_timeout)
84     g_source_destroy (monitor->priv->virtual_changes_done_timeout);
85   
86   if (G_OBJECT_CLASS (g_file_monitor_parent_class)->finalize)
87     (*G_OBJECT_CLASS (g_file_monitor_parent_class)->finalize) (object);
88 }
89
90 static void
91 g_file_monitor_dispose (GObject *object)
92 {
93   GFileMonitor *monitor;
94   
95   monitor = G_FILE_MONITOR (object);
96
97   /* Make sure we cancel on last unref */
98   if (!monitor->priv->cancelled)
99     g_file_monitor_cancel (monitor);
100   
101   if (G_OBJECT_CLASS (g_file_monitor_parent_class)->dispose)
102     (*G_OBJECT_CLASS (g_file_monitor_parent_class)->dispose) (object);
103 }
104
105 static void
106 g_file_monitor_class_init (GFileMonitorClass *klass)
107 {
108   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
109   
110   g_type_class_add_private (klass, sizeof (GFileMonitorPrivate));
111   
112   gobject_class->finalize = g_file_monitor_finalize;
113   gobject_class->dispose = g_file_monitor_dispose;
114
115   /**
116    * GFileMonitor::changed:
117    * @monitor: a #GFileMonitor.
118    * @file: a #GFile.
119    * @other_file: a #GFile.
120    * @event_type: a #GFileMonitorEvent.
121    * 
122    * Emitted when a file has been changed. 
123    **/
124   signals[CHANGED] =
125     g_signal_new (I_("changed"),
126                   G_TYPE_FILE_MONITOR,
127                   G_SIGNAL_RUN_LAST,
128                   G_STRUCT_OFFSET (GFileMonitorClass, changed),
129                   NULL, NULL,
130                   _gio_marshal_VOID__OBJECT_OBJECT_INT,
131                   G_TYPE_NONE,3,
132                   G_TYPE_FILE,
133                   G_TYPE_FILE,
134                   G_TYPE_INT);
135 }
136
137 static void
138 g_file_monitor_init (GFileMonitor *monitor)
139 {
140   monitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (monitor,
141                                                G_TYPE_FILE_MONITOR,
142                                                GFileMonitorPrivate);
143   monitor->priv->rate_limit_msec = DEFAULT_RATE_LIMIT_MSECS;
144 }
145
146 /**
147  * g_file_monitor_is_cancelled:
148  * @monitor:
149  * 
150  * Returns: %TRUE if monitor is canceled. %FALSE otherwise.
151  **/
152 gboolean
153 g_file_monitor_is_cancelled (GFileMonitor *monitor)
154 {
155   g_return_val_if_fail (G_IS_FILE_MONITOR (monitor), FALSE);
156
157   return monitor->priv->cancelled;
158 }
159
160 /**
161  * g_file_monitor_cancel:
162  * @monitor: a #GFileMonitor.
163  * 
164  * Cancels a file monitor.
165  * 
166  * Returns: %TRUE if monitor was cancelled.
167  **/
168 gboolean
169 g_file_monitor_cancel (GFileMonitor* monitor)
170 {
171   GFileMonitorClass *klass;
172   
173   g_return_val_if_fail (G_IS_FILE_MONITOR (monitor), FALSE);
174   
175   if (monitor->priv->cancelled)
176     return TRUE;
177   
178   monitor->priv->cancelled = TRUE;
179   
180   klass = G_FILE_MONITOR_GET_CLASS (monitor);
181   return (* klass->cancel) (monitor);
182 }
183
184 /**
185  * g_file_monitor_set_rate_limit:
186  * @monitor: a #GFileMonitor.
187  * @limit_msecs: a integer with the limit in milliseconds to 
188  * poll for changes.
189  *
190  * Sets the rate limit to which the @monitor will poll for changes 
191  * on the device. 
192  * 
193  **/
194 void
195 g_file_monitor_set_rate_limit (GFileMonitor *monitor,
196                                int           limit_msecs)
197 {
198   g_return_if_fail (G_IS_FILE_MONITOR (monitor));
199
200   monitor->priv->rate_limit_msec = limit_msecs;
201 }
202
203 static guint32
204 get_time_msecs (void)
205 {
206   return g_thread_gettime() / (1000 * 1000);
207 }
208
209 static guint32
210 time_difference (guint32 from, guint32 to)
211 {
212   if (from > to)
213     return 0;
214   return to - from;
215 }
216
217 /* Change event rate limiting support: */
218
219 static void
220 update_last_sent_change (GFileMonitor *monitor, GFile *file, guint32 time_now)
221 {
222   if (monitor->priv->last_sent_change_file != file)
223     {
224       if (monitor->priv->last_sent_change_file)
225         {
226           g_object_unref (monitor->priv->last_sent_change_file);
227           monitor->priv->last_sent_change_file = NULL;
228         }
229       if (file)
230         monitor->priv->last_sent_change_file = g_object_ref (file);
231     }
232   
233   monitor->priv->last_sent_change_time = time_now;
234 }
235
236 static void
237 send_delayed_change_now (GFileMonitor *monitor)
238 {
239   if (monitor->priv->send_delayed_change_timeout)
240     {
241       g_signal_emit (monitor, signals[CHANGED], 0,
242                      monitor->priv->last_sent_change_file, NULL,
243                      G_FILE_MONITOR_EVENT_CHANGED);
244       
245       g_source_remove (monitor->priv->send_delayed_change_timeout);
246       monitor->priv->send_delayed_change_timeout = 0;
247
248       /* Same file, new last_sent time */
249       monitor->priv->last_sent_change_time = get_time_msecs ();
250     }
251 }
252
253 static gboolean
254 delayed_changed_event_timeout (gpointer data)
255 {
256   GFileMonitor *monitor = data;
257
258   send_delayed_change_now (monitor);
259   
260   return FALSE;
261 }
262
263 static void
264 schedule_delayed_change (GFileMonitor *monitor, GFile *file, guint32 delay_msec)
265 {
266   if (monitor->priv->send_delayed_change_timeout == 0) /* Only set the timeout once */
267     {
268       monitor->priv->send_delayed_change_timeout = 
269         g_timeout_add (delay_msec, delayed_changed_event_timeout, monitor);
270     }
271 }
272
273 static void
274 cancel_delayed_change (GFileMonitor *monitor)
275 {
276   if (monitor->priv->send_delayed_change_timeout != 0)
277     {
278       g_source_remove (monitor->priv->send_delayed_change_timeout);
279       monitor->priv->send_delayed_change_timeout = 0;
280     }
281 }
282
283 /* Virtual changes_done_hint support: */
284
285 static void
286 send_virtual_changes_done_now (GFileMonitor *monitor)
287 {
288   if (monitor->priv->virtual_changes_done_timeout)
289     {
290       g_signal_emit (monitor, signals[CHANGED], 0,
291                      monitor->priv->virtual_changes_done_file, NULL,
292                      G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT);
293       
294       g_source_destroy (monitor->priv->virtual_changes_done_timeout);
295       monitor->priv->virtual_changes_done_timeout = NULL;
296
297       g_object_unref (monitor->priv->virtual_changes_done_file);
298       monitor->priv->virtual_changes_done_file = NULL;
299     }
300 }
301
302 static gboolean
303 virtual_changes_done_timeout (gpointer data)
304 {
305   GFileMonitor *monitor = data;
306
307   send_virtual_changes_done_now (monitor);
308   
309   return FALSE;
310 }
311
312 static void
313 schedule_virtual_change_done (GFileMonitor *monitor, GFile *file)
314 {
315   GSource *source;
316   
317   source = g_timeout_source_new_seconds (DEFAULT_VIRTUAL_CHANGES_DONE_DELAY_SECS);
318   
319   g_source_set_callback (source, virtual_changes_done_timeout, monitor, NULL);
320   g_source_attach (source, NULL);
321   monitor->priv->virtual_changes_done_timeout = source;
322   monitor->priv->virtual_changes_done_file = g_object_ref (file);
323   g_source_unref (source);
324 }
325
326 static void
327 cancel_virtual_changes_done (GFileMonitor *monitor)
328 {
329   if (monitor->priv->virtual_changes_done_timeout)
330     {
331       g_source_destroy (monitor->priv->virtual_changes_done_timeout);
332       monitor->priv->virtual_changes_done_timeout = NULL;
333       
334       g_object_unref (monitor->priv->virtual_changes_done_file);
335       monitor->priv->virtual_changes_done_file = NULL;
336     }
337 }
338
339 /**
340  * g_file_monitor_emit_event:
341  * @monitor: a #GFileMonitor.
342  * @file: a #GFile.
343  * @other_file: a #GFile.
344  * @event_type: a #GFileMonitorEvent
345  * 
346  * Emits a file monitor event. This is mainly necessary for implementations
347  * of GFileMonitor.
348  * 
349  **/
350 void
351 g_file_monitor_emit_event (GFileMonitor *monitor,
352                            GFile *file,
353                            GFile *other_file,
354                            GFileMonitorEvent event_type)
355 {
356   guint32 time_now, since_last;
357   gboolean emit_now;
358
359   g_return_if_fail (G_IS_FILE_MONITOR (monitor));
360   g_return_if_fail (G_IS_FILE (file));
361
362   if (event_type != G_FILE_MONITOR_EVENT_CHANGED)
363     {
364       send_delayed_change_now (monitor);
365       update_last_sent_change (monitor, NULL, 0);
366       if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
367         cancel_virtual_changes_done (monitor);
368       else
369         send_virtual_changes_done_now (monitor);
370       g_signal_emit (monitor, signals[CHANGED], 0, file, other_file, event_type);
371     }
372   else
373     {
374       time_now = get_time_msecs ();
375       emit_now = TRUE;
376       
377       if (monitor->priv->last_sent_change_file)
378         {
379           since_last = time_difference (monitor->priv->last_sent_change_time, time_now);
380           if (since_last < monitor->priv->rate_limit_msec)
381             {
382               /* We ignore this change, but arm a timer so that we can fire it later if we
383                  don't get any other events (that kill this timeout) */
384               emit_now = FALSE;
385               schedule_delayed_change (monitor, file,
386                                        monitor->priv->rate_limit_msec - since_last);
387             }
388         }
389       
390       if (emit_now)
391         {
392           g_signal_emit (monitor, signals[CHANGED], 0, file, other_file, event_type);
393           
394           cancel_delayed_change (monitor);
395           update_last_sent_change (monitor, file, time_now);
396         }
397
398       /* Schedule a virtual change done. This is removed if we get a real one, and
399          postponed if we get more change events. */
400       cancel_virtual_changes_done (monitor);
401       schedule_virtual_change_done (monitor, file);
402     }
403 }