[Window] Another try at thwarting focus-stealing prevention
[tilda-gobject.git] / tilda-window.c
1 #include <string.h>
2
3 #include "tilda.h"
4 #include "tilda-window.h"
5 #include "tilda-window-dbus-glue.h"
6 #include "tomboykeybinder.h"
7
8 /**
9  * Find the TildaTerminal corresponding to the currently selected
10  * tab in self->notebook. This could go away if TildaTerminal were
11  * a proper subclass of GtkWidget.
12  */
13 static TildaTerminal *
14 tilda_window_find_current_terminal (TildaWindow *self)
15 {
16         debug_enter();
17         debug_assert (TILDA_IS_WINDOW(self));
18
19         gint i;
20         TildaTerminal *ret;
21         gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK(self->notebook));
22         GtkWidget *box = gtk_notebook_get_nth_page (GTK_NOTEBOOK(self->notebook), current_page);
23
24         for (i=0; i<self->terms->len; ++i)
25         {
26                 ret = g_ptr_array_index (self->terms, i);
27
28                 if (ret->hbox == box)
29                         return ret;
30         }
31
32         debug_printf ("ERROR: unable to find current terminal!\n");
33         return NULL;
34 }
35
36 static gint
37 tilda_window_find_next_free_terminal_number (TildaWindow *self)
38 {
39         debug_enter ();
40         debug_assert (TILDA_IS_WINDOW(self));
41
42         gint i, j;
43         gboolean found;
44
45         for (i=0; i<INT_MAX; ++i)
46         {
47                 found = FALSE;
48
49                 for (j=0; j<self->terms->len; ++j)
50                 {
51                         TildaTerminal *tt = g_ptr_array_index (self->terms, j);
52
53                         if (tt->number == i)
54                         {
55                                 found = TRUE;
56                                 break;
57                         }
58                 }
59
60                 if (!found)
61                         return i;
62         }
63
64         return 0;
65 }
66
67 /**
68  * Clean up and remove self completely from the program
69  *
70  * Should only be used by DBus...
71  */
72 gboolean
73 tilda_window_close (TildaWindow *self)
74 {
75         debug_enter  ();
76         debug_assert (TILDA_IS_WINDOW(self));
77
78         tilda_del_window (self->number);
79
80         return TRUE;
81 }
82
83 gboolean
84 tilda_window_add_terminal (TildaWindow *self)
85 {
86         debug_enter ();
87         debug_assert (TILDA_IS_WINDOW(self));
88
89         gint number;
90         TildaTerminal *tt;
91
92         number = tilda_window_find_next_free_terminal_number (self);
93         tt = g_object_new (TILDA_TYPE_TERMINAL,
94                                            "number", number,
95                                            "parent-window", self,
96                                            NULL);
97         g_ptr_array_add (self->terms, tt);
98
99         GtkWidget *label = gtk_label_new ("Tilda");
100         gint index = gtk_notebook_prepend_page (GTK_NOTEBOOK(self->notebook), tt->hbox, label);
101         gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK(self->notebook), tt->hbox, TRUE, TRUE, GTK_PACK_END);
102         gtk_notebook_set_current_page (GTK_NOTEBOOK(self->notebook), index);
103
104         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK(self->notebook)) > 1)
105                 gtk_notebook_set_show_tabs (GTK_NOTEBOOK(self->notebook), TRUE);
106
107         /* Focus the VTE Terminal */
108         gtk_widget_grab_focus (tt->vte_term);
109
110         return TRUE;
111 }
112
113 /**
114  * Remove the TildaTerminal with the given number from the given
115  * TildaWindow.
116  *
117  * Return: TRUE on success, FALSE otherwise.
118  */
119 gboolean
120 tilda_window_remove_terminal (TildaWindow *self, gint terminal_number)
121 {
122         debug_enter  ();
123         debug_assert (TILDA_IS_WINDOW(self));
124         debug_assert (terminal_number >= 0);
125
126         gint i;
127
128         for (i=0; i<self->terms->len; ++i)
129         {
130                 TildaTerminal *tt = g_ptr_array_index (self->terms, i);
131
132                 if (tt->number == terminal_number)
133                 {
134                         gint notebook_index = gtk_notebook_page_num (GTK_NOTEBOOK(self->notebook), tt->hbox);
135
136                         /* Make sure the index was valid */
137                         if (notebook_index == -1)
138                         {
139                                 debug_printf ("ERROR: Bad Notebook Tab\n");
140                                 return FALSE;
141                         }
142
143                         /* Actually remove the terminal */
144                         gtk_notebook_remove_page (GTK_NOTEBOOK (self->notebook), notebook_index);
145
146                         /* We should hide the tabs if there is only one tab left */
147                         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->notebook)) == 1)
148                                 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (self->notebook), FALSE);
149
150                         /* Remove the term from our lists, then free it */
151                         g_ptr_array_remove_fast (self->terms, tt);
152                         g_object_unref (G_OBJECT(tt));
153
154                         /* With no pages left, it's time to remove this window */
155                         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->notebook)) < 1)
156                         {
157                                 debug_printf ("no terminals left, closing window %d\n", self->number);
158                                 tilda_del_window (self->number);
159                         }
160
161                         /* Leave the loop, we're done */
162                         break;
163                 }
164         }
165
166         return TRUE;
167 }
168
169 /**
170  * This sets up the given TildaWindow for the capability of real
171  * transparency, if the X server is capable of it. */
172 static void
173 tilda_window_setup_real_transparency (TildaWindow *self)
174 {
175         debug_enter  ();
176         debug_assert (TILDA_IS_WINDOW(self));
177
178         GdkScreen *screen;
179         GdkColormap *colormap;
180
181         screen = gtk_widget_get_screen (GTK_WIDGET(self->window));
182         colormap = gdk_screen_get_rgba_colormap (screen);
183
184         /* If possible, set the RGBA colormap so VTE can use real alpha
185          * channels for transparency. */
186         if (colormap != NULL && gdk_screen_is_composited (screen))
187         {
188                 gtk_widget_set_colormap (GTK_WIDGET(self->window), colormap);
189                 self->have_real_transparency = TRUE;
190                 return;
191         }
192
193         self->have_real_transparency = FALSE;
194 }
195
196 /* Center the given TildaWindow in the horizontal axis */
197 static void
198 tilda_window_center_horizontally (TildaWindow *self)
199 {
200         debug_enter  ();
201         debug_assert (TILDA_IS_WINDOW(self));
202
203         const gint screen_center = gdk_screen_width() / 2;
204         const gint tilda_center  = self->width / 2;
205         const gint center_coord  = screen_center - tilda_center;
206
207         g_object_set (G_OBJECT(self), "x-position", center_coord, NULL);
208 }
209
210 /* Center the given TildaWindow in the vertical axis */
211 static void
212 tilda_window_center_vertically (TildaWindow *self)
213 {
214         debug_enter  ();
215         debug_assert (TILDA_IS_WINDOW(self));
216
217         const gint screen_center = gdk_screen_height() / 2;
218         const gint tilda_center  = self->height / 2;
219         const gint center_coord  = screen_center - tilda_center;
220
221         g_object_set (G_OBJECT(self), "y-position", center_coord, NULL);
222 }
223
224 static void
225 tilda_window_keybinding_cb (const gchar *keystr, gpointer data)
226 {
227         debug_enter  ();
228         debug_assert (TILDA_IS_WINDOW(data));
229
230         TildaWindow *self = TILDA_WINDOW(data);
231         TildaTerminal *tt;
232
233         /* This call sets the X11 window property _NET_WM_USER_TIME, which GTK+ normally
234          * sets for us. However, because this callback is activated via a global keybinding,
235          * we see the event before GDK / GTK+ does. Therefore, to get the focus, we must
236          * set the property ourselves. */
237         gdk_x11_window_set_user_time (GTK_WIDGET(self->window)->window,
238                                                                   tomboy_keybinder_get_current_event_time());
239
240         switch (self->state)
241         {
242                 case WINDOW_UP: /* Pull the window up */
243
244                         /* Bugfix: having this here keeps the tilda window from being
245                          * hidden if you turn off "stick", pull it down on workspace 1,
246                          * switch to workspace 2, then pull it up and back down. Without
247                          * this, something in metacity (at least) hides the window. Stupid. */
248                         gtk_window_deiconify (GTK_WINDOW(self->window));
249
250                         /* Re-set the window properties that do not linger after hiding the
251                          * window. I know this looks stupid, but it keeps all of the state-
252                          * changing code in the place it belongs: the property-setting code. */
253                         g_object_set (G_OBJECT(self),
254                                         "keep-above", self->keep_above,
255                                         "stick", self->stick,
256                                         NULL);
257                         gtk_widget_show (GTK_WIDGET(self->window));
258
259                         /* Focusing the term here works perfectly, near as I can tell */
260                         tt = tilda_window_find_current_terminal (self);
261                         gtk_widget_grab_focus (GTK_WIDGET(tt->vte_term));
262
263                         self->state = WINDOW_DOWN;
264                         break;
265
266                 case WINDOW_DOWN: /* Pull the window up */
267
268                         gtk_widget_hide (GTK_WIDGET(self->window));
269
270                         self->state = WINDOW_UP;
271                         break;
272
273                 default:
274                         debug_printf ("ERROR: Window is in a bad state!\n");
275
276                         /* Pretend we're down, for good measure.... */
277                         self->state = WINDOW_DOWN;
278                         break;
279         }
280 }
281
282 /**
283  * Attempt to bind the new_key to show this window.
284  *
285  * Return: TRUE if successful, FALSE otherwise.
286  */
287 static gboolean
288 tilda_window_try_to_bind_key (TildaWindow *self, const gchar *new_key)
289 {
290         debug_enter  ();
291         debug_assert (TILDA_IS_WINDOW(self));
292
293         gboolean ret = FALSE;
294
295         /* Make sure the new key is not null in any way */
296         if (new_key == NULL || strcmp("", new_key) == 0)
297                 return FALSE;
298
299         /* Unbind if we were set */
300         if (self->key)
301                 tomboy_keybinder_unbind (self->key, tilda_window_keybinding_cb);
302
303         ret = tomboy_keybinder_bind (new_key, tilda_window_keybinding_cb, self);
304
305         /* If it was successful, update the self->key variable and be done with it */
306         if (ret)
307         {
308                 g_free (self->key);
309                 self->key = g_strdup (new_key);
310                 return TRUE;
311         }
312
313         g_printerr (_("Bind key '%s' failed. Reverting to original keybinding\n"), self->key);
314
315         /* Not successful, so rebind the old key, and return FALSE */
316         if (self->key != NULL && strcmp("",self->key) != 0)
317         {
318                 ret = tomboy_keybinder_bind (self->key, tilda_window_keybinding_cb, self);
319
320                 /* Check that it went ok */
321                 if (!ret)
322                         g_printerr (_("Unable to re-bind original key '%s'. Oh shit...\n"), self->key);
323         }
324         else
325                 g_printerr (_("No original key to revert to!\n"));
326
327         return FALSE;
328 }
329
330 static void
331 tilda_window_dbus_register_object (TildaWindow *self)
332 {
333         debug_enter  ();
334         debug_assert (TILDA_IS_WINDOW(self));
335
336         gchar *object_path;
337
338         // Register this object with DBus
339         object_path = g_strdup_printf ("/net/sourceforge/Tilda/Window%d", self->number);
340         dbus_g_connection_register_g_object (dbus_connection, object_path, G_OBJECT(self));
341         g_free (object_path);
342 }
343
344 /*******************************************************************************
345  * ALL GOBJECT STUFF BELOW PLEASE
346  ******************************************************************************/
347
348 static GObjectClass *parent_class = NULL;
349
350 enum tilda_window_properties {
351         TILDA_WINDOW_NUMBER = 1,
352
353         TILDA_WINDOW_KEY,
354
355         TILDA_WINDOW_HEIGHT,
356         TILDA_WINDOW_WIDTH,
357         TILDA_WINDOW_X_POSITION,
358         TILDA_WINDOW_Y_POSITION,
359
360         TILDA_WINDOW_TAB_POSITION,
361         TILDA_WINDOW_ANIMATION_ORIENTATION,
362         TILDA_WINDOW_ANIMATION_DELAY,
363
364         TILDA_WINDOW_KEEP_ABOVE,
365         TILDA_WINDOW_SKIP_TASKBAR_HINT,
366         TILDA_WINDOW_STICK,
367         TILDA_WINDOW_HIDDEN_AT_START,
368         TILDA_WINDOW_CENTERED_HORIZONTALLY,
369         TILDA_WINDOW_CENTERED_VERTICALLY,
370
371         TILDA_WINDOW_HAVE_REAL_TRANSPARENCY,
372 };
373
374 static void
375 tilda_window_instance_init (GTypeInstance *instance,
376                                                         gpointer       g_class)
377 {
378         debug_enter ();
379
380         TildaWindow *self = (TildaWindow *) instance;
381         self->dispose_has_run = FALSE;
382
383         /* Initialize all properties */
384         self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
385         self->notebook = gtk_notebook_new ();
386         self->terms = g_ptr_array_new ();
387
388         /* Somewhat of a "poison" value, incase we don't set this */
389         self->number = 0xdeadbeef;
390
391         self->state = WINDOW_UP;
392 }
393
394 static void
395 tilda_window_set_property (GObject      *object,
396                                                    guint         property_id,
397                                                    const GValue *value,
398                                                    GParamSpec   *pspec)
399 {
400         TildaWindow *self = (TildaWindow *) object;
401
402         switch (property_id) {
403
404                 case TILDA_WINDOW_NUMBER:
405                         self->number = g_value_get_int (value);
406                         debug_printf ("window number: %d\n", self->number);
407                         break;
408
409                 case TILDA_WINDOW_KEY:
410                         tilda_window_try_to_bind_key (self, g_value_get_string (value));
411                         debug_printf ("window key %s\n", self->key);
412                         break;
413
414                 case TILDA_WINDOW_HEIGHT:
415                         self->height = g_value_get_int (value);
416                         gtk_widget_set_size_request (self->window, self->width, self->height);
417                         gtk_window_resize (GTK_WINDOW(self->window), self->width, self->height);
418                         debug_printf ("window height: %d\n", self->height);
419                         break;
420
421                 case TILDA_WINDOW_WIDTH:
422                         self->width = g_value_get_int (value);
423                         gtk_widget_set_size_request (self->window, self->width, self->height);
424                         gtk_window_resize (GTK_WINDOW(self->window), self->width, self->height);
425                         debug_printf ("window width: %d\n", self->width);
426                         break;
427
428                 case TILDA_WINDOW_X_POSITION:
429                         self->x_position = g_value_get_int (value);
430                         gtk_window_move (GTK_WINDOW(self->window), self->x_position, self->y_position);
431                         debug_printf ("window x position: %d\n", self->x_position);
432                         break;
433
434                 case TILDA_WINDOW_Y_POSITION:
435                         self->y_position = g_value_get_int (value);
436                         gtk_window_move (GTK_WINDOW(self->window), self->x_position, self->y_position);
437                         debug_printf ("window y position: %d\n", self->y_position);
438                         break;
439
440                 case TILDA_WINDOW_TAB_POSITION:
441                         self->tab_position = g_value_get_int (value);
442                         gtk_notebook_set_tab_pos (GTK_NOTEBOOK(self->notebook), self->tab_position);
443                         debug_printf ("window tab position: %d\n", self->tab_position);
444                         break;
445
446                 case TILDA_WINDOW_ANIMATION_ORIENTATION:
447                         self->animation_orientation = g_value_get_int (value);
448                         debug_printf ("window animation orientation: %d\n", self->animation_orientation);
449                         break;
450
451                 case TILDA_WINDOW_ANIMATION_DELAY:
452                         self->animation_delay = g_value_get_int (value);
453                         debug_printf ("window animation delay: %d\n", self->animation_delay);
454                         break;
455
456                 case TILDA_WINDOW_KEEP_ABOVE:
457                         self->keep_above = g_value_get_boolean (value);
458                         gtk_window_set_keep_above (GTK_WINDOW(self->window), self->keep_above);
459                         debug_printf ("window keep above: %d\n", self->keep_above);
460                         break;
461
462                 case TILDA_WINDOW_SKIP_TASKBAR_HINT:
463                         self->skip_taskbar_hint = g_value_get_boolean (value);
464                         gtk_window_set_skip_taskbar_hint (GTK_WINDOW(self->window), self->skip_taskbar_hint);
465                         debug_printf ("window skip taskbar hint: %d\n", self->skip_taskbar_hint);
466                         break;
467
468                 case TILDA_WINDOW_STICK:
469                         self->stick = g_value_get_boolean (value);
470
471                         /* This is moderately ugly, but GTK+ does it this way... */
472                         self->stick ? gtk_window_stick (GTK_WINDOW(self->window))
473                                                 : gtk_window_unstick (GTK_WINDOW(self->window));
474                         debug_printf ("window stick: %d\n", self->stick);
475                         break;
476
477                 case TILDA_WINDOW_HIDDEN_AT_START:
478                         self->hidden_at_start = g_value_get_boolean (value);
479                         debug_printf ("window hidden at start: %d\n", self->hidden_at_start);
480                         break;
481
482                 case TILDA_WINDOW_CENTERED_HORIZONTALLY:
483                         self->centered_horizontally = g_value_get_boolean (value);
484                         if (self->centered_horizontally)
485                                 tilda_window_center_horizontally (self);
486                         debug_printf ("window centered horizontally: %d\n", self->centered_horizontally);
487                         break;
488
489                 case TILDA_WINDOW_CENTERED_VERTICALLY:
490                         self->centered_vertically = g_value_get_boolean (value);
491                         if (self->centered_vertically)
492                                 tilda_window_center_vertically (self);
493                         debug_printf ("window centered vertically: %d\n", self->centered_vertically);
494                         break;
495
496                 case TILDA_WINDOW_HAVE_REAL_TRANSPARENCY:
497                         self->have_real_transparency = g_value_get_boolean (value);
498                         debug_printf ("window have real transp: %d\n", self->have_real_transparency);
499                         break;
500
501                 default:
502                         /* We don't have this property */
503                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
504                         break;
505         }
506 }
507
508 static void
509 tilda_window_get_property (GObject    *object,
510                                                    guint       property_id,
511                                                    GValue     *value,
512                                                    GParamSpec *pspec)
513 {
514         TildaWindow *self = (TildaWindow *) object;
515
516         switch (property_id) {
517
518                 case TILDA_WINDOW_NUMBER:
519                         g_value_set_int (value, self->number);
520                         break;
521
522                 case TILDA_WINDOW_KEY:
523                         g_value_set_string (value, self->key);
524                         break;
525
526                 case TILDA_WINDOW_HEIGHT:
527                         g_value_set_int (value, self->height);
528                         break;
529
530                 case TILDA_WINDOW_WIDTH:
531                         g_value_set_int (value, self->width);
532                         break;
533
534                 case TILDA_WINDOW_X_POSITION:
535                         g_value_set_int (value, self->x_position);
536                         break;
537
538                 case TILDA_WINDOW_Y_POSITION:
539                         g_value_set_int (value, self->y_position);
540                         break;
541
542                 case TILDA_WINDOW_TAB_POSITION:
543                         g_value_set_int (value, self->tab_position);
544                         break;
545
546                 case TILDA_WINDOW_ANIMATION_ORIENTATION:
547                         g_value_set_int (value, self->animation_orientation);
548                         break;
549
550                 case TILDA_WINDOW_ANIMATION_DELAY:
551                         g_value_set_int (value, self->animation_delay);
552                         break;
553
554                 case TILDA_WINDOW_KEEP_ABOVE:
555                         g_value_set_boolean (value, self->keep_above);
556                         break;
557
558                 case TILDA_WINDOW_SKIP_TASKBAR_HINT:
559                         g_value_set_boolean (value, self->skip_taskbar_hint);
560                         break;
561
562                 case TILDA_WINDOW_STICK:
563                         g_value_set_boolean (value, self->stick);
564                         break;
565
566                 case TILDA_WINDOW_HIDDEN_AT_START:
567                         g_value_set_boolean (value, self->hidden_at_start);
568                         break;
569
570                 case TILDA_WINDOW_CENTERED_HORIZONTALLY:
571                         g_value_set_boolean (value, self->centered_horizontally);
572                         break;
573
574                 case TILDA_WINDOW_CENTERED_VERTICALLY:
575                         g_value_set_boolean (value, self->centered_vertically);
576                         break;
577
578                 case TILDA_WINDOW_HAVE_REAL_TRANSPARENCY:
579                         g_value_set_boolean (value, self->have_real_transparency);
580                         break;
581
582                 default:
583                         /* We don't have this property */
584                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
585                         break;
586         }
587 }
588
589 static GObject *
590 tilda_window_constructor (GType                  type,
591                                                   guint                  n_construct_properties,
592                                                   GObjectConstructParam *construct_properties)
593 {
594         debug_enter ();
595
596         GObject *obj;
597         TildaWindow *self;
598
599         /* Invoke parent constructor */
600         TildaWindowClass *klass;
601         klass = TILDA_WINDOW_CLASS (g_type_class_peek (TILDA_TYPE_WINDOW));
602         obj = parent_class->constructor (type,
603                                                                          n_construct_properties,
604                                                                          construct_properties);
605
606         /* Do other stuff here. The object is ready to go now, and all
607          * ctor properties have been set.
608          */
609         self = TILDA_WINDOW(obj);
610
611         /* Register this object with DBus */
612         tilda_window_dbus_register_object (self);
613
614         /* Try to set up real transparency */
615         tilda_window_setup_real_transparency (self);
616
617         gtk_container_add (GTK_CONTAINER(self->window), self->notebook);
618         g_object_set (G_OBJECT(self->notebook), "can-focus", FALSE, NULL);
619         gtk_widget_show (self->notebook);
620
621         // FIXME: Remove these, and replace with reads from the config system
622         g_object_set (G_OBJECT(self), "key", "F2", NULL);
623         g_object_set (G_OBJECT(self), "x-position", 0, "y-position", 0, NULL);
624         g_object_set (G_OBJECT(self), "height", 400, "width", 1680, NULL);
625         g_object_set (G_OBJECT(self), "keep-above", TRUE, "stick", TRUE, NULL);
626         g_object_set (G_OBJECT(self), "hidden-at-start", FALSE, NULL);
627
628         gtk_window_set_decorated (GTK_WINDOW(self->window), FALSE);
629
630         // FIXME: It should be configurable how many terms we add at startup
631         tilda_window_add_terminal (self);
632         tilda_window_add_terminal (self);
633
634         /* Show us if we're ready. If not, just remain hidden. All sub-widgets must
635          * be gtk_widget_show()n by this point. */
636         if (!self->hidden_at_start)
637         {
638                 gtk_widget_show (self->window);
639                 self->state = WINDOW_DOWN;
640         }
641         else
642                 self->state = WINDOW_UP;
643
644         return obj;
645 }
646
647 static void
648 my_unref (gpointer data, gpointer user_data)
649 {
650         debug_enter ();
651
652         // FIXME: This function should probably be eliminated. It /is/ rather ugly
653         g_object_unref (G_OBJECT(data));
654 }
655
656 static void
657 tilda_window_dispose (GObject *obj)
658 {
659         debug_enter ();
660
661         TildaWindow *self = (TildaWindow *) obj;
662
663         /* We don't want to run dispose twice, so just return immediately */
664         if (self->dispose_has_run)
665                 return;
666
667         /*
668          * In dispose, you are supposed to free all types referenced from this
669          * object which might themselves hold a reference to self. Generally,
670          * the most simple solution is to unref all members on which you own a
671          * reference.
672          *
673          * NOTE: See the following for how to deal with GtkObject-derived things:
674          * http://library.gnome.org/devel/gtk/unstable/GtkObject.html
675          */
676         g_ptr_array_foreach (self->terms, my_unref, NULL);
677         gtk_widget_destroy (self->window);
678
679         /* Chain up to the parent class */
680         G_OBJECT_CLASS (parent_class)->dispose (obj);
681 }
682
683 static void
684 tilda_window_finalize (GObject *obj)
685 {
686         debug_enter ();
687
688         TildaWindow *self = (TildaWindow *) obj;
689
690         /*
691          * Here, complete the object's destruction.
692          * You might not need to do much...
693          */
694         // TODO: g_free() any primitives here
695         g_ptr_array_free (self->terms, TRUE);
696
697
698         /* Chain up to the parent class */
699         G_OBJECT_CLASS (parent_class)->finalize (obj);
700 }
701
702 static void
703 tilda_window_class_init (gpointer g_class,
704                                                  gpointer g_class_data)
705 {
706         debug_enter ();
707
708         GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
709         TildaWindowClass *klass = TILDA_WINDOW_CLASS (g_class);
710         GParamSpec *pspec;
711
712         /* Hook our functions to this type */
713         gobject_class->set_property = tilda_window_set_property;
714         gobject_class->get_property = tilda_window_get_property;
715         gobject_class->dispose = tilda_window_dispose;
716         gobject_class->finalize = tilda_window_finalize;
717         gobject_class->constructor = tilda_window_constructor;
718
719         parent_class = g_type_class_peek_parent (klass);
720
721         /* Install all of the properties */
722         pspec = g_param_spec_int ("number",
723                                                           _("Window number"),
724                                                           NULL,
725                                                           0,            // min value
726                                                           INT_MAX,      // max value
727                                                           0,            // def value
728                                                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
729
730         g_object_class_install_property (gobject_class,
731                                                                          TILDA_WINDOW_NUMBER,
732                                                                          pspec);
733
734         pspec = g_param_spec_string ("key",
735                                                                  _("Window's drop-down keybinding"),
736                                                                  NULL,
737                                                                  NULL,
738                                                                  G_PARAM_READWRITE);
739
740         g_object_class_install_property (gobject_class,
741                                                                          TILDA_WINDOW_KEY,
742                                                                          pspec);
743
744         pspec = g_param_spec_int ("height",
745                                                           _("Window's height"),
746                                                           NULL,
747                                                           0,
748                                                           INT_MAX,
749                                                           0,
750                                                           G_PARAM_READWRITE);
751
752         g_object_class_install_property (gobject_class,
753                                                                          TILDA_WINDOW_HEIGHT,
754                                                                          pspec);
755
756         pspec = g_param_spec_int ("width",
757                                                           _("Window's width"),
758                                                           NULL,
759                                                           0,
760                                                           INT_MAX,
761                                                           0,
762                                                           G_PARAM_READWRITE);
763
764         g_object_class_install_property (gobject_class,
765                                                                          TILDA_WINDOW_WIDTH,
766                                                                          pspec);
767
768         pspec = g_param_spec_int ("x-position",
769                                                           _("Window's x position"),
770                                                           NULL,
771                                                           0,
772                                                           INT_MAX,
773                                                           0,
774                                                           G_PARAM_READWRITE);
775
776         g_object_class_install_property (gobject_class,
777                                                                          TILDA_WINDOW_X_POSITION,
778                                                                          pspec);
779
780         pspec = g_param_spec_int ("y-position",
781                                                           _("Window's y position"),
782                                                           NULL,
783                                                           0,
784                                                           INT_MAX,
785                                                           0,
786                                                           G_PARAM_READWRITE);
787
788         g_object_class_install_property (gobject_class,
789                                                                          TILDA_WINDOW_Y_POSITION,
790                                                                          pspec);
791
792         pspec = g_param_spec_int ("tab-position",
793                                                           _("Position of window's tab bar"),
794                                                           NULL,
795                                                           0,
796                                                           INT_MAX,
797                                                           0,
798                                                           G_PARAM_READWRITE);
799
800         g_object_class_install_property (gobject_class,
801                                                                          TILDA_WINDOW_TAB_POSITION,
802                                                                          pspec);
803
804         pspec = g_param_spec_int ("animation-orientation",
805                                                           _("Window's animation orientation"),
806                                                           NULL,
807                                                           0,
808                                                           INT_MAX,
809                                                           0,
810                                                           G_PARAM_READWRITE);
811
812         g_object_class_install_property (gobject_class,
813                                                                          TILDA_WINDOW_ANIMATION_ORIENTATION,
814                                                                          pspec);
815
816         pspec = g_param_spec_int ("animation-delay",
817                                                           _("Amount of time in milliseconds between animation intervals"),
818                                                           NULL,
819                                                           0,
820                                                           INT_MAX,
821                                                           0,
822                                                           G_PARAM_READWRITE);
823
824         g_object_class_install_property (gobject_class,
825                                                                          TILDA_WINDOW_ANIMATION_DELAY,
826                                                                          pspec);
827
828         pspec = g_param_spec_boolean ("keep-above",
829                                                                   _("Keep this window above all others"),
830                                                                   NULL,
831                                                                   FALSE,
832                                                                   G_PARAM_READWRITE);
833
834         g_object_class_install_property (gobject_class,
835                                                                          TILDA_WINDOW_KEEP_ABOVE,
836                                                                          pspec);
837
838         pspec = g_param_spec_boolean ("skip-taskbar-hint",
839                                                                   _("Hide this window in the taskbar if TRUE"),
840                                                                   NULL,
841                                                                   FALSE,
842                                                                   G_PARAM_READWRITE);
843
844         g_object_class_install_property (gobject_class,
845                                                                          TILDA_WINDOW_SKIP_TASKBAR_HINT,
846                                                                          pspec);
847
848         pspec = g_param_spec_boolean ("stick",
849                                                                   _("Display this window on all workspaces"),
850                                                                   NULL,
851                                                                   FALSE,
852                                                                   G_PARAM_READWRITE);
853
854         g_object_class_install_property (gobject_class,
855                                                                          TILDA_WINDOW_STICK,
856                                                                          pspec);
857
858         pspec = g_param_spec_boolean ("hidden-at-start",
859                                                                   _("Hide the window when it is first created"),
860                                                                   NULL,
861                                                                   FALSE,
862                                                                   G_PARAM_READWRITE);
863
864         g_object_class_install_property (gobject_class,
865                                                                          TILDA_WINDOW_HIDDEN_AT_START,
866                                                                          pspec);
867
868         pspec = g_param_spec_boolean ("centered-horizontally",
869                                                                   _("Center the window horizontally"),
870                                                                   NULL,
871                                                                   FALSE,
872                                                                   G_PARAM_READWRITE);
873
874         g_object_class_install_property (gobject_class,
875                                                                          TILDA_WINDOW_CENTERED_HORIZONTALLY,
876                                                                          pspec);
877
878         pspec = g_param_spec_boolean ("centered-vertically",
879                                                                   _("Center the window vertically"),
880                                                                   NULL,
881                                                                   FALSE,
882                                                                   G_PARAM_READWRITE);
883
884         g_object_class_install_property (gobject_class,
885                                                                          TILDA_WINDOW_CENTERED_VERTICALLY,
886                                                                          pspec);
887
888         pspec = g_param_spec_boolean ("have-real-transparency",
889                                                                   NULL, NULL, FALSE, G_PARAM_READABLE);
890
891         g_object_class_install_property (gobject_class,
892                                                                          TILDA_WINDOW_HAVE_REAL_TRANSPARENCY,
893                                                                          pspec);
894
895         /* Hook the TildaWindow type into DBus */
896         dbus_g_object_type_install_info (tilda_window_get_type(), &dbus_glib_tilda_window_object_info);
897 }
898
899 GType
900 tilda_window_get_type (void)
901 {
902         static GType type = 0;
903
904         if (type == 0)
905         {
906                 static const GTypeInfo info = {
907                         sizeof (TildaWindowClass),
908                         NULL,   /* base_init */
909                         NULL,   /* base_finalize */
910                         tilda_window_class_init,        /* class_init */
911                         NULL,   /* class_finalize */
912                         NULL,   /* class_data */
913                         sizeof (TildaWindow),
914                         0,              /* n_preallocs */
915                         tilda_window_instance_init,     /* instance_init */
916                 };
917
918                 type = g_type_register_static (G_TYPE_OBJECT,
919                                                                            "TildaWindowType",
920                                                                            &info,
921                                                                            0);
922         }
923
924         return type;
925 }
926
927 /* vim: set ts=4 sts=4 sw=4 noet tw=112: */