[Window] Focus new VteTerminals when adding a new tab
[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         // FIXME: this doesn't handle animation!
234
235         switch (self->state)
236         {
237                 case WINDOW_UP: /* Pull the window up */
238
239                         /* Bugfix: having this here keeps the tilda window from being
240                          * hidden if you turn off "stick", pull it down on workspace 1,
241                          * switch to workspace 2, then pull it up and back down. Without
242                          * this, something in metacity (at least) hides the window. Stupid. */
243                         gtk_window_deiconify (GTK_WINDOW(self->window));
244
245                         /* Re-set the window properties that do not linger after hiding the
246                          * window. I know this looks stupid, but it keeps all of the state-
247                          * changing code in the place it belongs: the property-setting code. */
248                         g_object_set (G_OBJECT(self),
249                                         "keep-above", self->keep_above,
250                                         "stick", self->stick,
251                                         NULL);
252                         gtk_window_present_with_time (GTK_WINDOW(self->window),
253                                                                                   tomboy_keybinder_get_current_event_time());
254
255                         /* Focusing the term here works perfectly, near as I can tell */
256                         tt = tilda_window_find_current_terminal (self);
257                         gtk_widget_grab_focus (GTK_WIDGET(tt->vte_term));
258
259                         self->state = WINDOW_DOWN;
260                         break;
261
262                 case WINDOW_DOWN: /* Pull the window up */
263
264                         gtk_widget_hide (GTK_WIDGET(self->window));
265
266                         self->state = WINDOW_UP;
267                         break;
268
269                 default:
270                         debug_printf ("ERROR: Window is in a bad state!\n");
271
272                         /* Pretend we're down, for good measure.... */
273                         self->state = WINDOW_DOWN;
274                         break;
275         }
276 }
277
278 /**
279  * Attempt to bind the new_key to show this window.
280  *
281  * Return: TRUE if successful, FALSE otherwise.
282  */
283 static gboolean
284 tilda_window_try_to_bind_key (TildaWindow *self, const gchar *new_key)
285 {
286         debug_enter  ();
287         debug_assert (TILDA_IS_WINDOW(self));
288
289         gboolean ret = FALSE;
290
291         /* Make sure the new key is not null in any way */
292         if (new_key == NULL || strcmp("", new_key) == 0)
293                 return FALSE;
294
295         /* Unbind if we were set */
296         if (self->key)
297                 tomboy_keybinder_unbind (self->key, tilda_window_keybinding_cb);
298
299         ret = tomboy_keybinder_bind (new_key, tilda_window_keybinding_cb, self);
300
301         /* If it was successful, update the self->key variable and be done with it */
302         if (ret)
303         {
304                 g_free (self->key);
305                 self->key = g_strdup (new_key);
306                 return TRUE;
307         }
308
309         g_printerr (_("Bind key '%s' failed. Reverting to original keybinding\n"), self->key);
310
311         /* Not successful, so rebind the old key, and return FALSE */
312         if (self->key != NULL && strcmp("",self->key) != 0)
313         {
314                 ret = tomboy_keybinder_bind (self->key, tilda_window_keybinding_cb, self);
315
316                 /* Check that it went ok */
317                 if (!ret)
318                         g_printerr (_("Unable to re-bind original key '%s'. Oh shit...\n"), self->key);
319         }
320         else
321                 g_printerr (_("No original key to revert to!\n"));
322
323         return FALSE;
324 }
325
326 static void
327 tilda_window_dbus_register_object (TildaWindow *self)
328 {
329         debug_enter  ();
330         debug_assert (TILDA_IS_WINDOW(self));
331
332         gchar *object_path;
333
334         // Register this object with DBus
335         object_path = g_strdup_printf ("/net/sourceforge/Tilda/Window%d", self->number);
336         dbus_g_connection_register_g_object (dbus_connection, object_path, G_OBJECT(self));
337         g_free (object_path);
338 }
339
340 /*******************************************************************************
341  * ALL GOBJECT STUFF BELOW PLEASE
342  ******************************************************************************/
343
344 static GObjectClass *parent_class = NULL;
345
346 enum tilda_window_properties {
347         TILDA_WINDOW_NUMBER = 1,
348
349         TILDA_WINDOW_KEY,
350
351         TILDA_WINDOW_HEIGHT,
352         TILDA_WINDOW_WIDTH,
353         TILDA_WINDOW_X_POSITION,
354         TILDA_WINDOW_Y_POSITION,
355
356         TILDA_WINDOW_TAB_POSITION,
357         TILDA_WINDOW_ANIMATION_ORIENTATION,
358         TILDA_WINDOW_ANIMATION_DELAY,
359
360         TILDA_WINDOW_KEEP_ABOVE,
361         TILDA_WINDOW_SKIP_TASKBAR_HINT,
362         TILDA_WINDOW_STICK,
363         TILDA_WINDOW_HIDDEN_AT_START,
364         TILDA_WINDOW_CENTERED_HORIZONTALLY,
365         TILDA_WINDOW_CENTERED_VERTICALLY,
366
367         TILDA_WINDOW_HAVE_REAL_TRANSPARENCY,
368 };
369
370 static void
371 tilda_window_instance_init (GTypeInstance *instance,
372                                                         gpointer       g_class)
373 {
374         debug_enter ();
375
376         TildaWindow *self = (TildaWindow *) instance;
377         self->dispose_has_run = FALSE;
378
379         /* Initialize all properties */
380         self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
381         self->notebook = gtk_notebook_new ();
382         self->terms = g_ptr_array_new ();
383
384         /* Somewhat of a "poison" value, incase we don't set this */
385         self->number = 0xdeadbeef;
386
387         self->state = WINDOW_UP;
388 }
389
390 static void
391 tilda_window_set_property (GObject      *object,
392                                                    guint         property_id,
393                                                    const GValue *value,
394                                                    GParamSpec   *pspec)
395 {
396         TildaWindow *self = (TildaWindow *) object;
397
398         switch (property_id) {
399
400                 case TILDA_WINDOW_NUMBER:
401                         self->number = g_value_get_int (value);
402                         debug_printf ("window number: %d\n", self->number);
403                         break;
404
405                 case TILDA_WINDOW_KEY:
406                         tilda_window_try_to_bind_key (self, g_value_get_string (value));
407                         debug_printf ("window key %s\n", self->key);
408                         break;
409
410                 case TILDA_WINDOW_HEIGHT:
411                         self->height = g_value_get_int (value);
412                         gtk_widget_set_size_request (self->window, self->width, self->height);
413                         gtk_window_resize (GTK_WINDOW(self->window), self->width, self->height);
414                         debug_printf ("window height: %d\n", self->height);
415                         break;
416
417                 case TILDA_WINDOW_WIDTH:
418                         self->width = g_value_get_int (value);
419                         gtk_widget_set_size_request (self->window, self->width, self->height);
420                         gtk_window_resize (GTK_WINDOW(self->window), self->width, self->height);
421                         debug_printf ("window width: %d\n", self->width);
422                         break;
423
424                 case TILDA_WINDOW_X_POSITION:
425                         self->x_position = g_value_get_int (value);
426                         gtk_window_move (GTK_WINDOW(self->window), self->x_position, self->y_position);
427                         debug_printf ("window x position: %d\n", self->x_position);
428                         break;
429
430                 case TILDA_WINDOW_Y_POSITION:
431                         self->y_position = g_value_get_int (value);
432                         gtk_window_move (GTK_WINDOW(self->window), self->x_position, self->y_position);
433                         debug_printf ("window y position: %d\n", self->y_position);
434                         break;
435
436                 case TILDA_WINDOW_TAB_POSITION:
437                         self->tab_position = g_value_get_int (value);
438                         gtk_notebook_set_tab_pos (GTK_NOTEBOOK(self->notebook), self->tab_position);
439                         debug_printf ("window tab position: %d\n", self->tab_position);
440                         break;
441
442                 case TILDA_WINDOW_ANIMATION_ORIENTATION:
443                         self->animation_orientation = g_value_get_int (value);
444                         debug_printf ("window animation orientation: %d\n", self->animation_orientation);
445                         break;
446
447                 case TILDA_WINDOW_ANIMATION_DELAY:
448                         self->animation_delay = g_value_get_int (value);
449                         debug_printf ("window animation delay: %d\n", self->animation_delay);
450                         break;
451
452                 case TILDA_WINDOW_KEEP_ABOVE:
453                         self->keep_above = g_value_get_boolean (value);
454                         gtk_window_set_keep_above (GTK_WINDOW(self->window), self->keep_above);
455                         debug_printf ("window keep above: %d\n", self->keep_above);
456                         break;
457
458                 case TILDA_WINDOW_SKIP_TASKBAR_HINT:
459                         self->skip_taskbar_hint = g_value_get_boolean (value);
460                         gtk_window_set_skip_taskbar_hint (GTK_WINDOW(self->window), self->skip_taskbar_hint);
461                         debug_printf ("window skip taskbar hint: %d\n", self->skip_taskbar_hint);
462                         break;
463
464                 case TILDA_WINDOW_STICK:
465                         self->stick = g_value_get_boolean (value);
466
467                         /* This is moderately ugly, but GTK+ does it this way... */
468                         self->stick ? gtk_window_stick (GTK_WINDOW(self->window))
469                                                 : gtk_window_unstick (GTK_WINDOW(self->window));
470                         debug_printf ("window stick: %d\n", self->stick);
471                         break;
472
473                 case TILDA_WINDOW_HIDDEN_AT_START:
474                         self->hidden_at_start = g_value_get_boolean (value);
475                         debug_printf ("window hidden at start: %d\n", self->hidden_at_start);
476                         break;
477
478                 case TILDA_WINDOW_CENTERED_HORIZONTALLY:
479                         self->centered_horizontally = g_value_get_boolean (value);
480                         if (self->centered_horizontally)
481                                 tilda_window_center_horizontally (self);
482                         debug_printf ("window centered horizontally: %d\n", self->centered_horizontally);
483                         break;
484
485                 case TILDA_WINDOW_CENTERED_VERTICALLY:
486                         self->centered_vertically = g_value_get_boolean (value);
487                         if (self->centered_vertically)
488                                 tilda_window_center_vertically (self);
489                         debug_printf ("window centered vertically: %d\n", self->centered_vertically);
490                         break;
491
492                 case TILDA_WINDOW_HAVE_REAL_TRANSPARENCY:
493                         self->have_real_transparency = g_value_get_boolean (value);
494                         debug_printf ("window have real transp: %d\n", self->have_real_transparency);
495                         break;
496
497                 default:
498                         /* We don't have this property */
499                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
500                         break;
501         }
502 }
503
504 static void
505 tilda_window_get_property (GObject    *object,
506                                                    guint       property_id,
507                                                    GValue     *value,
508                                                    GParamSpec *pspec)
509 {
510         TildaWindow *self = (TildaWindow *) object;
511
512         switch (property_id) {
513
514                 case TILDA_WINDOW_NUMBER:
515                         g_value_set_int (value, self->number);
516                         break;
517
518                 case TILDA_WINDOW_KEY:
519                         g_value_set_string (value, self->key);
520                         break;
521
522                 case TILDA_WINDOW_HEIGHT:
523                         g_value_set_int (value, self->height);
524                         break;
525
526                 case TILDA_WINDOW_WIDTH:
527                         g_value_set_int (value, self->width);
528                         break;
529
530                 case TILDA_WINDOW_X_POSITION:
531                         g_value_set_int (value, self->x_position);
532                         break;
533
534                 case TILDA_WINDOW_Y_POSITION:
535                         g_value_set_int (value, self->y_position);
536                         break;
537
538                 case TILDA_WINDOW_TAB_POSITION:
539                         g_value_set_int (value, self->tab_position);
540                         break;
541
542                 case TILDA_WINDOW_ANIMATION_ORIENTATION:
543                         g_value_set_int (value, self->animation_orientation);
544                         break;
545
546                 case TILDA_WINDOW_ANIMATION_DELAY:
547                         g_value_set_int (value, self->animation_delay);
548                         break;
549
550                 case TILDA_WINDOW_KEEP_ABOVE:
551                         g_value_set_boolean (value, self->keep_above);
552                         break;
553
554                 case TILDA_WINDOW_SKIP_TASKBAR_HINT:
555                         g_value_set_boolean (value, self->skip_taskbar_hint);
556                         break;
557
558                 case TILDA_WINDOW_STICK:
559                         g_value_set_boolean (value, self->stick);
560                         break;
561
562                 case TILDA_WINDOW_HIDDEN_AT_START:
563                         g_value_set_boolean (value, self->hidden_at_start);
564                         break;
565
566                 case TILDA_WINDOW_CENTERED_HORIZONTALLY:
567                         g_value_set_boolean (value, self->centered_horizontally);
568                         break;
569
570                 case TILDA_WINDOW_CENTERED_VERTICALLY:
571                         g_value_set_boolean (value, self->centered_vertically);
572                         break;
573
574                 case TILDA_WINDOW_HAVE_REAL_TRANSPARENCY:
575                         g_value_set_boolean (value, self->have_real_transparency);
576                         break;
577
578                 default:
579                         /* We don't have this property */
580                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
581                         break;
582         }
583 }
584
585 static GObject *
586 tilda_window_constructor (GType                  type,
587                                                   guint                  n_construct_properties,
588                                                   GObjectConstructParam *construct_properties)
589 {
590         debug_enter ();
591
592         GObject *obj;
593         TildaWindow *self;
594
595         /* Invoke parent constructor */
596         TildaWindowClass *klass;
597         klass = TILDA_WINDOW_CLASS (g_type_class_peek (TILDA_TYPE_WINDOW));
598         obj = parent_class->constructor (type,
599                                                                          n_construct_properties,
600                                                                          construct_properties);
601
602         /* Do other stuff here. The object is ready to go now, and all
603          * ctor properties have been set.
604          */
605         self = TILDA_WINDOW(obj);
606
607         /* Register this object with DBus */
608         tilda_window_dbus_register_object (self);
609
610         /* Try to set up real transparency */
611         tilda_window_setup_real_transparency (self);
612
613         gtk_container_add (GTK_CONTAINER(self->window), self->notebook);
614         gtk_widget_show (self->notebook);
615
616         // FIXME: Remove these, and replace with reads from the config system
617         g_object_set (G_OBJECT(self), "key", "F2", NULL);
618         g_object_set (G_OBJECT(self), "x-position", 0, "y-position", 0, NULL);
619         g_object_set (G_OBJECT(self), "height", 400, "width", 1680, NULL);
620         g_object_set (G_OBJECT(self), "keep-above", TRUE, "stick", TRUE, NULL);
621         g_object_set (G_OBJECT(self), "hidden-at-start", FALSE, NULL);
622
623         gtk_window_set_decorated (GTK_WINDOW(self->window), FALSE);
624
625         // FIXME: It should be configurable how many terms we add at startup
626         tilda_window_add_terminal (self);
627         tilda_window_add_terminal (self);
628
629         /* Show us if we're ready. If not, just remain hidden. All sub-widgets must
630          * be gtk_widget_show()n by this point. */
631         if (!self->hidden_at_start)
632         {
633                 gtk_widget_show (self->window);
634                 self->state = WINDOW_DOWN;
635         }
636         else
637                 self->state = WINDOW_UP;
638
639         return obj;
640 }
641
642 static void
643 my_unref (gpointer data, gpointer user_data)
644 {
645         debug_enter ();
646
647         // FIXME: This function should probably be eliminated. It /is/ rather ugly
648         g_object_unref (G_OBJECT(data));
649 }
650
651 static void
652 tilda_window_dispose (GObject *obj)
653 {
654         debug_enter ();
655
656         TildaWindow *self = (TildaWindow *) obj;
657
658         /* We don't want to run dispose twice, so just return immediately */
659         if (self->dispose_has_run)
660                 return;
661
662         /*
663          * In dispose, you are supposed to free all types referenced from this
664          * object which might themselves hold a reference to self. Generally,
665          * the most simple solution is to unref all members on which you own a
666          * reference.
667          *
668          * NOTE: See the following for how to deal with GtkObject-derived things:
669          * http://library.gnome.org/devel/gtk/unstable/GtkObject.html
670          */
671         g_ptr_array_foreach (self->terms, my_unref, NULL);
672         gtk_widget_destroy (self->window);
673
674         /* Chain up to the parent class */
675         G_OBJECT_CLASS (parent_class)->dispose (obj);
676 }
677
678 static void
679 tilda_window_finalize (GObject *obj)
680 {
681         debug_enter ();
682
683         TildaWindow *self = (TildaWindow *) obj;
684
685         /*
686          * Here, complete the object's destruction.
687          * You might not need to do much...
688          */
689         // TODO: g_free() any primitives here
690         g_ptr_array_free (self->terms, TRUE);
691
692
693         /* Chain up to the parent class */
694         G_OBJECT_CLASS (parent_class)->finalize (obj);
695 }
696
697 static void
698 tilda_window_class_init (gpointer g_class,
699                                                  gpointer g_class_data)
700 {
701         debug_enter ();
702
703         GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
704         TildaWindowClass *klass = TILDA_WINDOW_CLASS (g_class);
705         GParamSpec *pspec;
706
707         /* Hook our functions to this type */
708         gobject_class->set_property = tilda_window_set_property;
709         gobject_class->get_property = tilda_window_get_property;
710         gobject_class->dispose = tilda_window_dispose;
711         gobject_class->finalize = tilda_window_finalize;
712         gobject_class->constructor = tilda_window_constructor;
713
714         parent_class = g_type_class_peek_parent (klass);
715
716         /* Install all of the properties */
717         pspec = g_param_spec_int ("number",
718                                                           _("Window number"),
719                                                           NULL,
720                                                           0,            // min value
721                                                           INT_MAX,      // max value
722                                                           0,            // def value
723                                                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
724
725         g_object_class_install_property (gobject_class,
726                                                                          TILDA_WINDOW_NUMBER,
727                                                                          pspec);
728
729         pspec = g_param_spec_string ("key",
730                                                                  _("Window's drop-down keybinding"),
731                                                                  NULL,
732                                                                  NULL,
733                                                                  G_PARAM_READWRITE);
734
735         g_object_class_install_property (gobject_class,
736                                                                          TILDA_WINDOW_KEY,
737                                                                          pspec);
738
739         pspec = g_param_spec_int ("height",
740                                                           _("Window's height"),
741                                                           NULL,
742                                                           0,
743                                                           INT_MAX,
744                                                           0,
745                                                           G_PARAM_READWRITE);
746
747         g_object_class_install_property (gobject_class,
748                                                                          TILDA_WINDOW_HEIGHT,
749                                                                          pspec);
750
751         pspec = g_param_spec_int ("width",
752                                                           _("Window's width"),
753                                                           NULL,
754                                                           0,
755                                                           INT_MAX,
756                                                           0,
757                                                           G_PARAM_READWRITE);
758
759         g_object_class_install_property (gobject_class,
760                                                                          TILDA_WINDOW_WIDTH,
761                                                                          pspec);
762
763         pspec = g_param_spec_int ("x-position",
764                                                           _("Window's x position"),
765                                                           NULL,
766                                                           0,
767                                                           INT_MAX,
768                                                           0,
769                                                           G_PARAM_READWRITE);
770
771         g_object_class_install_property (gobject_class,
772                                                                          TILDA_WINDOW_X_POSITION,
773                                                                          pspec);
774
775         pspec = g_param_spec_int ("y-position",
776                                                           _("Window's y position"),
777                                                           NULL,
778                                                           0,
779                                                           INT_MAX,
780                                                           0,
781                                                           G_PARAM_READWRITE);
782
783         g_object_class_install_property (gobject_class,
784                                                                          TILDA_WINDOW_Y_POSITION,
785                                                                          pspec);
786
787         pspec = g_param_spec_int ("tab-position",
788                                                           _("Position of window's tab bar"),
789                                                           NULL,
790                                                           0,
791                                                           INT_MAX,
792                                                           0,
793                                                           G_PARAM_READWRITE);
794
795         g_object_class_install_property (gobject_class,
796                                                                          TILDA_WINDOW_TAB_POSITION,
797                                                                          pspec);
798
799         pspec = g_param_spec_int ("animation-orientation",
800                                                           _("Window's animation orientation"),
801                                                           NULL,
802                                                           0,
803                                                           INT_MAX,
804                                                           0,
805                                                           G_PARAM_READWRITE);
806
807         g_object_class_install_property (gobject_class,
808                                                                          TILDA_WINDOW_ANIMATION_ORIENTATION,
809                                                                          pspec);
810
811         pspec = g_param_spec_int ("animation-delay",
812                                                           _("Amount of time in milliseconds between animation intervals"),
813                                                           NULL,
814                                                           0,
815                                                           INT_MAX,
816                                                           0,
817                                                           G_PARAM_READWRITE);
818
819         g_object_class_install_property (gobject_class,
820                                                                          TILDA_WINDOW_ANIMATION_DELAY,
821                                                                          pspec);
822
823         pspec = g_param_spec_boolean ("keep-above",
824                                                                   _("Keep this window above all others"),
825                                                                   NULL,
826                                                                   FALSE,
827                                                                   G_PARAM_READWRITE);
828
829         g_object_class_install_property (gobject_class,
830                                                                          TILDA_WINDOW_KEEP_ABOVE,
831                                                                          pspec);
832
833         pspec = g_param_spec_boolean ("skip-taskbar-hint",
834                                                                   _("Hide this window in the taskbar if TRUE"),
835                                                                   NULL,
836                                                                   FALSE,
837                                                                   G_PARAM_READWRITE);
838
839         g_object_class_install_property (gobject_class,
840                                                                          TILDA_WINDOW_SKIP_TASKBAR_HINT,
841                                                                          pspec);
842
843         pspec = g_param_spec_boolean ("stick",
844                                                                   _("Display this window on all workspaces"),
845                                                                   NULL,
846                                                                   FALSE,
847                                                                   G_PARAM_READWRITE);
848
849         g_object_class_install_property (gobject_class,
850                                                                          TILDA_WINDOW_STICK,
851                                                                          pspec);
852
853         pspec = g_param_spec_boolean ("hidden-at-start",
854                                                                   _("Hide the window when it is first created"),
855                                                                   NULL,
856                                                                   FALSE,
857                                                                   G_PARAM_READWRITE);
858
859         g_object_class_install_property (gobject_class,
860                                                                          TILDA_WINDOW_HIDDEN_AT_START,
861                                                                          pspec);
862
863         pspec = g_param_spec_boolean ("centered-horizontally",
864                                                                   _("Center the window horizontally"),
865                                                                   NULL,
866                                                                   FALSE,
867                                                                   G_PARAM_READWRITE);
868
869         g_object_class_install_property (gobject_class,
870                                                                          TILDA_WINDOW_CENTERED_HORIZONTALLY,
871                                                                          pspec);
872
873         pspec = g_param_spec_boolean ("centered-vertically",
874                                                                   _("Center the window vertically"),
875                                                                   NULL,
876                                                                   FALSE,
877                                                                   G_PARAM_READWRITE);
878
879         g_object_class_install_property (gobject_class,
880                                                                          TILDA_WINDOW_CENTERED_VERTICALLY,
881                                                                          pspec);
882
883         pspec = g_param_spec_boolean ("have-real-transparency",
884                                                                   NULL, NULL, FALSE, G_PARAM_READABLE);
885
886         g_object_class_install_property (gobject_class,
887                                                                          TILDA_WINDOW_HAVE_REAL_TRANSPARENCY,
888                                                                          pspec);
889
890         /* Hook the TildaWindow type into DBus */
891         dbus_g_object_type_install_info (tilda_window_get_type(), &dbus_glib_tilda_window_object_info);
892 }
893
894 GType
895 tilda_window_get_type (void)
896 {
897         static GType type = 0;
898
899         if (type == 0)
900         {
901                 static const GTypeInfo info = {
902                         sizeof (TildaWindowClass),
903                         NULL,   /* base_init */
904                         NULL,   /* base_finalize */
905                         tilda_window_class_init,        /* class_init */
906                         NULL,   /* class_finalize */
907                         NULL,   /* class_data */
908                         sizeof (TildaWindow),
909                         0,              /* n_preallocs */
910                         tilda_window_instance_init,     /* instance_init */
911                 };
912
913                 type = g_type_register_static (G_TYPE_OBJECT,
914                                                                            "TildaWindowType",
915                                                                            &info,
916                                                                            0);
917         }
918
919         return type;
920 }
921
922 /* vim: set ts=4 sts=4 sw=4 noet tw=112: */