FAM/gamin support for ROX-Filer

Ben Morrow <[email protected]>
Newsgroups gmane.comp.desktop.rox.devel
Message-ID <[email protected]>
For the benefit of those of us not on Linux, I've patched ROX-Filer to
use FAM to watch for changes. This patch also increases the rescan
timeout to 5 seconds, as I found that having a filer window rescan every
half second (because something is continuously changing) causes it to
start eating all the CPU. I don't know if this isn't an issue with
dnotify for some reason, or if this should be made a config option.

Tested on FreeBSD with gamin 0.1.9.

Ben

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php

_______________________________________________
rox-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/rox-devel
fam.patch (text/x-diff, 9.1 KB)
diff --git a/ROX-Filer/src/config.h.in b/ROX-Filer/src/config.h.in
index d5bbc01..00c4b0c 100644
--- a/ROX-Filer/src/config.h.in
+++ b/ROX-Filer/src/config.h.in
@@ -33,6 +33,10 @@
 #undef HAVE_SYS_XATTR_H
 #undef HAVE_ATTR_XATTR_H
 
+#undef HAVE_FAM_H
+#undef HAVE_FAM
+#undef HAVE_FAMNOEXISTS
+
 /* Enable extensions - used for dnotify support */
 #ifndef _GNU_SOURCE
 # define _GNU_SOURCE
diff --git a/ROX-Filer/src/configure.in b/ROX-Filer/src/configure.in
index 12a31f7..97ccb05 100644
--- a/ROX-Filer/src/configure.in
+++ b/ROX-Filer/src/configure.in
@@ -94,6 +94,16 @@ ROX_REQUIRE(libxml-2.0, 2.0.0)
 ROX_REQUIRE(libglade-2.0, 2.0.0)
 ROX_REQUIRE(shared-mime-info, 0.14)
 
+AC_MSG_CHECKING(if gamin is installed)
+if "$PKG_CONFIG" gamin ; then
+    AC_MSG_RESULT(yes)
+    CPPFLAGS="$CPPFLAGS `$PKG_CONFIG --cflags gamin`"
+    CFLAGS="$CFLAGS `$PKG_CONFIG --cflags gamin`"
+    LIBS="$LDFLAGS `$PKG_CONFIG --libs gamin`"
+else
+    AC_MSG_RESULT(no)
+fi
+
 GTK_VERSION=`"$PKG_CONFIG" --modversion gtk+-2.0`
 AC_DEFINE_UNQUOTED(GTK_VERSION, "$GTK_VERSION")
 
@@ -112,6 +122,7 @@ if test x$no_x = xyes ; then
 fi
 LIBS="$LIBS $X_LIBS -lX11 $X_EXTRA_LIBS"
 CFLAGS="$CFLAGS $X_CFLAGS"
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
 
 dnl Does file(1) support '-b' ?
 AC_MSG_CHECKING(whether file -b works)
