[Controller] Add initial-windows property
authorIra W. Snyder <devel@irasnyder.com>
Mon, 28 Jan 2008 23:13:06 +0000 (15:13 -0800)
committerIra W. Snyder <devel@irasnyder.com>
Mon, 28 Jan 2008 23:13:06 +0000 (15:13 -0800)
This adds the initial-windows property, which can be used to make Tilda
start more than one window when the program is started. This is another
frequent feature request.

Note that there was a bad bug in tilda_controller_set_property(), which
has been fixed. There was a bad cast to the self pointer at the very
beginning of the function.

tilda-config.c
tilda-config.h
tilda-controller.c
tilda-controller.h

index 8732793..6563312 100644 (file)
@@ -1,43 +1,40 @@
-#include "debug.h"
-#include "translation.h"
 #include "tilda-config.h"
 
 #include "tilda.h"
 #include "tilda-types.h"
-#include "tilda-window.h"
-#include "tilda-terminal.h"
-#include <glib-object.h>
-#include <stdlib.h>
+#include "debug.h"
+#include "translation.h"
+
+#include <glib-object.h> /* for GType */
+#include <stdlib.h> /* for exit() */
 
 GKeyFile *config_defaults = NULL;
 GKeyFile *config_userprefs = NULL;
 
 /*
  * TODO:
- *
- * Add some capability to version the config file. Maybe a [meta] section.
- *
- * Make it possible to get the version number without firing up the config system
- * as a whole. Or maybe just add the migration here, in this file, upon startup.
- *
- * The whole idea of this is that each of the objects that accesses the config
- * system implements their own lookup engine.
- */
-
-/*
- * The main idea behind this configuration system is that each of the objects
- * that accesses the config system implements their own lookup scheme. Since
- * both TildaWindow and TildaTerminal need to lookup things different ways,
- * I thought this would be the most logical solution.
+ * 1) Configuration forward-migration, automatically, on startup.
  */
 
-/* NOTE NOTE NOTE:
- * This essentially works. You still need to feasibility-test it to make sure that
- * everything pulls out of the gkeyfile ok. And you need to add the lookup code.
+/* The main idea behind this configuration system is that each type of GObject
+ * that needs to use the system implements its own lookup scheme. I tried to
+ * do this as generically as possible, by using just the GObject property names,
+ * and then looking up their type and using that to use the correct parsing
+ * function.
  *
- * Other than that, this is a mostly generic version :) !!!
+ * It is basically function overloading (for example, from C++) but done in C.
+ * Rather complicated, if you ask me. Also a complete pain. But the result
+ * sure is nice.
  */
 
