0e1703e529e07065b9cac3ce2761bc25710fde51
[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 Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 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  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include <config.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #include "paths.h"
30 #include "registry.h"
31 #include "introspection.h"
32 //TIZEN_ONLY(20220420) Provide GetForegroundWindows
33 #include "atspi/atspi.h"
34
35 static gboolean
36 _is_same (const char *s1, const char *s2)
37 {
38   size_t l1, l2;
39
40   if (!s1 || !s2)
41     return (s1 == s2);
42
43   l1 = strlen (s1);
44   l2 = strlen (s2);
45
46   if (l1 != l2)
47     return FALSE;
48
49   return !strncmp (s1, s2, l1);
50 }
51 //
52
53 typedef struct event_data event_data;
54 struct event_data
55 {
56   gchar *bus_name;
57   gchar **data;
58   GSList *properties;
59 };
60
61 static void
62 children_added_listener (DBusConnection * bus,
63                          gint             index,
64                          const gchar    * name,
65                          const gchar    * path);
66
67 static void
68 children_removed_listener (DBusConnection * bus,
69                            gint             index,
70                            const gchar    * name,
71                            const gchar    * path);
72
73 /*---------------------------------------------------------------------------*/
74
75 typedef struct _SpiReference
76 {
77   gchar *name;
78   gchar *path;
79 } SpiReference;
80
81 static SpiReference *
82 spi_reference_new (const gchar *name, const gchar *path)
83 {
84   SpiReference *ref;
85
86   ref = g_new0 (SpiReference, 1);
87   ref->name = g_strdup (name);
88   ref->path = g_strdup (path);
89
90   return ref;
91 }
92
93 static void
94 spi_reference_free (SpiReference *ref)
95 {
96   g_free (ref->name);
97   g_free (ref->path);
98   g_free (ref);
99 }
100
101 /*---------------------------------------------------------------------------*/
102
103 G_DEFINE_TYPE(SpiRegistry, spi_registry, G_TYPE_OBJECT)
104
105 static void
106 spi_registry_class_init (SpiRegistryClass *klass)
107 {
108   spi_registry_parent_class = g_type_class_ref (G_TYPE_OBJECT);
109 }
110
111 static void
112 spi_registry_init (SpiRegistry *registry)
113 {
114   registry->apps = g_ptr_array_new_with_free_func ((GDestroyNotify) spi_reference_free);
115   registry->wins = g_ptr_array_new_with_free_func ((GDestroyNotify) spi_reference_free);
116 }
117
118 /*---------------------------------------------------------------------------*/
119
120 static dbus_bool_t
121 return_v_string (DBusMessageIter * iter, const gchar * str)
122 {
123   DBusMessageIter variant;
124
125   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "s",
126                                     &variant))
127     return FALSE;
128
129   dbus_message_iter_append_basic (&variant, DBUS_TYPE_STRING, &str);
130   dbus_message_iter_close_container (iter, &variant);
131   return TRUE;
132 }
133
134 static dbus_bool_t
135 append_reference (DBusMessageIter * iter, const char * name, const char * path)
136 {
137   DBusMessageIter iter_struct;
138
139   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
140                                     &iter_struct))
141     return FALSE;
142   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
143   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
144   dbus_message_iter_close_container (iter, &iter_struct);
145   return TRUE;
146 }
147
148 /*---------------------------------------------------------------------------*/
149
150 static gboolean
151 compare_reference (SpiReference *one, SpiReference *two)
152 {
153   if (g_strcmp0 (one->name, two->name) == 0 &&
154       g_strcmp0 (one->path, two->path) == 0)
155     return TRUE;
156   else
157     return FALSE;
158 }
159
160 static gboolean
161 find_index_of_reference (GPtrArray *arr, const gchar *name, const gchar * path, guint *index)
162 {
163   SpiReference *ref;
164   gboolean found = FALSE;
165   guint i = 0;
166
167   ref = spi_reference_new (name, path);
168
169   for (i = 0; i < arr->len; i++)
170     {
171       if (compare_reference (ref, g_ptr_array_index (arr, i)))
172         {
173           found = TRUE;
174           break;
175         }
176     }
177
178   spi_reference_free (ref);
179
180   *index = i;
181   return found;
182 }
183
184 static void
185 add_application (SpiRegistry *reg, DBusConnection *bus, const gchar *name, const gchar *path)
186 {
187   g_ptr_array_add (reg->apps, spi_reference_new (name, path));
188   children_added_listener (bus, reg->apps->len - 1, name, path);
189 }
190
191 static void
192 set_id (SpiRegistry *reg, DBusConnection *bus, const gchar *name, const gchar *path)
193 {
194   DBusMessage *message;
195   DBusMessageIter iter, iter_variant;
196   const char *iface_application = "org.a11y.atspi.Application";
197   const char *id = "Id";
198
199   message = dbus_message_new_method_call (name, path,
200                                           DBUS_INTERFACE_PROPERTIES, "Set");
201   if (!message)
202     return;
203   dbus_message_iter_init_append (message, &iter);
204   dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface_application);
205   dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &id);
206   dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "i", &iter_variant);
207   dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_INT32, &reg->id);
208   /* TODO: This will cause problems if we cycle through 2^31 ids */
209   reg->id++;
210   dbus_message_iter_close_container (&iter, &iter_variant);
211   dbus_connection_send (bus, message, NULL);
212   dbus_message_unref (message);
213 }
214
215 static void
216 remove_application (SpiRegistry *reg, DBusConnection *bus, guint index)
217 {
218   SpiReference *ref = g_ptr_array_index (reg->apps, index);
219
220   spi_remove_device_listeners (reg->dec, ref->name);
221   children_removed_listener (bus, index, ref->name, ref->path);
222   g_ptr_array_remove_index (reg->apps, index);
223 }
224
225 static gboolean
226 event_is_subtype (gchar **needle, gchar **haystack)
227 {
228   while (*haystack && **haystack)
229     {
230       if (g_strcmp0 (*needle, *haystack))
231         return FALSE;
232       needle++;
233       haystack++;
234     }
235   return TRUE;
236 }
237
238 static gboolean
239 needs_mouse_poll (char **event)
240 {
241   if (g_strcmp0 (event [0], "Mouse") != 0)
242     return FALSE;
243   if (!event [1] || !event [1][0])
244     return TRUE;
245   return (g_strcmp0 (event [1], "Abs") == 0);
246 }
247
248 static void
249 remove_events (SpiRegistry *registry, const char *bus_name, const char *event)
250 {
251   gchar **remove_data;
252   GList *list;
253   gboolean mouse_found = FALSE;
254   DBusMessage *signal;
255
256   remove_data = g_strsplit (event, ":", 3);
257   if (!remove_data)
258     {
259       return;
260     }
261
262   for (list = registry->events; list;)
263     {
264       event_data *evdata = list->data;
265       list = list->next;
266       if (!g_strcmp0 (evdata->bus_name, bus_name) &&
267           event_is_subtype (evdata->data, remove_data))
268         {
269           g_strfreev (evdata->data);
270           g_free (evdata->bus_name);
271           g_slist_free_full (evdata->properties, g_free);
272           g_free (evdata);
273           registry->events = g_list_remove (registry->events, evdata);
274         }
275       else
276         {
277           if (needs_mouse_poll (evdata->data))
278             mouse_found = TRUE;
279         }
280     }
281
282   if (!mouse_found)
283     spi_device_event_controller_stop_poll_mouse ();
284
285   g_strfreev (remove_data);
286
287   signal = dbus_message_new_signal (SPI_DBUS_PATH_REGISTRY,
288                                     SPI_DBUS_INTERFACE_REGISTRY,
289                                     "EventListenerDeregistered");
290   dbus_message_append_args (signal, DBUS_TYPE_STRING, &bus_name,
291                             DBUS_TYPE_STRING, &event, DBUS_TYPE_INVALID);
292   dbus_connection_send (registry->bus, signal, NULL);
293   dbus_message_unref (signal);
294 }
295
296 static void
297 handle_disconnection (DBusConnection *bus, DBusMessage *message, void *user_data)
298 {
299   char *name, *old, *new;
300   SpiRegistry *reg = SPI_REGISTRY (user_data);
301
302   if (dbus_message_get_args (message, NULL,
303                              DBUS_TYPE_STRING, &name,
304                              DBUS_TYPE_STRING, &old,
305                              DBUS_TYPE_STRING, &new,
306                              DBUS_TYPE_INVALID))
307     {
308       if (*old != '\0' && *new == '\0')
309         {
310           /* Remove all children with the application name the same as the disconnected application. */
311           guint i;
312           for (i = 0; i < reg->apps->len; i++)
313             {
314               SpiReference *ref  = g_ptr_array_index (reg->apps, i);
315               if (!g_strcmp0 (old, ref->name))
316                 {
317                   remove_application (reg, bus, i);
318                   i--;
319                 }
320             } 
321
322           remove_events (reg, old, "");
323           //TIZEN_ONLY(20220420) Provide GetForegroundWindows
324           for (i = 0; i < reg->wins->len; i++)
325             {
326               SpiReference *ref  = g_ptr_array_index (reg->wins, i);
327               if (_is_same (old, ref->name))
328                 {
329                   g_ptr_array_remove_index (reg->wins, i);
330                   i--;
331                 }
332             }
333           //
334         }
335     }
336 }
337
338 //TIZEN_ONLY(20211206) Provide GetActiveWindow
339 static void
340 _set_active_window (SpiRegistry *reg, DBusMessage *message, const char* sender, const char *path)
341 {
342   char *detail = NULL;
343   dbus_int32_t detail1;
344   DBusMessageIter iter;
345   dbus_message_iter_init (message, &iter);
346   dbus_message_iter_get_basic (&iter, &detail);
347   dbus_message_iter_next (&iter);
348   dbus_message_iter_get_basic (&iter, &detail1);
349
350   if (detail1 & ACCESSIBLE_WINDOW_ACTIVATE_INFO_KEYBOARD)
351     return;
352
353   if (reg->active_win) spi_reference_free (reg->active_win);
354   reg->active_win = spi_reference_new (sender, path);
355 }
356
357 static void
358 _unset_active_window (SpiRegistry *reg, const char* sender, const char *path)
359 {
360   SpiReference *ref;
361
362   if (!reg->active_win)
363     return;
364
365   ref = spi_reference_new (sender, path);
366
367   if (compare_reference (ref, reg->active_win))
368     {
369       spi_reference_free (reg->active_win);
370       reg->active_win = NULL;
371     }
372
373   spi_reference_free (ref);
374 }
375
376 static void
377 _add_window_info (SpiRegistry *reg, const char* sender, const char *path)
378 {
379   guint index;
380   if (find_index_of_reference (reg->wins, sender, path, &index))
381     return;
382
383   g_ptr_array_add (reg->wins, spi_reference_new (sender, path));
384 }
385
386 static void
387 _remove_window_info (SpiRegistry *reg, const char* sender, const char *path)
388 {
389   guint index;
390   if (find_index_of_reference (reg->wins, sender, path, &index))
391     g_ptr_array_remove_index (reg->wins, index);
392 }
393
394 static void
395 handle_activate_window (DBusConnection *bus, DBusMessage *message, void *user_data)
396 {
397   SpiRegistry *reg = SPI_REGISTRY (user_data);
398
399   const char *sender = dbus_message_get_sender (message);
400   const char *path = dbus_message_get_path (message);
401
402   if (!sender || !path)
403     return;
404
405   _set_active_window (reg, message, sender, path);
406   _add_window_info (reg, sender, path);
407 }
408
409 static void
410 handle_deactivate_window (DBusConnection *bus, DBusMessage *message, void *user_data)
411 {
412   SpiRegistry *reg = SPI_REGISTRY (user_data);
413
414   const char *sender = dbus_message_get_sender (message);
415   const char *path = dbus_message_get_path (message);
416
417   if (!sender || !path)
418     return;
419
420   _unset_active_window (reg, sender, path);
421   /* deactivate window can be showing, so no need _remove_window_info */
422 }
423
424 static void
425 handle_destroy_window (DBusConnection *bus, DBusMessage *message, void *user_data)
426 {
427   SpiRegistry *reg = SPI_REGISTRY (user_data);
428
429   const char *sender = dbus_message_get_sender (message);
430   const char *path = dbus_message_get_path (message);
431
432   if (!sender || !path)
433     return;
434
435   _unset_active_window (reg, sender, path);
436   _remove_window_info (reg, sender, path);
437 }
438
439 static void
440 handle_state_changed (DBusConnection *bus, DBusMessage *message, void *user_data)
441 {
442   SpiRegistry *reg = SPI_REGISTRY (user_data);
443
444   const char *sender = dbus_message_get_sender (message);
445   const char *path = dbus_message_get_path (message);
446   const char *signature = dbus_message_get_signature (message);
447
448   if (!sender || !path || !signature)
449     return;
450
451   if (!_is_same (signature, "siiv(so)") &&
452       !_is_same (signature, "siiva{sv}"))
453     return;
454
455   DBusMessageIter iter;
456   dbus_int32_t detail1, detail2;
457   char *detail = NULL;
458
459   dbus_message_iter_init (message, &iter);
460   dbus_message_iter_get_basic (&iter, &detail);
461   dbus_message_iter_next (&iter);
462   dbus_message_iter_get_basic (&iter, &detail1);
463   dbus_message_iter_next (&iter);
464   dbus_message_iter_get_basic (&iter, &detail2);
465   dbus_message_iter_next (&iter);
466
467   /* TODO: detail == showing */
468   if (!detail || !_is_same (detail, "visible"))
469     return;
470
471   AtspiAccessible *accessible;
472   AtspiRole role;
473
474   accessible = ref_accessible (sender, path);
475   role = atspi_accessible_get_role (accessible, NULL);
476
477   if (role == ATSPI_ROLE_WINDOW ||
478       role == ATSPI_ROLE_INPUT_METHOD_WINDOW)
479     {
480       if (detail1)
481         _add_window_info (reg, sender, path);
482       else
483         _remove_window_info (reg, sender, path);
484     }
485
486   g_object_unref (accessible);
487 }
488 //
489
490 /*
491  * Converts names of the form "active-descendant-changed" to
492  *" ActiveDescendantChanged"
493  */
494 static gchar *
495 ensure_proper_format (const char *name)
496 {
497   gchar *ret = (gchar *) g_malloc (strlen (name) * 2 + 2);
498   gchar *p = ret;
499   gboolean need_upper = TRUE;
500
501   if (!ret)
502     return NULL;
503   while (*name)
504     {
505       if (need_upper)
506         {
507           *p++ = toupper (*name);
508           need_upper = FALSE;
509         }
510       else if (*name == '-')
511         need_upper = TRUE;
512       else if (*name == ':')
513         {
514           need_upper = TRUE;
515           *p++ = *name;
516         }
517       else
518         *p++ = *name;
519       name++;
520     }
521   *p = '\0';
522   return ret;
523 }
524
525 static DBusHandlerResult
526 signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data)
527 {
528   guint res = DBUS_HANDLER_RESULT_HANDLED;
529   const gint   type    = dbus_message_get_type (message);
530   const char *iface = dbus_message_get_interface (message);
531   const char *member = dbus_message_get_member (message);
532
533   if (type != DBUS_MESSAGE_TYPE_SIGNAL)
534     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
535
536   //TIZEN_ONLY(20220420) Provide GetForegroundWindows
537   if (!iface || !member)
538     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
539   //
540
541   if (!g_strcmp0(iface, DBUS_INTERFACE_DBUS) &&
542       !g_strcmp0(member, "NameOwnerChanged"))
543       handle_disconnection (bus, message, user_data);
544   //TIZEN_ONLY(20211206) Provide GetActiveWindow
545   else if (_is_same (iface, "org.a11y.atspi.Event.Window"))
546     {
547       if (_is_same (member, "Activate"))
548         handle_activate_window (bus, message, user_data);
549       else if (_is_same (member, "Deactivate"))
550         handle_deactivate_window (bus, message, user_data);
551       else if (_is_same (member, "Destroy"))
552         handle_destroy_window (bus, message, user_data);
553     }
554   else if (_is_same (iface, "org.a11y.atspi.Event.Object"))
555     {
556       if (_is_same (member, "StateChanged"))
557         handle_state_changed (bus, message, user_data);
558     }
559   //
560   else
561       res = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
562
563   return res;
564 }
565
566 /* org.at_spi.Socket interface */
567 /*---------------------------------------------------------------------------*/
568
569 static DBusMessage*
570 impl_Embed (DBusConnection *bus, DBusMessage *message, void *user_data)
571 {
572   SpiRegistry *reg = SPI_REGISTRY (user_data);
573   DBusMessageIter iter, iter_struct;
574   const gchar *app_name, *obj_path;
575
576   DBusMessage *reply = NULL;
577   DBusMessageIter reply_iter;
578
579   dbus_message_iter_init (message, &iter);
580   dbus_message_iter_recurse (&iter, &iter_struct);
581   if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_STRING))
582         goto error;
583   dbus_message_iter_get_basic (&iter_struct, &app_name);
584   if (!app_name)
585     app_name = dbus_message_get_sender (message);
586   if (!dbus_message_iter_next (&iter_struct))
587         goto error;
588   if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_OBJECT_PATH))
589         goto error;
590   dbus_message_iter_get_basic (&iter_struct, &obj_path);
591
592   add_application(reg, bus, app_name, obj_path);
593
594   set_id (reg, bus, app_name, obj_path);
595
596   reply = dbus_message_new_method_return (message);
597   dbus_message_iter_init_append (reply, &reply_iter);
598   append_reference (&reply_iter, 
599                     dbus_bus_get_unique_name (bus),
600                     SPI_DBUS_PATH_ROOT);
601
602   return reply;
603 error:
604   return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Invalid arguments");
605 }
606
607 static DBusMessage*
608 impl_Unembed (DBusConnection *bus, DBusMessage *message, void *user_data)
609 {
610   SpiRegistry *reg = SPI_REGISTRY (user_data);
611   DBusMessageIter iter, iter_struct;
612   gchar *app_name, *obj_path;
613   guint index;
614
615   dbus_message_iter_init (message, &iter);
616   dbus_message_iter_recurse (&iter, &iter_struct);
617   if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_STRING))
618         goto error;
619   dbus_message_iter_get_basic (&iter_struct, &app_name);
620   if (!dbus_message_iter_next (&iter_struct))
621         goto error;
622   if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_OBJECT_PATH))
623         goto error;
624   dbus_message_iter_get_basic (&iter_struct, &obj_path);
625
626   if (find_index_of_reference (reg->apps, app_name, obj_path, &index))
627       remove_application(reg, bus, index);
628
629   return NULL;
630 error:
631   return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Invalid arguments");
632 }
633
634 /* org.at_spi.Component interface */
635 /*---------------------------------------------------------------------------*/
636
637 static DBusMessage *
638 impl_Contains (DBusConnection * bus, DBusMessage * message, void *user_data)
639 {
640   dbus_bool_t retval = FALSE;
641   DBusMessage *reply;
642
643   reply = dbus_message_new_method_return (message);
644   dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval,
645                             DBUS_TYPE_INVALID);
646   return reply;
647 }
648
649 static DBusMessage *
650 impl_GetAccessibleAtPoint (DBusConnection * bus, DBusMessage * message,
651                            void *user_data)
652 {
653   DBusMessage *reply = NULL;
654   DBusMessageIter iter;
655
656   reply = dbus_message_new_method_return (message);
657   dbus_message_iter_init_append (reply, &iter);
658   append_reference (&iter, 
659                     dbus_bus_get_unique_name (bus),
660                     SPI_DBUS_PATH_NULL);
661
662   return reply;
663 }
664
665 static DBusMessage *
666 impl_GetExtents (DBusConnection * bus, DBusMessage * message, void *user_data)
667 {
668   dbus_int32_t x = 0, y = 0, width = 1024, height = 768;
669   DBusMessage *reply;
670   DBusMessageIter iter, iter_struct;
671
672   reply = dbus_message_new_method_return (message);
673   dbus_message_iter_init_append (reply, &iter);
674   dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL,
675                                     &iter_struct);
676     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &x);
677     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &y);
678     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &width);
679     dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &height);
680   dbus_message_iter_close_container (&iter, &iter_struct);
681   return reply;
682 }
683
684 static DBusMessage *
685 impl_GetPosition (DBusConnection * bus, DBusMessage * message,
686                   void *user_data)
687 {
688   DBusMessage *reply;
689   dbus_int32_t x = 0, y = 0;
690
691   reply = dbus_message_new_method_return (message);
692   dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
693                             &y, DBUS_TYPE_INVALID);
694   return reply;
695 }
696
697 static DBusMessage *
698 impl_GetSize (DBusConnection * bus, DBusMessage * message, void *user_data)
699 {
700   /* TODO - Get the screen size */
701   DBusMessage *reply;
702   dbus_int32_t width = 1024, height = 768;
703
704   reply = dbus_message_new_method_return (message);
705   dbus_message_append_args (reply, DBUS_TYPE_INT32, &width,
706                             DBUS_TYPE_INT32, &height, DBUS_TYPE_INVALID);
707   return reply;
708 }
709
710 #define LAYER_WIDGET 3;
711
712 static DBusMessage *
713 impl_GetLayer (DBusConnection * bus, DBusMessage * message, void *user_data)
714 {
715   DBusMessage *reply;
716   dbus_uint32_t rv = LAYER_WIDGET;
717
718   reply = dbus_message_new_method_return (message);
719   dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
720                             DBUS_TYPE_INVALID);
721   return reply;
722 }
723
724 static DBusMessage *
725 impl_GetMDIZOrder (DBusConnection * bus, DBusMessage * message,
726                    void *user_data)
727 {
728   DBusMessage *reply;
729   dbus_int16_t rv = 0;
730
731   reply = dbus_message_new_method_return (message);
732   dbus_message_append_args (reply, DBUS_TYPE_INT16, &rv,
733                             DBUS_TYPE_INVALID);
734   return reply;
735 }
736
737 static DBusMessage *
738 impl_GrabFocus (DBusConnection * bus, DBusMessage * message, void *user_data)
739 {
740   DBusMessage *reply;
741   dbus_bool_t retval = FALSE;
742
743   reply = dbus_message_new_method_return (message);
744   dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval,
745                             DBUS_TYPE_INVALID);
746   return reply;
747 }
748
749 static DBusMessage *
750 impl_ClearHighlight (DBusConnection * bus, DBusMessage * message, void *user_data)
751 {
752   DBusMessage *reply;
753   dbus_bool_t retval = FALSE;
754
755   reply = dbus_message_new_method_return (message);
756   dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval,
757                             DBUS_TYPE_INVALID);
758   return reply;
759 }
760
761 static DBusMessage *
762 impl_GrabHighlight (DBusConnection * bus, DBusMessage * message, void *user_data)
763 {
764   DBusMessage *reply;
765   dbus_bool_t retval = FALSE;
766
767   reply = dbus_message_new_method_return (message);
768   dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval,
769                             DBUS_TYPE_INVALID);
770   return reply;
771 }
772
773 static DBusMessage *
774 impl_GetAlpha (DBusConnection * bus, DBusMessage * message, void *user_data)
775 {
776   double rv = 1.0;
777   DBusMessage *reply;
778
779   reply = dbus_message_new_method_return (message);
780   dbus_message_append_args (reply, DBUS_TYPE_DOUBLE, &rv,
781                             DBUS_TYPE_INVALID);
782   return reply;
783 }
784
785 /* org.at_spi.Accessible interface */
786 /*---------------------------------------------------------------------------*/
787
788 static dbus_bool_t
789 impl_get_Name (DBusMessageIter * iter, void *user_data)
790 {
791   const gchar *name = "main";
792   return return_v_string (iter, name);
793 }
794
795 static dbus_bool_t
796 impl_get_Description (DBusMessageIter * iter, void *user_data)
797 {
798   const gchar *description = "";
799   return return_v_string (iter, description);
800 }
801
802 static dbus_bool_t
803 impl_get_Parent (DBusMessageIter * iter, void *user_data)
804 {
805   const gchar *name = "";
806   DBusMessageIter iter_variant;
807
808   dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)",
809                                     &iter_variant);
810   append_reference (&iter_variant, 
811                     name,
812                     SPI_DBUS_PATH_NULL);
813   dbus_message_iter_close_container (iter, &iter_variant);
814   return TRUE;
815 }
816
817 static dbus_bool_t
818 impl_get_ChildCount (DBusMessageIter * iter, void *user_data)
819 {
820   SpiRegistry *reg = SPI_REGISTRY (user_data);
821   dbus_int32_t rv = reg->apps->len;
822   dbus_bool_t result;
823   DBusMessageIter iter_variant;
824
825   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "i",
826                                          &iter_variant))
827     return FALSE;
828   result = dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_INT32, &rv);
829   dbus_message_iter_close_container (iter, &iter_variant);
830   return result;
831 }
832
833 static dbus_bool_t
834 impl_get_ToolkitName (DBusMessageIter * iter, void *user_data)
835 {
836   return return_v_string (iter, "at-spi-registry");
837 }
838
839 static dbus_bool_t
840 impl_get_ToolkitVersion (DBusMessageIter * iter, void *user_data)
841 {
842   return return_v_string (iter, "2.0");
843 }
844
845 static DBusMessage *
846 impl_GetChildAtIndex (DBusConnection * bus,
847                       DBusMessage * message, void *user_data)
848 {
849   SpiRegistry *reg = SPI_REGISTRY (user_data);
850   DBusMessage *reply;
851   DBusMessageIter iter;
852   DBusError error;
853   SpiReference *ref;
854   dbus_int32_t i;
855
856   dbus_error_init (&error);
857   if (!dbus_message_get_args 
858        (message, &error, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
859     {
860       return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Invalid arguments");
861     }
862
863   reply = dbus_message_new_method_return (message);
864   dbus_message_iter_init_append (reply, &iter);
865
866   if (i < 0 || i >= reg->apps->len)
867     append_reference (&iter, SPI_DBUS_NAME_REGISTRY, SPI_DBUS_PATH_NULL);
868   else
869     {
870       ref = g_ptr_array_index (reg->apps, i);
871       append_reference (&iter, ref->name, ref->path);
872     }
873
874   return reply;
875 }
876
877 static DBusMessage *
878 impl_GetChildren (DBusConnection * bus,
879                   DBusMessage * message, void *user_data)
880 {
881   DBusMessage *reply = NULL;
882   DBusMessageIter iter, iter_array;
883   SpiRegistry *reg = SPI_REGISTRY (user_data);
884   int i;
885
886   reply = dbus_message_new_method_return (message);
887
888   dbus_message_iter_init_append (reply, &iter);
889   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array);
890   for (i=0; i < reg->apps->len; i++)
891     {
892       SpiReference *current = g_ptr_array_index (reg->apps, i);
893       append_reference (&iter_array, current->name, current->path);
894     }
895   dbus_message_iter_close_container(&iter, &iter_array);
896   return reply;
897 }
898
899 static DBusMessage *
900 impl_GetIndexInParent (DBusConnection * bus,
901                        DBusMessage * message, void *user_data)
902 {
903   DBusMessage *reply;
904   dbus_uint32_t rv = 0;
905
906   reply = dbus_message_new_method_return (message);
907   dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv, DBUS_TYPE_INVALID);
908   return reply;
909 }
910
911 static DBusMessage *
912 impl_GetRelationSet (DBusConnection * bus,
913                      DBusMessage * message, void *user_data)
914 {
915   DBusMessage *reply;
916   DBusMessageIter iter, iter_array;
917
918   reply = dbus_message_new_method_return (message);
919   dbus_message_iter_init_append (reply, &iter);
920   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ua(so))", &iter_array);
921   dbus_message_iter_close_container (&iter, &iter_array);
922
923   return reply;
924 }
925
926 static DBusMessage *
927 impl_GetRole (DBusConnection * bus, DBusMessage * message, void * user_data)
928 {
929   DBusMessage *reply;
930   dbus_uint32_t rv = 14;        /* TODO: Get DESKTOP_FRAME from somewhere */
931
932   reply = dbus_message_new_method_return (message);
933   dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv, DBUS_TYPE_INVALID);
934   return reply;
935 }
936
937 static DBusMessage *
938 impl_GetRoleName (DBusConnection * bus,
939                   DBusMessage * message, void *user_data)
940 {
941   DBusMessage *reply;
942   const char *role_name = "desktop frame";
943
944   reply = dbus_message_new_method_return (message);
945   dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
946                             DBUS_TYPE_INVALID);
947   return reply;
948 }
949
950 static DBusMessage *
951 impl_GetLocalizedRoleName (DBusConnection * bus,
952                            DBusMessage * message, void *user_data)
953 {
954   /* TODO - Localize this */
955   DBusMessage *reply;
956   const char *role_name = "desktop frame";
957
958   reply = dbus_message_new_method_return (message);
959   dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
960                             DBUS_TYPE_INVALID);
961   return reply;
962 }
963
964 static DBusMessage *
965 impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
966 {
967   DBusMessage *reply = NULL;
968   DBusMessageIter iter, iter_array;
969
970   dbus_uint32_t states[2] = {0, 0};
971   guint count;
972
973   reply = dbus_message_new_method_return (message);
974   dbus_message_iter_init_append (reply, &iter);
975
976   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
977   for (count = 0; count < 2; count++)
978     {
979       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
980                                       &states[count]);
981     }
982   dbus_message_iter_close_container (&iter, &iter_array);
983   return reply;
984 }
985
986 static DBusMessage *
987 impl_GetAttributes (DBusConnection * bus,
988                     DBusMessage * message, void *user_data)
989 {
990   DBusMessage *reply = NULL;
991   DBusMessageIter iter, array;
992
993   reply = dbus_message_new_method_return (message);
994   dbus_message_iter_init_append (reply, &iter);
995   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{ss}", &array);
996   dbus_message_iter_close_container (&iter, &array);
997
998   return reply;
999 }
1000
1001 static DBusMessage *
1002 impl_GetApplication (DBusConnection * bus,
1003                      DBusMessage * message, void *user_data)
1004 {
1005   DBusMessage *reply = NULL;
1006   DBusMessageIter iter;
1007
1008   reply = dbus_message_new_method_return (message);
1009   dbus_message_iter_init_append (reply, &iter);
1010   append_reference (&iter,
1011                     dbus_bus_get_unique_name (bus),
1012                     SPI_DBUS_PATH_NULL);
1013
1014   return reply;
1015 }
1016
1017 static DBusMessage *
1018 impl_GetInterfaces (DBusConnection * bus,
1019                     DBusMessage * message, void *user_data)
1020 {
1021   DBusMessage *reply;
1022   DBusMessageIter iter, iter_array;
1023
1024   const char *acc = SPI_DBUS_INTERFACE_ACCESSIBLE;
1025   const char *com = SPI_DBUS_INTERFACE_COMPONENT;
1026
1027   reply = dbus_message_new_method_return (message);
1028
1029   dbus_message_iter_init_append (reply, &iter);
1030   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
1031                                     &iter_array);
1032     dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &acc);
1033     dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &com);
1034   dbus_message_iter_close_container (&iter, &iter_array);
1035
1036   return reply;
1037 }
1038
1039 //TIZEN_ONLY(20211206) Provide GetActiveWindow
1040 static DBusMessage *
1041 impl_GetActiveWindow (DBusConnection * bus,
1042                       DBusMessage * message, void *user_data)
1043 {
1044   SpiRegistry *reg = SPI_REGISTRY (user_data);
1045   DBusMessage *reply;
1046   DBusMessageIter iter;
1047
1048   reply = dbus_message_new_method_return (message);
1049   dbus_message_iter_init_append (reply, &iter);
1050
1051   SpiReference *active_window = reg->active_win;
1052   if (!active_window)
1053     append_reference (&iter, SPI_DBUS_NAME_REGISTRY, SPI_DBUS_PATH_NULL);
1054   else
1055     append_reference (&iter, active_window->name, active_window->path);
1056
1057   return reply;
1058 }
1059
1060 static DBusMessage *
1061 impl_GetForegroundWindows (DBusConnection * bus,
1062                            DBusMessage * message, void *user_data)
1063 {
1064   SpiRegistry *reg = SPI_REGISTRY (user_data);
1065   DBusMessage *reply;
1066   DBusMessageIter iter, iter_array, iter_struct;
1067   guint i = 0;
1068
1069   reply = dbus_message_new_method_return (message);
1070   dbus_message_iter_init_append (reply, &iter);
1071   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array);
1072
1073   SpiReference *win;
1074   for (i = 0; i < reg->wins->len; i++)
1075     {
1076       win = g_ptr_array_index (reg->wins, i);
1077       dbus_message_iter_open_container (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
1078       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &win->name);
1079       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &win->path);
1080       dbus_message_iter_close_container (&iter_array, &iter_struct);
1081     }
1082   dbus_message_iter_close_container (&iter, &iter_array);
1083   return reply;
1084 }
1085 //
1086
1087 static DBusMessage *
1088 impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data)
1089 {
1090   DBusMessage *reply;
1091   DBusMessageIter iter, iter_array;
1092
1093   reply = dbus_message_new_method_return (message);
1094
1095   dbus_message_iter_init_append (reply, &iter);
1096   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
1097                                     "((so)(so)(so)a(so)assusau)", &iter_array);
1098   dbus_message_iter_close_container (&iter, &iter_array);
1099   return reply;
1100 }
1101
1102 /* I would rather these two be signals, but I'm not sure that dbus-python
1103  * supports emitting signals except for a service, so implementing as both
1104  * a method call and signal for now.
1105  */
1106 static DBusMessage *
1107 impl_register_event (DBusConnection *bus, DBusMessage *message, void *user_data)
1108 {
1109   SpiRegistry *registry = SPI_REGISTRY (user_data);
1110   const char *orig_name;
1111   gchar *name;
1112   event_data *evdata;
1113   gchar **data;
1114   DBusMessage *signal;
1115   const char *sender = dbus_message_get_sender (message);
1116   DBusMessageIter iter, iter_array;
1117   const char *signature = dbus_message_get_signature (message);
1118
1119   if (strcmp (signature, "sas") != 0 &&
1120       strcmp (signature, "s") != 0)
1121   {
1122     g_warning ("got RegisterEvent with invalid signature '%s'", signature);
1123     return NULL;
1124   }
1125
1126   dbus_message_iter_init (message, &iter);
1127   dbus_message_iter_get_basic (&iter, &orig_name);
1128   dbus_message_iter_next (&iter);
1129   name = ensure_proper_format (orig_name);
1130
1131   evdata = g_new0 (event_data, 1);
1132   data = g_strsplit (name, ":", 3);
1133   evdata->bus_name = g_strdup (sender);
1134   evdata->data = data;
1135
1136   if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY)
1137   {
1138     dbus_message_iter_recurse (&iter, &iter_array);
1139     while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
1140     {
1141       const char *property;
1142       dbus_message_iter_get_basic (&iter_array, &property);
1143       evdata->properties = g_slist_append (evdata->properties,
1144                                            g_strdup (property));
1145       dbus_message_iter_next (&iter_array);
1146     }
1147   }
1148   registry->events = g_list_append (registry->events, evdata);
1149
1150   if (needs_mouse_poll (evdata->data))
1151     {
1152       spi_device_event_controller_start_poll_mouse (registry);
1153     }
1154
1155   signal = dbus_message_new_signal (SPI_DBUS_PATH_REGISTRY,
1156                                     SPI_DBUS_INTERFACE_REGISTRY,
1157                                     "EventListenerRegistered");
1158   if (signal)
1159   {
1160     GSList *ls = evdata->properties;
1161     dbus_message_iter_init_append (signal, &iter);
1162     dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender);
1163     dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
1164     dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &iter_array);
1165     while (ls)
1166     {
1167       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &ls->data);
1168       ls = g_slist_next (ls);
1169     }
1170     dbus_message_iter_close_container (&iter, &iter_array);
1171     dbus_connection_send (bus, signal, NULL);
1172     dbus_message_unref (signal);
1173   }
1174
1175   g_free (name);
1176   return dbus_message_new_method_return (message);
1177 }
1178
1179 static DBusMessage *
1180 impl_deregister_event (DBusConnection *bus, DBusMessage *message, void *user_data)
1181 {
1182   SpiRegistry *registry = SPI_REGISTRY (user_data);
1183   const char *orig_name;
1184   gchar *name;
1185   const char *sender = dbus_message_get_sender (message);
1186
1187   if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &orig_name,
1188     DBUS_TYPE_INVALID))
1189     return NULL;
1190   name = ensure_proper_format (orig_name);
1191
1192   remove_events (registry, sender, name);
1193
1194   g_free (name);
1195   return dbus_message_new_method_return (message);
1196 }
1197
1198 static DBusMessage *
1199 impl_get_registered_events (DBusConnection *bus, DBusMessage *message, void *user_data)
1200 {
1201   SpiRegistry *registry = SPI_REGISTRY (user_data);
1202   event_data *evdata;
1203   DBusMessage *reply;
1204   DBusMessageIter iter, iter_struct, iter_array;
1205   GList *list;
1206
1207   reply = dbus_message_new_method_return (message);
1208   if (!reply)
1209     return NULL;
1210
1211   dbus_message_iter_init_append (reply, &iter);
1212   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ss)", &iter_array);
1213
1214   //TIZEN_ONLY(20211206) Provide GetActiveWindow
1215   //we need this part because EFL sends only registered event
1216   const char *registry_bus_name = SPI_DBUS_NAME_REGISTRY;
1217   const char *window_activate_event = "Window:Activate:";
1218   const char *window_deactivate_event = "Window:Deactivate:";
1219
1220   dbus_message_iter_open_container (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
1221   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &registry_bus_name);
1222   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &window_activate_event);
1223   dbus_message_iter_close_container (&iter_array, &iter_struct);
1224
1225   dbus_message_iter_open_container (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
1226   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &registry_bus_name);
1227   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &window_deactivate_event);
1228   dbus_message_iter_close_container (&iter_array, &iter_struct);
1229   //
1230
1231   for (list = registry->events; list; list = list->next)
1232     {
1233       gchar *str;
1234       evdata = list->data;
1235       str = g_strconcat (evdata->data [0],
1236                          ":", (evdata->data [1]? evdata->data [1]: ""),
1237                          ":", (evdata->data [1] && evdata->data [2]? evdata->data [2]: ""), NULL);
1238       dbus_message_iter_open_container (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
1239       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &evdata->bus_name);
1240       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &str);
1241       dbus_message_iter_close_container (&iter_array, &iter_struct);
1242       g_free (str);
1243     }
1244   dbus_message_iter_close_container (&iter, &iter_array);
1245   return reply;
1246 }
1247
1248 /*---------------------------------------------------------------------------*/
1249
1250 static void 
1251 emit_Available (DBusConnection * bus)
1252 {
1253   DBusMessage *sig;
1254   DBusMessageIter iter;
1255   
1256   sig = dbus_message_new_signal(SPI_DBUS_PATH_ROOT, SPI_DBUS_INTERFACE_SOCKET, "Available");
1257
1258   dbus_message_iter_init_append(sig, &iter);
1259   append_reference (&iter, SPI_DBUS_NAME_REGISTRY, SPI_DBUS_PATH_ROOT);
1260
1261   dbus_connection_send(bus, sig, NULL);
1262   dbus_message_unref(sig);
1263 }
1264
1265 /*---------------------------------------------------------------------------*/
1266
1267 static const char *introspection_header =
1268 "<?xml version=\"1.0\"?>\n";
1269
1270 static const char *introspection_node_element =
1271 "<node name=\"%s\">\n";
1272
1273 static const char *introspection_footer =
1274 "</node>";
1275
1276 static DBusMessage *
1277 impl_Introspect_root (DBusConnection * bus,
1278                  DBusMessage * message, void *user_data)
1279 {
1280   GString *output;
1281   gchar *final;
1282
1283   const gchar *pathstr = SPI_DBUS_PATH_ROOT;
1284
1285   DBusMessage *reply;
1286
1287   output = g_string_new(introspection_header);
1288
1289   g_string_append_printf(output, introspection_node_element, pathstr);
1290
1291   g_string_append (output, spi_org_a11y_atspi_Accessible);
1292   g_string_append (output, spi_org_a11y_atspi_Component);
1293
1294   g_string_append(output, introspection_footer);
1295   final = g_string_free(output, FALSE);
1296
1297   reply = dbus_message_new_method_return (message);
1298   dbus_message_append_args(reply, DBUS_TYPE_STRING, &final, DBUS_TYPE_INVALID);
1299
1300   g_free(final);
1301   return reply;
1302 }
1303
1304 static DBusMessage *
1305 impl_Introspect_registry (DBusConnection * bus,
1306                  DBusMessage * message, void *user_data)
1307 {
1308   GString *output;
1309   gchar *final;
1310
1311   const gchar *pathstr = SPI_DBUS_PATH_REGISTRY;
1312
1313   DBusMessage *reply;
1314
1315   output = g_string_new(introspection_header);
1316
1317   g_string_append_printf(output, introspection_node_element, pathstr);
1318
1319   g_string_append (output, spi_org_a11y_atspi_Registry);
1320
1321   g_string_append(output, introspection_footer);
1322   final = g_string_free(output, FALSE);
1323
1324   reply = dbus_message_new_method_return (message);
1325   dbus_message_append_args(reply, DBUS_TYPE_STRING, &final, DBUS_TYPE_INVALID);
1326
1327   g_free(final);
1328   return reply;
1329 }
1330
1331 /*---------------------------------------------------------------------------*/
1332
1333 /*
1334  * Emits an AT-SPI event.
1335  * AT-SPI events names are split into three parts:
1336  * class:major:minor
1337  * This is mapped onto D-Bus events as:
1338  * D-Bus Interface:Signal Name:Detail argument
1339  *
1340  * Marshals a basic type into the 'any_data' attribute of
1341  * the AT-SPI event.
1342  */
1343 static void 
1344 emit_event (DBusConnection *bus,
1345             const char *klass,
1346             const char *major,
1347             const char *minor,
1348             dbus_int32_t detail1,
1349             dbus_int32_t detail2,
1350             const char *name,
1351             const char *path)
1352 {
1353   DBusMessage *sig;
1354   DBusMessageIter iter, iter_variant;
1355   
1356   sig = dbus_message_new_signal(SPI_DBUS_PATH_ROOT, klass, major);
1357
1358   dbus_message_iter_init_append(sig, &iter);
1359
1360   dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
1361   dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
1362   dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
1363
1364   dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(so)",
1365                                     &iter_variant);
1366     append_reference (&iter_variant, name, path);
1367   dbus_message_iter_close_container (&iter, &iter_variant);
1368
1369   append_reference (&iter,
1370                     dbus_bus_get_unique_name (bus),
1371                     SPI_DBUS_PATH_ROOT);
1372
1373   dbus_connection_send(bus, sig, NULL);
1374   dbus_message_unref(sig);
1375 }
1376
1377 /*---------------------------------------------------------------------------*/
1378
1379 /*
1380  * Children changed signal converter and forwarder.
1381  *
1382  * Klass (Interface) org.a11y.atspi.Event.Object
1383  * Major is the signal name.
1384  * Minor is 'add' or 'remove'
1385  * detail1 is the index.
1386  * detail2 is 0.
1387  * any_data is the child reference.
1388  */
1389
1390 static void
1391 children_added_listener (DBusConnection * bus,
1392                          gint             index,
1393                          const gchar    * name,
1394                          const gchar    * path)
1395 {
1396   emit_event (bus, SPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", "add", index, 0,
1397               name, path);
1398 }
1399
1400 static void
1401 children_removed_listener (DBusConnection * bus,
1402                            gint             index,
1403                            const gchar    * name,
1404                            const gchar    * path)
1405 {
1406   emit_event (bus, SPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", "remove", index, 0,
1407               name, path);
1408 }
1409
1410 /*---------------------------------------------------------------------------*/
1411
1412 static DBusHandlerResult
1413 handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data)
1414 {
1415   DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1416
1417   const gchar *iface   = dbus_message_get_interface (message);
1418   const gchar *member  = dbus_message_get_member (message);
1419   const gint   type    = dbus_message_get_type (message);
1420
1421   DBusMessage *reply = NULL;
1422
1423   /* Check for basic reasons not to handle */
1424   if (type   != DBUS_MESSAGE_TYPE_METHOD_CALL ||
1425       member == NULL ||
1426       iface  == NULL)
1427       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1428
1429   if (!strcmp (iface, "org.freedesktop.DBus.Properties"))
1430     {
1431       if (!strcmp (member, "Get"))
1432         {
1433           const gchar *prop_iface;
1434           const gchar *prop_member;
1435           DBusError error;
1436
1437           dbus_error_init (&error);
1438           if (dbus_message_get_args (message,
1439                                      &error,
1440                                      DBUS_TYPE_STRING,
1441                                      &prop_iface,
1442                                      DBUS_TYPE_STRING,
1443                                      &prop_member,
1444                                      DBUS_TYPE_INVALID))
1445             {
1446               DBusMessageIter iter;
1447
1448               reply = dbus_message_new_method_return (message);
1449               dbus_message_iter_init_append (reply, &iter);
1450
1451
1452               if (!strcmp (prop_iface, SPI_DBUS_INTERFACE_ACCESSIBLE))
1453                 {
1454                   if      (!strcmp (prop_member, "Name"))
1455                     impl_get_Name (&iter, user_data);
1456                   else if (!strcmp (prop_member, "Description"))
1457                     impl_get_Description (&iter, user_data);
1458                   else if (!strcmp (prop_member, "Parent"))
1459                     impl_get_Parent (&iter, user_data);
1460                   else if (!strcmp (prop_member, "ChildCount"))
1461                     impl_get_ChildCount (&iter, user_data);
1462                   else
1463                     {
1464                       dbus_message_unref (reply); 
1465                       reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Property unavailable");
1466                     }
1467                 }
1468               else if (!strcmp (prop_iface, SPI_DBUS_INTERFACE_APPLICATION))
1469                 {
1470                   if (!strcmp (prop_member, "ToolkitName"))
1471                     impl_get_ToolkitName (&iter, user_data);
1472                   else if (!strcmp (prop_member, "ToolkitVersion"))
1473                     impl_get_ToolkitVersion (&iter, user_data);
1474                   else
1475                     {
1476                       dbus_message_unref (reply); 
1477                       reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Property unavailable");
1478                     }
1479                 }
1480               else
1481                 {
1482                   dbus_message_unref (reply); 
1483                   reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Property unavailable");
1484                 }
1485             }
1486           else
1487             {
1488               reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, error.message);
1489             }
1490           result = DBUS_HANDLER_RESULT_HANDLED;
1491         }
1492       else if (!strcmp (member, "GetAll"))
1493         {
1494           result = DBUS_HANDLER_RESULT_HANDLED;
1495         }
1496     }
1497
1498   if (!strcmp (iface, SPI_DBUS_INTERFACE_ACCESSIBLE))
1499     {
1500       result = DBUS_HANDLER_RESULT_HANDLED;
1501       if      (!strcmp (member, "GetChildAtIndex"))
1502           reply = impl_GetChildAtIndex (bus, message, user_data);
1503       else if (!strcmp (member, "GetChildren"))
1504           reply = impl_GetChildren (bus, message, user_data);
1505       else if (!strcmp (member, "GetIndexInParent"))
1506           reply = impl_GetIndexInParent (bus, message, user_data);
1507       else if (!strcmp (member, "GetRelationSet"))
1508           reply = impl_GetRelationSet (bus, message, user_data);
1509       else if (!strcmp (member, "GetRole"))
1510           reply = impl_GetRole (bus, message, user_data);
1511       else if (!strcmp (member, "GetRoleName"))
1512           reply = impl_GetRoleName (bus, message, user_data);
1513       else if (!strcmp (member, "GetLocalizedRoleName"))
1514           reply = impl_GetLocalizedRoleName (bus, message, user_data);
1515       else if (!strcmp (member, "GetState"))
1516           reply = impl_GetState (bus, message, user_data);
1517       else if (!strcmp (member, "GetAttributes"))
1518           reply = impl_GetAttributes (bus, message, user_data);
1519       else if (!strcmp (member, "GetApplication"))
1520           reply = impl_GetApplication (bus, message, user_data);
1521       else if (!strcmp (member, "GetInterfaces"))
1522           reply = impl_GetInterfaces (bus, message, user_data);
1523       else
1524          result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1525     }
1526
1527   if (!strcmp (iface, SPI_DBUS_INTERFACE_COMPONENT))
1528     {
1529       result = DBUS_HANDLER_RESULT_HANDLED;
1530       if      (!strcmp (member, "Contains"))
1531           reply = impl_Contains (bus, message, user_data);
1532       else if (!strcmp (member, "GetAccessibleAtPoint"))
1533           reply = impl_GetAccessibleAtPoint (bus, message, user_data);
1534       else if (!strcmp (member, "GetExtents"))
1535           reply = impl_GetExtents (bus, message, user_data);
1536       else if (!strcmp (member, "GetPosition"))
1537           reply = impl_GetPosition (bus, message, user_data);
1538       else if (!strcmp (member, "GetSize"))
1539           reply = impl_GetSize (bus, message, user_data);
1540       else if (!strcmp (member, "GetLayer"))
1541           reply = impl_GetLayer (bus, message, user_data);
1542       else if (!strcmp (member, "GetMDIZOrder"))
1543           reply = impl_GetMDIZOrder (bus, message, user_data);
1544       else if (!strcmp (member, "GrabFocus"))
1545           reply = impl_GrabFocus (bus, message, user_data);
1546       else if (!strcmp (member, "GrabHighlight"))
1547           reply = impl_GrabHighlight (bus, message, user_data);
1548       else if (!strcmp (member, "ClearHighlight"))
1549           reply = impl_ClearHighlight (bus, message, user_data);
1550       else if (!strcmp (member, "GetAlpha"))
1551           reply = impl_GetAlpha (bus, message, user_data);
1552       else
1553          result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1554     }
1555
1556   if (!strcmp (iface, SPI_DBUS_INTERFACE_SOCKET))
1557     {
1558       result = DBUS_HANDLER_RESULT_HANDLED;
1559       if      (!strcmp (member, "Embed"))
1560           reply = impl_Embed (bus, message, user_data);
1561       else if (!strcmp (member, "Unembed"))
1562           reply = impl_Unembed (bus, message, user_data);
1563       else
1564           result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1565     }
1566
1567   if (!strcmp (iface, "org.freedesktop.DBus.Introspectable"))
1568     {
1569       result = DBUS_HANDLER_RESULT_HANDLED;
1570       if      (!strcmp (member, "Introspect"))
1571           reply = impl_Introspect_root (bus, message, user_data);
1572       else
1573           result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1574     }
1575
1576   if (result == DBUS_HANDLER_RESULT_HANDLED)
1577     {
1578       if (!reply)
1579         {
1580           reply = dbus_message_new_method_return (message);
1581         }
1582
1583       dbus_connection_send (bus, reply, NULL);
1584       dbus_message_unref (reply);
1585     }
1586 #if 0
1587   else
1588     {
1589       g_print ("Registry | Unhandled message : %s|%s\n", iface, member);
1590     }
1591 #endif
1592   
1593   return result;
1594 }
1595
1596 static DBusHandlerResult
1597 handle_method_cache (DBusConnection *bus, DBusMessage *message, void *user_data)
1598 {
1599   DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1600
1601   const gchar *iface   = dbus_message_get_interface (message);
1602   const gchar *member  = dbus_message_get_member (message);
1603   const gint   type    = dbus_message_get_type (message);
1604
1605   DBusMessage *reply = NULL;
1606
1607   /* Check for basic reasons not to handle */
1608   if (type   != DBUS_MESSAGE_TYPE_METHOD_CALL ||
1609       member == NULL ||
1610       iface  == NULL)
1611       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1612
1613   if (!strcmp (iface, SPI_DBUS_INTERFACE_CACHE))
1614     {
1615       result = DBUS_HANDLER_RESULT_HANDLED;
1616       if      (!strcmp (member, "GetItems"))
1617           reply = impl_GetItems (bus, message, user_data);
1618       else
1619          result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1620     }
1621
1622   if (result == DBUS_HANDLER_RESULT_HANDLED)
1623     {
1624       if (!reply)
1625         {
1626           reply = dbus_message_new_method_return (message);
1627         }
1628
1629       dbus_connection_send (bus, reply, NULL);
1630       dbus_message_unref (reply);
1631     }
1632   return result;
1633 }
1634
1635 static DBusHandlerResult
1636 handle_method_registry (DBusConnection *bus, DBusMessage *message, void *user_data)
1637 {
1638   DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1639
1640   const gchar *iface   = dbus_message_get_interface (message);
1641   const gchar *member  = dbus_message_get_member (message);
1642   const gint   type    = dbus_message_get_type (message);
1643
1644   DBusMessage *reply = NULL;
1645
1646   /* Check for basic reasons not to handle */
1647   if (type   != DBUS_MESSAGE_TYPE_METHOD_CALL ||
1648       member == NULL ||
1649       iface  == NULL)
1650       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1651
1652   if (!strcmp (iface, SPI_DBUS_INTERFACE_REGISTRY))
1653     {
1654       result = DBUS_HANDLER_RESULT_HANDLED;
1655       if (!strcmp(member, "RegisterEvent"))
1656       reply = impl_register_event (bus, message, user_data);
1657       else if (!strcmp(member, "DeregisterEvent"))
1658         reply = impl_deregister_event (bus, message, user_data);
1659       else if (!strcmp(member, "GetRegisteredEvents"))
1660         reply = impl_get_registered_events (bus, message, user_data);
1661       //TIZEN_ONLY(20211206) Provide GetActiveWindow
1662       else if (_is_same(member, "GetActiveWindow"))
1663           reply = impl_GetActiveWindow (bus, message, user_data);
1664       else if (_is_same(member, "GetForegroundWindows"))
1665           reply = impl_GetForegroundWindows(bus, message, user_data);
1666       //
1667       else
1668           result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1669     }
1670
1671   if (!strcmp (iface, "org.freedesktop.DBus.Introspectable"))
1672     {
1673       result = DBUS_HANDLER_RESULT_HANDLED;
1674       if      (!strcmp (member, "Introspect"))
1675           reply = impl_Introspect_registry (bus, message, user_data);
1676       else
1677           result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1678     }
1679
1680   if (result == DBUS_HANDLER_RESULT_HANDLED)
1681     {
1682       if (!reply)
1683         {
1684           reply = dbus_message_new_method_return (message);
1685         }
1686
1687       dbus_connection_send (bus, reply, NULL);
1688       dbus_message_unref (reply);
1689     }
1690 #if 0
1691   else
1692     {
1693       g_print ("Registry | Unhandled message : %s|%s\n", iface, member);
1694     }
1695 #endif
1696   
1697   return result;
1698 }
1699
1700 /*---------------------------------------------------------------------------*/
1701
1702 static DBusObjectPathVTable root_vtable =
1703 {
1704   NULL,
1705   &handle_method_root,
1706   NULL, NULL, NULL, NULL
1707 };
1708
1709 static DBusObjectPathVTable registry_vtable =
1710 {
1711   NULL,
1712   &handle_method_registry,
1713   NULL, NULL, NULL, NULL
1714 };
1715
1716 static DBusObjectPathVTable cache_vtable =
1717 {
1718   NULL,
1719   &handle_method_cache,
1720   NULL, NULL, NULL, NULL
1721 };
1722
1723 static gchar *app_sig_match_name_owner =
1724        "type='signal', interface='org.freedesktop.DBus', member='NameOwnerChanged'";
1725
1726 //TIZEN_ONLY(20211206) Provide GetActivateWindow
1727 static gchar *app_sig_match_window_activate =
1728        "type='signal',interface='org.a11y.atspi.Event.Window',member='Activate'";
1729 static gchar *app_sig_match_window_deactivate =
1730        "type='signal',interface='org.a11y.atspi.Event.Window',member='Deactivate'";
1731 static gchar *app_sig_match_window_destroy =
1732        "type='signal',interface='org.a11y.atspi.Event.Window',member='Destroy'";
1733 static gchar *app_sig_match_state_changed =
1734        "type='signal',interface='org.a11y.atspi.Event.Object',member='StateChanged'";
1735
1736 void spi_registry_free_active_window (SpiRegistry *reg)
1737 {
1738   if (reg->active_win)
1739     spi_reference_free (reg->active_win);
1740 }
1741 //
1742
1743 SpiRegistry *
1744 spi_registry_new (DBusConnection *bus)
1745 {
1746   SpiRegistry *reg = g_object_new (SPI_REGISTRY_TYPE, NULL);
1747
1748   reg->bus = bus;
1749
1750   dbus_bus_add_match (bus, app_sig_match_name_owner, NULL);
1751   dbus_connection_add_filter (bus, signal_filter, reg, NULL);
1752
1753   //TIZEN_ONLY(20211206) Provide GetActiveWindow
1754   reg->active_win = NULL;
1755
1756   dbus_bus_add_match (reg->bus, app_sig_match_window_activate, NULL);
1757   dbus_bus_add_match (reg->bus, app_sig_match_window_deactivate, NULL);
1758   dbus_bus_add_match (reg->bus, app_sig_match_window_destroy, NULL);
1759   dbus_bus_add_match (reg->bus, app_sig_match_state_changed, NULL);
1760   //
1761
1762   dbus_connection_register_object_path (bus, SPI_DBUS_PATH_ROOT, &root_vtable, reg);
1763
1764   dbus_connection_register_object_path (bus, SPI_DBUS_PATH_CACHE, &cache_vtable, reg);
1765
1766   dbus_connection_register_object_path (bus, SPI_DBUS_PATH_REGISTRY, &registry_vtable, reg);
1767
1768   emit_Available (bus);
1769
1770   reg->events = NULL;
1771
1772   return reg;
1773 }
1774 //
1775
1776 /*END------------------------------------------------------------------------*/