ci: collect test coverage and deploy a html report through gitlab pages
[glib.git] / gio / glocalfilemonitor.c
blobc19da3ba8c79249f1b3ce317ee9fd77e894d1a2b
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.1 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, see <http://www.gnu.org/licenses/>.
18 * Author: Alexander Larsson <alexl@redhat.com>
21 #include "config.h"
23 #include "gioenumtypes.h"
24 #include "glocalfilemonitor.h"
25 #include "giomodule-priv.h"
26 #include "gioerror.h"
27 #include "glibintl.h"
28 #include "glocalfile.h"
29 #include "glib-private.h"
31 #include <string.h>
33 #define DEFAULT_RATE_LIMIT 800 * G_TIME_SPAN_MILLISECOND
34 #define VIRTUAL_CHANGES_DONE_DELAY 2 * G_TIME_SPAN_SECOND
36 /* GFileMonitorSource is a GSource responsible for emitting the changed
37 * signals in the owner-context of the GFileMonitor.
39 * It contains functionality for cross-thread queuing of events. It
40 * also handles merging of CHANGED events and emission of CHANGES_DONE
41 * events.
43 * We use the "priv" pointer in the external struct to store it.
45 struct _GFileMonitorSource {
46 GSource source;
48 GMutex lock;
49 gpointer instance;
50 GFileMonitorFlags flags;
51 gchar *dirname;
52 gchar *basename;
53 gchar *filename;
54 GSequence *pending_changes; /* sorted by ready time */
55 GHashTable *pending_changes_table;
56 GQueue event_queue;
57 gint64 rate_limit;
60 /* PendingChange is a struct to keep track of a file that needs to have
61 * (at least) a CHANGES_DONE_HINT event sent for it in the near future.
63 * If 'dirty' is TRUE then a CHANGED event also needs to be sent.
65 * last_emission is the last time a CHANGED event was emitted. It is
66 * used to calculate the time to send the next event.
68 typedef struct {
69 gchar *child;
70 guint64 last_emission : 63;
71 guint64 dirty : 1;
72 } PendingChange;
74 /* QueuedEvent is a signal that will be sent immediately, as soon as the
75 * source gets a chance to dispatch. The existence of any queued event
76 * implies that the source is ready now.
78 typedef struct
80 GFileMonitorEvent event_type;
81 GFile *child;
82 GFile *other;
83 } QueuedEvent;
85 static gint64
86 pending_change_get_ready_time (const PendingChange *change,
87 GFileMonitorSource *fms)
89 if (change->dirty)
90 return change->last_emission + fms->rate_limit;
91 else
92 return change->last_emission + VIRTUAL_CHANGES_DONE_DELAY;
95 static int
96 pending_change_compare_ready_time (gconstpointer a_p,
97 gconstpointer b_p,
98 gpointer user_data)
100 GFileMonitorSource *fms = user_data;
101 const PendingChange *a = a_p;
102 const PendingChange *b = b_p;
103 gint64 ready_time_a;
104 gint64 ready_time_b;
106 ready_time_a = pending_change_get_ready_time (a, fms);
107 ready_time_b = pending_change_get_ready_time (b, fms);
109 if (ready_time_a < ready_time_b)
110 return -1;
111 else
112 return ready_time_a > ready_time_b;
115 static void
116 pending_change_free (gpointer data)
118 PendingChange *change = data;
120 g_free (change->child);
122 g_slice_free (PendingChange, change);
125 static void
126 queued_event_free (QueuedEvent *event)
128 g_object_unref (event->child);
129 if (event->other)
130 g_object_unref (event->other);
132 g_slice_free (QueuedEvent, event);
135 static gint64
136 g_file_monitor_source_get_ready_time (GFileMonitorSource *fms)
138 GSequenceIter *iter;
140 if (fms->event_queue.length)
141 return 0;
143 iter = g_sequence_get_begin_iter (fms->pending_changes);
144 if (g_sequence_iter_is_end (iter))
145 return -1;
147 return pending_change_get_ready_time (g_sequence_get (iter), fms);
150 static void
151 g_file_monitor_source_update_ready_time (GFileMonitorSource *fms)
153 g_source_set_ready_time ((GSource *) fms, g_file_monitor_source_get_ready_time (fms));
156 static GSequenceIter *
157 g_file_monitor_source_find_pending_change (GFileMonitorSource *fms,
158 const gchar *child)
160 return g_hash_table_lookup (fms->pending_changes_table, child);
163 static void
164 g_file_monitor_source_add_pending_change (GFileMonitorSource *fms,
165 const gchar *child,
166 gint64 now)
168 PendingChange *change;
169 GSequenceIter *iter;
171 change = g_slice_new (PendingChange);
172 change->child = g_strdup (child);
173 change->last_emission = now;
174 change->dirty = FALSE;
176 iter = g_sequence_insert_sorted (fms->pending_changes, change, pending_change_compare_ready_time, fms);
177 g_hash_table_insert (fms->pending_changes_table, change->child, iter);
180 static gboolean
181 g_file_monitor_source_set_pending_change_dirty (GFileMonitorSource *fms,
182 GSequenceIter *iter)
184 PendingChange *change;
186 change = g_sequence_get (iter);
188 /* if it was already dirty then this change is 'uninteresting' */
189 if (change->dirty)
190 return FALSE;
192 change->dirty = TRUE;
194 g_sequence_sort_changed (iter, pending_change_compare_ready_time, fms);
196 return TRUE;
199 static gboolean
200 g_file_monitor_source_get_pending_change_dirty (GFileMonitorSource *fms,
201 GSequenceIter *iter)
203 PendingChange *change;
205 change = g_sequence_get (iter);
207 return change->dirty;
210 static void
211 g_file_monitor_source_remove_pending_change (GFileMonitorSource *fms,
212 GSequenceIter *iter,
213 const gchar *child)
215 /* must remove the hash entry first -- its key is owned by the data
216 * which will be freed when removing the sequence iter
218 g_hash_table_remove (fms->pending_changes_table, child);
219 g_sequence_remove (iter);
222 static void
223 g_file_monitor_source_queue_event (GFileMonitorSource *fms,
224 GFileMonitorEvent event_type,
225 const gchar *child,
226 GFile *other)
228 QueuedEvent *event;
230 event = g_slice_new (QueuedEvent);
231 event->event_type = event_type;
232 if (child != NULL && fms->dirname != NULL)
233 event->child = g_local_file_new_from_dirname_and_basename (fms->dirname, child);
234 else if (child != NULL)
236 gchar *dirname = g_path_get_dirname (fms->filename);
237 event->child = g_local_file_new_from_dirname_and_basename (dirname, child);
238 g_free (dirname);
240 else if (fms->dirname)
241 event->child = _g_local_file_new (fms->dirname);
242 else if (fms->filename)
243 event->child = _g_local_file_new (fms->filename);
244 event->other = other;
245 if (other)
246 g_object_ref (other);
248 g_queue_push_tail (&fms->event_queue, event);
251 static gboolean
252 g_file_monitor_source_file_changed (GFileMonitorSource *fms,
253 const gchar *child,
254 gint64 now)
256 GSequenceIter *pending;
257 gboolean interesting;
259 pending = g_file_monitor_source_find_pending_change (fms, child);
261 /* If there is no pending change, emit one and create a record,
262 * else: just mark the existing record as dirty.
264 if (!pending)
266 g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, child, NULL);
267 g_file_monitor_source_add_pending_change (fms, child, now);
268 interesting = TRUE;
270 else
271 interesting = g_file_monitor_source_set_pending_change_dirty (fms, pending);
273 g_file_monitor_source_update_ready_time (fms);
275 return interesting;
278 static void
279 g_file_monitor_source_file_changes_done (GFileMonitorSource *fms,
280 const gchar *child)
282 GSequenceIter *pending;
284 pending = g_file_monitor_source_find_pending_change (fms, child);
285 if (pending)
287 /* If it is dirty, make sure we push out the last CHANGED event */
288 if (g_file_monitor_source_get_pending_change_dirty (fms, pending))
289 g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, child, NULL);
291 g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, child, NULL);
292 g_file_monitor_source_remove_pending_change (fms, pending, child);
296 static void
297 g_file_monitor_source_file_created (GFileMonitorSource *fms,
298 const gchar *child,
299 gint64 event_time)
301 /* Unlikely, but if we have pending changes for this filename, make
302 * sure we flush those out first, before creating the new ones.
304 g_file_monitor_source_file_changes_done (fms, child);
306 /* Emit CREATE and add a pending changes record */
307 g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CREATED, child, NULL);
308 g_file_monitor_source_add_pending_change (fms, child, event_time);
311 static void
312 g_file_monitor_source_send_event (GFileMonitorSource *fms,
313 GFileMonitorEvent event_type,
314 const gchar *child,
315 GFile *other)
317 /* always flush any pending changes before we queue a new event */
318 g_file_monitor_source_file_changes_done (fms, child);
319 g_file_monitor_source_queue_event (fms, event_type, child, other);
322 static void
323 g_file_monitor_source_send_synthetic_created (GFileMonitorSource *fms,
324 const gchar *child)
326 g_file_monitor_source_file_changes_done (fms, child);
327 g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CREATED, child, NULL);
328 g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, child, NULL);
331 static gboolean
332 is_basename (const gchar *name)
334 if (name[0] == '.' && ((name[1] == '.' && name[2] == '\0') || name[1] == '\0'))
335 return FALSE;
337 return !strchr (name, '/');
340 gboolean
341 g_file_monitor_source_handle_event (GFileMonitorSource *fms,
342 GFileMonitorEvent event_type,
343 const gchar *child,
344 const gchar *rename_to,
345 GFile *other,
346 gint64 event_time)
348 gboolean interesting = TRUE;
350 g_assert (!child || is_basename (child));
351 g_assert (!rename_to || is_basename (rename_to));
353 if (fms->basename && (!child || !g_str_equal (child, fms->basename))
354 && (!rename_to || !g_str_equal (rename_to, fms->basename)))
355 return TRUE;
357 g_mutex_lock (&fms->lock);
359 /* monitor is already gone -- don't bother */
360 if (!fms->instance)
362 g_mutex_unlock (&fms->lock);
363 return TRUE;
366 switch (event_type)
368 case G_FILE_MONITOR_EVENT_CREATED:
369 g_assert (!other && !rename_to);
370 g_file_monitor_source_file_created (fms, child, event_time);
371 break;
373 case G_FILE_MONITOR_EVENT_CHANGED:
374 g_assert (!other && !rename_to);
375 interesting = g_file_monitor_source_file_changed (fms, child, event_time);
376 break;
378 case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
379 g_assert (!other && !rename_to);
380 g_file_monitor_source_file_changes_done (fms, child);
381 break;
383 case G_FILE_MONITOR_EVENT_MOVED_IN:
384 g_assert (!rename_to);
385 if (fms->flags & G_FILE_MONITOR_WATCH_MOVES)
386 g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED_IN, child, other);
387 else
388 g_file_monitor_source_send_synthetic_created (fms, child);
389 break;
391 case G_FILE_MONITOR_EVENT_MOVED_OUT:
392 g_assert (!rename_to);
393 if (fms->flags & G_FILE_MONITOR_WATCH_MOVES)
394 g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED_OUT, child, other);
395 else if (other && (fms->flags & G_FILE_MONITOR_SEND_MOVED))
396 g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED, child, other);
397 else
398 g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_DELETED, child, NULL);
399 break;
401 case G_FILE_MONITOR_EVENT_RENAMED:
402 g_assert (!other && rename_to);
403 if (fms->flags & (G_FILE_MONITOR_WATCH_MOVES | G_FILE_MONITOR_SEND_MOVED))
405 GFile *other;
406 const gchar *dirname;
407 gchar *allocated_dirname = NULL;
408 GFileMonitorEvent event;
410 event = (fms->flags & G_FILE_MONITOR_WATCH_MOVES) ? G_FILE_MONITOR_EVENT_RENAMED : G_FILE_MONITOR_EVENT_MOVED;
412 if (fms->dirname != NULL)
413 dirname = fms->dirname;
414 else
416 allocated_dirname = g_path_get_dirname (fms->filename);
417 dirname = allocated_dirname;
420 other = g_local_file_new_from_dirname_and_basename (dirname, rename_to);
421 g_file_monitor_source_file_changes_done (fms, rename_to);
422 g_file_monitor_source_send_event (fms, event, child, other);
424 g_object_unref (other);
425 g_free (allocated_dirname);
427 else
429 g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_DELETED, child, NULL);
430 g_file_monitor_source_send_synthetic_created (fms, rename_to);
432 break;
434 case G_FILE_MONITOR_EVENT_DELETED:
435 case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
436 case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
437 case G_FILE_MONITOR_EVENT_UNMOUNTED:
438 g_assert (!other && !rename_to);
439 g_file_monitor_source_send_event (fms, event_type, child, NULL);
440 break;
442 case G_FILE_MONITOR_EVENT_MOVED:
443 /* was never available in this API */
444 default:
445 g_assert_not_reached ();
448 g_file_monitor_source_update_ready_time (fms);
450 g_mutex_unlock (&fms->lock);
452 return interesting;
455 static gint64
456 g_file_monitor_source_get_rate_limit (GFileMonitorSource *fms)
458 gint64 rate_limit;
460 g_mutex_lock (&fms->lock);
461 rate_limit = fms->rate_limit;
462 g_mutex_unlock (&fms->lock);
464 return rate_limit;
467 static gboolean
468 g_file_monitor_source_set_rate_limit (GFileMonitorSource *fms,
469 gint64 rate_limit)
471 gboolean changed;
473 g_mutex_lock (&fms->lock);
475 if (rate_limit != fms->rate_limit)
477 fms->rate_limit = rate_limit;
479 g_sequence_sort (fms->pending_changes, pending_change_compare_ready_time, fms);
480 g_file_monitor_source_update_ready_time (fms);
482 changed = TRUE;
484 else
485 changed = FALSE;
487 g_mutex_unlock (&fms->lock);
489 return changed;
492 static gboolean
493 g_file_monitor_source_dispatch (GSource *source,
494 GSourceFunc callback,
495 gpointer user_data)
497 GFileMonitorSource *fms = (GFileMonitorSource *) source;
498 QueuedEvent *event;
499 GQueue event_queue;
500 gint64 now;
502 /* make sure the monitor still exists */
503 if (!fms->instance)
504 return FALSE;
506 now = g_source_get_time (source);
508 /* Acquire the lock once and grab all events in one go, handling the
509 * queued events first. This avoids strange possibilities in cases of
510 * long delays, such as CHANGED events coming before CREATED events.
512 * We do this by converting the applicable pending changes into queued
513 * events (after the ones already queued) and then stealing the entire
514 * event queue in one go.
516 g_mutex_lock (&fms->lock);
518 /* Create events for any pending changes that are due to fire */
519 while (!g_sequence_is_empty (fms->pending_changes))
521 GSequenceIter *iter = g_sequence_get_begin_iter (fms->pending_changes);
522 PendingChange *pending = g_sequence_get (iter);
524 /* We've gotten to a pending change that's not ready. Stop. */
525 if (pending_change_get_ready_time (pending, fms) > now)
526 break;
528 if (pending->dirty)
530 /* It's time to send another CHANGED and update the record */
531 g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, pending->child, NULL);
532 pending->last_emission = now;
533 pending->dirty = FALSE;
535 g_sequence_sort_changed (iter, pending_change_compare_ready_time, fms);
537 else
539 /* It's time to send CHANGES_DONE and remove the pending record */
540 g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, pending->child, NULL);
541 g_file_monitor_source_remove_pending_change (fms, iter, pending->child);
545 /* Steal the queue */
546 memcpy (&event_queue, &fms->event_queue, sizeof event_queue);
547 memset (&fms->event_queue, 0, sizeof fms->event_queue);
549 g_file_monitor_source_update_ready_time (fms);
551 g_mutex_unlock (&fms->lock);
553 /* We now have our list of events to deliver */
554 while ((event = g_queue_pop_head (&event_queue)))
556 /* an event handler could destroy 'instance', so check each time */
557 if (fms->instance)
558 g_file_monitor_emit_event (fms->instance, event->child, event->other, event->event_type);
560 queued_event_free (event);
563 return TRUE;
566 static void
567 g_file_monitor_source_dispose (GFileMonitorSource *fms)
569 g_mutex_lock (&fms->lock);
571 if (fms->instance)
573 GHashTableIter iter;
574 gpointer seqiter;
575 QueuedEvent *event;
577 g_hash_table_iter_init (&iter, fms->pending_changes_table);
578 while (g_hash_table_iter_next (&iter, NULL, &seqiter))
580 g_hash_table_iter_remove (&iter);
581 g_sequence_remove (seqiter);
584 while ((event = g_queue_pop_head (&fms->event_queue)))
585 queued_event_free (event);
587 g_assert (g_sequence_is_empty (fms->pending_changes));
588 g_assert (g_hash_table_size (fms->pending_changes_table) == 0);
589 g_assert (fms->event_queue.length == 0);
590 fms->instance = NULL;
592 g_file_monitor_source_update_ready_time (fms);
595 g_mutex_unlock (&fms->lock);
597 g_source_destroy ((GSource *) fms);
600 static void
601 g_file_monitor_source_finalize (GSource *source)
603 GFileMonitorSource *fms = (GFileMonitorSource *) source;
605 /* should already have been cleared in dispose of the monitor */
606 g_assert (fms->instance == NULL);
607 g_assert (g_sequence_is_empty (fms->pending_changes));
608 g_assert (g_hash_table_size (fms->pending_changes_table) == 0);
609 g_assert (fms->event_queue.length == 0);
611 g_hash_table_unref (fms->pending_changes_table);
612 g_sequence_free (fms->pending_changes);
614 g_free (fms->dirname);
615 g_free (fms->basename);
616 g_free (fms->filename);
618 g_mutex_clear (&fms->lock);
621 static guint
622 str_hash0 (gconstpointer str)
624 return str ? g_str_hash (str) : 0;
627 static gboolean
628 str_equal0 (gconstpointer a,
629 gconstpointer b)
631 return g_strcmp0 (a, b) == 0;
634 static GFileMonitorSource *
635 g_file_monitor_source_new (gpointer instance,
636 const gchar *filename,
637 gboolean is_directory,
638 GFileMonitorFlags flags)
640 static GSourceFuncs source_funcs = {
641 NULL, NULL,
642 g_file_monitor_source_dispatch,
643 g_file_monitor_source_finalize
645 GFileMonitorSource *fms;
646 GSource *source;
648 source = g_source_new (&source_funcs, sizeof (GFileMonitorSource));
649 fms = (GFileMonitorSource *) source;
651 g_mutex_init (&fms->lock);
652 fms->instance = instance;
653 fms->pending_changes = g_sequence_new (pending_change_free);
654 fms->pending_changes_table = g_hash_table_new (str_hash0, str_equal0);
655 fms->rate_limit = DEFAULT_RATE_LIMIT;
656 fms->flags = flags;
658 if (is_directory)
660 fms->dirname = g_strdup (filename);
661 fms->basename = NULL;
662 fms->filename = NULL;
664 else if (flags & G_FILE_MONITOR_WATCH_HARD_LINKS)
666 fms->dirname = NULL;
667 fms->basename = NULL;
668 fms->filename = g_strdup (filename);
670 else
672 fms->dirname = g_path_get_dirname (filename);
673 fms->basename = g_path_get_basename (filename);
674 fms->filename = NULL;
677 return fms;
680 G_DEFINE_ABSTRACT_TYPE (GLocalFileMonitor, g_local_file_monitor, G_TYPE_FILE_MONITOR)
682 enum {
683 PROP_0,
684 PROP_RATE_LIMIT,
687 static void
688 g_local_file_monitor_get_property (GObject *object, guint prop_id,
689 GValue *value, GParamSpec *pspec)
691 GLocalFileMonitor *monitor = G_LOCAL_FILE_MONITOR (object);
692 gint64 rate_limit;
694 g_assert (prop_id == PROP_RATE_LIMIT);
696 rate_limit = g_file_monitor_source_get_rate_limit (monitor->source);
697 rate_limit /= G_TIME_SPAN_MILLISECOND;
699 g_value_set_int (value, rate_limit);
702 static void
703 g_local_file_monitor_set_property (GObject *object, guint prop_id,
704 const GValue *value, GParamSpec *pspec)
706 GLocalFileMonitor *monitor = G_LOCAL_FILE_MONITOR (object);
707 gint64 rate_limit;
709 g_assert (prop_id == PROP_RATE_LIMIT);
711 rate_limit = g_value_get_int (value);
712 rate_limit *= G_TIME_SPAN_MILLISECOND;
714 if (g_file_monitor_source_set_rate_limit (monitor->source, rate_limit))
715 g_object_notify (object, "rate-limit");
718 #ifndef G_OS_WIN32
719 static void
720 g_local_file_monitor_mounts_changed (GUnixMountMonitor *mount_monitor,
721 gpointer user_data)
723 GLocalFileMonitor *local_monitor = user_data;
724 GUnixMountEntry *mount;
725 gboolean is_mounted;
726 GFile *file;
728 /* Emulate unmount detection */
729 mount = g_unix_mount_at (local_monitor->source->dirname, NULL);
731 is_mounted = mount != NULL;
733 if (mount)
734 g_unix_mount_free (mount);
736 if (local_monitor->was_mounted != is_mounted)
738 if (local_monitor->was_mounted && !is_mounted)
740 file = g_file_new_for_path (local_monitor->source->dirname);
741 g_file_monitor_emit_event (G_FILE_MONITOR (local_monitor), file, NULL, G_FILE_MONITOR_EVENT_UNMOUNTED);
742 g_object_unref (file);
744 local_monitor->was_mounted = is_mounted;
747 #endif
749 static void
750 g_local_file_monitor_start (GLocalFileMonitor *local_monitor,
751 const gchar *filename,
752 gboolean is_directory,
753 GFileMonitorFlags flags,
754 GMainContext *context)
756 GLocalFileMonitorClass *class = G_LOCAL_FILE_MONITOR_GET_CLASS (local_monitor);
757 GFileMonitorSource *source;
759 g_return_if_fail (G_IS_LOCAL_FILE_MONITOR (local_monitor));
761 g_assert (!local_monitor->source);
763 source = g_file_monitor_source_new (local_monitor, filename, is_directory, flags);
764 local_monitor->source = source; /* owns the ref */
766 if (is_directory && !class->mount_notify && (flags & G_FILE_MONITOR_WATCH_MOUNTS))
768 #ifdef G_OS_WIN32
769 /*claim everything was mounted */
770 local_monitor->was_mounted = TRUE;
771 #else
772 GUnixMountEntry *mount;
774 /* Emulate unmount detection */
776 mount = g_unix_mount_at (local_monitor->source->dirname, NULL);
778 local_monitor->was_mounted = mount != NULL;
780 if (mount)
781 g_unix_mount_free (mount);
783 local_monitor->mount_monitor = g_unix_mount_monitor_get ();
784 g_signal_connect_object (local_monitor->mount_monitor, "mounts-changed",
785 G_CALLBACK (g_local_file_monitor_mounts_changed), local_monitor, 0);
786 #endif
789 G_LOCAL_FILE_MONITOR_GET_CLASS (local_monitor)->start (local_monitor,
790 source->dirname, source->basename, source->filename,
791 source);
793 g_source_attach ((GSource *) source, context);
796 static void
797 g_local_file_monitor_dispose (GObject *object)
799 GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (object);
801 g_file_monitor_source_dispose (local_monitor->source);
803 G_OBJECT_CLASS (g_local_file_monitor_parent_class)->dispose (object);
806 static void
807 g_local_file_monitor_finalize (GObject *object)
809 GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (object);
811 g_source_unref ((GSource *) local_monitor->source);
813 G_OBJECT_CLASS (g_local_file_monitor_parent_class)->finalize (object);
816 static void
817 g_local_file_monitor_init (GLocalFileMonitor* local_monitor)
821 static void g_local_file_monitor_class_init (GLocalFileMonitorClass *class)
823 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
825 gobject_class->get_property = g_local_file_monitor_get_property;
826 gobject_class->set_property = g_local_file_monitor_set_property;
827 gobject_class->dispose = g_local_file_monitor_dispose;
828 gobject_class->finalize = g_local_file_monitor_finalize;
830 g_object_class_override_property (gobject_class, PROP_RATE_LIMIT, "rate-limit");
833 static GLocalFileMonitor *
834 g_local_file_monitor_new (gboolean is_remote_fs,
835 GError **error)
837 GType type = G_TYPE_INVALID;
839 if (is_remote_fs)
840 type = _g_io_module_get_default_type (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
841 "GIO_USE_FILE_MONITOR",
842 G_STRUCT_OFFSET (GLocalFileMonitorClass, is_supported));
844 if (type == G_TYPE_INVALID)
845 type = _g_io_module_get_default_type (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
846 "GIO_USE_FILE_MONITOR",
847 G_STRUCT_OFFSET (GLocalFileMonitorClass, is_supported));
849 if (type == G_TYPE_INVALID)
851 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
852 _("Unable to find default local file monitor type"));
853 return NULL;
856 return g_object_new (type, NULL);
859 GFileMonitor *
860 g_local_file_monitor_new_for_path (const gchar *pathname,
861 gboolean is_directory,
862 GFileMonitorFlags flags,
863 GError **error)
865 GLocalFileMonitor *monitor;
866 gboolean is_remote_fs;
868 is_remote_fs = g_local_file_is_remote (pathname);
870 monitor = g_local_file_monitor_new (is_remote_fs, error);
872 if (monitor)
873 g_local_file_monitor_start (monitor, pathname, is_directory, flags, g_main_context_get_thread_default ());
875 return G_FILE_MONITOR (monitor);
878 GFileMonitor *
879 g_local_file_monitor_new_in_worker (const gchar *pathname,
880 gboolean is_directory,
881 GFileMonitorFlags flags,
882 GFileMonitorCallback callback,
883 gpointer user_data,
884 GError **error)
886 GLocalFileMonitor *monitor;
887 gboolean is_remote_fs;
889 is_remote_fs = g_local_file_is_remote (pathname);
891 monitor = g_local_file_monitor_new (is_remote_fs, error);
893 if (monitor)
895 if (callback)
896 g_signal_connect (monitor, "changed", G_CALLBACK (callback), user_data);
898 g_local_file_monitor_start (monitor, pathname, is_directory, flags, GLIB_PRIVATE_CALL(g_get_worker_context) ());
901 return G_FILE_MONITOR (monitor);