More trivial doc fixes
[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: a #GFileMonitor
149  * 
150  * Returns whether the monitor is canceled.
151  *
152  * Returns: %TRUE if monitor is canceled. %FALSE otherwise.
153  **/
154 gboolean
155 g_file_monitor_is_cancelled (GFileMonitor *monitor)
156 {
157   g_return_val_if_fail (G_IS_FILE_MONITOR (monitor), FALSE);
158
159   return monitor->priv->cancelled;
160 }
161
162 /**
163  * g_file_monitor_cancel:
164  * @monitor: a #GFileMonitor.
165  * 
166  * Cancels a file monitor.
167  * 
168  * Returns: %TRUE if monitor was cancelled.
169  **/
170 gboolean
171 g_file_monitor_cancel (GFileMonitor* monitor)
172 {
173   GFileMonitorClass *klass;
174   
175   g_return_val_if_fail (G_IS_FILE_MONITOR (monitor), FALSE);
176   
177   if (monitor->priv->cancelled)
178     return TRUE;
179   
180   monitor->priv->cancelled = TRUE;
181   
182   klass = G_FILE_MONITOR_GET_CLASS (monitor);
183   return (* klass->cancel) (monitor);
184 }
185
186 /**
187  * g_file_monitor_set_rate_limit:
188  * @monitor: a #GFileMonitor.
189  * @limit_msecs: a integer with the limit in milliseconds to 
190  * poll for changes.
191  *
192  * Sets the rate limit to which the @monitor will poll for changes 
193  * on the device. 
194  * 
195  **/
196 void
197 g_file_monitor_set_rate_limit (GFileMonitor *monitor,
198                                int           limit_msecs)
199 {
200   g_return_if_fail (G_IS_FILE_MONITOR (monitor));
201
202   monitor->priv->rate_limit_msec = limit_msecs;
203 }
204
205 static guint32
206 get_time_msecs (void)
207 {
208   return g_thread_gettime() / (1000 * 1000);
209 }
210
211 static guint32
212 time_difference (guint32 from, guint32 to)
213 {
214   if (from > to)
215     return 0;
216   return to - from;
217 }
218
219 /* Change event rate limiting support: */
220
221 static void
222 update_last_sent_change (GFileMonitor *monitor, GFile *file, guint32 time_now)
223 {
224   if (monitor->priv->last_sent_change_file != file)
225     {
226       if (monitor->priv->last_sent_change_file)
227         {
228           g_object_unref (monitor->priv->last_sent_change_file);
229           monitor->priv->last_sent_change_file = NULL;
230         }
231       if (file)
232         monitor->priv->last_sent_change_file = g_object_ref (file);
233     }
234   
235   monitor->priv->last_sent_change_time = time_now;
236 }
237
238 static void
239 send_delayed_change_now (GFileMonitor *monitor)
240 {
241   if (monitor->priv->send_delayed_change_timeout)
242     {
243       g_signal_emit (monitor, signals[CHANGED], 0,
244                      monitor->priv->last_sent_change_file, NULL,
245                      G_FILE_MONITOR_EVENT_CHANGED);
246       
247       g_source_remove (monitor->priv->send_delayed_change_timeout);
248       monitor->priv->send_delayed_change_timeout = 0;
249
250       /* Same file, new last_sent time */
251       monitor->priv->last_sent_change_time = get_time_msecs ();
252     }
253 }
254
255 static gboolean
256 delayed_changed_event_timeout (gpointer data)
257 {
258   GFileMonitor *monitor = data;
259
260   send_delayed_change_now (monitor);
261   
262   return FALSE;
263 }
264
265 static void
266 schedule_delayed_change (GFileMonitor *monitor, GFile *file, guint32 delay_msec)
267 {
268   if (monitor->priv->send_delayed_change_timeout == 0) /* Only set the timeout once */
269     {
270       monitor->priv->send_delayed_change_timeout = 
271         g_timeout_add (delay_msec, delayed_changed_event_timeout, monitor);
272     }
273 }
274
275 static void
276 cancel_delayed_change (GFileMonitor *monitor)
277 {
278   if (monitor->priv->send_delayed_change_timeout != 0)
279     {
280       g_source_remove (monitor->priv->send_delayed_change_timeout);
281       monitor->priv->send_delayed_change_timeout = 0;
282     }
283 }
284
285 /* Virtual changes_done_hint support: */
286
287 static void
288 send_virtual_changes_done_now (GFileMonitor *monitor)
289 {
290   if (monitor->priv->virtual_changes_done_timeout)
291     {
292       g_signal_emit (monitor, signals[CHANGED], 0,
293                      monitor->priv->virtual_changes_done_file, NULL,
294                      G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT);
295       
296       g_source_destroy (monitor->priv->virtual_changes_done_timeout);
297       monitor->priv->virtual_changes_done_timeout = NULL;
298
299       g_object_unref (monitor->priv->virtual_changes_done_file);
300       monitor->priv->virtual_changes_done_file = NULL;
301     }
302 }
303
304 static gboolean
305 virtual_changes_done_timeout (gpointer data)
306 {
307   GFileMonitor *monitor = data;
308
309   send_virtual_changes_done_now (monitor);
310   
311   return FALSE;
312 }
313
314 static void
315 schedule_virtual_change_done (GFileMonitor *monitor, GFile *file)
316 {
317   GSource *source;
318   
319   source = g_timeout_source_new_seconds (DEFAULT_VIRTUAL_CHANGES_DONE_DELAY_SECS);
320   
321   g_source_set_callback (source, virtual_changes_done_timeout, monitor, NULL);
322   g_source_attach (source, NULL);
323   monitor->priv->virtual_changes_done_timeout = source;
324   monitor->priv->virtual_changes_done_file = g_object_ref (file);
325   g_source_unref (source);
326 }
327
328 static void
329 cancel_virtual_changes_done (GFileMonitor *monitor)
330 {
331   if (monitor->priv->virtual_changes_done_timeout)
332     {
333       g_source_destroy (monitor->priv->virtual_changes_done_timeout);
334       monitor->priv->virtual_changes_done_timeout = NULL;
335       
336       g_object_unref (monitor->priv->virtual_changes_done_file);
337       monitor->priv->virtual_changes_done_file = NULL;
338     }
339 }
340
341 /**
342  * g_file_monitor_emit_event:
343  * @monitor: a #GFileMonitor.
344  * @file: a #GFile.
345  * @other_file: a #GFile.
346  * @event_type: a #GFileMonitorEvent
347  * 
348  * Emits a file monitor event. This is mainly necessary for implementations
349  * of GFileMonitor.
350  * 
351  **/
352 void
353 g_file_monitor_emit_event (GFileMonitor *monitor,
354                            GFile *file,
355                            GFile *other_file,
356                            GFileMonitorEvent event_type)
357 {
358   guint32 time_now, since_last;
359   gboolean emit_now;
360
361   g_return_if_fail (G_IS_FILE_MONITOR (monitor));
362   g_return_if_fail (G_IS_FILE (file));
363
364   if (event_type != G_FILE_MONITOR_EVENT_CHANGED)
365     {
366       send_delayed_change_now (monitor);
367       update_last_sent_change (monitor, NULL, 0);
368       if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
369         cancel_virtual_changes_done (monitor);
370       else
371         send_virtual_changes_done_now (monitor);
372       g_signal_emit (monitor, signals[CHANGED], 0, file, other_file, event_type);
373     }
374   else
375     {
376       time_now = get_time_msecs ();
377       emit_now = TRUE;
378       
379       if (monitor->priv->last_sent_change_file)
380         {
381           since_last = time_difference (monitor->priv->last_sent_change_time, time_now);
382           if (since_last < monitor->priv->rate_limit_msec)
383             {
384               /* We ignore this change, but arm a timer so that we can fire it later if we
385                  don't get any other events (that kill this timeout) */
386               emit_now = FALSE;
387               schedule_delayed_change (monitor, file,
388                                        monitor->priv->rate_limit_msec - since_last);
389             }
390         }
391       
392       if (emit_now)
393         {
394           g_signal_emit (monitor, signals[CHANGED], 0, file, other_file, event_type);
395           
396           cancel_delayed_change (monitor);
397           update_last_sent_change (monitor, file, time_now);
398         }
399
400       /* Schedule a virtual change done. This is removed if we get a real one, and
401          postponed if we get more change events. */
402       cancel_virtual_changes_done (monitor);
403       schedule_virtual_change_done (monitor, file);
404     }
405 }