1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
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.
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.
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.
20 * Author: Alexander Larsson <alexl@redhat.com>
26 #include "gfilemonitor.h"
27 #include "gio-marshal.h"
28 #include "gioenumtypes.h"
35 typedef struct _FileChange FileChange
;
36 static void file_change_free (FileChange
*change
);
39 * SECTION:gfilemonitor
40 * @short_description: File Monitor
43 * Monitors a file or directory for changes.
45 * To obtain a #GFileMonitor for a file or directory, use
46 * g_file_monitor(), g_file_monitor_file(), or
47 * g_file_monitor_directory().
49 * To get informed about changes to the file or directory you are
50 * monitoring, connect to the #GFileMonitor::changed signal. The
51 * signal will be emitted in the <link
52 * linkend="g-main-context-push-thread-default">thread-default main
53 * context</link> of the thread that the monitor was created in
54 * (though if the global default main context is blocked, this may
55 * cause notifications to be blocked even if the thread-default
56 * context is still running).
59 G_LOCK_DEFINE_STATIC(cancelled
);
66 /* work around a limitation of the aliasing foo */
69 G_DEFINE_ABSTRACT_TYPE (GFileMonitor
, g_file_monitor
, G_TYPE_OBJECT
);
73 guint32 last_sent_change_time
; /* 0 == not sent */
74 guint32 send_delayed_change_at
; /* 0 == never */
75 guint32 send_virtual_changes_done_at
; /* 0 == never */
78 struct _GFileMonitorPrivate
{
82 /* Rate limiting change events */
83 GHashTable
*rate_limiter
;
85 GSource
*pending_file_change_source
;
86 GSList
*pending_file_changes
; /* FileChange */
89 guint32 timeout_fires_at
;
91 GMainContext
*context
;
101 g_file_monitor_set_property (GObject
*object
,
106 GFileMonitor
*monitor
;
108 monitor
= G_FILE_MONITOR (object
);
112 case PROP_RATE_LIMIT
:
113 g_file_monitor_set_rate_limit (monitor
, g_value_get_int (value
));
117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
123 g_file_monitor_get_property (GObject
*object
,
128 GFileMonitor
*monitor
;
129 GFileMonitorPrivate
*priv
;
131 monitor
= G_FILE_MONITOR (object
);
132 priv
= monitor
->priv
;
136 case PROP_RATE_LIMIT
:
137 g_value_set_int (value
, priv
->rate_limit_msec
);
142 g_value_set_boolean (value
, priv
->cancelled
);
143 G_UNLOCK (cancelled
);
147 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
152 #define DEFAULT_RATE_LIMIT_MSECS 800
153 #define DEFAULT_VIRTUAL_CHANGES_DONE_DELAY_SECS 2
155 static guint signals
[LAST_SIGNAL
] = { 0 };
158 rate_limiter_free (RateLimiter
*limiter
)
160 g_object_unref (limiter
->file
);
161 g_slice_free (RateLimiter
, limiter
);
165 g_file_monitor_finalize (GObject
*object
)
167 GFileMonitor
*monitor
;
169 monitor
= G_FILE_MONITOR (object
);
171 if (monitor
->priv
->timeout
)
173 g_source_destroy (monitor
->priv
->timeout
);
174 g_source_unref (monitor
->priv
->timeout
);
177 g_hash_table_destroy (monitor
->priv
->rate_limiter
);
179 if (monitor
->priv
->context
)
180 g_main_context_unref (monitor
->priv
->context
);
182 G_OBJECT_CLASS (g_file_monitor_parent_class
)->finalize (object
);
186 g_file_monitor_dispose (GObject
*object
)
188 GFileMonitor
*monitor
;
189 GFileMonitorPrivate
*priv
;
191 monitor
= G_FILE_MONITOR (object
);
192 priv
= monitor
->priv
;
194 if (priv
->pending_file_change_source
)
196 g_source_destroy (priv
->pending_file_change_source
);
197 g_source_unref (priv
->pending_file_change_source
);
198 priv
->pending_file_change_source
= NULL
;
200 g_slist_foreach (priv
->pending_file_changes
, (GFunc
) file_change_free
, NULL
);
201 g_slist_free (priv
->pending_file_changes
);
202 priv
->pending_file_changes
= NULL
;
204 /* Make sure we cancel on last unref */
205 g_file_monitor_cancel (monitor
);
207 G_OBJECT_CLASS (g_file_monitor_parent_class
)->dispose (object
);
211 g_file_monitor_class_init (GFileMonitorClass
*klass
)
213 GObjectClass
*object_class
;
215 g_type_class_add_private (klass
, sizeof (GFileMonitorPrivate
));
217 object_class
= G_OBJECT_CLASS (klass
);
218 object_class
->finalize
= g_file_monitor_finalize
;
219 object_class
->dispose
= g_file_monitor_dispose
;
220 object_class
->get_property
= g_file_monitor_get_property
;
221 object_class
->set_property
= g_file_monitor_set_property
;
224 * GFileMonitor::changed:
225 * @monitor: a #GFileMonitor.
227 * @other_file: a #GFile.
228 * @event_type: a #GFileMonitorEvent.
230 * Emitted when a file has been changed.
233 g_signal_new (I_("changed"),
236 G_STRUCT_OFFSET (GFileMonitorClass
, changed
),
238 _gio_marshal_VOID__OBJECT_OBJECT_ENUM
,
240 G_TYPE_FILE
, G_TYPE_FILE
, G_TYPE_FILE_MONITOR_EVENT
);
242 g_object_class_install_property (object_class
,
244 g_param_spec_int ("rate-limit",
246 P_("The limit of the monitor to watch for changes, in milliseconds"),
248 DEFAULT_RATE_LIMIT_MSECS
,
250 G_PARAM_STATIC_NAME
|G_PARAM_STATIC_NICK
|G_PARAM_STATIC_BLURB
));
252 g_object_class_install_property (object_class
,
254 g_param_spec_boolean ("cancelled",
256 P_("Whether the monitor has been cancelled"),
259 G_PARAM_STATIC_NAME
|G_PARAM_STATIC_NICK
|G_PARAM_STATIC_BLURB
));
263 g_file_monitor_init (GFileMonitor
*monitor
)
265 monitor
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (monitor
,
267 GFileMonitorPrivate
);
268 monitor
->priv
->rate_limit_msec
= DEFAULT_RATE_LIMIT_MSECS
;
269 monitor
->priv
->rate_limiter
= g_hash_table_new_full (g_file_hash
, (GEqualFunc
)g_file_equal
,
270 NULL
, (GDestroyNotify
) rate_limiter_free
);
271 monitor
->priv
->context
= g_main_context_get_thread_default ();
275 * g_file_monitor_is_cancelled:
276 * @monitor: a #GFileMonitor
278 * Returns whether the monitor is canceled.
280 * Returns: %TRUE if monitor is canceled. %FALSE otherwise.
283 g_file_monitor_is_cancelled (GFileMonitor
*monitor
)
287 g_return_val_if_fail (G_IS_FILE_MONITOR (monitor
), FALSE
);
290 res
= monitor
->priv
->cancelled
;
291 G_UNLOCK (cancelled
);
297 * g_file_monitor_cancel:
298 * @monitor: a #GFileMonitor.
300 * Cancels a file monitor.
302 * Returns: %TRUE if monitor was cancelled.
305 g_file_monitor_cancel (GFileMonitor
* monitor
)
307 GFileMonitorClass
*klass
;
309 g_return_val_if_fail (G_IS_FILE_MONITOR (monitor
), FALSE
);
312 if (monitor
->priv
->cancelled
)
314 G_UNLOCK (cancelled
);
318 monitor
->priv
->cancelled
= TRUE
;
319 G_UNLOCK (cancelled
);
321 g_object_notify (G_OBJECT (monitor
), "cancelled");
323 klass
= G_FILE_MONITOR_GET_CLASS (monitor
);
324 return (* klass
->cancel
) (monitor
);
328 * g_file_monitor_set_rate_limit:
329 * @monitor: a #GFileMonitor.
330 * @limit_msecs: a integer with the limit in milliseconds to
333 * Sets the rate limit to which the @monitor will report
334 * consecutive change events to the same file.
338 g_file_monitor_set_rate_limit (GFileMonitor
*monitor
,
341 GFileMonitorPrivate
*priv
;
343 g_return_if_fail (G_IS_FILE_MONITOR (monitor
));
345 priv
= monitor
->priv
;
346 if (priv
->rate_limit_msec
!= limit_msecs
)
348 monitor
->priv
->rate_limit_msec
= limit_msecs
;
349 g_object_notify (G_OBJECT (monitor
), "rate-limit");
356 GFileMonitorEvent event_type
;
360 file_change_free (FileChange
*change
)
362 g_object_unref (change
->child
);
363 if (change
->other_file
)
364 g_object_unref (change
->other_file
);
366 g_slice_free (FileChange
, change
);
370 emit_cb (gpointer data
)
372 GFileMonitor
*monitor
= G_FILE_MONITOR (data
);
373 GSList
*pending
, *iter
;
375 pending
= g_slist_reverse (monitor
->priv
->pending_file_changes
);
376 monitor
->priv
->pending_file_changes
= NULL
;
377 if (monitor
->priv
->pending_file_change_source
)
379 g_source_unref (monitor
->priv
->pending_file_change_source
);
380 monitor
->priv
->pending_file_change_source
= NULL
;
383 g_object_ref (monitor
);
384 for (iter
= pending
; iter
; iter
= iter
->next
)
386 FileChange
*change
= iter
->data
;
387 g_signal_emit (monitor
, signals
[CHANGED
], 0,
388 change
->child
, change
->other_file
, change
->event_type
);
389 file_change_free (change
);
391 g_slist_free (pending
);
392 g_object_unref (monitor
);
398 emit_in_idle (GFileMonitor
*monitor
,
401 GFileMonitorEvent event_type
)
405 GFileMonitorPrivate
*priv
;
407 priv
= monitor
->priv
;
409 change
= g_slice_new (FileChange
);
411 change
->child
= g_object_ref (child
);
413 change
->other_file
= g_object_ref (other_file
);
415 change
->other_file
= NULL
;
416 change
->event_type
= event_type
;
418 if (!priv
->pending_file_change_source
)
420 source
= g_idle_source_new ();
421 priv
->pending_file_change_source
= source
;
422 g_source_set_priority (source
, 0);
424 /* We don't ref monitor here - instead dispose will free any
427 g_source_set_callback (source
, emit_cb
, monitor
, NULL
);
428 g_source_attach (source
, monitor
->priv
->context
);
430 /* We reverse this in the processor */
431 priv
->pending_file_changes
= g_slist_prepend (priv
->pending_file_changes
, change
);
435 get_time_msecs (void)
437 return g_thread_gettime() / (1000 * 1000);
441 time_difference (guint32 from
, guint32 to
)
448 /* Change event rate limiting support: */
451 new_limiter (GFileMonitor
*monitor
,
454 RateLimiter
*limiter
;
456 limiter
= g_slice_new0 (RateLimiter
);
457 limiter
->file
= g_object_ref (file
);
458 g_hash_table_insert (monitor
->priv
->rate_limiter
, file
, limiter
);
464 rate_limiter_send_virtual_changes_done_now (GFileMonitor
*monitor
,
465 RateLimiter
*limiter
)
467 if (limiter
->send_virtual_changes_done_at
!= 0)
469 emit_in_idle (monitor
, limiter
->file
, NULL
,
470 G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
);
471 limiter
->send_virtual_changes_done_at
= 0;
476 rate_limiter_send_delayed_change_now (GFileMonitor
*monitor
,
477 RateLimiter
*limiter
,
480 if (limiter
->send_delayed_change_at
!= 0)
482 emit_in_idle (monitor
,
484 G_FILE_MONITOR_EVENT_CHANGED
);
485 limiter
->send_delayed_change_at
= 0;
486 limiter
->last_sent_change_time
= time_now
;
493 GFileMonitor
*monitor
;
497 calc_min_time (GFileMonitor
*monitor
,
498 RateLimiter
*limiter
,
507 if (limiter
->last_sent_change_time
!= 0)
509 /* Set a timeout at 2*rate limit so that we can clear out the change from the hash eventualy */
510 expire_at
= limiter
->last_sent_change_time
+ 2 * monitor
->priv
->rate_limit_msec
;
512 if (time_difference (time_now
, expire_at
) > 0)
515 *min_time
= MIN (*min_time
,
516 time_difference (time_now
, expire_at
));
520 if (limiter
->send_delayed_change_at
!= 0)
523 *min_time
= MIN (*min_time
,
524 time_difference (time_now
, limiter
->send_delayed_change_at
));
527 if (limiter
->send_virtual_changes_done_at
!= 0)
530 *min_time
= MIN (*min_time
,
531 time_difference (time_now
, limiter
->send_virtual_changes_done_at
));
538 foreach_rate_limiter_fire (gpointer key
,
542 RateLimiter
*limiter
= value
;
543 ForEachData
*data
= user_data
;
545 if (limiter
->send_delayed_change_at
!= 0 &&
546 time_difference (data
->time_now
, limiter
->send_delayed_change_at
) == 0)
547 rate_limiter_send_delayed_change_now (data
->monitor
, limiter
, data
->time_now
);
549 if (limiter
->send_virtual_changes_done_at
!= 0 &&
550 time_difference (data
->time_now
, limiter
->send_virtual_changes_done_at
) == 0)
551 rate_limiter_send_virtual_changes_done_now (data
->monitor
, limiter
);
553 return calc_min_time (data
->monitor
, limiter
, data
->time_now
, &data
->min_time
);
557 rate_limiter_timeout (gpointer timeout_data
)
559 GFileMonitor
*monitor
= timeout_data
;
563 data
.min_time
= G_MAXUINT32
;
564 data
.monitor
= monitor
;
565 data
.time_now
= get_time_msecs ();
566 g_hash_table_foreach_remove (monitor
->priv
->rate_limiter
,
567 foreach_rate_limiter_fire
,
570 /* Remove old timeout */
571 if (monitor
->priv
->timeout
)
573 g_source_destroy (monitor
->priv
->timeout
);
574 g_source_unref (monitor
->priv
->timeout
);
575 monitor
->priv
->timeout
= NULL
;
576 monitor
->priv
->timeout_fires_at
= 0;
579 /* Set up new timeout */
580 if (data
.min_time
!= G_MAXUINT32
)
582 source
= g_timeout_source_new (data
.min_time
+ 1); /* + 1 to make sure we've really passed the time */
583 g_source_set_callback (source
, rate_limiter_timeout
, monitor
, NULL
);
584 g_source_attach (source
, monitor
->priv
->context
);
586 monitor
->priv
->timeout
= source
;
587 monitor
->priv
->timeout_fires_at
= data
.time_now
+ data
.min_time
;
594 foreach_rate_limiter_update (gpointer key
,
598 RateLimiter
*limiter
= value
;
599 ForEachData
*data
= user_data
;
601 return calc_min_time (data
->monitor
, limiter
, data
->time_now
, &data
->min_time
);
605 update_rate_limiter_timeout (GFileMonitor
*monitor
,
611 if (monitor
->priv
->timeout_fires_at
!= 0 && new_time
!= 0 &&
612 time_difference (new_time
, monitor
->priv
->timeout_fires_at
) == 0)
613 return; /* Nothing to do, we already fire earlier than that */
615 data
.min_time
= G_MAXUINT32
;
616 data
.monitor
= monitor
;
617 data
.time_now
= get_time_msecs ();
618 g_hash_table_foreach_remove (monitor
->priv
->rate_limiter
,
619 foreach_rate_limiter_update
,
622 /* Remove old timeout */
623 if (monitor
->priv
->timeout
)
625 g_source_destroy (monitor
->priv
->timeout
);
626 g_source_unref (monitor
->priv
->timeout
);
627 monitor
->priv
->timeout_fires_at
= 0;
628 monitor
->priv
->timeout
= NULL
;
631 /* Set up new timeout */
632 if (data
.min_time
!= G_MAXUINT32
)
634 source
= g_timeout_source_new (data
.min_time
+ 1); /* + 1 to make sure we've really passed the time */
635 g_source_set_callback (source
, rate_limiter_timeout
, monitor
, NULL
);
636 g_source_attach (source
, monitor
->priv
->context
);
638 monitor
->priv
->timeout
= source
;
639 monitor
->priv
->timeout_fires_at
= data
.time_now
+ data
.min_time
;
644 * g_file_monitor_emit_event:
645 * @monitor: a #GFileMonitor.
647 * @other_file: a #GFile.
648 * @event_type: a set of #GFileMonitorEvent flags.
650 * Emits the #GFileMonitor::changed signal if a change
651 * has taken place. Should be called from file monitor
652 * implementations only.
654 * The signal will be emitted from an idle handler (in the <link
655 * linkend="g-main-context-push-thread-default">thread-default main
659 g_file_monitor_emit_event (GFileMonitor
*monitor
,
662 GFileMonitorEvent event_type
)
664 guint32 time_now
, since_last
;
666 RateLimiter
*limiter
;
668 g_return_if_fail (G_IS_FILE_MONITOR (monitor
));
669 g_return_if_fail (G_IS_FILE (child
));
671 limiter
= g_hash_table_lookup (monitor
->priv
->rate_limiter
, child
);
673 if (event_type
!= G_FILE_MONITOR_EVENT_CHANGED
)
677 rate_limiter_send_delayed_change_now (monitor
, limiter
, get_time_msecs ());
678 if (event_type
== G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
)
679 limiter
->send_virtual_changes_done_at
= 0;
681 rate_limiter_send_virtual_changes_done_now (monitor
, limiter
);
682 update_rate_limiter_timeout (monitor
, 0);
684 emit_in_idle (monitor
, child
, other_file
, event_type
);
688 /* Changed event, rate limit */
689 time_now
= get_time_msecs ();
694 since_last
= time_difference (limiter
->last_sent_change_time
, time_now
);
695 if (since_last
< monitor
->priv
->rate_limit_msec
)
697 /* We ignore this change, but arm a timer so that we can fire it later if we
698 don't get any other events (that kill this timeout) */
700 if (limiter
->send_delayed_change_at
== 0)
702 limiter
->send_delayed_change_at
= time_now
+ monitor
->priv
->rate_limit_msec
;
703 update_rate_limiter_timeout (monitor
, limiter
->send_delayed_change_at
);
709 limiter
= new_limiter (monitor
, child
);
713 emit_in_idle (monitor
, child
, other_file
, event_type
);
715 limiter
->last_sent_change_time
= time_now
;
716 limiter
->send_delayed_change_at
= 0;
717 /* Set a timeout of 2*rate limit so that we can clear out the change from the hash eventualy */
718 update_rate_limiter_timeout (monitor
, time_now
+ 2 * monitor
->priv
->rate_limit_msec
);
721 /* Schedule a virtual change done. This is removed if we get a real one, and
722 postponed if we get more change events. */
724 limiter
->send_virtual_changes_done_at
= time_now
+ DEFAULT_VIRTUAL_CHANGES_DONE_DELAY_SECS
* 1000;
725 update_rate_limiter_timeout (monitor
, limiter
->send_virtual_changes_done_at
);