mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-21 08:28:53 +02:00
file monitors: rewrite FAM file monitor
Completely rewrite the FAM file monitor. Major changes: - now runs in the worker thread - dispatches events in a threadsafe way via GFileMonitorSource - uses unix fd source instead of a GIOChannel - is now simple enough to fit into one short file
This commit is contained in:
@@ -5,15 +5,7 @@ module_flags = -export_dynamic -avoid-version -module -no-undefined -export-symb
|
|||||||
giomodule_LTLIBRARIES = libgiofam.la
|
giomodule_LTLIBRARIES = libgiofam.la
|
||||||
giomoduledir = $(GIO_MODULE_DIR)
|
giomoduledir = $(GIO_MODULE_DIR)
|
||||||
|
|
||||||
libgiofam_la_SOURCES = \
|
libgiofam_la_SOURCES = gfamfilemonitor.c
|
||||||
fam-helper.c \
|
|
||||||
fam-helper.h \
|
|
||||||
fam-module.c \
|
|
||||||
gfamdirectorymonitor.c \
|
|
||||||
gfamdirectorymonitor.h \
|
|
||||||
gfamfilemonitor.c \
|
|
||||||
gfamfilemonitor.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
libgiofam_la_CFLAGS = \
|
libgiofam_la_CFLAGS = \
|
||||||
-DG_LOG_DOMAIN=\"GLib-GIO\" \
|
-DG_LOG_DOMAIN=\"GLib-GIO\" \
|
||||||
|
@@ -1,274 +0,0 @@
|
|||||||
/* GIO - GLib Input, Output and Streaming Library
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General
|
|
||||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
|
||||||
* John McCutchan <john@johnmccutchan.com>
|
|
||||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include <fam.h>
|
|
||||||
#include <gio/gfilemonitor.h>
|
|
||||||
#include <gio/gfile.h>
|
|
||||||
|
|
||||||
#include "fam-helper.h"
|
|
||||||
|
|
||||||
static FAMConnection* fam_connection = NULL;
|
|
||||||
static gint fam_watch_id = 0;
|
|
||||||
G_LOCK_DEFINE_STATIC(fam_connection);
|
|
||||||
|
|
||||||
struct _fam_sub
|
|
||||||
{
|
|
||||||
gchar *pathname;
|
|
||||||
gboolean directory;
|
|
||||||
gpointer user_data;
|
|
||||||
gboolean cancelled;
|
|
||||||
FAMRequest request;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* This uses int as the argument type because the
|
|
||||||
real type differs between implementations:
|
|
||||||
gamin has "typedef enum FAMCodes {....} FAMCodes;"
|
|
||||||
fam has "enum FAMCodes { ... }".
|
|
||||||
*/
|
|
||||||
static GFileMonitorEvent
|
|
||||||
fam_event_to_file_monitor_event (int code)
|
|
||||||
{
|
|
||||||
switch (code)
|
|
||||||
{
|
|
||||||
case FAMChanged:
|
|
||||||
return G_FILE_MONITOR_EVENT_CHANGED;
|
|
||||||
break;
|
|
||||||
case FAMDeleted:
|
|
||||||
return G_FILE_MONITOR_EVENT_DELETED;
|
|
||||||
break;
|
|
||||||
case FAMCreated:
|
|
||||||
return G_FILE_MONITOR_EVENT_CREATED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
fam_do_iter_unlocked (void)
|
|
||||||
{
|
|
||||||
while (fam_connection != NULL && FAMPending (fam_connection))
|
|
||||||
{
|
|
||||||
FAMEvent ev;
|
|
||||||
fam_sub* sub = NULL;
|
|
||||||
gboolean cancelled;
|
|
||||||
|
|
||||||
if (FAMNextEvent (fam_connection, &ev) != 1)
|
|
||||||
{
|
|
||||||
FAMClose (fam_connection);
|
|
||||||
g_free (fam_connection);
|
|
||||||
g_source_remove (fam_watch_id);
|
|
||||||
fam_watch_id = 0;
|
|
||||||
fam_connection = NULL;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub = (fam_sub*)ev.userdata;
|
|
||||||
cancelled = sub->cancelled;
|
|
||||||
if (ev.code == FAMAcknowledge && cancelled)
|
|
||||||
{
|
|
||||||
_fam_sub_free (sub);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cancelled)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (sub->directory)
|
|
||||||
{
|
|
||||||
GFileMonitor* monitor = G_FILE_MONITOR (sub->user_data);
|
|
||||||
GFileMonitorEvent eflags = fam_event_to_file_monitor_event (ev.code);
|
|
||||||
gchar* path = NULL;
|
|
||||||
GFile *child, *parent;
|
|
||||||
|
|
||||||
/* unsupported event */
|
|
||||||
if (eflags == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ev.filename[0] == '/')
|
|
||||||
path = g_strdup (ev.filename);
|
|
||||||
else
|
|
||||||
path = g_strdup_printf ("%s/%s", sub->pathname, ev.filename);
|
|
||||||
|
|
||||||
child = g_file_new_for_path (path);
|
|
||||||
parent = g_file_get_parent (child);
|
|
||||||
g_file_monitor_emit_event (monitor, child, NULL, eflags);
|
|
||||||
g_free (path);
|
|
||||||
g_object_unref (child);
|
|
||||||
g_object_unref (parent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GFile *child;
|
|
||||||
GFileMonitor* monitor = G_FILE_MONITOR (sub->user_data);
|
|
||||||
GFileMonitorEvent eflags = fam_event_to_file_monitor_event (ev.code);
|
|
||||||
gchar* path = NULL;
|
|
||||||
|
|
||||||
if (eflags == -1)
|
|
||||||
continue;
|
|
||||||
path = g_strdup (ev.filename);
|
|
||||||
child = g_file_new_for_path (path);
|
|
||||||
g_file_monitor_emit_event (monitor, child, NULL, eflags);
|
|
||||||
g_free (path);
|
|
||||||
g_object_unref (child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
fam_callback (GIOChannel *source,
|
|
||||||
GIOCondition condition,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
gboolean res;
|
|
||||||
G_LOCK (fam_connection);
|
|
||||||
|
|
||||||
res = fam_do_iter_unlocked ();
|
|
||||||
|
|
||||||
G_UNLOCK (fam_connection);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
_fam_sub_startup (void)
|
|
||||||
{
|
|
||||||
GIOChannel *ioc;
|
|
||||||
|
|
||||||
G_LOCK (fam_connection);
|
|
||||||
|
|
||||||
if (fam_connection == NULL)
|
|
||||||
{
|
|
||||||
fam_connection = g_new0 (FAMConnection, 1);
|
|
||||||
if (FAMOpen2 (fam_connection, "gvfs user") != 0)
|
|
||||||
{
|
|
||||||
g_warning ("FAMOpen failed, FAMErrno=%d\n", FAMErrno);
|
|
||||||
g_free (fam_connection);
|
|
||||||
fam_connection = NULL;
|
|
||||||
G_UNLOCK (fam_connection);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
#ifdef HAVE_FAM_NO_EXISTS
|
|
||||||
/* This is a gamin extension that avoids sending all the Exists event for dir monitors */
|
|
||||||
FAMNoExists (fam_connection);
|
|
||||||
#endif
|
|
||||||
ioc = g_io_channel_unix_new (FAMCONNECTION_GETFD(fam_connection));
|
|
||||||
fam_watch_id = g_io_add_watch (ioc,
|
|
||||||
G_IO_IN | G_IO_HUP | G_IO_ERR,
|
|
||||||
fam_callback, fam_connection);
|
|
||||||
g_io_channel_unref (ioc);
|
|
||||||
}
|
|
||||||
|
|
||||||
G_UNLOCK (fam_connection);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_fam_sub_shutdown (void)
|
|
||||||
{
|
|
||||||
G_LOCK (fam_connection);
|
|
||||||
|
|
||||||
if (fam_connection != NULL)
|
|
||||||
{
|
|
||||||
FAMClose (fam_connection);
|
|
||||||
g_free (fam_connection);
|
|
||||||
g_source_remove (fam_watch_id);
|
|
||||||
fam_watch_id = 0;
|
|
||||||
fam_connection = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
G_UNLOCK (fam_connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
fam_sub*
|
|
||||||
_fam_sub_add (const gchar *pathname,
|
|
||||||
gboolean directory,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
fam_sub *sub;
|
|
||||||
|
|
||||||
if (!_fam_sub_startup ())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
G_LOCK (fam_connection);
|
|
||||||
/* We need to queue up incoming messages to avoid blocking on write
|
|
||||||
* if there are many monitors being canceled */
|
|
||||||
fam_do_iter_unlocked ();
|
|
||||||
|
|
||||||
if (fam_connection == NULL)
|
|
||||||
{
|
|
||||||
G_UNLOCK (fam_connection);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub = g_new0 (fam_sub, 1);
|
|
||||||
sub->pathname = g_strdup (pathname);
|
|
||||||
sub->directory = directory;
|
|
||||||
sub->user_data = user_data;
|
|
||||||
|
|
||||||
if (directory)
|
|
||||||
FAMMonitorDirectory (fam_connection, pathname, &sub->request, sub);
|
|
||||||
else
|
|
||||||
FAMMonitorFile (fam_connection, pathname, &sub->request, sub);
|
|
||||||
|
|
||||||
G_UNLOCK (fam_connection);
|
|
||||||
|
|
||||||
return sub;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
_fam_sub_cancel (fam_sub* sub)
|
|
||||||
{
|
|
||||||
if (sub->cancelled)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
sub->cancelled = TRUE;
|
|
||||||
|
|
||||||
G_LOCK (fam_connection);
|
|
||||||
/* We need to queue up incoming messages to avoid blocking on write
|
|
||||||
* if there are many monitors being canceled */
|
|
||||||
fam_do_iter_unlocked ();
|
|
||||||
|
|
||||||
if (fam_connection == NULL)
|
|
||||||
{
|
|
||||||
G_UNLOCK (fam_connection);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
FAMCancelMonitor (fam_connection, &sub->request);
|
|
||||||
|
|
||||||
G_UNLOCK (fam_connection);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_fam_sub_free (fam_sub* sub)
|
|
||||||
{
|
|
||||||
g_free (sub->pathname);
|
|
||||||
g_free (sub);
|
|
||||||
}
|
|
||||||
|
|
@@ -1,36 +0,0 @@
|
|||||||
/* GIO - GLib Input, Output and Streaming Library
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General
|
|
||||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
|
||||||
* John McCutchan <john@johnmccutchan.com>
|
|
||||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FAM_HELPER_H__
|
|
||||||
#define __FAM_HELPER_H__
|
|
||||||
|
|
||||||
typedef struct _fam_sub fam_sub;
|
|
||||||
|
|
||||||
gboolean _fam_sub_startup (void);
|
|
||||||
void _fam_sub_shutdown (void);
|
|
||||||
fam_sub* _fam_sub_add (const gchar* pathname,
|
|
||||||
gboolean directory,
|
|
||||||
gpointer user_data);
|
|
||||||
gboolean _fam_sub_cancel (fam_sub* sub);
|
|
||||||
void _fam_sub_free (fam_sub* sub);
|
|
||||||
|
|
||||||
#endif /* __FAM_HELPER_H__ */
|
|
@@ -1,54 +0,0 @@
|
|||||||
/* GIO - GLib Input, Output and Streaming Library
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
||||||
* Copyright (C) 2007 Sebastian Dröge.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General
|
|
||||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
|
||||||
* John McCutchan <john@johnmccutchan.com>
|
|
||||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gio/giomodule.h>
|
|
||||||
#include "gfamdirectorymonitor.h"
|
|
||||||
#include "gfamfilemonitor.h"
|
|
||||||
#include "fam-helper.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
g_io_module_load (GIOModule *module)
|
|
||||||
{
|
|
||||||
g_fam_file_monitor_register (module);
|
|
||||||
g_fam_directory_monitor_register (module);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
g_io_module_unload (GIOModule *module)
|
|
||||||
{
|
|
||||||
_fam_sub_shutdown ();
|
|
||||||
}
|
|
||||||
|
|
||||||
char **
|
|
||||||
g_io_module_query (void)
|
|
||||||
{
|
|
||||||
char *eps[] = {
|
|
||||||
G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
|
|
||||||
G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
|
||||||
G_NFS_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
|
|
||||||
G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
return g_strdupv (eps);
|
|
||||||
}
|
|
||||||
|
|
@@ -1,155 +0,0 @@
|
|||||||
/* GIO - GLib Input, Output and Streaming Library
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
||||||
* Copyright (C) 2007 Sebastian Dröge.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General
|
|
||||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
|
||||||
* John McCutchan <john@johnmccutchan.com>
|
|
||||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "gfamdirectorymonitor.h"
|
|
||||||
#include <gio/giomodule.h>
|
|
||||||
|
|
||||||
#include "fam-helper.h"
|
|
||||||
|
|
||||||
struct _GFamDirectoryMonitor
|
|
||||||
{
|
|
||||||
GLocalDirectoryMonitor parent_instance;
|
|
||||||
fam_sub *sub;
|
|
||||||
};
|
|
||||||
|
|
||||||
static gboolean g_fam_directory_monitor_cancel (GFileMonitor* monitor);
|
|
||||||
|
|
||||||
G_DEFINE_DYNAMIC_TYPE (GFamDirectoryMonitor, g_fam_directory_monitor, G_TYPE_LOCAL_DIRECTORY_MONITOR)
|
|
||||||
|
|
||||||
static void
|
|
||||||
g_fam_directory_monitor_finalize (GObject *object)
|
|
||||||
{
|
|
||||||
GFamDirectoryMonitor *fam_monitor = G_FAM_DIRECTORY_MONITOR (object);
|
|
||||||
fam_sub *sub = fam_monitor->sub;
|
|
||||||
|
|
||||||
if (sub) {
|
|
||||||
if (!_fam_sub_cancel (sub))
|
|
||||||
g_warning ("Unexpected error cancelling fam monitor");
|
|
||||||
|
|
||||||
fam_monitor->sub = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (G_OBJECT_CLASS (g_fam_directory_monitor_parent_class)->finalize)
|
|
||||||
(*G_OBJECT_CLASS (g_fam_directory_monitor_parent_class)->finalize) (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GObject *
|
|
||||||
g_fam_directory_monitor_constructor (GType type,
|
|
||||||
guint n_construct_properties,
|
|
||||||
GObjectConstructParam *construct_properties)
|
|
||||||
{
|
|
||||||
GObject *obj;
|
|
||||||
GFamDirectoryMonitorClass *klass;
|
|
||||||
GObjectClass *parent_class;
|
|
||||||
GFamDirectoryMonitor *fam_monitor;
|
|
||||||
const gchar *dirname = NULL;
|
|
||||||
fam_sub *sub = NULL;
|
|
||||||
|
|
||||||
klass = G_FAM_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_FAM_DIRECTORY_MONITOR));
|
|
||||||
parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
|
|
||||||
obj = parent_class->constructor (type,
|
|
||||||
n_construct_properties,
|
|
||||||
construct_properties);
|
|
||||||
|
|
||||||
fam_monitor = G_FAM_DIRECTORY_MONITOR (obj);
|
|
||||||
|
|
||||||
dirname = G_LOCAL_DIRECTORY_MONITOR (obj)->dirname;
|
|
||||||
g_assert (dirname != NULL);
|
|
||||||
|
|
||||||
sub = _fam_sub_add (dirname, TRUE, fam_monitor);
|
|
||||||
/* FIXME: what to do about errors here? we can't return NULL or another
|
|
||||||
* kind of error and an assertion is probably too hard */
|
|
||||||
g_assert (sub != NULL);
|
|
||||||
|
|
||||||
fam_monitor->sub = sub;
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
g_fam_directory_monitor_class_finalize (GFamDirectoryMonitorClass *klass)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
g_fam_directory_monitor_is_supported (void)
|
|
||||||
{
|
|
||||||
return _fam_sub_startup ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
g_fam_directory_monitor_class_init (GFamDirectoryMonitorClass* klass)
|
|
||||||
{
|
|
||||||
GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
|
|
||||||
GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass);
|
|
||||||
GLocalDirectoryMonitorClass *local_directory_monitor_class = G_LOCAL_DIRECTORY_MONITOR_CLASS (klass);
|
|
||||||
|
|
||||||
gobject_class->finalize = g_fam_directory_monitor_finalize;
|
|
||||||
gobject_class->constructor = g_fam_directory_monitor_constructor;
|
|
||||||
file_monitor_class->cancel = g_fam_directory_monitor_cancel;
|
|
||||||
|
|
||||||
local_directory_monitor_class->mount_notify = FALSE;
|
|
||||||
local_directory_monitor_class->is_supported = g_fam_directory_monitor_is_supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
g_fam_directory_monitor_init (GFamDirectoryMonitor* monitor)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
g_fam_directory_monitor_cancel (GFileMonitor* monitor)
|
|
||||||
{
|
|
||||||
GFamDirectoryMonitor *fam_monitor = G_FAM_DIRECTORY_MONITOR (monitor);
|
|
||||||
fam_sub *sub = fam_monitor->sub;
|
|
||||||
|
|
||||||
if (sub) {
|
|
||||||
if (!_fam_sub_cancel (sub))
|
|
||||||
g_warning ("Unexpected error cancelling fam monitor");
|
|
||||||
|
|
||||||
fam_monitor->sub = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (G_FILE_MONITOR_CLASS (g_fam_directory_monitor_parent_class)->cancel)
|
|
||||||
(*G_FILE_MONITOR_CLASS (g_fam_directory_monitor_parent_class)->cancel) (monitor);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
g_fam_directory_monitor_register (GIOModule *module)
|
|
||||||
{
|
|
||||||
g_fam_directory_monitor_register_type (G_TYPE_MODULE (module));
|
|
||||||
g_io_extension_point_implement (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
|
|
||||||
G_TYPE_FAM_DIRECTORY_MONITOR,
|
|
||||||
"fam",
|
|
||||||
10);
|
|
||||||
g_io_extension_point_implement (G_NFS_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
|
|
||||||
G_TYPE_FAM_DIRECTORY_MONITOR,
|
|
||||||
"fam",
|
|
||||||
10);
|
|
||||||
}
|
|
||||||
|
|
@@ -1,52 +0,0 @@
|
|||||||
/* GIO - GLib Input, Output and Streaming Library
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
||||||
* Copyright (C) 2007 Sebastian Dröge.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General
|
|
||||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
|
||||||
* John McCutchan <john@johnmccutchan.com>
|
|
||||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __G_FAM_DIRECTORY_MONITOR_H__
|
|
||||||
#define __G_FAM_DIRECTORY_MONITOR_H__
|
|
||||||
|
|
||||||
#include <glib-object.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <gio/glocaldirectorymonitor.h>
|
|
||||||
#include <gio/giomodule.h>
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define G_TYPE_FAM_DIRECTORY_MONITOR (g_fam_directory_monitor_get_type ())
|
|
||||||
#define G_FAM_DIRECTORY_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_FAM_DIRECTORY_MONITOR, GFamDirectoryMonitor))
|
|
||||||
#define G_FAM_DIRECTORY_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), G_TYPE_FAM_DIRECTORY_MONITOR, GFamDirectoryMonitorClass))
|
|
||||||
#define G_IS_FAM_DIRECTORY_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_FAM_DIRECTORY_MONITOR))
|
|
||||||
#define G_IS_FAM_DIRECTORY_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FAM_DIRECTORY_MONITOR))
|
|
||||||
|
|
||||||
typedef struct _GFamDirectoryMonitor GFamDirectoryMonitor;
|
|
||||||
typedef struct _GFamDirectoryMonitorClass GFamDirectoryMonitorClass;
|
|
||||||
|
|
||||||
struct _GFamDirectoryMonitorClass {
|
|
||||||
GLocalDirectoryMonitorClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
GType g_fam_directory_monitor_get_type (void);
|
|
||||||
void g_fam_directory_monitor_register (GIOModule *module);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __G_FAM_DIRECTORY_MONITOR_H__ */
|
|
@@ -1,7 +1,5 @@
|
|||||||
/* GIO - GLib Input, Output and Streaming Library
|
/*
|
||||||
*
|
* Copyright © 2015 Canonical Limited
|
||||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
||||||
* Copyright (C) 2007 Sebastian Dröge.
|
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@@ -16,138 +14,224 @@
|
|||||||
* You should have received a copy of the GNU Lesser General
|
* You should have received a copy of the GNU Lesser General
|
||||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||||
* John McCutchan <john@johnmccutchan.com>
|
|
||||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "gfamfilemonitor.h"
|
#include <gio/glocalfilemonitor.h>
|
||||||
#include <gio/giomodule.h>
|
#include <gio/giomodule.h>
|
||||||
|
#include "glib-private.h"
|
||||||
|
#include <glib-unix.h>
|
||||||
|
#include <fam.h>
|
||||||
|
|
||||||
#include "fam-helper.h"
|
static GMutex fam_lock;
|
||||||
|
static gboolean fam_initialised;
|
||||||
|
static FAMConnection fam_connection;
|
||||||
|
static GSource *fam_source;
|
||||||
|
|
||||||
struct _GFamFileMonitor
|
#define G_TYPE_FAM_FILE_MONITOR (g_fam_file_monitor_get_type ())
|
||||||
|
#define G_FAM_FILE_MONITOR(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
||||||
|
G_TYPE_FAM_FILE_MONITOR, GFamFileMonitor))
|
||||||
|
|
||||||
|
typedef GLocalFileMonitorClass GFamFileMonitorClass;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
{
|
{
|
||||||
GLocalFileMonitor parent_instance;
|
GLocalFileMonitor parent_instance;
|
||||||
fam_sub *sub;
|
|
||||||
};
|
|
||||||
|
|
||||||
static gboolean g_fam_file_monitor_cancel (GFileMonitor* monitor);
|
FAMRequest request;
|
||||||
|
} GFamFileMonitor;
|
||||||
|
|
||||||
|
static GType g_fam_file_monitor_get_type (void);
|
||||||
G_DEFINE_DYNAMIC_TYPE (GFamFileMonitor, g_fam_file_monitor, G_TYPE_LOCAL_FILE_MONITOR)
|
G_DEFINE_DYNAMIC_TYPE (GFamFileMonitor, g_fam_file_monitor, G_TYPE_LOCAL_FILE_MONITOR)
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
g_fam_file_monitor_finalize (GObject *object)
|
g_fam_file_monitor_callback (gint fd,
|
||||||
|
GIOCondition condition,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GFamFileMonitor *fam_monitor = G_FAM_FILE_MONITOR (object);
|
gint64 now = g_source_get_time (fam_source);
|
||||||
fam_sub *sub = fam_monitor->sub;
|
|
||||||
|
|
||||||
if (sub) {
|
g_mutex_lock (&fam_lock);
|
||||||
if (!_fam_sub_cancel (sub))
|
|
||||||
g_warning ("Unexpected error cancelling fam monitor");
|
|
||||||
fam_monitor->sub = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (G_OBJECT_CLASS (g_fam_file_monitor_parent_class)->finalize)
|
while (FAMPending (&fam_connection))
|
||||||
(*G_OBJECT_CLASS (g_fam_file_monitor_parent_class)->finalize) (object);
|
{
|
||||||
}
|
const gchar *child;
|
||||||
|
FAMEvent ev;
|
||||||
|
|
||||||
static GObject *
|
if (FAMNextEvent (&fam_connection, &ev) != 1)
|
||||||
g_fam_file_monitor_constructor (GType type,
|
{
|
||||||
guint n_construct_properties,
|
/* The daemon died. We're in a really bad situation now
|
||||||
GObjectConstructParam *construct_properties)
|
* because we potentially have a bunch of request structures
|
||||||
{
|
* outstanding which no longer make any sense to anyone.
|
||||||
GObject *obj;
|
*
|
||||||
GFamFileMonitorClass *klass;
|
* The best thing that we can do is do nothing. Notification
|
||||||
GObjectClass *parent_class;
|
* won't work anymore for this process.
|
||||||
GFamFileMonitor *fam_monitor;
|
*/
|
||||||
const gchar *filename = NULL;
|
g_mutex_unlock (&fam_lock);
|
||||||
fam_sub *sub = NULL;
|
|
||||||
|
|
||||||
klass = G_FAM_FILE_MONITOR_CLASS (g_type_class_peek (G_TYPE_FAM_FILE_MONITOR));
|
|
||||||
parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
|
|
||||||
obj = parent_class->constructor (type,
|
|
||||||
n_construct_properties,
|
|
||||||
construct_properties);
|
|
||||||
|
|
||||||
fam_monitor = G_FAM_FILE_MONITOR (obj);
|
g_warning ("Lost connection to FAM (file monitoring) service. Expect no further file monitor events.");
|
||||||
|
|
||||||
filename = G_LOCAL_FILE_MONITOR (obj)->filename;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
g_assert (filename != NULL);
|
/* We expect ev.filename to be a relative path for children in a
|
||||||
|
* monitored directory, and an absolute path for a monitored file
|
||||||
|
* or the directory itself.
|
||||||
|
*/
|
||||||
|
if (ev.filename[0] != '/')
|
||||||
|
child = ev.filename;
|
||||||
|
else
|
||||||
|
child = NULL;
|
||||||
|
|
||||||
sub = _fam_sub_add (filename, FALSE, fam_monitor);
|
switch (ev.code)
|
||||||
/* FIXME: what to do about errors here? we can't return NULL or another
|
{
|
||||||
* kind of error and an assertion is probably too hard */
|
case FAMAcknowledge:
|
||||||
g_assert (sub != NULL);
|
g_source_unref (ev.userdata);
|
||||||
|
break;
|
||||||
|
|
||||||
fam_monitor->sub = sub;
|
case FAMChanged:
|
||||||
|
g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CHANGED, child, NULL, NULL, now);
|
||||||
|
break;
|
||||||
|
|
||||||
return obj;
|
case FAMDeleted:
|
||||||
}
|
g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_DELETED, child, NULL, NULL, now);
|
||||||
|
break;
|
||||||
|
|
||||||
static void
|
case FAMCreated:
|
||||||
g_fam_file_monitor_class_finalize (GFamFileMonitorClass *klass)
|
g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CREATED, child, NULL, NULL, now);
|
||||||
{
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* unknown type */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_unlock (&fam_lock);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
g_fam_file_monitor_is_supported (void)
|
g_fam_file_monitor_is_supported (void)
|
||||||
{
|
{
|
||||||
return _fam_sub_startup ();
|
g_mutex_lock (&fam_lock);
|
||||||
|
|
||||||
|
if (!fam_initialised)
|
||||||
|
{
|
||||||
|
fam_initialised = FAMOpen2 (&fam_connection, "GLib GIO") == 0;
|
||||||
|
|
||||||
|
if (fam_initialised)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_FAM_NO_EXISTS
|
||||||
|
/* This is a gamin extension that avoids sending all the
|
||||||
|
* Exists event for dir monitors
|
||||||
|
*/
|
||||||
|
FAMNoExists (&fam_connection);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fam_source = g_unix_fd_source_new (FAMCONNECTION_GETFD (&fam_connection), G_IO_IN);
|
||||||
|
g_source_set_callback (fam_source, (GSourceFunc) g_fam_file_monitor_callback, NULL, NULL);
|
||||||
|
g_source_attach (fam_source, GLIB_PRIVATE_CALL(g_get_worker_context) ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_unlock (&fam_lock);
|
||||||
|
|
||||||
|
g_print ("II %d\n", fam_initialised);
|
||||||
|
|
||||||
|
return fam_initialised;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
g_fam_file_monitor_cancel (GFileMonitor *monitor)
|
||||||
|
{
|
||||||
|
GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (monitor);
|
||||||
|
|
||||||
|
g_mutex_lock (&fam_lock);
|
||||||
|
|
||||||
|
g_assert (fam_initialised);
|
||||||
|
|
||||||
|
FAMCancelMonitor (&fam_connection, &gffm->request);
|
||||||
|
|
||||||
|
g_mutex_unlock (&fam_lock);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_fam_file_monitor_class_init (GFamFileMonitorClass* klass)
|
g_fam_file_monitor_start (GLocalFileMonitor *local_monitor,
|
||||||
|
const gchar *dirname,
|
||||||
|
const gchar *basename,
|
||||||
|
const gchar *filename,
|
||||||
|
GFileMonitorSource *source)
|
||||||
{
|
{
|
||||||
GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
|
GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (local_monitor);
|
||||||
GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass);
|
|
||||||
GLocalFileMonitorClass *local_file_monitor_class = G_LOCAL_FILE_MONITOR_CLASS (klass);
|
|
||||||
|
|
||||||
gobject_class->finalize = g_fam_file_monitor_finalize;
|
|
||||||
gobject_class->constructor = g_fam_file_monitor_constructor;
|
|
||||||
file_monitor_class->cancel = g_fam_file_monitor_cancel;
|
|
||||||
|
|
||||||
local_file_monitor_class->is_supported = g_fam_file_monitor_is_supported;
|
g_mutex_lock (&fam_lock);
|
||||||
|
|
||||||
|
g_assert (fam_initialised);
|
||||||
|
|
||||||
|
g_source_ref ((GSource *) source);
|
||||||
|
|
||||||
|
if (dirname)
|
||||||
|
FAMMonitorDirectory (&fam_connection, dirname, &gffm->request, source);
|
||||||
|
else
|
||||||
|
FAMMonitorFile (&fam_connection, filename, &gffm->request, source);
|
||||||
|
|
||||||
|
g_mutex_unlock (&fam_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_fam_file_monitor_init (GFamFileMonitor* monitor)
|
g_fam_file_monitor_init (GFamFileMonitor* monitor)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
g_fam_file_monitor_cancel (GFileMonitor* monitor)
|
g_fam_file_monitor_class_init (GFamFileMonitorClass *class)
|
||||||
{
|
{
|
||||||
GFamFileMonitor *fam_monitor = G_FAM_FILE_MONITOR (monitor);
|
GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (class);
|
||||||
fam_sub *sub = fam_monitor->sub;
|
|
||||||
|
|
||||||
if (sub) {
|
class->is_supported = g_fam_file_monitor_is_supported;
|
||||||
if (!_fam_sub_cancel (sub))
|
class->start = g_fam_file_monitor_start;
|
||||||
g_warning ("Unexpected error cancelling fam monitor");
|
file_monitor_class->cancel = g_fam_file_monitor_cancel;
|
||||||
fam_monitor->sub = NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (G_FILE_MONITOR_CLASS (g_fam_file_monitor_parent_class)->cancel)
|
static void
|
||||||
(*G_FILE_MONITOR_CLASS (g_fam_file_monitor_parent_class)->cancel) (monitor);
|
g_fam_file_monitor_class_finalize (GFamFileMonitorClass *class)
|
||||||
|
{
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
g_fam_file_monitor_register (GIOModule *module)
|
g_io_module_load (GIOModule *module)
|
||||||
{
|
{
|
||||||
|
g_type_module_use (G_TYPE_MODULE (module));
|
||||||
|
|
||||||
g_fam_file_monitor_register_type (G_TYPE_MODULE (module));
|
g_fam_file_monitor_register_type (G_TYPE_MODULE (module));
|
||||||
|
|
||||||
g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||||
G_TYPE_FAM_FILE_MONITOR,
|
G_TYPE_FAM_FILE_MONITOR, "fam", 10);
|
||||||
"fam",
|
|
||||||
10);
|
|
||||||
g_io_extension_point_implement (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
g_io_extension_point_implement (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||||
G_TYPE_FAM_FILE_MONITOR,
|
G_TYPE_FAM_FILE_MONITOR, "fam", 10);
|
||||||
"fam",
|
|
||||||
10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_io_module_unload (GIOModule *module)
|
||||||
|
{
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
char **
|
||||||
|
g_io_module_query (void)
|
||||||
|
{
|
||||||
|
char *eps[] = {
|
||||||
|
G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||||
|
G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
return g_strdupv (eps);
|
||||||
|
}
|
||||||
|
@@ -1,53 +0,0 @@
|
|||||||
/* GIO - GLib Input, Output and Streaming Library
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
||||||
* Copyright (C) 2007 Sebastian Dröge.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General
|
|
||||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
|
||||||
* John McCutchan <john@johnmccutchan.com>
|
|
||||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __G_FAM_FILE_MONITOR_H__
|
|
||||||
#define __G_FAM_FILE_MONITOR_H__
|
|
||||||
|
|
||||||
#include <glib-object.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <gio/gfilemonitor.h>
|
|
||||||
#include <gio/glocalfilemonitor.h>
|
|
||||||
#include <gio/giomodule.h>
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define G_TYPE_FAM_FILE_MONITOR (g_fam_file_monitor_get_type ())
|
|
||||||
#define G_FAM_FILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_FAM_FILE_MONITOR, GFamFileMonitor))
|
|
||||||
#define G_FAM_FILE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), G_TYPE_FAM_FILE_MONITOR, GFamFileMonitorClass))
|
|
||||||
#define G_IS_FAM_FILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_FAM_FILE_MONITOR))
|
|
||||||
#define G_IS_FAM_FILE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FAM_FILE_MONITOR))
|
|
||||||
|
|
||||||
typedef struct _GFamFileMonitor GFamFileMonitor;
|
|
||||||
typedef struct _GFamFileMonitorClass GFamFileMonitorClass;
|
|
||||||
|
|
||||||
struct _GFamFileMonitorClass {
|
|
||||||
GLocalFileMonitorClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
GType g_fam_file_monitor_get_type (void);
|
|
||||||
void g_fam_file_monitor_register (GIOModule *module);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __G_FAM_FILE_MONITOR_H__ */
|
|
Reference in New Issue
Block a user