[Window] Add always-show-tabs property
[tilda-gobject.git] / tilda-window.c
1 #include <gdk/gdkx.h> /* for gdk_x11_window_set_user_time() */
2 #include <stdlib.h>
3
4 #include "tilda.h"
5 #include "tilda-config.h"
6 #include "tilda-controller.h"
7 #include "tilda-window.h"
8 #include "tilda-window-dbus-glue.h"
9 #include "tomboykeybinder.h"
10
11 /**
12  * Find the TildaTerminal corresponding to the currently selected
13  * tab in self->notebook. This could go away if TildaTerminal were
14  * a proper subclass of GtkWidget.
15  */
16 static TildaTerminal *
17 tilda_window_find_current_terminal (TildaWindow *self)
18 {
19         debug_enter();
20         debug_assert (TILDA_IS_WINDOW(self));
21
22         gint i;
23         TildaTerminal *ret;
24         gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(self->notebook));
25         GtkWidget *box = gtk_notebook_get_nth_page (GTK_NOTEBOOK(self->notebook), current_page);
26
27         for (i=0; i<self->terms->len; ++i)
28         {
29                 ret = g_ptr_array_index (self->terms, i);
30
31                 if (ret->hbox == box)
32                         return ret;
33         }
34
35         debug_printf ("ERROR: unable to find current terminal!\n");
36         return NULL;
37 }
38
39 static gint
40 tilda_window_find_next_free_terminal_number (TildaWindow *self)
41 {
42         debug_enter ();
43         debug_assert (TILDA_IS_WINDOW(self));
44
45         gint i, j;
46         gboolean found;
47
48         for (i=0; i<INT_MAX; ++i)
49         {
50                 found = FALSE;
51
52                 for (j=0; j<self->terms->len; ++j)
53                 {
54                         TildaTerminal *tt = g_ptr_array_index (self->terms, j);
55
56                         if (tt->number == i)
57                         {
58                                 found = TRUE;
59                                 break;
60                         }
61                 }
62
63                 if (!found)
64                         return i;
65         }
66
67         return 0;
68 }
69
70 /**
71  * Clean up and remove self completely from the program
72  *
73  * Should only be used by DBus...
74  */
75 gboolean
76 tilda_window_close (TildaWindow *self)
77 {
78         debug_enter  ();
79         debug_assert (TILDA_IS_WINDOW(self));
80
81         tilda_controller_remove_window (TILDA_CONTROLLER(self->controller), self->number);
82
83         return TRUE;
84 }
85
86 gboolean
87 tilda_window_add_terminal (TildaWindow *self)
88 {
89         debug_enter ();
90         debug_assert (TILDA_IS_WINDOW(self));
91
92         gint number;
93         TildaTerminal *tt;
94         GtkWidget *label;
95         gint notebook_index;
96
97         number = tilda_window_find_next_free_terminal_number (self);
98         tt = g_object_new (TILDA_TYPE_TERMINAL,
99                                            "number", number,
100                                            "parent-window", self,
101                                            NULL);
102         g_ptr_array_add (self->terms, tt);
103
104         label = gtk_label_new ("Tilda");
105         notebook_index = gtk_notebook_prepend_page (GTK_NOTEBOOK(self->notebook), tt->hbox, label);
106         gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK(self->notebook), tt->hbox,
107                                                                                 self->full_width_tabs, TRUE, GTK_PACK_START);
108         gtk_notebook_set_current_page (GTK_NOTEBOOK(self->notebook), notebook_index);
109
110         /* Always show tabs if we have > 1 tab open */
111         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK(self->notebook)) > 1)
112                 gtk_notebook_set_show_tabs (GTK_NOTEBOOK(self->notebook), TRUE);
113
114         /* Focus the VTE Terminal */
115         gtk_widget_grab_focus (tt->vte_term);
116
117         return TRUE;
118 }
119
120 /**
121  * Remove the TildaTerminal with the given number from the given
122  * TildaWindow.
123  *
124  * Return: TRUE on success, FALSE otherwise.
125  */
126 gboolean
127 tilda_window_remove_terminal (TildaWindow *self, gint terminal_number)
128 {
129         debug_enter  ();
130         debug_assert (TILDA_IS_WINDOW(self));
131         debug_assert (terminal_number >= 0);
132
133         gint i;
134
135         for (i=0; i<self->terms->len; ++i)
136         {
137                 TildaTerminal *tt = g_ptr_array_index (self->terms, i);
138
139                 if (tt->number == terminal_number)
140                 {
141                         gint notebook_index = gtk_notebook_page_num (GTK_NOTEBOOK(self->notebook), tt->hbox);
142
143                         /* Make sure the index was valid */
144                         if (notebook_index == -1)
145                         {
146                                 debug_printf ("ERROR: Bad Notebook Tab\n");
147                                 return FALSE;
148                         }
149
150                         /* Actually remove the terminal */
151                         gtk_notebook_remove_page (GTK_NOTEBOOK (self->notebook), notebook_index);
152
153                         /* We should hide the tabs if there is only one tab left */
154                         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->notebook)) <= 1)
155                         {
156                                 if (!self->always_show_tabs)
157                                         gtk_notebook_set_show_tabs (GTK_NOTEBOOK (self->notebook), FALSE);
158                         }
159
160                         /* Remove the term from our lists, then free it */
161                         g_ptr_array_remove_fast (self->terms, tt);
162                         g_object_unref (G_OBJECT(tt));
163
164                         /* With no pages left, it's time to remove this window */
165                         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->notebook)) < 1)
166                         {
167                                 debug_printf ("no terminals left, closing window %d\n", self->number);
168                                 tilda_controller_remove_window (TILDA_CONTROLLER(self->controller), self->number);
169                         }
170
171                         /* Leave the loop, we're done */
172                         break;
173                 }
174         }
175
176         return TRUE;
177 }
178
179 /**
180  * This sets up the given TildaWindow for the capability of real
181  * transparency, if the X server is capable of it. */
182 static void
183 tilda_window_setup_real_transparency (TildaWindow *self)
184 {
185         debug_enter  ();
186         debug_assert (TILDA_IS_WINDOW(self));
187
188         GdkScreen *screen;
189         GdkColormap *colormap;
190
191         screen = gtk_widget_get_screen (GTK_WIDGET(self->window));
192         colormap = gdk_screen_get_rgba_colormap (screen);
193
194         /* If possible, set the RGBA colormap so VTE can use real alpha
195          * channels for transparency. */
196         if (colormap != NULL && gdk_screen_is_composited (screen))
197         {
198                 gtk_widget_set_colormap (GTK_WIDGET(self->window), colormap);
199                 self->have_real_transparency = TRUE;
200                 return;
201         }
202
203         self->have_real_transparency = FALSE;
204 }
205
206 /* Center the given TildaWindow in the horizontal axis */
207 static void
208 tilda_window_center_horizontally (TildaWindow *self)
209 {
210         debug_enter  ();
211         debug_assert (TILDA_IS_WINDOW(self));
212
213         const gint screen_center = gdk_screen_width() / 2;
214         const gint tilda_center  = self->width / 2;
215         const gint center_coord  = screen_center - tilda_center;
216
217         g_object_set (G_OBJECT(self), "x-position", center_coord, NULL);
218 }
219
220 /* Center the given TildaWindow in the vertical axis */
221 static void
222 tilda_window_center_vertically (TildaWindow *self)
223 {
224         debug_enter  ();
225         debug_assert (TILDA_IS_WINDOW(self));
226
227         const gint screen_center = gdk_screen_height() / 2;
228         const gint tilda_center  = self->height / 2;
229         const gint center_coord  = screen_center - tilda_center;
230
231         g_object_set (G_OBJECT(self), "y-position", center_coord, NULL);
232 }
233
234 static void
235 tilda_window_keybinding_cb (const gchar *keystr, gpointer data)
236 {
237         debug_enter  ();
238         debug_assert (TILDA_IS_WINDOW(data));
239
240         TildaWindow *self = TILDA_WINDOW(data);
241         TildaTerminal *tt;
242
243         /* This call sets the X11 window property _NET_WM_USER_TIME, which GTK+ normally
244          * sets for us. However, because this callback is activated via a global keybinding,
245          * we see the event before GDK / GTK+ does. Therefore, to get the focus, we must
246          * set the property ourselves. */
247         gdk_x11_window_set_user_time (GTK_WIDGET(self->window)->window,
248                                                                   tomboy_keybinder_get_current_event_time());
249
250         switch (self->state)
251         {
252                 case WINDOW_UP: /* Pull the window up */
253
254                         /* Bugfix: having this here keeps the tilda window from being
255                          * hidden if you turn off "stick", pull it down on workspace 1,
256                          * switch to workspace 2, then pull it up and back down. Without
257                          * this, something in metacity (at least) hides the window. Stupid. */
258                         gtk_window_deiconify (GTK_WINDOW(self->window));
259
260                         /* Re-set the window properties that do not linger after hiding the
261                          * window. I know this looks stupid, but it keeps all of the state-
262                          * changing code in the place it belongs: the property-setting code. */
263                         g_object_set (G_OBJECT(self),
264                                         "keep-above", self->keep_above,
265                                         "stick", self->stick,
266                                         NULL);
267                         gtk_widget_show (GTK_WIDGET(self->window));
268
269                         /* Focusing the term here works perfectly, near as I can tell */
270                         tt = tilda_window_find_current_terminal (self);
271                         gtk_widget_grab_focus (GTK_WIDGET(tt->vte_term));
272
273                         self->state = WINDOW_DOWN;
274                         break;
275
276                 case WINDOW_DOWN: /* Pull the window up */
277
278                         gtk_widget_hide (GTK_WIDGET(self->window));
279
280                         self->state = WINDOW_UP;
281                         break;
282
283                 default:
284                         debug_printf ("ERROR: Window is in a bad state!\n");
285
286                         /* Pretend we're down, for good measure.... */
287                         self->state = WINDOW_DOWN;
288                         break;
289         }
290 }
291
292 /**
293  * Attempt to bind the new_key to show this window.
294  *
295  * Return: TRUE if successful, FALSE otherwise.
296  */
297 static gboolean
298 tilda_window_try_to_bind_key (TildaWindow *self, const gchar *new_key)
299 {
300         debug_enter  ();
301         debug_assert (TILDA_IS_WINDOW(self));
302
303         gboolean ret = FALSE;
304
305         /* Make sure the new key is not null in any way */
306         if (new_key == NULL || g_ascii_strcasecmp("", new_key) == 0)
307                 return FALSE;
308
309         /* Check that no other windows are using the key */
310         // FIXME: there should be a hidden option to disable this. Maybe some people want
311         // to have logs in two Tildas, and just show them with one key. Crazy...
312         if (tilda_controller_global_key_in_use(TILDA_CONTROLLER(self->controller), new_key))
313                 return FALSE;
314
315         /* Unbind if we were set */
316         if (self->key)
317                 tomboy_keybinder_unbind (self->key, tilda_window_keybinding_cb);
318
319         ret = tomboy_keybinder_bind (new_key, tilda_window_keybinding_cb, self);
320
321         /* If it was successful, update the self->key variable and be done with it */
322         if (ret)
323         {
324                 g_free (self->key);
325                 self->key = g_strdup (new_key);
326                 return TRUE;
327         }
328
329         g_printerr (_("Bind key '%s' failed. Reverting to original keybinding\n"), self->key);
330
331         /* Not successful, so rebind the old key, and return FALSE */
332         if (self->key != NULL && g_ascii_strcasecmp("",self->key) != 0)
333         {
334                 ret = tomboy_keybinder_bind (self->key, tilda_window_keybinding_cb, self);
335
336                 /* Check that it went ok */
337                 if (!ret)
338                         g_printerr (_("Unable to re-bind original key '%s'. Oh shit...\n"), self->key);
339         }
340         else
341                 g_printerr (_("No original key to revert to!\n"));
342
343         return FALSE;
344 }
345
346 static void
347 tilda_window_dbus_register_object (TildaWindow *self)
348 {
349         debug_enter  ();
350         debug_assert (TILDA_IS_WINDOW(self));
351
352         gchar *object_path;
353
354         /* If DBus is not running, leave */
355         if (!dbus_connection)
356                 return;
357
358         /* Register this object with DBus */
359         object_path = g_strdup_printf ("/net/sourceforge/Tilda/Window%d", self->number);
360         dbus_g_connection_register_g_object (dbus_connection, object_path, G_OBJECT(self));
361         g_free (object_path);
362 }
363
364 /*******************************************************************************
365  * All accelerator-related stuff below
366  ******************************************************************************/
367
368 typedef gboolean (*TildaWindowAccelCallback) (TildaWindow *self, gpointer data);
369
370 /**
371  * This function updates the accelerator used to call the given function for this
372  * TildaWindow. If accel is NULL, then func will be removed (no accelerator will
373  * cause func to be called).
374  *
375  * Returns: TRUE on success, FALSE on failure
376  */
377 static gboolean
378 tilda_window_update_accelerator (TildaWindow *self,                             /* object */
379                                                                  gchar **accel_to_update,               /* self->??? */
380                                                                  const gchar *accel,                    /* new accel */
381                                                                  const TildaWindowAccelCallback func)
382 {
383         debug_enter  ();
384         debug_assert (TILDA_IS_WINDOW(self));
385         debug_assert (accel_to_update != NULL);
386         debug_assert (func != NULL);
387
388         gboolean ret;
389         guint key;
390         GdkModifierType mod;
391         GClosure *closure;
392
393         /* Remove the old accelerator if there was a previous one set */
394         if (*accel_to_update != NULL)
395         {
396                 /* This should always parse, we've done it before! */
397                 gtk_accelerator_parse (*accel_to_update, &key, &mod);
398                 ret = gtk_accel_group_disconnect_key (self->accel_group, key, mod);
399         }
400
401         /* If we are just removing the old accelerator, we're already done */
402         if (accel == NULL)
403         {
404                 g_free (*accel_to_update);
405                 *accel_to_update = NULL;
406                 return TRUE;
407         }
408
409         /* Create the closure for this function */
410         closure = g_cclosure_new_swap (G_CALLBACK(func), self, NULL);
411
412         /* Try to parse the new accelerator */
413         gtk_accelerator_parse (accel, &key, &mod);
414
415         if (!gtk_accelerator_valid (key, mod))
416         {
417                 g_warning (_("Failed to parse accelerator: %s\n"), accel);
418
419                 /* Re-install the old accelerator */
420                 if (*accel_to_update != NULL)
421                 {
422                         gtk_accelerator_parse (*accel_to_update, &key, &mod);
423                         gtk_accel_group_connect (self->accel_group, key, mod, GTK_ACCEL_VISIBLE, closure);
424                 }
425                 return FALSE;
426         }
427
428         /* All good, g_free() the old accelerator, g_strdup() the new one */
429         g_free (*accel_to_update);
430         *accel_to_update = g_strdup(accel);
431
432         /* Add the new accelerator */
433         gtk_accel_group_connect (self->accel_group, key, mod, GTK_ACCEL_VISIBLE, closure);
434
435         return TRUE;
436 }
437
438 static gboolean
439 tilda_window_accel_quit_cb (TildaWindow *self, gpointer data)
440 {
441         debug_enter  ();
442         debug_assert (TILDA_IS_WINDOW(self));
443
444         tilda_window_close (self);
445
446         /* Do not keep propagating */
447         return TRUE;
448 }
449
450 static gboolean
451 tilda_window_accel_next_tab_cb (TildaWindow *self, gpointer data)
452 {
453         debug_enter  ();
454         debug_assert (TILDA_IS_WINDOW(self));
455
456         gint num_pages;
457         gint current_page;
458
459         num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK(self->notebook));
460         current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(self->notebook));
461
462         /* Go to next page (with wrapping) */
463         if (num_pages != (current_page + num_pages))
464                 gtk_notebook_next_page (GTK_NOTEBOOK(self->notebook));
465         else
466                 gtk_notebook_set_current_page (GTK_NOTEBOOK(self->notebook), num_pages-1);
467
468         /* Do not keep propagating */
469         return TRUE;
470 }
471
472 static gboolean
473 tilda_window_accel_prev_tab_cb (TildaWindow *self, gpointer data)
474 {
475         debug_enter  ();
476         debug_assert (TILDA_IS_WINDOW(self));
477
478         gint num_pages;
479         gint current_page;
480
481         num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK(self->notebook));
482         current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(self->notebook));
483
484         if ((num_pages-1) != current_page)
485                 gtk_notebook_prev_page (GTK_NOTEBOOK(self->notebook));
486         else
487                 gtk_notebook_set_current_page (GTK_NOTEBOOK(self->notebook), 0);
488
489         /* Do not keep propagating */
490         return TRUE;
491 }
492
493 static gboolean
494 tilda_window_accel_add_term_cb (TildaWindow *self, gpointer data)
495 {
496         debug_enter  ();
497         debug_assert (TILDA_IS_WINDOW(self));
498
499         tilda_window_add_terminal (self);
500
501         /* Do not keep propagating */
502         return TRUE;
503 }
504
505 static gboolean
506 tilda_window_accel_remove_term_cb (TildaWindow *self, gpointer data)
507 {
508         debug_enter  ();
509         debug_assert (TILDA_IS_WINDOW(self));
510
511         TildaTerminal *tt = tilda_window_find_current_terminal (self);
512
513         tilda_window_remove_terminal (self, tt->number);
514
515         /* Do not keep propagating */
516         return TRUE;
517 }
518
519 static gboolean
520 tilda_window_accel_copy_cb (TildaWindow *self, gpointer data)
521 {
522         debug_enter  ();
523         debug_assert (TILDA_IS_WINDOW(self));
524
525         TildaTerminal *tt = tilda_window_find_current_terminal (self);
526
527         vte_terminal_copy_clipboard (VTE_TERMINAL(tt->vte_term));
528
529         /* Do not keep propagating */
530         return TRUE;
531 }
532
533 static gboolean
534 tilda_window_accel_paste_cb (TildaWindow *self, gpointer data)
535 {
536         debug_enter  ();
537         debug_assert (TILDA_IS_WINDOW(self));
538
539         TildaTerminal *tt = tilda_window_find_current_terminal (self);
540
541         vte_terminal_paste_clipboard (VTE_TERMINAL(tt->vte_term));
542
543         /* Do not keep propagating */
544         return TRUE;
545 }
546
547 static gboolean
548 tilda_window_accel_goto_generic (TildaWindow *self, guint number)
549 {
550         debug_enter  ();
551         debug_assert (TILDA_IS_WINDOW(self));
552
553         gtk_notebook_set_current_page (GTK_NOTEBOOK(self->notebook), number-1);
554
555         /* Do not keep propagating */
556         return TRUE;
557 }
558
559 static gboolean
560 tilda_window_accel_goto_1_cb (TildaWindow *self, gpointer data)
561 {
562         debug_enter  ();
563         debug_assert (TILDA_IS_WINDOW(self));
564
565         return tilda_window_accel_goto_generic (self, 1);
566 }
567
568 static gboolean
569 tilda_window_accel_goto_2_cb (TildaWindow *self, gpointer data)
570 {
571         debug_enter  ();
572         debug_assert (TILDA_IS_WINDOW(self));
573
574         return tilda_window_accel_goto_generic (self, 2);
575 }
576
577 static gboolean
578 tilda_window_accel_goto_3_cb (TildaWindow *self, gpointer data)
579 {
580         debug_enter  ();
581         debug_assert (TILDA_IS_WINDOW(self));
582
583         return tilda_window_accel_goto_generic (self, 3);
584 }
585
586 static gboolean
587 tilda_window_accel_goto_4_cb (TildaWindow *self, gpointer data)
588 {
589         debug_enter  ();
590         debug_assert (TILDA_IS_WINDOW(self));
591
592         return tilda_window_accel_goto_generic (self, 4);
593 }
594
595 static gboolean
596 tilda_window_accel_goto_5_cb (TildaWindow *self, gpointer data)
597 {
598         debug_enter  ();
599         debug_assert (TILDA_IS_WINDOW(self));
600
601         return tilda_window_accel_goto_generic (self, 5);
602 }
603
604 static gboolean
605 tilda_window_accel_goto_6_cb (TildaWindow *self, gpointer data)
606 {
607         debug_enter  ();
608         debug_assert (TILDA_IS_WINDOW(self));
609
610         return tilda_window_accel_goto_generic (self, 6);
611 }
612
613 static gboolean
614 tilda_window_accel_goto_7_cb (TildaWindow *self, gpointer data)
615 {
616         debug_enter  ();
617         debug_assert (TILDA_IS_WINDOW(self));
618
619         return tilda_window_accel_goto_generic (self, 7);
620 }
621
622 static gboolean
623 tilda_window_accel_goto_8_cb (TildaWindow *self, gpointer data)
624 {
625         debug_enter  ();
626         debug_assert (TILDA_IS_WINDOW(self));
627
628         return tilda_window_accel_goto_generic (self, 8);
629 }
630
631 static gboolean
632 tilda_window_accel_goto_9_cb (TildaWindow *self, gpointer data)
633 {
634         debug_enter  ();
635         debug_assert (TILDA_IS_WINDOW(self));
636
637         return tilda_window_accel_goto_generic (self, 9);
638 }
639
640 static gboolean
641 tilda_window_accel_goto_10_cb (TildaWindow *self, gpointer data)
642 {
643         debug_enter  ();
644         debug_assert (TILDA_IS_WINDOW(self));
645
646         return tilda_window_accel_goto_generic (self, 10);
647 }
648
649 /*******************************************************************************
650  * ALL GOBJECT STUFF BELOW PLEASE
651  ******************************************************************************/
652
653 static GObjectClass *parent_class = NULL;
654
655 enum tilda_window_properties {
656         TILDA_WINDOW_NUMBER = 1,
657         TILDA_WINDOW_CONTROLLER,
658
659         TILDA_WINDOW_ACCEL_QUIT,
660         TILDA_WINDOW_ACCEL_NEXT_TAB,
661         TILDA_WINDOW_ACCEL_PREV_TAB,
662         TILDA_WINDOW_ACCEL_ADD_TERM,
663         TILDA_WINDOW_ACCEL_REMOVE_TERM,
664         TILDA_WINDOW_ACCEL_COPY,
665         TILDA_WINDOW_ACCEL_PASTE,
666         TILDA_WINDOW_ACCEL_GOTO_1,
667         TILDA_WINDOW_ACCEL_GOTO_2,
668         TILDA_WINDOW_ACCEL_GOTO_3,
669         TILDA_WINDOW_ACCEL_GOTO_4,
670         TILDA_WINDOW_ACCEL_GOTO_5,
671         TILDA_WINDOW_ACCEL_GOTO_6,
672         TILDA_WINDOW_ACCEL_GOTO_7,
673         TILDA_WINDOW_ACCEL_GOTO_8,
674         TILDA_WINDOW_ACCEL_GOTO_9,
675         TILDA_WINDOW_ACCEL_GOTO_10,
676
677         TILDA_WINDOW_KEY,
678
679         TILDA_WINDOW_HEIGHT,
680         TILDA_WINDOW_WIDTH,
681         TILDA_WINDOW_X_POSITION,
682         TILDA_WINDOW_Y_POSITION,
683         TILDA_WINDOW_INITIAL_TERMINALS,
684
685         TILDA_WINDOW_TAB_POSITION,
686         TILDA_WINDOW_ANIMATION_ORIENTATION,
687         TILDA_WINDOW_ANIMATION_DELAY,
688
689         TILDA_WINDOW_KEEP_ABOVE,
690         TILDA_WINDOW_SKIP_TASKBAR_HINT,
691         TILDA_WINDOW_STICK,
692         TILDA_WINDOW_HIDDEN_AT_START,
693         TILDA_WINDOW_CENTERED_HORIZONTALLY,
694         TILDA_WINDOW_CENTERED_VERTICALLY,
695         TILDA_WINDOW_FULL_WIDTH_TABS,
696         TILDA_WINDOW_ALWAYS_SHOW_TABS,
697
698         TILDA_WINDOW_HAVE_REAL_TRANSPARENCY,
699 };
700
701 static void
702 tilda_window_instance_init (GTypeInstance *instance,
703                                                         gpointer       g_class)
704 {
705         debug_enter ();
706
707         TildaWindow *self = (TildaWindow *) instance;
708         self->dispose_has_run = FALSE;
709
710         /* Initialize all properties */
711         self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
712         self->notebook = gtk_notebook_new ();
713         self->terms = g_ptr_array_new ();
714
715         /* Accelerators */
716         self->accel_group = gtk_accel_group_new ();
717         gtk_window_add_accel_group (GTK_WINDOW(self->window), self->accel_group);
718
719         /* Somewhat of a "poison" value, incase we don't set this */
720         self->number = 0xdeadbeef;
721         self->controller = NULL;
722
723         self->state = WINDOW_UP;
724 }
725
726 static void
727 tilda_window_set_property (GObject      *object,
728                                                    guint         property_id,
729                                                    const GValue *value,
730                                                    GParamSpec   *pspec)
731 {
732         TildaWindow *self = (TildaWindow *) object;
733         gint i;
734
735         switch (property_id) {
736
737                 case TILDA_WINDOW_NUMBER:
738                         self->number = g_value_get_int (value);
739                         debug_printf ("window number: %d\n", self->number);
740                         break;
741
742                 case TILDA_WINDOW_CONTROLLER:
743                         self->controller = g_value_get_pointer (value);
744                         debug_printf ("window controller: 0x%p\n", self->controller);
745                         break;
746
747                 case TILDA_WINDOW_ACCEL_QUIT:
748                         tilda_window_update_accelerator (self,
749                                                                                          &self->accel_quit,
750                                                                                          g_value_get_string (value),
751                                                                                          tilda_window_accel_quit_cb);
752                         debug_printf ("window accel quit: %s\n", self->accel_quit);
753                         break;
754
755                 case TILDA_WINDOW_ACCEL_NEXT_TAB:
756                         tilda_window_update_accelerator (self,
757                                                                                          &self->accel_next_tab,
758                                                                                          g_value_get_string (value),
759                                                                                          tilda_window_accel_next_tab_cb);
760                         debug_printf ("window accel next tab: %s\n", self->accel_next_tab);
761                         break;
762
763                 case TILDA_WINDOW_ACCEL_PREV_TAB:
764                         tilda_window_update_accelerator (self,
765                                                                                          &self->accel_prev_tab,
766                                                                                          g_value_get_string (value),
767                                                                                          tilda_window_accel_prev_tab_cb);
768                         debug_printf ("window accel prev tab: %s\n", self->accel_prev_tab);
769                         break;
770
771                 case TILDA_WINDOW_ACCEL_ADD_TERM:
772                         tilda_window_update_accelerator (self,
773                                                                                          &self->accel_add_term,
774                                                                                          g_value_get_string (value),
775                                                                                          tilda_window_accel_add_term_cb);
776                         debug_printf ("window accel add term: %s\n", self->accel_add_term);
777                         break;
778
779                 case TILDA_WINDOW_ACCEL_REMOVE_TERM:
780                         tilda_window_update_accelerator (self,
781                                                                                          &self->accel_remove_term,
782                                                                                          g_value_get_string (value),
783                                                                                          tilda_window_accel_remove_term_cb);
784                         debug_printf ("window accel remove term: %s\n", self->accel_remove_term);
785                         break;
786
787                 case TILDA_WINDOW_ACCEL_COPY:
788                         tilda_window_update_accelerator (self,
789                                                                                          &self->accel_copy,
790                                                                                          g_value_get_string (value),
791                                                                                          tilda_window_accel_copy_cb);
792                         debug_printf ("window accel copy: %s\n", self->accel_copy);
793                         break;
794
795                 case TILDA_WINDOW_ACCEL_PASTE:
796                         tilda_window_update_accelerator (self,
797                                                                                          &self->accel_paste,
798                                                                                          g_value_get_string (value),
799                                                                                          tilda_window_accel_paste_cb);
800                         debug_printf ("window accel paste: %s\n", self->accel_paste);
801                         break;
802
803                 case TILDA_WINDOW_ACCEL_GOTO_1:
804                         tilda_window_update_accelerator (self,
805                                                                                          &self->accel_goto_1,
806                                                                                          g_value_get_string (value),
807                                                                                          tilda_window_accel_goto_1_cb);
808                         debug_printf ("window accel goto 1: %s\n", self->accel_goto_1);
809                         break;
810
811                 case TILDA_WINDOW_ACCEL_GOTO_2:
812                         tilda_window_update_accelerator (self,
813                                                                                          &self->accel_goto_2,
814                                                                                          g_value_get_string (value),
815                                                                                          tilda_window_accel_goto_2_cb);
816                         debug_printf ("window accel goto 2: %s\n", self->accel_goto_2);
817                         break;
818
819                 case TILDA_WINDOW_ACCEL_GOTO_3:
820                         tilda_window_update_accelerator (self,
821                                                                                          &self->accel_goto_3,
822                                                                                          g_value_get_string (value),
823                                                                                          tilda_window_accel_goto_3_cb);
824                         debug_printf ("window accel goto 3: %s\n", self->accel_goto_3);
825                         break;
826
827                 case TILDA_WINDOW_ACCEL_GOTO_4:
828                         tilda_window_update_accelerator (self,
829                                                                                          &self->accel_goto_4,
830                                                                                          g_value_get_string (value),
831                                                                                          tilda_window_accel_goto_4_cb);
832                         debug_printf ("window accel goto 4: %s\n", self->accel_goto_4);
833                         break;
834
835                 case TILDA_WINDOW_ACCEL_GOTO_5:
836                         tilda_window_update_accelerator (self,
837                                                                                          &self->accel_goto_5,
838                                                                                          g_value_get_string (value),
839                                                                                          tilda_window_accel_goto_5_cb);
840                         debug_printf ("window accel goto 5: %s\n", self->accel_goto_5);
841                         break;
842
843                 case TILDA_WINDOW_ACCEL_GOTO_6:
844                         tilda_window_update_accelerator (self,
845                                                                                          &self->accel_goto_6,
846                                                                                          g_value_get_string (value),
847                                                                                          tilda_window_accel_goto_6_cb);
848                         debug_printf ("window accel goto 6: %s\n", self->accel_goto_6);
849                         break;
850
851                 case TILDA_WINDOW_ACCEL_GOTO_7:
852                         tilda_window_update_accelerator (self,
853                                                                                          &self->accel_goto_7,
854                                                                                          g_value_get_string (value),
855                                                                                          tilda_window_accel_goto_7_cb);
856                         debug_printf ("window accel goto 7: %s\n", self->accel_goto_7);
857                         break;
858
859                 case TILDA_WINDOW_ACCEL_GOTO_8:
860                         tilda_window_update_accelerator (self,
861                                                                                          &self->accel_goto_8,
862                                                                                          g_value_get_string (value),
863                                                                                          tilda_window_accel_goto_8_cb);
864                         debug_printf ("window accel goto 8: %s\n", self->accel_goto_8);
865                         break;
866
867                 case TILDA_WINDOW_ACCEL_GOTO_9:
868                         tilda_window_update_accelerator (self,
869                                                                                          &self->accel_goto_9,
870                                                                                          g_value_get_string (value),
871                                                                                          tilda_window_accel_goto_9_cb);
872                         debug_printf ("window accel goto 9: %s\n", self->accel_goto_9);
873                         break;
874
875                 case TILDA_WINDOW_ACCEL_GOTO_10:
876                         tilda_window_update_accelerator (self,
877                                                                                          &self->accel_goto_10,
878                                                                                          g_value_get_string (value),
879                                                                                          tilda_window_accel_goto_10_cb);
880                         debug_printf ("window accel goto 10: %s\n", self->accel_goto_10);
881                         break;
882
883                 case TILDA_WINDOW_KEY:
884                         tilda_window_try_to_bind_key (self, g_value_get_string (value));
885                         debug_printf ("window key %s\n", self->key);
886                         break;
887
888                 case TILDA_WINDOW_HEIGHT:
889                         self->height = g_value_get_int (value);
890                         gtk_widget_set_size_request (self->window, self->width, self->height);
891                         gtk_window_resize (GTK_WINDOW(self->window), self->width, self->height);
892                         debug_printf ("window height: %d\n", self->height);
893                         break;
894
895                 case TILDA_WINDOW_WIDTH:
896                         self->width = g_value_get_int (value);
897                         gtk_widget_set_size_request (self->window, self->width, self->height);
898                         gtk_window_resize (GTK_WINDOW(self->window), self->width, self->height);
899                         debug_printf ("window width: %d\n", self->width);
900                         break;
901
902                 case TILDA_WINDOW_X_POSITION:
903                         self->x_position = g_value_get_int (value);
904                         gtk_window_move (GTK_WINDOW(self->window), self->x_position, self->y_position);
905                         debug_printf ("window x position: %d\n", self->x_position);
906                         break;
907
908                 case TILDA_WINDOW_Y_POSITION:
909                         self->y_position = g_value_get_int (value);
910                         gtk_window_move (GTK_WINDOW(self->window), self->x_position, self->y_position);
911                         debug_printf ("window y position: %d\n", self->y_position);
912                         break;
913
914                 case TILDA_WINDOW_INITIAL_TERMINALS:
915                         self->initial_terminals = g_value_get_int (value);
916                         debug_printf ("window initial terminals: %d\n", self->initial_terminals);
917                         break;
918
919                 case TILDA_WINDOW_TAB_POSITION:
920                         self->tab_position = g_value_get_enum (value);
921                         gtk_notebook_set_tab_pos (GTK_NOTEBOOK(self->notebook), self->tab_position);
922                         debug_printf ("window tab position: %d\n", self->tab_position);
923                         break;
924
925                 case TILDA_WINDOW_ANIMATION_ORIENTATION:
926                         self->animation_orientation = g_value_get_enum (value);
927                         debug_printf ("window animation orientation: %d\n", self->animation_orientation);
928                         break;
929
930                 case TILDA_WINDOW_ANIMATION_DELAY:
931                         self->animation_delay = g_value_get_int (value);
932                         debug_printf ("window animation delay: %d\n", self->animation_delay);
933                         break;
934
935                 case TILDA_WINDOW_KEEP_ABOVE:
936                         self->keep_above = g_value_get_boolean (value);
937                         gtk_window_set_keep_above (GTK_WINDOW(self->window), self->keep_above);
938                         debug_printf ("window keep above: %d\n", self->keep_above);
939                         break;
940
941                 case TILDA_WINDOW_SKIP_TASKBAR_HINT:
942                         self->skip_taskbar_hint = g_value_get_boolean (value);
943                         gtk_window_set_skip_taskbar_hint (GTK_WINDOW(self->window), self->skip_taskbar_hint);
944                         debug_printf ("window skip taskbar hint: %d\n", self->skip_taskbar_hint);
945                         break;
946
947                 case TILDA_WINDOW_STICK:
948                         self->stick = g_value_get_boolean (value);
949
950                         /* This is moderately ugly, but GTK+ does it this way... */
951                         self->stick ? gtk_window_stick (GTK_WINDOW(self->window))
952                                                 : gtk_window_unstick (GTK_WINDOW(self->window));
953                         debug_printf ("window stick: %d\n", self->stick);
954                         break;
955
956                 case TILDA_WINDOW_HIDDEN_AT_START:
957                         self->hidden_at_start = g_value_get_boolean (value);
958                         debug_printf ("window hidden at start: %d\n", self->hidden_at_start);
959                         break;
960
961                 case TILDA_WINDOW_CENTERED_HORIZONTALLY:
962                         self->centered_horizontally = g_value_get_boolean (value);
963                         if (self->centered_horizontally)
964                                 tilda_window_center_horizontally (self);
965                         debug_printf ("window centered horizontally: %d\n", self->centered_horizontally);
966                         break;
967
968                 case TILDA_WINDOW_CENTERED_VERTICALLY:
969                         self->centered_vertically = g_value_get_boolean (value);
970                         if (self->centered_vertically)
971                                 tilda_window_center_vertically (self);
972                         debug_printf ("window centered vertically: %d\n", self->centered_vertically);
973                         break;
974
975                 case TILDA_WINDOW_FULL_WIDTH_TABS:
976                         self->full_width_tabs = g_value_get_boolean (value);
977                         for (i=0; i<self->terms->len; ++i)
978                                 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK(self->notebook),
979                                                                                                         TILDA_TERMINAL(g_ptr_array_index(self->terms, i))->hbox,
980                                                                                                         self->full_width_tabs,
981                                                                                                         TRUE,
982                                                                                                         GTK_PACK_START);
983                         debug_printf ("window full width tabs: %d\n", self->full_width_tabs);
984                         break;
985
986                 case TILDA_WINDOW_ALWAYS_SHOW_TABS:
987                         self->always_show_tabs = g_value_get_boolean (value);
988                         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK(self->notebook)) <= 1)
989                         {
990                                 if (self->always_show_tabs)
991                                         gtk_notebook_set_show_tabs (GTK_NOTEBOOK(self->notebook), TRUE);
992                                 else
993                                         gtk_notebook_set_show_tabs (GTK_NOTEBOOK(self->notebook), FALSE);
994                         }
995                         debug_printf ("window always show tabs: %d\n", self->always_show_tabs);
996                         break;
997
998                 case TILDA_WINDOW_HAVE_REAL_TRANSPARENCY:
999                         self->have_real_transparency = g_value_get_boolean (value);
1000                         debug_printf ("window have real transp: %d\n", self->have_real_transparency);
1001                         break;
1002
1003                 default:
1004                         /* We don't have this property */
1005                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1006                         break;
1007         }
1008 }
1009
1010 static void
1011 tilda_window_get_property (GObject    *object,
1012                                                    guint       property_id,
1013                                                    GValue     *value,
1014                                                    GParamSpec *pspec)
1015 {
1016         TildaWindow *self = (TildaWindow *) object;
1017
1018         switch (property_id) {
1019
1020                 case TILDA_WINDOW_NUMBER:
1021                         g_value_set_int (value, self->number);
1022                         break;
1023
1024                 case TILDA_WINDOW_CONTROLLER:
1025                         g_value_set_pointer (value, self->controller);
1026                         break;
1027
1028                 case TILDA_WINDOW_ACCEL_QUIT:
1029                         g_value_set_string (value, self->accel_quit);
1030                         break;
1031
1032                 case TILDA_WINDOW_ACCEL_NEXT_TAB:
1033                         g_value_set_string (value, self->accel_next_tab);
1034                         break;
1035
1036                 case TILDA_WINDOW_ACCEL_PREV_TAB:
1037                         g_value_set_string (value, self->accel_prev_tab);
1038                         break;
1039
1040                 case TILDA_WINDOW_ACCEL_ADD_TERM:
1041                         g_value_set_string (value, self->accel_prev_tab);
1042                         break;
1043
1044                 case TILDA_WINDOW_ACCEL_REMOVE_TERM:
1045                         g_value_set_string (value, self->accel_remove_term);
1046                         break;
1047
1048                 case TILDA_WINDOW_ACCEL_COPY:
1049                         g_value_set_string (value, self->accel_copy);
1050                         break;
1051
1052                 case TILDA_WINDOW_ACCEL_PASTE:
1053                         g_value_set_string (value, self->accel_paste);
1054                         break;
1055
1056                 case TILDA_WINDOW_ACCEL_GOTO_1:
1057                         g_value_set_string (value, self->accel_goto_1);
1058                         break;
1059
1060                 case TILDA_WINDOW_ACCEL_GOTO_2:
1061                         g_value_set_string (value, self->accel_goto_2);
1062                         break;
1063
1064                 case TILDA_WINDOW_ACCEL_GOTO_3:
1065                         g_value_set_string (value, self->accel_goto_3);
1066                         break;
1067
1068                 case TILDA_WINDOW_ACCEL_GOTO_4:
1069                         g_value_set_string (value, self->accel_goto_4);
1070                         break;
1071
1072                 case TILDA_WINDOW_ACCEL_GOTO_5:
1073                         g_value_set_string (value, self->accel_goto_5);
1074                         break;
1075
1076                 case TILDA_WINDOW_ACCEL_GOTO_6:
1077                         g_value_set_string (value, self->accel_goto_6);
1078                         break;
1079
1080                 case TILDA_WINDOW_ACCEL_GOTO_7:
1081                         g_value_set_string (value, self->accel_goto_7);
1082                         break;
1083
1084                 case TILDA_WINDOW_ACCEL_GOTO_8:
1085                         g_value_set_string (value, self->accel_goto_8);
1086                         break;
1087
1088                 case TILDA_WINDOW_ACCEL_GOTO_9:
1089                         g_value_set_string (value, self->accel_goto_9);
1090                         break;
1091
1092                 case TILDA_WINDOW_ACCEL_GOTO_10:
1093                         g_value_set_string (value, self->accel_goto_10);
1094                         break;
1095
1096                 case TILDA_WINDOW_KEY:
1097                         g_value_set_string (value, self->key);
1098                         break;
1099
1100                 case TILDA_WINDOW_HEIGHT:
1101                         g_value_set_int (value, self->height);
1102                         break;
1103
1104                 case TILDA_WINDOW_WIDTH:
1105                         g_value_set_int (value, self->width);
1106                         break;
1107
1108                 case TILDA_WINDOW_X_POSITION:
1109                         g_value_set_int (value, self->x_position);
1110                         break;
1111
1112                 case TILDA_WINDOW_Y_POSITION:
1113                         g_value_set_int (value, self->y_position);
1114                         break;
1115
1116                 case TILDA_WINDOW_INITIAL_TERMINALS:
1117                         g_value_set_int (value, self->initial_terminals);
1118                         break;
1119
1120                 case TILDA_WINDOW_TAB_POSITION:
1121                         g_value_set_enum (value, self->tab_position);
1122                         break;
1123
1124                 case TILDA_WINDOW_ANIMATION_ORIENTATION:
1125                         g_value_set_enum (value, self->animation_orientation);
1126                         break;
1127
1128                 case TILDA_WINDOW_ANIMATION_DELAY:
1129                         g_value_set_int (value, self->animation_delay);
1130                         break;
1131
1132                 case TILDA_WINDOW_KEEP_ABOVE:
1133                         g_value_set_boolean (value, self->keep_above);
1134                         break;
1135
1136                 case TILDA_WINDOW_SKIP_TASKBAR_HINT:
1137                         g_value_set_boolean (value, self->skip_taskbar_hint);
1138                         break;
1139
1140                 case TILDA_WINDOW_STICK:
1141                         g_value_set_boolean (value, self->stick);
1142                         break;
1143
1144                 case TILDA_WINDOW_HIDDEN_AT_START:
1145                         g_value_set_boolean (value, self->hidden_at_start);
1146                         break;
1147
1148                 case TILDA_WINDOW_CENTERED_HORIZONTALLY:
1149                         g_value_set_boolean (value, self->centered_horizontally);
1150                         break;
1151
1152                 case TILDA_WINDOW_CENTERED_VERTICALLY:
1153                         g_value_set_boolean (value, self->centered_vertically);
1154                         break;
1155
1156                 case TILDA_WINDOW_FULL_WIDTH_TABS:
1157                         g_value_set_boolean (value, self->full_width_tabs);
1158                         break;
1159
1160                 case TILDA_WINDOW_ALWAYS_SHOW_TABS:
1161                         g_value_set_boolean (value, self->always_show_tabs);
1162                         break;
1163
1164                 case TILDA_WINDOW_HAVE_REAL_TRANSPARENCY:
1165                         g_value_set_boolean (value, self->have_real_transparency);
1166                         break;
1167
1168                 default:
1169                         /* We don't have this property */
1170                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1171                         break;
1172         }
1173 }
1174
1175 static GObject *
1176 tilda_window_constructor (GType                  type,
1177                                                   guint                  n_construct_properties,
1178                                                   GObjectConstructParam *construct_properties)
1179 {
1180         debug_enter ();
1181
1182         GObject *obj;
1183         TildaWindow *self;
1184         gint i;
1185
1186         /* Invoke parent constructor */
1187         TildaWindowClass *klass;
1188         klass = TILDA_WINDOW_CLASS (g_type_class_peek (TILDA_TYPE_WINDOW));
1189         obj = parent_class->constructor (type,
1190                                                                          n_construct_properties,
1191                                                                          construct_properties);
1192
1193         /* Do other stuff here. The object is ready to go now, and all
1194          * ctor properties have been set.
1195          */
1196         self = TILDA_WINDOW(obj);
1197
1198         /* Try to set up real transparency */
1199         tilda_window_setup_real_transparency (self);
1200
1201         gtk_container_add (GTK_CONTAINER(self->window), self->notebook);
1202         g_object_set (G_OBJECT(self->notebook), "can-focus", FALSE, NULL);
1203         gtk_widget_show (self->notebook);
1204
1205         /* Tilda is never decorated */
1206         gtk_window_set_decorated (GTK_WINDOW(self->window), FALSE);
1207
1208         /* Set all of the properties out of the config file */
1209         tilda_window_set_property_from_config (self, "key");
1210
1211         // FIXME: hack -- start the wizard in this case :)
1212         if (!self->key)
1213         {
1214                 gchar *key = g_strdup_printf ("F%d", self->number+3);
1215                 g_object_set (G_OBJECT(self), "key", key, NULL);
1216                 g_free (key);
1217
1218                 g_critical ("HACK: start the wizard here\n");
1219         }
1220
1221         tilda_window_set_property_from_config (self, "accelerator-quit");
1222         tilda_window_set_property_from_config (self, "accelerator-next-tab");
1223         tilda_window_set_property_from_config (self, "accelerator-previous-tab");
1224         tilda_window_set_property_from_config (self, "accelerator-add-terminal");
1225         tilda_window_set_property_from_config (self, "accelerator-remove-terminal");
1226         tilda_window_set_property_from_config (self, "accelerator-copy");
1227         tilda_window_set_property_from_config (self, "accelerator-paste");
1228         tilda_window_set_property_from_config (self, "accelerator-goto-1");
1229         tilda_window_set_property_from_config (self, "accelerator-goto-2");
1230         tilda_window_set_property_from_config (self, "accelerator-goto-3");
1231         tilda_window_set_property_from_config (self, "accelerator-goto-4");
1232         tilda_window_set_property_from_config (self, "accelerator-goto-5");
1233         tilda_window_set_property_from_config (self, "accelerator-goto-6");
1234         tilda_window_set_property_from_config (self, "accelerator-goto-7");
1235         tilda_window_set_property_from_config (self, "accelerator-goto-8");
1236         tilda_window_set_property_from_config (self, "accelerator-goto-9");
1237         tilda_window_set_property_from_config (self, "accelerator-goto-10");
1238
1239         tilda_window_set_property_from_config (self, "height");
1240         tilda_window_set_property_from_config (self, "width");
1241         tilda_window_set_property_from_config (self, "x-position");
1242         tilda_window_set_property_from_config (self, "y-position");
1243         tilda_window_set_property_from_config (self, "initial-terminals");
1244         tilda_window_set_property_from_config (self, "animation-delay");
1245
1246         tilda_window_set_property_from_config (self, "tab-position");
1247         tilda_window_set_property_from_config (self, "animation-orientation");
1248
1249         tilda_window_set_property_from_config (self, "keep-above");
1250         tilda_window_set_property_from_config (self, "skip-taskbar-hint");
1251         tilda_window_set_property_from_config (self, "stick");
1252         tilda_window_set_property_from_config (self, "hidden-at-start");
1253         tilda_window_set_property_from_config (self, "centered-horizontally");
1254         tilda_window_set_property_from_config (self, "centered-vertically");
1255         tilda_window_set_property_from_config (self, "full-width-tabs");
1256         tilda_window_set_property_from_config (self, "always-show-tabs");
1257
1258         /* Add the initial terminal(s) */
1259         for (i=0; i<self->initial_terminals; ++i)
1260                 tilda_window_add_terminal (self);
1261
1262         /* Show us if we're ready. If not, just remain hidden. All sub-widgets must
1263          * be gtk_widget_show()n by this point. */
1264         if (!self->hidden_at_start)
1265         {
1266                 gtk_widget_show (self->window);
1267                 self->state = WINDOW_DOWN;
1268         }
1269         else
1270                 self->state = WINDOW_UP;
1271
1272         /* Register this object with DBus */
1273         tilda_window_dbus_register_object (self);
1274
1275         return obj;
1276 }
1277
1278 static void
1279 tilda_window_dispose (GObject *obj)
1280 {
1281         debug_enter ();
1282
1283         TildaWindow *self = (TildaWindow *) obj;
1284
1285         /* We don't want to run dispose twice, so just return immediately */
1286         if (self->dispose_has_run)
1287                 return;
1288
1289         /*
1290          * In dispose, you are supposed to free all types referenced from this
1291          * object which might themselves hold a reference to self. Generally,
1292          * the most simple solution is to unref all members on which you own a
1293          * reference.
1294          *
1295          * NOTE: See the following for how to deal with GtkObject-derived things:
1296          * http://library.gnome.org/devel/gtk/unstable/GtkObject.html
1297          */
1298         g_object_unref (G_OBJECT(self->accel_group));
1299         g_ptr_array_foreach (self->terms, g_object_unref, NULL);
1300         gtk_widget_destroy (self->window);
1301
1302         /* Unbind if we were set */
1303         if (self->key)
1304                 tomboy_keybinder_unbind (self->key, tilda_window_keybinding_cb);
1305
1306         /* Chain up to the parent class */
1307         G_OBJECT_CLASS (parent_class)->dispose (obj);
1308 }
1309
1310 static void
1311 tilda_window_finalize (GObject *obj)
1312 {
1313         debug_enter ();
1314
1315         TildaWindow *self = (TildaWindow *) obj;
1316
1317         /*
1318          * Here, complete the object's destruction.
1319          * You might not need to do much...
1320          */
1321         // TODO: g_free() any primitives here
1322         g_ptr_array_free (self->terms, TRUE);
1323
1324
1325         /* Chain up to the parent class */
1326         G_OBJECT_CLASS (parent_class)->finalize (obj);
1327 }
1328
1329 static void
1330 tilda_window_class_init (gpointer g_class,
1331                                                  gpointer g_class_data)
1332 {
1333         debug_enter ();
1334
1335         GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
1336         TildaWindowClass *klass = TILDA_WINDOW_CLASS (g_class);
1337         GParamSpec *pspec;
1338
1339         /* Hook our functions to this type */
1340         gobject_class->set_property = tilda_window_set_property;
1341         gobject_class->get_property = tilda_window_get_property;
1342         gobject_class->dispose = tilda_window_dispose;
1343         gobject_class->finalize = tilda_window_finalize;
1344         gobject_class->constructor = tilda_window_constructor;
1345
1346         parent_class = g_type_class_peek_parent (klass);
1347
1348         /* Install all of the properties */
1349         pspec = g_param_spec_int ("number",
1350                                                           _("Window number"),
1351                                                           NULL,
1352                                                           0,            // min value
1353                                                           INT_MAX,      // max value
1354                                                           0,            // def value
1355                                                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1356
1357         g_object_class_install_property (gobject_class,
1358                                                                          TILDA_WINDOW_NUMBER,
1359                                                                          pspec);
1360
1361         pspec = g_param_spec_pointer ("controller",
1362                                                                   _("Pointer to window's controlling TildaController"),
1363                                                                   NULL,
1364                                                                   G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1365
1366         g_object_class_install_property (gobject_class,
1367                                                                          TILDA_WINDOW_CONTROLLER,
1368                                                                          pspec);
1369
1370         pspec = g_param_spec_string ("accelerator-quit",
1371                                                                  _("Accelerator to quit this window"),
1372                                                                  NULL,
1373                                                                  NULL,
1374                                                                  G_PARAM_READWRITE);
1375
1376         g_object_class_install_property (gobject_class,
1377                                                                          TILDA_WINDOW_ACCEL_QUIT,
1378                                                                          pspec);
1379
1380         pspec = g_param_spec_string ("accelerator-next-tab",
1381                                                                  _("Accelerator to go to the next tab"),
1382                                                                  NULL,
1383                                                                  NULL,
1384                                                                  G_PARAM_READWRITE);
1385
1386         g_object_class_install_property (gobject_class,
1387                                                                          TILDA_WINDOW_ACCEL_NEXT_TAB,
1388                                                                          pspec);
1389
1390         pspec = g_param_spec_string ("accelerator-previous-tab",
1391                                                                  _("Accelerator to go to the previous tab"),
1392                                                                  NULL,
1393                                                                  NULL,
1394                                                                  G_PARAM_READWRITE);
1395
1396         g_object_class_install_property (gobject_class,
1397                                                                          TILDA_WINDOW_ACCEL_PREV_TAB,
1398                                                                          pspec);
1399
1400         pspec = g_param_spec_string ("accelerator-add-terminal",
1401                                                                  _("Accelerator to add a terminal"),
1402                                                                  NULL,
1403                                                                  NULL,
1404                                                                  G_PARAM_READWRITE);
1405
1406         g_object_class_install_property (gobject_class,
1407                                                                          TILDA_WINDOW_ACCEL_ADD_TERM,
1408                                                                          pspec);
1409
1410         pspec = g_param_spec_string ("accelerator-remove-terminal",
1411                                                                  _("Accelerator to remove a terminal"),
1412                                                                  NULL,
1413                                                                  NULL,
1414                                                                  G_PARAM_READWRITE);
1415
1416         g_object_class_install_property (gobject_class,
1417                                                                          TILDA_WINDOW_ACCEL_REMOVE_TERM,
1418                                                                          pspec);
1419
1420         pspec = g_param_spec_string ("accelerator-copy",
1421                                                                  _("Accelerator to copy to the clipboard"),
1422                                                                  NULL,
1423                                                                  NULL,
1424                                                                  G_PARAM_READWRITE);
1425
1426         g_object_class_install_property (gobject_class,
1427                                                                          TILDA_WINDOW_ACCEL_COPY,
1428                                                                          pspec);
1429
1430         pspec = g_param_spec_string ("accelerator-paste",
1431                                                                  _("Accelerator to paste from the clipboard"),
1432                                                                  NULL,
1433                                                                  NULL,
1434                                                                  G_PARAM_READWRITE);
1435
1436         g_object_class_install_property (gobject_class,
1437                                                                          TILDA_WINDOW_ACCEL_PASTE,
1438                                                                          pspec);
1439
1440         pspec = g_param_spec_string ("accelerator-goto-1",
1441                                                                  _("Accelerator to go to tab 1"),
1442                                                                  NULL,
1443                                                                  NULL,
1444                                                                  G_PARAM_READWRITE);
1445
1446         g_object_class_install_property (gobject_class,
1447                                                                          TILDA_WINDOW_ACCEL_GOTO_1,
1448                                                                          pspec);
1449
1450         pspec = g_param_spec_string ("accelerator-goto-2",
1451                                                                  _("Accelerator to go to tab 2"),
1452                                                                  NULL,
1453                                                                  NULL,
1454                                                                  G_PARAM_READWRITE);
1455
1456         g_object_class_install_property (gobject_class,
1457                                                                          TILDA_WINDOW_ACCEL_GOTO_2,
1458                                                                          pspec);
1459
1460         pspec = g_param_spec_string ("accelerator-goto-3",
1461                                                                  _("Accelerator to go to tab 3"),
1462                                                                  NULL,
1463                                                                  NULL,
1464                                                                  G_PARAM_READWRITE);
1465
1466         g_object_class_install_property (gobject_class,
1467                                                                          TILDA_WINDOW_ACCEL_GOTO_3,
1468                                                                          pspec);
1469
1470         pspec = g_param_spec_string ("accelerator-goto-4",
1471                                                                  _("Accelerator to go to tab 4"),
1472                                                                  NULL,
1473                                                                  NULL,
1474                                                                  G_PARAM_READWRITE);
1475
1476         g_object_class_install_property (gobject_class,
1477                                                                          TILDA_WINDOW_ACCEL_GOTO_4,
1478                                                                          pspec);
1479
1480         pspec = g_param_spec_string ("accelerator-goto-5",
1481                                                                  _("Accelerator to go to tab 5"),
1482                                                                  NULL,
1483                                                                  NULL,
1484                                                                  G_PARAM_READWRITE);
1485
1486         g_object_class_install_property (gobject_class,
1487                                                                          TILDA_WINDOW_ACCEL_GOTO_5,
1488                                                                          pspec);
1489
1490         pspec = g_param_spec_string ("accelerator-goto-6",
1491                                                                  _("Accelerator to go to tab 6"),
1492                                                                  NULL,
1493                                                                  NULL,
1494                                                                  G_PARAM_READWRITE);
1495
1496         g_object_class_install_property (gobject_class,
1497                                                                          TILDA_WINDOW_ACCEL_GOTO_6,
1498                                                                          pspec);
1499
1500         pspec = g_param_spec_string ("accelerator-goto-7",
1501                                                                  _("Accelerator to go to tab 7"),
1502                                                                  NULL,
1503                                                                  NULL,
1504                                                                  G_PARAM_READWRITE);
1505
1506         g_object_class_install_property (gobject_class,
1507                                                                          TILDA_WINDOW_ACCEL_GOTO_7,
1508                                                                          pspec);
1509
1510         pspec = g_param_spec_string ("accelerator-goto-8",
1511                                                                  _("Accelerator to go to tab 8"),
1512                                                                  NULL,
1513                                                                  NULL,
1514                                                                  G_PARAM_READWRITE);
1515
1516         g_object_class_install_property (gobject_class,
1517                                                                          TILDA_WINDOW_ACCEL_GOTO_8,
1518                                                                          pspec);
1519
1520         pspec = g_param_spec_string ("accelerator-goto-9",
1521                                                                  _("Accelerator to go to tab 9"),
1522                                                                  NULL,
1523                                                                  NULL,
1524                                                                  G_PARAM_READWRITE);
1525
1526         g_object_class_install_property (gobject_class,
1527                                                                          TILDA_WINDOW_ACCEL_GOTO_9,
1528                                                                          pspec);
1529
1530         pspec = g_param_spec_string ("accelerator-goto-10",
1531                                                                  _("Accelerator to go to tab 10"),
1532                                                                  NULL,
1533                                                                  NULL,
1534                                                                  G_PARAM_READWRITE);
1535
1536         g_object_class_install_property (gobject_class,
1537                                                                          TILDA_WINDOW_ACCEL_GOTO_10,
1538                                                                          pspec);
1539
1540         pspec = g_param_spec_string ("key",
1541                                                                  _("Window's drop-down keybinding"),
1542                                                                  NULL,
1543                                                                  NULL,
1544                                                                  G_PARAM_READWRITE);
1545
1546         g_object_class_install_property (gobject_class,
1547                                                                          TILDA_WINDOW_KEY,
1548                                                                          pspec);
1549
1550         pspec = g_param_spec_int ("height",
1551                                                           _("Window's height"),
1552                                                           NULL,
1553                                                           0,
1554                                                           INT_MAX,
1555                                                           0,
1556                                                           G_PARAM_READWRITE);
1557
1558         g_object_class_install_property (gobject_class,
1559                                                                          TILDA_WINDOW_HEIGHT,
1560                                                                          pspec);
1561
1562         pspec = g_param_spec_int ("width",
1563                                                           _("Window's width"),
1564                                                           NULL,
1565                                                           0,
1566                                                           INT_MAX,
1567                                                           0,
1568                                                           G_PARAM_READWRITE);
1569
1570         g_object_class_install_property (gobject_class,
1571                                                                          TILDA_WINDOW_WIDTH,
1572                                                                          pspec);
1573
1574         pspec = g_param_spec_int ("x-position",
1575                                                           _("Window's x position"),
1576                                                           NULL,
1577                                                           0,
1578                                                           INT_MAX,
1579                                                           0,
1580                                                           G_PARAM_READWRITE);
1581
1582         g_object_class_install_property (gobject_class,
1583                                                                          TILDA_WINDOW_X_POSITION,
1584                                                                          pspec);
1585
1586         pspec = g_param_spec_int ("y-position",
1587                                                           _("Window's y position"),
1588                                                           NULL,
1589                                                           0,
1590                                                           INT_MAX,
1591                                                           0,
1592                                                           G_PARAM_READWRITE);
1593
1594         g_object_class_install_property (gobject_class,
1595                                                                          TILDA_WINDOW_Y_POSITION,
1596                                                                          pspec);
1597
1598         pspec = g_param_spec_int ("initial-terminals",
1599                                                           _("Window's inital number of terminals"),
1600                                                           NULL,
1601                                                           1,
1602                                                           INT_MAX,
1603                                                           1,
1604                                                           G_PARAM_READWRITE);
1605
1606         g_object_class_install_property (gobject_class,
1607                                                                          TILDA_WINDOW_INITIAL_TERMINALS,
1608                                                                          pspec);
1609
1610         pspec = g_param_spec_enum ("tab-position",
1611                                                            _("Position of window's tab bar"),
1612                                                            NULL,
1613                                                            gtk_position_type_get_type(),
1614                                                            GTK_POS_TOP,
1615                                                            G_PARAM_READWRITE);
1616
1617         g_object_class_install_property (gobject_class,
1618                                                                          TILDA_WINDOW_TAB_POSITION,
1619                                                                          pspec);
1620
1621         pspec = g_param_spec_enum ("animation-orientation",
1622                                                            _("Window's animation orientation"),
1623                                                            NULL,
1624                                                            gtk_position_type_get_type(),
1625                                                            GTK_POS_TOP,
1626                                                            G_PARAM_READWRITE);
1627
1628         g_object_class_install_property (gobject_class,
1629                                                                          TILDA_WINDOW_ANIMATION_ORIENTATION,
1630                                                                          pspec);
1631
1632         pspec = g_param_spec_int ("animation-delay",
1633                                                           _("Amount of time in milliseconds between animation intervals"),
1634                                                           NULL,
1635                                                           0,
1636                                                           INT_MAX,
1637                                                           0,
1638                                                           G_PARAM_READWRITE);
1639
1640         g_object_class_install_property (gobject_class,
1641                                                                          TILDA_WINDOW_ANIMATION_DELAY,
1642                                                                          pspec);
1643
1644         pspec = g_param_spec_boolean ("keep-above",
1645                                                                   _("Keep this window above all others"),
1646                                                                   NULL,
1647                                                                   FALSE,
1648                                                                   G_PARAM_READWRITE);
1649
1650         g_object_class_install_property (gobject_class,
1651                                                                          TILDA_WINDOW_KEEP_ABOVE,
1652                                                                          pspec);
1653
1654         pspec = g_param_spec_boolean ("skip-taskbar-hint",
1655                                                                   _("Hide this window in the taskbar if TRUE"),
1656                                                                   NULL,
1657                                                                   FALSE,
1658                                                                   G_PARAM_READWRITE);
1659
1660         g_object_class_install_property (gobject_class,
1661                                                                          TILDA_WINDOW_SKIP_TASKBAR_HINT,
1662                                                                          pspec);
1663
1664         pspec = g_param_spec_boolean ("stick",
1665                                                                   _("Display this window on all workspaces"),
1666                                                                   NULL,
1667                                                                   FALSE,
1668                                                                   G_PARAM_READWRITE);
1669
1670         g_object_class_install_property (gobject_class,
1671                                                                          TILDA_WINDOW_STICK,
1672                                                                          pspec);
1673
1674         pspec = g_param_spec_boolean ("hidden-at-start",
1675                                                                   _("Hide the window when it is first created"),
1676                                                                   NULL,
1677                                                                   FALSE,
1678                                                                   G_PARAM_READWRITE);
1679
1680         g_object_class_install_property (gobject_class,
1681                                                                          TILDA_WINDOW_HIDDEN_AT_START,
1682                                                                          pspec);
1683
1684         pspec = g_param_spec_boolean ("centered-horizontally",
1685                                                                   _("Center the window horizontally"),
1686                                                                   NULL,
1687                                                                   FALSE,
1688                                                                   G_PARAM_READWRITE);
1689
1690         g_object_class_install_property (gobject_class,
1691                                                                          TILDA_WINDOW_CENTERED_HORIZONTALLY,
1692                                                                          pspec);
1693
1694         pspec = g_param_spec_boolean ("centered-vertically",
1695                                                                   _("Center the window vertically"),
1696                                                                   NULL,
1697                                                                   FALSE,
1698                                                                   G_PARAM_READWRITE);
1699
1700         g_object_class_install_property (gobject_class,
1701                                                                          TILDA_WINDOW_CENTERED_VERTICALLY,
1702                                                                          pspec);
1703
1704         pspec = g_param_spec_boolean ("full-width-tabs",
1705                                                                   _("Tabs should have full width of window"),
1706                                                                   NULL,
1707                                                                   TRUE,
1708                                                                   G_PARAM_READWRITE);
1709
1710         g_object_class_install_property (gobject_class,
1711                                                                          TILDA_WINDOW_FULL_WIDTH_TABS,
1712                                                                          pspec);
1713
1714         pspec = g_param_spec_boolean ("always-show-tabs",
1715                                                                   _("Always show the tab bar, regardless of the number of open tabs"),
1716                                                                   NULL,
1717                                                                   TRUE,
1718                                                                   G_PARAM_READWRITE);
1719
1720         g_object_class_install_property (gobject_class,
1721                                                                          TILDA_WINDOW_ALWAYS_SHOW_TABS,
1722                                                                          pspec);
1723
1724         pspec = g_param_spec_boolean ("have-real-transparency",
1725                                                                   NULL, NULL, FALSE, G_PARAM_READABLE);
1726
1727         g_object_class_install_property (gobject_class,
1728                                                                          TILDA_WINDOW_HAVE_REAL_TRANSPARENCY,
1729                                                                          pspec);
1730
1731         /* Hook the TildaWindow type into DBus */
1732         dbus_g_object_type_install_info (tilda_window_get_type(), &dbus_glib_tilda_window_object_info);
1733 }
1734
1735 GType
1736 tilda_window_get_type (void)
1737 {
1738         static GType type = 0;
1739
1740         if (type == 0)
1741         {
1742                 static const GTypeInfo info = {
1743                         sizeof (TildaWindowClass),
1744                         NULL,   /* base_init */
1745                         NULL,   /* base_finalize */
1746                         tilda_window_class_init,        /* class_init */
1747                         NULL,   /* class_finalize */
1748                         NULL,   /* class_data */
1749                         sizeof (TildaWindow),
1750                         0,              /* n_preallocs */
1751                         tilda_window_instance_init,     /* instance_init */
1752                 };
1753
1754                 type = g_type_register_static (G_TYPE_OBJECT,
1755                                                                            "TildaWindowType",
1756                                                                            &info,
1757                                                                            0);
1758         }
1759
1760         return type;
1761 }
1762
1763 /* vim: set ts=4 sts=4 sw=4 noet tw=112: */