1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include "config.h"
21 
22 #include <stdlib.h>
23 #include <libintl.h>
24 #include <locale.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <signal.h>
28 #include <errno.h>
29 
30 #include <glib/gi18n.h>
31 #include <gdk/gdkx.h>
32 #include <gtk/gtk.h>
33 
34 #include "gdm-common.h"
35 #include "gdm-log.h"
36 
37 #include "gdm-chooser-session.h"
38 
39 #define ACCESSIBILITY_KEY         "/desktop/gnome/interface/accessibility"
40 
41 static Atom AT_SPI_IOR;
42 
43 
44 static gboolean
assistive_registry_launch(void)45 assistive_registry_launch (void)
46 {
47         GPid        pid;
48         GError     *error;
49         const char *command;
50         char      **argv;
51         gboolean    res;
52 
53         command = AT_SPI_REGISTRYD_DIR "/at-spi2-registryd";
54 
55         argv = NULL;
56         error = NULL;
57         res = g_shell_parse_argv (command, NULL, &argv, &error);
58         if (! res) {
59                 g_warning ("Unable to parse command: %s", error->message);
60                 return FALSE;
61         }
62 
63         error = NULL;
64         res = g_spawn_async (NULL,
65                              argv,
66                              NULL,
67                              G_SPAWN_SEARCH_PATH
68                              | G_SPAWN_STDOUT_TO_DEV_NULL
69                              | G_SPAWN_STDERR_TO_DEV_NULL,
70                              NULL,
71                              NULL,
72                              &pid,
73                              &error);
74         g_strfreev (argv);
75 
76         if (! res) {
77                 g_warning ("Unable to run command %s: %s", command, error->message);
78                 return FALSE;
79         }
80 
81         if (kill (pid, 0) < 0) {
82                 g_warning ("at-spi-registryd not running");
83                 return FALSE;
84         }
85 
86         return TRUE;
87 }
88 
89 static GdkFilterReturn
filter_watch(GdkXEvent * xevent,GdkEvent * event,gpointer data)90 filter_watch (GdkXEvent *xevent,
91               GdkEvent  *event,
92               gpointer   data)
93 {
94         XEvent *xev = (XEvent *)xevent;
95 
96         if (xev->xany.type == PropertyNotify
97             && xev->xproperty.atom == AT_SPI_IOR) {
98                 gtk_main_quit ();
99 
100                 return GDK_FILTER_REMOVE;
101         }
102 
103         return GDK_FILTER_CONTINUE;
104 }
105 
106 static gboolean
filter_timeout(gpointer data)107 filter_timeout (gpointer data)
108 {
109         g_warning ("The accessibility registry was not found.");
110 
111         gtk_main_quit ();
112 
113         return FALSE;
114 }
115 
116 static void
assistive_registry_start(void)117 assistive_registry_start (void)
118 {
119         GdkWindow *root;
120         guint      tid;
121 
122         root = gdk_get_default_root_window ();
123 
124         if ( ! AT_SPI_IOR) {
125                 AT_SPI_IOR = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "AT_SPI_IOR", False);
126         }
127 
128         gdk_window_set_events (root,  GDK_PROPERTY_CHANGE_MASK);
129 
130         if ( ! assistive_registry_launch ()) {
131                 g_warning ("The accessibility registry could not be started.");
132                 return;
133         }
134 
135         gdk_window_add_filter (root, filter_watch, NULL);
136         tid = g_timeout_add_seconds (5, filter_timeout, NULL);
137 
138         gtk_main ();
139 
140         gdk_window_remove_filter (root, filter_watch, NULL);
141         g_source_remove (tid);
142 }
143 
144 static void
at_set_gtk_modules(void)145 at_set_gtk_modules (void)
146 {
147         GSList     *modules_list;
148         GSList     *l;
149         const char *old;
150         char      **modules;
151         gboolean    found_gail;
152         gboolean    found_atk_bridge;
153         int         n;
154 
155         n = 0;
156         modules_list = NULL;
157         found_gail = FALSE;
158         found_atk_bridge = FALSE;
159 
160         if ((old = g_getenv ("GTK_MODULES")) != NULL) {
161                 modules = g_strsplit (old, ":", -1);
162                 for (n = 0; modules[n]; n++) {
163                         if (!strcmp (modules[n], "gail")) {
164                                 found_gail = TRUE;
165                         } else if (!strcmp (modules[n], "atk-bridge")) {
166                                 found_atk_bridge = TRUE;
167                         }
168 
169                         modules_list = g_slist_prepend (modules_list, modules[n]);
170                         modules[n] = NULL;
171                 }
172                 g_free (modules);
173         }
174 
175         if (!found_gail) {
176                 modules_list = g_slist_prepend (modules_list, "gail");
177                 ++n;
178         }
179 
180         if (!found_atk_bridge) {
181                 modules_list = g_slist_prepend (modules_list, "atk-bridge");
182                 ++n;
183         }
184 
185         modules = g_new (char *, n + 1);
186         modules[n--] = NULL;
187         for (l = modules_list; l; l = l->next) {
188                 modules[n--] = g_strdup (l->data);
189         }
190 
191         g_setenv ("GTK_MODULES", g_strjoinv (":", modules), TRUE);
192         g_strfreev (modules);
193         g_slist_free (modules_list);
194 }
195 
196 static void
load_a11y(void)197 load_a11y (void)
198 {
199         assistive_registry_start ();
200         at_set_gtk_modules ();
201 }
202 
203 int
main(int argc,char * argv[])204 main (int argc, char *argv[])
205 {
206         GdmChooserSession *session;
207         gboolean           res;
208         GError            *error;
209 
210         bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
211         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
212         textdomain (GETTEXT_PACKAGE);
213 
214         setlocale (LC_ALL, "");
215 
216         gdm_log_init ();
217         gdm_log_set_debug (TRUE);
218 
219         g_debug ("Chooser for display %s xauthority:%s",
220                  g_getenv ("DISPLAY"),
221                  g_getenv ("XAUTHORITY"));
222 
223         gdk_init (&argc, &argv);
224 
225         load_a11y ();
226 
227         gtk_init (&argc, &argv);
228 
229         session = gdm_chooser_session_new ();
230         if (session == NULL) {
231                 g_critical ("Unable to create chooser session");
232                 exit (EXIT_FAILURE);
233         }
234 
235         error = NULL;
236         res = gdm_chooser_session_start (session, &error);
237         if (! res) {
238                 g_warning ("Unable to start chooser session: %s", error->message);
239                 g_error_free (error);
240                 exit (EXIT_FAILURE);
241         }
242 
243         gtk_main ();
244 
245         if (session != NULL) {
246                 g_object_unref (session);
247         }
248 
249         return 0;
250 }
251