@@ -157,7 +168,15 @@ dnl Checks for header files.
 AC_HEADER_DIRENT
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h mntent.h sys/ucred.h sys/mntent.h apsymbols.h apbuild/apsymbols.h sys/statvfs.h sys/vfs.h wctype.h libintl.h)
+AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h mntent.h sys/param.h sys/types.h sys/mntent.h apsymbols.h apbuild/apsymbols.h sys/statvfs.h sys/vfs.h wctype.h libintl.h)
+AC_CHECK_HEADERS([sys/ucred.h], [], [],
+[#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+])
 
 AC_CHECK_HEADER([X11/SM/SMlib.h], [],
   [AC_MSG_ERROR([Session management library (libsm) missing. It is part of the X server distribution. Try installing the libsm-dev package.])]
@@ -181,6 +200,11 @@ dnl Check for extended attribute support
 AC_CHECK_FUNCS(attropen getxattr)
 AC_CHECK_HEADERS(attr/xattr.h sys/xattr.h)
 
+dnl Check for FAM/gamin support
+AC_CHECK_HEADERS(fam.h)
+AC_SEARCH_LIBS([FAMOpen], [fam], [AC_DEFINE(HAVE_FAM)], [])
+AC_CHECK_FUNCS(FAMNoExists)
+
 dnl Extract version info from AppInfo.xml
 AC_MSG_CHECKING(extracting version information)
 [
diff --git a/ROX-Filer/src/dir.c b/ROX-Filer/src/dir.c
index fa820cf..1d7124d 100644
--- a/ROX-Filer/src/dir.c
+++ b/ROX-Filer/src/dir.c
@@ -94,8 +94,10 @@ static GPtrArray *hash_to_array(GHashTable *hash);
 static void dir_force_update_item(Directory *dir, const gchar *leaf);
 static Directory *dir_new(const char *pathname);
 static void dir_rescan(Directory *dir);
-#ifdef USE_DNOTIFY
+#if defined(USE_DNOTIFY) || defined(HAVE_FAM)
 static void dir_rescan_soon(Directory *dir);
+#endif
+#ifdef USE_DNOTIFY
 static void dnotify_handler(int sig, siginfo_t *si, void *data);
 #endif
 
@@ -173,6 +175,24 @@ void dir_attach(Directory *dir, DirCallback callback, gpointer data)
 		}
 	}
 #endif
+
+#ifdef HAVE_FAM
+        if (fam_open && !dir->users)
+        {
+            FAMRequest fr;
+
+            if (dir->fam_reqnum != -1)
+                g_warning("dir_attach: fam error\n");
+
+            if (FAMMonitorDirectory(
+                &fam_conn, dir->pathname,
+                &fr, dir
+            ) == 0)
+            {
+                dir->fam_reqnum = fr.reqnum;
+            }
+        }
+#endif
 	
 	dir->users = g_list_prepend(dir->users, user);
 
@@ -226,6 +246,25 @@ void dir_detach(Directory *dir, DirCallback callback, gpointer data)
 				dir->dnotify_fd = -1;
 			}
 #endif
+
+#ifdef HAVE_FAM
+                        if (!dir->users && dir->fam_reqnum != -1)
+                        {
+                            FAMRequest fr;
+
+                            if (fam_open)
+                            {
+                                fr.reqnum = dir->fam_reqnum;
+                                if (FAMCancelMonitor(&fam_conn, &fr) < 0)
+                                    g_warning("dir_detach: FAMCancelMonitor failed\n");
+                            }
+                            else {
+                                g_warning("dir_detach: fam not open\n");
+                            }
+                            dir->fam_reqnum = -1;
+                        }
+#endif
+                            
 			return;
 		}
 	}
@@ -498,11 +537,36 @@ void dnotify_wakeup(void)
 }
 #endif
 
+#ifdef HAVE_FAM
+void fam_wakeup(void)
+{
+    FAMEvent ev;
+
+    while (FAMPending(&fam_conn))
+    {
+        if (FAMNextEvent(&fam_conn, &ev) < 0)
+            g_warning("fam_wakeup: fam error\n");
+
+        switch (ev.code) {
+        case FAMChanged:
+        case FAMDeleted:
+        case FAMCreated:
+        case FAMMoved:
+            dir_rescan_soon(ev.userdata);
+            break;
+
+        default:
+            break;
+        }
+    }
+}
+#endif
+
 /****************************************************************
  *			INTERNAL FUNCTIONS			*
  ****************************************************************/
 
-#ifdef USE_DNOTIFY
+#if defined(USE_DNOTIFY) || defined(HAVE_FAM)
 static gint rescan_soon_timeout(gpointer data)
 {
 	Directory *dir = (Directory *) data;
@@ -522,7 +586,7 @@ static void dir_rescan_soon(Directory *dir)
 {
 	if (dir->rescan_timeout != -1)
 		return;
-	dir->rescan_timeout = g_timeout_add(500, rescan_soon_timeout, dir);
+	dir->rescan_timeout = g_timeout_add(5000, rescan_soon_timeout, dir);
 }
 #endif
 
@@ -902,6 +966,9 @@ static void directory_init(GTypeInstance *object, gpointer gclass)
 #ifdef USE_DNOTIFY
 	dir->dnotify_fd = -1;
 #endif
+#ifdef HAVE_FAM
+        dir->fam_reqnum = -1;
+#endif
 
 	dir->new_items = g_ptr_array_new();
 	dir->up_items = g_ptr_array_new();
diff --git a/ROX-Filer/src/dir.h b/ROX-Filer/src/dir.h
index a66e413..5a1de8e 100644
--- a/ROX-Filer/src/dir.h
+++ b/ROX-Filer/src/dir.h
@@ -14,7 +14,7 @@
 #include <fcntl.h>
 
 /* Check for dnotify support */
-#if defined(DN_MULTISHOT) && defined(SIGRTMIN)
+#if !defined(HAVE_FAM) && defined(DN_MULTISHOT) && defined(SIGRTMIN)
 # define USE_DNOTIFY
 extern gboolean dnotify_wakeup_flag;
 #endif
@@ -87,6 +87,10 @@ struct _Directory
 #ifdef USE_DNOTIFY
 	int		dnotify_fd;	/* -1 if not watching */
 #endif
+
+#ifdef HAVE_FAM
+        int             fam_reqnum;     /* -1 if not watching */
+#endif
 };
 
 void dir_init(void);
