X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=registryd%2Fdeviceeventcontroller.c;h=61ab91d40dec55c2fe9b497cdc0964a2f78fd5d8;hb=535f1a1be9a7e94cb8ec33877903f814f85242ca;hp=c63f41dd2de64c6507cfc01b5e6211fabd824874;hpb=2da78cef2bf99aef92f5de6b83df4094bf01277e;p=platform%2Fupstream%2Fat-spi2-core.git diff --git a/registryd/deviceeventcontroller.c b/registryd/deviceeventcontroller.c index c63f41d..61ab91d 100644 --- a/registryd/deviceeventcontroller.c +++ b/registryd/deviceeventcontroller.c @@ -33,12 +33,13 @@ #include #include #include -#include #include +#include #include #include #define XK_MISCELLANY +#define XK_LATIN1 #include #ifdef HAVE_XEVIE @@ -47,22 +48,44 @@ #include #endif /* HAVE_XEVIE */ -#include -#include /* TODO: hide dependency (wrap in single porting file) */ -#include -#include +#include + +#include + +#include "paths.h" +#include "keymasks.h" +#include "de-types.h" +#include "de-marshaller.h" +#include "display.h" +#include "event-source.h" -#include "../libspi/spi-private.h" #include "deviceeventcontroller.h" +#include "reentrant-list.h" + +#include "introspection.h" + +KeySym ucs2keysym (long ucs); +long keysym2ucs(KeySym keysym); + +#define CHECK_RELEASE_DELAY 20 +#define BIT(c, x) (c[x/8]&(1<<(x%8))) +static guint check_release_handler = 0; +static Accessibility_DeviceEvent pressed_event; +static SpiDEController *saved_controller; +static void wait_for_release_event (XEvent *event, SpiDEController *controller); /* Our parent Gtk object type */ -#define PARENT_TYPE BONOBO_TYPE_OBJECT +#define PARENT_TYPE G_TYPE_OBJECT /* A pointer to our parent object class */ -static GObjectClass *spi_device_event_controller_parent_class; static int spi_error_code = 0; -static GdkPoint last_mouse_pos_static = {0, 0}; -static GdkPoint *last_mouse_pos = &last_mouse_pos_static; +struct _SpiPoint { + gint x; + gint y; +}; +typedef struct _SpiPoint SpiPoint; +static SpiPoint last_mouse_pos_static = {0, 0}; +static SpiPoint *last_mouse_pos = &last_mouse_pos_static; static unsigned int mouse_mask_state = 0; static unsigned int mouse_button_mask = Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask; @@ -71,8 +94,12 @@ static unsigned int key_modifier_mask = static unsigned int _numlock_physical_mask = Mod2Mask; /* a guess, will be reset */ static GQuark spi_dec_private_quark = 0; +static XModifierKeymap* xmkeymap = NULL; + +static gboolean have_mouse_listener = FALSE; +static gboolean have_mouse_event_listener = FALSE; -int (*x_default_error_handler) (Display *display, XErrorEvent *error_event); +static int (*x_default_error_handler) (Display *display, XErrorEvent *error_event); typedef enum { SPI_DEVICE_TYPE_KBD, @@ -86,19 +113,20 @@ typedef struct { guint pending_remove : 1; Accessibility_ControllerEventMask mod_mask; - CORBA_unsigned_long key_val; /* KeyCode */ + dbus_uint32_t key_val; /* KeyCode */ } DEControllerGrabMask; typedef struct { - CORBA_Object object; + char *bus_name; + char *path; SpiDeviceTypeCategory type; - Accessibility_EventTypeSeq *typeseq; + gulong types; } DEControllerListener; typedef struct { DEControllerListener listener; - Accessibility_KeySet *keys; + GSList *keys; Accessibility_ControllerEventMask mask; Accessibility_EventListenerMode *mode; } DEControllerKeyListener; @@ -115,36 +143,82 @@ typedef struct { unsigned int xkb_latch_mask; unsigned int pending_xkb_mod_relatch_mask; XkbDescPtr xkb_desc; + KeyCode reserved_keycode; + KeySym reserved_keysym; + guint reserved_reset_timeout; } DEControllerPrivateData; static void spi_controller_register_with_devices (SpiDEController *controller); static gboolean spi_controller_update_key_grabs (SpiDEController *controller, Accessibility_DeviceEvent *recv); static gboolean spi_controller_register_device_listener (SpiDEController *controller, - DEControllerListener *l, - CORBA_Environment *ev); + DEControllerListener *l); static gboolean spi_device_event_controller_forward_key_event (SpiDEController *controller, const XEvent *event); -static void spi_deregister_controller_device_listener (SpiDEController *controller, - DEControllerListener *listener, - CORBA_Environment *ev); +static void spi_controller_deregister_device_listener (SpiDEController *controller, + DEControllerListener *listener); static void spi_deregister_controller_key_listener (SpiDEController *controller, - DEControllerKeyListener *key_listener, - CORBA_Environment *ev); + DEControllerKeyListener *key_listener); static gboolean spi_controller_notify_mouselisteners (SpiDEController *controller, - const Accessibility_DeviceEvent *event, - CORBA_Environment *ev); + const Accessibility_DeviceEvent *event); -static gboolean spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq *type_seq, +static gboolean spi_eventtype_seq_contains_event (dbus_uint32_t types, const Accessibility_DeviceEvent *event); static gboolean spi_clear_error_state (void); static gboolean spi_dec_poll_mouse_moved (gpointer data); static gboolean spi_dec_poll_mouse_moving (gpointer data); static gboolean spi_dec_poll_mouse_idle (gpointer data); -#define spi_get_display() GDK_DISPLAY() +G_DEFINE_TYPE(SpiDEController, spi_device_event_controller, G_TYPE_OBJECT) + +DBusMessage * +invalid_arguments_error (DBusMessage *message) +{ + DBusMessage *reply; + gchar *errmsg; + + errmsg= g_strdup_printf ( + "Method \"%s\" with signature \"%s\" on interface \"%s\" was supplied with invalid arguments\n", + dbus_message_get_member (message), + dbus_message_get_signature (message), + dbus_message_get_interface (message)); + reply = dbus_message_new_error (message, + DBUS_ERROR_INVALID_ARGS, + errmsg); + g_free (errmsg); + return reply; +} /* Private methods */ +static dbus_bool_t +spi_dbus_add_disconnect_match (DBusConnection *bus, const char *name) +{ + char *match = g_strdup_printf ("interface=%s,member=NameOwnerChanged,arg0=%s", DBUS_INTERFACE_DBUS, name); + if (match) + { + DBusError error; + dbus_error_init (&error); + dbus_bus_add_match (bus, match, &error); + g_free (match); + return !dbus_error_is_set (&error); + } + else return FALSE; +} + +static dbus_bool_t +spi_dbus_remove_disconnect_match (DBusConnection *bus, const char *name) +{ + char *match = g_strdup_printf ("interface=%s,member=NameOwnerChanged,arg0=%s", DBUS_INTERFACE_DBUS, name); + if (match) + { + DBusError error; + dbus_error_init (&error); + dbus_bus_remove_match (bus, match, &error); + g_free (match); + return !dbus_error_is_set (&error); + } + else return FALSE; +} static unsigned int keysym_mod_mask (KeySym keysym, KeyCode keycode) @@ -192,11 +266,76 @@ keysym_mod_mask (KeySym keysym, KeyCode keycode) return retval; } +static gboolean +spi_dec_replace_map_keysym (DEControllerPrivateData *priv, KeyCode keycode, KeySym keysym) +{ +#ifdef HAVE_XKB + Display *dpy = spi_get_display (); + XkbDescPtr desc; + if (!(desc = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd))) + { + fprintf (stderr, "ERROR getting map\n"); + } + XFlush (dpy); + XSync (dpy, False); + if (desc && desc->map) + { + gint offset = desc->map->key_sym_map[keycode].offset; + desc->map->syms[offset] = keysym; + } + else + { + fprintf (stderr, "Error changing key map: empty server structure\n"); + } + XkbSetMap (dpy, XkbAllMapComponentsMask, desc); + /** + * FIXME: the use of XkbChangeMap, and the reuse of the priv->xkb_desc structure, + * would be far preferable. + * HOWEVER it does not seem to work using XFree 4.3. + **/ + /* XkbChangeMap (dpy, priv->xkb_desc, priv->changes); */ + XFlush (dpy); + XSync (dpy, False); + XkbFreeKeyboard (desc, 0, TRUE); + + return TRUE; +#else + return FALSE; +#endif +} + +static gboolean +spi_dec_reset_reserved (gpointer data) +{ + DEControllerPrivateData *priv = data; + spi_dec_replace_map_keysym (priv, priv->reserved_keycode, priv->reserved_keysym); + priv->reserved_reset_timeout = 0; + return FALSE; +} + static KeyCode -keycode_for_keysym (long keysym, unsigned int *modmask) +keycode_for_keysym (SpiDEController *controller, long keysym, unsigned int *modmask) { KeyCode keycode = 0; keycode = XKeysymToKeycode (spi_get_display (), (KeySym) keysym); + if (!keycode) + { + DEControllerPrivateData *priv = (DEControllerPrivateData *) + g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark); + /* if there's no keycode available, fix it */ + if (spi_dec_replace_map_keysym (priv, priv->reserved_keycode, keysym)) + { + keycode = priv->reserved_keycode; + /* + * queue a timer to restore the old keycode. Ugly, but required + * due to races / asynchronous X delivery. + * Long-term fix is to extend the X keymap here instead of replace entries. + */ + priv->reserved_reset_timeout = g_timeout_add (500, spi_dec_reset_reserved, priv); + } + *modmask = 0; + return keycode; + } if (modmask) *modmask = keysym_mod_mask (keysym, keycode); return keycode; @@ -255,17 +394,44 @@ spi_dec_clear_unlatch_pending (SpiDEController *controller) { DEControllerPrivateData *priv = g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark); - priv->xkb_latch_mask = 0; + priv->xkb_latch_mask = 0; } - + +static void emit(SpiDEController *controller, const char *interface, const char *name, const char *minor, int a1, int a2) +{ + DBusMessage *signal = NULL; + DBusMessageIter iter, iter_struct, iter_variant; + int nil = 0; + const char *path = SPI_DBUS_PATH_ROOT; + const char *bus_name = dbus_bus_get_unique_name (controller->bus); + + signal = dbus_message_new_signal (path, interface, name); + + dbus_message_iter_init_append (signal, &iter); + + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &minor); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &a1); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &a2); + dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "i", &iter_variant); + dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_INT32, &nil); + dbus_message_iter_close_container (&iter, &iter_variant); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL, + &iter_struct); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &bus_name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path); + dbus_message_iter_close_container (&iter, &iter_struct); + + dbus_connection_send (controller->bus, signal, NULL); + dbus_message_unref (signal); +} + static gboolean -spi_dec_button_update_and_emit (SpiDEController *controller, +spi_dec_button_update_and_emit (SpiDEController *controller, guint mask_return) { - CORBA_Environment ev; - Accessibility_Event e; Accessibility_DeviceEvent mouse_e; - gchar event_name[24]; + gchar event_detail[3]; gboolean is_consumed = FALSE; if ((mask_return & mouse_button_mask) != @@ -344,7 +510,7 @@ spi_dec_button_update_and_emit (SpiDEController *controller, fprintf (stderr, "Button %d %s\n", button_number, (is_down) ? "Pressed" : "Released"); #endif - snprintf (event_name, 22, "mouse:button:%d%c", button_number, + snprintf (event_detail, 3, "%d%c", button_number, (is_down) ? 'p' : 'r'); /* TODO: FIXME distinguish between physical and * logical buttons @@ -354,25 +520,17 @@ spi_dec_button_update_and_emit (SpiDEController *controller, Accessibility_BUTTON_RELEASED_EVENT; mouse_e.id = button_number; mouse_e.hw_code = button_number; - mouse_e.modifiers = (CORBA_unsigned_short) mouse_mask_state; + mouse_e.modifiers = (dbus_uint16_t) mouse_mask_state; mouse_e.timestamp = 0; mouse_e.event_string = ""; - mouse_e.is_text = CORBA_FALSE; + mouse_e.is_text = FALSE; is_consumed = spi_controller_notify_mouselisteners (controller, - &mouse_e, - &ev); - e.type = event_name; - e.source = BONOBO_OBJREF (controller->registry->desktop); - e.detail1 = last_mouse_pos->x; - e.detail2 = last_mouse_pos->y; - spi_init_any_nil (&e.any_data); - CORBA_exception_init (&ev); + &mouse_e); if (!is_consumed) { - Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry), - &e, - &ev); + dbus_uint32_t x = last_mouse_pos->x, y = last_mouse_pos->y; + emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "Button", event_detail, x, y); } else spi_dec_set_unlatch_pending (controller, mask_return); @@ -390,8 +548,6 @@ static guint spi_dec_mouse_check (SpiDEController *controller, int *x, int *y, gboolean *moved) { - Accessibility_Event e; - CORBA_Environment ev; int win_x_return,win_y_return; unsigned int mask_return; Window root_return, child_return; @@ -416,26 +572,14 @@ spi_dec_mouse_check (SpiDEController *controller, if (*x != last_mouse_pos->x || *y != last_mouse_pos->y) { - e.type = "mouse:abs"; - e.source = BONOBO_OBJREF (controller->registry->desktop); - e.detail1 = *x; - e.detail2 = *y; - spi_init_any_nil (&e.any_data); - CORBA_exception_init (&ev); - Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry), - &e, - &ev); - e.type = "mouse:rel"; - e.source = BONOBO_OBJREF (controller->registry->desktop); - e.detail1 = *x - last_mouse_pos->x; - e.detail2 = *y - last_mouse_pos->y; - spi_init_any_nil (&e.any_data); - CORBA_exception_init (&ev); + // TODO: combine these two signals? + dbus_uint32_t ix = *x, iy = *y; + emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "Abs", "", ix, iy); + ix -= last_mouse_pos->x; + iy -= last_mouse_pos->y; + emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "Rel", "", ix, iy); last_mouse_pos->x = *x; last_mouse_pos->y = *y; - Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry), - &e, - &ev); *moved = True; } else @@ -450,8 +594,7 @@ static void spi_dec_emit_modifier_event (SpiDEController *controller, guint prev_mask, guint current_mask) { - Accessibility_Event e; - CORBA_Environment ev; + dbus_uint32_t d1, d2; #ifdef SPI_XKB_DEBUG fprintf (stderr, "MODIFIER CHANGE EVENT! %x to %x\n", @@ -464,28 +607,21 @@ spi_dec_emit_modifier_event (SpiDEController *controller, guint prev_mask, if (current_mask & _numlock_physical_mask) current_mask |= SPI_KEYMASK_NUMLOCK; - e.type = "keyboard:modifiers"; - e.source = BONOBO_OBJREF (controller->registry->desktop); - e.detail1 = prev_mask & key_modifier_mask; - e.detail2 = current_mask & key_modifier_mask; - spi_init_any_nil (&e.any_data); - CORBA_exception_init (&ev); - Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry), - &e, - &ev); + d1 = prev_mask & key_modifier_mask; + d2 = current_mask & key_modifier_mask; + emit(controller, SPI_DBUS_INTERFACE_EVENT_KEYBOARD, "Modifiers", "", d1, d2); } static gboolean spi_dec_poll_mouse_moved (gpointer data) { - SpiRegistry *registry = SPI_REGISTRY (data); - SpiDEController *controller = registry->de_controller; - int x, y; + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(data); + int x, y; gboolean moved; guint mask_return; mask_return = spi_dec_mouse_check (controller, &x, &y, &moved); - + if ((mask_return & key_modifier_mask) != (mouse_mask_state & key_modifier_mask)) { @@ -499,7 +635,9 @@ spi_dec_poll_mouse_moved (gpointer data) static gboolean spi_dec_poll_mouse_idle (gpointer data) { - if (! spi_dec_poll_mouse_moved (data)) + if (!have_mouse_event_listener && !have_mouse_listener) + return FALSE; + else if (!spi_dec_poll_mouse_moved (data)) return TRUE; else { @@ -511,7 +649,9 @@ spi_dec_poll_mouse_idle (gpointer data) static gboolean spi_dec_poll_mouse_moving (gpointer data) { - if (spi_dec_poll_mouse_moved (data)) + if (!have_mouse_event_listener && !have_mouse_listener) + return FALSE; + else if (spi_dec_poll_mouse_moved (data)) return TRUE; else { @@ -535,15 +675,15 @@ spi_dec_ungrab_mouse (gpointer data) #endif static void -spi_dec_init_mouse_listener (SpiRegistry *registry) +spi_dec_init_mouse_listener (SpiDEController *dec) { +#ifdef GRAB_BUTTON Display *display = spi_get_display (); - g_timeout_add (100, spi_dec_poll_mouse_idle, registry); if (display) { if (XGrabButton (display, AnyButton, AnyModifier, - gdk_x11_get_default_root_xwindow (), + spi_get_root_window (), True, ButtonPressMask | ButtonReleaseMask, GrabModeSync, GrabModeAsync, None, None) != Success) { #ifdef SPI_DEBUG @@ -556,42 +696,53 @@ spi_dec_init_mouse_listener (SpiRegistry *registry) fprintf (stderr, "mouse buttons grabbed\n"); #endif } +#endif } /** * Eventually we can use this to make the marshalling of mask types * more sane, but for now we just use this to detect - * the use of 'virtual' masks such as Mumlock and convert them to + * the use of 'virtual' masks such as numlock and convert them to * system-specific mask values (i.e. ModMask). * **/ static Accessibility_ControllerEventMask spi_dec_translate_mask (Accessibility_ControllerEventMask mask) { - DEControllerPrivateData *priv; + Accessibility_ControllerEventMask tmp_mask; + gboolean has_numlock; - if (mask == SPI_KEYMASK_NUMLOCK) { - mask = _numlock_physical_mask; - } - return mask; + has_numlock = (mask & SPI_KEYMASK_NUMLOCK); + tmp_mask = mask; + if (has_numlock) + { + tmp_mask = mask ^ SPI_KEYMASK_NUMLOCK; + tmp_mask |= _numlock_physical_mask; + } + + return tmp_mask; } static DEControllerKeyListener * -spi_dec_key_listener_new (CORBA_Object l, - const Accessibility_KeySet *keys, +spi_dec_key_listener_new (const char *bus_name, + const char *path, + GSList *keys, const Accessibility_ControllerEventMask mask, - const Accessibility_EventTypeSeq *typeseq, - const Accessibility_EventListenerMode *mode, - CORBA_Environment *ev) + const dbus_uint32_t types, + const Accessibility_EventListenerMode *mode) { DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1); - key_listener->listener.object = bonobo_object_dup_ref (l, ev); + key_listener->listener.bus_name = g_strdup(bus_name); + key_listener->listener.path = g_strdup(path); key_listener->listener.type = SPI_DEVICE_TYPE_KBD; - key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet); + key_listener->keys = keys; key_listener->mask = spi_dec_translate_mask (mask); - key_listener->listener.typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq); + key_listener->listener.types = types; if (mode) - key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode); + { + key_listener->mode = (Accessibility_EventListenerMode *) g_malloc(sizeof(Accessibility_EventListenerMode)); + memcpy(key_listener->mode, mode, sizeof(*mode)); + } else key_listener->mode = NULL; @@ -600,82 +751,123 @@ spi_dec_key_listener_new (CORBA_Object l, (unsigned int) key_listener->mask, (int) (mode ? mode->global : 0), (void *) key_listener->keys, - (int) (key_listener->keys ? key_listener->keys->_length : 0)); + (int) (key_listener->keys ? g_slist_length(key_listener->keys) : 0)); #endif return key_listener; } static DEControllerListener * -spi_dec_listener_new (CORBA_Object l, - const Accessibility_EventTypeSeq *typeseq, - CORBA_Environment *ev) +spi_dec_listener_new (const char *bus_name, + const char *path, + dbus_uint32_t types) { DEControllerListener *listener = g_new0 (DEControllerListener, 1); - listener->object = bonobo_object_dup_ref (l, ev); + listener->bus_name = g_strdup(bus_name); + listener->path = g_strdup(path); listener->type = SPI_DEVICE_TYPE_MOUSE; - listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq); + listener->types = types; return listener; } static DEControllerListener * -spi_listener_clone (DEControllerListener *listener, CORBA_Environment *ev) +spi_listener_clone (DEControllerListener *listener) { DEControllerListener *clone = g_new0 (DEControllerListener, 1); - clone->object = - CORBA_Object_duplicate (listener->object, ev); + clone->bus_name = g_strdup (listener->bus_name); + clone->path = g_strdup (listener->path); clone->type = listener->type; - clone->typeseq = ORBit_copy_value (listener->typeseq, TC_Accessibility_EventTypeSeq); + clone->types = listener->types; return clone; } +static GSList *keylist_clone (GSList *s) +{ + GSList *d = NULL; + GSList *l; + + for (l = s; l; l = g_slist_next(l)) + { + Accessibility_KeyDefinition *kd = (Accessibility_KeyDefinition *)g_malloc(sizeof(Accessibility_KeyDefinition)); + if (kd) + { + Accessibility_KeyDefinition *kds = (Accessibility_KeyDefinition *)l->data; + kd->keycode = kds->keycode; + kd->keysym = kds->keysym; + kd->keystring = g_strdup(kds->keystring); + d = g_slist_append(d, kd); + } + } + return d; +} + static DEControllerKeyListener * -spi_key_listener_clone (DEControllerKeyListener *key_listener, CORBA_Environment *ev) +spi_key_listener_clone (DEControllerKeyListener *key_listener) { DEControllerKeyListener *clone = g_new0 (DEControllerKeyListener, 1); - clone->listener.object = - CORBA_Object_duplicate (key_listener->listener.object, ev); + clone->listener.bus_name = g_strdup (key_listener->listener.bus_name); + clone->listener.path = g_strdup (key_listener->listener.path); clone->listener.type = SPI_DEVICE_TYPE_KBD; - clone->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet); + clone->keys = keylist_clone (key_listener->keys); clone->mask = key_listener->mask; - clone->listener.typeseq = ORBit_copy_value (key_listener->listener.typeseq, TC_Accessibility_EventTypeSeq); + clone->listener.types = key_listener->listener.types; if (key_listener->mode) - clone->mode = ORBit_copy_value (key_listener->mode, TC_Accessibility_EventListenerMode); + { + clone->mode = (Accessibility_EventListenerMode *)g_malloc(sizeof(Accessibility_EventListenerMode)); + if (clone->mode) memcpy(clone->mode, key_listener->mode, sizeof(Accessibility_EventListenerMode)); + } else clone->mode = NULL; return clone; } +static void keylist_free(GSList *keys) +{ + GSList *l; + + for (l = keys; l; l = g_slist_next(l)) + { + Accessibility_KeyDefinition *kd = (Accessibility_KeyDefinition *)l->data; + g_free(kd->keystring); + g_free(kd); + } + g_slist_free (keys); +} + static void -spi_key_listener_data_free (DEControllerKeyListener *key_listener, CORBA_Environment *ev) +spi_key_listener_data_free (DEControllerKeyListener *key_listener) { - CORBA_free (key_listener->listener.typeseq); - CORBA_free (key_listener->keys); + keylist_free(key_listener->keys); + if (key_listener->mode) g_free(key_listener->mode); + g_free (key_listener->listener.bus_name); + g_free (key_listener->listener.path); g_free (key_listener); } static void -spi_key_listener_clone_free (DEControllerKeyListener *clone, CORBA_Environment *ev) +spi_key_listener_clone_free (DEControllerKeyListener *clone) { - CORBA_Object_release (clone->listener.object, ev); - spi_key_listener_data_free (clone, ev); + spi_key_listener_data_free (clone); } static void -spi_listener_clone_free (DEControllerListener *clone, CORBA_Environment *ev) +spi_listener_clone_free (DEControllerListener *clone) { - CORBA_Object_release (clone->object, ev); - CORBA_free (clone->typeseq); + g_free (clone->path); + g_free (clone->bus_name); g_free (clone); } static void -spi_dec_listener_free (DEControllerListener *listener, - CORBA_Environment *ev) +spi_dec_listener_free (DEControllerListener *listener) { - bonobo_object_release_unref (listener->object, ev); if (listener->type == SPI_DEVICE_TYPE_KBD) - spi_key_listener_data_free ((DEControllerKeyListener *) listener, ev); + spi_key_listener_data_free ((DEControllerKeyListener *) listener); + else + { + g_free (listener->bus_name); + g_free (listener->path); + } } static void @@ -723,10 +915,6 @@ _deregister_keygrab (SpiDEController *controller, cur_mask->pending_remove = TRUE; } } - else - { - DBG (1, g_warning ("De-registering non-existant grab")); - } } static void @@ -738,7 +926,7 @@ handle_keygrab (SpiDEController *controller, DEControllerGrabMask grab_mask = { 0 }; grab_mask.mod_mask = key_listener->mask; - if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */ + if (g_slist_length (key_listener->keys) == 0) /* special case means AnyKey/AllKeys */ { grab_mask.key_val = AnyKey; #ifdef SPI_DEBUG @@ -748,16 +936,16 @@ handle_keygrab (SpiDEController *controller, } else { - int i; + GSList *l; - for (i = 0; i < key_listener->keys->_length; ++i) + for (l = key_listener->keys; l; l = g_slist_next(l)) { - Accessibility_KeyDefinition keydef = key_listener->keys->_buffer[i]; - long int key_val = keydef.keysym; + Accessibility_KeyDefinition *keydef = l->data; + long int key_val = keydef->keysym; /* X Grabs require keycodes, not keysyms */ - if (keydef.keystring && keydef.keystring[0]) + if (keydef->keystring && keydef->keystring[0]) { - key_val = XStringToKeysym(keydef.keystring); + key_val = XStringToKeysym(keydef->keystring); } if (key_val > 0) { @@ -765,7 +953,7 @@ handle_keygrab (SpiDEController *controller, } else { - key_val = keydef.keycode; + key_val = keydef->keycode; } grab_mask.key_val = key_val; process_cb (controller, &grab_mask); @@ -793,12 +981,129 @@ spi_controller_deregister_global_keygrabs (SpiDEController *controller, spi_controller_update_key_grabs (controller, NULL); } +static void +append_keystroke_listener (DBusMessageIter *iter, DEControllerKeyListener *listener) +{ + dbus_uint32_t d_uint; + DBusMessageIter iter_struct, iter_subarray, iter_substruct; + GList *l; + GSList *kl; + + if (!dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, + &iter_struct)) + return; + + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, + &listener->listener.bus_name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, + &listener->listener.path); + d_uint = listener->listener.type; + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &d_uint); + d_uint = listener->listener.types; + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &d_uint); + if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, + "(iisi)", &iter_subarray)) + { + dbus_message_iter_close_container (iter, &iter_struct); + return; + } + for (kl = listener->keys; kl; kl = kl->next) + { + Accessibility_KeyDefinition *kd = kl->data; + if (!dbus_message_iter_open_container (&iter_subarray, DBUS_TYPE_STRUCT, + NULL, &iter_substruct)) + break; + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_INT32, &kd->keycode); + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_INT32, &kd->keysym); + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_STRING, &kd->keystring); + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_INT32, &kd->unused); + dbus_message_iter_close_container (&iter_subarray, &iter_substruct); + } + dbus_message_iter_close_container (&iter_struct, &iter_subarray); + d_uint = listener->mask; + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &d_uint); + if (dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, + NULL, &iter_substruct)) + { + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_BOOLEAN, + &listener->mode->synchronous); + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_BOOLEAN, + &listener->mode->preemptive); + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_BOOLEAN, + &listener->mode->global); + dbus_message_iter_close_container (&iter_struct, &iter_substruct); + } + dbus_message_iter_close_container (iter, &iter_struct); +} + +static void +notify_keystroke_listener (SpiDEController *controller, + DEControllerKeyListener *listener, + gboolean enable) +{ + const char *path = SPI_DBUS_PATH_DEC; + const char *interface = SPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER; + const char *name = (enable + ? "KeystrokeListenerRegistered" + : "KeystrokeListenerDeregistered"); + DBusMessage *signal; + DBusMessageIter iter; + + signal = dbus_message_new_signal (path, interface, name); + if (!signal) + return; + dbus_message_iter_init_append (signal, &iter); + append_keystroke_listener (&iter, listener); + dbus_connection_send (controller->bus, signal, NULL); + dbus_message_unref (signal); +} + +static void +append_mouse_listener (DBusMessageIter *iter, DEControllerListener *listener) +{ + DBusMessageIter iter_struct; + dbus_uint32_t d_uint; + + if (!dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, + &iter_struct)) + return; + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, + &listener->bus_name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, + &listener->path); + d_uint = listener->types; + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &d_uint); + dbus_message_iter_close_container (iter, &iter_struct); +} + +static void +notify_mouse_listener (SpiDEController *controller, + DEControllerListener *listener, + gboolean enable) +{ + const char *path = SPI_DBUS_PATH_DEC; + const char *interface = SPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER; + const char *name = (enable + ? "DeviceListenerRegistered" + : "DeviceListenerDeregistered"); + DBusMessage *signal; + DBusMessageIter iter; + + signal = dbus_message_new_signal (path, interface, name); + if (!signal) + return; + dbus_message_iter_init_append (signal, &iter); + append_mouse_listener (&iter, listener); + dbus_connection_send (controller->bus, signal, NULL); + dbus_message_unref (signal); +} + static gboolean spi_controller_register_device_listener (SpiDEController *controller, - DEControllerListener *listener, - CORBA_Environment *ev) + DEControllerListener *listener) { DEControllerKeyListener *key_listener; + gboolean retval; switch (listener->type) { case SPI_DEVICE_TYPE_KBD: @@ -806,34 +1111,196 @@ spi_controller_register_device_listener (SpiDEController *controller, controller->key_listeners = g_list_prepend (controller->key_listeners, key_listener); + spi_dbus_add_disconnect_match (controller->bus, key_listener->listener.bus_name); if (key_listener->mode->global) { - return spi_controller_register_global_keygrabs (controller, key_listener); + retval = spi_controller_register_global_keygrabs (controller, key_listener); } else - return TRUE; + retval = TRUE; + if (retval) + notify_keystroke_listener (controller, key_listener, TRUE); break; case SPI_DEVICE_TYPE_MOUSE: controller->mouse_listeners = g_list_prepend (controller->mouse_listeners, listener); + if (!have_mouse_listener) + { + have_mouse_listener = TRUE; + if (!have_mouse_event_listener) + g_timeout_add (100, spi_dec_poll_mouse_idle, controller); + } + spi_dbus_add_disconnect_match (controller->bus, listener->bus_name); + notify_mouse_listener (controller, listener, TRUE); break; default: - DBG (1, g_warning ("listener registration for unknown device type.\n")); break; } - return FALSE; + return FALSE; +} + +static void +set_reply (DBusPendingCall *pending, void *user_data) +{ + void **replyptr = (void **)user_data; + + *replyptr = dbus_pending_call_steal_reply (pending); +} + +static GSList *hung_processes = NULL; + +static void +reset_hung_process (DBusPendingCall *pending, void *data) +{ + DBusMessage *message = data; + const char *dest = dbus_message_get_destination (message); + GSList *l; + + /* At this point we don't care about the result */ + dbus_pending_call_unref (pending); + + for (l = hung_processes; l; l = l->next) + { + if (!strcmp (l->data, dest)) + { + g_free (l->data); + hung_processes = g_slist_remove (hung_processes, data); + break; + } + } +} + +static gint +time_elapsed (struct timeval *origin) +{ + struct timeval tv; + + gettimeofday (&tv, NULL); + return (tv.tv_sec - origin->tv_sec) * 1000 + (tv.tv_usec - origin->tv_usec) / 1000; +} + +static void +reset_hung_process_from_ping (DBusPendingCall *pending, void *data) +{ + gchar *bus_name = data; + GSList *l; + + for (l = hung_processes; l; l = l->next) + { + if (!strcmp (l->data, data)) + { + g_free (l->data); + hung_processes = g_slist_remove (hung_processes, data); + break; + } + } + g_free (data); + dbus_pending_call_unref (pending); +} + +static DBusMessage * +send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, int timeout, DBusError *error) +{ + DBusPendingCall *pending; + DBusMessage *reply = NULL; + struct timeval tv; + + if (!dbus_connection_send_with_reply (bus, message, &pending, -1)) + { + return NULL; + } + dbus_pending_call_set_notify (pending, set_reply, (void *)&reply, NULL); + gettimeofday (&tv, NULL); + while (!reply) + { + if (!dbus_connection_read_write_dispatch (bus, timeout) || + time_elapsed (&tv) > timeout) + { + const char *dest = dbus_message_get_destination (message); + GSList *l; + gchar *bus_name_dup; + dbus_message_ref (message); + dbus_pending_call_set_notify (pending, reset_hung_process, message, + (DBusFreeFunction) dbus_message_unref); + message = dbus_message_new_method_call (dest, "/", + "org.freedesktop.DBus.Peer", + "Ping"); + if (!message) + return NULL; + dbus_connection_send_with_reply (bus, message, &pending, -1); + dbus_message_unref (message); + if (!pending) + return NULL; + bus_name_dup = g_strdup (dest); + dbus_pending_call_set_notify (pending, reset_hung_process_from_ping, + bus_name_dup, NULL); + for (l = hung_processes; l; l = l->next) + if (!strcmp (l->data, dest)) + return NULL; + hung_processes = g_slist_prepend (hung_processes, g_strdup (dest)); + return NULL; + } + } + dbus_pending_call_unref (pending); + return reply; +} +static gboolean +Accessibility_DeviceEventListener_NotifyEvent(SpiDEController *controller, + SpiRegistry *registry, + DEControllerListener *listener, + const Accessibility_DeviceEvent *key_event) +{ + DBusMessage *message = dbus_message_new_method_call(listener->bus_name, + listener->path, + SPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER, + "NotifyEvent"); + DBusError error; + dbus_bool_t consumed = FALSE; + GSList *l; + gboolean hung = FALSE; + + for (l = hung_processes; l; l = l->next) + { + if (!strcmp (l->data, listener->bus_name)) + { + dbus_message_set_no_reply (message, TRUE); + hung = TRUE; + break; + } + } + + dbus_error_init(&error); + if (spi_dbus_marshal_deviceEvent(message, key_event)) + { + if (hung) + { + dbus_connection_send (controller->bus, message, NULL); + dbus_message_unref (message); + return FALSE; + } + DBusMessage *reply = send_and_allow_reentry (controller->bus, message, 3000, &error); + if (reply) + { + DBusError error; + dbus_error_init(&error); + dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &consumed, DBUS_TYPE_INVALID); + dbus_message_unref(reply); + } + } + dbus_message_unref(message); + return consumed; } static gboolean spi_controller_notify_mouselisteners (SpiDEController *controller, - const Accessibility_DeviceEvent *event, - CORBA_Environment *ev) + const Accessibility_DeviceEvent *event) { GList *l; GSList *notify = NULL, *l2; GList **listeners = &controller->mouse_listeners; gboolean is_consumed; +#ifdef SPI_KEYEVENT_DEBUG gboolean found = FALSE; - +#endif if (!listeners) { return FALSE; @@ -843,17 +1310,14 @@ spi_controller_notify_mouselisteners (SpiDEController *controlle { DEControllerListener *listener = l->data; - if (spi_eventtype_seq_contains_event (listener->typeseq, event)) + if (spi_eventtype_seq_contains_event (listener->types, event)) { - Accessibility_DeviceEventListener ls = listener->object; - - if (ls != CORBA_OBJECT_NIL) - { - /* we clone (don't dup) the listener, to avoid refcount inc. */ - notify = g_slist_prepend (notify, - spi_listener_clone (listener, ev)); - found = TRUE; - } + /* we clone (don't dup) the listener, to avoid refcount inc. */ + notify = g_slist_prepend (notify, + spi_listener_clone (listener)); +#ifdef SPI_KEYEVENT_DEBUG + found = TRUE; +#endif } } @@ -867,27 +1331,17 @@ spi_controller_notify_mouselisteners (SpiDEController *controlle is_consumed = FALSE; for (l2 = notify; l2 && !is_consumed; l2 = l2->next) { - DEControllerListener *listener = l2->data; - Accessibility_DeviceEventListener ls = listener->object; + DEControllerListener *listener = l2->data; - CORBA_exception_init (ev); - is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, event, ev); - if (BONOBO_EX (ev)) - { - is_consumed = FALSE; - DBG (2, g_warning ("error notifying listener, removing it\n")); - spi_deregister_controller_device_listener (controller, listener, - ev); - CORBA_exception_free (ev); - } - - spi_listener_clone_free ((DEControllerListener *) l2->data, ev); + is_consumed = Accessibility_DeviceEventListener_NotifyEvent (controller, controller->registry, listener, event); + + spi_listener_clone_free ((DEControllerListener *) l2->data); } for (; l2; l2 = l2->next) { - DEControllerListener *listener = l2->data; - spi_listener_clone_free (listener, ev); + DEControllerListener *listener = l2->data; + spi_listener_clone_free (listener); /* clone doesn't have its own ref, so don't use spi_device_listener_free */ } @@ -903,13 +1357,12 @@ static void spi_device_event_controller_forward_mouse_event (SpiDEController *controller, XEvent *xevent) { - Accessibility_Event e; Accessibility_DeviceEvent mouse_e; - CORBA_Environment ev; - gchar event_name[24]; + gchar event_detail[3]; gboolean is_consumed = FALSE; gboolean xkb_mod_unlatch_occurred; XButtonEvent *xbutton_event = (XButtonEvent *) xevent; + dbus_uint32_t ix, iy; int button = xbutton_event->button; @@ -943,7 +1396,7 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller, (xevent->type == ButtonPress) ? "Press" : "Release", mouse_button_state); #endif - snprintf (event_name, 22, "mouse:button:%d%c", button, + snprintf (event_detail, 3, "%d%c", button, (xevent->type == ButtonPress) ? 'p' : 'r'); /* TODO: FIXME distinguish between physical and logical buttons */ @@ -952,10 +1405,10 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller, Accessibility_BUTTON_RELEASED_EVENT; mouse_e.id = button; mouse_e.hw_code = button; - mouse_e.modifiers = (CORBA_unsigned_short) xbutton_event->state; - mouse_e.timestamp = (CORBA_unsigned_long) xbutton_event->time; + mouse_e.modifiers = (dbus_uint16_t) xbutton_event->state; + mouse_e.timestamp = (dbus_uint32_t) xbutton_event->time; mouse_e.event_string = ""; - mouse_e.is_text = CORBA_FALSE; + mouse_e.is_text = FALSE; if ((mouse_button_state & mouse_button_mask) != (mouse_mask_state & mouse_button_mask)) { @@ -965,17 +1418,10 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller, mouse_mask_state, mouse_button_state); mouse_mask_state = mouse_button_state; is_consumed = - spi_controller_notify_mouselisteners (controller, &mouse_e, &ev); - e.type = CORBA_string_dup (event_name); - e.source = BONOBO_OBJREF (controller->registry->desktop); - e.detail1 = last_mouse_pos->x; - e.detail2 = last_mouse_pos->y; - spi_init_any_nil (&e.any_data); - CORBA_exception_init (&ev); - - Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry), - &e, - &ev); + spi_controller_notify_mouselisteners (controller, &mouse_e); + ix = last_mouse_pos->x; + iy = last_mouse_pos->y; + emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "Button", event_detail, ix, iy); } xkb_mod_unlatch_occurred = (xevent->type == ButtonPress || @@ -992,10 +1438,9 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller, CurrentTime); } -static GdkFilterReturn -global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) +static void +global_filter_fn (XEvent *xevent, void *data) { - XEvent *xevent = gdk_xevent; SpiDEController *controller; DEControllerPrivateData *priv; Display *display = spi_get_display (); @@ -1003,20 +1448,49 @@ global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) priv = (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark); + if (xevent->type == MappingNotify) + xmkeymap = NULL; + if (xevent->type == KeyPress || xevent->type == KeyRelease) { if (controller->xevie_display == NULL) { - gboolean is_consumed = + gboolean is_consumed; + + is_consumed = spi_device_event_controller_forward_key_event (controller, xevent); if (is_consumed) - XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime); + { + int n_events; + int i; + XEvent next_event; + n_events = XPending (display); + +#ifdef SPI_KEYEVENT_DEBUG + g_print ("Number of events pending: %d\n", n_events); +#endif + for (i = 0; i < n_events; i++) + { + XNextEvent (display, &next_event); + if (next_event.type != KeyPress && + next_event.type != KeyRelease) + g_warning ("Unexpected event type %d in queue", next_event.type); + } + + XAllowEvents (display, AsyncKeyboard, CurrentTime); + if (n_events) + XUngrabKeyboard (display, CurrentTime); + } else - XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime); + { + if (xevent->type == KeyPress) + wait_for_release_event (xevent, controller); + XAllowEvents (display, ReplayKeyboard, CurrentTime); + } } - return GDK_FILTER_CONTINUE; + return; } if (xevent->type == ButtonPress || xevent->type == ButtonRelease) { @@ -1026,7 +1500,7 @@ global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { XkbAnyEvent * xkb_ev = (XkbAnyEvent *) xevent; /* ugly but probably necessary...*/ - XSynchronize (spi_get_display (), TRUE); + XSynchronize (display, TRUE); if (xkb_ev->xkb_type == XkbStateNotify) { @@ -1086,15 +1560,13 @@ global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) priv->xkb_latch_mask = xkb_snev->latched_mods; } } - else - DBG (2, g_warning ("XKB event %d\n", xkb_ev->xkb_type)); - XSynchronize (spi_get_display (), FALSE); + XSynchronize (display, FALSE); } - return GDK_FILTER_CONTINUE; + return; } -int +static int _spi_controller_device_error_handler (Display *display, XErrorEvent *error) { if (error->error_code == BadAccess) @@ -1112,10 +1584,14 @@ _spi_controller_device_error_handler (Display *display, XErrorEvent *error) static void spi_controller_register_with_devices (SpiDEController *controller) { - DEControllerPrivateData *priv = (DEControllerPrivateData *) - g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark); - /* FIXME: should check for extension first! */ - XTestGrabControl (spi_get_display (), True); + DEControllerPrivateData *priv; + int event_base, error_base, major_version, minor_version; + + priv = (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark); + if (XTestQueryExtension (spi_get_display(), &event_base, &error_base, &major_version, &minor_version)) + { + XTestGrabControl (spi_get_display (), True); + } /* calls to device-specific implementations and routines go here */ /* register with: keyboard hardware code handler */ @@ -1127,64 +1603,121 @@ spi_controller_register_with_devices (SpiDEController *controller) &priv->xkb_base_error_code, NULL, NULL); if (priv->have_xkb) { - priv->xkb_desc = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd); + gint i; + guint64 reserved = 0; + priv->xkb_desc = XkbGetMap (spi_get_display (), XkbKeySymsMask, XkbUseCoreKbd); XkbSelectEvents (spi_get_display (), XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask); _numlock_physical_mask = XkbKeysymToModifiers (spi_get_display (), XK_Num_Lock); + for (i = priv->xkb_desc->max_key_code; i >= priv->xkb_desc->min_key_code; --i) + { + if (priv->xkb_desc->map->key_sym_map[i].kt_index[0] == XkbOneLevelIndex) + { + if (XKeycodeToKeysym (spi_get_display (), i, 0) != 0) + { + /* don't use this one if there's a grab client! */ + + /* Runtime errors are generated from these functions, + * that are then quashed. Equivalent to: + * try + * {Blah} + * except + * {;} + */ + + spi_x_error_trap (); + XGrabKey (spi_get_display (), i, 0, + spi_get_root_window (), + TRUE, + GrabModeSync, GrabModeSync); + XSync (spi_get_display (), TRUE); + XUngrabKey (spi_get_display (), i, 0, + spi_get_root_window ()); + if (!spi_x_error_release ()) + { + reserved = i; + break; + } + } + } + } + if (reserved) + { + priv->reserved_keycode = reserved; + priv->reserved_keysym = XKeycodeToKeysym (spi_get_display (), reserved, 0); + } + else + { + priv->reserved_keycode = XKeysymToKeycode (spi_get_display (), XK_numbersign); + priv->reserved_keysym = XK_numbersign; + } +#ifdef SPI_RESERVED_DEBUG + unsigned sym = 0; + sym = XKeycodeToKeysym (spi_get_display (), reserved, 0); + fprintf (stderr, "%x\n", sym); + fprintf (stderr, "setting the reserved keycode to %d (%s)\n", + reserved, + XKeysymToString (XKeycodeToKeysym (spi_get_display (), + reserved, 0))); +#endif } - gdk_window_add_filter (NULL, global_filter_fn, controller); - - gdk_window_set_events (gdk_get_default_root_window (), - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); + spi_set_filter (global_filter_fn, controller); + spi_set_events (KeyPressMask | KeyReleaseMask); x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler); } static gboolean -spi_key_set_contains_key (Accessibility_KeySet *key_set, +spi_key_set_contains_key (GSList *key_set, const Accessibility_DeviceEvent *key_event) { gint i; gint len; + GSList *l; if (!key_set) { - g_print ("null key set!"); +#ifdef SPI_DEBUG + g_print ("null key set!\n"); +#endif return TRUE; } - len = key_set->_length; + len = g_slist_length (key_set); if (len == 0) /* special case, means "all keys/any key" */ { +#ifdef SPI_DEBUG g_print ("anykey\n"); +#endif return TRUE; } - for (i = 0; i < len; ++i) + for (l = key_set,i = 0; l; l = g_slist_next(l),i++) { + Accessibility_KeyDefinition *kd = l->data; #ifdef SPI_KEYEVENT_DEBUG g_print ("key_set[%d] event = %d, code = %d; key_event %d, code %d, string %s\n", i, - (int)key_set->_buffer[i].keysym, - (int) key_set->_buffer[i].keycode, + (int) kd->keysym, + (int) kd->keycode, (int) key_event->id, (int) key_event->hw_code, key_event->event_string); #endif - if (key_set->_buffer[i].keysym == (CORBA_long) key_event->id) + if (kd->keysym == (dbus_uint32_t) key_event->id) { return TRUE; } - if (key_set->_buffer[i].keycode == (CORBA_long) key_event->hw_code) + if (kd->keycode == (dbus_uint32_t) key_event->hw_code) { return TRUE; } if (key_event->event_string && key_event->event_string[0] && - !strcmp (key_set->_buffer[i].keystring, key_event->event_string)) + !strcmp (kd->keystring, key_event->event_string)) { return TRUE; } @@ -1194,49 +1727,25 @@ spi_key_set_contains_key (Accessibility_KeySet *key_set, } static gboolean -spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq *type_seq, +spi_eventtype_seq_contains_event (dbus_uint32_t types, const Accessibility_DeviceEvent *event) { - gint i; - gint len; - - - if (!type_seq) - { - g_print ("null type seq!"); - return TRUE; - } - - len = type_seq->_length; - - if (len == 0) /* special case, means "all events/any event" */ + if (types == 0) /* special case, means "all events/any event" */ { return TRUE; } - for (i = 0; i < len; ++i) - { -#ifdef SPI_DEBUG - g_print ("type_seq[%d] = %d; event type = %d\n", i, - (int) type_seq->_buffer[i], (int) event->type); -#endif - if (type_seq->_buffer[i] == (CORBA_long) event->type) - { - return TRUE; - } - } - - return FALSE; + return (types & (1 << event->type)); } static gboolean spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event, DEControllerKeyListener *listener, - CORBA_boolean is_system_global) + dbus_bool_t is_system_global) { - if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFF)) && + if (((key_event->modifiers & 0xFF) == (dbus_uint16_t) (listener->mask & 0xFF)) && spi_key_set_contains_key (listener->keys, key_event) && - spi_eventtype_seq_contains_event (listener->listener.typeseq, key_event) && + spi_eventtype_seq_contains_event (listener->listener.types, key_event) && (is_system_global == listener->mode->global)) { return TRUE; @@ -1249,9 +1758,8 @@ spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event, static gboolean spi_controller_notify_keylisteners (SpiDEController *controller, - const Accessibility_DeviceEvent *key_event, - CORBA_boolean is_system_global, - CORBA_Environment *ev) + Accessibility_DeviceEvent *key_event, + dbus_bool_t is_system_global) { GList *l; GSList *notify = NULL, *l2; @@ -1263,20 +1771,19 @@ spi_controller_notify_keylisteners (SpiDEController *controller, return FALSE; } + /* set the NUMLOCK event mask bit if appropriate: see bug #143702 */ + if (key_event->modifiers & _numlock_physical_mask) + key_event->modifiers |= SPI_KEYMASK_NUMLOCK; + for (l = *key_listeners; l; l = l->next) { DEControllerKeyListener *key_listener = l->data; if (spi_key_event_matches_listener (key_event, key_listener, is_system_global)) { - Accessibility_DeviceEventListener ls = key_listener->listener.object; - - if (ls != CORBA_OBJECT_NIL) - { - /* we clone (don't dup) the listener, to avoid refcount inc. */ - notify = g_slist_prepend (notify, - spi_key_listener_clone (key_listener, ev)); - } + /* we clone (don't dup) the listener, to avoid refcount inc. */ + notify = g_slist_prepend (notify, + spi_key_listener_clone (key_listener)); } } @@ -1291,25 +1798,17 @@ spi_controller_notify_keylisteners (SpiDEController *controller, for (l2 = notify; l2 && !is_consumed; l2 = l2->next) { DEControllerKeyListener *key_listener = l2->data; - Accessibility_DeviceEventListener ls = key_listener->listener.object; - is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev); + is_consumed = Accessibility_DeviceEventListener_NotifyEvent (controller, controller->registry, &key_listener->listener, key_event) && + key_listener->mode->preemptive; - if (BONOBO_EX (ev)) - { - is_consumed = FALSE; - spi_deregister_controller_key_listener (controller, key_listener, - ev); - CORBA_exception_free (ev); - } - - spi_key_listener_clone_free (key_listener, ev); + spi_key_listener_clone_free (key_listener); } for (; l2; l2 = l2->next) { DEControllerKeyListener *key_listener = l2->data; - spi_key_listener_clone_free (key_listener, ev); + spi_key_listener_clone_free (key_listener); /* clone doesn't have its own ref, so don't use spi_dec_listener_free */ } @@ -1322,7 +1821,7 @@ spi_controller_notify_keylisteners (SpiDEController *controller, } static gboolean -spi_clear_error_state () +spi_clear_error_state (void) { gboolean retval = spi_error_code != 0; spi_error_code = 0; @@ -1335,12 +1834,12 @@ spi_keystroke_from_x_key_event (XKeyEvent *x_key_event) Accessibility_DeviceEvent key_event; KeySym keysym; const int cbuf_bytes = 20; - char cbuf [cbuf_bytes+1]; + char cbuf [21]; int nbytes; nbytes = XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL); - key_event.id = (CORBA_long)(keysym); - key_event.hw_code = (CORBA_short) x_key_event->keycode; + key_event.id = (dbus_int32_t)(keysym); + key_event.hw_code = (dbus_int16_t) x_key_event->keycode; if (((XEvent *) x_key_event)->type == KeyPress) { key_event.type = Accessibility_KEY_PRESSED_EVENT; @@ -1349,105 +1848,105 @@ spi_keystroke_from_x_key_event (XKeyEvent *x_key_event) { key_event.type = Accessibility_KEY_RELEASED_EVENT; } - key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state); - key_event.is_text = CORBA_FALSE; + key_event.modifiers = (dbus_uint16_t)(x_key_event->state); + key_event.is_text = FALSE; switch (keysym) { case ' ': - key_event.event_string = CORBA_string_dup ("space"); + key_event.event_string = g_strdup ("space"); break; case XK_Tab: - key_event.event_string = CORBA_string_dup ("Tab"); + key_event.event_string = g_strdup ("Tab"); break; case XK_BackSpace: - key_event.event_string = CORBA_string_dup ("Backspace"); + key_event.event_string = g_strdup ("Backspace"); break; case XK_Return: - key_event.event_string = CORBA_string_dup ("Return"); + key_event.event_string = g_strdup ("Return"); break; case XK_Home: - key_event.event_string = CORBA_string_dup ("Home"); + key_event.event_string = g_strdup ("Home"); break; case XK_Page_Down: - key_event.event_string = CORBA_string_dup ("Page_Down"); + key_event.event_string = g_strdup ("Page_Down"); break; case XK_Page_Up: - key_event.event_string = CORBA_string_dup ("Page_Up"); + key_event.event_string = g_strdup ("Page_Up"); break; case XK_F1: - key_event.event_string = CORBA_string_dup ("F1"); + key_event.event_string = g_strdup ("F1"); break; case XK_F2: - key_event.event_string = CORBA_string_dup ("F2"); + key_event.event_string = g_strdup ("F2"); break; case XK_F3: - key_event.event_string = CORBA_string_dup ("F3"); + key_event.event_string = g_strdup ("F3"); break; case XK_F4: - key_event.event_string = CORBA_string_dup ("F4"); + key_event.event_string = g_strdup ("F4"); break; case XK_F5: - key_event.event_string = CORBA_string_dup ("F5"); + key_event.event_string = g_strdup ("F5"); break; case XK_F6: - key_event.event_string = CORBA_string_dup ("F6"); + key_event.event_string = g_strdup ("F6"); break; case XK_F7: - key_event.event_string = CORBA_string_dup ("F7"); + key_event.event_string = g_strdup ("F7"); break; case XK_F8: - key_event.event_string = CORBA_string_dup ("F8"); + key_event.event_string = g_strdup ("F8"); break; case XK_F9: - key_event.event_string = CORBA_string_dup ("F9"); + key_event.event_string = g_strdup ("F9"); break; case XK_F10: - key_event.event_string = CORBA_string_dup ("F10"); + key_event.event_string = g_strdup ("F10"); break; case XK_F11: - key_event.event_string = CORBA_string_dup ("F11"); + key_event.event_string = g_strdup ("F11"); break; case XK_F12: - key_event.event_string = CORBA_string_dup ("F12"); + key_event.event_string = g_strdup ("F12"); break; case XK_End: - key_event.event_string = CORBA_string_dup ("End"); + key_event.event_string = g_strdup ("End"); break; case XK_Escape: - key_event.event_string = CORBA_string_dup ("Escape"); + key_event.event_string = g_strdup ("Escape"); break; case XK_Up: - key_event.event_string = CORBA_string_dup ("Up"); + key_event.event_string = g_strdup ("Up"); break; case XK_Down: - key_event.event_string = CORBA_string_dup ("Down"); + key_event.event_string = g_strdup ("Down"); break; case XK_Left: - key_event.event_string = CORBA_string_dup ("Left"); + key_event.event_string = g_strdup ("Left"); break; case XK_Right: - key_event.event_string = CORBA_string_dup ("Right"); + key_event.event_string = g_strdup ("Right"); break; default: if (nbytes > 0) { gunichar c; cbuf[nbytes] = '\0'; /* OK since length is cbuf_bytes+1 */ - key_event.event_string = CORBA_string_dup (cbuf); - c = g_utf8_get_char_validated (cbuf, nbytes); - if ((c > 0) && g_unichar_isprint (c)) + key_event.event_string = g_strdup (cbuf); + c = keysym2ucs (keysym); + if (c > 0 && !g_unichar_iscntrl (c)) { - key_event.is_text = CORBA_TRUE; + key_event.is_text = TRUE; /* incorrect for some composed chars? */ } } else { - key_event.event_string = CORBA_string_dup (""); + key_event.event_string = g_strdup (""); } } - key_event.timestamp = (CORBA_unsigned_long) x_key_event->time; + key_event.timestamp = (dbus_uint32_t) x_key_event->time; #ifdef SPI_KEYEVENT_DEBUG { char *pressed_str = "pressed"; @@ -1467,7 +1966,7 @@ spi_keystroke_from_x_key_event (XKeyEvent *x_key_event) (int) x_key_event->state, key_event.event_string, key_event.event_string[0], - (key_event.is_text == CORBA_TRUE) ? "(text)" : "(not text)"); + (key_event.is_text == TRUE) ? "(text)" : "(not text)"); } #endif #ifdef SPI_DEBUG @@ -1475,6 +1974,7 @@ spi_keystroke_from_x_key_event (XKeyEvent *x_key_event) (x_key_event->state & Mod1Mask)?"Alt-":"", ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))? g_ascii_toupper (keysym) : g_ascii_tolower (keysym)); + fprintf (stderr, "serial: %x Time: %x\n", x_key_event->serial, x_key_event->time); #endif /* SPI_DEBUG */ return key_event; } @@ -1485,6 +1985,7 @@ spi_controller_update_key_grabs (SpiDEController *controller, { GList *l, *next; gboolean update_failed = FALSE; + KeyCode keycode = 0; g_return_val_if_fail (controller != NULL, FALSE); @@ -1497,6 +1998,8 @@ spi_controller_update_key_grabs (SpiDEController *controller, * * ControlMask grabs are broken, must be in use already */ + if (recv) + keycode = keycode_for_keysym (controller, recv->id, NULL); for (l = controller->keygrabs_list; l; l = next) { gboolean do_remove; @@ -1507,7 +2010,7 @@ spi_controller_update_key_grabs (SpiDEController *controller, re_issue_grab = recv && (recv->modifiers & grab_mask->mod_mask) && - (grab_mask->key_val == keycode_for_keysym (recv->id, NULL)); + (grab_mask->key_val == keycode); #ifdef SPI_DEBUG fprintf (stderr, "mask=%lx %lx (%c%c) %s\n", @@ -1532,7 +2035,7 @@ spi_controller_update_key_grabs (SpiDEController *controller, XUngrabKey (spi_get_display (), grab_mask->key_val, grab_mask->mod_mask, - gdk_x11_get_default_root_xwindow ()); + spi_get_root_window ()); do_remove = TRUE; } @@ -1545,7 +2048,7 @@ spi_controller_update_key_grabs (SpiDEController *controller, XGrabKey (spi_get_display (), grab_mask->key_val, grab_mask->mod_mask, - gdk_x11_get_default_root_xwindow (), + spi_get_root_window (), True, GrabModeSync, GrabModeSync); @@ -1584,14 +2087,14 @@ spi_device_event_controller_object_finalize (GObject *object) SpiDEController *controller; DEControllerPrivateData *private; controller = SPI_DEVICE_EVENT_CONTROLLER (object); - + GObjectClass *parent_class = G_OBJECT_CLASS(spi_device_event_controller_parent_class); #ifdef SPI_DEBUG fprintf(stderr, "spi_device_event_controller_object_finalize called\n"); #endif /* disconnect any special listeners, get rid of outstanding keygrabs */ XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ())); -#ifdef HAVE_XEEVIE +#ifdef HAVE_XEVIE if (controller->xevie_display != NULL) { XevieEnd(controller->xevie_display); @@ -1605,56 +2108,107 @@ spi_device_event_controller_object_finalize (GObject *object) if (private->xkb_desc) XkbFreeKeyboard (private->xkb_desc, 0, True); g_free (private); - spi_device_event_controller_parent_class->finalize (object); + parent_class->finalize (object); } /* - * CORBA Accessibility::DEController::registerKeystrokeListener + * DBus Accessibility::DEController::RegisterKeystrokeListener * method implementation */ -static CORBA_boolean -impl_register_keystroke_listener (PortableServer_Servant servant, - const Accessibility_DeviceEventListener l, - const Accessibility_KeySet *keys, - const Accessibility_ControllerEventMask mask, - const Accessibility_EventTypeSeq *type, - const Accessibility_EventListenerMode *mode, - CORBA_Environment *ev) -{ - SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER ( - bonobo_object_from_servant (servant)); +static DBusMessage * +impl_register_keystroke_listener (DBusConnection *bus, + DBusMessage *message, + void *user_data) +{ + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); DEControllerKeyListener *dec_listener; + DBusMessageIter iter, iter_array; + const char *path; + GSList *keys = NULL; + dbus_int32_t mask, type; + Accessibility_EventListenerMode *mode; + dbus_bool_t ret; + DBusMessage *reply = NULL; + char *keystring; + + if (strcmp (dbus_message_get_signature (message), "oa(iisi)uu(bbb)") != 0) + return invalid_arguments_error (message); + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &path); + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &iter_array); + while (dbus_message_iter_get_arg_type(&iter_array) != DBUS_TYPE_INVALID) + { + Accessibility_KeyDefinition *kd = (Accessibility_KeyDefinition *)g_malloc(sizeof(Accessibility_KeyDefinition)); + if (!spi_dbus_message_iter_get_struct(&iter_array, DBUS_TYPE_INT32, &kd->keycode, DBUS_TYPE_INT32, &kd->keysym, DBUS_TYPE_STRING, &keystring, DBUS_TYPE_INVALID)) + { + break; + } + kd->keystring = g_strdup (keystring); + keys = g_slist_append(keys, kd); + } + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &mask); + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &type); + dbus_message_iter_next(&iter); + mode = (Accessibility_EventListenerMode *)g_malloc(sizeof(Accessibility_EventListenerMode)); + if (mode) + { + spi_dbus_message_iter_get_struct(&iter, DBUS_TYPE_BOOLEAN, &mode->synchronous, DBUS_TYPE_BOOLEAN, &mode->preemptive, DBUS_TYPE_BOOLEAN, &mode->global, DBUS_TYPE_INVALID); + } #ifdef SPI_DEBUG - fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n", - (void *) l, (unsigned long) mask); + fprintf (stderr, "registering keystroke listener %s:%s with maskVal %lu\n", + dbus_message_get_sender(message), path, (unsigned long) mask); #endif - dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev); - return spi_controller_register_device_listener ( - controller, (DEControllerListener *) dec_listener, ev); + dec_listener = spi_dec_key_listener_new (dbus_message_get_sender(message), path, keys, mask, type, mode); + g_free (mode); + ret = spi_controller_register_device_listener ( + controller, (DEControllerListener *) dec_listener); + reply = dbus_message_new_method_return (message); + if (reply) + { + dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret, DBUS_TYPE_INVALID); + } + return reply; } - /* - * CORBA Accessibility::DEController::registerDeviceEventListener + * DBus Accessibility::DEController::RegisterDeviceEventListener * method implementation */ -static CORBA_boolean -impl_register_device_listener (PortableServer_Servant servant, - const Accessibility_DeviceEventListener l, - const Accessibility_EventTypeSeq *event_types, - CORBA_Environment *ev) -{ - SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER ( - bonobo_object_from_servant (servant)); +static DBusMessage * +impl_register_device_event_listener (DBusConnection *bus, + DBusMessage *message, + void *user_data) +{ + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); DEControllerListener *dec_listener; - - dec_listener = spi_dec_listener_new (l, event_types, ev); - return spi_controller_register_device_listener ( - controller, (DEControllerListener *) dec_listener, ev); + DBusError error; + const char *path; + dbus_int32_t event_types; + dbus_bool_t ret; + DBusMessage *reply = NULL; + + dbus_error_init(&error); + if (!dbus_message_get_args(message, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_UINT32, &event_types, DBUS_TYPE_INVALID)) + { + return invalid_arguments_error (message); + } + dec_listener = spi_dec_listener_new (dbus_message_get_sender(message), path, event_types); + ret = spi_controller_register_device_listener ( + controller, (DEControllerListener *) dec_listener); + reply = dbus_message_new_method_return (message); + if (reply) + { + dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret, DBUS_TYPE_INVALID); + } + return reply; } typedef struct { - CORBA_Environment *ev; + DBusConnection *bus; DEControllerListener *listener; } RemoveListenerClosure; @@ -1665,11 +2219,12 @@ remove_listener_cb (GList * const *list, DEControllerListener *listener = (*list)->data; RemoveListenerClosure *ctx = user_data; - if (CORBA_Object_is_equivalent (ctx->listener->object, - listener->object, ctx->ev)) + if (!strcmp(ctx->listener->bus_name, listener->bus_name) && + !strcmp(ctx->listener->path, listener->path)) { spi_re_entrant_list_delete_link (list); - spi_dec_listener_free (listener, ctx->ev); + spi_dbus_remove_disconnect_match (ctx->bus, listener->bus_name); + spi_dec_listener_free (listener); } return SPI_RE_ENTRANT_CONTINUE; @@ -1682,105 +2237,218 @@ copy_key_listener_cb (GList * const *list, DEControllerKeyListener *key_listener = (*list)->data; RemoveListenerClosure *ctx = user_data; - if (CORBA_Object_is_equivalent (ctx->listener->object, - key_listener->listener.object, ctx->ev)) + if (!strcmp(ctx->listener->bus_name, key_listener->listener.bus_name) && + !strcmp(ctx->listener->path, key_listener->listener.path)) { /* TODO: FIXME aggregate keys in case the listener is registered twice */ DEControllerKeyListener *ctx_key_listener = (DEControllerKeyListener *) ctx->listener; - CORBA_free (ctx_key_listener->keys); - ctx_key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet); + keylist_free (ctx_key_listener->keys); + ctx_key_listener->keys = keylist_clone(key_listener->keys); } return SPI_RE_ENTRANT_CONTINUE; } static void -spi_deregister_controller_device_listener (SpiDEController *controller, - DEControllerListener *listener, - CORBA_Environment *ev) +spi_controller_deregister_device_listener (SpiDEController *controller, + DEControllerListener *listener) { RemoveListenerClosure ctx; - ctx.ev = ev; + ctx.bus = controller->bus; ctx.listener = listener; + notify_mouse_listener (controller, listener, FALSE); + spi_re_entrant_list_foreach (&controller->mouse_listeners, remove_listener_cb, &ctx); + if (!controller->mouse_listeners) + have_mouse_listener = FALSE; } static void spi_deregister_controller_key_listener (SpiDEController *controller, - DEControllerKeyListener *key_listener, - CORBA_Environment *ev) + DEControllerKeyListener *key_listener) { RemoveListenerClosure ctx; - ctx.ev = ev; - ctx.listener = (DEControllerListener *) key_listener; + ctx.bus = controller->bus; + ctx.listener = (DEControllerListener *) spi_key_listener_clone (key_listener); + + notify_keystroke_listener (controller, key_listener, FALSE); /* special case, copy keyset from existing controller list entry */ - if (key_listener->keys->_length == 0) + if (g_slist_length(key_listener->keys) == 0) { spi_re_entrant_list_foreach (&controller->key_listeners, copy_key_listener_cb, &ctx); } - + spi_controller_deregister_global_keygrabs (controller, key_listener); spi_re_entrant_list_foreach (&controller->key_listeners, remove_listener_cb, &ctx); + spi_key_listener_clone_free ((DEControllerKeyListener *) ctx.listener); +} + +void +spi_remove_device_listeners (SpiDEController *controller, const char *bus_name) +{ + GList *l, *tmp; + + for (l = controller->mouse_listeners; l; l = tmp) + { + DEControllerListener *listener = l->data; + tmp = l->next; + if (!strcmp (listener->bus_name, bus_name)) + { + spi_controller_deregister_device_listener (controller, listener); + tmp = controller->mouse_listeners; + } + } + for (l = controller->key_listeners; l; l = tmp) + { + DEControllerKeyListener *key_listener = l->data; + tmp = l->next; + if (!strcmp (key_listener->listener.bus_name, bus_name)) + { + /* TODO: untangle the below line(s) */ + spi_deregister_controller_key_listener (controller, key_listener); + tmp = controller->key_listeners; + } + } } /* - * CORBA Accessibility::DEController::deregisterKeystrokeListener + * DBus Accessibility::DEController::DeregisterKeystrokeListener * method implementation */ -static void -impl_deregister_keystroke_listener (PortableServer_Servant servant, - const Accessibility_DeviceEventListener l, - const Accessibility_KeySet *keys, - const Accessibility_ControllerEventMask mask, - const Accessibility_EventTypeSeq *type, - CORBA_Environment *ev) -{ - DEControllerKeyListener *key_listener; - SpiDEController *controller; - - controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant)); - - key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev); +static DBusMessage * +impl_deregister_keystroke_listener (DBusConnection *bus, + DBusMessage *message, + void *user_data) +{ + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); + DEControllerKeyListener *key_listener; + DBusMessageIter iter, iter_array; + const char *path; + GSList *keys = NULL; + dbus_int32_t mask, type; + DBusMessage *reply = NULL; + + dbus_message_iter_init(message, &iter); + if (strcmp (dbus_message_get_signature (message), "oa(iisi)uu") != 0) + dbus_message_iter_get_basic(&iter, &path); + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &iter_array); + while (dbus_message_iter_get_arg_type(&iter_array) != DBUS_TYPE_INVALID) + { + Accessibility_KeyDefinition *kd = (Accessibility_KeyDefinition *)g_malloc(sizeof(Accessibility_KeyDefinition)); + char *keystring; + if (!spi_dbus_message_iter_get_struct(&iter_array, DBUS_TYPE_INT32, &kd->keycode, DBUS_TYPE_INT32, &kd->keysym, DBUS_TYPE_STRING, &keystring, DBUS_TYPE_INVALID)) + { + break; + } + kd->keystring = g_strdup (keystring); + keys = g_slist_append(keys, kd); + } + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &mask); + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &type); + dbus_message_iter_next(&iter); + key_listener = spi_dec_key_listener_new (dbus_message_get_sender(message), path, keys, mask, type, NULL); #ifdef SPI_DEREGISTER_DEBUG fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n", (void *) l, (unsigned long) mask->value); #endif - spi_deregister_controller_key_listener (controller, key_listener, ev); + spi_deregister_controller_key_listener (controller, key_listener); - spi_dec_listener_free ((DEControllerListener *) key_listener, ev); + spi_dec_listener_free ((DEControllerListener *) key_listener); + reply = dbus_message_new_method_return (message); + return reply; } /* - * CORBA Accessibility::DEController::deregisterDeviceEventListener + * DBus Accessibility::DEController::DeregisterDeviceEventListener * method implementation */ -static void -impl_deregister_device_listener (PortableServer_Servant servant, - const Accessibility_DeviceEventListener l, - const Accessibility_EventTypeSeq *event_types, - CORBA_Environment *ev) +static DBusMessage * +impl_deregister_device_event_listener (DBusConnection *bus, + DBusMessage *message, + void *user_data) +{ + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); + DEControllerListener *listener; + DBusError error; + const char *path; + dbus_int32_t event_types; + DBusMessage *reply = NULL; + + dbus_error_init(&error); + if (!dbus_message_get_args(message, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_UINT32, &event_types, DBUS_TYPE_INVALID)) + { + return invalid_arguments_error (message); + } + listener = spi_dec_listener_new (dbus_message_get_sender(message), path, event_types); + spi_controller_deregister_device_listener ( + controller, listener); + reply = dbus_message_new_method_return (message); + return reply; +} + +static DBusMessage * +impl_get_keystroke_listeners (DBusConnection *bus, + DBusMessage *message, + void *user_data) { - SpiDEController *controller; - DEControllerListener *listener = - spi_dec_listener_new (l, event_types, ev); + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); + DEControllerKeyListener *dec_listener; + DBusMessageIter iter, iter_array; + DBusMessage *reply = dbus_message_new_method_return (message); + GList *l; - controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant)); + if (!reply) + return NULL; - spi_deregister_controller_device_listener (controller, listener, ev); + dbus_message_iter_init_append (reply, &iter); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, + "(souua(iisi)u(bbb))", &iter_array); + for (l = controller->key_listeners; l; l = l->next) + { + append_keystroke_listener (&iter_array, l->data); + } + dbus_message_iter_close_container (&iter, &iter_array); + return reply; +} - spi_dec_listener_free (listener, ev); +static DBusMessage * +impl_get_device_event_listeners (DBusConnection *bus, + DBusMessage *message, + void *user_data) +{ + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); + DEControllerKeyListener *dec_listener; + DBusMessageIter iter, iter_array; + GList *l; + DBusMessage *reply = dbus_message_new_method_return (message); + + if (!reply) + return NULL; + + dbus_message_iter_init_append (reply, &iter); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, + "(sou)", &iter_array); + for (l = controller->key_listeners; l; l = l->next) + { + append_mouse_listener (&iter_array, l->data); + } + dbus_message_iter_close_container (&iter, &iter_array); + return reply; } static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller) @@ -1877,6 +2545,7 @@ dec_synth_keycode_press (SpiDEController *controller, } XTestFakeKeyEvent (spi_get_display (), keycode, True, time); priv->last_press_keycode = keycode; + XFlush (spi_get_display ()); XSync (spi_get_display (), False); gettimeofday (&priv->last_press_time, NULL); return TRUE; @@ -1934,59 +2603,43 @@ dec_get_modifier_state (SpiDEController *controller) static gboolean dec_lock_modifiers (SpiDEController *controller, unsigned modifiers) { - return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd, - modifiers, modifiers); + DEControllerPrivateData *priv = (DEControllerPrivateData *) + g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark); + + if (priv->have_xkb) { + return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd, + modifiers, modifiers); + } else { + int mod_index; + for (mod_index=0;mod_index<8;mod_index++) + if (modifiers & (1<modifiermap[mod_index]); + return TRUE; + } } static gboolean dec_unlock_modifiers (SpiDEController *controller, unsigned modifiers) { - return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd, - modifiers, 0); + DEControllerPrivateData *priv = (DEControllerPrivateData *) + g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark); + + if (priv->have_xkb) { + return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd, + modifiers, 0); + } else { + int mod_index; + for (mod_index=0;mod_index<8;mod_index++) + if (modifiers & (1<modifiermap[mod_index]); + return TRUE; + } } static KeySym dec_keysym_for_unichar (SpiDEController *controller, gunichar unichar) { - /* TODO: table lookups within a range, for various code pages! */ - KeySym keysym = NoSymbol; - - if (unichar >= 0x20 && unichar < 0x7f) { /* Basic Latin/ASCII */ - keysym = (KeySym) unichar; - } - else if (unichar >= 0xa0 && unichar <= 0xff) { /* Latin 1 extensions */ - keysym = (KeySym) unichar; - } - else if (unichar >= 0x100 && unichar <= 0x233) { /* unfortunately the mapping gets nasty for Latin-2 and 3... help! */ - keysym = NoSymbol; - } - else if (unichar >= 0x7c1 && unichar <= 0x3a1) { /* let's try Greek anyway... */ - keysym = (KeySym) (0x391 + (unichar - 0x7c1)); - } - else if (unichar >= 0x3a3 && unichar <= 0x3a9) { /* let's try Greek anyway... */ - keysym = (KeySym) (0x7d2 + (unichar - 0x3a3)); - } - else if (unichar >= 0x3b1 && unichar <= 0x3c1) { /* let's try Greek anyway... */ - keysym = (KeySym) (0x7e1 + (unichar - 0x3b1)); - } - else if (unichar == 0x3c2) { - keysym = (KeySym) 0x7f3; /* XK_Greek_finalsmallsigma; */ - } - else if (unichar >= 0x3c3 && unichar <= 0x3c9) { /* let's try Greek anyway... */ - keysym = (KeySym) (0x7f2 + (unichar - 0x3c2)); - } - else if (unichar >= 0x5d0 && unichar <= 0x5ea) { /* Hebrew basics */ - /* probably broken :-) */ - keysym = (KeySym) (0xce0 + (unichar - 0x5d0)); - } - else if (unichar >= 0x30a1 && unichar <= 0x30ab) { /* partial katakana support */ - /* TODO: complete! */ - keysym = (KeySym) (0x4b1 + (unichar - 0x30a1)/2); - } - else if (unichar >= 0x20a0 && unichar <= 0x20ac) { /* currency */ - keysym = (KeySym) unichar; /* how convenient ;-) */ - } - return keysym; + return ucs2keysym ((long) unichar); } static gboolean @@ -1995,7 +2648,7 @@ dec_synth_keysym (SpiDEController *controller, KeySym keysym) KeyCode key_synth_code; unsigned int modifiers, synth_mods, lock_mods; - key_synth_code = keycode_for_keysym (keysym, &synth_mods); + key_synth_code = keycode_for_keysym (controller, keysym, &synth_mods); if ((key_synth_code == 0) || (synth_mods == 0xFF)) return FALSE; @@ -2003,12 +2656,14 @@ dec_synth_keysym (SpiDEController *controller, KeySym keysym) modifiers = dec_get_modifier_state (controller); /* side-effect; we may unset mousebutton modifiers here! */ + lock_mods = 0; if (synth_mods != modifiers) { lock_mods = synth_mods & ~modifiers; dec_lock_modifiers (controller, lock_mods); } dec_synth_keycode_press (controller, key_synth_code); dec_synth_keycode_release (controller, key_synth_code); + if (synth_mods != modifiers) dec_unlock_modifiers (controller, lock_mods); return TRUE; @@ -2016,7 +2671,7 @@ dec_synth_keysym (SpiDEController *controller, KeySym keysym) static gboolean -dec_synth_keystring (SpiDEController *controller, const CORBA_char *keystring) +dec_synth_keystring (SpiDEController *controller, const char *keystring) { /* probably we need to create and inject an XIM handler eventually. */ /* for now, try to match the string to existing @@ -2029,7 +2684,7 @@ dec_synth_keystring (SpiDEController *controller, const CORBA_char *keystring) gboolean retval = TRUE; const gchar *c; - maxlen = strlen (keystring); + maxlen = strlen (keystring) + 1; keysyms = g_new0 (KeySym, maxlen); if (!(keystring && *keystring && g_utf8_validate (keystring, -1, &c))) { retval = FALSE; @@ -2060,6 +2715,7 @@ dec_synth_keystring (SpiDEController *controller, const CORBA_char *keystring) keystring = g_utf8_next_char (keystring); } keysyms[i++] = 0; + XSynchronize (spi_get_display (), TRUE); for (i = 0; keysyms[i]; ++i) { if (!dec_synth_keysym (controller, keysyms[i])) { #ifdef SPI_DEBUG @@ -2070,6 +2726,7 @@ dec_synth_keystring (SpiDEController *controller, const CORBA_char *keystring) break; } } + XSynchronize (spi_get_display (), FALSE); } g_free (keysyms); @@ -2078,20 +2735,26 @@ dec_synth_keystring (SpiDEController *controller, const CORBA_char *keystring) /* - * CORBA Accessibility::DEController::registerKeystrokeListener + * DBus Accessibility::DEController::RegisterKeystrokeListener * method implementation */ -static void -impl_generate_keyboard_event (PortableServer_Servant servant, - const CORBA_long keycode, - const CORBA_char *keystring, - const Accessibility_KeySynthType synth_type, - CORBA_Environment *ev) -{ - SpiDEController *controller = - SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant)); - long key_synth_code; +static DBusMessage * impl_generate_keyboard_event (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); + DBusError error; + dbus_int32_t keycode; + char *keystring; + dbus_uint32_t synth_type; + gint err; KeySym keysym; + DEControllerPrivateData *priv; + DBusMessage *reply = NULL; + + dbus_error_init(&error); + if (!dbus_message_get_args(message, &error, DBUS_TYPE_INT32, &keycode, DBUS_TYPE_STRING, &keystring, DBUS_TYPE_UINT32, &synth_type, DBUS_TYPE_INVALID)) + { + return invalid_arguments_error (message); + } #ifdef SPI_DEBUG fprintf (stderr, "synthesizing keystroke %ld, type %d\n", @@ -2104,8 +2767,14 @@ impl_generate_keyboard_event (PortableServer_Servant servant, * and fall back to XSendEvent() if XTest is not available. */ - gdk_error_trap_push (); - key_synth_code = keycode; + spi_x_error_trap (); + + priv = (DEControllerPrivateData *) + g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark); + + if (!priv->have_xkb && xmkeymap==NULL) { + xmkeymap = XGetModifierMapping(spi_get_display ()); + } switch (synth_type) { @@ -2134,10 +2803,6 @@ impl_generate_keyboard_event (PortableServer_Servant servant, keystring); break; } - if (gdk_error_trap_pop ()) - { - DBG (-1, g_warning ("Error emitting keystroke")); - } if (synth_type == Accessibility_KEY_SYM) { keysym = keycode; } @@ -2148,19 +2813,28 @@ impl_generate_keyboard_event (PortableServer_Servant servant, { spi_dec_clear_unlatch_pending (controller); } + reply = dbus_message_new_method_return (message); + return reply; } -/* Accessibility::DEController::generateMouseEvent */ -static void -impl_generate_mouse_event (PortableServer_Servant servant, - const CORBA_long x, - const CORBA_long y, - const CORBA_char *eventName, - CORBA_Environment *ev) +/* Accessibility::DEController::GenerateMouseEvent */ +static DBusMessage * impl_generate_mouse_event (DBusConnection *bus, DBusMessage *message, void *user_data) { + DBusError error; + dbus_int32_t x; + dbus_int32_t y; + char *eventName; + DBusMessage *reply = NULL; int button = 0; - gboolean error = FALSE; + gboolean err = FALSE; Display *display = spi_get_display (); + + dbus_error_init (&error); + if (!dbus_message_get_args(message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_STRING, &eventName, DBUS_TYPE_INVALID)) + { + return invalid_arguments_error (message); + } + #ifdef SPI_DEBUG fprintf (stderr, "generating mouse %s event at %ld, %ld\n", eventName, (long int) x, (long int) y); @@ -2187,9 +2861,9 @@ impl_generate_mouse_event (PortableServer_Servant servant, button = 5; break; default: - error = TRUE; + err = TRUE; } - if (!error) + if (!err) { if (x != -1 && y != -1) { @@ -2215,71 +2889,80 @@ impl_generate_mouse_event (PortableServer_Servant servant, x, y, 0); break; } + reply = dbus_message_new_method_return (message); + return reply; } -/* Accessibility::DEController::notifyListenersSync */ -static CORBA_boolean -impl_notify_listeners_sync (PortableServer_Servant servant, - const Accessibility_DeviceEvent *event, - CORBA_Environment *ev) +/* Accessibility::DEController::NotifyListenersSync */ +static DBusMessage * +impl_notify_listeners_sync (DBusConnection *bus, DBusMessage *message, void *user_data) { - SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER ( - bonobo_object_from_servant (servant)); + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); + Accessibility_DeviceEvent event; + dbus_bool_t ret; + DBusMessage *reply = NULL; + + if (!spi_dbus_demarshal_deviceEvent(message, &event)) + { + return invalid_arguments_error (message); + } #ifdef SPI_DEBUG g_print ("notifylistening listeners synchronously: controller %p, event id %d\n", - controller, (int) event->id); + controller, (int) event.id); #endif - return spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev) ? - CORBA_TRUE : CORBA_FALSE; + ret = spi_controller_notify_keylisteners (controller, + (Accessibility_DeviceEvent *) + &event, FALSE) ? + TRUE : FALSE; + reply = dbus_message_new_method_return (message); + if (reply) + { + dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret, DBUS_TYPE_INVALID); + } + return reply; } -/* Accessibility::DEController::notifyListenersAsync */ -static void -impl_notify_listeners_async (PortableServer_Servant servant, - const Accessibility_DeviceEvent *event, - CORBA_Environment *ev) +static DBusMessage * +impl_notify_listeners_async (DBusConnection *bus, DBusMessage *message, void *user_data) { - SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER ( - bonobo_object_from_servant (servant)); + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); + Accessibility_DeviceEvent event; + DBusMessage *reply = NULL; + + if (!spi_dbus_demarshal_deviceEvent(message, &event)) + { + return invalid_arguments_error (message); + } #ifdef SPI_DEBUG - fprintf (stderr, "notifying listeners asynchronously\n"); + g_print ("notifylistening listeners asynchronously: controller %p, event id %d\n", + controller, (int) event.id); #endif - spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev); + spi_controller_notify_keylisteners (controller, (Accessibility_DeviceEvent *) + &event, FALSE); + reply = dbus_message_new_method_return (message); + return reply; } static void spi_device_event_controller_class_init (SpiDEControllerClass *klass) { GObjectClass * object_class = (GObjectClass *) klass; - POA_Accessibility_DeviceEventController__epv *epv = &klass->epv; spi_device_event_controller_parent_class = g_type_class_peek_parent (klass); - + object_class->finalize = spi_device_event_controller_object_finalize; - - epv->registerKeystrokeListener = impl_register_keystroke_listener; - epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener; - epv->registerDeviceEventListener = impl_register_device_listener; - epv->deregisterDeviceEventListener = impl_deregister_device_listener; - epv->generateKeyboardEvent = impl_generate_keyboard_event; - epv->generateMouseEvent = impl_generate_mouse_event; - epv->notifyListenersSync = impl_notify_listeners_sync; - epv->notifyListenersAsync = impl_notify_listeners_async; if (!spi_dec_private_quark) spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private"); } #ifdef HAVE_XEVIE -Bool isEvent(dpy,event,arg) - Display *dpy; - XEvent *event; - char *arg; +static Bool isEvent(Display *dpy, XEvent *event, char *arg) { return TRUE; } -gboolean +static gboolean handle_io (GIOChannel *source, GIOCondition condition, gpointer data) @@ -2304,6 +2987,7 @@ handle_io (GIOChannel *source, static void spi_device_event_controller_init (SpiDEController *device_event_controller) { + spi_events_init (spi_get_display()); #ifdef HAVE_XEVIE GIOChannel *ioc; int fd; @@ -2346,43 +3030,236 @@ spi_device_event_controller_init (SpiDEController *device_event_controller) spi_dec_private_quark, private); spi_controller_register_with_devices (device_event_controller); + device_event_controller->message_queue = g_queue_new (); + saved_controller = device_event_controller; } static gboolean spi_device_event_controller_forward_key_event (SpiDEController *controller, const XEvent *event) { - CORBA_Environment ev; Accessibility_DeviceEvent key_event; + gboolean ret; g_assert (event->type == KeyPress || event->type == KeyRelease); - CORBA_exception_init (&ev); - key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event); if (controller->xevie_display == NULL) spi_controller_update_key_grabs (controller, &key_event); /* relay to listeners, and decide whether to consume it or not */ - return spi_controller_notify_keylisteners (controller, &key_event, CORBA_TRUE, &ev); + ret = spi_controller_notify_keylisteners (controller, &key_event, TRUE); + g_free(key_event.event_string); + return ret; +} + + +static gboolean +is_key_released (KeyCode code) +{ + char keys[32]; + int down; + + XQueryKeymap (spi_get_display (), keys); + down = BIT (keys, code); + return (down == 0); +} + +static gboolean +check_release (gpointer data) +{ + gboolean released; + Accessibility_DeviceEvent *event = (Accessibility_DeviceEvent *)data; + KeyCode code = event->hw_code; + + released = is_key_released (code); + + if (released) + { + check_release_handler = 0; + event->type = Accessibility_KEY_RELEASED_EVENT; + spi_controller_notify_keylisteners (saved_controller, event, TRUE); + } + return (released == 0); +} + +static void wait_for_release_event (XEvent *event, + SpiDEController *controller) +{ + pressed_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event); + check_release_handler = g_timeout_add (CHECK_RELEASE_DELAY, check_release, &pressed_event); +} + +/*---------------------------------------------------------------------------*/ + +static const char *introspection_header = +"\n"; + +static const char *introspection_node_element = +"\n"; + +static const char *introspection_footer = +""; + +static DBusMessage * +impl_Introspect (DBusConnection * bus, + DBusMessage * message, void *user_data) +{ + GString *output; + gchar *final; + gint i; + + const gchar *pathstr = SPI_DBUS_PATH_DEC; + + DBusMessage *reply; + + output = g_string_new(introspection_header); + + g_string_append_printf(output, introspection_node_element, pathstr); + + g_string_append (output, spi_org_a11y_atspi_DeviceEventController); + + g_string_append(output, introspection_footer); + final = g_string_free(output, FALSE); + + reply = dbus_message_new_method_return (message); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &final, DBUS_TYPE_INVALID); + + g_free(final); + return reply; +} + +/*---------------------------------------------------------------------------*/ + +static void +handle_dec_method_from_idle (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + const gchar *iface = dbus_message_get_interface (message); + const gchar *member = dbus_message_get_member (message); + const gint type = dbus_message_get_type (message); + DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + DBusMessage *reply = NULL; + + if (!strcmp (iface, SPI_DBUS_INTERFACE_DEC)) + { + result = DBUS_HANDLER_RESULT_HANDLED; + if (!strcmp (member, "RegisterKeystrokeListener")) + reply = impl_register_keystroke_listener (bus, message, user_data); + else if (!strcmp (member, "RegisterDeviceEventListener")) + reply = impl_register_device_event_listener (bus, message, user_data); + else if (!strcmp (member, "DeregisterKeystrokeListener")) + reply = impl_deregister_keystroke_listener (bus, message, user_data); + else if (!strcmp (member, "DeregisterDeviceEventListener")) + reply = impl_deregister_device_event_listener (bus, message, user_data); + else if (!strcmp (member, "GetKeystrokeListeners")) + reply = impl_get_keystroke_listeners (bus, message, user_data); + else if (!strcmp (member, "GetDeviceEventListeners")) + reply = impl_get_device_event_listeners (bus, message, user_data); + else if (!strcmp (member, "GenerateKeyboardEvent")) + reply = impl_generate_keyboard_event (bus, message, user_data); + else if (!strcmp (member, "GenerateMouseEvent")) + reply = impl_generate_mouse_event (bus, message, user_data); + else if (!strcmp (member, "NotifyListenersSync")) + reply = impl_notify_listeners_sync (bus, message, user_data); + else if (!strcmp (member, "NotifyListenersAsync")) + reply = impl_notify_listeners_async (bus, message, user_data); + else + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (!strcmp (iface, "org.freedesktop.DBus.Introspectable")) + { + result = DBUS_HANDLER_RESULT_HANDLED; + if (!strcmp (member, "Introspect")) + reply = impl_Introspect (bus, message, user_data); + else + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (result == DBUS_HANDLER_RESULT_HANDLED) + { + if (!reply) + { + reply = dbus_message_new_method_return (message); + } + + dbus_connection_send (bus, reply, NULL); + dbus_message_unref (reply); + } } +static gboolean +message_queue_dispatch (gpointer data) +{ + saved_controller->message_queue_idle = 0; + while (!g_queue_is_empty (saved_controller->message_queue)) + { + DBusMessage *message = g_queue_pop_head (saved_controller->message_queue); + data = g_queue_pop_head (saved_controller->message_queue); + handle_dec_method_from_idle (saved_controller->bus, message, data); + dbus_message_unref (message); + } + return FALSE; +} + +static DBusHandlerResult +handle_dec_method (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + const gchar *iface = dbus_message_get_interface (message); + const gchar *member = dbus_message_get_member (message); + const gint type = dbus_message_get_type (message); + + /* Check for basic reasons not to handle */ + if (type != DBUS_MESSAGE_TYPE_METHOD_CALL || + member == NULL || + iface == NULL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + dbus_message_ref (message); + g_queue_push_tail (saved_controller->message_queue, message); + g_queue_push_tail (saved_controller->message_queue, user_data); + if (!saved_controller->message_queue_idle) + saved_controller->message_queue_idle = g_idle_add (message_queue_dispatch, NULL); + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusObjectPathVTable dec_vtable = +{ + NULL, + &handle_dec_method, + NULL, NULL, NULL, NULL +}; + SpiDEController * -spi_device_event_controller_new (SpiRegistry *registry) +spi_registry_dec_new (SpiRegistry *reg, DBusConnection *bus) { - SpiDEController *retval = g_object_new ( - SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL); - - retval->registry = SPI_REGISTRY (bonobo_object_ref ( - BONOBO_OBJECT (registry))); + SpiDEController *dec = g_object_new (SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL); - spi_dec_init_mouse_listener (registry); - /* TODO: kill mouse listener on finalize */ - return retval; + dec->registry = g_object_ref (reg); + reg->dec = g_object_ref (dec); + dec->bus = bus; + + dbus_connection_register_object_path (bus, SPI_DBUS_PATH_DEC, &dec_vtable, dec); + + spi_dec_init_mouse_listener (dec); + + return dec; +} + +void +spi_device_event_controller_start_poll_mouse (SpiRegistry *registry) +{ + if (!have_mouse_event_listener) + { + have_mouse_event_listener = TRUE; + if (!have_mouse_listener) + g_timeout_add (100, spi_dec_poll_mouse_idle, registry->dec); + } } -BONOBO_TYPE_FUNC_FULL (SpiDEController, - Accessibility_DeviceEventController, - PARENT_TYPE, - spi_device_event_controller) +void +spi_device_event_controller_stop_poll_mouse (void) +{ + have_mouse_event_listener = FALSE; +}