[Window] Add tilda_window_remove_term() implementation
[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 /**
59  * Remove the TildaTerminal with the given number from the given
60  * TildaWindow.
61  *
62  * Return: TRUE on success, FALSE otherwise.
63  */
64 gboolean
65 tilda_window_remove_term (TildaWindow *tw, gint terminal_number)
66 {
67         gint i;
68
69         for (i=0; i<tw->terms->len; ++i)
70         {
71                 TildaTerminal *tt = g_ptr_array_index (tw->terms, i);
72
73                 if (tt->number == terminal_number)
74                 {
75                         gint notebook_index = gtk_notebook_page_num (GTK_NOTEBOOK(tw->notebook), tt->hbox);
76
77                         /* Make sure the index was valid */
78                         if (notebook_index == -1)
79                         {
80                                 g_printerr ("DEBUG ERROR: Bad Notebook Tab\n");
81                                 return FALSE;
82                         }
83
84                         /* Actually remove the terminal */
85                         gtk_notebook_remove_page (GTK_NOTEBOOK (tw->notebook), notebook_index);
86
87                         /* We should hide the tabs if there is only one tab left */
88                         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (tw->notebook)) == 1)
89                                 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (tw->notebook), FALSE);
90
91 #if 0
92                         // FIXME FIXME FIXME: need to actually do the stuff below
93                         /* With no pages left, it's time to leave the program */
94                         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (tw->notebook)) < 1)
95                                 gtk_main_quit ();
96 #endif
97
98                         /* Remove the term from our lists, then free it */
99                         g_ptr_array_remove_fast (tw->terms, tt);
100                         g_object_unref (G_OBJECT(tt));
101
102                         /* Leave the loop, we're done */
103                         break;
104                 }
105         }
106
107         return TRUE;
108 }
109
110 static void
111 tilda_window_dbus_register_object (TildaWindow *tw)
112 {
113         gchar *object_path;
114
115         // Register this object with DBus
116         object_path = g_strdup_printf ("/net/sourceforge/Tilda/Window%d", tw->number);
117         dbus_g_connection_register_g_object (dbus_connection, object_path, G_OBJECT(tw));
118         g_free (object_path);
119 }
120
121 /*******************************************************************************
122  * ALL GOBJECT STUFF BELOW PLEASE
123  ******************************************************************************/
124
125 static GObjectClass *parent_class = NULL;
126
127 enum tilda_window_properties {
128         TILDA_WINDOW_NUMBER = 1,
129 };
130
131 static void
132 tilda_window_instance_init (GTypeInstance *instance,
133                                                         gpointer       g_class)
134 {
135         TildaWindow *self = (TildaWindow *) instance;
136         self->dispose_has_run = FALSE;
137
138         /* Initialize all properties */
139         self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
140         self->notebook = gtk_notebook_new ();
141         self->terms = g_ptr_array_new ();
142
143         /* Somewhat of a "poison" value, incase we don't set this */
144         self->number = 0xdeadbeef;
145 }
146
147 static void
148 tilda_window_set_property (GObject      *object,
149                                                    guint         property_id,
150                                                    const GValue *value,
151                                                    GParamSpec   *pspec)
152 {
153         TildaWindow *self = (TildaWindow *) object;
154
155         switch (property_id) {
156
157                 case TILDA_WINDOW_NUMBER:
158                         self->number = g_value_get_int (value);
159                         g_print ("window number: %d\n", self->number);
160                         break;
161
162                 default:
163                         /* We don't have this property */
164                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
165                         break;
166         }
167 }
168
169 static void
170 tilda_window_get_property (GObject    *object,
171                                                    guint       property_id,
172                                                    GValue     *value,
173                                                    GParamSpec *pspec)
174 {
175         TildaWindow *self = (TildaWindow *) object;
176
177         switch (property_id) {
178
179                 case TILDA_WINDOW_NUMBER:
180                         g_value_set_int (value, self->number);
181                         break;
182
183                 default:
184                         /* We don't have this property */
185                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
186                         break;
187         }
188 }
189
190 static GObject *
191 tilda_window_constructor (GType                  type,
192                                                   guint                  n_construct_properties,
193                                                   GObjectConstructParam *construct_properties)
194 {
195         GObject *obj;
196         TildaWindow *self;
197
198         /* Invoke parent constructor */
199         TildaWindowClass *klass;
200         klass = TILDA_WINDOW_CLASS (g_type_class_peek (TILDA_TYPE_WINDOW));
201         obj = parent_class->constructor (type,
202                                                                          n_construct_properties,
203                                                                          construct_properties);
204
205         /* Do other stuff here. The object is ready to go now, and all
206          * ctor properties have been set.
207          *
208          * TODO: This is the place to do DBus-init */
209         self = TILDA_WINDOW(obj);
210
211         /* Register this object with DBus */
212         tilda_window_dbus_register_object (self);
213
214         gtk_container_add (GTK_CONTAINER(self->window), self->notebook);
215         gtk_widget_show (self->notebook);
216
217         tilda_window_add_term (self);
218         tilda_window_add_term (self);
219         gtk_widget_show_all (self->window);
220
221         return obj;
222 }
223
224 static void
225 my_unref (gpointer data, gpointer user_data)
226 {
227         g_object_unref (G_OBJECT(data));
228 }
229
230 static void
231 tilda_window_dispose (GObject *obj)
232 {
233         TildaWindow *self = (TildaWindow *) obj;
234
235         /* We don't want to run dispose twice, so just return immediately */
236         if (self->dispose_has_run)
237                 return;
238
239         /*
240          * In dispose, you are supposed to free all types referenced from this
241          * object which might themselves hold a reference to self. Generally,
242          * the most simple solution is to unref all members on which you own a
243          * reference.
244          *
245          * NOTE: See the following for how to deal with GtkObject-derived things:
246          * http://library.gnome.org/devel/gtk/unstable/GtkObject.html
247          */
248         g_ptr_array_foreach (self->terms, my_unref, NULL);
249         gtk_widget_destroy (self->window);
250
251         /* Chain up to the parent class */
252         G_OBJECT_CLASS (parent_class)->dispose (obj);
253 }
254
255 static void
256 tilda_window_finalize (GObject *obj)
257 {
258         TildaWindow *self = (TildaWindow *) obj;
259
260         /*
261          * Here, complete the object's destruction.
262          * You might not need to do much...
263          */
264         // TODO: g_free() any primitives here
265         g_ptr_array_free (self->terms, TRUE);
266
267
268         /* Chain up to the parent class */
269         G_OBJECT_CLASS (parent_class)->finalize (obj);
270 }
271
272 static void
273 tilda_window_class_init (gpointer g_class,
274                                                  gpointer g_class_data)
275 {
276         GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
277         TildaWindowClass *klass = TILDA_WINDOW_CLASS (g_class);
278         GParamSpec *pspec;
279
280         /* Hook our functions to this type */
281         gobject_class->set_property = tilda_window_set_property;
282         gobject_class->get_property = tilda_window_get_property;
283         gobject_class->dispose = tilda_window_dispose;
284         gobject_class->finalize = tilda_window_finalize;
285         gobject_class->constructor = tilda_window_constructor;
286
287         parent_class = g_type_class_peek_parent (klass);
288
289         /* Install all of the properties */
290         pspec = g_param_spec_int ("number",
291                                                           "Window number",
292                                                           "Set window's number",
293                                                           0,            // min value
294                                                           INT_MAX,      // max value
295                                                           0,            // def value
296                                                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
297
298         g_object_class_install_property (gobject_class,
299                                                                          TILDA_WINDOW_NUMBER,
300                                                                          pspec);
301
302         /* TODO: more properties */
303
304         /* Hook the TildaWindow type into DBus */
305         dbus_g_object_type_install_info (tilda_window_get_type(), &dbus_glib_tilda_window_object_info);
306 }
307
308 GType
309 tilda_window_get_type (void)
310 {
311         static GType type = 0;
312
313         if (type == 0)
314         {
315                 static const GTypeInfo info = {
316                         sizeof (TildaWindowClass),
317                         NULL,   /* base_init */
318                         NULL,   /* base_finalize */
319                         tilda_window_class_init,        /* class_init */
320                         NULL,   /* class_finalize */
321                         NULL,   /* class_data */
322                         sizeof (TildaWindow),
323                         0,              /* n_preallocs */
324                         tilda_window_instance_init,     /* instance_init */
325                 };
326
327                 type = g_type_register_static (G_TYPE_OBJECT,
328                                                                            "TildaWindowType",
329                                                                            &info,
330                                                                            0);
331         }
332
333         return type;
334 }
335
336 #if 0
337
338 int main (int argc, char *argv[])
339 {
340         GObject *tw;
341         gint test_number = INT_MIN;
342
343         /* Initialize the GObject type system */
344         g_type_init ();
345         gtk_init (&argc, &argv);
346
347         tw = g_object_new (TILDA_TYPE_WINDOW, "number", 10, NULL);
348         g_object_get (G_OBJECT (tw), "number", &test_number, NULL);
349         g_assert (test_number == 10);
350
351         g_object_unref (G_OBJECT (tw));
352
353         tw = g_object_new (TILDA_TYPE_WINDOW, "number", 22, NULL);
354         g_object_get (G_OBJECT (tw), "number", &test_number, NULL);
355         g_assert (test_number == 22);
356
357         gtk_main ();
358
359         g_object_unref (G_OBJECT (tw));
360
361         return 0;
362 }
363
364 #endif
365
366 /* vim: set ts=4 sts=4 sw=4 noet tw=112: */