[Controller] Add initial-windows property
[tilda-gobject.git] / tilda-controller.c
1 #include "tilda.h"
2 #include "tilda-config.h"
3 #include "tilda-controller.h"
4 #include "tilda-controller-dbus-glue.h"
5 #include "tilda-window.h"
6
7 /**
8  * Register this object with DBus, so it can be interacted with!
9  */
10 static void
11 tilda_controller_dbus_register_object (TildaController *self)
12 {
13         debug_enter  ();
14         debug_assert (TILDA_IS_CONTROLLER(self));
15
16         static const gchar object_path[] = "/net/sourceforge/Tilda";
17
18         dbus_g_connection_register_g_object (dbus_connection, object_path, G_OBJECT(self));
19 }
20
21 /**
22  * Find the next free window number, so it can be used by a TildaWindow
23  */
24 static gint
25 tilda_controller_find_next_free_window_number (TildaController *self)
26 {
27         debug_enter  ();
28         debug_assert (TILDA_IS_CONTROLLER(self));
29
30         gint i, j;
31         gboolean found;
32
33         for (i=0; i<INT_MAX; ++i)
34         {
35                 found = FALSE;
36
37                 for (j=0; j<self->windows->len; ++j)
38                 {
39                         TildaWindow *tw = g_ptr_array_index (self->windows, j);
40
41                         if (tw->number == i)
42                         {
43                                 found = TRUE;
44                                 break;
45                         }
46                 }
47
48                 if (!found)
49                         return i;
50         }
51
52         return 0;
53 }
54
55 gboolean
56 tilda_controller_add_window (TildaController *self)
57 {
58         debug_enter  ();
59         debug_assert (TILDA_IS_CONTROLLER(self));
60
61         TildaWindow *ret;
62         gint number;
63
64         number = tilda_controller_find_next_free_window_number (self);
65         ret = g_object_new (TILDA_TYPE_WINDOW,
66                                                 "number", number,
67                                                 "controller", G_OBJECT(self),
68                                                 NULL);
69
70         g_ptr_array_add (self->windows, ret);
71
72         debug_printf ("Adding window: 0x%x (number %d of %d)\n", ret, ret->number, self->windows->len);
73         return TRUE;
74 }
75
76 gboolean
77 tilda_controller_remove_window (TildaController *self, gint window_number)
78 {
79         debug_enter  ();
80         debug_assert (TILDA_IS_CONTROLLER(self));
81         debug_assert (window_number >= 0);
82
83         gint i;
84         TildaWindow *win;
85
86         for (i=0; i<self->windows->len; ++i)
87         {
88                 win = g_ptr_array_index (self->windows, i);
89
90                 if (win->number == window_number)
91                 {
92                         debug_printf ("Deleting TildaWindow 0x%x (number %d of %d)\n",
93                                                   win, win->number, self->windows->len);
94                         g_ptr_array_remove_index (self->windows, i);
95                         g_object_unref (G_OBJECT(win));
96
97                         if (self->windows->len == 0)
98                         {
99                                 debug_printf ("No windows left, exiting...\n");
100
101                                 /* We get unref'd in main() */
102                                 gtk_main_quit ();
103                         }
104
105                         /* We were able to remove the window */
106                         return TRUE;
107                 }
108         }
109
110         /* There must have been no window to remove */
111         return FALSE;
112 }
113
114 /**
115  * Check if a key is used in one of our windows.
116  *
117  * This is needed because the tomboy_keybinder_bind() function allows
118  * more than one callback to be registered for the same key.
119  */
120 gboolean
121 tilda_controller_global_key_in_use (const TildaController *self, const gchar *keystr)
122 {
123         gint i;
124         TildaWindow *tw;
125
126         guint key1, key2;
127         GdkModifierType mod1, mod2;
128
129         gtk_accelerator_parse (keystr, &key1, &mod1);
130
131         for (i=0; i<self->windows->len; ++i)
132         {
133                 tw = g_ptr_array_index (self->windows, i);
134                 gtk_accelerator_parse (tw->key, &key2, &mod2);
135
136                 if (key1 == key2 && mod1 == mod2)
137                         return TRUE;
138         }
139
140         /* No identical keys found, we're ok */
141         return FALSE;
142 }
143
144 gboolean
145 tilda_controller_quit (TildaController *self, GError **error)
146 {
147         debug_enter  ();
148         debug_assert (TILDA_IS_CONTROLLER(self));
149
150         /* Not much left but to quit, since we get unref'd in main() */
151         gtk_main_quit ();
152
153         return TRUE;
154 }
155
156 /*******************************************************************************
157  * GObject code below... it is doubtful you'll need to make big changes :)
158  ******************************************************************************/
159
160 static GObjectClass *parent_class = NULL;
161
162 enum tilda_controller_properties {
163         TILDA_CONTROLLER_INITIAL_WINDOWS = 1,
164 };
165
166 static void
167 tilda_controller_instance_init (GTypeInstance *instance,
168                                                                 gpointer       g_class)
169 {
170         debug_enter ();
171
172         TildaController *self = (TildaController *) instance;
173
174         self->dispose_has_run = FALSE;
175         self->windows = g_ptr_array_new ();
176         self->initial_windows = 1;
177 }
178
179 static void
180 tilda_controller_set_property (GObject      *object,
181                                                            guint         property_id,
182                                                            const GValue *value,
183                                                            GParamSpec   *pspec)
184 {
185         debug_enter ();
186
187         TildaController *self = (TildaController *) object;
188
189         switch (property_id)
190         {
191                 case TILDA_CONTROLLER_INITIAL_WINDOWS:
192                         self->initial_windows = g_value_get_int (value);
193                         debug_printf ("tilda controller initial windows: %d\n", self->initial_windows);
194                         break;
195
196                 default:
197                         /* We don't have any other properties */
198                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
199                         break;
200         }
201 }
202
203 static void
204 tilda_controller_get_property (GObject    *object,
205                                                            guint       property_id,
206                                                            GValue     *value,
207                                                            GParamSpec *pspec)
208 {
209         debug_enter ();
210
211         TildaController *self = (TildaController *) object;
212
213         switch (property_id)
214         {
215                 case TILDA_CONTROLLER_INITIAL_WINDOWS:
216                         g_value_set_int (value, self->initial_windows);
217                         break;
218
219                 default:
220                         /* We don't have any other properties */
221                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
222                         break;
223         }
224 }
225
226 static GObject *
227 tilda_controller_constructor (GType                  type,
228                                                           guint                  n_construct_properties,
229                                                           GObjectConstructParam *construct_properties)
230 {
231         debug_enter ();
232
233         GObject *obj;
234         TildaController *self;
235         gint i;
236
237         /* Invoke the parent constructor */
238         TildaControllerClass *klass;
239         klass = TILDA_CONTROLLER_CLASS (g_type_class_peek (TILDA_TYPE_CONTROLLER));
240         obj = parent_class->constructor (type,
241                                                                          n_construct_properties,
242                                                                          construct_properties);
243         g_print ("%s all set up\n", __func__);
244
245         /* The object is ready, and all constructor-time properties have been set.
246          * Have fun! */
247         self = TILDA_CONTROLLER(obj);
248
249         /* Set all of the properties from the config */
250         tilda_controller_set_property_from_config (self, "initial-windows");
251
252         /* Add initial windows */
253         for (i=0; i<self->initial_windows; ++i)
254                 tilda_controller_add_window (self);
255
256         /* Register this object with DBus */
257         tilda_controller_dbus_register_object (self);
258
259         return obj;
260 }
261
262 static void
263 tilda_controller_dispose (GObject *obj)
264 {
265         debug_enter ();
266
267         TildaController *self = (TildaController *) obj;
268
269         /* We must only run dispose once ... */
270         if (self->dispose_has_run)
271                 return;
272
273         self->dispose_has_run = TRUE;
274
275         /*
276          * In dispose, you are supposed to free all types referenced from this
277          * object which might themselves hold a reference to self. Generally,
278          * the most simple solution is to unref all members on which you own a
279          * reference.
280          */
281         g_ptr_array_foreach (self->windows, g_object_unref, NULL);
282
283         /* Chain up to the parent class */
284         G_OBJECT_CLASS (parent_class)->dispose (obj);
285 }
286
287 static void
288 tilda_controller_finalize (GObject *obj)
289 {
290         debug_enter ();
291
292         TildaController *self = (TildaController *) obj;
293
294         /*
295          * Here, complete the object's destruction.
296          * You might not need to do much more than
297          * g_free() any primitives.
298          */
299
300         /* Chain up to the parent class */
301         G_OBJECT_CLASS (parent_class)->finalize (obj);
302 }
303
304 static void
305 tilda_controller_class_init (gpointer g_class,
306                                                          gpointer g_class_data)
307 {
308         debug_enter ();
309
310         GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
311         TildaControllerClass *klass = TILDA_CONTROLLER_CLASS (g_class);
312         GParamSpec *pspec;
313
314         gobject_class->set_property = tilda_controller_set_property;
315         gobject_class->get_property = tilda_controller_get_property;
316         gobject_class->dispose = tilda_controller_dispose;
317         gobject_class->finalize = tilda_controller_finalize;
318         gobject_class->constructor = tilda_controller_constructor;
319
320         parent_class = g_type_class_peek_parent (klass);
321
322         /* Add properties here */
323         pspec = g_param_spec_int ("initial-windows",
324                                                           _("The number of windows that will be opened on startup"),
325                                                           NULL,
326                                                           1,
327                                                           100, /* Sane Limit */
328                                                           1,
329                                                           G_PARAM_READWRITE);
330
331         g_object_class_install_property (gobject_class,
332                                                                          TILDA_CONTROLLER_INITIAL_WINDOWS,
333                                                                          pspec);
334
335         /* Hook the TildaController type into DBus */
336         dbus_g_object_type_install_info (tilda_controller_get_type(),
337                                                                          &dbus_glib_tilda_controller_object_info);
338 }
339
340 GType tilda_controller_get_type (void)
341 {
342         static GType type = 0;
343
344         if (type == 0)
345         {
346                 static const GTypeInfo info = {
347                         sizeof (TildaControllerClass),
348                         NULL,   /* base_init */
349                         NULL,   /* base_finalize */
350                         tilda_controller_class_init,    /* class_init */
351                         NULL,   /* class_finalize */
352                         NULL,   /* class_data */
353                         sizeof (TildaController),
354                         0,              /* n_preallocs */
355                         tilda_controller_instance_init, /* instance_init */
356                 };
357
358                 type = g_type_register_static (G_TYPE_OBJECT,
359                                                                            "TildaControllerType",
360                                                                            &info,
361                                                                            0);
362         }
363
364         return type;
365 }
366
367 /* vim: set ts=4 sts=4 sw=4 noet tw=112: */