+static gchar *
+tilda_config_lookup_version (GKeyFile *keyfile, GError **error)
+{
+       debug_enter  ();
+
+       return g_key_file_get_string (keyfile, "Meta", "version", error);
+}
+
 static gboolean
 tilda_config_parse_integer (GKeyFile    *keyfile,
                                                        const gchar *group_name,
@@ -183,6 +180,105 @@ tilda_config_parse_enum (GKeyFile    *keyfile,
        return TRUE;
 }
 
+gboolean
+tilda_controller_set_property_from_config (TildaController *self, const gchar *property)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_CONTROLLER(self));
+
+       GError *error = NULL;
+       gboolean ret;
+
+       GParamSpec *pspec;
+       GValue *value = g_malloc0(sizeof(GValue));
+       gboolean (*parse_func) (GKeyFile *keyfile, const gchar *group_name, const gchar *key, GValue *value, GError **error);
+
+       /* Get the pspec for this property */
+       pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(self), property);
+
+       /* Make sure that this property exists */
+       if (pspec == NULL)
+       {
+               g_critical ("FIXME: developer error -- unable to find property: %s\n", property);
+               exit (1);
+       }
+
+       /* Initialize the GValue that is going to hold the returned value */
+       g_value_init (value, pspec->value_type);
+
+       /* Set the correct function to do the parsing */
+       if      (g_type_is_a (pspec->value_type, G_TYPE_INT))
+               parse_func = tilda_config_parse_integer;
+       else if (g_type_is_a (pspec->value_type, G_TYPE_BOOLEAN))
+               parse_func = tilda_config_parse_boolean;
+       else if (g_type_is_a (pspec->value_type, G_TYPE_STRING))
+               parse_func = tilda_config_parse_string;
+       else if (g_type_is_a (pspec->value_type, G_TYPE_ENUM))
+               parse_func = tilda_config_parse_enum;
+       else
+       {
+               g_critical ("FIXME: developer error -- unknown property type: %s\n", g_type_name(pspec->value_type));
+               exit(1);
+       }
+
+       /* Do the [Controller] lookup */
+       ret = parse_func (config_userprefs, "Controller", property, value, &error);
+
+       if (error)
+       {
+               if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
+                       g_warning (error->message);
+
+               g_clear_error (&error);
+       }
+       else
+               goto success;
+
+       /* Do the [Global] lookup */
+       ret = parse_func (config_userprefs, "Global", property, value, &error);
+
+       if (error)
+       {
+               if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
+                       g_warning (error->message);
+
+               g_clear_error (&error);
+       }
+       else
+               goto success;
+
+       /* Do the [controller-defaults] lookup */
+       ret = parse_func (config_defaults, "controller-defaults", property, value, &error);
+
+       if (error)
+       {
+               if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
+                       g_warning (error->message);
+
+               g_clear_error (&error);
+
+               /* This is somewhat of a nasty hack, but I really do want to just set the property to
+                * NULL if there is no default, but ONLY for strings. */
+               if (parse_func == tilda_config_parse_string)
+               {
+                       g_value_set_string (value, NULL);
+                       goto success;
+               }
+       }
+       else
+               goto success;
+
+//failure:
+       g_critical (_("Unable to find a value for controller property: %s\n"), property);
+       return FALSE;
+
+success:
+       g_object_set_property (G_OBJECT(self), property, value);
+       g_value_unset (value);
+       g_free (value);
+       return TRUE;
+}
+
 gboolean
 tilda_window_set_property_from_config (TildaWindow *self, const gchar *property)
 {
index ba12de6..d930dd1 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef TILDA_CONFIG_H
 #define TILDA_CONFIG_H
 
+#include "tilda-controller.h"
+#include "tilda-window.h"
 #include "tilda-terminal.h"
 #include <glib.h>
 
@@ -13,8 +15,9 @@ gboolean tilda_config_init (const gchar *filename);
 gboolean tilda_config_free ();
 
 /* API */
-gboolean tilda_terminal_set_property_from_config (TildaTerminal *self, const gchar *property);
+gboolean tilda_controller_set_property_from_config (TildaController *self, const gchar *property);
 gboolean tilda_window_set_property_from_config (TildaWindow *self, const gchar *property);
+gboolean tilda_terminal_set_property_from_config (TildaTerminal *self, const gchar *property);
 
 #endif /* TILDA_CONFIG_H */
 
index 613bedb..a3d6f67 100644 (file)
@@ -1,4 +1,5 @@
 #include "tilda.h"
+#include "tilda-config.h"
 #include "tilda-controller.h"
 #include "tilda-controller-dbus-glue.h"
 #include "tilda-window.h"
@@ -158,6 +159,10 @@ tilda_controller_quit (TildaController *self, GError **error)
 
 static GObjectClass *parent_class = NULL;
 
+enum tilda_controller_properties {
+       TILDA_CONTROLLER_INITIAL_WINDOWS = 1,
+};
+
 static void
 tilda_controller_instance_init (GTypeInstance *instance,
                                                                gpointer       g_class)
@@ -168,6 +173,7 @@ tilda_controller_instance_init (GTypeInstance *instance,
 
        self->dispose_has_run = FALSE;
        self->windows = g_ptr_array_new ();
+       self->initial_windows = 1;
 }
 
 static void
@@ -176,10 +182,17 @@ tilda_controller_set_property (GObject      *object,
                                                           const GValue *value,
                                                           GParamSpec   *pspec)
 {
-       TildaController *self = (TildaController *) self;
+       debug_enter ();
+
+       TildaController *self = (TildaController *) object;
 
        switch (property_id)
        {
+               case TILDA_CONTROLLER_INITIAL_WINDOWS:
+                       self->initial_windows = g_value_get_int (value);
+                       debug_printf ("tilda controller initial windows: %d\n", self->initial_windows);
+                       break;
+
                default:
                        /* We don't have any other properties */
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -193,10 +206,16 @@ tilda_controller_get_property (GObject    *object,
                                                           GValue     *value,
                                                           GParamSpec *pspec)
 {
+       debug_enter ();
+
        TildaController *self = (TildaController *) object;
 
        switch (property_id)
        {
+               case TILDA_CONTROLLER_INITIAL_WINDOWS:
+                       g_value_set_int (value, self->initial_windows);
+                       break;
+
                default:
                        /* We don't have any other properties */
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -212,25 +231,31 @@ tilda_controller_constructor (GType                  type,
        debug_enter ();
 
        GObject *obj;
-       TildaControllerClass *klass;
        TildaController *self;
+       gint i;
 
        /* Invoke the parent constructor */
+       TildaControllerClass *klass;
        klass = TILDA_CONTROLLER_CLASS (g_type_class_peek (TILDA_TYPE_CONTROLLER));
        obj = parent_class->constructor (type,
                                                                         n_construct_properties,
                                                                         construct_properties);
+       g_print ("%s all set up\n", __func__);
 
        /* The object is ready, and all constructor-time properties have been set.
         * Have fun! */
        self = TILDA_CONTROLLER(obj);
 
+       /* Set all of the properties from the config */
+       tilda_controller_set_property_from_config (self, "initial-windows");
+
+       /* Add initial windows */
+       for (i=0; i<self->initial_windows; ++i)
+               tilda_controller_add_window (self);
+
        /* Register this object with DBus */
        tilda_controller_dbus_register_object (self);
 
-       /* Add a window -- FIXME: the number should be configurable */
-       tilda_controller_add_window (self);
-
        return obj;
 }
 
@@ -278,7 +303,7 @@ tilda_controller_finalize (GObject *obj)
 
 static void
 tilda_controller_class_init (gpointer g_class,
-                                          gpointer g_class_data)
+                                                        gpointer g_class_data)
 {
        debug_enter ();
 
@@ -295,6 +320,17 @@ tilda_controller_class_init (gpointer g_class,
        parent_class = g_type_class_peek_parent (klass);
 
        /* Add properties here */
+       pspec = g_param_spec_int ("initial-windows",
+                                                         _("The number of windows that will be opened on startup"),
+                                                         NULL,
+                                                         1,
+                                                         100, /* Sane Limit */
+                                                         1,
+                                                         G_PARAM_READWRITE);
+
+       g_object_class_install_property (gobject_class,
+                                                                        TILDA_CONTROLLER_INITIAL_WINDOWS,
+                                                                        pspec);
 
        /* Hook the TildaController type into DBus */
        dbus_g_object_type_install_info (tilda_controller_get_type(),
index 6645436..a0a5ff1 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef TILDA_CONTROLLER_H
 #define TILDA_CONTROLLER_H
 
-#include <glib.h>
+#include <glib-object.h>
 
 #define TILDA_TYPE_CONTROLLER                          (tilda_controller_get_type ())
 #define TILDA_CONTROLLER(obj)                          (G_TYPE_CHECK_INSTANCE_CAST ((obj), TILDA_TYPE_CONTROLLER, TildaController))
@@ -19,6 +19,8 @@ struct _TildaController {
 
        /* instance members */
        GPtrArray *windows;
+
+       gint initial_windows;
 };
 
 struct _TildaControllerClass {