406 lines
9.4 KiB
Diff
406 lines
9.4 KiB
Diff
--- gtk+-2.10.3/gtk/gtkrecentmanager.c.fam 2006-08-18 11:30:57.000000000 -0400
|
|
+++ gtk+-2.10.3/gtk/gtkrecentmanager.c 2006-09-05 11:33:48.000000000 -0400
|
|
@@ -38,6 +38,9 @@
|
|
#include "gtktypebuiltins.h"
|
|
#include "gtkprivate.h"
|
|
#include "gtkmarshalers.h"
|
|
+
|
|
+#include <fam.h>
|
|
+
|
|
#include "gtkalias.h"
|
|
|
|
#ifdef G_OS_UNIX
|
|
@@ -110,6 +113,9 @@
|
|
|
|
time_t last_mtime;
|
|
guint poll_timeout;
|
|
+
|
|
+ FAMRequest *fam_request;
|
|
+ guint changed_timeout;
|
|
};
|
|
|
|
enum
|
|
@@ -274,6 +280,309 @@
|
|
g_type_class_add_private (klass, sizeof (GtkRecentManagerPrivate));
|
|
}
|
|
|
|
+
|
|
+/* fam support */
|
|
+#undef DEBUG_FAM
|
|
+
|
|
+static FAMConnection fam_connection;
|
|
+static gboolean opened_connection = FALSE;
|
|
+static gboolean failed_to_connect = FALSE;
|
|
+static guint fam_io_watch = 0;
|
|
+
|
|
+static int (*fam_open) (FAMConnection *fc) = NULL;
|
|
+static int (*fam_close) (FAMConnection *fc) = NULL;
|
|
+static int (*fam_pending) (FAMConnection *fc) = NULL;
|
|
+static int (*fam_next_event) (FAMConnection *fc,
|
|
+ FAMEvent *fe) = NULL;
|
|
+static int (*fam_monitor_file) (FAMConnection *fc,
|
|
+ const char *filename,
|
|
+ FAMRequest *fr,
|
|
+ void *userData) = NULL;
|
|
+static int (*fam_cancel_monitor) (FAMConnection *fc,
|
|
+ const FAMRequest *fr) = NULL;
|
|
+
|
|
+
|
|
+static struct FamDlMapping
|
|
+{
|
|
+ const char *fn_name;
|
|
+ gpointer fn_ptr_ref;
|
|
+} fam_dl_mapping[] = {
|
|
+ { "FAMOpen", &fam_open },
|
|
+ { "FAMClose", &fam_close },
|
|
+ { "FAMPending", &fam_pending },
|
|
+ { "FAMNextEvent", &fam_next_event },
|
|
+ { "FAMMonitorFile", &fam_monitor_file },
|
|
+ { "FAMCancelMonitor", &fam_cancel_monitor }
|
|
+};
|
|
+
|
|
+static void
|
|
+open_libfam (void)
|
|
+{
|
|
+ static gboolean done = FALSE;
|
|
+
|
|
+ if (!done)
|
|
+ {
|
|
+ int i;
|
|
+ GModule *fam;
|
|
+
|
|
+ done = TRUE;
|
|
+
|
|
+ fam = g_module_open ("libfam.so.0", G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
|
|
+ if (!fam)
|
|
+ {
|
|
+ g_warning ("Can't open libfam '%s'\n", g_module_error ());
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < G_N_ELEMENTS (fam_dl_mapping); i++)
|
|
+ {
|
|
+ if (!g_module_symbol (fam, fam_dl_mapping[i].fn_name,
|
|
+ fam_dl_mapping[i].fn_ptr_ref))
|
|
+ {
|
|
+ g_warning ("Missing symbol '%s' in libfam\n",
|
|
+ fam_dl_mapping[i].fn_name);
|
|
+ g_module_close (fam);
|
|
+ for (i = 0; i < G_N_ELEMENTS (fam_dl_mapping); i++)
|
|
+ fam_dl_mapping[i].fn_ptr_ref = NULL;
|
|
+
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+changed_timeout (gpointer data)
|
|
+{
|
|
+ GtkRecentManager *manager;
|
|
+
|
|
+ GDK_THREADS_ENTER ();
|
|
+
|
|
+ manager = (GtkRecentManager *)data;
|
|
+ manager->priv->changed_timeout = 0;
|
|
+
|
|
+ gtk_recent_manager_changed (manager);
|
|
+
|
|
+ GDK_THREADS_LEAVE ();
|
|
+
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+static void
|
|
+handle_fam_event (GtkRecentManager *manager,
|
|
+ FAMEvent *event)
|
|
+{
|
|
+ GtkRecentManagerPrivate *priv = manager->priv;
|
|
+
|
|
+ /* try to group delete-create pairs */
|
|
+ if (event->code == FAMDeleted)
|
|
+ {
|
|
+ if (priv->changed_timeout == 0)
|
|
+ priv->changed_timeout = g_timeout_add (500, changed_timeout, manager);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (priv->changed_timeout != 0)
|
|
+ {
|
|
+ g_source_remove (priv->changed_timeout);
|
|
+ priv->changed_timeout = 0;
|
|
+ }
|
|
+ gtk_recent_manager_changed (manager);
|
|
+ }
|
|
+}
|
|
+
|
|
+#ifdef DEBUG_FAM
|
|
+static inline void
|
|
+debug_event (FAMEvent *event)
|
|
+{
|
|
+#define PRINT_EVENT(str) g_print ("Got event: %d %s <" str ">\n", event->code, event->filename);
|
|
+
|
|
+ switch (event->code)
|
|
+ {
|
|
+ case FAMChanged:
|
|
+ PRINT_EVENT ("changed");
|
|
+ break;
|
|
+ case FAMDeleted:
|
|
+ PRINT_EVENT ("deleted");
|
|
+ break;
|
|
+ case FAMStartExecuting:
|
|
+ PRINT_EVENT ("start-executing");
|
|
+ break;
|
|
+ case FAMStopExecuting:
|
|
+ PRINT_EVENT ("stop-executing");
|
|
+ break;
|
|
+ case FAMCreated:
|
|
+ PRINT_EVENT ("created");
|
|
+ break;
|
|
+ case FAMAcknowledge:
|
|
+ PRINT_EVENT ("acknowledge");
|
|
+ break;
|
|
+ case FAMExists:
|
|
+ PRINT_EVENT ("exists");
|
|
+ break;
|
|
+ case FAMEndExist:
|
|
+ PRINT_EVENT ("end-exist");
|
|
+ break;
|
|
+ case FAMMoved:
|
|
+ PRINT_EVENT ("moved");
|
|
+ break;
|
|
+ default:
|
|
+ PRINT_EVENT ("invalid");
|
|
+ break;
|
|
+ }
|
|
+
|
|
+#undef PRINT_EVENT
|
|
+}
|
|
+#else
|
|
+#define debug_event(event)
|
|
+#endif
|
|
+
|
|
+static gboolean
|
|
+process_fam_events (void)
|
|
+{
|
|
+ if (failed_to_connect)
|
|
+ return FALSE;
|
|
+
|
|
+ while (fam_pending (&fam_connection))
|
|
+ {
|
|
+ FAMEvent event;
|
|
+
|
|
+ if (fam_next_event (&fam_connection, &event) != 1)
|
|
+ {
|
|
+ g_warning ("Failed to read next event from FAM");
|
|
+ failed_to_connect = TRUE;
|
|
+ fam_close (&fam_connection);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ debug_event (&event);
|
|
+
|
|
+ if (event.code != FAMChanged &&
|
|
+ event.code != FAMCreated &&
|
|
+ event.code != FAMDeleted)
|
|
+ continue;
|
|
+
|
|
+ handle_fam_event (event.userdata, &event);
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+fam_data_pending (GIOChannel *source,
|
|
+ GIOCondition condition)
|
|
+{
|
|
+ g_assert (condition == G_IO_IN || condition == G_IO_PRI);
|
|
+
|
|
+ if (!process_fam_events ())
|
|
+ {
|
|
+ fam_io_watch = 0;
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ return TRUE; /* do come again */
|
|
+}
|
|
+
|
|
+static FAMConnection *
|
|
+get_fam_connection (void)
|
|
+{
|
|
+ if (!opened_connection)
|
|
+ {
|
|
+ opened_connection = TRUE;
|
|
+
|
|
+ open_libfam ();
|
|
+
|
|
+ if (fam_open != NULL &&
|
|
+ fam_open (&fam_connection) == 0)
|
|
+ {
|
|
+ GIOChannel *io_channel;
|
|
+
|
|
+ io_channel = g_io_channel_unix_new (fam_connection.fd);
|
|
+ fam_io_watch = g_io_add_watch (io_channel,
|
|
+ G_IO_IN|G_IO_PRI,
|
|
+ (GIOFunc) fam_data_pending,
|
|
+ NULL);
|
|
+ g_io_channel_unref (io_channel);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ g_warning ("Failed to connect to the FAM server");
|
|
+ failed_to_connect = TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return failed_to_connect ? NULL : &fam_connection;
|
|
+}
|
|
+
|
|
+static FAMRequest *
|
|
+register_fam_monitor (const gchar *path,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ FAMConnection *fam_connection;
|
|
+ FAMRequest *request;
|
|
+
|
|
+ if ((fam_connection = get_fam_connection ()) == NULL)
|
|
+ {
|
|
+ g_warning ("Not adding file monitor on '%s', "
|
|
+ "failed to connect to FAM server\n",
|
|
+ path);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* Need to process any pending events, otherwise we may block
|
|
+ * on write - i.e. the FAM sever is blocked because its write
|
|
+ * buffer is full notifying us of events, we need to read those
|
|
+ * events before it can process our new request.
|
|
+ */
|
|
+ if (!process_fam_events ())
|
|
+ {
|
|
+ g_source_remove (fam_io_watch);
|
|
+ fam_io_watch = 0;
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ request = g_new0 (FAMRequest, 1);
|
|
+
|
|
+ if (fam_monitor_file (fam_connection, path, request, user_data) != 0)
|
|
+ {
|
|
+ g_warning ("Failed to add file monitor on '%s'", path);
|
|
+ g_free (request);
|
|
+
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+#ifdef DEBUG_FAM
|
|
+ g_print ("registering file monitor for '%s'\n", path);
|
|
+#endif
|
|
+
|
|
+ return request;
|
|
+}
|
|
+
|
|
+static void
|
|
+unregister_fam_monitor (FAMRequest *request)
|
|
+{
|
|
+ if (failed_to_connect)
|
|
+ return;
|
|
+
|
|
+ if (request != NULL)
|
|
+ fam_cancel_monitor (&fam_connection, request);
|
|
+
|
|
+ /* Need to process any remaining events for this monitor
|
|
+ */
|
|
+ if (!process_fam_events ())
|
|
+ {
|
|
+ g_source_remove (fam_io_watch);
|
|
+ fam_io_watch = 0;
|
|
+ }
|
|
+
|
|
+#ifdef DEBUG_FAM
|
|
+ g_print ("unregistering file monitor\n");
|
|
+#endif
|
|
+}
|
|
+
|
|
+/* end of fam support */
|
|
+
|
|
+
|
|
static void
|
|
gtk_recent_manager_init (GtkRecentManager *manager)
|
|
{
|
|
@@ -296,9 +605,12 @@
|
|
priv->filename = g_build_filename (g_get_home_dir (),
|
|
GTK_RECENTLY_USED_FILE,
|
|
NULL);
|
|
- priv->poll_timeout = g_timeout_add (POLL_DELTA,
|
|
- gtk_recent_manager_poll_timeout,
|
|
- manager);
|
|
+
|
|
+ priv->fam_request = register_fam_monitor (priv->filename, manager);
|
|
+ if (priv->fam_request == NULL)
|
|
+ priv->poll_timeout = g_timeout_add (POLL_DELTA,
|
|
+ gtk_recent_manager_poll_timeout,
|
|
+ manager);
|
|
|
|
build_recent_items_list (manager);
|
|
}
|
|
@@ -356,10 +668,19 @@
|
|
GtkRecentManager *manager = GTK_RECENT_MANAGER (object);
|
|
GtkRecentManagerPrivate *priv = manager->priv;
|
|
|
|
+ if (priv->fam_request)
|
|
+ {
|
|
+ unregister_fam_monitor (priv->fam_request);
|
|
+ g_free (priv->fam_request);
|
|
+ priv->fam_request = NULL;
|
|
+ }
|
|
+ if (priv->changed_timeout)
|
|
+ g_source_remove (priv->changed_timeout);
|
|
+
|
|
/* remove the poll timeout */
|
|
if (priv->poll_timeout)
|
|
g_source_remove (priv->poll_timeout);
|
|
-
|
|
+
|
|
if (priv->filename)
|
|
g_free (priv->filename);
|
|
|
|
@@ -499,18 +820,28 @@
|
|
if (!filename || filename[0] == '\0')
|
|
return;
|
|
|
|
- g_free (manager->priv->filename);
|
|
+ g_free (priv->filename);
|
|
|
|
- if (manager->priv->poll_timeout)
|
|
+ if (priv->fam_request)
|
|
{
|
|
- g_source_remove (manager->priv->poll_timeout);
|
|
- manager->priv->poll_timeout = 0;
|
|
+ unregister_fam_monitor (priv->fam_request);
|
|
+ g_free (priv->fam_request);
|
|
+ priv->fam_request = NULL;
|
|
+ }
|
|
+
|
|
+ if (priv->poll_timeout)
|
|
+ {
|
|
+ g_source_remove (priv->poll_timeout);
|
|
+ priv->poll_timeout = 0;
|
|
}
|
|
|
|
priv->filename = g_strdup (filename);
|
|
- priv->poll_timeout = g_timeout_add (POLL_DELTA,
|
|
- gtk_recent_manager_poll_timeout,
|
|
- manager);
|
|
+
|
|
+ priv->fam_request = register_fam_monitor (priv->filename, manager);
|
|
+ if (priv->fam_request == NULL)
|
|
+ priv->poll_timeout = g_timeout_add (POLL_DELTA,
|
|
+ gtk_recent_manager_poll_timeout,
|
|
+ manager);
|
|
|
|
/* mark us clean, so that we can re-read the list
|
|
* of recently used resources
|