|
Packit |
ae235b |
/* GIO - GLib Input, Output and Streaming Library
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* This library is free software; you can redistribute it and/or
|
|
Packit |
ae235b |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
ae235b |
* License as published by the Free Software Foundation; either
|
|
Packit |
ae235b |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
ae235b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
ae235b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
ae235b |
* Lesser General Public License for more details.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* You should have received a copy of the GNU Lesser General
|
|
Packit |
ae235b |
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Author: Alexander Larsson <alexl@redhat.com>
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#include "config.h"
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#include "gioenumtypes.h"
|
|
Packit |
ae235b |
#include "glocalfilemonitor.h"
|
|
Packit |
ae235b |
#include "giomodule-priv.h"
|
|
Packit |
ae235b |
#include "gioerror.h"
|
|
Packit |
ae235b |
#include "glibintl.h"
|
|
Packit |
ae235b |
#include "glocalfile.h"
|
|
Packit |
ae235b |
#include "glib-private.h"
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#include <string.h>
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#define DEFAULT_RATE_LIMIT 800 * G_TIME_SPAN_MILLISECOND
|
|
Packit |
ae235b |
#define VIRTUAL_CHANGES_DONE_DELAY 2 * G_TIME_SPAN_SECOND
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* GFileMonitorSource is a GSource responsible for emitting the changed
|
|
Packit |
ae235b |
* signals in the owner-context of the GFileMonitor.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* It contains functionality for cross-thread queuing of events. It
|
|
Packit |
ae235b |
* also handles merging of CHANGED events and emission of CHANGES_DONE
|
|
Packit |
ae235b |
* events.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* We use the "priv" pointer in the external struct to store it.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
struct _GFileMonitorSource {
|
|
Packit |
ae235b |
GSource source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
GMutex lock;
|
|
Packit |
ae235b |
gpointer instance;
|
|
Packit |
ae235b |
GFileMonitorFlags flags;
|
|
Packit |
ae235b |
gchar *dirname;
|
|
Packit |
ae235b |
gchar *basename;
|
|
Packit |
ae235b |
gchar *filename;
|
|
Packit |
ae235b |
GSequence *pending_changes; /* sorted by ready time */
|
|
Packit |
ae235b |
GHashTable *pending_changes_table;
|
|
Packit |
ae235b |
GQueue event_queue;
|
|
Packit |
ae235b |
gint64 rate_limit;
|
|
Packit |
ae235b |
};
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* PendingChange is a struct to keep track of a file that needs to have
|
|
Packit |
ae235b |
* (at least) a CHANGES_DONE_HINT event sent for it in the near future.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* If 'dirty' is TRUE then a CHANGED event also needs to be sent.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* last_emission is the last time a CHANGED event was emitted. It is
|
|
Packit |
ae235b |
* used to calculate the time to send the next event.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
typedef struct {
|
|
Packit |
ae235b |
gchar *child;
|
|
Packit |
ae235b |
guint64 last_emission : 63;
|
|
Packit |
ae235b |
guint64 dirty : 1;
|
|
Packit |
ae235b |
} PendingChange;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* QueuedEvent is a signal that will be sent immediately, as soon as the
|
|
Packit |
ae235b |
* source gets a chance to dispatch. The existence of any queued event
|
|
Packit |
ae235b |
* implies that the source is ready now.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
typedef struct
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GFileMonitorEvent event_type;
|
|
Packit |
ae235b |
GFile *child;
|
|
Packit |
ae235b |
GFile *other;
|
|
Packit |
ae235b |
} QueuedEvent;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gint64
|
|
Packit |
ae235b |
pending_change_get_ready_time (const PendingChange *change,
|
|
Packit |
ae235b |
GFileMonitorSource *fms)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
if (change->dirty)
|
|
Packit |
ae235b |
return change->last_emission + fms->rate_limit;
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
return change->last_emission + VIRTUAL_CHANGES_DONE_DELAY;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static int
|
|
Packit |
ae235b |
pending_change_compare_ready_time (gconstpointer a_p,
|
|
Packit |
ae235b |
gconstpointer b_p,
|
|
Packit |
ae235b |
gpointer user_data)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GFileMonitorSource *fms = user_data;
|
|
Packit |
ae235b |
const PendingChange *a = a_p;
|
|
Packit |
ae235b |
const PendingChange *b = b_p;
|
|
Packit |
ae235b |
gint64 ready_time_a;
|
|
Packit |
ae235b |
gint64 ready_time_b;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
ready_time_a = pending_change_get_ready_time (a, fms);
|
|
Packit |
ae235b |
ready_time_b = pending_change_get_ready_time (b, fms);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (ready_time_a < ready_time_b)
|
|
Packit |
ae235b |
return -1;
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
return ready_time_a > ready_time_b;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
pending_change_free (gpointer data)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
PendingChange *change = data;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_free (change->child);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_slice_free (PendingChange, change);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
queued_event_free (QueuedEvent *event)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_object_unref (event->child);
|
|
Packit |
ae235b |
if (event->other)
|
|
Packit |
ae235b |
g_object_unref (event->other);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_slice_free (QueuedEvent, event);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gint64
|
|
Packit |
ae235b |
g_file_monitor_source_get_ready_time (GFileMonitorSource *fms)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GSequenceIter *iter;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (fms->event_queue.length)
|
|
Packit |
ae235b |
return 0;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
iter = g_sequence_get_begin_iter (fms->pending_changes);
|
|
Packit |
ae235b |
if (g_sequence_iter_is_end (iter))
|
|
Packit |
ae235b |
return -1;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return pending_change_get_ready_time (g_sequence_get (iter), fms);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_update_ready_time (GFileMonitorSource *fms)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_source_set_ready_time ((GSource *) fms, g_file_monitor_source_get_ready_time (fms));
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static GSequenceIter *
|
|
Packit |
ae235b |
g_file_monitor_source_find_pending_change (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
const gchar *child)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
return g_hash_table_lookup (fms->pending_changes_table, child);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_add_pending_change (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
const gchar *child,
|
|
Packit |
ae235b |
gint64 now)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
PendingChange *change;
|
|
Packit |
ae235b |
GSequenceIter *iter;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
change = g_slice_new (PendingChange);
|
|
Packit |
ae235b |
change->child = g_strdup (child);
|
|
Packit |
ae235b |
change->last_emission = now;
|
|
Packit |
ae235b |
change->dirty = FALSE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
iter = g_sequence_insert_sorted (fms->pending_changes, change, pending_change_compare_ready_time, fms);
|
|
Packit |
ae235b |
g_hash_table_insert (fms->pending_changes_table, change->child, iter);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_file_monitor_source_set_pending_change_dirty (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
GSequenceIter *iter)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
PendingChange *change;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
change = g_sequence_get (iter);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* if it was already dirty then this change is 'uninteresting' */
|
|
Packit |
ae235b |
if (change->dirty)
|
|
Packit |
ae235b |
return FALSE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
change->dirty = TRUE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_sequence_sort_changed (iter, pending_change_compare_ready_time, fms);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_file_monitor_source_get_pending_change_dirty (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
GSequenceIter *iter)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
PendingChange *change;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
change = g_sequence_get (iter);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return change->dirty;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_remove_pending_change (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
GSequenceIter *iter,
|
|
Packit |
ae235b |
const gchar *child)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* must remove the hash entry first -- its key is owned by the data
|
|
Packit |
ae235b |
* which will be freed when removing the sequence iter
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
g_hash_table_remove (fms->pending_changes_table, child);
|
|
Packit |
ae235b |
g_sequence_remove (iter);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
GFileMonitorEvent event_type,
|
|
Packit |
ae235b |
const gchar *child,
|
|
Packit |
ae235b |
GFile *other)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
QueuedEvent *event;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
event = g_slice_new (QueuedEvent);
|
|
Packit |
ae235b |
event->event_type = event_type;
|
|
Packit |
ae235b |
if (child)
|
|
Packit |
ae235b |
event->child = g_local_file_new_from_dirname_and_basename (fms->dirname, child);
|
|
Packit |
ae235b |
else if (fms->dirname)
|
|
Packit |
ae235b |
event->child = _g_local_file_new (fms->dirname);
|
|
Packit |
ae235b |
else if (fms->filename)
|
|
Packit |
ae235b |
event->child = _g_local_file_new (fms->filename);
|
|
Packit |
ae235b |
event->other = other;
|
|
Packit |
ae235b |
if (other)
|
|
Packit |
ae235b |
g_object_ref (other);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_queue_push_tail (&fms->event_queue, event);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_file_monitor_source_file_changed (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
const gchar *child,
|
|
Packit |
ae235b |
gint64 now)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GSequenceIter *pending;
|
|
Packit |
ae235b |
gboolean interesting;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
pending = g_file_monitor_source_find_pending_change (fms, child);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* If there is no pending change, emit one and create a record,
|
|
Packit |
ae235b |
* else: just mark the existing record as dirty.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
if (!pending)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, child, NULL);
|
|
Packit |
ae235b |
g_file_monitor_source_add_pending_change (fms, child, now);
|
|
Packit |
ae235b |
interesting = TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
interesting = g_file_monitor_source_set_pending_change_dirty (fms, pending);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_file_monitor_source_update_ready_time (fms);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return interesting;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_file_changes_done (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
const gchar *child)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GSequenceIter *pending;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
pending = g_file_monitor_source_find_pending_change (fms, child);
|
|
Packit |
ae235b |
if (pending)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* If it is dirty, make sure we push out the last CHANGED event */
|
|
Packit |
ae235b |
if (g_file_monitor_source_get_pending_change_dirty (fms, pending))
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, child, NULL);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, child, NULL);
|
|
Packit |
ae235b |
g_file_monitor_source_remove_pending_change (fms, pending, child);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_file_created (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
const gchar *child,
|
|
Packit |
ae235b |
gint64 event_time)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* Unlikely, but if we have pending changes for this filename, make
|
|
Packit |
ae235b |
* sure we flush those out first, before creating the new ones.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
g_file_monitor_source_file_changes_done (fms, child);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Emit CREATE and add a pending changes record */
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CREATED, child, NULL);
|
|
Packit |
ae235b |
g_file_monitor_source_add_pending_change (fms, child, event_time);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_send_event (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
GFileMonitorEvent event_type,
|
|
Packit |
ae235b |
const gchar *child,
|
|
Packit |
ae235b |
GFile *other)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* always flush any pending changes before we queue a new event */
|
|
Packit |
ae235b |
g_file_monitor_source_file_changes_done (fms, child);
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (fms, event_type, child, other);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_send_synthetic_created (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
const gchar *child)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_file_monitor_source_file_changes_done (fms, child);
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CREATED, child, NULL);
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, child, NULL);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
is_basename (const gchar *name)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
if (name[0] == '.' && ((name[1] == '.' && name[2] == '\0') || name[1] == '\0'))
|
|
Packit |
ae235b |
return FALSE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return !strchr (name, '/');
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
gboolean
|
|
Packit |
ae235b |
g_file_monitor_source_handle_event (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
GFileMonitorEvent event_type,
|
|
Packit |
ae235b |
const gchar *child,
|
|
Packit |
ae235b |
const gchar *rename_to,
|
|
Packit |
ae235b |
GFile *other,
|
|
Packit |
ae235b |
gint64 event_time)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gboolean interesting = TRUE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_assert (!child || is_basename (child));
|
|
Packit |
ae235b |
g_assert (!rename_to || is_basename (rename_to));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (fms->basename && (!child || !g_str_equal (child, fms->basename))
|
|
Packit |
ae235b |
&& (!rename_to || !g_str_equal (rename_to, fms->basename)))
|
|
Packit |
ae235b |
return TRUE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_lock (&fms->lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* monitor is already gone -- don't bother */
|
|
Packit |
ae235b |
if (!fms->instance)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_mutex_unlock (&fms->lock);
|
|
Packit |
ae235b |
return TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
switch (event_type)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_CREATED:
|
|
Packit |
ae235b |
g_assert (!other && !rename_to);
|
|
Packit |
ae235b |
g_file_monitor_source_file_created (fms, child, event_time);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_CHANGED:
|
|
Packit |
ae235b |
g_assert (!other && !rename_to);
|
|
Packit |
ae235b |
interesting = g_file_monitor_source_file_changed (fms, child, event_time);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
|
|
Packit |
ae235b |
g_assert (!other && !rename_to);
|
|
Packit |
ae235b |
g_file_monitor_source_file_changes_done (fms, child);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_MOVED_IN:
|
|
Packit |
ae235b |
g_assert (!rename_to);
|
|
Packit |
ae235b |
if (fms->flags & G_FILE_MONITOR_WATCH_MOVES)
|
|
Packit |
ae235b |
g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED_IN, child, other);
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
g_file_monitor_source_send_synthetic_created (fms, child);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_MOVED_OUT:
|
|
Packit |
ae235b |
g_assert (!rename_to);
|
|
Packit |
ae235b |
if (fms->flags & G_FILE_MONITOR_WATCH_MOVES)
|
|
Packit |
ae235b |
g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED_OUT, child, other);
|
|
Packit |
ae235b |
else if (other && (fms->flags & G_FILE_MONITOR_SEND_MOVED))
|
|
Packit |
ae235b |
g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED, child, other);
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_DELETED, child, NULL);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_RENAMED:
|
|
Packit |
ae235b |
g_assert (!other && rename_to);
|
|
Packit |
ae235b |
if (fms->flags & G_FILE_MONITOR_WATCH_MOVES)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GFile *other;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
other = g_local_file_new_from_dirname_and_basename (fms->dirname, rename_to);
|
|
Packit |
ae235b |
g_file_monitor_source_file_changes_done (fms, rename_to);
|
|
Packit |
ae235b |
g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_RENAMED, child, other);
|
|
Packit |
ae235b |
g_object_unref (other);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else if (fms->flags & G_FILE_MONITOR_SEND_MOVED)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GFile *other;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
other = g_local_file_new_from_dirname_and_basename (fms->dirname, rename_to);
|
|
Packit |
ae235b |
g_file_monitor_source_file_changes_done (fms, rename_to);
|
|
Packit |
ae235b |
g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED, child, other);
|
|
Packit |
ae235b |
g_object_unref (other);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_DELETED, child, NULL);
|
|
Packit |
ae235b |
g_file_monitor_source_send_synthetic_created (fms, rename_to);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_DELETED:
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_UNMOUNTED:
|
|
Packit |
ae235b |
g_assert (!other && !rename_to);
|
|
Packit |
ae235b |
g_file_monitor_source_send_event (fms, event_type, child, NULL);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case G_FILE_MONITOR_EVENT_MOVED:
|
|
Packit |
ae235b |
/* was never available in this API */
|
|
Packit |
ae235b |
default:
|
|
Packit |
ae235b |
g_assert_not_reached ();
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_file_monitor_source_update_ready_time (fms);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_unlock (&fms->lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return interesting;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gint64
|
|
Packit |
ae235b |
g_file_monitor_source_get_rate_limit (GFileMonitorSource *fms)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gint64 rate_limit;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_lock (&fms->lock);
|
|
Packit |
ae235b |
rate_limit = fms->rate_limit;
|
|
Packit |
ae235b |
g_mutex_unlock (&fms->lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return rate_limit;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_file_monitor_source_set_rate_limit (GFileMonitorSource *fms,
|
|
Packit |
ae235b |
gint64 rate_limit)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gboolean changed;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_lock (&fms->lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (rate_limit != fms->rate_limit)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
fms->rate_limit = rate_limit;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_sequence_sort (fms->pending_changes, pending_change_compare_ready_time, fms);
|
|
Packit |
ae235b |
g_file_monitor_source_update_ready_time (fms);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
changed = TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
changed = FALSE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_unlock (&fms->lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return changed;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_file_monitor_source_dispatch (GSource *source,
|
|
Packit |
ae235b |
GSourceFunc callback,
|
|
Packit |
ae235b |
gpointer user_data)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GFileMonitorSource *fms = (GFileMonitorSource *) source;
|
|
Packit |
ae235b |
QueuedEvent *event;
|
|
Packit |
ae235b |
GQueue event_queue;
|
|
Packit |
ae235b |
gint64 now;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* make sure the monitor still exists */
|
|
Packit |
ae235b |
if (!fms->instance)
|
|
Packit |
ae235b |
return FALSE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
now = g_source_get_time (source);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Acquire the lock once and grab all events in one go, handling the
|
|
Packit |
ae235b |
* queued events first. This avoids strange possibilities in cases of
|
|
Packit |
ae235b |
* long delays, such as CHANGED events coming before CREATED events.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* We do this by converting the applicable pending changes into queued
|
|
Packit |
ae235b |
* events (after the ones already queued) and then stealing the entire
|
|
Packit |
ae235b |
* event queue in one go.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
g_mutex_lock (&fms->lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Create events for any pending changes that are due to fire */
|
|
Packit |
ae235b |
while (!g_sequence_is_empty (fms->pending_changes))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GSequenceIter *iter = g_sequence_get_begin_iter (fms->pending_changes);
|
|
Packit |
ae235b |
PendingChange *pending = g_sequence_get (iter);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* We've gotten to a pending change that's not ready. Stop. */
|
|
Packit |
ae235b |
if (pending_change_get_ready_time (pending, fms) > now)
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (pending->dirty)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* It's time to send another CHANGED and update the record */
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, pending->child, NULL);
|
|
Packit |
ae235b |
pending->last_emission = now;
|
|
Packit |
ae235b |
pending->dirty = FALSE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_sequence_sort_changed (iter, pending_change_compare_ready_time, fms);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* It's time to send CHANGES_DONE and remove the pending record */
|
|
Packit |
ae235b |
g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, pending->child, NULL);
|
|
Packit |
ae235b |
g_file_monitor_source_remove_pending_change (fms, iter, pending->child);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Steal the queue */
|
|
Packit |
ae235b |
memcpy (&event_queue, &fms->event_queue, sizeof event_queue);
|
|
Packit |
ae235b |
memset (&fms->event_queue, 0, sizeof fms->event_queue);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_file_monitor_source_update_ready_time (fms);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_unlock (&fms->lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* We now have our list of events to deliver */
|
|
Packit |
ae235b |
while ((event = g_queue_pop_head (&event_queue)))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* an event handler could destroy 'instance', so check each time */
|
|
Packit |
ae235b |
if (fms->instance)
|
|
Packit |
ae235b |
g_file_monitor_emit_event (fms->instance, event->child, event->other, event->event_type);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
queued_event_free (event);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_dispose (GFileMonitorSource *fms)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_mutex_lock (&fms->lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (fms->instance)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GHashTableIter iter;
|
|
Packit |
ae235b |
gpointer seqiter;
|
|
Packit |
ae235b |
QueuedEvent *event;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_hash_table_iter_init (&iter, fms->pending_changes_table);
|
|
Packit |
ae235b |
while (g_hash_table_iter_next (&iter, NULL, &seqiter))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_hash_table_iter_remove (&iter);
|
|
Packit |
ae235b |
g_sequence_remove (seqiter);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
while ((event = g_queue_pop_head (&fms->event_queue)))
|
|
Packit |
ae235b |
queued_event_free (event);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_assert (g_sequence_is_empty (fms->pending_changes));
|
|
Packit |
ae235b |
g_assert (g_hash_table_size (fms->pending_changes_table) == 0);
|
|
Packit |
ae235b |
g_assert (fms->event_queue.length == 0);
|
|
Packit |
ae235b |
fms->instance = NULL;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_file_monitor_source_update_ready_time (fms);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_unlock (&fms->lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_source_destroy ((GSource *) fms);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_file_monitor_source_finalize (GSource *source)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GFileMonitorSource *fms = (GFileMonitorSource *) source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* should already have been cleared in dispose of the monitor */
|
|
Packit |
ae235b |
g_assert (fms->instance == NULL);
|
|
Packit |
ae235b |
g_assert (g_sequence_is_empty (fms->pending_changes));
|
|
Packit |
ae235b |
g_assert (g_hash_table_size (fms->pending_changes_table) == 0);
|
|
Packit |
ae235b |
g_assert (fms->event_queue.length == 0);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_hash_table_unref (fms->pending_changes_table);
|
|
Packit |
ae235b |
g_sequence_free (fms->pending_changes);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_free (fms->dirname);
|
|
Packit |
ae235b |
g_free (fms->basename);
|
|
Packit |
ae235b |
g_free (fms->filename);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_clear (&fms->lock);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static guint
|
|
Packit |
ae235b |
str_hash0 (gconstpointer str)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
return str ? g_str_hash (str) : 0;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
str_equal0 (gconstpointer a,
|
|
Packit |
ae235b |
gconstpointer b)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
return g_strcmp0 (a, b) == 0;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static GFileMonitorSource *
|
|
Packit |
ae235b |
g_file_monitor_source_new (gpointer instance,
|
|
Packit |
ae235b |
const gchar *filename,
|
|
Packit |
ae235b |
gboolean is_directory,
|
|
Packit |
ae235b |
GFileMonitorFlags flags)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
static GSourceFuncs source_funcs = {
|
|
Packit |
ae235b |
NULL, NULL,
|
|
Packit |
ae235b |
g_file_monitor_source_dispatch,
|
|
Packit |
ae235b |
g_file_monitor_source_finalize
|
|
Packit |
ae235b |
};
|
|
Packit |
ae235b |
GFileMonitorSource *fms;
|
|
Packit |
ae235b |
GSource *source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
source = g_source_new (&source_funcs, sizeof (GFileMonitorSource));
|
|
Packit |
ae235b |
fms = (GFileMonitorSource *) source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_init (&fms->lock);
|
|
Packit |
ae235b |
fms->instance = instance;
|
|
Packit |
ae235b |
fms->pending_changes = g_sequence_new (pending_change_free);
|
|
Packit |
ae235b |
fms->pending_changes_table = g_hash_table_new (str_hash0, str_equal0);
|
|
Packit |
ae235b |
fms->rate_limit = DEFAULT_RATE_LIMIT;
|
|
Packit |
ae235b |
fms->flags = flags;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (is_directory)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
fms->dirname = g_strdup (filename);
|
|
Packit |
ae235b |
fms->basename = NULL;
|
|
Packit |
ae235b |
fms->filename = NULL;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else if (flags & G_FILE_MONITOR_WATCH_HARD_LINKS)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
fms->dirname = NULL;
|
|
Packit |
ae235b |
fms->basename = NULL;
|
|
Packit |
ae235b |
fms->filename = g_strdup (filename);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
fms->dirname = g_path_get_dirname (filename);
|
|
Packit |
ae235b |
fms->basename = g_path_get_basename (filename);
|
|
Packit |
ae235b |
fms->filename = NULL;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return fms;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
G_DEFINE_ABSTRACT_TYPE (GLocalFileMonitor, g_local_file_monitor, G_TYPE_FILE_MONITOR)
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
enum {
|
|
Packit |
ae235b |
PROP_0,
|
|
Packit |
ae235b |
PROP_RATE_LIMIT,
|
|
Packit |
ae235b |
};
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_local_file_monitor_get_property (GObject *object, guint prop_id,
|
|
Packit |
ae235b |
GValue *value, GParamSpec *pspec)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GLocalFileMonitor *monitor = G_LOCAL_FILE_MONITOR (object);
|
|
Packit |
ae235b |
gint64 rate_limit;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_assert (prop_id == PROP_RATE_LIMIT);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
rate_limit = g_file_monitor_source_get_rate_limit (monitor->source);
|
|
Packit |
ae235b |
rate_limit /= G_TIME_SPAN_MILLISECOND;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_value_set_int (value, rate_limit);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_local_file_monitor_set_property (GObject *object, guint prop_id,
|
|
Packit |
ae235b |
const GValue *value, GParamSpec *pspec)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GLocalFileMonitor *monitor = G_LOCAL_FILE_MONITOR (object);
|
|
Packit |
ae235b |
gint64 rate_limit;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_assert (prop_id == PROP_RATE_LIMIT);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
rate_limit = g_value_get_int (value);
|
|
Packit |
ae235b |
rate_limit *= G_TIME_SPAN_MILLISECOND;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (g_file_monitor_source_set_rate_limit (monitor->source, rate_limit))
|
|
Packit |
ae235b |
g_object_notify (object, "rate-limit");
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#ifndef G_OS_WIN32
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_local_file_monitor_mounts_changed (GUnixMountMonitor *mount_monitor,
|
|
Packit |
ae235b |
gpointer user_data)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GLocalFileMonitor *local_monitor = user_data;
|
|
Packit |
ae235b |
GUnixMountEntry *mount;
|
|
Packit |
ae235b |
gboolean is_mounted;
|
|
Packit |
ae235b |
GFile *file;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Emulate unmount detection */
|
|
Packit |
ae235b |
mount = g_unix_mount_at (local_monitor->source->dirname, NULL);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
is_mounted = mount != NULL;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (mount)
|
|
Packit |
ae235b |
g_unix_mount_free (mount);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (local_monitor->was_mounted != is_mounted)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
if (local_monitor->was_mounted && !is_mounted)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
file = g_file_new_for_path (local_monitor->source->dirname);
|
|
Packit |
ae235b |
g_file_monitor_emit_event (G_FILE_MONITOR (local_monitor), file, NULL, G_FILE_MONITOR_EVENT_UNMOUNTED);
|
|
Packit |
ae235b |
g_object_unref (file);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
local_monitor->was_mounted = is_mounted;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
#endif
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_local_file_monitor_start (GLocalFileMonitor *local_monitor,
|
|
Packit |
ae235b |
const gchar *filename,
|
|
Packit |
ae235b |
gboolean is_directory,
|
|
Packit |
ae235b |
GFileMonitorFlags flags,
|
|
Packit |
ae235b |
GMainContext *context)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GLocalFileMonitorClass *class = G_LOCAL_FILE_MONITOR_GET_CLASS (local_monitor);
|
|
Packit |
ae235b |
GFileMonitorSource *source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_return_if_fail (G_IS_LOCAL_FILE_MONITOR (local_monitor));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_assert (!local_monitor->source);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
source = g_file_monitor_source_new (local_monitor, filename, is_directory, flags);
|
|
Packit |
ae235b |
local_monitor->source = source; /* owns the ref */
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (is_directory && !class->mount_notify && (flags & G_FILE_MONITOR_WATCH_MOUNTS))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
#ifdef G_OS_WIN32
|
|
Packit |
ae235b |
/*claim everything was mounted */
|
|
Packit |
ae235b |
local_monitor->was_mounted = TRUE;
|
|
Packit |
ae235b |
#else
|
|
Packit |
ae235b |
GUnixMountEntry *mount;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Emulate unmount detection */
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
mount = g_unix_mount_at (local_monitor->source->dirname, NULL);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
local_monitor->was_mounted = mount != NULL;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (mount)
|
|
Packit |
ae235b |
g_unix_mount_free (mount);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
local_monitor->mount_monitor = g_unix_mount_monitor_get ();
|
|
Packit |
ae235b |
g_signal_connect_object (local_monitor->mount_monitor, "mounts-changed",
|
|
Packit |
ae235b |
G_CALLBACK (g_local_file_monitor_mounts_changed), local_monitor, 0);
|
|
Packit |
ae235b |
#endif
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
G_LOCAL_FILE_MONITOR_GET_CLASS (local_monitor)->start (local_monitor,
|
|
Packit |
ae235b |
source->dirname, source->basename, source->filename,
|
|
Packit |
ae235b |
source);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_source_attach ((GSource *) source, context);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_local_file_monitor_dispose (GObject *object)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (object);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_file_monitor_source_dispose (local_monitor->source);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
G_OBJECT_CLASS (g_local_file_monitor_parent_class)->dispose (object);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_local_file_monitor_finalize (GObject *object)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (object);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_source_unref ((GSource *) local_monitor->source);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
G_OBJECT_CLASS (g_local_file_monitor_parent_class)->finalize (object);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_local_file_monitor_init (GLocalFileMonitor* local_monitor)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void g_local_file_monitor_class_init (GLocalFileMonitorClass *class)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
gobject_class->get_property = g_local_file_monitor_get_property;
|
|
Packit |
ae235b |
gobject_class->set_property = g_local_file_monitor_set_property;
|
|
Packit |
ae235b |
gobject_class->dispose = g_local_file_monitor_dispose;
|
|
Packit |
ae235b |
gobject_class->finalize = g_local_file_monitor_finalize;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_object_class_override_property (gobject_class, PROP_RATE_LIMIT, "rate-limit");
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static GLocalFileMonitor *
|
|
Packit |
ae235b |
g_local_file_monitor_new (gboolean is_remote_fs,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GType type = G_TYPE_INVALID;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (is_remote_fs)
|
|
Packit |
ae235b |
type = _g_io_module_get_default_type (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
|
Packit |
ae235b |
"GIO_USE_FILE_MONITOR",
|
|
Packit |
ae235b |
G_STRUCT_OFFSET (GLocalFileMonitorClass, is_supported));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (type == G_TYPE_INVALID)
|
|
Packit |
ae235b |
type = _g_io_module_get_default_type (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
|
Packit |
ae235b |
"GIO_USE_FILE_MONITOR",
|
|
Packit |
ae235b |
G_STRUCT_OFFSET (GLocalFileMonitorClass, is_supported));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (type == G_TYPE_INVALID)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
Packit |
ae235b |
_("Unable to find default local file monitor type"));
|
|
Packit |
ae235b |
return NULL;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return g_object_new (type, NULL);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
GFileMonitor *
|
|
Packit |
ae235b |
g_local_file_monitor_new_for_path (const gchar *pathname,
|
|
Packit |
ae235b |
gboolean is_directory,
|
|
Packit |
ae235b |
GFileMonitorFlags flags,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GLocalFileMonitor *monitor;
|
|
Packit |
ae235b |
gboolean is_remote_fs;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
is_remote_fs = g_local_file_is_remote (pathname);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
monitor = g_local_file_monitor_new (is_remote_fs, error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (monitor)
|
|
Packit |
ae235b |
g_local_file_monitor_start (monitor, pathname, is_directory, flags, g_main_context_get_thread_default ());
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return G_FILE_MONITOR (monitor);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
GFileMonitor *
|
|
Packit |
ae235b |
g_local_file_monitor_new_in_worker (const gchar *pathname,
|
|
Packit |
ae235b |
gboolean is_directory,
|
|
Packit |
ae235b |
GFileMonitorFlags flags,
|
|
Packit |
ae235b |
GFileMonitorCallback callback,
|
|
Packit |
ae235b |
gpointer user_data,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GLocalFileMonitor *monitor;
|
|
Packit |
ae235b |
gboolean is_remote_fs;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
is_remote_fs = g_local_file_is_remote (pathname);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
monitor = g_local_file_monitor_new (is_remote_fs, error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (monitor)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
if (callback)
|
|
Packit |
ae235b |
g_signal_connect (monitor, "changed", G_CALLBACK (callback), user_data);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_local_file_monitor_start (monitor, pathname, is_directory, flags, GLIB_PRIVATE_CALL(g_get_worker_context) ());
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return G_FILE_MONITOR (monitor);
|
|
Packit |
ae235b |
}
|