/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
- *
- * at-spi-bus-launcher: Manage the a11y bus as a child process
+ *
+ * at-spi-bus-launcher: Manage the a11y bus as a child process
*
* Copyright 2011 Red Hat, Inc.
*
#define APP_CONTROL_OPERATION_SCREEN_READ "http://tizen.org/appcontrol/operation/read_screen"
#include <appsvc.h>
#include <vconf.h>
+
+//uncomment if you want debug
+//#ifndef TIZEN_ENGINEER_MODE
+//#define TIZEN_ENGINEER_MODE
+//#endif
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "ATSPI_BUS_LAUNCHER"
+
#include <dlog.h>
#include <aul.h>
+//uncomment this if you want log suring startup
+//seems like dlog is not working at startup time
+#define ATSPI_BUS_LAUNCHER_LOG_TO_FILE
+
+#ifdef ATSPI_BUS_LAUNCHER_LOG_TO_FILE
+FILE *log_file;
+#ifdef LOGD
+#undef LOGD
+#endif
+#define LOGD(arg...) do {if (log_file) {fprintf(log_file, ##arg);fprintf(log_file, "\n"); fflush(log_file);}} while(0)
+#endif
+
+
typedef enum {
A11Y_BUS_STATE_IDLE = 0,
A11Y_BUS_STATE_READING_ADDRESS,
GSettings *a11y_schema;
GSettings *interface_schema;
+ int launch_screen_reader_repeats;
gboolean screen_reader_needed;
int pid;
#ifdef __linux
#include <sys/prctl.h>
prctl (PR_SET_PDEATHSIG, 15);
-#endif
+#endif
}
/**
gpointer data)
{
A11yBusLauncher *app = data;
-
+
app->a11y_bus_pid = -1;
app->state = A11Y_BUS_STATE_ERROR;
if (app->a11y_launch_error_message == NULL)
app->a11y_launch_error_message = g_strdup_printf ("Bus stopped by signal %d", WSTOPSIG (status));
}
g_main_loop_quit (app->loop);
-}
+}
static gboolean
ensure_a11y_bus (A11yBusLauncher *app)
if (app->a11y_bus_pid != 0)
return FALSE;
-
+
argv[1] = g_strdup_printf ("--config-file=%s/at-spi2/accessibility.conf", SYSCONFDIR);
if (pipe (app->pipefd) < 0)
g_error ("Failed to create pipe: %s", strerror (errno));
-
+
if (!g_spawn_async (NULL,
argv,
NULL,
app->state = A11Y_BUS_STATE_READING_ADDRESS;
app->a11y_bus_pid = pid;
- g_debug ("Launched a11y bus, child is %ld", (long) pid);
+ LOGD("Launched a11y bus, child is %ld", (long) pid);
if (!unix_read_all_fd_to_string (app->pipefd[0], addr_buf, sizeof (addr_buf)))
{
app->a11y_launch_error_message = g_strdup_printf ("Failed to read address: %s", strerror (errno));
/* Trim the trailing newline */
app->a11y_bus_address = g_strchomp (g_strdup (addr_buf));
- g_debug ("a11y bus address: %s", app->a11y_bus_address);
+ LOGD("a11y bus address: %s", app->a11y_bus_address);
#ifdef HAVE_X11
{
}
#endif
+ if (argv[1]) g_free(argv[1]);
+
return TRUE;
-
+
error:
+ if (argv[1]) g_free(argv[1]);
close (app->pipefd[0]);
close (app->pipefd[1]);
app->state = A11Y_BUS_STATE_ERROR;
A11yBusLauncher *app = user_data;
const gchar *type = g_variant_get_type_string (value);
gboolean enabled;
-
+
if (g_strcmp0 (type, "b") != 0)
{
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
A11yBusLauncher *app = user_data;
GError *error;
guint registration_id;
-
+
if (connection == NULL)
{
g_main_loop_quit (app->loop);
gpointer data)
{
A11yBusLauncher *app = data;
-
+
g_main_loop_quit (app->loop);
return FALSE;
bridge_display = XOpenDisplay (NULL);
if (!bridge_display)
return FALSE;
-
+
AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False);
XGetWindowProperty (bridge_display,
XDefaultRootWindow (bridge_display),
}
static gboolean
-_launch_screen_reader(A11yBusLauncher *bl)
+_launch_screen_reader(gpointer user_data, gboolean by_vconf_change)
{
+ A11yBusLauncher *bl = user_data;
+ LOGD("Launching screen reader");
+
bundle *kb = NULL;
gboolean ret = FALSE;
kb = bundle_create();
+
if (kb == NULL)
- return FALSE;
+ {
+ LOGD("Can't create bundle");
+ return FALSE;
+ }
+
+ if (by_vconf_change)
+ {
+ if (bundle_add_str(kb, "by_vconf_change", "yes") != BUNDLE_ERROR_NONE)
+ {
+ LOGD("Can't add information to bundle");
+ }
+ }
+
+ int operation_error = appsvc_set_operation(kb, APP_CONTROL_OPERATION_SCREEN_READ);
+ LOGD("appsvc_set_operation: %i", operation_error);
- appsvc_set_operation(kb, APP_CONTROL_OPERATION_SCREEN_READ);
+ bl->pid = appsvc_run_service(kb, 0, NULL, NULL);
+
+ if (bl->pid > 0)
+ {
+ LOGD("Screen reader launched with pid: %i", bl->pid);
+ ret = TRUE;
+ }
+ else
+ {
+ LOGD("Can't start screen-reader - error code: %i", bl->pid);
+ }
- bl->pid = appsvc_usr_run_service(kb, 0, NULL, NULL, getuid());
- if (bl->pid >= 0) {
- ret = TRUE;
- }
bundle_free(kb);
return ret;
}
static gboolean
+_launch_screen_reader_repeat_until_success(gpointer user_data) {
+ A11yBusLauncher *bl = user_data;
+
+ if (bl->launch_screen_reader_repeats > 100 || bl->pid > 0)
+ {
+ //do not try anymore
+ return FALSE;
+ }
+
+ gboolean ret = _launch_screen_reader(user_data, FALSE);
+
+ if (ret)
+ {
+ //we managed to
+ bl->launch_screen_reader_repeats = 0;
+ return FALSE;
+ }
+ //try again
+ return TRUE;
+}
+
+static gboolean
_terminate_screen_reader(A11yBusLauncher *bl)
{
+ LOGD("Terminating screen reader");
int ret;
+ int ret_aul;
if (bl->pid <= 0)
return FALSE;
+
+ int status = aul_app_get_status_bypid(bl->pid);
+
+ if (status < 0)
+ {
+ LOGD("App with pid %d already terminated", bl->pid);
+ bl->pid = 0;
+ return TRUE;
+ }
+
LOGD("terminate process with pid %d", bl->pid);
- if (!aul_terminate_pid(bl->pid))
+ ret_aul = aul_terminate_pid(bl->pid);
+ if (ret_aul >= 0)
{
+ LOGD("Terminating with aul_terminate_pid: return is %d", ret_aul);
bl->pid = 0;
return TRUE;
}
+ else
+ LOGD("aul_terminate_pid failed: return is %d", ret_aul);
LOGD("Unable to terminate process using aul api. Sending SIGTERM signal");
ret = kill(bl->pid, SIGTERM);
int ret;
ret = vconf_keynode_get_bool(node);
+ LOGD("vconf_keynode_get_bool(node): %i", ret);
if (ret < 0)
return;
- bl->screen_reader_needed = ret;
+ //check if process really exists (e.g didn't crash)
+ if (bl->pid > 0)
+ {
+ int err = kill(bl->pid,0);
+ //process doesn't exist
+ if (err == ESRCH)
+ bl->pid = 0;
+ }
+ bl->screen_reader_needed = ret;
+ LOGD("bl->screen_reader_needed: %i, bl->pid: %i", ret, bl->pid);
if (!bl->screen_reader_needed && (bl->pid > 0))
_terminate_screen_reader(bl);
else if (bl->screen_reader_needed && (bl->pid <= 0))
- _launch_screen_reader(bl);
+ _launch_screen_reader(bl, TRUE);
}
int
main (int argc,
char **argv)
{
+#ifdef ATSPI_BUS_LAUNCHER_LOG_TO_FILE
+ log_file = fopen("/tmp/at-spi-bus-launcher.log", "a");
+#endif
+
+ LOGD("Starting atspi bus launcher");
GError *error = NULL;
GMainLoop *loop;
GDBusConnection *session_bus;
gint i;
if (already_running ())
- return 0;
+ {
+ LOGD("atspi bus launcher is already running");
+ return 0;
+ }
_global_app = g_slice_new0 (A11yBusLauncher);
_global_app->loop = g_main_loop_new (NULL, FALSE);
+ _global_app->launch_screen_reader_repeats = 0;
for (i = 1; i < argc; i++)
{
_global_app,
NULL);
- int ret = vconf_get_bool("db/menu/accessibility/screen_reader", &_global_app->screen_reader_needed);
+ int ret = vconf_get_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &_global_app->screen_reader_needed);
if (ret != 0)
{
- LOGD("Could not read 'db/menu/accessibility/screen_reader' key value.\n");
+ LOGD("Could not read VCONFKEY_SETAPPL_ACCESSIBILITY_TTS key value.\n");
return FALSE;
}
- ret = vconf_notify_key_changed("db/menu/accessibility/screen_reader", screen_reader_cb, _global_app);
+ ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, screen_reader_cb, _global_app);
if(ret != 0)
{
LOGD("Could not add information level callback\n");
return FALSE;
}
if (_global_app->screen_reader_needed)
- _launch_screen_reader(_global_app);
+ g_timeout_add_seconds(2,_launch_screen_reader_repeat_until_success, _global_app);
g_main_loop_run (_global_app->loop);
if (_global_app->a11y_bus_pid > 0)
kill (_global_app->a11y_bus_pid, SIGTERM);
- /* Clear the X property if our bus is gone; in the case where e.g.
+ /* Clear the X property if our bus is gone; in the case where e.g.
* GDM is launching a login on an X server it was using before,
* we don't want early login processes to pick up the stale address.
*/