diff --git a/gtk+-2.10.3-fam.patch b/gtk+-2.10.3-fam.patch new file mode 100644 index 0000000..dedeffd --- /dev/null +++ b/gtk+-2.10.3-fam.patch @@ -0,0 +1,405 @@ +--- 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 ++ + #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 diff --git a/gtk2.spec b/gtk2.spec index 45891f3..72cad68 100644 --- a/gtk2.spec +++ b/gtk2.spec @@ -16,7 +16,7 @@ Summary: The GIMP ToolKit (GTK+), a library for creating GUIs for X Name: gtk2 Version: %{base_version} -Release: 1%{?dist} +Release: 2%{?dist} License: LGPL Group: System Environment/Libraries Source: gtk+-%{version}.tar.bz2 @@ -28,11 +28,14 @@ Patch0: gtk+-2.4.1-lib64.patch Patch1: gtk+-2.8.10-set-invisible-char-to-bullet.patch # Filechooser search Patch2: gtk+-2.10.3-search.patch +# use fam for recent-files +Patch3: gtk+-2.10.3-fam.patch # backport from HEAD Patch7: gtk+-2.10.2-cursor-blink.patch Patch8: gtk+-2.10.2-im-reset.patch + BuildPrereq: atk-devel >= %{atk_version} BuildPrereq: pango-devel >= %{pango_version} BuildPrereq: glib2-devel >= %{glib2_version} @@ -50,6 +53,8 @@ BuildRequires: libXrender-devel BuildRequires: libXcursor-devel BuildRequires: libXfixes-devel BuildRequires: libXinerama-devel +# for patch 3 +BuildRequires: gamin-devel BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Obsoletes: gtk+-gtkbeta @@ -112,6 +117,7 @@ tar xzf %{SOURCE1} %patch0 -p1 -b .lib64 %patch1 -p1 -b .set-invisible-char-to-bullet %patch2 -p1 -b .search +%patch3 -p1 -b .fam %patch7 -p0 -b .cursor-blink %patch8 -p1 -b .im-reset @@ -124,6 +130,8 @@ done libtoolize --force # Patch3 modifies gdk-pixbuf/Makefile.am +# Patch9 modifies configure.in +autoheader aclocal-1.7 automake-1.7 @@ -286,6 +294,9 @@ rm -rf $RPM_BUILD_ROOT %doc tmpdocs/examples %changelog +* Mon Sep 5 2006 Matthias Clasen - 2.10.3-2.fc6 +- Use fam for recent files + * Tue Sep 5 2006 Matthias Clasen - 2.10.3-1.fc6 - Update to 2.10.3