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