Index: Makefile.am
===================================================================
--- Makefile.am	(revision c2662816286b30464feee0b8ba6ad4566b650c16)
+++ Makefile.am	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -39,5 +39,6 @@
 
 CODELIST_SRCS=message.c mainwin.c popwin.c zephyr.c messagelist.c \
-     commands.c global.c text.c fmtext.c editwin.c util.c logging.c \
+     commands.c global.c text.c fmtext.c gmarshal_funcs.c editwin.c \
+     util.c logging.c \
      perlconfig.c keys.c functions.c zwrite.c viewwin.c help.c filter.c \
      regex.c history.c view.c dict.c variable.c filterelement.c pair.c \
@@ -45,5 +46,5 @@
      aim.c buddy.c buddylist.c style.c errqueue.c \
      zbuddylist.c popexec.c select.c wcwidth.c \
-     mainpanel.c msgwin.c sepbar.c editcontext.c signal.c
+     mainpanel.c msgwin.c sepbar.c editcontext.c signal.c closures.c
 
 NORMAL_SRCS = filterproc.c window.c windowcb.c
Index: closures.c
===================================================================
--- closures.c	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
+++ closures.c	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -0,0 +1,28 @@
+#define OWL_PERL
+#include "owl.h"
+#include <dlfcn.h>
+#include <gperl.h>
+#include <gperl_marshal.h>
+
+gboolean (*gvalue_from_sv) (GValue * value, SV * sv) = NULL;
+SV * (*sv_from_gvalue) (const GValue * value) = NULL;
+GClosure * (*perl_closure_new) (SV * callback, SV * data, gboolean swap) = NULL;
+
+/* Caller does not own return value */
+const char *owl_closure_init(void)
+{
+  void *handle = NULL;
+  const char *res = "Unable to dlopen self - huh?";
+
+  handle = dlopen(NULL, RTLD_LAZY | RTLD_NOLOAD);
+  if(handle) {
+    gvalue_from_sv = dlsym(handle, "gperl_value_from_sv");
+    sv_from_gvalue = dlsym(handle, "gperl_sv_from_value");
+    perl_closure_new = dlsym(handle, "gperl_closure_new");
+    /* ... */
+    res = dlerror();
+    dlclose(handle);
+  }
+  return res;
+}
+
Index: configure.ac
===================================================================
--- configure.ac	(revision 58b6ce5427395fc8c1887a2a8c69ea459a1fc9e5)
+++ configure.ac	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -127,4 +127,6 @@
 AX_PROG_PERL_MODULES([PAR],,
                      [AC_MSG_WARN([PAR.pm not found. Loadable modules will be disabled.])])
+AX_PROG_PERL_MODULES([ExtUtils::Depends],,
+                     [AC_MSG_ERROR([cannot find perl module ExtUtils::Depends])])
 
 dnl Add CFLAGS and LIBS for glib-2.0
@@ -139,4 +141,9 @@
    prefix="${ac_default_prefix}"
 fi
+
+dnl Add CFLAGS for glib-perl
+GLIB_PERL_CFLAGS=`perl -MExtUtils::Depends -e 'my $e = ExtUtils::Depends->new("BarnOwl","Glib"); my %h = $e->get_makefile_vars; print $h{"INC"}'`
+AC_MSG_NOTICE([Adding glib-perl CFLAGS ${GLIB_PERL_CFLAGS}])
+AM_CFLAGS="${GLIB_PERL_CFLAGS} ${AM_CFLAGS}"
 
 dnl Checks for typedefs, structures, and compiler characteristics.
