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, see <http://www.gnu.org/licenses/>.
18 * Author: Alexander Larsson <alexl@redhat.com>
23 #include "gioenumtypes.h"
24 #include "glocalfilemonitor.h"
25 #include "giomodule-priv.h"
28 #include "glocalfile.h"
29 #include "glib-private.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
43 * We use the "priv" pointer in the external struct to store it.
45 struct _GFileMonitorSource
{
50 GFileMonitorFlags flags
;
54 GSequence
*pending_changes
; /* sorted by ready time */
55 GHashTable
*pending_changes_table
;
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.
70 guint64 last_emission
: 63;
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.
80 GFileMonitorEvent event_type
;
86 pending_change_get_ready_time (const PendingChange
*change
,
87 GFileMonitorSource
*fms
)
90 return change
->last_emission
+ fms
->rate_limit
;
92 return change
->last_emission
+ VIRTUAL_CHANGES_DONE_DELAY
;
96 pending_change_compare_ready_time (gconstpointer a_p
,
100 GFileMonitorSource
*fms
= user_data
;
101 const PendingChange
*a
= a_p
;
102 const PendingChange
*b
= b_p
;
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
)
112 return ready_time_a
> ready_time_b
;
116 pending_change_free (gpointer data
)
118 PendingChange
*change
= data
;
120 g_free (change
->child
);
122 g_slice_free (PendingChange
, change
);
126 queued_event_free (QueuedEvent
*event
)
128 g_object_unref (event
->child
);
130 g_object_unref (event
->other
);
132 g_slice_free (QueuedEvent
, event
);
136 g_file_monitor_source_get_ready_time (GFileMonitorSource
*fms
)
140 if (fms
->event_queue
.length
)
143 iter
= g_sequence_get_begin_iter (fms
->pending_changes
);
144 if (g_sequence_iter_is_end (iter
))
147 return pending_change_get_ready_time (g_sequence_get (iter
), fms
);
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
,
160 return g_hash_table_lookup (fms
->pending_changes_table
, child
);
164 g_file_monitor_source_add_pending_change (GFileMonitorSource
*fms
,
168 PendingChange
*change
;
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
);
181 g_file_monitor_source_set_pending_change_dirty (GFileMonitorSource
*fms
,
184 PendingChange
*change
;
186 change
= g_sequence_get (iter
);
188 /* if it was already dirty then this change is 'uninteresting' */
192 change
->dirty
= TRUE
;
194 g_sequence_sort_changed (iter
, pending_change_compare_ready_time
, fms
);
200 g_file_monitor_source_get_pending_change_dirty (GFileMonitorSource
*fms
,
203 PendingChange
*change
;
205 change
= g_sequence_get (iter
);
207 return change
->dirty
;
211 g_file_monitor_source_remove_pending_change (GFileMonitorSource
*fms
,
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
);
223 g_file_monitor_source_queue_event (GFileMonitorSource
*fms
,
224 GFileMonitorEvent event_type
,
230 event
= g_slice_new (QueuedEvent
);
231 event
->event_type
= event_type
;
233 event
->child
= g_local_file_new_from_dirname_and_basename (fms
->dirname
, child
);
234 else if (fms
->dirname
)
235 event
->child
= _g_local_file_new (fms
->dirname
);
236 else if (fms
->filename
)
237 event
->child
= _g_local_file_new (fms
->filename
);
238 event
->other
= other
;
240 g_object_ref (other
);
242 g_queue_push_tail (&fms
->event_queue
, event
);
246 g_file_monitor_source_file_changed (GFileMonitorSource
*fms
,
250 GSequenceIter
*pending
;
251 gboolean interesting
;
253 pending
= g_file_monitor_source_find_pending_change (fms
, child
);
255 /* If there is no pending change, emit one and create a record,
256 * else: just mark the existing record as dirty.
260 g_file_monitor_source_queue_event (fms
, G_FILE_MONITOR_EVENT_CHANGED
, child
, NULL
);
261 g_file_monitor_source_add_pending_change (fms
, child
, now
);
265 interesting
= g_file_monitor_source_set_pending_change_dirty (fms
, pending
);
267 g_file_monitor_source_update_ready_time (fms
);
273 g_file_monitor_source_file_changes_done (GFileMonitorSource
*fms
,
276 GSequenceIter
*pending
;
278 pending
= g_file_monitor_source_find_pending_change (fms
, child
);
281 /* If it is dirty, make sure we push out the last CHANGED event */
282 if (g_file_monitor_source_get_pending_change_dirty (fms
, pending
))
283 g_file_monitor_source_queue_event (fms
, G_FILE_MONITOR_EVENT_CHANGED
, child
, NULL
);
285 g_file_monitor_source_queue_event (fms
, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
, child
, NULL
);
286 g_file_monitor_source_remove_pending_change (fms
, pending
, child
);
291 g_file_monitor_source_file_created (GFileMonitorSource
*fms
,
295 /* Unlikely, but if we have pending changes for this filename, make
296 * sure we flush those out first, before creating the new ones.
298 g_file_monitor_source_file_changes_done (fms
, child
);
300 /* Emit CREATE and add a pending changes record */
301 g_file_monitor_source_queue_event (fms
, G_FILE_MONITOR_EVENT_CREATED
, child
, NULL
);
302 g_file_monitor_source_add_pending_change (fms
, child
, event_time
);
306 g_file_monitor_source_send_event (GFileMonitorSource
*fms
,
307 GFileMonitorEvent event_type
,
311 /* always flush any pending changes before we queue a new event */
312 g_file_monitor_source_file_changes_done (fms
, child
);
313 g_file_monitor_source_queue_event (fms
, event_type
, child
, other
);
317 g_file_monitor_source_send_synthetic_created (GFileMonitorSource
*fms
,
320 g_file_monitor_source_file_changes_done (fms
, child
);
321 g_file_monitor_source_queue_event (fms
, G_FILE_MONITOR_EVENT_CREATED
, child
, NULL
);
322 g_file_monitor_source_queue_event (fms
, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
, child
, NULL
);
326 is_basename (const gchar
*name
)
328 if (name
[0] == '.' && ((name
[1] == '.' && name
[2] == '\0') || name
[1] == '\0'))
331 return !strchr (name
, '/');
335 g_file_monitor_source_handle_event (GFileMonitorSource
*fms
,
336 GFileMonitorEvent event_type
,
338 const gchar
*rename_to
,
342 gboolean interesting
= TRUE
;
344 g_assert (!child
|| is_basename (child
));
345 g_assert (!rename_to
|| is_basename (rename_to
));
347 if (fms
->basename
&& (!child
|| !g_str_equal (child
, fms
->basename
))
348 && (!rename_to
|| !g_str_equal (rename_to
, fms
->basename
)))
351 g_mutex_lock (&fms
->lock
);
353 /* monitor is already gone -- don't bother */
356 g_mutex_unlock (&fms
->lock
);
362 case G_FILE_MONITOR_EVENT_CREATED
:
363 g_assert (!other
&& !rename_to
);
364 g_file_monitor_source_file_created (fms
, child
, event_time
);
367 case G_FILE_MONITOR_EVENT_CHANGED
:
368 g_assert (!other
&& !rename_to
);
369 interesting
= g_file_monitor_source_file_changed (fms
, child
, event_time
);
372 case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
:
373 g_assert (!other
&& !rename_to
);
374 g_file_monitor_source_file_changes_done (fms
, child
);
377 case G_FILE_MONITOR_EVENT_MOVED_IN
:
378 g_assert (!rename_to
);
379 if (fms
->flags
& G_FILE_MONITOR_WATCH_MOVES
)
380 g_file_monitor_source_send_event (fms
, G_FILE_MONITOR_EVENT_MOVED_IN
, child
, other
);
382 g_file_monitor_source_send_synthetic_created (fms
, child
);
385 case G_FILE_MONITOR_EVENT_MOVED_OUT
:
386 g_assert (!rename_to
);
387 if (fms
->flags
& G_FILE_MONITOR_WATCH_MOVES
)
388 g_file_monitor_source_send_event (fms
, G_FILE_MONITOR_EVENT_MOVED_OUT
, child
, other
);
389 else if (other
&& (fms
->flags
& G_FILE_MONITOR_SEND_MOVED
))
390 g_file_monitor_source_send_event (fms
, G_FILE_MONITOR_EVENT_MOVED
, child
, other
);
392 g_file_monitor_source_send_event (fms
, G_FILE_MONITOR_EVENT_DELETED
, child
, NULL
);
395 case G_FILE_MONITOR_EVENT_RENAMED
:
396 g_assert (!other
&& rename_to
);
397 if (fms
->flags
& G_FILE_MONITOR_WATCH_MOVES
)
401 other
= g_local_file_new_from_dirname_and_basename (fms
->dirname
, rename_to
);
402 g_file_monitor_source_file_changes_done (fms
, rename_to
);
403 g_file_monitor_source_send_event (fms
, G_FILE_MONITOR_EVENT_RENAMED
, child
, other
);
404 g_object_unref (other
);
406 else if (fms
->flags
& G_FILE_MONITOR_SEND_MOVED
)
410 other
= g_local_file_new_from_dirname_and_basename (fms
->dirname
, rename_to
);
411 g_file_monitor_source_file_changes_done (fms
, rename_to
);
412 g_file_monitor_source_send_event (fms
, G_FILE_MONITOR_EVENT_MOVED
, child
, other
);
413 g_object_unref (other
);
417 g_file_monitor_source_send_event (fms
, G_FILE_MONITOR_EVENT_DELETED
, child
, NULL
);
418 g_file_monitor_source_send_synthetic_created (fms
, rename_to
);
422 case G_FILE_MONITOR_EVENT_DELETED
:
423 case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED
:
424 case G_FILE_MONITOR_EVENT_PRE_UNMOUNT
:
425 case G_FILE_MONITOR_EVENT_UNMOUNTED
:
426 g_assert (!other
&& !rename_to
);
427 g_file_monitor_source_send_event (fms
, event_type
, child
, NULL
);
430 case G_FILE_MONITOR_EVENT_MOVED
:
431 /* was never available in this API */
433 g_assert_not_reached ();
436 g_file_monitor_source_update_ready_time (fms
);
438 g_mutex_unlock (&fms
->lock
);
444 g_file_monitor_source_get_rate_limit (GFileMonitorSource
*fms
)
448 g_mutex_lock (&fms
->lock
);
449 rate_limit
= fms
->rate_limit
;
450 g_mutex_unlock (&fms
->lock
);
456 g_file_monitor_source_set_rate_limit (GFileMonitorSource
*fms
,
461 g_mutex_lock (&fms
->lock
);
463 if (rate_limit
!= fms
->rate_limit
)
465 fms
->rate_limit
= rate_limit
;
467 g_sequence_sort (fms
->pending_changes
, pending_change_compare_ready_time
, fms
);
468 g_file_monitor_source_update_ready_time (fms
);
475 g_mutex_unlock (&fms
->lock
);
481 g_file_monitor_source_dispatch (GSource
*source
,
482 GSourceFunc callback
,
485 GFileMonitorSource
*fms
= (GFileMonitorSource
*) source
;
490 /* make sure the monitor still exists */
494 now
= g_source_get_time (source
);
496 /* Acquire the lock once and grab all events in one go, handling the
497 * queued events first. This avoids strange possibilities in cases of
498 * long delays, such as CHANGED events coming before CREATED events.
500 * We do this by converting the applicable pending changes into queued
501 * events (after the ones already queued) and then stealing the entire
502 * event queue in one go.
504 g_mutex_lock (&fms
->lock
);
506 /* Create events for any pending changes that are due to fire */
507 while (!g_sequence_is_empty (fms
->pending_changes
))
509 GSequenceIter
*iter
= g_sequence_get_begin_iter (fms
->pending_changes
);
510 PendingChange
*pending
= g_sequence_get (iter
);
512 /* We've gotten to a pending change that's not ready. Stop. */
513 if (pending_change_get_ready_time (pending
, fms
) > now
)
518 /* It's time to send another CHANGED and update the record */
519 g_file_monitor_source_queue_event (fms
, G_FILE_MONITOR_EVENT_CHANGED
, pending
->child
, NULL
);
520 pending
->last_emission
= now
;
521 pending
->dirty
= FALSE
;
523 g_sequence_sort_changed (iter
, pending_change_compare_ready_time
, fms
);
527 /* It's time to send CHANGES_DONE and remove the pending record */
528 g_file_monitor_source_queue_event (fms
, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
, pending
->child
, NULL
);
529 g_file_monitor_source_remove_pending_change (fms
, iter
, pending
->child
);
533 /* Steal the queue */
534 memcpy (&event_queue
, &fms
->event_queue
, sizeof event_queue
);
535 memset (&fms
->event_queue
, 0, sizeof fms
->event_queue
);
537 g_file_monitor_source_update_ready_time (fms
);
539 g_mutex_unlock (&fms
->lock
);
541 /* We now have our list of events to deliver */
542 while ((event
= g_queue_pop_head (&event_queue
)))
544 /* an event handler could destroy 'instance', so check each time */
546 g_file_monitor_emit_event (fms
->instance
, event
->child
, event
->other
, event
->event_type
);
548 queued_event_free (event
);
555 g_file_monitor_source_dispose (GFileMonitorSource
*fms
)
557 g_mutex_lock (&fms
->lock
);
565 g_hash_table_iter_init (&iter
, fms
->pending_changes_table
);
566 while (g_hash_table_iter_next (&iter
, NULL
, &seqiter
))
568 g_hash_table_iter_remove (&iter
);
569 g_sequence_remove (seqiter
);
572 while ((event
= g_queue_pop_head (&fms
->event_queue
)))
573 queued_event_free (event
);
575 g_assert (g_sequence_is_empty (fms
->pending_changes
));
576 g_assert (g_hash_table_size (fms
->pending_changes_table
) == 0);
577 g_assert (fms
->event_queue
.length
== 0);
578 fms
->instance
= NULL
;
580 g_file_monitor_source_update_ready_time (fms
);
583 g_mutex_unlock (&fms
->lock
);
585 g_source_destroy ((GSource
*) fms
);
589 g_file_monitor_source_finalize (GSource
*source
)
591 GFileMonitorSource
*fms
= (GFileMonitorSource
*) source
;
593 /* should already have been cleared in dispose of the monitor */
594 g_assert (fms
->instance
== NULL
);
595 g_assert (g_sequence_is_empty (fms
->pending_changes
));
596 g_assert (g_hash_table_size (fms
->pending_changes_table
) == 0);
597 g_assert (fms
->event_queue
.length
== 0);
599 g_hash_table_unref (fms
->pending_changes_table
);
600 g_sequence_free (fms
->pending_changes
);
602 g_free (fms
->dirname
);
603 g_free (fms
->basename
);
604 g_free (fms
->filename
);
606 g_mutex_clear (&fms
->lock
);
610 str_hash0 (gconstpointer str
)
612 return str
? g_str_hash (str
) : 0;
616 str_equal0 (gconstpointer a
,
619 return g_strcmp0 (a
, b
) == 0;
622 static GFileMonitorSource
*
623 g_file_monitor_source_new (gpointer instance
,
624 const gchar
*filename
,
625 gboolean is_directory
,
626 GFileMonitorFlags flags
)
628 static GSourceFuncs source_funcs
= {
630 g_file_monitor_source_dispatch
,
631 g_file_monitor_source_finalize
633 GFileMonitorSource
*fms
;
636 source
= g_source_new (&source_funcs
, sizeof (GFileMonitorSource
));
637 fms
= (GFileMonitorSource
*) source
;
639 g_mutex_init (&fms
->lock
);
640 fms
->instance
= instance
;
641 fms
->pending_changes
= g_sequence_new (pending_change_free
);
642 fms
->pending_changes_table
= g_hash_table_new (str_hash0
, str_equal0
);
643 fms
->rate_limit
= DEFAULT_RATE_LIMIT
;
648 fms
->dirname
= g_strdup (filename
);
649 fms
->basename
= NULL
;
650 fms
->filename
= NULL
;
652 else if (flags
& G_FILE_MONITOR_WATCH_HARD_LINKS
)
655 fms
->basename
= NULL
;
656 fms
->filename
= g_strdup (filename
);
660 fms
->dirname
= g_path_get_dirname (filename
);
661 fms
->basename
= g_path_get_basename (filename
);
662 fms
->filename
= NULL
;
668 G_DEFINE_ABSTRACT_TYPE (GLocalFileMonitor
, g_local_file_monitor
, G_TYPE_FILE_MONITOR
)
676 g_local_file_monitor_get_property (GObject
*object
, guint prop_id
,
677 GValue
*value
, GParamSpec
*pspec
)
679 GLocalFileMonitor
*monitor
= G_LOCAL_FILE_MONITOR (object
);
682 g_assert (prop_id
== PROP_RATE_LIMIT
);
684 rate_limit
= g_file_monitor_source_get_rate_limit (monitor
->source
);
685 rate_limit
/= G_TIME_SPAN_MILLISECOND
;
687 g_value_set_int (value
, rate_limit
);
691 g_local_file_monitor_set_property (GObject
*object
, guint prop_id
,
692 const GValue
*value
, GParamSpec
*pspec
)
694 GLocalFileMonitor
*monitor
= G_LOCAL_FILE_MONITOR (object
);
697 g_assert (prop_id
== PROP_RATE_LIMIT
);
699 rate_limit
= g_value_get_int (value
);
700 rate_limit
*= G_TIME_SPAN_MILLISECOND
;
702 if (g_file_monitor_source_set_rate_limit (monitor
->source
, rate_limit
))
703 g_object_notify (object
, "rate-limit");
708 g_local_file_monitor_mounts_changed (GUnixMountMonitor
*mount_monitor
,
711 GLocalFileMonitor
*local_monitor
= user_data
;
712 GUnixMountEntry
*mount
;
716 /* Emulate unmount detection */
717 mount
= g_unix_mount_at (local_monitor
->source
->dirname
, NULL
);
719 is_mounted
= mount
!= NULL
;
722 g_unix_mount_free (mount
);
724 if (local_monitor
->was_mounted
!= is_mounted
)
726 if (local_monitor
->was_mounted
&& !is_mounted
)
728 file
= g_file_new_for_path (local_monitor
->source
->dirname
);
729 g_file_monitor_emit_event (G_FILE_MONITOR (local_monitor
), file
, NULL
, G_FILE_MONITOR_EVENT_UNMOUNTED
);
730 g_object_unref (file
);
732 local_monitor
->was_mounted
= is_mounted
;
738 g_local_file_monitor_start (GLocalFileMonitor
*local_monitor
,
739 const gchar
*filename
,
740 gboolean is_directory
,
741 GFileMonitorFlags flags
,
742 GMainContext
*context
)
744 GLocalFileMonitorClass
*class = G_LOCAL_FILE_MONITOR_GET_CLASS (local_monitor
);
745 GFileMonitorSource
*source
;
747 g_return_if_fail (G_IS_LOCAL_FILE_MONITOR (local_monitor
));
749 g_assert (!local_monitor
->source
);
751 source
= g_file_monitor_source_new (local_monitor
, filename
, is_directory
, flags
);
752 local_monitor
->source
= source
; /* owns the ref */
754 if (is_directory
&& !class->mount_notify
&& (flags
& G_FILE_MONITOR_WATCH_MOUNTS
))
757 /*claim everything was mounted */
758 local_monitor
->was_mounted
= TRUE
;
760 GUnixMountEntry
*mount
;
762 /* Emulate unmount detection */
764 mount
= g_unix_mount_at (local_monitor
->source
->dirname
, NULL
);
766 local_monitor
->was_mounted
= mount
!= NULL
;
769 g_unix_mount_free (mount
);
771 local_monitor
->mount_monitor
= g_unix_mount_monitor_get ();
772 g_signal_connect_object (local_monitor
->mount_monitor
, "mounts-changed",
773 G_CALLBACK (g_local_file_monitor_mounts_changed
), local_monitor
, 0);
777 G_LOCAL_FILE_MONITOR_GET_CLASS (local_monitor
)->start (local_monitor
,
778 source
->dirname
, source
->basename
, source
->filename
,
781 g_source_attach ((GSource
*) source
, context
);
785 g_local_file_monitor_dispose (GObject
*object
)
787 GLocalFileMonitor
*local_monitor
= G_LOCAL_FILE_MONITOR (object
);
789 g_file_monitor_source_dispose (local_monitor
->source
);
791 G_OBJECT_CLASS (g_local_file_monitor_parent_class
)->dispose (object
);
795 g_local_file_monitor_finalize (GObject
*object
)
797 GLocalFileMonitor
*local_monitor
= G_LOCAL_FILE_MONITOR (object
);
799 g_source_unref ((GSource
*) local_monitor
->source
);
801 G_OBJECT_CLASS (g_local_file_monitor_parent_class
)->finalize (object
);
805 g_local_file_monitor_init (GLocalFileMonitor
* local_monitor
)
809 static void g_local_file_monitor_class_init (GLocalFileMonitorClass
*class)
811 GObjectClass
*gobject_class
= G_OBJECT_CLASS (class);
813 gobject_class
->get_property
= g_local_file_monitor_get_property
;
814 gobject_class
->set_property
= g_local_file_monitor_set_property
;
815 gobject_class
->dispose
= g_local_file_monitor_dispose
;
816 gobject_class
->finalize
= g_local_file_monitor_finalize
;
818 g_object_class_override_property (gobject_class
, PROP_RATE_LIMIT
, "rate-limit");
821 static GLocalFileMonitor
*
822 g_local_file_monitor_new (gboolean is_remote_fs
,
825 GType type
= G_TYPE_INVALID
;
828 type
= _g_io_module_get_default_type (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME
,
829 "GIO_USE_FILE_MONITOR",
830 G_STRUCT_OFFSET (GLocalFileMonitorClass
, is_supported
));
832 if (type
== G_TYPE_INVALID
)
833 type
= _g_io_module_get_default_type (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME
,
834 "GIO_USE_FILE_MONITOR",
835 G_STRUCT_OFFSET (GLocalFileMonitorClass
, is_supported
));
837 if (type
== G_TYPE_INVALID
)
839 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
840 _("Unable to find default local file monitor type"));
844 return g_object_new (type
, NULL
);
848 g_local_file_monitor_new_for_path (const gchar
*pathname
,
849 gboolean is_directory
,
850 GFileMonitorFlags flags
,
853 GLocalFileMonitor
*monitor
;
854 gboolean is_remote_fs
;
856 is_remote_fs
= g_local_file_is_remote (pathname
);
858 monitor
= g_local_file_monitor_new (is_remote_fs
, error
);
861 g_local_file_monitor_start (monitor
, pathname
, is_directory
, flags
, g_main_context_get_thread_default ());
863 return G_FILE_MONITOR (monitor
);
867 g_local_file_monitor_new_in_worker (const gchar
*pathname
,
868 gboolean is_directory
,
869 GFileMonitorFlags flags
,
870 GFileMonitorCallback callback
,
874 GLocalFileMonitor
*monitor
;
875 gboolean is_remote_fs
;
877 is_remote_fs
= g_local_file_is_remote (pathname
);
879 monitor
= g_local_file_monitor_new (is_remote_fs
, error
);
884 g_signal_connect (monitor
, "changed", G_CALLBACK (callback
), user_data
);
886 g_local_file_monitor_start (monitor
, pathname
, is_directory
, flags
, GLIB_PRIVATE_CALL(g_get_worker_context
) ());
889 return G_FILE_MONITOR (monitor
);