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