Make TildaWindow properly generate terminal numbers
[tilda-gobject.git] / tilda-window.c
1 #include "tilda.h"
2 #include "tilda-window.h"
3 #include "tilda-window-dbus-glue.h"
4
5 static gint
6 tilda_window_find_next_free_terminal_number (TildaWindow *tw)
7 {
8         gint i, j;
9         gboolean found;
10
11         for (i=0; i<INT_MAX; ++i)
12         {
13                 found = FALSE;
14
15                 for (j=0; j<tw->terms->len; ++j)
16                 {
17                         TildaTerminal *tt = g_ptr_array_index (tw->terms, j);
18
19                         if (tt->number == i)
20                         {
21                                 found = TRUE;
22                                 break;
23                         }
24                 }
25
26                 if (!found)
27                         return i;
28         }
29
30         return 0;
31 }
32
33 static gboolean
34 tilda_window_add_term (TildaWindow *tw)
35 {
36         gint number;
37         TildaTerminal *tt;
38
39         number = tilda_window_find_next_free_terminal_number (tw);
40         tt = g_object_new (TILDA_TYPE_TERMINAL,
41                                            "number", number,
42                                            "window-number", tw->number,
43                                            "parent-window", tw,
44                                            NULL);
45         g_ptr_array_add (tw->terms, tt);
46
47         GtkWidget *label = gtk_label_new ("Tilda");
48         gint index = gtk_notebook_prepend_page (GTK_NOTEBOOK(tw->notebook), tt->hbox, label);
49         gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK(tw->notebook), tt->hbox, TRUE, TRUE, GTK_PACK_END);
50         //gtk_notebook_set_current_page (GTK_NOTEBOOK(tw->notebook), index);
51
52         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK(tw->notebook)) > 1)
53                 gtk_notebook_set_show_tabs (GTK_NOTEBOOK(tw->notebook), TRUE);
54
55         return TRUE;
56 }
57
58 static gboolean
59 tilda_window_remove_term (TildaWindow *tw, int number)
60 {
61         int i;
62
63         for (i=0; i<tw->terms->len; ++i)
64         {
65                 TildaTerminal *tt = g_ptr_array_index (tw->terms, i);
66
67                 if (tt->number == number)
68                 {
69                         // FIXME: Find it in the notebook. Remove that notebook page.
70                         // FIXME: Check if we need to exit. Etc.
71                         g_print ("Need to remove window %d terminal %d\n", tw->number, tt->number);
72                 }
73         }
74
75         return TRUE;
76 }
77
78 static void
79 tilda_window_dbus_register_object (TildaWindow *tw)
80 {
81         gchar *object_path;
82
83         // Register this object with DBus
84         object_path = g_strdup_printf ("/net/sourceforge/Tilda/Window%d", tw->number);
85         dbus_g_connection_register_g_object (dbus_connection, object_path, G_OBJECT(tw));
86         g_free (object_path);
87 }
88
89 /*******************************************************************************
90  * ALL GOBJECT STUFF BELOW PLEASE
91  ******************************************************************************/
92
93 static GObjectClass *parent_class = NULL;
94
95 enum tilda_window_properties {
96         TILDA_WINDOW_NUMBER = 1,
97 };
98
99 static void
100 tilda_window_instance_init (GTypeInstance *instance,
101                                                         gpointer       g_class)
102 {
103         TildaWindow *self = (TildaWindow *) instance;
104         self->dispose_has_run = FALSE;
105
106         /* Initialize all properties */
107         self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
108         self->notebook = gtk_notebook_new ();
109         self->terms = g_ptr_array_new ();
110
111         /* Somewhat of a "poison" value, incase we don't set this */
112         self->number = 0xdeadbeef;
113 }
114
115 static void
116 tilda_window_set_property (GObject      *object,
117                                                    guint         property_id,
118                                                    const GValue *value,
119                                                    GParamSpec   *pspec)
120 {
121         TildaWindow *self = (TildaWindow *) object;
122
123         switch (property_id) {
124
125                 case TILDA_WINDOW_NUMBER:
126                         self->number = g_value_get_int (value);
127                         g_print ("window number: %d\n", self->number);
128                         break;
129
130                 default:
131                         /* We don't have this property */
132                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
133                         break;
134         }
135 }
136
137 static void
138 tilda_window_get_property (GObject    *object,
139                                                    guint       property_id,
140                                                    GValue     *value,
141                                                    GParamSpec *pspec)
142 {
143         TildaWindow *self = (TildaWindow *) object;
144
145         switch (property_id) {
146
147                 case TILDA_WINDOW_NUMBER:
148                         g_value_set_int (value, self->number);
149                         break;
150
151                 default:
152                         /* We don't have this property */
153                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
154                         break;
155         }
156 }
157
158 static GObject *
159 tilda_window_constructor (GType                  type,
160                                                   guint                  n_construct_properties,
161                                                   GObjectConstructParam *construct_properties)
162 {
163         GObject *obj;
164         TildaWindow *self;
165
166         /* Invoke parent constructor */
167         TildaWindowClass *klass;
168         klass = TILDA_WINDOW_CLASS (g_type_class_peek (TILDA_TYPE_WINDOW));
169         obj = parent_class->constructor (type,
170                                                                          n_construct_properties,
171                                                                          construct_properties);
172
173         /* Do other stuff here. The object is ready to go now, and all
174          * ctor properties have been set.
175          *
176          * TODO: This is the place to do DBus-init */
177         self = TILDA_WINDOW(obj);
178
179         /* Register this object with DBus */
180         tilda_window_dbus_register_object (self);
181
182         gtk_container_add (GTK_CONTAINER(self->window), self->notebook);
183         gtk_widget_show (self->notebook);
184
185         tilda_window_add_term (self);
186         tilda_window_add_term (self);
187         gtk_widget_show_all (self->window);
188
189         return obj;
190 }
191
192 static void
193 my_unref (gpointer data, gpointer user_data)
194 {
195         g_object_unref (G_OBJECT(data));
196 }
197
198 static void
199 tilda_window_dispose (GObject *obj)
200 {
201         TildaWindow *self = (TildaWindow *) obj;
202
203         /* We don't want to run dispose twice, so just return immediately */
204         if (self->dispose_has_run)
205                 return;
206
207         /*
208          * In dispose, you are supposed to free all types referenced from this
209          * object which might themselves hold a reference to self. Generally,
210          * the most simple solution is to unref all members on which you own a
211          * reference.
212          *
213          * NOTE: See the following for how to deal with GtkObject-derived things:
214          * http://library.gnome.org/devel/gtk/unstable/GtkObject.html
215          */
216         g_ptr_array_foreach (self->terms, my_unref, NULL);
217         gtk_widget_destroy (self->window);
218
219         /* Chain up to the parent class */
220         G_OBJECT_CLASS (parent_class)->dispose (obj);
221 }
222
223 static void
224 tilda_window_finalize (GObject *obj)
225 {
226         TildaWindow *self = (TildaWindow *) obj;
227
228         /*
229          * Here, complete the object's destruction.
230          * You might not need to do much...
231          */
232         // TODO: g_free() any primitives here
233         g_ptr_array_free (self->terms, TRUE);
234
235
236         /* Chain up to the parent class */
237         G_OBJECT_CLASS (parent_class)->finalize (obj);
238 }
239
240 static void
241 tilda_window_class_init (gpointer g_class,
242                                                  gpointer g_class_data)
243 {
244         GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
245         TildaWindowClass *klass = TILDA_WINDOW_CLASS (g_class);
246         GParamSpec *pspec;
247
248         /* Hook our functions to this type */
249         gobject_class->set_property = tilda_window_set_property;
250         gobject_class->get_property = tilda_window_get_property;
251         gobject_class->dispose = tilda_window_dispose;
252         gobject_class->finalize = tilda_window_finalize;
253         gobject_class->constructor = tilda_window_constructor;
254
255         parent_class = g_type_class_peek_parent (klass);
256
257         /* Install all of the properties */
258         pspec = g_param_spec_int ("number",
259                                                           "Window number",
260                                                           "Set window's number",
261                                                           0,            // min value
262                                                           INT_MAX,      // max value
263                                                           0,            // def value
264                                                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
265
266         g_object_class_install_property (gobject_class,
267                                                                          TILDA_WINDOW_NUMBER,
268                                                                          pspec);
269
270         /* TODO: more properties */
271
272         /* Hook the TildaWindow type into DBus */
273         dbus_g_object_type_install_info (tilda_window_get_type(), &dbus_glib_tilda_window_object_info);
274 }
275
276 GType
277 tilda_window_get_type (void)
278 {
279         static GType type = 0;
280
281         if (type == 0)
282         {
283                 static const GTypeInfo info = {
284                         sizeof (TildaWindowClass),
285                         NULL,   /* base_init */
286                         NULL,   /* base_finalize */
287                         tilda_window_class_init,        /* class_init */
288                         NULL,   /* class_finalize */
289                         NULL,   /* class_data */
290                         sizeof (TildaWindow),
291                         0,              /* n_preallocs */
292                         tilda_window_instance_init,     /* instance_init */
293                 };
294
295                 type = g_type_register_static (G_TYPE_OBJECT,
296                                                                            "TildaWindowType",
297                                                                            &info,
298                                                                            0);
299         }
300
301         return type;
302 }
303
304 #if 0
305
306 int main (int argc, char *argv[])
307 {
308         GObject *tw;
309         gint test_number = INT_MIN;
310
311         /* Initialize the GObject type system */
312         g_type_init ();
313         gtk_init (&argc, &argv);
314
315         tw = g_object_new (TILDA_TYPE_WINDOW, "number", 10, NULL);
316         g_object_get (G_OBJECT (tw), "number", &test_number, NULL);
317         g_assert (test_number == 10);
318
319         g_object_unref (G_OBJECT (tw));
320
321         tw = g_object_new (TILDA_TYPE_WINDOW, "number", 22, NULL);
322         g_object_get (G_OBJECT (tw), "number", &test_number, NULL);
323         g_assert (test_number == 22);
324
325         gtk_main ();
326
327         g_object_unref (G_OBJECT (tw));
328
329         return 0;
330 }
331
332 #endif
333
334 /* vim: set ts=4 sts=4 sw=4 noet tw=112: */