@@ -99,6 +103,7 @@ DirItem *dir_update_item(Directory *dir, const gchar *leafname);
 void dir_merge_new(Directory *dir);
 void dir_force_update_path(const gchar *path);
 void dnotify_wakeup(void);
+void fam_wakeup(void);
 void dir_drop_all_dnotifies(void);
 void dir_queue_recheck(Directory *dir, DirItem *item);
 
diff --git a/ROX-Filer/src/main.c b/ROX-Filer/src/main.c
index 0522fee..1abfe79 100644
--- a/ROX-Filer/src/main.c
+++ b/ROX-Filer/src/main.c
@@ -88,6 +88,11 @@ const gchar *show_user_message = NULL;
 int home_dir_len;
 const char *home_dir, *app_dir;
 
+#ifdef HAVE_FAM
+FAMConnection fam_conn;
+int fam_open = 0;
+#endif
+
 GtkTooltips *tooltips = NULL;
 
 #define COPYING								\
@@ -618,6 +623,23 @@ int main(int argc, char **argv)
 	/* If the pipe is full then we're going to get woken up anyway... */
 	set_blocking(to_wakeup_pipe, FALSE);
 
+        /* Set up fam */
+#ifdef HAVE_FAM
+        if (FAMOpen(&fam_conn) == 0)
+        {
+            fam_open = 1;
+
+#ifdef HAVE_FAMNOEXISTS
+            FAMNoExists(&fam_conn);
+#endif
+
+            gdk_input_add_full(
+                FAMCONNECTION_GETFD(&fam_conn), GDK_INPUT_READ,
+                wake_up_cb, NULL, NULL
+            );
+        }
+#endif
+
 	/* Let child processes die */
 	act.sa_handler = child_died;
 	sigemptyset(&act.sa_mask);
@@ -651,6 +673,10 @@ int main(int argc, char **argv)
 	if (number_of_windows > 0)
 		gtk_main();
 
+#ifdef HAVE_FAM
+        FAMClose(&fam_conn);
+#endif
+
 	return EXIT_SUCCESS;
 }
 
@@ -701,6 +727,13 @@ static void show_features(void)
 #else
 		_("No")
 #endif
+                );
+        g_print("%s... %s\n", _("FAM support"),
+#ifdef HAVE_FAM
+                _("Yes")
+#else
+                _("No")
+#endif
 	       );
 	g_print("%s... %s\n", _("Binary compatibility"),
 #if defined(HAVE_APSYMBOLS_H) || defined(HAVE_APBUILD_APSYMBOLS_H)
@@ -808,6 +841,11 @@ static void wake_up_cb(gpointer data, gint source, GdkInputCondition condition)
 {
 	char buf[BUFLEN];
 
+#ifdef HAVE_FAM
+        if (source == FAMCONNECTION_GETFD(&fam_conn))
+            fam_wakeup();
+        else
+#endif
 	read(source, buf, BUFLEN);
 	
 	if (child_died_flag)
diff --git a/ROX-Filer/src/main.h b/ROX-Filer/src/main.h
index 44262ca..83d2313 100644
--- a/ROX-Filer/src/main.h
+++ b/ROX-Filer/src/main.h
@@ -9,6 +9,10 @@
 #include <sys/types.h>
 #include <gtk/gtk.h>
 
+#ifdef HAVE_FAM_H
+#include <fam.h>
+#endif
+
 typedef struct _Callback Callback;
 typedef void (*CallbackFn)(gpointer data);
 
@@ -33,6 +37,11 @@ extern int home_dir_len;
 extern const char *home_dir, *app_dir;
 extern Option o_dnd_no_hostnames;
 
+#ifdef HAVE_FAM
+extern FAMConnection fam_conn;
+extern int fam_open;
+#endif
+
 /* Prototypes */
 int main(int argc, char **argv);
 void on_child_death(gint child, CallbackFn callback, gpointer data);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.