diff -urNd ../pcmanfm-0.3.0.1-r0/pcmanfm-0.3.0.1/configure.in pcmanfm-0.3.0.1/configure.in --- ../pcmanfm-0.3.0.1-r0/pcmanfm-0.3.0.1/configure.in 2006-08-20 15:45:28.000000000 +0100 +++ pcmanfm-0.3.0.1/configure.in 2006-08-20 20:37:36.000000000 +0100 @@ -63,8 +63,8 @@ LIBS="$LIBS $FAM_LIBS" AC_CHECK_FUNCS([FAMNoExists]) LIBS="$save_LIBS" -else - AC_MSG_ERROR([Fatal Error: no fam or gamin detected.]) +#else +# AC_MSG_ERROR([Fatal Error: no fam or gamin detected.]) fi AC_SUBST([FAM_CFLAGS]) diff -urNd ../pcmanfm-0.3.0.1-r0/pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.c pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.c --- ../pcmanfm-0.3.0.1-r0/pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.c 2006-07-16 20:00:46.000000000 +0100 +++ pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.c 2006-08-20 20:54:07.000000000 +0100 @@ -31,7 +31,6 @@ VFSFileMonitorCallbackEntry; static GHashTable* monitor_hash = NULL; -static FAMConnection fam; static GIOChannel* fam_io_channel = NULL; static guint fam_io_watch = 0; @@ -40,6 +39,8 @@ GIOCondition cond, gpointer user_data ); +#ifdef HAVE_FAM_H +static FAMConnection fam; static gboolean connect_to_fam() { @@ -81,6 +82,16 @@ FAMClose( &fam ); } } +#else +static gboolean connect_to_fam () +{ + return FALSE; +} + +static void disconnect_from_fam () +{ +} +#endif /* final cleanup */ void vfs_file_monitor_clean() @@ -109,6 +120,7 @@ VFSFileMonitorCallback cb, gpointer user_data ) { +#ifdef HAVE_FAM_H VFSFileMonitor * monitor; VFSFileMonitorCallbackEntry cb_ent; gboolean add_new = FALSE; @@ -154,12 +166,16 @@ } ++monitor->n_ref; return monitor; +#else + return NULL; +#endif } void vfs_file_monitor_remove( VFSFileMonitor* fm, VFSFileMonitorCallback cb, gpointer user_data ) { +#ifdef HAVE_FAM_H int i; VFSFileMonitorCallbackEntry* callbacks; if ( cb && fm->callbacks ) @@ -183,12 +199,14 @@ g_array_free( fm->callbacks, TRUE ); g_slice_free( VFSFileMonitor, fm ); } +#endif } static void reconnect_fam( gpointer key, gpointer value, gpointer user_data ) { +#ifdef HAVE_FAM_H struct stat file_stat; VFSFileMonitor* monitor = ( VFSFileMonitor* ) value; const char* path = ( const char* ) key; @@ -209,6 +227,7 @@ monitor ); } } +#endif } /* event handler of all FAM events */ @@ -216,6 +235,7 @@ GIOCondition cond, gpointer user_data ) { +#ifdef HAVE_FAM_H FAMEvent evt; VFSFileMonitor* monitor = NULL; VFSFileMonitorCallbackEntry* cb; @@ -266,5 +286,8 @@ } } return TRUE; +#else + return TRUE; +#endif } diff -urNd ../pcmanfm-0.3.0.1-r0/pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.c~ pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.c~ --- ../pcmanfm-0.3.0.1-r0/pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.c~ 1970-01-01 01:00:00.000000000 +0100 +++ pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.c~ 2006-08-20 20:50:49.000000000 +0100 @@ -0,0 +1,292 @@ +/* +* C Implementation: vfs-monitor +* +* Description: +* +* +* Author: Hong Jen Yee (PCMan) , (C) 2006 +* +* Copyright: See COPYING file that comes with this distribution +* +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "vfs-file-monitor.h" +#include /* for stat */ +#include + +#include +#include + +#include "glib-mem.h" + +typedef struct +{ + VFSFileMonitorCallback callback; + gpointer user_data; +} +VFSFileMonitorCallbackEntry; + +static GHashTable* monitor_hash = NULL; +static FAMConnection fam; +static GIOChannel* fam_io_channel = NULL; +static guint fam_io_watch = 0; + +/* event handler of all FAM events */ +static gboolean on_fam_event( GIOChannel *channel, + GIOCondition cond, + gpointer user_data ); + +#ifdef HAVE_FAM_H +static gboolean connect_to_fam() +{ + if ( FAMOpen( &fam ) ) + { + fam_io_channel = NULL; + fam.fd = -1; + g_warning( "There is no FAM/gamin server\n" ); + return FALSE; + } +#if HAVE_FAMNOEXISTS + /* + * Disable the initital directory content loading. + * This can greatly speed up directory loading, but + * unfortunately, it's not compatible with original FAM. + */ + FAMNoExists( &fam ); /* This is an extension of gamin */ +#endif + + fam_io_channel = g_io_channel_unix_new( fam.fd ); + g_io_channel_set_encoding( fam_io_channel, NULL, NULL ); + g_io_channel_set_buffered( fam_io_channel, FALSE ); + + fam_io_watch = g_io_add_watch( fam_io_channel, + G_IO_IN | G_IO_HUP, + on_fam_event, + NULL ); + return TRUE; +} + +static void disconnect_from_fam() +{ + if ( fam_io_channel ) + { + g_io_channel_unref( fam_io_channel ); + fam_io_channel = NULL; + g_source_remove( fam_io_watch ); + + FAMClose( &fam ); + } +} +#else +static gboolean connect_to_fam () +{ + return FALSE; +} + +static void disconnect_from_fam () +{ +} +#endif + +/* final cleanup */ +void vfs_file_monitor_clean() +{ + disconnect_from_fam(); + if ( monitor_hash ) + { + g_hash_table_destroy( monitor_hash ); + monitor_hash = NULL; + } +} + +/* +* Init monitor: +* Establish connection with gamin/fam. +*/ +gboolean vfs_file_monitor_init() +{ + monitor_hash = g_hash_table_new( g_str_hash, g_str_equal ); + if ( ! connect_to_fam() ) + return FALSE; + return TRUE; +} + +VFSFileMonitor* vfs_file_monitor_add( const char* path, + VFSFileMonitorCallback cb, + gpointer user_data ) +{ +#ifdef HAVE_FAM_H + VFSFileMonitor * monitor; + VFSFileMonitorCallbackEntry cb_ent; + gboolean add_new = FALSE; + struct stat file_stat; + + if ( ! monitor_hash ) + { + if ( !vfs_file_monitor_init() ) + return NULL; + } + monitor = ( VFSFileMonitor* ) g_hash_table_lookup ( monitor_hash, path ); + if ( ! monitor ) + { + monitor = g_slice_new0( VFSFileMonitor ); + monitor->path = g_strdup( path ); + monitor->callbacks = g_array_new ( FALSE, FALSE, sizeof( VFSFileMonitorCallbackEntry ) ); + g_hash_table_insert ( monitor_hash, + path, + monitor ); + if ( lstat( path, &file_stat ) != -1 ) + { + if ( S_ISDIR( file_stat.st_mode ) ) + { + FAMMonitorDirectory( &fam, + path, + &monitor->request, + monitor ); + } + else + { + FAMMonitorFile( &fam, + path, + &monitor->request, + monitor ); + } + } + } + if ( cb ) + { /* Install a callback */ + cb_ent.callback = cb; + cb_ent.user_data = user_data; + monitor->callbacks = g_array_append_val( monitor->callbacks, cb_ent ); + } + ++monitor->n_ref; + return monitor; +#else + return NULL; +#endif +} + +void vfs_file_monitor_remove( VFSFileMonitor* fm, + VFSFileMonitorCallback cb, + gpointer user_data ) +{ +#ifdef HAVE_FAM_H + int i; + VFSFileMonitorCallbackEntry* callbacks; + if ( cb && fm->callbacks ) + { + callbacks = ( VFSFileMonitorCallbackEntry* ) fm->callbacks->data; + for ( i = 0; i < fm->callbacks->len; ++i ) + { + if ( callbacks[ i ].callback == cb && callbacks[ i ].user_data == user_data ) + { + fm->callbacks = g_array_remove_index_fast ( fm->callbacks, i ); + break; + } + } + } + --fm->n_ref; + if ( 0 >= fm->n_ref ) + { + FAMCancelMonitor( &fam, &fm->request ); + g_hash_table_remove( monitor_hash, fm->path ); + g_free( fm->path ); + g_array_free( fm->callbacks, TRUE ); + g_slice_free( VFSFileMonitor, fm ); + } +#endif +} + +static void reconnect_fam( gpointer key, + gpointer value, + gpointer user_data ) +{ +#ifdef HAVE_FAM_H + struct stat file_stat; + VFSFileMonitor* monitor = ( VFSFileMonitor* ) value; + const char* path = ( const char* ) key; + if ( lstat( path, &file_stat ) != -1 ) + { + if ( S_ISDIR( file_stat.st_mode ) ) + { + FAMMonitorDirectory( &fam, + path, + &monitor->request, + monitor ); + } + else + { + FAMMonitorFile( &fam, + path, + &monitor->request, + monitor ); + } + } +#endif +} + +/* event handler of all FAM events */ +static gboolean on_fam_event( GIOChannel *channel, + GIOCondition cond, + gpointer user_data ) +{ +#ifdef HAVE_FAM_H + FAMEvent evt; + VFSFileMonitor* monitor = NULL; + VFSFileMonitorCallbackEntry* cb; + VFSFileMonitorCallback func; + int i; + + if ( cond & G_IO_HUP ) + { + disconnect_from_fam(); + if ( g_hash_table_size ( monitor_hash ) > 0 ) + { + /* + Disconnected from FAM server, but there are still monitors. + This may be caused by crash of FAM server. + So we have to reconnect to FAM server. + */ + connect_to_fam(); + g_hash_table_foreach( monitor_hash, ( GHFunc ) reconnect_fam, NULL ); + } + return TRUE; /* don't need to remove the event source since + it has been removed by disconnect_from_fam(). */ + } + + while ( FAMPending( &fam ) ) + { + if ( FAMNextEvent( &fam, &evt ) > 0 ) + { + monitor = ( VFSFileMonitor* ) evt.userdata; + switch ( evt.code ) + { + case FAMCreated: + case FAMDeleted: + case FAMChanged: + /* Call the callback functions */ + if ( monitor->callbacks && monitor->callbacks->len ) + { + cb = ( VFSFileMonitorCallbackEntry* ) monitor->callbacks->data; + for ( i = 0; i < monitor->callbacks->len; ++i ) + { + func = cb[ i ].callback; + func( monitor, evt.code, evt.filename, cb[ i ].user_data ); + } + } + break; + default: + return TRUE; /* Other events are not supported */ + } + } + } + return TRUE; +#else + return TRUE; +#endif +} + diff -urNd ../pcmanfm-0.3.0.1-r0/pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.h pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.h --- ../pcmanfm-0.3.0.1-r0/pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.h 2006-04-03 00:38:33.000000000 +0100 +++ pcmanfm-0.3.0.1/src/vfs/vfs-file-monitor.h 2006-08-20 20:47:00.000000000 +0100 @@ -20,7 +20,16 @@ #define _VFS_FILE_MONITOR_H_ #include +#ifdef HAVE_FAM_H #include +#else +# define FAMCreated 0 +# define FAMDeleted 1 +# define FAMChanged 2 +typedef struct { + int reqnum; +} FAMRequest; +#endif G_BEGIN_DECLS