This is actually a mail I sent on gtk-devel-list. Obligatory disclaimer: this is not a proposal for getting gnome-vfs inside GLib, or for making GTK depend on gnome-vfs or for replacing gnome-vfs entirely; please, read on before commenting.
A while ago, on IRC, Christian Persch made the request that the monitoring of the storage file used by the GtkRecentManager could be overridden by libgnome, so that every application using the GnomeProgram
API would automagically have notifications of file changes using gnome-vfs, instead of the default implementation which stat()s the file once in a while.
This spawned a more interesting discussion about how to implement a simple file monitoring API inside GLib; my approach and Christian’s were equivalent, and resolved in a new object with a vtable to be overridden per-process. Matthias, instead, suggested using a GSource
, and having the file monitor to play nice with the main loop. Thus GFileMonitor
was born.
Description
The file monitoring API is as simple as the current API for idle and timeout sources:
GSource *g_file_monitor_source_new (const gchar *uri);
gint g_file_monitor_add_full (gint priority
const gchar *uri,
GFileMonitorFunc function,
gpointer data,
GDestroyNotify notify);
gint g_file_monitor_add (const gchar *uri,
GFileMonitorFunc function,
gpointer data);
Where GFileMonitorFunc
has the signature:
typedef gboolean (*GFileMonitorFunc) (const gchar *uri,
GFileEvent event,
gpointer data);
And works like every other GSourceFunc
(continues until you return FALSE
); GFileEvent
is an enumeration:
typedef enum {
G_FILE_CREATED_EVENT,
G_FILE_CHANGED_EVENT,
G_FILE_REMOVED_EVENT,
G_FILE_UNKNOWN_EVENT
} GFileEvent;
The default implementation uses stat()
for checking for file changes; it uses a quantum-based timeout delay; that is: the more time passes between one file event and the next, the more the timeout will be increased.
The nice part is that the file monitor is “pluggable” – that is, you can use another file notification mechanism (like gnome-vfs) to actually get the notification of the changes. This is done using hooks:
typedef struct _GFileMonitorHooks GFileMonitorHooks;
struct _GFileMonitorHooks
{
gboolean (*add_monitor) (const gchar *uri,
gpointer data);
gboolean (*cancel_monitor) (const gchar *uri,
gpointer data);
gboolean (*check_uri) (const gchar *uri,
GFileEvent *event,
gpointer data);
};
void g_set_file_monitor_hooks (GFileMonitorHooks *hooks,
gpointer data);
The add_monitor hook will be invoked before the source created by g_file_monitor_add()
and g_file_monitor_add_full()
is attached to the main loop; the cancel_monitor hook will be invoked if the callback returns FALSE
; the check_uri hook is where the magic happens: it will be called at each iteration of the main loop, and will be used to check if uri has changed. The gnome-vfs implementation (attached to bug #340746) uses this hook to check for a flag inside a structure; the flag is set by the callback invoked by the GnomeVFSMonitor
created inside the add_monitor hook and destroyed inside the cancel_monitor hook.
Rationale
It’s important (very important: please don’t reply with “you should use gnome-vfs” – I know that, and you missed the point of this RFC) to note that this file monitoring is not intended to be more complicated than this or to replace in any way gnome-vfs; it’s useful only if you can’t depend on gnome-vfs, and for monitoring a single, local file without too much accuracy. If you need directory monitoring, more events, efficiency and remote files support, then by all means you
should use gnome-vfs.
Further improvements
A possible further enhancement would be changing the default implementation to use i-notify if it’s found at compile time, and to fall back to the stat()
implementation if not (or on other platforms than linux >= 2.6.13, unless they have a native file monitoring API we could hook into).
that said, this blog officially pushes his way room among my favorites :)
are the comments working..?
well, just wanted to say hi, in the end, and to let you know it feels good to read the latest entry. l