e2d84897395f33de1fea19c56ff796d607c036cf
[platform/upstream/at-spi2-core.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 2008, 2010 Codethink Ltd.
6  * Copyright 2001, 2002 Sun Microsystems Inc.,
7  * Copyright 2001, 2002 Ximian, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include <config.h>
26 #include <string.h>
27 #include <dbus/dbus-glib-lowlevel.h>
28
29 #include "paths.h"
30 #include "registry.h"
31
32 static gboolean
33 children_added_listener (DBusConnection * bus,
34                          gint             index,
35                          const gchar    * name,
36                          const gchar    * path);
37
38 static gboolean
39 children_removed_listener (DBusConnection * bus,
40                            gint             index,
41                            const gchar    * name,
42                            const gchar    * path);
43
44 /*---------------------------------------------------------------------------*/
45
46 typedef struct _SpiReference
47 {
48   gchar *name;
49   gchar *path;
50 } SpiReference;
51
52 static SpiReference *
53 spi_reference_new (const gchar *name, const gchar *path)
54 {
55   SpiReference *ref;
56
57   ref = g_new0 (SpiReference, 1);
58   ref->name = g_strdup (name);
59   ref->path = g_strdup (path);
60
61   return ref;
62 }
63
64 static void
65 spi_reference_free (SpiReference *ref)
66 {
67   g_free (ref->name);
68   g_free (ref->path);
69   g_free (ref);
70 }
71
72 /*---------------------------------------------------------------------------*/
73
74 G_DEFINE_TYPE(SpiRegistry, spi_registry, G_TYPE_OBJECT)
75
76 static void
77 spi_registry_class_init (SpiRegistryClass *klass)
78 {
79   GObjectClass * object_class = (GObjectClass *) klass;
80
81   spi_registry_parent_class = g_type_class_ref (G_TYPE_OBJECT);
82 }
83
84 static void
85 spi_registry_init (SpiRegistry *registry)
86 {
87   registry->apps = g_ptr_array_new_with_free_func ((GDestroyNotify) spi_reference_free);
88 }
89
90 /*---------------------------------------------------------------------------*/
91
92 static dbus_bool_t
93 return_v_string (DBusMessageIter * iter, const gchar * str)
94 {
95   DBusMessageIter variant;
96
97   dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "s",
98                                     &variant);
99     dbus_message_iter_append_basic (&variant, DBUS_TYPE_STRING, &str);
100   dbus_message_iter_close_container (iter, &variant);
101 }
102
103 static void
104 append_reference (DBusMessageIter * iter, const char * name, const char * path)
105 {
106   DBusMessageIter iter_struct;
107
108   dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
109                                     &iter_struct);
110   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
111   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
112   dbus_message_iter_close_container (iter, &iter_struct);
113 }
114
115 /*---------------------------------------------------------------------------*/
116
117 static gboolean
118 compare_reference (SpiReference *one, SpiReference *two)
119 {
120   if (g_strcmp0 (one->name, two->name) == 0 &&
121       g_strcmp0 (one->path, two->path) == 0)
122     return TRUE;
123   else
124     return FALSE;
125 }
126
127 static gboolean
128 find_index_of_reference (GPtrArray *arr, const gchar *name, const gchar * path, guint *index)
129 {
130   SpiReference *ref;
131   gboolean found = FALSE;
132   guint i = 0;
133
134   ref = spi_reference_new (name, path);
135
136   for (i = 0; i < arr->len && found == FALSE; i++)
137     {
138       if (compare_reference (ref, g_ptr_array_index (arr, i)));
139         {
140           found = TRUE;
141         }
142     }
143
144   spi_reference_free (ref);
145
146   *index = i;
147   return found;
148 }
149
150 static void
151 add_application (SpiRegistry *reg, DBusConnection *bus, const gchar *name, const gchar *path)
152 {
153   g_ptr_array_add (reg->apps, spi_reference_new (name, path));
154   children_added_listener (bus, reg->apps->len - 1, name, path);
155 }
156
157 static void
158 remove_application (SpiRegistry *reg, DBusConnection *bus, guint index)
159 {
160   const gchar *name = "";
161   g_ptr_array_remove_index (reg->apps, index);
162   /*TODO spi_remove_device_listeners (registry->de_controller, old);*/
163   children_removed_listener (bus, index, name, SPI_DBUS_PATH_NULL);
164 }
165
166 static void
167 handle_disconnection (DBusConnection *bus, DBusMessage *message, void *user_data)
168 {
169   char *name, *old, *new;
170   SpiRegistry *reg = SPI_REGISTRY (user_data);
171
172   if (dbus_message_get_args (message, NULL,
173                              DBUS_TYPE_STRING, &name,
174                              DBUS_TYPE_STRING, &old,
175                              DBUS_TYPE_STRING, &new,
176                              DBUS_TYPE_INVALID))
177     {
178       if (*old != '\0' && *new == '\0')
179         {
180           /* Remove all children with the application name the same as the disconnected application. */
181           guint i;
182           for (i = 0; i < reg->apps->len; i++)
183             {
184               SpiReference *ref  = g_ptr_array_index (reg->apps, i);
185               while (!g_strcmp0 (old, ref->name))
186                 {
187                   g_ptr_array_remove_index (reg->apps, i);
188                   children_removed_listener (bus, i, old, SPI_DBUS_PATH_NULL);
189                 }
190             } 
191         }
192     }
193 }
194
195 static DBusHandlerResult
196 signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data)
197 {
198   SpiRegistry *registry = SPI_REGISTRY (user_data);
199   guint res = DBUS_HANDLER_RESULT_HANDLED;
200   const char *iface = dbus_message_get_interface (message);
201   const char *member = dbus_message_get_member (message);
202
203   if (!g_strcmp0(iface, DBUS_INTERFACE_DBUS) && !g_strcmp0(member, "NameOwnerChanged"))
204       handle_disconnection (bus, message, user_data);
205   else
206       res = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
207
208   return res;
209 }
210
211 /* org.at_spi.Socket interface */
212 /*---------------------------------------------------------------------------*/
213
214 static DBusMessage*
215 impl_Embed (DBusConnection *bus, DBusMessage *message, void *user_data)
216 {
217   SpiRegistry *reg = SPI_REGISTRY (user_data);
218   DBusMessageIter iter, iter_struct;
219   gchar *app_name, *obj_path;
220
221   dbus_message_iter_init (message, &iter);
222   dbus_message_iter_recurse (&iter, &iter_struct);
223   if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_STRING))
224         goto error;
225   dbus_message_iter_get_basic (&iter_struct, &app_name);
226   if (!dbus_message_iter_next (&iter_struct))
227         goto error;
228   if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_OBJECT_PATH))
229         goto error;
230   dbus_message_iter_get_basic (&iter_struct, &obj_path);
231
232   add_application(reg, bus, app_name, obj_path);
233
234   return NULL;
235 error:
236   return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Invalid arguments");
237 }
238
239 static DBusMessage*
240 impl_Unembed (DBusConnection *bus, DBusMessage *message, void *user_data)
241 {
242   SpiRegistry *reg = SPI_REGISTRY (user_data);
243   DBusMessageIter iter, iter_struct;
244   gchar *app_name, *obj_path;
245   guint index;
246
247   dbus_message_iter_init (message, &iter);
248   dbus_message_iter_recurse (&iter, &iter_struct);
249   if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_STRING))
250         goto error;
251   dbus_message_iter_get_basic (&iter_struct, &app_name);
252   if (!dbus_message_iter_next (&iter_struct))
253         goto error;
254   if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_OBJECT_PATH))
255         goto error;
256   dbus_message_iter_get_basic (&iter_struct, &obj_path);
257
258   if (find_index_of_reference (reg->apps, app_name, obj_path, &index))
259       remove_application(reg, bus, index);
260
261   return NULL;
262 error:
263   return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Invalid arguments");
264 }
265
266 /* org.at_spi.Component interface */
267 /*---------------------------------------------------------------------------*/
268
269 static DBusMessage *
270 impl_Contains (DBusConnection * bus, DBusMessage * message, void *user_data)
271 {
272   dbus_bool_t retval = FALSE;
273   DBusMessage *reply;
274
275   reply = dbus_message_new_method_return (message);
276   dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval,
277                             DBUS_TYPE_INVALID);
278   return reply;
279 }
280
281 static DBusMessage *
282 impl_GetAccessibleAtPoint (DBusConnection * bus, DBusMessage * message,
283                            void *user_data)
284 {
285   DBusMessage *reply = NULL;
286   DBusMessageIter iter;
287
288   reply = dbus_message_new_method_return (message);
289   dbus_message_iter_init_append (reply, &iter);
290   append_reference (&iter, 
291                     dbus_bus_get_unique_name (bus),
292                     SPI_DBUS_PATH_NULL);
293
294   return reply;
295 }
296
297 static DBusMessage *
298 impl_GetExtents (DBusConnection * bus, DBusMessage * message, void *user_data)
299 {
300   dbus_uint32_t coord_type;
301   dbus_int32_t x = 0, y = 0, width = 1024, height = 768;
302   DBusMessage *reply;
303   DBusMessageIter iter, iter_struct;
304
305   reply = dbus_message_new_method_return (message);
306   dbus_message_iter_init_append (reply, &iter);
307   dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL,
308                                     &iter_struct);
309     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &x);
310     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &y);
311     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &width);
312     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &height);
313   dbus_message_iter_close_container (&iter, &iter_struct);
314   return reply;
315 }
316
317 static DBusMessage *
318 impl_GetPosition (DBusConnection * bus, DBusMessage * message,
319                   void *user_data)
320 {
321   DBusMessage *reply;
322   dbus_int32_t x = 0, y = 0;
323
324   reply = dbus_message_new_method_return (message);
325   dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
326                             &y, DBUS_TYPE_INVALID);
327   return reply;
328 }
329
330 static DBusMessage *
331 impl_GetSize (DBusConnection * bus, DBusMessage * message, void *user_data)
332 {
333   /* TODO - Get the screen size */
334   DBusMessage *reply;
335   dbus_int32_t width = 1024, height = 768;
336
337   reply = dbus_message_new_method_return (message);
338   dbus_message_append_args (reply, DBUS_TYPE_INT32, &width,
339                             DBUS_TYPE_INT32, &height, DBUS_TYPE_INVALID);
340   return reply;
341 }
342
343 #define LAYER_WIDGET 3;
344
345 static DBusMessage *
346 impl_GetLayer (DBusConnection * bus, DBusMessage * message, void *user_data)
347 {
348   DBusMessage *reply;
349   dbus_uint32_t rv = LAYER_WIDGET;
350
351   reply = dbus_message_new_method_return (message);
352   dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
353                             DBUS_TYPE_INVALID);
354   return reply;
355 }
356
357 static DBusMessage *
358 impl_GetMDIZOrder (DBusConnection * bus, DBusMessage * message,
359                    void *user_data)
360 {
361   DBusMessage *reply;
362   dbus_int16_t rv = 0;
363
364   reply = dbus_message_new_method_return (message);
365   dbus_message_append_args (reply, DBUS_TYPE_INT16, &rv,
366                             DBUS_TYPE_INVALID);
367   return reply;
368 }
369
370 static DBusMessage *
371 impl_GrabFocus (DBusConnection * bus, DBusMessage * message, void *user_data)
372 {
373   DBusMessage *reply;
374   dbus_bool_t retval = FALSE;
375
376   reply = dbus_message_new_method_return (message);
377   dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval,
378                             DBUS_TYPE_INVALID);
379   return reply;
380 }
381
382 static DBusMessage *
383 impl_GetAlpha (DBusConnection * bus, DBusMessage * message, void *user_data)
384 {
385   double rv = 1.0;
386   DBusMessage *reply;
387
388   reply = dbus_message_new_method_return (message);
389   dbus_message_append_args (reply, DBUS_TYPE_DOUBLE, &rv,
390                             DBUS_TYPE_INVALID);
391   return reply;
392 }
393
394 /* org.at_spi.Accessible interface */
395 /*---------------------------------------------------------------------------*/
396
397 static dbus_bool_t
398 impl_get_Name (DBusMessageIter * iter, void *user_data)
399 {
400   const gchar *name = "main";
401   return return_v_string (iter, name);
402 }
403
404 static dbus_bool_t
405 impl_get_Description (DBusMessageIter * iter, void *user_data)
406 {
407   const gchar *description = "";
408   return return_v_string (iter, description);
409 }
410
411 static dbus_bool_t
412 impl_get_Parent (DBusMessageIter * iter, void *user_data)
413 {
414   const gchar *name = "";
415   append_reference (iter, 
416                     name,
417                     SPI_DBUS_PATH_NULL);
418   return TRUE;
419 }
420
421 static dbus_bool_t
422 impl_get_ChildCount (DBusMessageIter * iter, void *user_data)
423 {
424   SpiRegistry *reg = SPI_REGISTRY (user_data);
425   dbus_int32_t rv = reg->apps->len;
426
427   dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &rv);
428 }
429
430 static DBusMessage *
431 impl_GetChildAtIndex (DBusConnection * bus,
432                       DBusMessage * message, void *user_data)
433 {
434   SpiRegistry *reg = SPI_REGISTRY (user_data);
435   DBusMessage *reply;
436   DBusMessageIter iter;
437   DBusError error;
438   SpiReference *ref;
439   dbus_int32_t i;
440
441   dbus_error_init (&error);
442   if (!dbus_message_get_args 
443        (message, &error, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
444     {
445       return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Invalid arguments");
446     }
447
448   reply = dbus_message_new_method_return (message);
449   dbus_message_iter_init_append (reply, &iter);
450
451   ref = g_ptr_array_index (reg->apps, i);
452   append_reference (&iter, ref->name, ref->path);
453
454   return reply;
455 }
456
457 static DBusMessage *
458 impl_GetChildren (DBusConnection * bus,
459                   DBusMessage * message, void *user_data)
460 {
461   DBusMessage *reply = NULL;
462   DBusMessageIter iter, iter_array;
463   SpiRegistry *reg = SPI_REGISTRY (user_data);
464   int i;
465
466   reply = dbus_message_new_method_return (message);
467
468   dbus_message_iter_init_append (reply, &iter);
469   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array);
470   for (i=0; i < reg->apps->len; i++)
471     {
472       SpiReference *current = g_ptr_array_index (reg->apps, i);
473       append_reference (&iter_array, current->name, current->path);
474     }
475   dbus_message_iter_close_container(&iter, &iter_array);
476   return reply;
477 }
478
479 static DBusMessage *
480 impl_GetIndexInParent (DBusConnection * bus,
481                        DBusMessage * message, void *user_data)
482 {
483   DBusMessage *reply;
484   dbus_uint32_t rv = 0;
485
486   reply = dbus_message_new_method_return (message);
487   dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv, DBUS_TYPE_INVALID);
488   return reply;
489 }
490
491 static DBusMessage *
492 impl_GetRelationSet (DBusConnection * bus,
493                      DBusMessage * message, void *user_data)
494 {
495   DBusMessage *reply;
496   DBusMessageIter iter, iter_array;
497
498   reply = dbus_message_new_method_return (message);
499   dbus_message_iter_init_append (reply, &iter);
500   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ua(so))", &iter_array);
501   dbus_message_iter_close_container (&iter, &iter_array);
502
503   return reply;
504 }
505
506 static DBusMessage *
507 impl_GetRole (DBusConnection * bus, DBusMessage * message, void * user_data)
508 {
509   DBusMessage *reply;
510   dbus_uint32_t rv = 0;
511
512   reply = dbus_message_new_method_return (message);
513   dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv, DBUS_TYPE_INVALID);
514   return reply;
515 }
516
517 static DBusMessage *
518 impl_GetRoleName (DBusConnection * bus,
519                   DBusMessage * message, void *user_data)
520 {
521   DBusMessage *reply;
522   const char *role_name = "unknown";
523
524   reply = dbus_message_new_method_return (message);
525   dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
526                             DBUS_TYPE_INVALID);
527   return reply;
528 }
529
530 static DBusMessage *
531 impl_GetLocalizedRoleName (DBusConnection * bus,
532                            DBusMessage * message, void *user_data)
533 {
534   /* TODO - Localize this */
535   DBusMessage *reply;
536   const char *role_name = "unknown";
537
538   reply = dbus_message_new_method_return (message);
539   dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
540                             DBUS_TYPE_INVALID);
541   return reply;
542 }
543
544 static DBusMessage *
545 impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
546 {
547   DBusMessage *reply = NULL;
548   DBusMessageIter iter, iter_array;
549
550   dbus_uint32_t states[2] = {0, 0};
551   guint count;
552
553   reply = dbus_message_new_method_return (message);
554   dbus_message_iter_init_append (reply, &iter);
555
556   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
557   for (count = 0; count < 2; count++)
558     {
559       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
560                                       &states[count]);
561     }
562   dbus_message_iter_close_container (&iter, &iter_array);
563   return reply;
564 }
565
566 static DBusMessage *
567 impl_GetAttributes (DBusConnection * bus,
568                     DBusMessage * message, void *user_data)
569 {
570   DBusMessage *reply = NULL;
571   DBusMessageIter iter, array;
572
573   reply = dbus_message_new_method_return (message);
574   dbus_message_iter_init_append (reply, &iter);
575   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{ss}", &array);
576   dbus_message_iter_close_container (&iter, &array);
577
578   return reply;
579 }
580
581 static DBusMessage *
582 impl_GetApplication (DBusConnection * bus,
583                      DBusMessage * message, void *user_data)
584 {
585   DBusMessage *reply = NULL;
586   DBusMessageIter iter;
587
588   reply = dbus_message_new_method_return (message);
589   dbus_message_iter_init_append (reply, &iter);
590   append_reference (&iter,
591                     dbus_bus_get_unique_name (bus),
592                     SPI_DBUS_PATH_NULL);
593
594   return reply;
595 }
596
597 static DBusMessage *
598 impl_GetInterfaces (DBusConnection * bus,
599                     DBusMessage * message, void *user_data)
600 {
601   DBusMessage *reply;
602   DBusMessageIter iter, iter_array;
603
604   const char *acc = SPI_DBUS_INTERFACE_ACCESSIBLE;
605   const char *com = SPI_DBUS_INTERFACE_COMPONENT;
606
607   reply = dbus_message_new_method_return (message);
608
609   dbus_message_iter_init_append (reply, &iter);
610   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
611                                     &iter_array);
612     dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &acc);
613     dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &com);
614   dbus_message_iter_close_container (&iter, &iter_array);
615
616   return reply;
617 }
618
619 /*---------------------------------------------------------------------------*/
620
621 static void 
622 emit_Available (DBusConnection * bus)
623 {
624   DBusMessage *sig;
625   DBusMessageIter iter;
626   
627   sig = dbus_message_new_signal(SPI_DBUS_PATH_ROOT, SPI_DBUS_INTERFACE_SOCKET, "Available");
628
629   dbus_message_iter_init_append(sig, &iter);
630   append_reference (&iter, SPI_DBUS_NAME_REGISTRY, SPI_DBUS_PATH_ROOT);
631
632   dbus_connection_send(bus, sig, NULL);
633   dbus_message_unref(sig);
634 }
635
636 /*---------------------------------------------------------------------------*/
637
638 /*
639  * Emits an AT-SPI event.
640  * AT-SPI events names are split into three parts:
641  * class:major:minor
642  * This is mapped onto D-Bus events as:
643  * D-Bus Interface:Signal Name:Detail argument
644  *
645  * Marshals a basic type into the 'any_data' attribute of
646  * the AT-SPI event.
647  */
648 static void 
649 emit_event (DBusConnection *bus,
650             const char *klass,
651             const char *major,
652             const char *minor,
653             dbus_int32_t detail1,
654             dbus_int32_t detail2,
655             const char *name,
656             const char *path)
657 {
658   DBusMessage *sig;
659   DBusMessageIter iter, iter_variant;
660   
661   sig = dbus_message_new_signal(SPI_DBUS_PATH_ROOT, klass, major);
662
663   dbus_message_iter_init_append(sig, &iter);
664
665   append_reference (&iter,
666                     dbus_bus_get_unique_name (bus),
667                     SPI_DBUS_PATH_ROOT);
668   dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
669   dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
670   dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
671
672   dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(so)",
673                                     &iter_variant);
674     append_reference (&iter_variant, name, path);
675   dbus_message_iter_close_container (&iter, &iter_variant);
676
677   dbus_connection_send(bus, sig, NULL);
678   dbus_message_unref(sig);
679 }
680
681 /*---------------------------------------------------------------------------*/
682
683 /*
684  * Children changed signal converter and forwarder.
685  *
686  * Klass (Interface) org.freedesktop.atspi.Event.Object
687  * Major is the signal name.
688  * Minor is 'add' or 'remove'
689  * detail1 is the index.
690  * detail2 is 0.
691  * any_data is the child reference.
692  */
693
694 static gboolean
695 children_added_listener (DBusConnection * bus,
696                          gint             index,
697                          const gchar    * name,
698                          const gchar    * path)
699 {
700   emit_event (bus, SPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", "add", index, 0,
701               name, path);
702 }
703
704 static gboolean
705 children_removed_listener (DBusConnection * bus,
706                            gint             index,
707                            const gchar    * name,
708                            const gchar    * path)
709 {
710   emit_event (bus, SPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", "remove", index, 0,
711               name, SPI_DBUS_PATH_NULL);
712 }
713
714 /*---------------------------------------------------------------------------*/
715
716 static DBusHandlerResult
717 handle_method (DBusConnection *bus, DBusMessage *message, void *user_data)
718 {
719   DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
720
721   const gchar *iface   = dbus_message_get_interface (message);
722   const gchar *member  = dbus_message_get_member (message);
723   const gint   type    = dbus_message_get_type (message);
724
725   DBusMessage *reply = NULL;
726
727   /* Check for basic reasons not to handle */
728   if (type   != DBUS_MESSAGE_TYPE_METHOD_CALL ||
729       member == NULL ||
730       iface  == NULL)
731       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
732
733   if (!strcmp (iface, "org.freedesktop.DBus.Properties"))
734     {
735       if (!strcmp (member, "Get"))
736         {
737           const gchar *prop_iface;
738           const gchar *prop_member;
739           DBusError error;
740
741           dbus_error_init (&error);
742           if (dbus_message_get_args (message,
743                                      &error,
744                                      DBUS_TYPE_STRING,
745                                      &prop_iface,
746                                      DBUS_TYPE_STRING,
747                                      &prop_member,
748                                      DBUS_TYPE_INVALID))
749             {
750               DBusMessageIter iter;
751
752               reply = dbus_message_new_method_return (message);
753               dbus_message_iter_init_append (reply, &iter);
754
755
756               if (!strcmp (prop_iface, SPI_DBUS_INTERFACE_ACCESSIBLE))
757                 {
758                   if      (!strcmp (prop_member, "Name"))
759                     impl_get_Name (&iter, user_data);
760                   else if (!strcmp (prop_member, "Description"))
761                     impl_get_Description (&iter, user_data);
762                   else if (!strcmp (prop_member, "Parent"))
763                     impl_get_Parent (&iter, user_data);
764                   else if (!strcmp (prop_member, "ChildCount"))
765                     impl_get_ChildCount (&iter, user_data);
766                   else
767                     {
768                       dbus_message_unref (reply); 
769                       reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Property unavailable");
770                     }
771                 }
772             }
773           else
774             {
775               reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, error.message);
776             }
777           result = DBUS_HANDLER_RESULT_HANDLED;
778         }
779       else if (!strcmp (member, "GetAll"))
780         {
781           result = DBUS_HANDLER_RESULT_HANDLED;
782         }
783     }
784
785   if (!strcmp (iface, SPI_DBUS_INTERFACE_ACCESSIBLE))
786     {
787       result = DBUS_HANDLER_RESULT_HANDLED;
788       if      (!strcmp (member, "GetChildAtIndex"))
789           reply = impl_GetChildAtIndex (bus, message, user_data);
790       else if (!strcmp (member, "GetChildren"))
791           reply = impl_GetChildren (bus, message, user_data);
792       else if (!strcmp (member, "GetIndexInParent"))
793           reply = impl_GetIndexInParent (bus, message, user_data);
794       else if (!strcmp (member, "GetRelationSet"))
795           reply = impl_GetRelationSet (bus, message, user_data);
796       else if (!strcmp (member, "GetRole"))
797           reply = impl_GetRole (bus, message, user_data);
798       else if (!strcmp (member, "GetRoleName"))
799           reply = impl_GetRoleName (bus, message, user_data);
800       else if (!strcmp (member, "GetLocalizedRoleName"))
801           reply = impl_GetLocalizedRoleName (bus, message, user_data);
802       else if (!strcmp (member, "GetState"))
803           reply = impl_GetState (bus, message, user_data);
804       else if (!strcmp (member, "GetAttributes"))
805           reply = impl_GetAttributes (bus, message, user_data);
806       else if (!strcmp (member, "GetApplication"))
807           reply = impl_GetApplication (bus, message, user_data);
808       else if (!strcmp (member, "GetInterfaces"))
809           reply = impl_GetInterfaces (bus, message, user_data);
810       else
811          result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
812     }
813
814   if (!strcmp (iface, SPI_DBUS_INTERFACE_COMPONENT))
815     {
816       result = DBUS_HANDLER_RESULT_HANDLED;
817       if      (!strcmp (member, "Contains"))
818           reply = impl_Contains (bus, message, user_data);
819       else if (!strcmp (member, "GetAccessibleAtPoint"))
820           reply = impl_GetAccessibleAtPoint (bus, message, user_data);
821       else if (!strcmp (member, "GetExtents"))
822           reply = impl_GetExtents (bus, message, user_data);
823       else if (!strcmp (member, "GetPosition"))
824           reply = impl_GetPosition (bus, message, user_data);
825       else if (!strcmp (member, "GetSize"))
826           reply = impl_GetSize (bus, message, user_data);
827       else if (!strcmp (member, "GetLayer"))
828           reply = impl_GetLayer (bus, message, user_data);
829       else if (!strcmp (member, "GetMDIZOrder"))
830           reply = impl_GetMDIZOrder (bus, message, user_data);
831       else if (!strcmp (member, "GrabFocus"))
832           reply = impl_GrabFocus (bus, message, user_data);
833       else if (!strcmp (member, "GetAlpha"))
834           reply = impl_GetAlpha (bus, message, user_data);
835       else
836          result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
837     }
838
839   if (!strcmp (iface, SPI_DBUS_INTERFACE_SOCKET))
840     {
841       result = DBUS_HANDLER_RESULT_HANDLED;
842       if      (!strcmp (member, "Embed"))
843           reply = impl_Embed (bus, message, user_data);
844       else if (!strcmp (member, "Unembed"))
845           reply = impl_Unembed (bus, message, user_data);
846       else
847          result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
848     }
849
850   if (result == DBUS_HANDLER_RESULT_HANDLED)
851     {
852       if (!reply)
853         {
854           reply = dbus_message_new_method_return (message);
855         }
856
857       dbus_connection_send (bus, reply, NULL);
858       dbus_message_unref (reply);
859     }
860   
861   return result;
862 }
863
864 /*---------------------------------------------------------------------------*/
865
866 static DBusObjectPathVTable registry_vtable =
867 {
868   NULL,
869   &handle_method,
870   NULL, NULL, NULL, NULL
871 };
872
873 static gchar *app_sig_match_name_owner =
874        "type='signal', interface='org.freedesktop.DBus', member='NameOwnerChanged'";
875
876 SpiRegistry *
877 spi_registry_new (DBusConnection *bus)
878 {
879   SpiRegistry *reg = g_object_new (SPI_REGISTRY_TYPE, NULL);
880
881   reg->bus = bus;
882
883   dbus_bus_add_match (bus, app_sig_match_name_owner, NULL);
884   dbus_connection_add_filter (bus, signal_filter, reg, NULL);
885
886   dbus_connection_register_object_path (bus, SPI_DBUS_PATH_ROOT, &registry_vtable, reg);
887
888   emit_Available (bus);
889
890   return reg;
891 }
892
893 /*END------------------------------------------------------------------------*/