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