gtk2/gtk+-2.10.3-fam.patch
2006-09-05 16:02:32 +00:00

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