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 "gioenumtypes.h"
34 typedef struct _FileChange FileChange
;
35 static void file_change_free (FileChange
*change
);
38 * SECTION:gfilemonitor
39 * @short_description: File Monitor
42 * Monitors a file or directory for changes.
44 * To obtain a #GFileMonitor for a file or directory, use
45 * g_file_monitor(), g_file_monitor_file(), or
46 * g_file_monitor_directory().
48 * To get informed about changes to the file or directory you are
49 * monitoring, connect to the #GFileMonitor::changed signal. The
50 * signal will be emitted in the <link
51 * linkend="g-main-context-push-thread-default">thread-default main
52 * context</link> of the thread that the monitor was created in
53 * (though if the global default main context is blocked, this may
54 * cause notifications to be blocked even if the thread-default
55 * context is still running).
58 G_LOCK_DEFINE_STATIC(cancelled
);
65 /* work around a limitation of the aliasing foo */
68 G_DEFINE_ABSTRACT_TYPE (GFileMonitor
, g_file_monitor
, G_TYPE_OBJECT
);
72 guint32 last_sent_change_time
; /* 0 == not sent */
73 guint32 send_delayed_change_at
; /* 0 == never */
74 guint32 send_virtual_changes_done_at
; /* 0 == never */
77 struct _GFileMonitorPrivate
{
81 /* Rate limiting change events */
82 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 g_main_context_unref (monitor
->priv
->context
);
180 g_mutex_clear (&monitor
->priv
->mutex
);
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_free_full (priv
->pending_file_changes
, (GDestroyNotify
) file_change_free
);
201 priv
->pending_file_changes
= NULL
;
203 /* Make sure we cancel on last unref */
204 g_file_monitor_cancel (monitor
);
206 G_OBJECT_CLASS (g_file_monitor_parent_class
)->dispose (object
);
210 g_file_monitor_class_init (GFileMonitorClass
*klass
)
212 GObjectClass
*object_class
;
214 g_type_class_add_private (klass
, sizeof (GFileMonitorPrivate
));
216 object_class
= G_OBJECT_CLASS (klass
);
217 object_class
->finalize
= g_file_monitor_finalize
;
218 object_class
->dispose
= g_file_monitor_dispose
;
219 object_class
->get_property
= g_file_monitor_get_property
;
220 object_class
->set_property
= g_file_monitor_set_property
;
223 * GFileMonitor::changed:
224 * @monitor: a #GFileMonitor.
226 * @other_file: (allow-none): a #GFile or #NULL.
227 * @event_type: a #GFileMonitorEvent.
229 * Emitted when @file has been changed.
231 * If using #G_FILE_MONITOR_SEND_MOVED flag and @event_type is
232 * #G_FILE_MONITOR_EVENT_MOVED, @file will be set to a #GFile containing the
233 * old path, and @other_file will be set to a #GFile containing the new path.
235 * In all the other cases, @other_file will be set to #NULL.
238 g_signal_new (I_("changed"),
241 G_STRUCT_OFFSET (GFileMonitorClass
, changed
),
245 G_TYPE_FILE
, G_TYPE_FILE
, G_TYPE_FILE_MONITOR_EVENT
);
247 g_object_class_install_property (object_class
,
249 g_param_spec_int ("rate-limit",
251 P_("The limit of the monitor to watch for changes, in milliseconds"),
253 DEFAULT_RATE_LIMIT_MSECS
,
255 G_PARAM_STATIC_NAME
|G_PARAM_STATIC_NICK
|G_PARAM_STATIC_BLURB
));
257 g_object_class_install_property (object_class
,
259 g_param_spec_boolean ("cancelled",
261 P_("Whether the monitor has been cancelled"),
264 G_PARAM_STATIC_NAME
|G_PARAM_STATIC_NICK
|G_PARAM_STATIC_BLURB
));
268 g_file_monitor_init (GFileMonitor
*monitor
)
270 monitor
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (monitor
,
272 GFileMonitorPrivate
);
273 monitor
->priv
->rate_limit_msec
= DEFAULT_RATE_LIMIT_MSECS
;
274 monitor
->priv
->rate_limiter
= g_hash_table_new_full (g_file_hash
, (GEqualFunc
)g_file_equal
,
275 NULL
, (GDestroyNotify
) rate_limiter_free
);
276 monitor
->priv
->context
= g_main_context_ref_thread_default ();
277 g_mutex_init (&monitor
->priv
->mutex
);
281 * g_file_monitor_is_cancelled:
282 * @monitor: a #GFileMonitor
284 * Returns whether the monitor is canceled.
286 * Returns: %TRUE if monitor is canceled. %FALSE otherwise.
289 g_file_monitor_is_cancelled (GFileMonitor
*monitor
)
293 g_return_val_if_fail (G_IS_FILE_MONITOR (monitor
), FALSE
);
296 res
= monitor
->priv
->cancelled
;
297 G_UNLOCK (cancelled
);
303 * g_file_monitor_cancel:
304 * @monitor: a #GFileMonitor.
306 * Cancels a file monitor.
308 * Returns: %TRUE if monitor was cancelled.
311 g_file_monitor_cancel (GFileMonitor
* monitor
)
313 GFileMonitorClass
*klass
;
315 g_return_val_if_fail (G_IS_FILE_MONITOR (monitor
), FALSE
);
318 if (monitor
->priv
->cancelled
)
320 G_UNLOCK (cancelled
);
324 monitor
->priv
->cancelled
= TRUE
;
325 G_UNLOCK (cancelled
);
327 g_object_notify (G_OBJECT (monitor
), "cancelled");
329 klass
= G_FILE_MONITOR_GET_CLASS (monitor
);
330 return (* klass
->cancel
) (monitor
);
334 * g_file_monitor_set_rate_limit:
335 * @monitor: a #GFileMonitor.
336 * @limit_msecs: a non-negative integer with the limit in milliseconds
337 * to poll for changes
339 * Sets the rate limit to which the @monitor will report
340 * consecutive change events to the same file.
343 g_file_monitor_set_rate_limit (GFileMonitor
*monitor
,
346 GFileMonitorPrivate
*priv
;
348 g_return_if_fail (G_IS_FILE_MONITOR (monitor
));
349 g_return_if_fail (limit_msecs
>= 0);
351 priv
= monitor
->priv
;
352 if (priv
->rate_limit_msec
!= limit_msecs
)
354 monitor
->priv
->rate_limit_msec
= limit_msecs
;
355 g_object_notify (G_OBJECT (monitor
), "rate-limit");
362 GFileMonitorEvent event_type
;
366 file_change_free (FileChange
*change
)
368 g_object_unref (change
->child
);
369 if (change
->other_file
)
370 g_object_unref (change
->other_file
);
372 g_slice_free (FileChange
, change
);
376 emit_cb (gpointer data
)
378 GFileMonitor
*monitor
= G_FILE_MONITOR (data
);
379 GSList
*pending
, *iter
;
381 g_mutex_lock (&monitor
->priv
->mutex
);
382 pending
= g_slist_reverse (monitor
->priv
->pending_file_changes
);
383 monitor
->priv
->pending_file_changes
= NULL
;
384 if (monitor
->priv
->pending_file_change_source
)
386 g_source_unref (monitor
->priv
->pending_file_change_source
);
387 monitor
->priv
->pending_file_change_source
= NULL
;
389 g_mutex_unlock (&monitor
->priv
->mutex
);
391 g_object_ref (monitor
);
392 for (iter
= pending
; iter
; iter
= iter
->next
)
394 FileChange
*change
= iter
->data
;
396 g_signal_emit (monitor
, signals
[CHANGED
], 0,
397 change
->child
, change
->other_file
, change
->event_type
);
398 file_change_free (change
);
400 g_slist_free (pending
);
401 g_object_unref (monitor
);
407 emit_in_idle (GFileMonitor
*monitor
,
410 GFileMonitorEvent event_type
)
414 GFileMonitorPrivate
*priv
;
416 priv
= monitor
->priv
;
418 change
= g_slice_new (FileChange
);
420 change
->child
= g_object_ref (child
);
422 change
->other_file
= g_object_ref (other_file
);
424 change
->other_file
= NULL
;
425 change
->event_type
= event_type
;
427 g_mutex_lock (&monitor
->priv
->mutex
);
428 if (!priv
->pending_file_change_source
)
430 source
= g_idle_source_new ();
431 priv
->pending_file_change_source
= source
;
432 g_source_set_priority (source
, 0);
434 /* We don't ref monitor here - instead dispose will free any
437 g_source_set_callback (source
, emit_cb
, monitor
, NULL
);
438 g_source_attach (source
, monitor
->priv
->context
);
440 /* We reverse this in the processor */
441 priv
->pending_file_changes
= g_slist_prepend (priv
->pending_file_changes
, change
);
442 g_mutex_unlock (&monitor
->priv
->mutex
);
446 get_time_msecs (void)
448 return g_get_monotonic_time () / G_TIME_SPAN_MILLISECOND
;
452 time_difference (guint32 from
, guint32 to
)
459 /* Change event rate limiting support: */
462 new_limiter (GFileMonitor
*monitor
,
465 RateLimiter
*limiter
;
467 limiter
= g_slice_new0 (RateLimiter
);
468 limiter
->file
= g_object_ref (file
);
469 g_hash_table_insert (monitor
->priv
->rate_limiter
, file
, limiter
);
475 rate_limiter_send_virtual_changes_done_now (GFileMonitor
*monitor
,
476 RateLimiter
*limiter
)
478 if (limiter
->send_virtual_changes_done_at
!= 0)
480 emit_in_idle (monitor
, limiter
->file
, NULL
,
481 G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
);
482 limiter
->send_virtual_changes_done_at
= 0;
487 rate_limiter_send_delayed_change_now (GFileMonitor
*monitor
,
488 RateLimiter
*limiter
,
491 if (limiter
->send_delayed_change_at
!= 0)
493 emit_in_idle (monitor
,
495 G_FILE_MONITOR_EVENT_CHANGED
);
496 limiter
->send_delayed_change_at
= 0;
497 limiter
->last_sent_change_time
= time_now
;
504 GFileMonitor
*monitor
;
508 calc_min_time (GFileMonitor
*monitor
,
509 RateLimiter
*limiter
,
518 if (limiter
->last_sent_change_time
!= 0)
520 /* Set a timeout at 2*rate limit so that we can clear out the change from the hash eventually */
521 expire_at
= limiter
->last_sent_change_time
+ 2 * monitor
->priv
->rate_limit_msec
;
523 if (time_difference (time_now
, expire_at
) > 0)
526 *min_time
= MIN (*min_time
,
527 time_difference (time_now
, expire_at
));
531 if (limiter
->send_delayed_change_at
!= 0)
534 *min_time
= MIN (*min_time
,
535 time_difference (time_now
, limiter
->send_delayed_change_at
));
538 if (limiter
->send_virtual_changes_done_at
!= 0)
541 *min_time
= MIN (*min_time
,
542 time_difference (time_now
, limiter
->send_virtual_changes_done_at
));
549 foreach_rate_limiter_fire (gpointer key
,
553 RateLimiter
*limiter
= value
;
554 ForEachData
*data
= user_data
;
556 if (limiter
->send_delayed_change_at
!= 0 &&
557 time_difference (data
->time_now
, limiter
->send_delayed_change_at
) == 0)
558 rate_limiter_send_delayed_change_now (data
->monitor
, limiter
, data
->time_now
);
560 if (limiter
->send_virtual_changes_done_at
!= 0 &&
561 time_difference (data
->time_now
, limiter
->send_virtual_changes_done_at
) == 0)
562 rate_limiter_send_virtual_changes_done_now (data
->monitor
, limiter
);
564 return calc_min_time (data
->monitor
, limiter
, data
->time_now
, &data
->min_time
);
568 rate_limiter_timeout (gpointer timeout_data
)
570 GFileMonitor
*monitor
= timeout_data
;
574 data
.min_time
= G_MAXUINT32
;
575 data
.monitor
= monitor
;
576 data
.time_now
= get_time_msecs ();
577 g_hash_table_foreach_remove (monitor
->priv
->rate_limiter
,
578 foreach_rate_limiter_fire
,
581 /* Remove old timeout */
582 if (monitor
->priv
->timeout
)
584 g_source_destroy (monitor
->priv
->timeout
);
585 g_source_unref (monitor
->priv
->timeout
);
586 monitor
->priv
->timeout
= NULL
;
587 monitor
->priv
->timeout_fires_at
= 0;
590 /* Set up new timeout */
591 if (data
.min_time
!= G_MAXUINT32
)
593 source
= g_timeout_source_new (data
.min_time
+ 1); /* + 1 to make sure we've really passed the time */
594 g_source_set_callback (source
, rate_limiter_timeout
, monitor
, NULL
);
595 g_source_attach (source
, monitor
->priv
->context
);
597 monitor
->priv
->timeout
= source
;
598 monitor
->priv
->timeout_fires_at
= data
.time_now
+ data
.min_time
;
605 foreach_rate_limiter_update (gpointer key
,
609 RateLimiter
*limiter
= value
;
610 ForEachData
*data
= user_data
;
612 return calc_min_time (data
->monitor
, limiter
, data
->time_now
, &data
->min_time
);
616 update_rate_limiter_timeout (GFileMonitor
*monitor
,
622 if (monitor
->priv
->timeout_fires_at
!= 0 && new_time
!= 0 &&
623 time_difference (new_time
, monitor
->priv
->timeout_fires_at
) == 0)
624 return; /* Nothing to do, we already fire earlier than that */
626 data
.min_time
= G_MAXUINT32
;
627 data
.monitor
= monitor
;
628 data
.time_now
= get_time_msecs ();
629 g_hash_table_foreach_remove (monitor
->priv
->rate_limiter
,
630 foreach_rate_limiter_update
,
633 /* Remove old timeout */
634 if (monitor
->priv
->timeout
)
636 g_source_destroy (monitor
->priv
->timeout
);
637 g_source_unref (monitor
->priv
->timeout
);
638 monitor
->priv
->timeout_fires_at
= 0;
639 monitor
->priv
->timeout
= NULL
;
642 /* Set up new timeout */
643 if (data
.min_time
!= G_MAXUINT32
)
645 source
= g_timeout_source_new (data
.min_time
+ 1); /* + 1 to make sure we've really passed the time */
646 g_source_set_callback (source
, rate_limiter_timeout
, monitor
, NULL
);
647 g_source_attach (source
, monitor
->priv
->context
);
649 monitor
->priv
->timeout
= source
;
650 monitor
->priv
->timeout_fires_at
= data
.time_now
+ data
.min_time
;
655 * g_file_monitor_emit_event:
656 * @monitor: a #GFileMonitor.
658 * @other_file: a #GFile.
659 * @event_type: a set of #GFileMonitorEvent flags.
661 * Emits the #GFileMonitor::changed signal if a change
662 * has taken place. Should be called from file monitor
663 * implementations only.
665 * The signal will be emitted from an idle handler (in the <link
666 * linkend="g-main-context-push-thread-default">thread-default main
670 g_file_monitor_emit_event (GFileMonitor
*monitor
,
673 GFileMonitorEvent event_type
)
675 guint32 time_now
, since_last
;
677 RateLimiter
*limiter
;
679 g_return_if_fail (G_IS_FILE_MONITOR (monitor
));
680 g_return_if_fail (G_IS_FILE (child
));
682 limiter
= g_hash_table_lookup (monitor
->priv
->rate_limiter
, child
);
684 if (event_type
!= G_FILE_MONITOR_EVENT_CHANGED
)
688 rate_limiter_send_delayed_change_now (monitor
, limiter
, get_time_msecs ());
689 if (event_type
== G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
)
690 limiter
->send_virtual_changes_done_at
= 0;
692 rate_limiter_send_virtual_changes_done_now (monitor
, limiter
);
693 update_rate_limiter_timeout (monitor
, 0);
695 emit_in_idle (monitor
, child
, other_file
, event_type
);
699 /* Changed event, rate limit */
700 time_now
= get_time_msecs ();
705 since_last
= time_difference (limiter
->last_sent_change_time
, time_now
);
706 if (since_last
< monitor
->priv
->rate_limit_msec
)
708 /* We ignore this change, but arm a timer so that we can fire it later if we
709 don't get any other events (that kill this timeout) */
711 if (limiter
->send_delayed_change_at
== 0)
713 limiter
->send_delayed_change_at
= time_now
+ monitor
->priv
->rate_limit_msec
;
714 update_rate_limiter_timeout (monitor
, limiter
->send_delayed_change_at
);
720 limiter
= new_limiter (monitor
, child
);
724 emit_in_idle (monitor
, child
, other_file
, event_type
);
726 limiter
->last_sent_change_time
= time_now
;
727 limiter
->send_delayed_change_at
= 0;
728 /* Set a timeout of 2*rate limit so that we can clear out the change from the hash eventually */
729 update_rate_limiter_timeout (monitor
, time_now
+ 2 * monitor
->priv
->rate_limit_msec
);
732 /* Schedule a virtual change done. This is removed if we get a real one, and
733 postponed if we get more change events. */
735 limiter
->send_virtual_changes_done_at
= time_now
+ DEFAULT_VIRTUAL_CHANGES_DONE_DELAY_SECS
* 1000;
736 update_rate_limiter_timeout (monitor
, limiter
->send_virtual_changes_done_at
);