Restored FAM

This commit is contained in:
Yevgen Muntyan 2008-08-05 18:17:09 -05:00
parent 51321f36a7
commit cfdc38a4f0
8 changed files with 445 additions and 12 deletions

View File

@ -16,6 +16,13 @@ configure has the following medit-specific options:
Use this if you experience crashes on startup
and you are using Suse 9.
--with-fam whether to use FAM (or gamin) for file monitoring
(default = NO)
FAM seems to work well, but gamin seems to be much less stable. This option
is not recommended if FAM is provided by gamin on your system.
Note that file monitoring will work even without FAM, so it's unlikely you
want to use this option.
--with-python whether to compile python support (default = YES)
This option tells whether pygtk bindings should be built. If medit is built
without python, then python plugins (builtin terminal and project support in

View File

@ -81,6 +81,7 @@ if test x$MOO_OS_CYGWIN != "xyes"; then
echo " use python .............................. $use_python"
echo " use xml ................................. $MOO_USE_XML"
echo " build pcre library ...................... $MOO_BUILD_PCRE"
echo " use FAM ................................. $MOO_USE_FAM"
echo
echo " prefix .................................. $prefix"
echo " editor lang files go to ................. $MOO_TEXT_LANG_FILES_DIR"

84
m4/moo-fam.m4 Normal file
View File

@ -0,0 +1,84 @@
##############################################################################
# _MOO_AC_CHECK_FAM(action-if-found,action-if-not-found)
#
AC_DEFUN_ONCE([_MOO_AC_CHECK_FAM],[
moo_ac_save_CFLAGS="$CFLAGS"
moo_ac_save_LIBS="$LIBS"
if test x$FAM_LIBS = x; then
FAM_LIBS=-lfam
fi
CFLAGS="$CFLAGS $FAM_CFLAGS"
LIBS="$LIBS $FAM_LIBS"
AC_CHECK_HEADERS(fam.h,[
AC_CHECK_FUNCS([FAMMonitorDirectory FAMOpen],[fam_found=yes],[fam_found=no])
],[fam_found=no])
if test x$fam_found != xno; then
AC_SUBST(FAM_CFLAGS)
AC_SUBST(FAM_LIBS)
AC_MSG_CHECKING(for FAM_CFLAGS)
if test -z $FAM_CFLAGS; then
AC_MSG_RESULT(None)
else
AC_MSG_RESULT($FAM_CFLAGS)
fi
AC_MSG_CHECKING(for FAM_LIBS)
if test -z $FAM_LIBS; then
AC_MSG_RESULT(None)
else
AC_MSG_RESULT($FAM_LIBS)
fi
AC_CHECK_DECL([FAMNoExists],[
AC_DEFINE(HAVE_FAMNOEXISTS, 1, [fam.h has FAMNoExists defined])
AC_DEFINE(MOO_USE_GAMIN, 1, [whether libfam is provided by gamin])
],[],[#include <fam.h>])
MOO_FAM_CFLAGS="$FAM_CFLAGS"
MOO_FAM_LIBS="$FAM_LIBS"
ifelse([$1], , :, [$1])
else
unset FAM_CFLAGS
unset FAM_LIBS
MOO_FAM_LIBS=
MOO_FAM_CFLAGS=
ifelse([$2], , [AC_MSG_ERROR(libfam not found)], [$2])
fi
AC_SUBST(MOO_FAM_CFLAGS)
AC_SUBST(MOO_FAM_LIBS)
CFLAGS="$moo_ac_save_CFLAGS"
LIBS="$moo_ac_save_LIBS"
])
AC_DEFUN_ONCE([MOO_AC_FAM],[
AC_REQUIRE([MOO_AC_CHECK_OS])
AC_ARG_WITH([fam], AC_HELP_STRING([--with-fam], [whether to use fam or gamin for monitoring files in the editor (default = NO)]), [
if test x$with_fam = "xyes"; then
MOO_USE_FAM="yes"
else
MOO_USE_FAM="no"
fi
],[
MOO_USE_FAM="no"
])
if test x$MOO_OS_UNIX = xyes -a x$MOO_USE_FAM = xyes; then
_MOO_AC_CHECK_FAM([moo_has_fam=yes],[moo_has_fam=no])
if test x$moo_has_fam = xyes; then
MOO_USE_FAM="yes"
AC_DEFINE(MOO_USE_FAM, 1, [use libfam for monitoring files])
else
AC_MSG_ERROR([FAM or gamin not found.])
fi
fi
AM_CONDITIONAL(MOO_USE_FAM, test x$MOO_USE_FAM = "xyes")
])

View File

@ -21,6 +21,7 @@ AC_DEFUN_ONCE([MOO_AC_PRIV_FLAGS],[
MOO_AC_FLAGS
MOO_AC_FUNCS
MOO_AC_FAM
MOO_AC_XML
MOO_AC_PCRE
MOO_AC_PYTHON
@ -51,6 +52,11 @@ AC_DEFUN_ONCE([MOO_AC_PRIV_FLAGS],[
MOO_CFLAGS="-I`cd "$srcdir/doc" && pwd` $MOO_CFLAGS"
if test x$MOO_USE_FAM = xyes; then
MOO_CFLAGS="$MOO_CFLAGS $MOO_FAM_CFLAGS"
MOO_LIBS="$MOO_LIBS $MOO_FAM_LIBS"
fi
AC_SUBST(MOO_LIBS)
])

View File

@ -60,6 +60,7 @@ PKG_CONFIG_PROGRAM=${PKG_CONFIG_PROGRAM:-`which pkg-config`}
# Where gtk libraries are installed
export GTK_PREFIX=${GTK_PREFIX:-/usr/local/win/gtk}
export QT_PREFIX=${QT_PREFIX:-/usr/local/win/Qt/4.4.0}
# Prefix of mingw tools. prefix + tool should make up full path
# to the tool, e.g. prefix is '/usr/bin/i586-mingw32msvc-' on Debian

View File

@ -10,9 +10,10 @@
* See COPYING file that comes with this distribution.
*/
#define MOO_APP_COMPILATION
#include "mooappabout-glade.h"
#include "mooappabout.h"
#include "mooapp.h"
#include "mooapp-private.h"
#include "moohtml.h"
#include "moolinklabel.h"
#include "mooutils/moostock.h"
@ -88,7 +89,7 @@ show_credits (void)
GtkTextBuffer *buffer;
const MooAppInfo *info;
info = moo_app_get_info (moo_app_get_instance());
info = _moo_app_get_info (moo_app_instance ());
g_return_if_fail (info && info->credits);
if (credits_dialog)
@ -162,7 +163,7 @@ about_dialog_key_press (GtkWidget *dialog,
static GtkWidget *
create_about_dialog (void)
create_about_dialog (MooApp *app)
{
MooGladeXML *xml;
GtkWidget *dialog, *logo, *button;
@ -171,7 +172,7 @@ create_about_dialog (void)
GtkLabel *label;
MooLinkLabel *url;
info = moo_app_get_info (moo_app_get_instance());
info = _moo_app_get_info (app);
xml = moo_glade_xml_new_empty (GETTEXT_PACKAGE);
moo_glade_xml_map_id (xml, "url", MOO_TYPE_LINK_LABEL);
moo_glade_xml_parse_memory (xml, mooappabout_glade_xml, -1, "dialog", NULL);
@ -233,10 +234,11 @@ create_about_dialog (void)
void
moo_app_about_dialog (GtkWidget *parent)
_moo_app_about_dialog (MooApp *app,
GtkWidget *parent)
{
if (!about_dialog)
about_dialog = create_about_dialog ();
about_dialog = create_about_dialog (app);
if (parent)
parent = gtk_widget_get_toplevel (parent);
@ -269,14 +271,14 @@ create_system_info_dialog (void)
textview = moo_glade_xml_get_widget (xml, "textview");
buffer = gtk_text_view_get_buffer (textview);
text = moo_app_get_system_info (moo_app_get_instance ());
text = _moo_app_get_system_info (moo_app_instance ());
gtk_text_buffer_set_text (buffer, text, -1);
g_free (text);
}
char *
moo_app_get_system_info (MooApp *app)
_moo_app_get_system_info (MooApp *app)
{
GString *text;
char *string;
@ -287,7 +289,7 @@ moo_app_get_system_info (MooApp *app)
text = g_string_new (NULL);
app_info = moo_app_get_info (app);
app_info = _moo_app_get_info (app);
g_return_val_if_fail (app_info != NULL, NULL);
g_string_append_printf (text, "%s-%s\n", app_info->full_name, app_info->version);
@ -334,6 +336,14 @@ moo_app_get_system_info (MooApp *app)
g_string_append_printf (text, "libxml2: %s\n", LIBXML_DOTTED_VERSION);
#endif
#ifdef MOO_USE_FAM
#ifdef MOO_USE_GAMIN
g_string_append_printf (text, "FAM support: gamin\n");
#else
g_string_append_printf (text, "FAM support: yes\n");
#endif
#endif
g_string_append (text, "Data dirs: ");
dirs = moo_get_data_dirs (MOO_DATA_SHARE, NULL);
for (p = dirs; p && *p; ++p)
@ -361,7 +371,7 @@ moo_app_get_system_info (MooApp *app)
void
moo_app_system_info_dialog (GtkWidget *parent)
_moo_app_system_info_dialog (GtkWidget *parent)
{
create_system_info_dialog ();

View File

@ -14,7 +14,13 @@
#include "config.h"
#endif
#ifdef MOO_USE_FAM
/* need PATH_MAX even with -ansi */
#define _GNU_SOURCE
#include <fam.h>
#else
#define WANT_STAT_MONITOR
#endif
#ifdef __WIN32__
#include <windows.h>
@ -53,6 +59,9 @@ typedef struct {
guint id;
MooFileWatch *watch;
char *filename;
#ifdef MOO_USE_FAM
int fam_request;
#endif
MooFileWatchCallback callback;
GDestroyNotify notify;
@ -81,6 +90,10 @@ struct _MooFileWatch {
guint ref_count;
guint id;
guint stat_timeout;
#ifdef MOO_USE_FAM
FAMConnection fam_connection;
guint fam_connection_watch;
#endif
GSList *monitors;
GHashTable *requests; /* int -> Monitor* */
guint alive : 1;
@ -105,6 +118,18 @@ typedef enum
static GQuark moo_file_watch_error_quark (void);
#ifdef MOO_USE_FAM
static gboolean watch_fam_start (MooFileWatch *watch,
GError **error);
static gboolean watch_fam_shutdown (MooFileWatch *watch,
GError **error);
static gboolean watch_fam_start_monitor (MooFileWatch *watch,
Monitor *monitor,
GError **error);
static void watch_fam_stop_monitor (MooFileWatch *watch,
Monitor *monitor);
#endif /* MOO_USE_FAM */
#ifdef WANT_STAT_MONITOR
static gboolean watch_stat_start (MooFileWatch *watch,
GError **error);
@ -136,7 +161,12 @@ static void monitor_free (Monitor *monitor);
static struct WatchFuncs watch_funcs = {
#if defined(__WIN32__)
#if defined(MOO_USE_FAM)
watch_fam_start,
watch_fam_shutdown,
watch_fam_start_monitor,
watch_fam_stop_monitor
#elif defined(__WIN32__)
watch_win32_start,
watch_win32_shutdown,
watch_win32_start_monitor,
@ -488,6 +518,300 @@ monitor_free (Monitor *monitor)
}
/*****************************************************************************/
/* FAM
*/
#ifdef MOO_USE_FAM
#define SET_FAM_ERROR(func,error) \
g_set_error (error, MOO_FILE_WATCH_ERROR, \
MOO_FILE_WATCH_ERROR_FAILED, \
#func " failed: %s", \
((FAMErrno && FamErrlist[FAMErrno]) ? \
FamErrlist[FAMErrno] : \
"unknown error"))
#define MOO_FAM_SOCKET_WATCH_PRIORITY G_PRIORITY_DEFAULT
static gboolean read_fam_events (GIOChannel *source,
GIOCondition condition,
MooFileWatch *watch);
static gboolean
watch_fam_start (MooFileWatch *watch,
GError **error)
{
GIOChannel *fam_socket;
if (FAMOpen (&watch->fam_connection) != 0)
{
SET_FAM_ERROR (FAMOpen, error);
return FALSE;
}
#ifdef HAVE_FAMNOEXISTS
FAMNoExists (&watch->fam_connection);
#endif
fam_socket = g_io_channel_unix_new (watch->fam_connection.fd);
watch->fam_connection_watch =
_moo_io_add_watch_full (fam_socket, MOO_FAM_SOCKET_WATCH_PRIORITY,
G_IO_IN | G_IO_PRI | G_IO_HUP,
(GIOFunc) read_fam_events, watch, NULL);
g_io_channel_unref (fam_socket);
return TRUE;
}
static gboolean
watch_fam_shutdown (MooFileWatch *watch,
GError **error)
{
if (watch->fam_connection_watch)
g_source_remove (watch->fam_connection_watch);
if (FAMClose (&watch->fam_connection))
{
SET_FAM_ERROR (FAMClose, error);
return FALSE;
}
return TRUE;
}
static gboolean
watch_fam_start_monitor (MooFileWatch *watch,
Monitor *monitor,
GError **error)
{
FAMRequest fr;
int result;
g_return_val_if_fail (monitor->filename != NULL, FALSE);
monitor->isdir = g_file_test (monitor->filename, G_FILE_TEST_IS_DIR) != 0;
monitor->id = get_new_monitor_id ();
if (monitor->isdir)
result = FAMMonitorDirectory (&watch->fam_connection,
monitor->filename, &fr,
GUINT_TO_POINTER (monitor->id));
else
result = FAMMonitorFile (&watch->fam_connection,
monitor->filename, &fr,
GUINT_TO_POINTER (monitor->id));
if (result != 0)
{
DEBUG_PRINT ("Connection %d: creating monitor for '%s' failed",
watch->fam_connection.fd, monitor->filename);
if (monitor->isdir)
SET_FAM_ERROR (FAMMonitorDirectory, error);
else
SET_FAM_ERROR (FAMMonitorFile, error);
return FALSE;
}
else
{
DEBUG_PRINT ("Connection %d: created monitor %d for %s '%s'",
watch->fam_connection.fd, fr.reqnum,
monitor->isdir ? "directory" : "file",
monitor->filename);
}
monitor->fam_request = fr.reqnum;
return TRUE;
}
static void
watch_fam_stop_monitor (MooFileWatch *watch,
Monitor *monitor)
{
FAMRequest fr;
int result;
g_return_if_fail (monitor != NULL);
fr.reqnum = monitor->fam_request;
result = FAMCancelMonitor (&watch->fam_connection, &fr);
if (result != 0)
DEBUG_PRINT ("Connection %d: FAMCancelMonitor for '%s' failed",
watch->fam_connection.fd,
monitor->filename);
}
static void
do_events (MooFileWatch *watch,
GSList *events)
{
while (events)
{
MooFileEvent *e;
Monitor *monitor;
e = events->data;
events = events->next;
monitor = g_hash_table_lookup (watch->requests, GUINT_TO_POINTER (e->monitor_id));
if (!monitor || !monitor->alive)
continue;
moo_file_watch_emit_event (watch, e, monitor);
}
}
static MooFileEvent *
fam_event_to_file_event (FAMEvent *fe,
MooFileWatch *watch)
{
Monitor *monitor;
const char *filename;
MooFileEventCode code;
monitor = g_hash_table_lookup (watch->requests, fe->userdata);
if (!monitor)
return NULL;
g_assert (GUINT_TO_POINTER (monitor->id) == fe->userdata);
g_assert (monitor->fam_request == fe->fr.reqnum);
filename = fe->filename;
switch (fe->code)
{
case FAMCreated:
code = MOO_FILE_EVENT_CREATED;
break;
case FAMChanged:
/* Do not emit CHANGED for folders, since we are interested only in
* folder contents */
if (monitor->isdir)
return NULL;
code = MOO_FILE_EVENT_CHANGED;
break;
case FAMDeleted:
code = MOO_FILE_EVENT_DELETED;
break;
case FAMMoved:
/* XXX never happens with FAM, what about gamin? */
g_print ("file moved: %s\n", fe->filename);
code = MOO_FILE_EVENT_CHANGED;
filename = monitor->filename;
break;
case FAMStartExecuting:
case FAMStopExecuting:
case FAMAcknowledge:
case FAMExists:
case FAMEndExist:
return NULL;
default:
g_warning ("%s: unknown FAM code %d", G_STRLOC, fe->code);
return NULL;
}
return moo_file_event_new (filename, monitor->id, code);
}
static gboolean
read_fam_events (G_GNUC_UNUSED GIOChannel *source,
GIOCondition condition,
MooFileWatch *watch)
{
GError *error = NULL;
int result;
FAMConnection *connection = &watch->fam_connection;
gboolean retval = TRUE;
GSList *events = NULL;
guint n_events;
moo_file_watch_ref (watch);
if (!watch->alive || condition & (G_IO_ERR | G_IO_HUP))
{
g_warning ("Connection %d: broken FAM socket", connection->fd);
if (watch->alive && !moo_file_watch_close (watch, &error))
{
g_warning ("%s: error in moo_file_watch_close()", G_STRLOC);
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
}
retval = FALSE;
goto out;
}
for (n_events = 0; !error && n_events < 4096 && (result = FAMPending (connection)); n_events++)
{
if (result < 0)
{
SET_FAM_ERROR (FAMPending, &error);
DEBUG_PRINT ("Connection %d: FAMPending failed", connection->fd);
}
else
{
FAMEvent fe;
if (FAMNextEvent (connection, &fe) != 1)
{
SET_FAM_ERROR (FAMNextEvent, &error);
DEBUG_PRINT ("Connection %d: FAMNextEvent failed", connection->fd);
}
else
{
MooFileEvent *e;
if ((e = fam_event_to_file_event (&fe, watch)))
events = g_slist_prepend (events, e);
}
}
}
events = g_slist_reverse (events);
do_events (watch, events);
g_slist_foreach (events, (GFunc) moo_file_event_free, NULL);
g_slist_free (events);
if (error)
{
g_warning ("Connection %d: error: %s", connection->fd, error->message);
g_error_free (error);
error = NULL;
if (!moo_file_watch_close (watch, &error))
{
g_warning ("%s: error in moo_file_watch_close()", G_STRLOC);
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
}
retval = FALSE;
}
out:
moo_file_watch_unref (watch);
return retval;
}
#endif /* MOO_USE_FAM */
/*****************************************************************************/
/* stat()
*/

View File

@ -10,7 +10,7 @@
* See COPYING file that comes with this distribution.
*/
/* Files and directory monitor using stat().
/* Files and directory monitor. Uses FAM if present, or stat() otherwise.
On win32 does FindFirstChangeNotification and ReadDirectoryChangesW. */
#ifndef MOO_FILE_WATCH_H