Index: owl.h
===================================================================
--- owl.h	(revision 5001a3df5a2fd9b81667817e486556661f9e6ead)
+++ owl.h	(revision 69f74c224f994c1b7eb73c43474e4e31a6dc5854)
@@ -239,5 +239,4 @@
   char *summary;		/* summary of usage */
   char *description;		/* detailed description */
-  GValue val;                   /* current value */
   GClosure *set_fromstring_fn;
                                 /* sets the variable to a value
@@ -251,4 +250,6 @@
 
   /* These are only valid for OWL_VARIABLE_{INT,BOOL,STRING} */
+  GValue val;                   /* current value, if default get_fn/set_fn */
+
   GCallback get_fn;
 				/* returns a reference to the current value.
Index: perl/lib/BarnOwl.pm
===================================================================
--- perl/lib/BarnOwl.pm	(revision 374089acfb4f43fdb00e90ec924887d88fd84f5d)
+++ perl/lib/BarnOwl.pm	(revision 69f74c224f994c1b7eb73c43474e4e31a6dc5854)
@@ -426,21 +426,31 @@
 
 sub new_variable_int {
-    unshift @_, \&BarnOwl::Internal::new_variable_int, 0;
+    unshift @_, 0, "<int>", sub { "$_[0]" }, # to string
+                            sub { $_[0] =~ /^-?[0-9]+$/ }, # validate
+                            sub { 0 + $_[0] }; # from string
     goto \&_new_variable;
 }
 
 sub new_variable_bool {
-    unshift @_, \&BarnOwl::Internal::new_variable_bool, 0;
+    unshift @_, 0, "on,off", sub { $_[0] ? "on" : "off" }, # to string
+                             sub { $_[0] eq "on" || $_[0] eq "off" }, # validate
+                             sub { $_[0] eq "on" }; # from string
     goto \&_new_variable;
 }
 
 sub new_variable_string {
-    unshift @_, \&BarnOwl::Internal::new_variable_string, "";
+    unshift @_, "", "<string>", sub { $_[0] }, # to string
+                                sub { 1 }, # validate
+                                sub { $_[0] }; # from string
     goto \&_new_variable;
 }
 
 sub _new_variable {
-    my $func = shift;
     my $default_default = shift;
+    my $validsettings = shift;
+    my $tostring_fn = shift;
+    my $validate_fn = shift;
+    my $fromstring_fn = shift;
+
     my $name = shift;
     my $args = shift || {};
@@ -450,5 +460,18 @@
         default     => $default_default,
         %{$args});
-    $func->($name, $args{default}, $args{summary}, $args{description});
+
+    # Store the value in a closure.
+    my $value = $args{default};
+
+    my $get_tostring_fn = sub { $tostring_fn->($value) };
+    my $set_fromstring_fn = sub {
+      my ($dummy, $newval) = @_;
+      return -1 unless $validate_fn->($newval);
+      $value = $fromstring_fn->($newval);
+      return 0;
+    };
+
+    BarnOwl::Internal::new_variable($name, $args{summary}, $args{description}, $validsettings,
+                                    $get_tostring_fn, $set_fromstring_fn, undef);
 }
 
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision 353719a2ddec4d6a8458ee42af37514fedbd80bf)
+++ perlglue.xs	(revision 69f74c224f994c1b7eb73c43474e4e31a6dc5854)
@@ -405,114 +405,29 @@
 MODULE = BarnOwl		PACKAGE = BarnOwl::Internal
 
-/* TODO: Revise this after churn is done.
-void
-new_variable_full(name, summary, desc, type, data, default_val, get_fn, get_default_fn, tostring_fn, validate_fn, set_fn, fromstring_fn)
+void
+new_variable(name, summary, description, validsettings, get_tostring_fn, set_fromstring_fn, data)
     const char *name
     const char *summary
-    const char *desc
-    int type
+    const char *description
+    const char *validsettings
+    SV *get_tostring_fn
+    SV *set_fromstring_fn
     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)) {
+        /* data is somewhat redundant given we can create closures, but oh
+         * well. Might be convenient sometimes. */
+	if(!SV_IS_CODEREF(get_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)) {
+	if(!SV_IS_CODEREF(set_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;
+
+        owl_variable_dict_newvar_other(owl_global_get_vardict(&g),
+                                       name, summary, description, validsettings,
+                                       perl_closure_new(get_tostring_fn, data, false),
+                                       perl_closure_new(set_fromstring_fn, data, false));
 }
-*/
-
-void
-new_variable_string(name, ival, summ, desc)
-	const char * name
-	const char * ival
-	const char * summ
-	const char * desc
-	CODE:
-	owl_variable_dict_newvar_string(owl_global_get_vardict(&g),
-					name,
-					summ,
-					desc,
-					ival);
-
-void
-new_variable_int(name, ival, summ, desc)
-	const char * name
-	int ival
-	const char * summ
-	const char * desc
-	CODE:
-	owl_variable_dict_newvar_int(owl_global_get_vardict(&g),
-				     name,
-				     summ,
-				     desc,
-				     ival);
-
-void
-new_variable_bool(name, ival, summ, desc)
-	const char * name
-	int ival
-	const char * summ
-	const char * desc
-	CODE:
-	owl_variable_dict_newvar_bool(owl_global_get_vardict(&g),
-				      name,
-				      summ,
-				      desc,
-				      ival);
 
 void
Index: variable.c
===================================================================
--- variable.c	(revision 897fc1c486d9bf7768908eb79030e9f7829b51f3)
+++ variable.c	(revision 69f74c224f994c1b7eb73c43474e4e31a6dc5854)
@@ -680,5 +680,5 @@
 }
 
-CALLER_OWN owl_variable *owl_variable_newvar(const char *name, const char *summary, const char *description)
+void owl_variable_dict_newvar_other(owl_vardict *vd, const char *name, const char *summary, const char *description, const char *validsettings, GClosure *get_tostring_fn, GClosure *set_fromstring_fn)
 {
   owl_variable *var = g_new0(owl_variable, 1);
@@ -686,96 +686,17 @@
   var->summary = g_strdup(summary);
   var->description = g_strdup(description);
-  return var;
-}
-
-void owl_variable_update(owl_variable *var, const char *summary, const char *desc) {
-  g_free(var->summary);
-  var->summary = g_strdup(summary);
-  g_free(var->description);
-  var->description = g_strdup(desc);
-}
-
-#define OWL_VARIABLE_SETUP_DEFAULT_FUNCS(variable, type, gtype) do { \
-  variable->set_fn = G_CALLBACK(owl_variable_##type##_set_default); \
-  variable->get_fn = G_CALLBACK(owl_variable_##type##_get_default); \
-  variable->validate_fn = G_CALLBACK(owl_variable_##type##_validate_default); \
-  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__VOID); \
-  } while(0)
-
-void owl_variable_dict_newvar_string(owl_vardict *vd, const char *name, const char *summ, const char *desc, const char *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_value_copy(default_gval, &(old->gval_default)); */
-    /* TODO: Resolve this after churn; this function is only called from perl
-     * anyway. */
-  } else {
-    owl_variable * var = owl_variable_newvar(name, summ, desc);
-    var->type = OWL_VARIABLE_STRING;
-    var->validsettings = g_strdup("<string>");
-    g_value_init(&var->val, G_TYPE_STRING);
-    OWL_VARIABLE_SETUP_DEFAULT_FUNCS(var, string, STRING);
-
-    owl_variable_set_string(var, initval);
-
-    /* record the initial value as a string */
-    var->default_str = owl_variable_get_tostring(var);
-
-    owl_variable_dict_add_variable(vd, var);
-  }
-}
-
-void owl_variable_dict_newvar_int(owl_vardict *vd, const char *name, const char *summ, const char *desc, int 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);
-    /* g_value_copy(default_gval, &(old->gval_default)); */
-    /* TODO: Resolve this after churn; this function is only called from perl
-     * anyway. */
-  } else {
-    owl_variable * var = owl_variable_newvar(name, summ, desc);
-    var->type = OWL_VARIABLE_INT;
-    var->validsettings = g_strdup("<int>");
-    g_value_init(&var->val, G_TYPE_INT);
-    OWL_VARIABLE_SETUP_DEFAULT_FUNCS(var, int, INT);
-
-    owl_variable_set_int(var, initval);
-
-    /* record the initial value as a string */
-    var->default_str = owl_variable_get_tostring(var);
-
-    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, gboolean 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);
-    /* g_value_copy(default_gval, &(old->gval_default)); */
-    /* TODO: Resolve this after churn; this function is only called from perl
-     * anyway. */
-  } else {
-    owl_variable * var = owl_variable_newvar(name, summ, desc);
-    var->type = OWL_VARIABLE_BOOL;
-    var->validsettings = g_strdup("on,off");
-    g_value_init(&var->val, G_TYPE_BOOLEAN);
-    OWL_VARIABLE_SETUP_DEFAULT_FUNCS(var, bool, BOOLEAN);
-
-    owl_variable_set_bool(var, initval);
-
-    /* record the initial value as a string */
-    var->default_str = owl_variable_get_tostring(var);
-
-    owl_variable_dict_add_variable(vd, var);
-  }
+  var->validsettings = g_strdup(validsettings);
+
+  var->get_tostring_fn = g_closure_ref(get_tostring_fn);
+  g_closure_sink(get_tostring_fn);
+
+  var->set_fromstring_fn = g_closure_ref(set_fromstring_fn);
+  g_closure_sink(set_fromstring_fn);
+
+  var->default_str = owl_variable_get_tostring(var);
+
+  /* Note: this'll overwrite any existing variable of that name, even a C one,
+     but it's consistent with previous behavior and commands. */
+  owl_variable_dict_add_variable(vd, var);
 }
 
