[Window] Set up real transparency if possible
[tilda-gobject.git] / tilda-window.c
1 #include "tilda.h"
2 #include "tilda-window.h"
3 #include "tilda-window-dbus-glue.h"
4
5 static gint
6 tilda_window_find_next_free_terminal_number (TildaWindow *tw)
7 {
8         gint i, j;
9         gboolean found;
10
11         for (i=0; i<INT_MAX; ++i)
12         {
13                 found = FALSE;
14
15                 for (j=0; j<tw->terms->len; ++j)
16                 {
17                         TildaTerminal *tt = g_ptr_array_index (tw->terms, j);
18
19                         if (tt->number == i)
20                         {
21                                 found = TRUE;
22                                 break;
23                         }
24                 }
25
26                 if (!found)
27                         return i;
28         }
29
30         return 0;
31 }
32
33 static gboolean
34 tilda_window_add_term (TildaWindow *tw)
35 {
36         gint number;
37         TildaTerminal *tt;
38
39         number = tilda_window_find_next_free_terminal_number (tw);
40         tt = g_object_new (TILDA_TYPE_TERMINAL,
41                                            "number", number,
42                                            "window-number", tw->number,
43                                            "parent-window", tw,
44                                            NULL);
45         g_ptr_array_add (tw->terms, tt);
46
47         GtkWidget *label = gtk_label_new ("Tilda");
48         gint index = gtk_notebook_prepend_page (GTK_NOTEBOOK(tw->notebook), tt->hbox, label);
49         gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK(tw->notebook), tt->hbox, TRUE, TRUE, GTK_PACK_END);
50         //gtk_notebook_set_current_page (GTK_NOTEBOOK(tw->notebook), index);
51
52         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK(tw->notebook)) > 1)
53                 gtk_notebook_set_show_tabs (GTK_NOTEBOOK(tw->notebook), TRUE);
54
55         return TRUE;
56 }
57
58 /**
59  * Remove the TildaTerminal with the given number from the given
60  * TildaWindow.
61  *
62  * Return: TRUE on success, FALSE otherwise.
63  */
64 gboolean
65 tilda_window_remove_term (TildaWindow *tw, gint terminal_number)
66 {
67         gint i;
68
69         for (i=0; i<tw->terms->len; ++i)
70         {
71                 TildaTerminal *tt = g_ptr_array_index (tw->terms, i);
72
73                 if (tt->number == terminal_number)
74                 {
75                         gint notebook_index = gtk_notebook_page_num (GTK_NOTEBOOK(tw->notebook), tt->hbox);
76
77                         /* Make sure the index was valid */
78                         if (notebook_index == -1)
79                         {
80                                 g_printerr ("DEBUG ERROR: Bad Notebook Tab\n");
81                                 return FALSE;
82                         }
83
84                         /* Actually remove the terminal */
85                         gtk_notebook_remove_page (GTK_NOTEBOOK (tw->notebook), notebook_index);
86
87                         /* We should hide the tabs if there is only one tab left */
88                         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (tw->notebook)) == 1)
89                                 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (tw->notebook), FALSE);
90
91 #if 0
92                         // FIXME FIXME FIXME: need to actually do the stuff below
93                         /* With no pages left, it's time to leave the program */
94                         if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (tw->notebook)) < 1)
95                                 gtk_main_quit ();
96 #endif
97
98                         /* Remove the term from our lists, then free it */
99                         g_ptr_array_remove_fast (tw->terms, tt);
100                         g_object_unref (G_OBJECT(tt));
101
102                         /* Leave the loop, we're done */
103                         break;
104                 }
105         }
106
107         return TRUE;
108 }
109
110 /**
111  * This sets up the given TildaWindow for the capability of real
112  * transparency, if the X server is capable of it. */
113 static void
114 tilda_window_setup_real_transparency (TildaWindow *self)
115 {
116         GdkScreen *screen;
117         GdkColormap *colormap;
118
119         screen = gtk_widget_get_screen (GTK_WIDGET(self->window));
120         colormap = gdk_screen_get_rgba_colormap (screen);
121
122         /* If possible, set the RGBA colormap so VTE can use real alpha
123          * channels for transparency. */
124         if (colormap != NULL && gdk_screen_is_composited (screen))
125         {
126                 gtk_widget_set_colormap (GTK_WIDGET(self->window), colormap);
127                 self->have_real_transparency = TRUE;
128                 return;
129         }
130
131         self->have_real_transparency = FALSE;
132 }
133
134 static void
135 tilda_window_dbus_register_object (TildaWindow *tw)
136 {
137         gchar *object_path;
138
139         // Register this object with DBus
140         object_path = g_strdup_printf ("/net/sourceforge/Tilda/Window%d", tw->number);
141         dbus_g_connection_register_g_object (dbus_connection, object_path, G_OBJECT(tw));
142         g_free (object_path);
143 }
144
145 /*******************************************************************************
146  * ALL GOBJECT STUFF BELOW PLEASE
147  ******************************************************************************/
148
149 static GObjectClass *parent_class = NULL;
150
151 enum tilda_window_properties {
152         TILDA_WINDOW_NUMBER = 1,
153
154         TILDA_WINDOW_HAVE_REAL_TRANSPARENCY,
155 };
156
157 static void
158 tilda_window_instance_init (GTypeInstance *instance,
159                                                         gpointer       g_class)
160 {
161         TildaWindow *self = (TildaWindow *) instance;
162         self->dispose_has_run = FALSE;
163
164         /* Initialize all properties */
165         self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
166         self->notebook = gtk_notebook_new ();
167         self->terms = g_ptr_array_new ();
168
169         /* Somewhat of a "poison" value, incase we don't set this */
170         self->number = 0xdeadbeef;
171 }
172
173 static void
174 tilda_window_set_property (GObject      *object,
175                                                    guint         property_id,
176                                                    const GValue *value,
177                                                    GParamSpec   *pspec)
178 {
179         TildaWindow *self = (TildaWindow *) object;
180
181         switch (property_id) {
182
183                 case TILDA_WINDOW_NUMBER:
184                         self->number = g_value_get_int (value);
185                         g_print ("window number: %d\n", self->number);
186                         break;
187
188                 case TILDA_WINDOW_HAVE_REAL_TRANSPARENCY:
189                         self->have_real_transparency = g_value_get_boolean (value);
190                         g_print ("window have real transp: %d\n", self->have_real_transparency);
191                         break;
192
193                 default:
194                         /* We don't have this property */
195                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
196                         break;
197         }
198 }
199
200 static void
201 tilda_window_get_property (GObject    *object,
202                                                    guint       property_id,
203                                                    GValue     *value,
204                                                    GParamSpec *pspec)
205 {
206         TildaWindow *self = (TildaWindow *) object;
207
208         switch (property_id) {
209
210                 case TILDA_WINDOW_NUMBER:
211                         g_value_set_int (value, self->number);
212                         break;
213
214                 case TILDA_WINDOW_HAVE_REAL_TRANSPARENCY:
215                         g_value_set_boolean (value, self->have_real_transparency);
216                         break;
217
218                 default:
219                         /* We don't have this property */
220                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
221                         break;
222         }
223 }
224
225 static GObject *
226 tilda_window_constructor (GType                  type,
227                                                   guint                  n_construct_properties,
228                                                   GObjectConstructParam *construct_properties)
229 {
230         GObject *obj;
231         TildaWindow *self;
232
233         /* Invoke parent constructor */
234         TildaWindowClass *klass;
235         klass = TILDA_WINDOW_CLASS (g_type_class_peek (TILDA_TYPE_WINDOW));
236         obj = parent_class->constructor (type,
237                                                                          n_construct_properties,
238                                                                          construct_properties);
239
240         /* Do other stuff here. The object is ready to go now, and all
241          * ctor properties have been set.
242          *
243          * TODO: This is the place to do DBus-init */
244         self = TILDA_WINDOW(obj);
245
246         /* Register this object with DBus */
247         tilda_window_dbus_register_object (self);
248
249         /* Try to set up real transparency */
250         tilda_window_setup_real_transparency (self);
251
252         gtk_container_add (GTK_CONTAINER(self->window), self->notebook);
253         gtk_widget_show (self->notebook);
254
255         tilda_window_add_term (self);
256         tilda_window_add_term (self);
257         gtk_widget_show_all (self->window);
258
259         return obj;
260 }
261
262 static void
263 my_unref (gpointer data, gpointer user_data)
264 {
265         g_object_unref (G_OBJECT(data));
266 }
267
268 static void
269 tilda_window_dispose (GObject *obj)
270 {
271         TildaWindow *self = (TildaWindow *) obj;
272
273         /* We don't want to run dispose twice, so just return immediately */
274         if (self->dispose_has_run)
275                 return;
276
277         /*
278          * In dispose, you are supposed to free all types referenced from this
279          * object which might themselves hold a reference to self. Generally,
280          * the most simple solution is to unref all members on which you own a
281          * reference.
282          *
283          * NOTE: See the following for how to deal with GtkObject-derived things:
284          * http://library.gnome.org/devel/gtk/unstable/GtkObject.html
285          */
286         g_ptr_array_foreach (self->terms, my_unref, NULL);
287         gtk_widget_destroy (self->window);
288
289         /* Chain up to the parent class */
290         G_OBJECT_CLASS (parent_class)->dispose (obj);
291 }
292
293 static void
294 tilda_window_finalize (GObject *obj)
295 {
296         TildaWindow *self = (TildaWindow *) obj;
297
298         /*
299          * Here, complete the object's destruction.
300          * You might not need to do much...
301          */
302         // TODO: g_free() any primitives here
303         g_ptr_array_free (self->terms, TRUE);
304
305
306         /* Chain up to the parent class */
307         G_OBJECT_CLASS (parent_class)->finalize (obj);
308 }
309
310 static void
311 tilda_window_class_init (gpointer g_class,
312                                                  gpointer g_class_data)
313 {
314         GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
315         TildaWindowClass *klass = TILDA_WINDOW_CLASS (g_class);
316         GParamSpec *pspec;
317
318         /* Hook our functions to this type */
319         gobject_class->set_property = tilda_window_set_property;
320         gobject_class->get_property = tilda_window_get_property;
321         gobject_class->dispose = tilda_window_dispose;
322         gobject_class->finalize = tilda_window_finalize;
323         gobject_class->constructor = tilda_window_constructor;
324
325         parent_class = g_type_class_peek_parent (klass);
326
327         /* Install all of the properties */
328         pspec = g_param_spec_int ("number",
329                                                           "Window number",
330                                                           "Set window's number",
331                                                           0,            // min value
332                                                           INT_MAX,      // max value
333                                                           0,            // def value
334                                                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
335
336         g_object_class_install_property (gobject_class,
337                                                                          TILDA_WINDOW_NUMBER,
338                                                                          pspec);
339
340         pspec = g_param_spec_boolean ("have-real-transparency",
341                                                                   NULL, NULL, FALSE, G_PARAM_READABLE);
342
343         g_object_class_install_property (gobject_class,
344                                                                          TILDA_WINDOW_HAVE_REAL_TRANSPARENCY,
345                                                                          pspec);
346
347         /* TODO: more properties */
348
349         /* Hook the TildaWindow type into DBus */
350         dbus_g_object_type_install_info (tilda_window_get_type(), &dbus_glib_tilda_window_object_info);
351 }
352
353 GType
354 tilda_window_get_type (void)
355 {
356         static GType type = 0;
357
358         if (type == 0)
359         {
360                 static const GTypeInfo info = {
361                         sizeof (TildaWindowClass),
362                         NULL,   /* base_init */
363                         NULL,   /* base_finalize */
364                         tilda_window_class_init,        /* class_init */
365                         NULL,   /* class_finalize */
366                         NULL,   /* class_data */
367                         sizeof (TildaWindow),
368                         0,              /* n_preallocs */
369                         tilda_window_instance_init,     /* instance_init */
370                 };
371
372                 type = g_type_register_static (G_TYPE_OBJECT,
373                                                                            "TildaWindowType",
374                                                                            &info,
375                                                                            0);
376         }
377
378         return type;
379 }
380
381 #if 0
382
383 int main (int argc, char *argv[])
384 {
385         GObject *tw;
386         gint test_number = INT_MIN;
387
388         /* Initialize the GObject type system */
389         g_type_init ();
390         gtk_init (&argc, &argv);
391
392         tw = g_object_new (TILDA_TYPE_WINDOW, "number", 10, NULL);
393         g_object_get (G_OBJECT (tw), "number", &test_number, NULL);
394         g_assert (test_number == 10);
395
396         g_object_unref (G_OBJECT (tw));
397
398         tw = g_object_new (TILDA_TYPE_WINDOW, "number", 22, NULL);
399         g_object_get (G_OBJECT (tw), "number", &test_number, NULL);
400         g_assert (test_number == 22);
401
402         gtk_main ();
403
404         g_object_unref (G_OBJECT (tw));
405
406         return 0;
407 }
408
409 #endif
410
411 /* vim: set ts=4 sts=4 sw=4 noet tw=112: */