From b29938cc9dcd9059a83448cecf15aebab7f55323 Mon Sep 17 00:00:00 2001 From: "Ira W. Snyder" Date: Wed, 23 Jan 2008 13:38:29 -0800 Subject: [PATCH] Add TildaController class Add a GObject TildaController which controls many TildaWindows. This gives us a really good place to keep the GPtrArray of windows, and keeps that code out of tilda.c. --- Makefile | 13 +- tilda-controller.c | 301 +++++++++++++++++++++++++++++++++++++++++++ tilda-controller.h | 40 ++++++ tilda-controller.xml | 19 +++ tilda-window.c | 40 ++++-- tilda-window.h | 1 + tilda.c | 100 ++------------ tilda.h | 9 +- 8 files changed, 409 insertions(+), 114 deletions(-) create mode 100644 tilda-controller.c create mode 100644 tilda-controller.h create mode 100644 tilda-controller.xml diff --git a/Makefile b/Makefile index f781474..1a5179c 100644 --- a/Makefile +++ b/Makefile @@ -15,17 +15,21 @@ ALL_LIBS=`pkg-config --libs gtk+-2.0 vte dbus-glib-1` all: tilda -tilda: tilda.o tilda-window.o tilda-terminal.o tomboykeybinder.o tomboyutil.o eggaccelerators.o +tilda: tilda.o tilda-controller.o tilda-window.o tilda-terminal.o tomboykeybinder.o tomboyutil.o eggaccelerators.o $(GCC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(ALL_LIBS) -tilda.o: tilda.c +tilda.o: tilda.c tilda.h $(GCC) $(CFLAGS) -c -o $@ $< $(ALL_CFLAGS) -tilda-window.o: tilda-window.c tilda-window.h +tilda-controller.o: tilda-controller.c tilda-controller.h tilda-controller.xml + dbus-binding-tool --mode=glib-server --prefix=tilda_controller tilda-controller.xml > tilda-controller-dbus-glue.h + $(GCC) $(CFLAGS) -c -o $@ $< $(ALL_CFLAGS) + +tilda-window.o: tilda-window.c tilda-window.h tilda-window.xml dbus-binding-tool --mode=glib-server --prefix=tilda_window tilda-window.xml > tilda-window-dbus-glue.h $(GCC) $(CFLAGS) -c -o $@ $< $(ALL_CFLAGS) -tilda-terminal.o: tilda-terminal.c tilda-terminal.h +tilda-terminal.o: tilda-terminal.c tilda-terminal.h tilda-terminal.xml dbus-binding-tool --mode=glib-server --prefix=tilda_terminal tilda-terminal.xml > tilda-terminal-dbus-glue.h $(GCC) $(CFLAGS) -c -o $@ $< $(ALL_CFLAGS) @@ -46,6 +50,7 @@ clean: rm -f tilda-window rm -f tilda-terminal rm -f tilda + rm -f tilda-controller-dbus-glue.h rm -f tilda-window-dbus-glue.h rm -f tilda-terminal-dbus-glue.h diff --git a/tilda-controller.c b/tilda-controller.c new file mode 100644 index 0000000..aa61823 --- /dev/null +++ b/tilda-controller.c @@ -0,0 +1,301 @@ +#include "tilda.h" +#include "tilda-controller.h" +#include "tilda-controller-dbus-glue.h" +#include "tilda-window.h" + +/** + * Register this object with DBus, so it can be interacted with! + */ +static void +tilda_controller_dbus_register_object (TildaController *self) +{ + debug_enter (); + debug_assert (TILDA_IS_CONTROLLER(self)); + + static const gchar object_path[] = "/net/sourceforge/Tilda"; + + dbus_g_connection_register_g_object (dbus_connection, object_path, G_OBJECT(self)); +} + +/** + * Find the next free window number, so it can be used by a TildaWindow + */ +static gint +tilda_controller_find_next_free_window_number (TildaController *self) +{ + debug_enter (); + debug_assert (TILDA_IS_CONTROLLER(self)); + + gint i, j; + gboolean found; + + for (i=0; iwindows->len; ++j) + { + TildaWindow *tw = g_ptr_array_index (self->windows, j); + + if (tw->number == i) + { + found = TRUE; + break; + } + } + + if (!found) + return i; + } + + return 0; +} + +gboolean +tilda_controller_add_window (TildaController *self) +{ + debug_enter (); + debug_assert (TILDA_IS_CONTROLLER(self)); + + TildaWindow *ret; + gint number; + + number = tilda_controller_find_next_free_window_number (self); + ret = g_object_new (TILDA_TYPE_WINDOW, + "number", number, + "controller", G_OBJECT(self), + NULL); + + g_ptr_array_add (self->windows, ret); + + debug_printf ("Adding window: 0x%x (number %d of %d)\n", ret, ret->number, self->windows->len); + return TRUE; +} + +gboolean +tilda_controller_delete_window (TildaController *self, gint window_number) +{ + debug_enter (); + debug_assert (TILDA_IS_CONTROLLER(self)); + debug_assert (window_number >= 0); + + gint i; + TildaWindow *win; + + for (i=0; iwindows->len; ++i) + { + win = g_ptr_array_index (self->windows, i); + + if (win->number == window_number) + { + debug_printf ("Deleting TildaWindow 0x%x (number %d of %d)\n", + win, win->number, self->windows->len); + g_ptr_array_remove_index (self->windows, i); + g_object_unref (G_OBJECT(win)); + + if (self->windows->len == 0) + { + debug_printf ("No windows left, exiting...\n"); + + /* We get unref'd in main() */ + gtk_main_quit (); + } + + /* We were able to delete the window */ + return TRUE; + } + } + + /* There must have been no window to delete */ + return FALSE; +} + +gboolean +tilda_controller_quit (TildaController *self, GError **error) +{ + debug_enter (); + debug_assert (TILDA_IS_CONTROLLER(self)); + + /* Not much left but to quit, since we get unref'd in main() */ + gtk_main_quit (); + + return TRUE; +} + +/******************************************************************************* + * GObject code below... it is doubtful you'll need to make big changes :) + ******************************************************************************/ + +static GObjectClass *parent_class = NULL; + +static void +tilda_controller_instance_init (GTypeInstance *instance, + gpointer g_class) +{ + debug_enter (); + + TildaController *self = (TildaController *) instance; + + self->dispose_has_run = FALSE; + self->windows = g_ptr_array_new (); +} + +static void +tilda_controller_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + TildaController *self = (TildaController *) self; + + switch (property_id) + { + default: + /* We don't have any other properties */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +tilda_controller_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + TildaController *self = (TildaController *) object; + + switch (property_id) + { + default: + /* We don't have any other properties */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static GObject * +tilda_controller_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + debug_enter (); + + GObject *obj; + TildaControllerClass *klass; + TildaController *self; + + /* Invoke the parent constructor */ + klass = TILDA_CONTROLLER_CLASS (g_type_class_peek (TILDA_TYPE_CONTROLLER)); + obj = parent_class->constructor (type, + n_construct_properties, + construct_properties); + + /* The object is ready, and all constructor-time properties have been set. + * Have fun! */ + self = TILDA_CONTROLLER(obj); + + /* 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; +} + +static void +tilda_controller_dispose (GObject *obj) +{ + debug_enter (); + + TildaController *self = (TildaController *) obj; + + /* We must only run dispose once ... */ + if (self->dispose_has_run) + return; + + self->dispose_has_run = TRUE; + + /* + * In dispose, you are supposed to free all types referenced from this + * object which might themselves hold a reference to self. Generally, + * the most simple solution is to unref all members on which you own a + * reference. + */ + g_ptr_array_foreach (self->windows, g_object_unref, NULL); + + /* Chain up to the parent class */ + G_OBJECT_CLASS (parent_class)->dispose (obj); +} + +static void +tilda_controller_finalize (GObject *obj) +{ + debug_enter (); + + TildaController *self = (TildaController *) obj; + + /* + * Here, complete the object's destruction. + * You might not need to do much more than + * g_free() any primitives. + */ + + /* Chain up to the parent class */ + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + +static void +tilda_controller_class_init (gpointer g_class, + gpointer g_class_data) +{ + debug_enter (); + + GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); + TildaControllerClass *klass = TILDA_CONTROLLER_CLASS (g_class); + GParamSpec *pspec; + + gobject_class->set_property = tilda_controller_set_property; + gobject_class->get_property = tilda_controller_get_property; + gobject_class->dispose = tilda_controller_dispose; + gobject_class->finalize = tilda_controller_finalize; + gobject_class->constructor = tilda_controller_constructor; + + parent_class = g_type_class_peek_parent (klass); + + /* Add properties here */ + + /* Hook the TildaController type into DBus */ + dbus_g_object_type_install_info (tilda_controller_get_type(), + &dbus_glib_tilda_controller_object_info); +} + +GType tilda_controller_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + static const GTypeInfo info = { + sizeof (TildaControllerClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + tilda_controller_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (TildaController), + 0, /* n_preallocs */ + tilda_controller_instance_init, /* instance_init */ + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "TildaControllerType", + &info, + 0); + } + + return type; +} + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/tilda-controller.h b/tilda-controller.h new file mode 100644 index 0000000..0982ccb --- /dev/null +++ b/tilda-controller.h @@ -0,0 +1,40 @@ +#ifndef TILDA_CONTROLLER_H +#define TILDA_CONTROLLER_H + +#include + +#define TILDA_TYPE_CONTROLLER (tilda_controller_get_type ()) +#define TILDA_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TILDA_TYPE_CONTROLLER, TildaController)) +#define TILDA_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TILDA_TYPE_CONTROLLER, TildaControllerClass)) +#define TILDA_IS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TILDA_TYPE_CONTROLLER)) +#define TILDA_IS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TILDA_TYPE_CONTROLLER)) +#define TILDA_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TILDA_TYPE_CONTROLLER, TildaControllerClass)) + +typedef struct _TildaController TildaController; +typedef struct _TildaControllerClass TildaControllerClass; + +struct _TildaController { + GObject parent; + gboolean dispose_has_run; + + /* instance members */ + GPtrArray *windows; +}; + +struct _TildaControllerClass { + GObjectClass parent; +}; + +/* Used by TILDA_TYPE_CONTROLLER */ +GType tilda_controller_get_type (void); + +/* DBus API */ +gboolean tilda_controller_add_window (TildaController *self); // FIXME: needs GError +gboolean tilda_controller_quit (TildaController *self, GError **error); + +/* API */ +gboolean tilda_controller_delete_window (TildaController *self, gint window_number); + +#endif /* TILDA_CONTROLLER_H */ + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/tilda-controller.xml b/tilda-controller.xml new file mode 100644 index 0000000..3b321da --- /dev/null +++ b/tilda-controller.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tilda-window.c b/tilda-window.c index afb32c5..1ac2a14 100644 --- a/tilda-window.c +++ b/tilda-window.c @@ -2,6 +2,7 @@ #include /* for gdk_x11_window_set_user_time() */ #include "tilda.h" +#include "tilda-controller.h" #include "tilda-window.h" #include "tilda-window-dbus-glue.h" #include "tomboykeybinder.h" @@ -76,7 +77,7 @@ tilda_window_close (TildaWindow *self) debug_enter (); debug_assert (TILDA_IS_WINDOW(self)); - tilda_del_window (self->number); + tilda_controller_delete_window (TILDA_CONTROLLER(self->controller), self->number); return TRUE; } @@ -156,7 +157,7 @@ tilda_window_remove_terminal (TildaWindow *self, gint terminal_number) if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->notebook)) < 1) { debug_printf ("no terminals left, closing window %d\n", self->number); - tilda_del_window (self->number); + tilda_controller_delete_window (TILDA_CONTROLLER(self->controller), self->number); } /* Leave the loop, we're done */ @@ -350,6 +351,7 @@ static GObjectClass *parent_class = NULL; enum tilda_window_properties { TILDA_WINDOW_NUMBER = 1, + TILDA_WINDOW_CONTROLLER, TILDA_WINDOW_KEY, @@ -388,6 +390,7 @@ tilda_window_instance_init (GTypeInstance *instance, /* Somewhat of a "poison" value, incase we don't set this */ self->number = 0xdeadbeef; + self->controller = NULL; self->state = WINDOW_UP; } @@ -407,6 +410,11 @@ tilda_window_set_property (GObject *object, debug_printf ("window number: %d\n", self->number); break; + case TILDA_WINDOW_CONTROLLER: + self->controller = g_value_get_pointer (value); + debug_printf ("window controller: 0x%x\n", self->controller); + break; + case TILDA_WINDOW_KEY: tilda_window_try_to_bind_key (self, g_value_get_string (value)); debug_printf ("window key %s\n", self->key); @@ -520,6 +528,10 @@ tilda_window_get_property (GObject *object, g_value_set_int (value, self->number); break; + case TILDA_WINDOW_CONTROLLER: + g_value_set_pointer (value, self->controller); + break; + case TILDA_WINDOW_KEY: g_value_set_string (value, self->key); break; @@ -620,7 +632,9 @@ tilda_window_constructor (GType type, gtk_widget_show (self->notebook); // FIXME: Remove these, and replace with reads from the config system - g_object_set (G_OBJECT(self), "key", "F2", NULL); + gchar *mykey = g_strdup_printf ("F%d", self->number+3); // TERRIBLE HACK + g_object_set (G_OBJECT(self), "key", mykey, NULL); + g_free (mykey); g_object_set (G_OBJECT(self), "x-position", 0, "y-position", 0, NULL); g_object_set (G_OBJECT(self), "height", 400, "width", 1680, NULL); g_object_set (G_OBJECT(self), "keep-above", TRUE, "stick", TRUE, NULL); @@ -645,15 +659,6 @@ tilda_window_constructor (GType type, return obj; } -static void -my_unref (gpointer data, gpointer user_data) -{ - debug_enter (); - - // FIXME: This function should probably be eliminated. It /is/ rather ugly - g_object_unref (G_OBJECT(data)); -} - static void tilda_window_dispose (GObject *obj) { @@ -674,7 +679,7 @@ tilda_window_dispose (GObject *obj) * NOTE: See the following for how to deal with GtkObject-derived things: * http://library.gnome.org/devel/gtk/unstable/GtkObject.html */ - g_ptr_array_foreach (self->terms, my_unref, NULL); + g_ptr_array_foreach (self->terms, g_object_unref, NULL); gtk_widget_destroy (self->window); /* Unbind if we were set */ @@ -736,6 +741,15 @@ tilda_window_class_init (gpointer g_class, TILDA_WINDOW_NUMBER, pspec); + pspec = g_param_spec_pointer ("controller", + _("Pointer to window's controlling TildaController"), + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + g_object_class_install_property (gobject_class, + TILDA_WINDOW_CONTROLLER, + pspec); + pspec = g_param_spec_string ("key", _("Window's drop-down keybinding"), NULL, diff --git a/tilda-window.h b/tilda-window.h index 1806096..a6c8b61 100644 --- a/tilda-window.h +++ b/tilda-window.h @@ -42,6 +42,7 @@ struct _TildaWindow { GPtrArray *terms; gint number; + GObject *controller; /* pointer back to TildaController */ enum window_states { WINDOW_UP, WINDOW_DOWN } state; gchar *key; diff --git a/tilda.c b/tilda.c index 02b6848..c510779 100644 --- a/tilda.c +++ b/tilda.c @@ -1,14 +1,12 @@ -#include #include #include #include "tilda.h" -#include "tilda-window.h" -#include "tilda-terminal.h" +#include "tilda-controller.h" #include "tomboykeybinder.h" +/* Project-global variables */ DBusGConnection *dbus_connection; -GPtrArray *windows; static void tilda_initialize_dbus () @@ -57,82 +55,6 @@ tilda_initialize_dbus () g_object_unref (driver_proxy); } -static gint -tilda_find_next_free_window_number () -{ - debug_enter (); - - gint i, j; - gboolean found; - - for (i=0; ilen; ++j) - { - TildaWindow *tw = g_ptr_array_index (windows, j); - - if (tw->number == i) - { - found = TRUE; - break; - } - } - - if (!found) - return i; - } - - return 0; -} - -static TildaWindow * -tilda_add_window () -{ - debug_enter (); - - TildaWindow *ret; - gint number; - - number = tilda_find_next_free_window_number (); - ret = g_object_new (TILDA_TYPE_WINDOW, "number", number, NULL); - - g_ptr_array_add (windows, ret); - - debug_printf ("Adding window: 0x%x (number %d of %d)\n", ret, ret->number, windows->len-1); - return ret; -} - -void -tilda_del_window (gint number) -{ - debug_enter (); - - gint i; - TildaWindow *win; - - for (i=0; ilen; ++i) - { - win = g_ptr_array_index (windows, i); - - if (win->number == number) - { - debug_printf ("Deleting window 0x%x (number %d of %d)\n", win, win->number, windows->len-1); - g_ptr_array_remove_index (windows, i); - g_object_unref (G_OBJECT(win)); - - if (windows->len == 0) - { - debug_printf ("No windows left, exiting...\n"); - gtk_main_quit (); - } - - break; - } - } -} - static void tilda_parse_command_line (gint argc, gchar *argv[]) { @@ -212,7 +134,7 @@ int main (int argc, char *argv[]) { debug_enter (); - TildaWindow *tw; + TildaController *tilda; #if ENABLE_NLS /* Gettext Initialization */ @@ -236,22 +158,16 @@ int main (int argc, char *argv[]) /* Start our connection to DBus */ tilda_initialize_dbus (); - /* Initialize the array of windows */ - windows = g_ptr_array_new (); - - /* Create a TildaWindow, run it, and exit when it does, basically. - * - * This is nothing like what the real main() will be, but it's - * a good start for testing and integration of more of TildaWindow - * and TildaTerminal. */ - tw = tilda_add_window (); + /* Create a TildaController, which manages TildaWindows, which in turn manages + * TildaTerminals. Exit when it does. */ + tilda = g_object_new (TILDA_TYPE_CONTROLLER, NULL); debug_printf ("Starting gtk_main()!\n"); gtk_main (); debug_printf ("Out of gtk_main(), going down\n"); - /* Free the pointer array we allocated earlier */ - g_ptr_array_free (windows, TRUE); + /* Unref the TildaController that controls this whole operation */ + g_object_unref (G_OBJECT(tilda)); return 0; } diff --git a/tilda.h b/tilda.h index 7773b57..d634833 100644 --- a/tilda.h +++ b/tilda.h @@ -1,6 +1,9 @@ #ifndef TILDA_H #define TILDA_H +#include +#include +#include #include #include "debug.h" @@ -10,12 +13,8 @@ #define TILDA_VERSION "0.10.0pre" /* Project-global variables */ -extern DBusGConnection *dbus_connection; - -/* API */ -void tilda_del_window (gint number); +DBusGConnection *dbus_connection; #endif /* TILDA_H */ /* vim: set ts=4 sts=4 sw=4 noet tw=112: */ - -- 2.34.1