Index: gmarshal_funcs.c
===================================================================
--- gmarshal_funcs.c	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
+++ gmarshal_funcs.c	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -0,0 +1,396 @@
+
+#include	<glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v)     g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v)      g_value_get_int (v)
+#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
+#define g_marshal_value_peek_long(v)     g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
+#define g_marshal_value_peek_float(v)    g_value_get_float (v)
+#define g_marshal_value_peek_double(v)   g_value_get_double (v)
+#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v)    g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v)   g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ *          Do not access GValues directly in your code. Instead, use the
+ *          g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
+#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
+#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
+#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* INT:STRING (marshal_types:2) */
+void
+g_cclosure_user_marshal_INT__STRING (GClosure     *closure,
+                                     GValue       *return_value G_GNUC_UNUSED,
+                                     guint         n_param_values,
+                                     const GValue *param_values,
+                                     gpointer      invocation_hint G_GNUC_UNUSED,
+                                     gpointer      marshal_data)
+{
+  typedef gint (*GMarshalFunc_INT__STRING) (gpointer     data1,
+                                            gpointer     arg_1,
+                                            gpointer     data2);
+  register GMarshalFunc_INT__STRING callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gint v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 2);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_INT__STRING) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       g_marshal_value_peek_string (param_values + 1),
+                       data2);
+
+  g_value_set_int (return_value, v_return);
+}
+
+/* INT:INT (marshal_types:3) */
+void
+g_cclosure_user_marshal_INT__INT (GClosure     *closure,
+                                  GValue       *return_value G_GNUC_UNUSED,
+                                  guint         n_param_values,
+                                  const GValue *param_values,
+                                  gpointer      invocation_hint G_GNUC_UNUSED,
+                                  gpointer      marshal_data)
+{
+  typedef gint (*GMarshalFunc_INT__INT) (gpointer     data1,
+                                         gint         arg_1,
+                                         gpointer     data2);
+  register GMarshalFunc_INT__INT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gint v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 2);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_INT__INT) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       g_marshal_value_peek_int (param_values + 1),
+                       data2);
+
+  g_value_set_int (return_value, v_return);
+}
+
+/* INT:BOOL (marshal_types:4) */
+void
+g_cclosure_user_marshal_INT__BOOLEAN (GClosure     *closure,
+                                      GValue       *return_value G_GNUC_UNUSED,
+                                      guint         n_param_values,
+                                      const GValue *param_values,
+                                      gpointer      invocation_hint G_GNUC_UNUSED,
+                                      gpointer      marshal_data)
+{
+  typedef gint (*GMarshalFunc_INT__BOOLEAN) (gpointer     data1,
+                                             gboolean     arg_1,
+                                             gpointer     data2);
+  register GMarshalFunc_INT__BOOLEAN callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gint v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 2);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_INT__BOOLEAN) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       g_marshal_value_peek_boolean (param_values + 1),
+                       data2);
+
+  g_value_set_int (return_value, v_return);
+}
+
+/* INT:VOID (marshal_types:6) */
+void
+g_cclosure_user_marshal_INT__VOID (GClosure     *closure,
+                                   GValue       *return_value G_GNUC_UNUSED,
+                                   guint         n_param_values,
+                                   const GValue *param_values,
+                                   gpointer      invocation_hint G_GNUC_UNUSED,
+                                   gpointer      marshal_data)
+{
+  typedef gint (*GMarshalFunc_INT__VOID) (gpointer     data1,
+                                          gpointer     data2);
+  register GMarshalFunc_INT__VOID callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gint v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 1);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_INT__VOID) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       data2);
+
+  g_value_set_int (return_value, v_return);
+}
+
+/* BOOL:VOID (marshal_types:7) */
+void
+g_cclosure_user_marshal_BOOLEAN__VOID (GClosure     *closure,
+                                       GValue       *return_value G_GNUC_UNUSED,
+                                       guint         n_param_values,
+                                       const GValue *param_values,
+                                       gpointer      invocation_hint G_GNUC_UNUSED,
+                                       gpointer      marshal_data)
+{
+  typedef gboolean (*GMarshalFunc_BOOLEAN__VOID) (gpointer     data1,
+                                                  gpointer     data2);
+  register GMarshalFunc_BOOLEAN__VOID callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gboolean v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 1);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_BOOLEAN__VOID) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       data2);
+
+  g_value_set_boolean (return_value, v_return);
+}
+
+/* STRING:VOID (marshal_types:8) */
+void
+g_cclosure_user_marshal_STRING__VOID (GClosure     *closure,
+                                      GValue       *return_value G_GNUC_UNUSED,
+                                      guint         n_param_values,
+                                      const GValue *param_values,
+                                      gpointer      invocation_hint G_GNUC_UNUSED,
+                                      gpointer      marshal_data)
+{
+  typedef gchar* (*GMarshalFunc_STRING__VOID) (gpointer     data1,
+                                               gpointer     data2);
+  register GMarshalFunc_STRING__VOID callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gchar* v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 1);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_STRING__VOID) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       data2);
+
+  g_value_take_string (return_value, v_return);
+}
+
+/* INT:STRING (marshal_types:11) */
+
+/* STRING:BOOL (marshal_types:13) */
+void
+g_cclosure_user_marshal_STRING__BOOLEAN (GClosure     *closure,
+                                         GValue       *return_value G_GNUC_UNUSED,
+                                         guint         n_param_values,
+                                         const GValue *param_values,
+                                         gpointer      invocation_hint G_GNUC_UNUSED,
+                                         gpointer      marshal_data)
+{
+  typedef gchar* (*GMarshalFunc_STRING__BOOLEAN) (gpointer     data1,
+                                                  gboolean     arg_1,
+                                                  gpointer     data2);
+  register GMarshalFunc_STRING__BOOLEAN callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gchar* v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 2);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_STRING__BOOLEAN) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       g_marshal_value_peek_boolean (param_values + 1),
+                       data2);
+
+  g_value_take_string (return_value, v_return);
+}
+
+/* STRING:INT (marshal_types:14) */
+void
+g_cclosure_user_marshal_STRING__INT (GClosure     *closure,
+                                     GValue       *return_value G_GNUC_UNUSED,
+                                     guint         n_param_values,
+                                     const GValue *param_values,
+                                     gpointer      invocation_hint G_GNUC_UNUSED,
+                                     gpointer      marshal_data)
+{
+  typedef gchar* (*GMarshalFunc_STRING__INT) (gpointer     data1,
+                                              gint         arg_1,
+                                              gpointer     data2);
+  register GMarshalFunc_STRING__INT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gchar* v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 2);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_STRING__INT) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       g_marshal_value_peek_int (param_values + 1),
+                       data2);
+
+  g_value_take_string (return_value, v_return);
+}
+
+/* STRING:STRING (marshal_types:15) */
+void
+g_cclosure_user_marshal_STRING__STRING (GClosure     *closure,
+                                        GValue       *return_value G_GNUC_UNUSED,
+                                        guint         n_param_values,
+                                        const GValue *param_values,
+                                        gpointer      invocation_hint G_GNUC_UNUSED,
+                                        gpointer      marshal_data)
+{
+  typedef gchar* (*GMarshalFunc_STRING__STRING) (gpointer     data1,
+                                                 gpointer     arg_1,
+                                                 gpointer     data2);
+  register GMarshalFunc_STRING__STRING callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gchar* v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 2);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_STRING__STRING) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       g_marshal_value_peek_string (param_values + 1),
+                       data2);
+
+  g_value_take_string (return_value, v_return);
+}
+
Index: gmarshal_funcs.h
===================================================================
--- gmarshal_funcs.h	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
+++ gmarshal_funcs.h	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -0,0 +1,89 @@
+
+#ifndef __g_cclosure_user_marshal_MARSHAL_H__
+#define __g_cclosure_user_marshal_MARSHAL_H__
+
+#include	<glib-object.h>
+
+G_BEGIN_DECLS
+
+/* INT:STRING (marshal_types:2) */
+extern void g_cclosure_user_marshal_INT__STRING (GClosure     *closure,
+                                                 GValue       *return_value,
+                                                 guint         n_param_values,
+                                                 const GValue *param_values,
+                                                 gpointer      invocation_hint,
+                                                 gpointer      marshal_data);
+
+/* INT:INT (marshal_types:3) */
+extern void g_cclosure_user_marshal_INT__INT (GClosure     *closure,
+                                              GValue       *return_value,
+                                              guint         n_param_values,
+                                              const GValue *param_values,
+                                              gpointer      invocation_hint,
+                                              gpointer      marshal_data);
+
+/* INT:BOOL (marshal_types:4) */
+extern void g_cclosure_user_marshal_INT__BOOLEAN (GClosure     *closure,
+                                                  GValue       *return_value,
+                                                  guint         n_param_values,
+                                                  const GValue *param_values,
+                                                  gpointer      invocation_hint,
+                                                  gpointer      marshal_data);
+#define g_cclosure_user_marshal_INT__BOOL	g_cclosure_user_marshal_INT__BOOLEAN
+
+/* INT:VOID (marshal_types:6) */
+extern void g_cclosure_user_marshal_INT__VOID (GClosure     *closure,
+                                               GValue       *return_value,
+                                               guint         n_param_values,
+                                               const GValue *param_values,
+                                               gpointer      invocation_hint,
+                                               gpointer      marshal_data);
+
+/* BOOL:VOID (marshal_types:7) */
+extern void g_cclosure_user_marshal_BOOLEAN__VOID (GClosure     *closure,
+                                                   GValue       *return_value,
+                                                   guint         n_param_values,
+                                                   const GValue *param_values,
+                                                   gpointer      invocation_hint,
+                                                   gpointer      marshal_data);
+#define g_cclosure_user_marshal_BOOL__VOID	g_cclosure_user_marshal_BOOLEAN__VOID
+
+/* STRING:VOID (marshal_types:8) */
+extern void g_cclosure_user_marshal_STRING__VOID (GClosure     *closure,
+                                                  GValue       *return_value,
+                                                  guint         n_param_values,
+                                                  const GValue *param_values,
+                                                  gpointer      invocation_hint,
+                                                  gpointer      marshal_data);
+
+/* INT:STRING (marshal_types:11) */
+
+/* STRING:BOOL (marshal_types:13) */
+extern void g_cclosure_user_marshal_STRING__BOOLEAN (GClosure     *closure,
+                                                     GValue       *return_value,
+                                                     guint         n_param_values,
+                                                     const GValue *param_values,
+                                                     gpointer      invocation_hint,
+                                                     gpointer      marshal_data);
+#define g_cclosure_user_marshal_STRING__BOOL	g_cclosure_user_marshal_STRING__BOOLEAN
+
+/* STRING:INT (marshal_types:14) */
+extern void g_cclosure_user_marshal_STRING__INT (GClosure     *closure,
+                                                 GValue       *return_value,
+                                                 guint         n_param_values,
+                                                 const GValue *param_values,
+                                                 gpointer      invocation_hint,
+                                                 gpointer      marshal_data);
+
+/* STRING:STRING (marshal_types:15) */
+extern void g_cclosure_user_marshal_STRING__STRING (GClosure     *closure,
+                                                    GValue       *return_value,
+                                                    guint         n_param_values,
+                                                    const GValue *param_values,
+                                                    gpointer      invocation_hint,
+                                                    gpointer      marshal_data);
+
+G_END_DECLS
+
+#endif /* __g_cclosure_user_marshal_MARSHAL_H__ */
+
Index: marshal_types
===================================================================
--- marshal_types	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
+++ marshal_types	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -0,0 +1,16 @@
+# set_fn
+INT:STRING
+INT:INT
+INT:BOOL
+# get_fn
+INT:VOID
+BOOL:VOID
+STRING:VOID
+# validate_fn has same signature as set_fn
+# set_fromstring_fn
+INT:STRING
+# get_tostring_fn
+STRING:BOOL
+STRING:INT
+STRING:STRING
+
Index: owl.c
===================================================================
--- owl.c	(revision 4d9e311c006953157914f0491b8904e796ea3f19)
+++ owl.c	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -478,4 +478,5 @@
   char **argv_copy;
   char *perlout, *perlerr;
+  const char *dlerr;
   const owl_style *s;
   const char *dir;
@@ -554,4 +555,14 @@
   }
 
+  dlerr = owl_closure_init();
+  if(dlerr) {
+    endwin();
+    fprintf(stderr, "Error binding gtk2-perl functions from C: %s\n",dlerr);
+    fflush(stderr);
+    fprintf(stdout, "Error binding gtk2-perl functions from C: %s\n",dlerr);
+    fflush(stdout);
+    exit(1);
+  }
+  
   owl_global_complete_setup(&g);
 
Index: owl.h
===================================================================
--- owl.h	(revision c42a8d1091e249bf9e1e7a3a93c7e22c9f469414)
+++ owl.h	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -235,4 +235,40 @@
   char *name;
   int   type;  /* OWL_VARIABLE_* */
