Merge branch 'mgorse' of git+ssh://git.codethink.co.uk/git/atspi-dbus into rework
[platform/core/uifw/at-spi2-atk.git] / registryd / registry.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /* registry.c: the main accessibility service registry implementation */
25
26 #undef SPI_LISTENER_DEBUG
27 #undef SPI_DEBUG
28 #undef SPI_QUEUE_DEBUG
29
30 #include <config.h>
31 #ifdef SPI_DEBUG
32 #  include <stdio.h>
33 #endif
34
35 #include <spi-common/spi-dbus.h>
36
37 #include "registry.h"
38 #include "dbus/dbus-glib-lowlevel.h"
39
40 /* Our parent GObject type  */
41 #define PARENT_TYPE G_OBJECT_TYPE
42 <<<<<<< HEAD:registryd/registry.c
43 =======
44
45 >>>>>>> 6d509d490749c6bac3149a5ec45862352ffcf290:registryd/registry.c
46
47 int _dbg = 0;
48
49 typedef enum {
50   ETYPE_FOCUS,
51   ETYPE_OBJECT,
52   ETYPE_PROPERTY,
53   ETYPE_WINDOW,
54   ETYPE_TOOLKIT,
55   ETYPE_KEYBOARD,
56   ETYPE_MOUSE,
57   ETYPE_LAST_DEFINED
58 } EventTypeCategory;
59
60 typedef struct {
61   const char *event_name;
62   EventTypeCategory type_cat;
63   GQuark major;  /* from string segment[1] */
64   GQuark minor;  /* from string segment[1]+segment[2] */
65   GQuark detail; /* from string segment[3] (not concatenated) */
66 } EventTypeStruct;
67
68 G_DEFINE_TYPE(SpiRegistry, spi_registry, G_TYPE_OBJECT)
69
70 static void
71 spi_registry_set_debug (const char *debug_flag_string)
72 {
73   if (debug_flag_string) 
74     _dbg = (int) g_ascii_strtod (debug_flag_string, NULL);
75 }
76
77 static void emit(SpiRegistry *registry, const char *name, int first_type, ...)
78 {
79   va_list arg;
80
81   va_start(arg, first_type);
82   spi_dbus_emit_valist(registry->droute.bus, SPI_DBUS_PATH_REGISTRY, SPI_DBUS_INTERFACE_REGISTRY, name, first_type, arg);
83   va_end(arg);
84 }
85
86 static void
87 desktop_add_application (SpiDesktop *desktop,
88                          guint index, gpointer data)
89 {
90   SpiRegistry *registry = SPI_REGISTRY (data);
91   const char *name = g_list_nth_data(desktop->applications, index);
92   
93   emit(registry, "ApplicationAdd", DBUS_TYPE_UINT32, &index, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
94 }
95
96
97
98 static void
99 desktop_remove_application (SpiDesktop *desktop,
100                             guint index, gpointer data)
101 {
102   SpiRegistry *registry = SPI_REGISTRY (data);
103   const char *name = g_list_nth_data(desktop->applications, index);
104   
105   emit(registry, "ApplicationRemove", DBUS_TYPE_UINT32, &index, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
106 }
107
108
109 static void
110 spi_registry_object_finalize (GObject *object)
111 {
112   DBG (1, g_warning ("spi_registry_object_finalize called\n"));
113   g_object_unref (SPI_REGISTRY (object)->de_controller);
114
115   G_OBJECT_CLASS (spi_registry_parent_class)->finalize (object);
116 }
117
118 /**
119  * registerApplication:
120  * @application: a reference to the requesting @Application
121  * return values: void
122  *
123  * Register a new application with the accessibility broker.
124  *
125  **/
126 static DBusMessage *
127 impl_accessibility_registry_register_application (DBusConnection *bus, DBusMessage *message, void *user_data)
128 {
129   SpiRegistry *registry = SPI_REGISTRY (user_data);
130   const char *application = dbus_message_get_sender (message);
131
132 #ifdef SPI_DEBUG
133   fprintf (stderr, "registering app %s\n", application);
134 #endif
135   spi_desktop_add_application (registry->desktop, application);
136
137   /*
138    * TODO: change the implementation below to a WM-aware one;
139    * e.g. don't add all apps to the SpiDesktop
140    */
141   return dbus_message_new_method_return (message);
142 }
143
144 /**
145  * deregisterApplication:
146  * @application: a reference to the @Application
147  * to be deregistered.
148  * return values: void
149  *
150  * De-register an application previously registered with the broker.
151  *
152  **/
153 static DBusMessage *
154 impl_accessibility_registry_deregister_application (DBusConnection *bus, DBusMessage *message, void *user_data)
155 {
156   SpiRegistry *registry = SPI_REGISTRY (user_data);
157   const char *application = dbus_message_get_sender (message);
158
159   spi_desktop_remove_application (registry->desktop, application);
160
161 #ifdef SPI_DEBUG
162   fprintf (stderr, "de-registered app %s\n", application);
163 #endif
164   return dbus_message_new_method_return (message);
165 }
166
167 /**
168  * getDesktopCount:
169  * return values: a short integer indicating the current number of
170  * @Desktops.
171  *
172  * Get the current number of desktops.
173  *
174  **/
175 static DBusMessage *
176 impl_accessibility_registry_get_desktop_count (DBusConnection *bus, DBusMessage *message, void *user_data)
177 {
178   dbus_int16_t n_desktops = 1;
179   DBusMessage *reply;
180
181   /* TODO: implement support for multiple virtual desktops */
182   reply = dbus_message_new_method_return (message);
183   if (reply)
184   {
185     dbus_message_append_args (reply, DBUS_TYPE_INT16, &n_desktops, DBUS_TYPE_INVALID);
186   }
187   return reply;
188 }
189
190 /**
191  * getDesktop:
192  * @n: the index of the requested @Desktop.
193  * return values: a reference to the requested @Desktop.
194  *
195  * Get the nth accessible desktop.
196  *
197  **/
198 static DBusMessage *
199 impl_accessibility_registry_get_desktop (DBusConnection *bus, DBusMessage *message, void *user_data)
200 {
201   DBusError error;
202   dbus_int16_t n;
203   const char *path;
204   DBusMessage *reply;
205
206   /* TODO: implement support for multiple virtual desktops */
207   dbus_error_init (&error);
208   if (!dbus_message_get_args (message, &error, DBUS_TYPE_INT16, &n, DBUS_TYPE_INVALID))
209   {
210     return spi_dbus_general_error (message);
211   }
212   path = (n == 0? SPI_DBUS_PATH_DESKTOP: "/");
213   reply = dbus_message_new_method_return (message);
214   if (reply)
215   {
216     dbus_message_append_args (reply, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
217   }
218   return reply;
219 }
220
221
222 /**
223  * getDesktopList:
224  * return values: a sequence containing references to
225  * the @Desktops.
226  *
227  * Get a list of accessible desktops.
228  *
229  **/
230 static DBusMessage *
231 impl_accessibility_registry_get_desktop_list (DBusConnection *bus, DBusMessage *message, void *user_data)
232 {
233   DBusMessage *reply;
234   DBusMessageIter iter, iter_array;
235   const char *path = SPI_DBUS_PATH_DESKTOP;
236
237   reply = dbus_message_new_method_return (message);
238   if (!reply) return NULL;
239   dbus_message_iter_init_append(reply, &iter);
240   if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &iter_array)) goto oom;
241   dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_STRING, &path);
242   if (!dbus_message_iter_close_container (&iter, &iter_array)) goto oom;
243   return reply;
244 oom:
245   // TODO: handle out-of-memory
246   return reply;
247 }
248
249
250 static DBusMessage *
251 impl_accessibility_registry_get_device_event_controller (DBusConnection *bus, DBusMessage *message, void *user_data)
252 {
253   DBusMessage *reply;
254   const char *path = SPI_DBUS_PATH_DEC;
255
256   reply = dbus_message_new_method_return (message);
257   if (reply)
258   {
259     dbus_message_append_args (reply, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
260   }
261   return reply;
262 }
263
264
265 static void
266 spi_registry_class_init (SpiRegistryClass *klass)
267 {
268   GObjectClass * object_class = (GObjectClass *) klass;
269
270   spi_registry_parent_class = g_type_class_ref (G_TYPE_OBJECT);
271   
272   object_class->finalize = spi_registry_object_finalize;
273 }
274
275 static DBusObjectPathVTable droute_vtable =
276 {
277   NULL,
278   &droute_message,
279   NULL, NULL, NULL, NULL
280 };
281
282 static void
283 spi_registry_init (SpiRegistry *registry)
284 {
285   DBusError error;
286
287   spi_registry_set_debug (g_getenv ("AT_SPI_DEBUG"));
288   /*
289    * TODO: FIXME, this module makes the foolish assumptions that
290    * registryd uses the same display as the apps, and that the
291    * DISPLAY environment variable is set.
292    */
293   gdk_init (NULL, NULL);
294
295   registry->exit_notify_timeout = 200;
296   registry->queue_handler_id  = 0;
297
298   dbus_error_init (&error);
299   registry->droute.bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
300   if (!registry->droute.bus)
301   {
302     g_warning("Couldn't connect to dbus: %s\n", error.message);
303     return;
304   }
305   spi_registry_initialize_registry_interface (&registry->droute);
306   spi_registry_initialize_desktop_interface (&registry->droute);
307   spi_registry_initialize_dec_interface (&registry->droute);
308   // todo: initialize accessible and component interfaces, for desktop?
309   if (!dbus_connection_try_register_fallback (registry->droute.bus, "/org/freedesktop/atspi", &droute_vtable, &registry->droute, &error))
310   {
311     g_warning("Couldn't register droute.\n");
312   }
313   dbus_connection_setup_with_g_main(registry->droute.bus, g_main_context_default());
314
315   // TODO: decide whether focus_object is still relevant
316   registry->desktop = spi_desktop_new ();
317   /* Register callback notification for application addition and removal */
318   g_signal_connect (G_OBJECT (registry->desktop),
319                     "application_added",
320                     G_CALLBACK (desktop_add_application),
321                     registry);
322
323   g_signal_connect (G_OBJECT (registry->desktop),
324                     "application_removed",
325                     G_CALLBACK (desktop_remove_application),
326                     registry);
327
328   registry->de_controller = spi_device_event_controller_new (registry);
329 }
330
331 SpiRegistry *
332 spi_registry_new (void)
333 {
334   SpiRegistry *retval = g_object_new (SPI_REGISTRY_TYPE, NULL);
335   return retval;
336 }
337
338 static DRouteMethod methods[] =
339 {
340   { impl_accessibility_registry_register_application , "registerApplication" },
341   { impl_accessibility_registry_deregister_application, "deregisterApplication" },
342   { impl_accessibility_registry_get_desktop_count, "getDesktopCount" },
343   { impl_accessibility_registry_get_desktop, "getDesktop" },
344   { impl_accessibility_registry_get_desktop_list, "getDesktopList" },
345   { impl_accessibility_registry_get_device_event_controller, "getDeviceEventController" },
346   { NULL, NULL }
347 };
348
349 void
350 spi_registry_initialize_registry_interface (DRouteData * data)
351 {
352   droute_add_interface (data, "org.freedesktop.atspi.Registry", methods,
353                         NULL, NULL, NULL);
354 };