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