+  GValue gval_default;
+  const char *validsettings;	/* documentation of valid settings */
+  char *summary;		/* summary of usage */
+  char *description;		/* detailed description */
+  GValue val;                    /* current value */
+  GClosure *validate_fn;
+                                /* returns 1 if newval is valid */
+  GClosure *set_fn;
+                                /* sets the variable to a value
+				 * of the appropriate type.
+				 * unless documented, this 
+				 * should make a copy. 
+				 * returns 0 on success. */
+  GClosure *set_fromstring_fn;
+                                /* sets the variable to a value
+				 * of the appropriate type.
+				 * unless documented, this 
+				 * should make a copy. 
+				 * returns 0 on success. */
+  GClosure *get_fn;
+				/* returns a reference to the current value.
+				 * WARNING:  this approach is hard to make
+				 * thread-safe... */
+  GClosure *get_tostring_fn;
+                                /* converts val to a string;
+				 * caller must free the result */
+  GClosure *delete_fn;
+				/* frees val as needed */
+  GClosure *get_default_fn;
+                               /* return the default value, as set at creation time */
+  
+} owl_variable;
+
+typedef struct _owl_variable_init_params {
+  char *name;
+  int   type;  /* OWL_VARIABLE_* */
   void *pval_default;  /* for types other and string */
   int   ival_default;  /* for types int and bool     */
@@ -241,7 +277,7 @@
   char *description;		/* detailed description */
   void *val;                    /* current value */
-  int  (*validate_fn)(const struct _owl_variable *v, const void *newval);
+  GCallback validate_fn;
                                 /* returns 1 if newval is valid */
-  int  (*set_fn)(struct _owl_variable *v, const void *newval); 
+  GCallback set_fn;
                                 /* sets the variable to a value
 				 * of the appropriate type.
@@ -249,5 +285,5 @@
 				 * should make a copy. 
 				 * returns 0 on success. */
-  int  (*set_fromstring_fn)(struct _owl_variable *v, const char *newval);
+  GCallback set_fromstring_fn;
                                 /* sets the variable to a value
 				 * of the appropriate type.
@@ -255,14 +291,17 @@
 				 * should make a copy. 
 				 * returns 0 on success. */
-  const void *(*get_fn)(const struct _owl_variable *v);
+  GCallback get_fn;
 				/* returns a reference to the current value.
 				 * WARNING:  this approach is hard to make
 				 * thread-safe... */
-  CALLER_OWN char *(*get_tostring_fn)(const struct _owl_variable *v, const void *val);
+  GCallback get_tostring_fn;
                                 /* converts val to a string;
 				 * caller must free the result */
-  void (*delete_fn)(struct _owl_variable *v);
+  GCallback delete_fn;
 				/* frees val as needed */
-} owl_variable;
+  GCallback get_default_fn;
+				/* return the default value as set at creation time */
+} owl_variable_init_params;
+
 
 typedef struct _owl_input {
@@ -614,3 +653,9 @@
 #endif
 
+/* We have to dynamically bind these ourselves */
+extern gboolean (*gvalue_from_sv) (GValue * value, SV * sv);
+extern SV * (*sv_from_gvalue) (const GValue * value);
+extern GClosure * (*perl_closure_new) (SV * callback, SV * data, gboolean swap);
+
+
 #endif /* INC_BARNOWL_OWL_H */
Index: perlconfig.c
===================================================================
--- perlconfig.c	(revision 6401db33a7a1c3156833113bbe6e9eec7a571406)
+++ perlconfig.c	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -559,2 +559,10 @@
   SvREFCNT_dec(v);
 }
+
+void owl_perl_delete_perl_variable(owl_variable *variable, void *data)
+{
+  g_closure_unref(variable->delete_fn);
+  variable->delete_fn = NULL;
+  SvREFCNT_dec((SV*)data);
+  owl_variable_delete(variable);
+}
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision 374089acfb4f43fdb00e90ec924887d88fd84f5d)
+++ perlglue.xs	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -402,4 +402,77 @@
 	   }
 
+
+MODULE = BarnOwl		PACKAGE = BarnOwl::Internal
+
+void
+new_variable_full(name, summary, desc, type, data, default_val, get_fn, get_default_fn, tostring_fn, validate_fn, set_fn, fromstring_fn)
+    const char *name
+    const char *summary
+    const char *desc
+    int type
+    SV *data
+    SV *default_val
+    SV *get_fn
+    SV *get_default_fn
+    SV *tostring_fn
+    SV *validate_fn
+    SV *set_fn
+    SV *fromstring_fn
+    CODE:
+{
+	owl_variable *variable = NULL;
+	int count = 0;
+	int res = -1;
+	GClosure *delete_fn = NULL;
+	if(!SV_IS_CODEREF(get_fn)) {
+		croak("Get function must be a coderef!");
+	}
+	if(!SV_IS_CODEREF(tostring_fn)) {
+		croak("To-string function must be a coderef!");
+	}
+	if(!SV_IS_CODEREF(validate_fn)) {
+		croak("Validation function must be a coderef!");
+	}
+	if(!SV_IS_CODEREF(set_fn)) {
+		croak("Set function must be a coderef!");
+	}
+	if(!SV_IS_CODEREF(fromstring_fn)) {
+		croak("From-string function must be a coderef!");
+	}
+	if(!SV_IS_CODEREF(get_default_fn)) {
+		croak("Get-default function must be a coderef!");
+	}
+	variable = owl_variable_newvar(name, summary, desc);
+	variable->type = type;
+	variable->get_fn = perl_closure_new(get_fn, data, false);
+	variable->get_tostring_fn = perl_closure_new(tostring_fn, data, false);
+	variable->validate_fn = perl_closure_new(validate_fn, data, false);
+	variable->set_fn = perl_closure_new(set_fn, data, false);
+	variable->set_fromstring_fn = perl_closure_new(set_fn, data, false);
+	variable->get_default_fn = perl_closure_new(get_default_fn, 
+						    data, false);
+	delete_fn = g_cclosure_new(G_CALLBACK(owl_perl_delete_perl_variable),
+					   data, NULL);
+	g_closure_set_marshal(delete_fn,g_cclosure_marshal_VOID__VOID);
+	g_closure_ref(delete_fn);
+	g_closure_sink(delete_fn);
+	variable->delete_fn = delete_fn;
+
+	SvREFCNT_inc(data);
+
+	PUSHMARK(SP);
+	XPUSHs(sv_2mortal(newSViv(PTR2IV(variable))));
+	XPUSHs(default_val);
+	XPUSHs(data);
+	PUTBACK;
+	count = call_sv(set_fn, G_SCALAR | G_EVAL);
+	SPAGAIN;
+	
+	res = POPi;
+	owl_dict_insert_element(owl_global_get_vardict(&g),
+				variable->name, variable, NULL);
+	PUTBACK;
+}
+
 void
 new_variable_string(name, ival, summ, desc)
Index: variable.c
===================================================================
--- variable.c	(revision 8258ea514c05b11da3f68d25d8414e222496fa2d)
+++ variable.c	(revision 06e04a995f32e4c88df08bff7baf37fb5bc8a59c)
@@ -1,32 +1,37 @@
 #include "owl.h"
 #include <stdio.h>
+#include "gmarshal_funcs.h"
+
+static const GType owl_variable_gtype_map[] = {G_TYPE_POINTER, 
+					       G_TYPE_INT, G_TYPE_BOOLEAN,
+					       G_TYPE_STRING };
 
 #define OWLVAR_BOOL(name,default,summary,description) \
         { g_strdup(name), OWL_VARIABLE_BOOL, NULL, default, "on,off", g_strdup(summary), g_strdup(description), NULL, \
-        NULL, NULL, NULL, NULL, NULL, NULL }
+	    NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 
 #define OWLVAR_BOOL_FULL(name,default,summary,description,validate,set,get) \
         { g_strdup(name), OWL_VARIABLE_BOOL, NULL, default, "on,off", g_strdup(summary), g_strdup(description), NULL, \
-        validate, set, NULL, get, NULL, NULL }
+	    G_CALLBACK(validate), G_CALLBACK(set), NULL, G_CALLBACK(get), NULL, NULL, NULL }
 
 #define OWLVAR_INT(name,default,summary,description) \
         { g_strdup(name), OWL_VARIABLE_INT, NULL, default, "<int>", g_strdup(summary), g_strdup(description), NULL, \
-        NULL, NULL, NULL, NULL, NULL, NULL }
+	    NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 
 #define OWLVAR_INT_FULL(name,default,summary,description,validset,validate,set,get) \
         { g_strdup(name), OWL_VARIABLE_INT, NULL, default, validset, g_strdup(summary), g_strdup(description), NULL, \
-        validate, set, NULL, get, NULL, NULL }
+	    G_CALLBACK(validate), G_CALLBACK(set), NULL, G_CALLBACK(get), NULL, NULL, NULL }
 
 #define OWLVAR_PATH(name,default,summary,description) \
         { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, "<path>", g_strdup(summary), g_strdup(description),  NULL, \
-        NULL, NULL, NULL, NULL, NULL, NULL }
+	    NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 
 #define OWLVAR_STRING(name,default,summary,description) \
         { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, "<string>", g_strdup(summary), g_strdup(description), NULL, \
-        NULL, NULL, NULL, NULL, NULL, NULL }
+	    NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 
 #define OWLVAR_STRING_FULL(name,default,validset,summary,description,validate,set,get) \
         { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, validset, g_strdup(summary), g_strdup(description), NULL, \
-        validate, set, NULL, get, NULL, NULL }
+	    G_CALLBACK(validate), G_CALLBACK(set), NULL, G_CALLBACK(get), NULL, NULL, NULL }
 
 /* enums are really integers, but where validset is a comma-separated
@@ -35,19 +40,19 @@
 #define OWLVAR_ENUM(name,default,summary,description,validset) \
         { g_strdup(name), OWL_VARIABLE_INT, NULL, default, validset, g_strdup(summary), g_strdup(description), NULL, \
-        owl_variable_enum_validate, \
-        NULL, owl_variable_enum_set_fromstring, \
-        NULL, owl_variable_enum_get_tostring, \
-        NULL }
+	    G_CALLBACK(owl_variable_enum_validate),			\
+	    NULL, G_CALLBACK(owl_variable_enum_set_fromstring),		\
+	    NULL, G_CALLBACK(owl_variable_enum_get_tostring),		\
+	    NULL, NULL }
 
 #define OWLVAR_ENUM_FULL(name,default,summary,description,validset,validate, set, get) \
         { g_strdup(name), OWL_VARIABLE_INT, NULL, default, validset, g_strdup(summary), g_strdup(description), NULL, \
-        validate, \
-        set, owl_variable_enum_set_fromstring, \
-        get, owl_variable_enum_get_tostring, \
-        NULL }
+	    G_CALLBACK(validate),					\
+	    G_CALLBACK(set), G_CALLBACK(owl_variable_enum_set_fromstring), \
+	    G_CALLBACK(get), G_CALLBACK(owl_variable_enum_get_tostring), \
+	    NULL, NULL }
 
 int owl_variable_add_defaults(owl_vardict *vd)
 {
-  owl_variable variables_to_init[] = {
+  owl_variable_init_params variables_to_init[] = {
 
   OWLVAR_STRING( "personalbell" /* %OwlVarStub */, "off",
