2008-11-5 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / bridge.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2008             Codethink Ltd.
6  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
7  * Copyright 2001, 2002, 2003 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 "dbus/dbus-glib-lowlevel.h"
27
28 #include <X11/Xlib.h>
29 #include <X11/Xatom.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <atk/atk.h>
36 #include <atk/atkobject.h>
37 #include <atk/atknoopobject.h>
38 #include "accessible.h"
39 #include "bridge.h"
40 #include "atk-dbus.h"
41
42 void spi_atk_register_event_listeners   (void);
43 void spi_atk_deregister_event_listeners (void);
44 void spi_atk_tidy_windows               (void);
45
46 /*---------------------------------------------------------------------------*/
47
48 SpiAppData *app_data = NULL;
49
50 static const AtkMisc *atk_misc = NULL;
51
52 /*static Display *bridge_display = NULL;*/
53
54 /*---------------------------------------------------------------------------*/
55
56 /*
57  * Returns a 'canonicalized' value for DISPLAY,
58  * with the screen number stripped off if present.
59  *
60  * Not currently used in D-Bus version but may be
61  * useful in future if we make use of XAtom.
62  */
63 #if 0
64 static const gchar*
65 spi_display_name (void)
66 {
67     static const char *canonical_display_name = NULL;
68     if (!canonical_display_name)
69       {
70         const gchar *display_env = g_getenv ("AT_SPI_DISPLAY");
71         if (!display_env)
72           {
73             display_env = g_getenv ("DISPLAY");
74             if (!display_env || !display_env[0]) 
75                 canonical_display_name = ":0";
76             else
77               {
78                 gchar *display_p, *screen_p;
79                 canonical_display_name = g_strdup (display_env);
80                 display_p = strrchr (canonical_display_name, ':');
81                 screen_p = strrchr (canonical_display_name, '.');
82                 if (screen_p && display_p && (screen_p > display_p))
83                   {
84                     *screen_p = '\0';
85                   }
86               }
87           }
88         else
89           {
90             canonical_display_name = display_env;
91           }
92       }
93     return canonical_display_name;
94 }
95 #endif
96
97 /*---------------------------------------------------------------------------*/
98
99 /*
100  * Gets the IOR from the XDisplay.
101  * Not currently used in D-Bus version, but something similar
102  * may be employed in the future for accessing the registry daemon
103  * bus name.
104  */
105 #if 0
106 static gchar *
107 spi_atk_bridge_get_registry_ior (void)
108 {
109      Atom AT_SPI_IOR;
110      Atom actual_type;
111      int actual_format;
112      unsigned char *data = NULL;  
113      unsigned long nitems;
114      unsigned long leftover;
115      if (!bridge_display) 
116        bridge_display = XOpenDisplay (spi_display_name ());
117
118      AT_SPI_IOR = XInternAtom (bridge_display, "AT_SPI_IOR", False); 
119      XGetWindowProperty(bridge_display, 
120                         XDefaultRootWindow (bridge_display),
121                         AT_SPI_IOR, 0L,
122                         (long)BUFSIZ, False,
123                         (Atom) 31, &actual_type, &actual_format,
124                         &nitems, &leftover, &data);
125      if (data == NULL)
126          g_warning (_("AT_SPI_REGISTRY was not started at session startup."));
127      return (gchar *) data;
128 }
129 #endif
130
131 /*---------------------------------------------------------------------------*/
132
133 static void
134 register_application (SpiAppData *app)
135 {
136   DBusMessage *message;
137   DBusMessageIter iter;
138   DBusError error;
139   const char *uname;
140
141   dbus_error_init (&error);
142
143   message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
144                                           SPI_DBUS_PATH_REGISTRY,
145                                           SPI_DBUS_INTERFACE_REGISTRY,
146                                           "registerApplication");
147   dbus_message_set_no_reply (message, TRUE);
148
149   uname = dbus_bus_get_unique_name(app->droute.bus);
150
151   dbus_message_iter_init_append(message, &iter);
152   dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uname);
153   dbus_connection_send (app->droute.bus, message, NULL);
154   if (message) dbus_message_unref (message);
155 }
156
157 /*---------------------------------------------------------------------------*/
158
159 static void
160 deregister_application (SpiAppData *app)
161 {
162   DBusMessage *message;
163   DBusMessageIter iter;
164   DBusError error;
165   const char *uname;
166
167   dbus_error_init (&error);
168
169   message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
170                                           SPI_DBUS_PATH_REGISTRY,
171                                           SPI_DBUS_INTERFACE_REGISTRY,
172                                           "deregisterApplication");
173   dbus_message_set_no_reply (message, TRUE);
174
175   uname = dbus_bus_get_unique_name(app->droute.bus);
176
177   dbus_message_iter_init_append(message, &iter);
178   dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uname);
179   dbus_connection_send (app->droute.bus, message, NULL);
180   if (message) dbus_message_unref (message);
181 }
182
183 /*---------------------------------------------------------------------------*/
184
185 static void
186 exit_func (void)
187 {
188   if (!app_data)
189     {
190       return;
191     }
192
193   spi_atk_tidy_windows ();
194   spi_atk_deregister_event_listeners();
195   deregister_application (app_data);
196
197   g_free(app_data);
198   app_data = NULL;
199
200   /* Not currently creating an XDisplay */
201 #if 0
202   if (bridge_display)
203     XCloseDisplay (bridge_display);
204 #endif
205 }
206
207 /*---------------------------------------------------------------------------*/
208
209 static DBusObjectPathVTable droute_vtable =
210 {
211   NULL,
212   &droute_message,
213   NULL, NULL, NULL, NULL
214 };
215
216 static gchar *atspi_dbus_name;
217 static gboolean atspi_no_register;
218
219 static GOptionEntry atspi_option_entries[] =
220 {
221   {"atspi-dbus-name", 0, 0, G_OPTION_ARG_STRING, &atspi_dbus_name, "D-Bus bus name to register as", NULL},
222   {"atspi-no-register", 0, 0, G_OPTION_ARG_NONE, &atspi_no_register, "Do not register with Registry Daemon", NULL},
223   {NULL}
224 };
225
226 /*
227  * spi_app_init
228  *
229  * The following needs to be initialized.
230  *
231  * - DRoute for routing message to their accessible objects.
232  * - Event handlers for emmitting signals on specific ATK events.
233  * - Application registration with the AT-SPI registry.
234  *
235  */
236 static int
237 adaptor_init (gint *argc, gchar **argv[])
238 {
239   GOptionContext *opt;
240   GError *err = NULL;
241   DBusError error;
242
243   if (app_data != NULL)
244      return 0;
245
246   /* Parse command line options */
247   opt = g_option_context_new(NULL);
248   g_option_context_add_main_entries(opt, atspi_option_entries, NULL);
249   g_option_context_set_ignore_unknown_options(opt, TRUE);
250   if (!g_option_context_parse(opt, argc, argv, &err))
251       g_warning("AT-SPI Option parsing failed: %s\n", err->message);
252
253   /* Allocate global data and do ATK initializations */
254   app_data = g_new0 (SpiAppData, 1);
255   atk_misc = atk_misc_get_instance ();
256
257   /* Get D-Bus connection, register D-Bus name*/
258   dbus_error_init (&error);
259   app_data->root = atk_get_root();
260   app_data->droute.bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
261   if (!app_data->droute.bus)
262   {
263     g_warning ("AT-SPI Couldn't connect to D-Bus: %s\n", error.message);
264     g_free(app_data);
265     app_data = NULL;
266     return 0;
267   }
268   if (atspi_dbus_name != NULL &&
269       dbus_bus_request_name(app_data->droute.bus, atspi_dbus_name, 0, &error))
270   {
271     g_print("AT-SPI Recieved D-Bus name - %s\n", atspi_dbus_name);
272   }
273
274   /* Finish setting up D-Bus */
275   dbus_connection_setup_with_g_main(app_data->droute.bus, g_main_context_default());
276
277   /* Register droute for routing AT-SPI messages */
278   spi_register_tree_object(app_data->droute.bus, &app_data->droute, "/org/freedesktop/atspi/tree");
279
280   if (!dbus_connection_register_fallback (app_data->droute.bus,
281                                           "/org/freedesktop/atspi/accessible",
282                                           &droute_vtable,
283                                           &app_data->droute))
284   {
285     g_warning("AT-SPI Couldn't register droute.\n");
286     g_free(app_data);
287     app_data = NULL;
288     return 0;
289   }
290
291   /* Register all interfaces with droute and set up application accessible db */
292   atk_dbus_initialize (&app_data->droute);
293
294   /* Register methods to send D-Bus signals on certain ATK events */
295   spi_atk_register_event_listeners ();
296
297   /* Register this app by sending a signal out to AT-SPI registry daemon */
298   register_application (app_data);
299
300   g_atexit (exit_func);
301
302   return 0;
303 }
304
305 /*---------------------------------------------------------------------------*/
306
307 int
308 gtk_module_init (gint *argc, gchar **argv[])
309 {
310   return adaptor_init (argc, argv);
311 }
312
313 /*END------------------------------------------------------------------------*/