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