@@ -439,7 +444,7 @@
 
   int ret = owl_variable_dict_add_from_list(vd, variables_to_init);
-  owl_variable *var;
+  owl_variable_init_params *var;
   for (var = variables_to_init; var->name != NULL; var++)
-    owl_variable_cleanup(var);
+    owl_variable_cleanup_initializer(var);
   return ret;
 }
@@ -452,23 +457,19 @@
 /* commonly useful */
 
-int owl_variable_int_validate_gt0(const owl_variable *v, const void *newval)
-{
-  if (newval == NULL) return(0);
-  else if (*(const int*)newval < 1) return(0);
-  else return (1);
-}
-
-int owl_variable_int_validate_positive(const owl_variable *v, const void *newval)
-{
-  if (newval == NULL) return(0);
-  else if (*(const int*)newval < 0) return(0);
-  else return (1);
+int owl_variable_int_validate_gt0(const owl_variable *v, const int newval, void *dummy)
+{
+  return !(newval < 1);
+}
+
+int owl_variable_int_validate_positive(const owl_variable *v, const int newval, void *dummy)
+{
+  return !(newval < 0);
 }
 
 /* typewinsize */
-int owl_variable_typewinsize_set(owl_variable *v, const void *newval)
+int owl_variable_typewinsize_set(owl_variable *v, const int newval, void *dummy)
 {
   int rv;
-  rv = owl_variable_int_set_default(v, newval);
+  rv = owl_variable_int_set_default(v, newval, dummy);
   if (0 == rv) owl_mainpanel_layout_contents(&g.mainpanel);
   return(rv);
@@ -476,28 +477,26 @@
 
 /* debug (cache value in g->debug) */
-int owl_variable_debug_set(owl_variable *v, const void *newval)
-{
-  if (newval && (*(const int*)newval == 1 || *(const int*)newval == 0)) {
-    g.debug = *(const int*)newval;
-  }
-  return owl_variable_bool_set_default(v, newval);
+int owl_variable_debug_set(owl_variable *v, const int newval, void *dummy)
+{
+  if (newval == 1 || newval == 0) {
+    g.debug = newval;
+  }
+  return owl_variable_bool_set_default(v, newval, dummy);
 }
 
 /* When 'aaway' is changed, need to notify the AIM server */
-int owl_variable_aaway_set(owl_variable *v, const void *newval)
-{
-  if (newval) {
-    if (*(const int*)newval == 1) {
-      owl_aim_set_awaymsg(owl_global_get_aaway_msg(&g));
-    } else if (*(const int*)newval == 0) {
-      owl_aim_set_awaymsg("");
-    }
-  }
-  return owl_variable_bool_set_default(v, newval);
-}
-
-int owl_variable_colorztext_set(owl_variable *v, const void *newval)
-{
-  int ret = owl_variable_bool_set_default(v, newval);
+int owl_variable_aaway_set(owl_variable *v, const gboolean newval, void *dummy)
+{
+  if (newval == 1) {
+    owl_aim_set_awaymsg(owl_global_get_aaway_msg(&g));
+  } else if (newval == 0) {
+    owl_aim_set_awaymsg("");
+  }
+  return owl_variable_bool_set_default(v, newval, dummy);
+}
+
+int owl_variable_colorztext_set(owl_variable *v, const void *newval, void *dummy)
+{
+  int ret = owl_variable_bool_set_default(v, newval, dummy);
   /* flush the format cache so that we see the update, but only if we're done initializing BarnOwl */
   if (owl_global_get_msglist(&g) != NULL)
@@ -510,31 +509,29 @@
 }
 
-int owl_variable_pseudologins_set(owl_variable *v, const void *newval)
+int owl_variable_pseudologins_set(owl_variable *v, const int newval, void *dummy)
 {
   static guint timer = 0;
-  if (newval) {
-    if (*(const int*)newval == 1) {
-      owl_function_zephyr_buddy_check(0);
-      if (timer == 0) {
-        timer = g_timeout_add_seconds(180, owl_zephyr_buddycheck_timer, NULL);
-      }
-    } else {
-      if (timer != 0) {
-        g_source_remove(timer);
-        timer = 0;
-      }
+  if (newval == 1) {
+    owl_function_zephyr_buddy_check(0);
+    if (timer == 0) {
+      timer = g_timeout_add_seconds(180, owl_zephyr_buddycheck_timer, NULL);
     }
-  }
-  return owl_variable_bool_set_default(v, newval);
+  } else {
+    if (timer != 0) {
+      g_source_remove(timer);
+      timer = 0;
+    }
+  }
+  return owl_variable_bool_set_default(v, newval, dummy);
 }
 
 /* note that changing the value of this will clobber 
  * any user setting of this */
-int owl_variable_disable_ctrl_d_set(owl_variable *v, const void *newval)
-{
-  if (newval && !owl_context_is_startup(owl_global_get_context(&g))) {
-    if (*(const int*)newval == 2) {
+int owl_variable_disable_ctrl_d_set(owl_variable *v, const int newval, void *dummy)
+{
+  if (!owl_context_is_startup(owl_global_get_context(&g))) {
+    if (newval == 2) {
       owl_function_command_norv("bindkey editmulti C-d command edit:delete-next-char");
-    } else if (*(const int*)newval == 1) {
+    } else if (newval == 1) {
       owl_function_command_norv("bindkey editmulti C-d command edit:done-or-delete");
     } else {
@@ -542,29 +539,29 @@
     }
   }  
-  return owl_variable_int_set_default(v, newval);  
-}
-
-int owl_variable_tty_set(owl_variable *v, const void *newval)
+  return owl_variable_int_set_default(v, newval, dummy);  
+}
+
+int owl_variable_tty_set(owl_variable *v, const char *newval, void *dummy)
 {
   owl_zephyr_set_locationinfo(g_get_host_name(), newval);
-  return(owl_variable_string_set_default(v, newval));
-}
-
-int owl_variable_default_exposure_set(owl_variable *v, const void *newval)
+  return(owl_variable_string_set_default(v, newval, dummy));
+}
+
+int owl_variable_default_exposure_set(owl_variable *v, const char *newval, void *dummy)
 {
   return owl_zephyr_set_default_exposure(newval);
 }
 
-const void *owl_variable_default_exposure_get(const owl_variable *v)
+const char *owl_variable_default_exposure_get(const owl_variable *v, void *dummy)
 {
   return owl_zephyr_get_default_exposure();
 }
 
-int owl_variable_exposure_set(owl_variable *v, const void *newval)
+int owl_variable_exposure_set(owl_variable *v, const char *newval, void *dummy)
 {
   int ret = owl_zephyr_set_exposure(newval);
   if (ret != 0)
     return ret;
-  return owl_variable_string_set_default(v, owl_zephyr_normalize_exposure(newval));
+  return owl_variable_string_set_default(v, owl_zephyr_normalize_exposure(newval), dummy);
 }
 
@@ -578,65 +575,110 @@
 }
 
-int owl_variable_dict_add_from_list(owl_vardict *vd, owl_variable *variables_to_init)
-{
-  owl_variable *var, *cur;
-  for (var = variables_to_init; var->name != NULL; var++) {
-    cur = g_new(owl_variable, 1);
-    *cur = *var;
+CALLER_OWN GClosure *owl_variable_make_closure(owl_variable *v,
+                                                      GCallback fn,
+                                                      GClosureMarshal marshal) {
+  GClosure *closure = g_cclosure_new(fn, NULL, NULL);
+  g_closure_set_marshal(closure,marshal);
+  g_closure_ref(closure);
+  g_closure_sink(closure);
+  return closure;
+}
+
+#define OWL_VARIABLE_SETUP_FUNC(variable, initializer, func_name, default_func, marshal_func, temp) do { \
+  if(initializer->func_name) { \
+    temp = initializer->func_name; \
+  } else { \
+    temp = default_func; \
+  } \
+  variable->func_name = owl_variable_make_closure(variable, G_CALLBACK(temp), \
+						  marshal_func);	\
+  } while(0)
+  
+
+int owl_variable_dict_add_from_list(owl_vardict *vd, owl_variable_init_params *variables_to_init)
+{
+  owl_variable *newvar = NULL;
+  owl_variable_init_params *init_params = NULL;
+  for (init_params = variables_to_init; init_params->name; init_params++) {
+    newvar = g_new0(owl_variable, 1);
+    newvar->type = init_params->type;
     /* strdup all the strings so we can delete them consistently. */
-    cur->name = g_strdup(var->name);
-    cur->summary = g_strdup(var->summary);
-    cur->description = g_strdup(var->description);
-    switch (cur->type) {
-    case OWL_VARIABLE_OTHER:
-      cur->set_fn(cur, cur->pval_default);
-      break;
+    newvar->name = g_strdup(init_params->name);
+    newvar->summary = g_strdup(init_params->summary);
+    newvar->description = g_strdup(init_params->description);
+    newvar->validsettings = init_params->validsettings;
+    GValue values[] = {{0}, {0}};
+    GValue *value = values+1;
+    GValue ret = {0};
+    GCallback fn = NULL;
+    switch (init_params->type) {
     case OWL_VARIABLE_STRING:
-      if (!cur->validate_fn) 
-	cur->validate_fn = owl_variable_string_validate_default;
-      if (!cur->set_fn) 
-	cur->set_fn = owl_variable_string_set_default;
-      if (!cur->set_fromstring_fn) 
-	cur->set_fromstring_fn = owl_variable_string_set_fromstring_default;
-      if (!cur->get_fn) 
-	cur->get_fn = owl_variable_get_default;
-      if (!cur->get_tostring_fn) 
-	cur->get_tostring_fn = owl_variable_string_get_tostring_default;      
-      if (!cur->delete_fn)
-	cur->delete_fn = owl_variable_delete_default;
-      cur->pval_default = g_strdup(var->pval_default);
-      cur->set_fn(cur, cur->pval_default);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, get_fn, 
+                              G_CALLBACK(owl_variable_string_get_default), 
+                              g_cclosure_user_marshal_STRING__VOID, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, set_fn, 
+                              G_CALLBACK(owl_variable_string_set_default), 
+                              g_cclosure_user_marshal_INT__STRING, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, validate_fn,
+                              G_CALLBACK(owl_variable_string_validate_default),
+                              g_cclosure_user_marshal_INT__STRING, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, set_fromstring_fn,
+                              G_CALLBACK(owl_variable_string_set_fromstring_default),
+                              g_cclosure_user_marshal_INT__STRING, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, get_tostring_fn,
+                              G_CALLBACK(owl_variable_string_get_tostring_default),
+                              g_cclosure_user_marshal_STRING__STRING, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, get_default_fn, 
+                              G_CALLBACK(owl_variable_string_get_default_default), 
+                              g_cclosure_user_marshal_STRING__VOID, fn);
+
+      g_value_init(value,G_TYPE_STRING);
+      g_value_set_string(value, init_params->pval_default);
       break;
     case OWL_VARIABLE_BOOL:
-      if (!cur->validate_fn) 
-	cur->validate_fn = owl_variable_bool_validate_default;
-      if (!cur->set_fn) 
-	cur->set_fn = owl_variable_bool_set_default;
-      if (!cur->set_fromstring_fn) 
-	cur->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
-      if (!cur->get_fn) 
-	cur->get_fn = owl_variable_get_default;
-      if (!cur->get_tostring_fn) 
-	cur->get_tostring_fn = owl_variable_bool_get_tostring_default;      
-      if (!cur->delete_fn)
-	cur->delete_fn = owl_variable_delete_default;
-      cur->val = g_new(int, 1);
-      cur->set_fn(cur, &cur->ival_default);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, get_fn, 
+                              G_CALLBACK(owl_variable_bool_get_default), 
+                              g_cclosure_user_marshal_BOOLEAN__VOID, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, set_fn, 
+                              G_CALLBACK(owl_variable_bool_set_default), 
+                              g_cclosure_user_marshal_INT__BOOLEAN, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, validate_fn,
+                              G_CALLBACK(owl_variable_bool_validate_default),
+                              g_cclosure_user_marshal_INT__BOOLEAN, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, set_fromstring_fn,
+                              G_CALLBACK(owl_variable_bool_set_fromstring_default),
+                              g_cclosure_user_marshal_INT__STRING, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, get_tostring_fn,
+                              G_CALLBACK(owl_variable_bool_get_tostring_default),
+                              g_cclosure_user_marshal_STRING__BOOLEAN, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, get_default_fn,
+                              G_CALLBACK(owl_variable_bool_get_default_default),
+                              g_cclosure_user_marshal_BOOLEAN__VOID, fn);
+
+      g_value_init(value,G_TYPE_BOOLEAN);
+      g_value_set_boolean(value, !!(init_params->ival_default));
       break;
     case OWL_VARIABLE_INT:
-      if (!cur->validate_fn) 
-	cur->validate_fn = owl_variable_int_validate_default;
-      if (!cur->set_fn) 
-	cur->set_fn = owl_variable_int_set_default;
-      if (!cur->set_fromstring_fn) 
-	cur->set_fromstring_fn = owl_variable_int_set_fromstring_default;
-      if (!cur->get_fn) 
-	cur->get_fn = owl_variable_get_default;
-      if (!cur->get_tostring_fn) 
-	cur->get_tostring_fn = owl_variable_int_get_tostring_default;      
-      if (!cur->delete_fn)
-	cur->delete_fn = owl_variable_delete_default;
-      cur->val = g_new(int, 1);
-      cur->set_fn(cur, &cur->ival_default);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, get_fn, 
+                              G_CALLBACK(owl_variable_int_get_default), 
+                              g_cclosure_user_marshal_INT__VOID, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, set_fn, 
+                              G_CALLBACK(owl_variable_int_set_default), 
+                              g_cclosure_user_marshal_INT__INT, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, validate_fn,
+                              G_CALLBACK(owl_variable_int_validate_default),
+                              g_cclosure_user_marshal_INT__INT, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, set_fromstring_fn,
+                              G_CALLBACK(owl_variable_int_set_fromstring_default),
+                              g_cclosure_user_marshal_INT__STRING, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, get_tostring_fn,
+                              G_CALLBACK(owl_variable_int_get_tostring_default),
+                              g_cclosure_user_marshal_STRING__INT, fn);
+      OWL_VARIABLE_SETUP_FUNC(newvar, init_params, get_default_fn, 
+                              G_CALLBACK(owl_variable_int_get_default_default), 
+                              g_cclosure_user_marshal_INT__VOID, fn);
+
+      g_value_init(value,G_TYPE_INT);
+      g_value_set_int(value, init_params->ival_default);
       break;
     default:
@@ -644,5 +686,18 @@
       return(-2);
     }
-    owl_dict_insert_element(vd, cur->name, cur, NULL);
+    OWL_VARIABLE_SETUP_FUNC(newvar, init_params, delete_fn, 
+                            G_CALLBACK(owl_variable_delete_default),
+                            g_cclosure_marshal_VOID__VOID, fn);
+    
+    g_value_init(&(newvar->gval_default), G_VALUE_TYPE(value));
+    g_value_init(&(newvar->val), G_VALUE_TYPE(value));
+    g_value_copy(value, &(newvar->gval_default));
+    /* we have the value boxed up already *anyway*, so... */
+    g_value_init(values, G_TYPE_POINTER);
+    g_value_set_pointer(values, newvar);
+    g_value_init(&ret, G_TYPE_INT);
+    g_closure_invoke(newvar->set_fn, &ret, 2, values, NULL);
+    g_value_unset(value);
+    owl_dict_insert_element(vd, newvar->name, newvar, NULL);
   }
   return 0;
@@ -656,5 +711,5 @@
 CALLER_OWN owl_variable *owl_variable_newvar(const char *name, const char *summary, const char *description)
 {
-  owl_variable * var = g_new0(owl_variable, 1);
+  owl_variable *var = g_new0(owl_variable, 1);
   var->name = g_strdup(name);
   var->summary = g_strdup(summary);
@@ -670,22 +725,49 @@
 }
 
+#define OWL_VARIABLE_SETUP_DEFAULT_FUNCS(variable, type, gtype) do { \
+  variable->set_fn = owl_variable_make_closure(variable, \
+    G_CALLBACK(owl_variable_##type##_set_default), \
+    g_cclosure_user_marshal_INT__##gtype); \
+  variable->get_fn = owl_variable_make_closure(variable, \
+    G_CALLBACK(owl_variable_##type##_get_default), \
+    g_cclosure_user_marshal_##gtype##__##VOID); \
+  variable->validate_fn = owl_variable_make_closure(variable, \
+    G_CALLBACK(owl_variable_##type##_validate_default), \
+    g_cclosure_user_marshal_INT__##gtype); \
+  variable->set_fromstring_fn = owl_variable_make_closure(variable, \
+    G_CALLBACK(owl_variable_##type##_set_fromstring_default), \
+    g_cclosure_user_marshal_INT__STRING); \
+  variable->get_tostring_fn = owl_variable_make_closure(variable, \
+    G_CALLBACK(owl_variable_##type##_get_tostring_default), \
+    g_cclosure_user_marshal_STRING__##gtype); \
+  variable->get_default_fn = owl_variable_make_closure(variable, \
+    G_CALLBACK(owl_variable_##type##_get_default_default), \
+    g_cclosure_user_marshal_##gtype##__##VOID); \
+  } while(0);
+
 void owl_variable_dict_newvar_string(owl_vardict *vd, const char *name, const char *summ, const char *desc, const char *initval)
 {
+  GValue default_gvals[] = {{0}, {0}};
+  GValue *default_gval = default_gvals+1;
+  GValue retval = {0}; 
+  g_value_init(default_gval, G_TYPE_STRING);
+  g_value_init(&retval, G_TYPE_INT);
+  g_value_set_static_string(default_gval, initval);
   owl_variable *old = owl_variable_get_var(vd, name);
   if (old && owl_variable_get_type(old) == OWL_VARIABLE_STRING) {
     owl_variable_update(old, summ, desc);
-    g_free(old->pval_default);
-    old->pval_default = g_strdup(initval);
+    g_value_copy(default_gval, &(old->gval_default));
   } else {
     owl_variable * var = owl_variable_newvar(name, summ, desc);
     var->type = OWL_VARIABLE_STRING;
     var->validsettings = "<string>";
-    var->pval_default = g_strdup(initval);
-    var->set_fn = owl_variable_string_set_default;
-    var->set_fromstring_fn = owl_variable_string_set_fromstring_default;
-    var->get_fn = owl_variable_get_default;
-    var->get_tostring_fn = owl_variable_string_get_tostring_default;
-    var->delete_fn = owl_variable_delete_default;
-    var->set_fn(var, initval);
+    g_value_init(&(var->val), G_TYPE_STRING);
+    g_value_init(default_gvals, G_TYPE_POINTER);
+    g_value_set_pointer(default_gvals, var);
+    g_value_init(&(var->gval_default), G_TYPE_STRING);
+    g_value_set_string(&(var->gval_default), initval);
+    OWL_VARIABLE_SETUP_DEFAULT_FUNCS(var, string, STRING);
+
+    g_closure_invoke(var->set_fn, &retval, 2, default_gvals, NULL);
     owl_variable_dict_add_variable(vd, var);
   }
@@ -694,44 +776,54 @@
 void owl_variable_dict_newvar_int(owl_vardict *vd, const char *name, const char *summ, const char *desc, int initval)
 {
+  GValue default_gvals[] = {{0}, {0}};
+  GValue *default_gval = default_gvals+1;
+  GValue retval = {0}; 
+  g_value_init(default_gval, G_TYPE_INT);
+  g_value_init(&retval, G_TYPE_INT);
+  g_value_set_int(default_gval, initval);
   owl_variable *old = owl_variable_get_var(vd, name);
   if (old && owl_variable_get_type(old) == OWL_VARIABLE_INT) {
     owl_variable_update(old, summ, desc);
-    old->ival_default = initval;
+    g_value_copy(default_gval, &(old->gval_default));
   } else {
     owl_variable * var = owl_variable_newvar(name, summ, desc);
     var->type = OWL_VARIABLE_INT;
     var->validsettings = "<int>";
-    var->ival_default = initval;
-    var->validate_fn = owl_variable_int_validate_default;
-    var->set_fn = owl_variable_int_set_default;
-    var->set_fromstring_fn = owl_variable_int_set_fromstring_default;
-    var->get_fn = owl_variable_get_default;
-    var->get_tostring_fn = owl_variable_int_get_tostring_default;
-    var->delete_fn = owl_variable_delete_default;
-    var->val = g_new(int, 1);
-    var->set_fn(var, &initval);
+    g_value_init(&(var->val), G_TYPE_INT);
+    g_value_init(&(var->gval_default), G_TYPE_INT);
+    OWL_VARIABLE_SETUP_DEFAULT_FUNCS(var, int, INT);
+    g_value_init(default_gvals, G_TYPE_POINTER);
+    g_value_set_pointer(default_gvals, var);
+    g_value_set_int(&(var->gval_default), initval);
+    g_closure_invoke(var->set_fn, &retval, 2, default_gvals, NULL);
+    /*    g_value_unset(&retval); */
     owl_variable_dict_add_variable(vd, var);
   }
 }
 
-void owl_variable_dict_newvar_bool(owl_vardict *vd, const char *name, const char *summ, const char *desc, int initval)
-{
+void owl_variable_dict_newvar_bool(owl_vardict *vd, const char *name, const char *summ, const char *desc, gboolean initval)
+{
+  GValue default_gvals[] = {{0}, {0}};
+  GValue *default_gval = default_gvals+1;
+  GValue retval = {0}; 
+  g_value_init(default_gval, G_TYPE_BOOLEAN);
+  g_value_init(&retval, G_TYPE_INT);
+  g_value_set_boolean(default_gval, initval);
   owl_variable *old = owl_variable_get_var(vd, name);
   if (old && owl_variable_get_type(old) == OWL_VARIABLE_BOOL) {
     owl_variable_update(old, summ, desc);
-    old->ival_default = initval;
+    g_value_copy(default_gval, &(old->gval_default));
   } else {
     owl_variable * var = owl_variable_newvar(name, summ, desc);
     var->type = OWL_VARIABLE_BOOL;
     var->validsettings = "on,off";
-    var->ival_default = initval;
-    var->validate_fn = owl_variable_bool_validate_default;
-    var->set_fn = owl_variable_bool_set_default;
-    var->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
-    var->get_fn = owl_variable_get_default;
-    var->get_tostring_fn = owl_variable_bool_get_tostring_default;
-    var->delete_fn = owl_variable_delete_default;
-    var->val = g_new(int, 1);
-    var->set_fn(var, &initval);
+    g_value_init(&(var->val), G_TYPE_BOOLEAN);
+    g_value_init(&(var->gval_default), G_TYPE_BOOLEAN);
+    OWL_VARIABLE_SETUP_DEFAULT_FUNCS(var, bool, BOOLEAN);
+
+    g_value_init(default_gvals, G_TYPE_POINTER);
+    g_value_set_pointer(default_gvals, var);
+    g_value_set_int(&(var->gval_default), initval);
+    g_closure_invoke(var->set_fn, &retval, 2, default_gvals, NULL);  
     owl_variable_dict_add_variable(vd, var);
   }
@@ -749,5 +841,24 @@
 void owl_variable_cleanup(owl_variable *v)
 {
-  if (v->delete_fn) v->delete_fn(v);
+  GValue val = {0};
+  if (v->delete_fn) {
+    g_value_init(&val, G_TYPE_POINTER);
+    g_value_set_pointer(&val, v);
+    g_closure_invoke(v->delete_fn, NULL, 1, &val, NULL);
+  }
+  g_free(v->name);
+  g_free(v->summary);
+  g_free(v->description);
+  if (v->type == OWL_VARIABLE_STRING) {
+    g_value_unset(&v->gval_default);
+  }
+  g_closure_unref(v->get_fn);
+  g_closure_unref(v->set_fn);
+  g_closure_unref(v->validate_fn);
+  g_closure_unref(v->get_tostring_fn);
+  g_closure_unref(v->set_fromstring_fn);
+}
+ 
+void owl_variable_cleanup_initializer(owl_variable_init_params *v) {
   g_free(v->name);
   g_free(v->summary);
@@ -755,5 +866,5 @@
   if (v->type == OWL_VARIABLE_STRING)
     g_free(v->pval_default);
-}
+ }
 
 void owl_variable_delete(owl_variable *v)
@@ -787,44 +898,126 @@
 
 /* functions for getting and setting variable values */
+
+static CALLER_OWN  char *owl_variable_invoke_tostring(const owl_variable *v,
+						     const GValue *value) 
+{
+  GValue values[] = { {0}, {0}};
+  GValue *value_box = values+1;
+  GValue tostring_box = {0};
+  char *ret = NULL;
+  gboolean need_to_free = false;
+
+  g_value_init(values, G_TYPE_POINTER);
+  g_value_set_pointer(values, (gpointer)v);
+  g_value_init(&tostring_box, G_TYPE_STRING);
+  if(value) {
+    g_value_init(value_box, G_VALUE_TYPE(value));
+    g_value_copy(value, value_box);
+    need_to_free = true;
+  } else {
+    g_value_init(value_box, owl_variable_gtype_map[v->type]);
+    g_closure_invoke(v->get_fn, value_box, 1, values, NULL);
+  }
+  g_closure_invoke(v->get_tostring_fn,&tostring_box, 2, values, NULL);
+
+  ret = g_value_dup_string(&tostring_box);
+  g_value_unset(&tostring_box);
+  if(need_to_free) {
+    g_value_unset(value_box);
+  }
+
+  return ret;
+}
 
 /* returns 0 on success, prints a status msg if msg is true */
 int owl_variable_set_fromstring(owl_variable *v, const char *value, int msg) {
   char *tostring;
+  GValue values[] = {{0},{0},{0}};
+  GValue *value_box = values+1;
+  GValue return_box = {0};
+  int set_successfully = -1;
   if (!v->set_fromstring_fn) {
     if (msg) owl_function_error("Variable %s is read-only", owl_variable_get_name(v));
     return -1;   
   }
-  if (0 != v->set_fromstring_fn(v, value)) {
+  g_value_init(value_box, G_TYPE_STRING);
+  g_value_init(values, G_TYPE_POINTER);
+  g_value_set_pointer(values, v);
+  g_value_init(&return_box, G_TYPE_INT);
+  g_value_set_static_string(value_box, value);
+  g_closure_invoke(v->set_fromstring_fn, &return_box, 2, values, NULL);
+  set_successfully = g_value_get_int(&return_box);
+  if (0 != set_successfully) {
     if (msg) owl_function_error("Unable to set %s (must be %s)", owl_variable_get_name(v),
                                 owl_variable_get_validsettings(v));
-    return -1;
-  }
-  if (msg) {
-    tostring = v->get_tostring_fn(v, v->get_fn(v));
-    if (tostring)
+  }
+  if (msg && (0 != set_successfully)) {
+    tostring = owl_variable_invoke_tostring(v, NULL);
+    if (tostring) {
       owl_function_makemsg("%s = '%s'", owl_variable_get_name(v), tostring);
-    else
+    } else {
       owl_function_makemsg("%s = <null>", owl_variable_get_name(v));
+    }
     g_free(tostring);
-  }    
-  return 0;
+  }
+  g_value_unset(value_box);
+  return set_successfully;
+}
+
+static int owl_variable_invoke_setter(owl_variable *v, const GValue *value) {
+  GValue values[] = {{0},{0}};
+  GValue return_box = {0};
+  int ret = -1;
+  g_value_init(&return_box, G_TYPE_INT);
+  g_value_init(values, G_TYPE_POINTER);
+  g_value_set_pointer(values, v);
+  g_value_init(values+1, G_VALUE_TYPE(value));
+  g_value_copy(value, values+1);
+  g_closure_invoke(v->set_fn, &return_box, 2, values, NULL);
+  ret = g_value_get_int(&return_box);
+  /*  g_value_unset(&return_box); */
+  g_value_unset(values+1);
+  return ret;
 }
  
 int owl_variable_set_string(owl_variable *v, const char *newval)
 {
+  int ret = -1;
+  GValue value_box = {0};
   if (v->type != OWL_VARIABLE_STRING) return -1;
-  return v->set_fn(v, newval);
-}
- 
+  g_value_init(&value_box, G_TYPE_STRING);
+  g_value_set_static_string(&value_box, newval);
+  ret = owl_variable_invoke_setter(v, &value_box);
+  g_value_unset(&value_box);
+  return ret;
+}
+
 int owl_variable_set_int(owl_variable *v, int newval)
 {
+  int ret = -1;
+  GValue value_box = {0};
   if (v->type != OWL_VARIABLE_INT && v->type != OWL_VARIABLE_BOOL) return -1;
-  return v->set_fn(v, &newval);
-}
- 
+  g_value_init(&value_box, G_TYPE_INT);
+  g_value_set_int(&value_box, newval);
+  ret = owl_variable_invoke_setter(v, &value_box);
+  /* g_value_unset(&value_box); */
+  return ret;
+}
+
+int owl_variable_set_bool(owl_variable *v, gboolean newval) {
+  int ret = -1;
+  GValue value_box = {0};
+  if (v->type != OWL_VARIABLE_BOOL) return -1;
+  g_value_init(&value_box, G_TYPE_BOOLEAN);
+  g_value_set_int(&value_box, newval);
+  ret = owl_variable_invoke_setter(v, &value_box);
+  /* g_value_unset(&value_box); */
+  return ret;
+}
+
 int owl_variable_set_bool_on(owl_variable *v)
 {
   if (v->type != OWL_VARIABLE_BOOL) return -1;
-  return owl_variable_set_int(v, true);
+  return owl_variable_set_bool(v, true);
 }
 
@@ -832,19 +1025,25 @@
 {
   if (v->type != OWL_VARIABLE_BOOL) return -1;
-  return owl_variable_set_int(v, false);
+  return owl_variable_set_bool(v, false);
 }
 
 CALLER_OWN char *owl_variable_get_tostring(const owl_variable *v)
 {
-  return v->get_tostring_fn(v, v->get_fn(v));
+  return owl_variable_invoke_tostring(v, NULL);
 }
 
 CALLER_OWN char *owl_variable_get_default_tostring(const owl_variable *v)
 {
-  if (v->type == OWL_VARIABLE_INT || v->type == OWL_VARIABLE_BOOL) {
-    return v->get_tostring_fn(v, &(v->ival_default));
-  } else {
-    return v->get_tostring_fn(v, v->pval_default);
-  }
+  char *ret = NULL;
+  GValue default_value_box = {0};
+  GValue variable_box = {0};
+  g_value_init(&variable_box, G_TYPE_POINTER);
+  g_value_init(&default_value_box, owl_variable_gtype_map[v->type]);
+  g_value_set_pointer(&variable_box, (gpointer)v);
+  g_closure_invoke(v->get_default_fn, &default_value_box, 1, 
+		   &variable_box, NULL);  
+  ret = owl_variable_invoke_tostring(v, &default_value_box);
+  g_value_unset(&default_value_box);
+  return ret;
 }
 
@@ -854,49 +1053,45 @@
 }
 
-/* returns a reference */
-const void *owl_variable_get(const owl_variable *v)
-{
-  return v->get_fn(v);
+const GValue *owl_variable_get(const owl_variable *v, GValue *val)
+{
+  GValue variable_box = {0};
+  g_value_init(&variable_box, G_TYPE_POINTER);
+  g_value_set_pointer(&variable_box,(gpointer)v);
+  g_closure_invoke(v->get_fn, val, 1, &variable_box, NULL);  
+  return val;
 }
 
 const char *owl_variable_get_string(const owl_variable *v)
 {
+  GValue value = {0};
   if (owl_variable_get_type(v) != OWL_VARIABLE_STRING) {
     owl_function_error("Variable '%s' is not a string.", owl_variable_get_name(v));
     return NULL;
   }
-  return owl_variable_get(v);
-}
-
-/* returns a reference */
-const void *owl_variable_get_other(const owl_variable *v)
-{
-  if (owl_variable_get_type(v) != OWL_VARIABLE_OTHER) {
-    owl_function_error("Variable '%s' is not type other.", owl_variable_get_name(v));
-    return NULL;
-  }
-  return owl_variable_get(v);
+  g_value_init(&value, G_TYPE_STRING);
+  /* not a leak, since we don't own the underlying string */
+  return g_value_get_string(owl_variable_get(v,&value));
 }
 
 int owl_variable_get_int(const owl_variable *v)
 {
+  GValue value = {0};
   if (owl_variable_get_type(v) != OWL_VARIABLE_INT) {
     owl_function_error("Variable '%s' is an int.", owl_variable_get_name(v));
     return -1;
   }
-  const int *pi = owl_variable_get(v);
-  if (!pi) return -1;
-  return *pi;
+  g_value_init(&value, G_TYPE_INT);
+  return g_value_get_int(owl_variable_get(v,&value));
 }
 
 int owl_variable_get_bool(const owl_variable *v)
 {
+  GValue value = {0};
   if (owl_variable_get_type(v) != OWL_VARIABLE_BOOL) {
     owl_function_error("Variable '%s' is a boolean.", owl_variable_get_name(v));
     return -1;
   }
-  const int *pi = owl_variable_get(v);
-  if (!pi) return -1;
-  return *pi;
+  g_value_init(&value, G_TYPE_BOOLEAN);
+  return g_value_get_boolean(owl_variable_get(v,&value));
 }
 
@@ -933,9 +1128,9 @@
   owl_fmtext_append_normal(fm, "\n\n");
 
-
   tostring = owl_variable_get_default_tostring(v);
   owl_fmtext_append_normal(fm, "Default:        ");
   owl_fmtext_append_normal(fm, (tostring ? tostring : "<null>"));
   owl_fmtext_append_normal(fm, "\n\n");
+  g_free(tostring);
 
   owl_fmtext_append_normal(fm, "Valid Settings: ");
@@ -948,5 +1143,4 @@
     owl_fmtext_append_normal(fm, "\n\n");
   }
-  g_free(tostring);
 }
 
@@ -960,44 +1154,89 @@
 /* default common functions */
 
-const void *owl_variable_get_default(const owl_variable *v) {
-  return v->val;
-}
-
-void owl_variable_delete_default(owl_variable *v)
-{
-  g_free(v->val);
+const char *owl_variable_string_get_default(const owl_variable *v, void *dummy) {
+  return g_value_get_string(&(v->val));
+}
+
+const char *owl_variable_string_get_default_default(const owl_variable *v, void *dummy) {
+  return g_value_get_string(&(v->gval_default));
+}
+
+
+const int owl_variable_int_get_default(const owl_variable *v, void *dummy) {
+  return g_value_get_int(&(v->val));
+}
+
+const int owl_variable_int_get_default_default(const owl_variable *v, void *dummy) {
+  return g_value_get_int(&(v->gval_default));
+}
+
+
+const gboolean owl_variable_bool_get_default(const owl_variable *v, void *dummy) {
+  return g_value_get_boolean(&(v->val));
+}
+
+const gboolean owl_variable_bool_get_default_default(const owl_variable *v, void *dummy) {
+  return g_value_get_boolean(&(v->gval_default));
+}
+
+
+void owl_variable_delete_default(owl_variable *v, void *dummy)
+{
+  g_value_unset(&(v->val));
 }
 
 /* default functions for booleans */
 
-int owl_variable_bool_validate_default(const owl_variable *v, const void *newval) {
-  if (newval == NULL) return(0);
-  else if (*(const int*)newval==1 || *(const int*)newval==0) return(1);
-  else return (0);
-}
-
-int owl_variable_bool_set_default(owl_variable *v, const void *newval) {
+int owl_variable_bool_validate_default(const owl_variable *v, const gboolean newval, void *dummy) {
+  return (newval == 1) || (newval == 0);
+}
+
+static int owl_variable_invoke_validator(owl_variable *v, const GValue *newval)
+{
+  GValue values[] = {{0},{0}};
+  GValue ret = {0};
+  g_value_init(&ret, G_TYPE_INT);
+  g_value_init(values, G_TYPE_POINTER);
+  g_value_set_pointer(values, v);
+  g_value_init(values+1, G_VALUE_TYPE(newval));
+  g_value_copy(newval, values+1);
+  g_closure_invoke(v->validate_fn, &ret, 2, values, NULL);
+  g_value_unset(values+1);
+  return g_value_get_int(&ret);
+}
+
+int owl_variable_bool_set_default(owl_variable *v, const bool newval, void *dummy) {
+  GValue value = {0};
+  g_value_init(&value, G_TYPE_BOOLEAN);
+  g_value_set_boolean(&value, newval);
   if (v->validate_fn) {
-    if (!v->validate_fn(v, newval)) return(-1);
-  }
-  *(int*)v->val = *(const int*)newval;
+    if (!owl_variable_invoke_validator(v,&value)) {
+      return(-1);
+    }
+  }
+  g_value_set_boolean(&(v->val), newval);
   return(0);
 }
 
-int owl_variable_bool_set_fromstring_default(owl_variable *v, const char *newval) {
-  int i;
-  if (!strcmp(newval, "on")) i=1;
-  else if (!strcmp(newval, "off")) i=0;
-  else return(-1);
-  return (v->set_fn(v, &i));
-}
-
-CALLER_OWN char *owl_variable_bool_get_tostring_default(const owl_variable *v, const void *val)
-{
-  if (val == NULL) {
-    return NULL;
-  } else if (*(const int*)val == 0) {
+int owl_variable_bool_set_fromstring_default(owl_variable *v, const char *newval, void *dummy) {
+  gboolean i;
+  GValue value = {0};
+  if (!strcmp(newval, "on")) {
+    i=1;
+  } else if (!strcmp(newval, "off")) {
+    i=0;
+  } else {
+    return(-1);
+  }
+  g_value_init(&value, G_TYPE_BOOLEAN);
+  g_value_set_boolean(&value, i);
+  return owl_variable_invoke_setter(v,&value);
+}
+
+CALLER_OWN char *owl_variable_bool_get_tostring_default(const owl_variable *v, const bool val, void *dummy)
+{
+  if (val == 0) {
     return g_strdup("off");
-  } else if (*(const int*)val == 1) {
+  } else if (val == 1) {
     return g_strdup("on");
   } else {
@@ -1008,44 +1247,47 @@
 /* default functions for integers */
 
-int owl_variable_int_validate_default(const owl_variable *v, const void *newval) {
-  if (newval == NULL) return(0);
-  else return (1);
-}
-
-int owl_variable_int_set_default(owl_variable *v, const void *newval) {
+int owl_variable_int_validate_default(const owl_variable *v, const int newval, void *dummy)
+{
+  return (1);
+}
+
+int owl_variable_int_set_default(owl_variable *v, const int newval, void *dummy) {
+  GValue value = {0};
+  g_value_init(&value, G_TYPE_INT);
+  g_value_set_int(&value, newval);
   if (v->validate_fn) {
-    if (!v->validate_fn(v, newval)) return(-1);
-  }
-  *(int*)v->val = *(const int*)newval;
+    if (!owl_variable_invoke_validator(v,&value)) {
+      return(-1);
+    }
+  }
+  g_value_set_int(&(v->val), newval);
   return(0);
 }
 
-int owl_variable_int_set_fromstring_default(owl_variable *v, const char *newval) {
+int owl_variable_int_set_fromstring_default(owl_variable *v, const char *newval, void *dummy) {
   int i;
   char *ep;
+  GValue value = {0};
   i = strtol(newval, &ep, 10);
   if (*ep || ep==newval) return(-1);
-  return (v->set_fn(v, &i));
-}
-
-CALLER_OWN char *owl_variable_int_get_tostring_default(const owl_variable *v, const void *val)
-{
-  if (val == NULL) {
-    return NULL;
-  } else {
-    return g_strdup_printf("%d", *(const int*)val);
-  } 
+  g_value_init(&value, G_TYPE_INT);
+  g_value_set_int(&value, i);
+  return owl_variable_invoke_setter(v, &value);
+}
+
+CALLER_OWN char *owl_variable_int_get_tostring_default(const owl_variable *v, const int val, void *dummy)
+{
+  return g_strdup_printf("%d", val);
 }
 
 /* default functions for enums (a variant of integers) */
 
-int owl_variable_enum_validate(const owl_variable *v, const void *newval) {  
+int owl_variable_enum_validate(const owl_variable *v, const int newval, void *dummy) {  
   char **enums;
   int nenums, val;
-  if (newval == NULL) return(0);
   enums = g_strsplit_set(v->validsettings, ",", 0);
   nenums = g_strv_length(enums);
   g_strfreev(enums);
-  val = *(const int*)newval;
+  val = newval;
   if (val < 0 || val >= nenums) {
     return(0);
@@ -1054,7 +1296,8 @@
 }
 
-int owl_variable_enum_set_fromstring(owl_variable *v, const char *newval) {
+int owl_variable_enum_set_fromstring(owl_variable *v, const char *newval, void *dummy) {
   char **enums;
   int i, val=-1;
+  GValue box = {0};
   if (newval == NULL) return(-1);
   enums = g_strsplit_set(v->validsettings, ",", 0);
@@ -1066,8 +1309,10 @@
   g_strfreev(enums);
   if (val == -1) return(-1);
-  return (v->set_fn(v, &val));
-}
-
-CALLER_OWN char *owl_variable_enum_get_tostring(const owl_variable *v, const void *val)
+  g_value_init(&box, G_TYPE_INT);
+  g_value_set_int(&box, val);
+  return owl_variable_invoke_setter(v, &box);
+}
+
+CALLER_OWN char *owl_variable_enum_get_tostring(const owl_variable *v, const int val, void *dummy)
 {
   char **enums;
@@ -1075,10 +1320,7 @@
   char *tostring;
 
-  if (val == NULL) {
-    return NULL;
-  }
   enums = g_strsplit_set(v->validsettings, ",", 0);
   nenums = g_strv_length(enums);
-  i = *(const int*)val;
+  i = val;
   if (i<0 || i>=nenums) {
     g_strfreev(enums);
@@ -1092,25 +1334,43 @@
 /* default functions for stringeans */
 
-int owl_variable_string_validate_default(const struct _owl_variable *v, const void *newval) {
+int owl_variable_string_validate_default(const struct _owl_variable *v, const char *newval, void *dummy) {
   if (newval == NULL) return(0);
   else return (1);
 }
 
-int owl_variable_string_set_default(owl_variable *v, const void *newval) {
+int owl_variable_string_set_default(owl_variable *v, const char *newval, void *dummy) {
+  GValue value = {0};
+  g_value_init(&value, G_TYPE_STRING);
+  g_value_set_static_string(&value, newval);
   if (v->validate_fn) {
-    if (!v->validate_fn(v, newval)) return(-1);
-  }
-  g_free(v->val);
-  v->val = g_strdup(newval);
+    if (!owl_variable_invoke_validator(v,&value)) {
+      return(-1);
+    }
+  }
+
+  /* set_string dups the string for us */
+  g_value_set_string(&(v->val), newval);
   return(0);
 }
 
-int owl_variable_string_set_fromstring_default(owl_variable *v, const char *newval) {
-  return (v->set_fn(v, newval));
-}
-
-CALLER_OWN char *owl_variable_string_get_tostring_default(const owl_variable *v, const void *val)
-{
-  return g_strdup((const char*)val);
-}
-
+int owl_variable_string_set_fromstring_default(owl_variable *v, const char *newval, void *dummy) 
+{
+  GValue val = {0};
+  int ret = -1;
+  g_value_init(&val, G_TYPE_STRING);
+  /* we don't need to dup the string because we don't own it and the setter function we invoke will DTRT */
+  g_value_set_static_string(&val, newval);
+  ret = owl_variable_invoke_setter(v, &val);
+  g_value_unset(&val);
+  return ret;
+}
+
+CALLER_OWN char *owl_variable_string_get_tostring_default(const owl_variable *v, const char *val, void *dummy)
+{
+  if(val) {
+    return g_strdup(val);
+  } else {
+    return g_strdup("");
+  }
+}
+
