X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=registryd%2Fdeviceeventcontroller.c;h=19c6df5cf88744810e77bd654b5662dcaacbaad3;hb=53015630d728812dc944da021b5821d7eac3cb14;hp=eba38833cd761650dea41eace5291451f199f82b;hpb=47343ab9f86ad94bee68e2546854e9b46ff4b40a;p=platform%2Fupstream%2Fat-spi2-core.git diff --git a/registryd/deviceeventcontroller.c b/registryd/deviceeventcontroller.c index eba3883..19c6df5 100644 --- a/registryd/deviceeventcontroller.c +++ b/registryd/deviceeventcontroller.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #define XK_MISCELLANY @@ -48,21 +49,21 @@ #endif /* HAVE_XEVIE */ #include -#include -#include /* TODO: hide dependency (wrap in single porting file) */ -#include -#include -#include -#include -#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 "deviceeventcontroller.h" #include "reentrant-list.h" +#include "introspection.h" + KeySym ucs2keysym (long ucs); long keysym2ucs(KeySym keysym); @@ -78,8 +79,13 @@ static void wait_for_release_event (XEvent *event, SpiDEController *controller); /* A pointer to our parent object 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; @@ -90,6 +96,9 @@ 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; + static int (*x_default_error_handler) (Display *display, XErrorEvent *error_event); typedef enum { @@ -160,10 +169,26 @@ 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) @@ -175,7 +200,15 @@ spi_dbus_add_disconnect_match (DBusConnection *bus, const char *name) dbus_error_init (&error); dbus_bus_add_match (bus, match, &error); g_free (match); - return !dbus_error_is_set (&error); + if (dbus_error_is_set (&error)) + { + dbus_error_free (&error); + return FALSE; + } + else + { + return TRUE; + } } else return FALSE; } @@ -190,7 +223,15 @@ spi_dbus_remove_disconnect_match (DBusConnection *bus, const char *name) dbus_error_init (&error); dbus_bus_remove_match (bus, match, &error); g_free (match); - return !dbus_error_is_set (&error); + if (dbus_error_is_set (&error)) + { + dbus_error_free (&error); + return FALSE; + } + else + { + return TRUE; + } } else return FALSE; } @@ -372,26 +413,33 @@ spi_dec_clear_unlatch_pending (SpiDEController *controller) priv->xkb_latch_mask = 0; } -static void emit(SpiDEController *controller, const char *interface, const char *name, int a1, int a2) +static void emit(SpiDEController *controller, const char *interface, const char *name, const char *minor, int a1, int a2) { DBusMessage *signal = NULL; - DBusMessageIter iter, iter_variant; + DBusMessageIter iter, iter_struct, iter_variant; int nil = 0; - const char *minor = ""; - const char *path = SPI_DBUS_PATH_DESKTOP; + 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_UINT32, &a1); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &a2); + 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 @@ -399,7 +447,7 @@ spi_dec_button_update_and_emit (SpiDEController *controller, guint mask_return) { Accessibility_DeviceEvent mouse_e; - gchar event_detail[24]; + gchar event_detail[3]; gboolean is_consumed = FALSE; if ((mask_return & mouse_button_mask) != @@ -478,7 +526,7 @@ spi_dec_button_update_and_emit (SpiDEController *controller, fprintf (stderr, "Button %d %s\n", button_number, (is_down) ? "Pressed" : "Released"); #endif - snprintf (event_detail, 22, "%d%c", button_number, + snprintf (event_detail, 3, "%d%c", button_number, (is_down) ? 'p' : 'r'); /* TODO: FIXME distinguish between physical and * logical buttons @@ -498,7 +546,7 @@ spi_dec_button_update_and_emit (SpiDEController *controller, if (!is_consumed) { dbus_uint32_t x = last_mouse_pos->x, y = last_mouse_pos->y; - emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "button", x, y); + emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "Button", event_detail, x, y); } else spi_dec_set_unlatch_pending (controller, mask_return); @@ -542,10 +590,10 @@ spi_dec_mouse_check (SpiDEController *controller, { // TODO: combine these two signals? dbus_uint32_t ix = *x, iy = *y; - emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "abs", ix, iy); + 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); + emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "Rel", "", ix, iy); last_mouse_pos->x = *x; last_mouse_pos->y = *y; *moved = True; @@ -577,7 +625,7 @@ spi_dec_emit_modifier_event (SpiDEController *controller, guint prev_mask, d1 = prev_mask & key_modifier_mask; d2 = current_mask & key_modifier_mask; - emit(controller, SPI_DBUS_INTERFACE_EVENT_KEYBOARD, "modifiers", d1, d2); + emit(controller, SPI_DBUS_INTERFACE_EVENT_KEYBOARD, "Modifiers", "", d1, d2); } static gboolean @@ -603,7 +651,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 { @@ -615,7 +665,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 { @@ -643,14 +695,11 @@ spi_dec_init_mouse_listener (SpiDEController *dec) { #ifdef GRAB_BUTTON Display *display = spi_get_display (); -#endif - g_timeout_add (100, spi_dec_poll_mouse_idle, dec); -#ifdef GRAB_BUTTON 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 @@ -806,6 +855,8 @@ spi_key_listener_data_free (DEControllerKeyListener *key_listener) { 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); } @@ -826,10 +877,13 @@ spi_listener_clone_free (DEControllerListener *clone) static void spi_dec_listener_free (DEControllerListener *listener) { - g_free (listener->bus_name); - g_free (listener->path); if (listener->type == SPI_DEVICE_TYPE_KBD) spi_key_listener_data_free ((DEControllerKeyListener *) listener); + else + { + g_free (listener->bus_name); + g_free (listener->path); + } } static void @@ -943,11 +997,142 @@ 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)) + { + if (listener->mode) + { + 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); + } + else + { + dbus_bool_t dummy_val = FALSE; + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_BOOLEAN, + &dummy_val); + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_BOOLEAN, + &dummy_val); + dbus_message_iter_append_basic (&iter_substruct, DBUS_TYPE_BOOLEAN, + &dummy_val); + } + 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) { DEControllerKeyListener *key_listener; + gboolean retval; switch (listener->type) { case SPI_DEVICE_TYPE_KBD: @@ -958,14 +1143,23 @@ spi_controller_register_device_listener (SpiDEController *controller, 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: break; @@ -973,8 +1167,113 @@ spi_controller_register_device_listener (SpiDEController *controller, 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, l->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, l->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, +Accessibility_DeviceEventListener_NotifyEvent(SpiDEController *controller, SpiRegistry *registry, DEControllerListener *listener, const Accessibility_DeviceEvent *key_event) @@ -982,21 +1281,36 @@ Accessibility_DeviceEventListener_notifyEvent(SpiDEController *controller, DBusMessage *message = dbus_message_new_method_call(listener->bus_name, listener->path, SPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER, - "notifyEvent"); - DBusError error; + "NotifyEvent"); 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)) { - // TODO: Evaluate performance: perhaps rework this whole architecture - // to avoid blocking calls - DBusMessage *reply = dbus_connection_send_with_reply_and_block(controller->bus, message, 1000, &error); + DBusMessage *reply; + + if (hung) + { + dbus_connection_send (controller->bus, message, NULL); + dbus_message_unref (message); + return FALSE; + } + + reply = send_and_allow_reentry (controller->bus, message, 3000, NULL); if (reply) { - DBusError error; - dbus_error_init(&error); - dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &consumed, DBUS_TYPE_INVALID); + dbus_message_get_args(reply, NULL, DBUS_TYPE_BOOLEAN, &consumed, DBUS_TYPE_INVALID); dbus_message_unref(reply); } } @@ -1047,7 +1361,7 @@ spi_controller_notify_mouselisteners (SpiDEController *controlle { DEControllerListener *listener = l2->data; - is_consumed = Accessibility_DeviceEventListener_notifyEvent (controller, controller->registry, listener, event); + is_consumed = Accessibility_DeviceEventListener_NotifyEvent (controller, controller->registry, listener, event); spi_listener_clone_free ((DEControllerListener *) l2->data); } @@ -1072,7 +1386,7 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller, XEvent *xevent) { Accessibility_DeviceEvent mouse_e; - gchar event_detail[24]; + gchar event_detail[3]; gboolean is_consumed = FALSE; gboolean xkb_mod_unlatch_occurred; XButtonEvent *xbutton_event = (XButtonEvent *) xevent; @@ -1110,7 +1424,7 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller, (xevent->type == ButtonPress) ? "Press" : "Release", mouse_button_state); #endif - snprintf (event_detail, 22, "%d%c", button, + snprintf (event_detail, 3, "%d%c", button, (xevent->type == ButtonPress) ? 'p' : 'r'); /* TODO: FIXME distinguish between physical and logical buttons */ @@ -1135,8 +1449,7 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller, spi_controller_notify_mouselisteners (controller, &mouse_e); ix = last_mouse_pos->x; iy = last_mouse_pos->y; - /* TODO - Work out which part of the spec this emit is fulfilling */ - //emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "button", event_detail, ix, iy); + emit(controller, SPI_DBUS_INTERFACE_EVENT_MOUSE, "Button", event_detail, ix, iy); } xkb_mod_unlatch_occurred = (xevent->type == ButtonPress || @@ -1153,10 +1466,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 (); @@ -1206,7 +1518,7 @@ global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) } } - return GDK_FILTER_CONTINUE; + return; } if (xevent->type == ButtonPress || xevent->type == ButtonRelease) { @@ -1279,7 +1591,7 @@ global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) XSynchronize (display, FALSE); } - return GDK_FILTER_CONTINUE; + return; } static int @@ -1334,15 +1646,24 @@ spi_controller_register_with_devices (SpiDEController *controller) if (XKeycodeToKeysym (spi_get_display (), i, 0) != 0) { /* don't use this one if there's a grab client! */ - gdk_error_trap_push (); + + /* 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, - gdk_x11_get_default_root_xwindow (), + spi_get_root_window (), TRUE, GrabModeSync, GrabModeSync); XSync (spi_get_display (), TRUE); XUngrabKey (spi_get_display (), i, 0, - gdk_x11_get_default_root_xwindow ()); - if (!gdk_error_trap_pop ()) + spi_get_root_window ()); + if (!spi_x_error_release ()) { reserved = i; break; @@ -1371,10 +1692,8 @@ spi_controller_register_with_devices (SpiDEController *controller) #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); } @@ -1389,7 +1708,9 @@ spi_key_set_contains_key (GSList *key_set, if (!key_set) { +#ifdef SPI_DEBUG g_print ("null key set!\n"); +#endif return TRUE; } @@ -1506,7 +1827,7 @@ spi_controller_notify_keylisteners (SpiDEController *controller, { DEControllerKeyListener *key_listener = l2->data; - is_consumed = Accessibility_DeviceEventListener_notifyEvent (controller, controller->registry, &key_listener->listener, key_event) && + is_consumed = Accessibility_DeviceEventListener_NotifyEvent (controller, controller->registry, &key_listener->listener, key_event) && key_listener->mode->preemptive; spi_key_listener_clone_free (key_listener); @@ -1742,7 +2063,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; } @@ -1755,7 +2076,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); @@ -1819,7 +2140,7 @@ spi_device_event_controller_object_finalize (GObject *object) } /* - * DBus Accessibility::DEController::registerKeystrokeListener + * DBus Accessibility::DEController::RegisterKeystrokeListener * method implementation */ static DBusMessage * @@ -1834,12 +2155,14 @@ impl_register_keystroke_listener (DBusConnection *bus, GSList *keys = NULL; dbus_int32_t mask, type; Accessibility_EventListenerMode *mode; - dbus_bool_t ret; + 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); - // TODO: verify type signature dbus_message_iter_get_basic(&iter, &path); dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &iter_array); @@ -1856,20 +2179,7 @@ impl_register_keystroke_listener (DBusConnection *bus, dbus_message_iter_next(&iter); dbus_message_iter_get_basic(&iter, &mask); dbus_message_iter_next(&iter); - if (!strcmp (dbus_message_iter_get_signature (&iter), "u")) - dbus_message_iter_get_basic(&iter, &type); - else - { - dbus_message_iter_recurse(&iter, &iter_array); - while (dbus_message_iter_get_arg_type(&iter_array) != DBUS_TYPE_INVALID) - { - dbus_uint32_t t; - dbus_message_iter_get_basic (&iter_array, &t); - type |= (1 << t); - dbus_message_iter_next (&iter_array); - } - dbus_message_iter_next (&iter_array); - } + dbus_message_iter_get_basic(&iter, &type); dbus_message_iter_next(&iter); mode = (Accessibility_EventListenerMode *)g_malloc(sizeof(Accessibility_EventListenerMode)); if (mode) @@ -1881,6 +2191,7 @@ impl_register_keystroke_listener (DBusConnection *bus, dbus_message_get_sender(message), path, (unsigned long) mask); #endif 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); @@ -1892,7 +2203,7 @@ impl_register_keystroke_listener (DBusConnection *bus, } /* - * DBus Accessibility::DEController::registerDeviceEventListener + * DBus Accessibility::DEController::RegisterDeviceEventListener * method implementation */ static DBusMessage * @@ -1902,16 +2213,14 @@ impl_register_device_event_listener (DBusConnection *bus, { SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data); DEControllerListener *dec_listener; - 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)) + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_UINT32, &event_types, DBUS_TYPE_INVALID)) { - return droute_invalid_arguments_error (message); + 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 ( @@ -1976,8 +2285,12 @@ spi_controller_deregister_device_listener (SpiDEController *controlle 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 @@ -1987,7 +2300,9 @@ spi_deregister_controller_key_listener (SpiDEController *controller, RemoveListenerClosure ctx; ctx.bus = controller->bus; - ctx.listener = (DEControllerListener *) key_listener; + 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 (g_slist_length(key_listener->keys) == 0) @@ -2001,6 +2316,7 @@ spi_deregister_controller_key_listener (SpiDEController *controller, spi_re_entrant_list_foreach (&controller->key_listeners, remove_listener_cb, &ctx); + spi_key_listener_clone_free ((DEControllerKeyListener *) ctx.listener); } void @@ -2015,6 +2331,7 @@ spi_remove_device_listeners (SpiDEController *controller, const char *bus_name) 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) @@ -2023,13 +2340,15 @@ spi_remove_device_listeners (SpiDEController *controller, const char *bus_name) 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; } } } /* - * DBus Accessibility::DEController::deregisterKeystrokeListener + * DBus Accessibility::DEController::DeregisterKeystrokeListener * method implementation */ static DBusMessage * @@ -2046,7 +2365,12 @@ impl_deregister_keystroke_listener (DBusConnection *bus, DBusMessage *reply = NULL; dbus_message_iter_init(message, &iter); - // TODO: verify type signature + if (strcmp (dbus_message_get_signature (message), "oa(iisi)uu") != 0) + { + g_warning ("Received DeregisterKeystrokeListener with strange signature '%s'", dbus_message_get_signature (message)); + return invalid_arguments_error (message); + } + dbus_message_iter_get_basic(&iter, &path); dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &iter_array); @@ -2081,7 +2405,7 @@ impl_deregister_keystroke_listener (DBusConnection *bus, } /* - * DBus Accessibility::DEController::deregisterDeviceEventListener + * DBus Accessibility::DEController::DeregisterDeviceEventListener * method implementation */ static DBusMessage * @@ -2091,15 +2415,13 @@ impl_deregister_device_event_listener (DBusConnection *bus, { 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)) + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_UINT32, &event_types, DBUS_TYPE_INVALID)) { - return droute_invalid_arguments_error (message); + return invalid_arguments_error (message); } listener = spi_dec_listener_new (dbus_message_get_sender(message), path, event_types); spi_controller_deregister_device_listener ( @@ -2108,6 +2430,56 @@ impl_deregister_device_event_listener (DBusConnection *bus, return reply; } +static DBusMessage * +impl_get_keystroke_listeners (DBusConnection *bus, + DBusMessage *message, + void *user_data) +{ + 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; + + if (!reply) + return NULL; + + 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; +} + +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) { unsigned int retval = 0; @@ -2392,13 +2764,12 @@ dec_synth_keystring (SpiDEController *controller, const char *keystring) /* - * DBus Accessibility::DEController::registerKeystrokeListener + * DBus Accessibility::DEController::RegisterKeystrokeListener * method implementation */ 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; @@ -2407,10 +2778,9 @@ static DBusMessage * impl_generate_keyboard_event (DBusConnection *bus, DBusMess 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)) + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &keycode, DBUS_TYPE_STRING, &keystring, DBUS_TYPE_UINT32, &synth_type, DBUS_TYPE_INVALID)) { - return droute_invalid_arguments_error (message); + return invalid_arguments_error (message); } #ifdef SPI_DEBUG @@ -2424,7 +2794,7 @@ static DBusMessage * impl_generate_keyboard_event (DBusConnection *bus, DBusMess * and fall back to XSendEvent() if XTest is not available. */ - gdk_error_trap_push (); + spi_x_error_trap (); priv = (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark); @@ -2474,10 +2844,9 @@ static DBusMessage * impl_generate_keyboard_event (DBusConnection *bus, DBusMess return reply; } -/* Accessibility::DEController::generateMouseEvent */ +/* 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; @@ -2486,10 +2855,9 @@ static DBusMessage * impl_generate_mouse_event (DBusConnection *bus, DBusMessage 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)) + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_STRING, &eventName, DBUS_TYPE_INVALID)) { - return droute_invalid_arguments_error (message); + return invalid_arguments_error (message); } #ifdef SPI_DEBUG @@ -2550,7 +2918,7 @@ static DBusMessage * impl_generate_mouse_event (DBusConnection *bus, DBusMessage return reply; } -/* Accessibility::DEController::notifyListenersSync */ +/* Accessibility::DEController::NotifyListenersSync */ static DBusMessage * impl_notify_listeners_sync (DBusConnection *bus, DBusMessage *message, void *user_data) { @@ -2561,7 +2929,7 @@ impl_notify_listeners_sync (DBusConnection *bus, DBusMessage *message, void *use if (!spi_dbus_demarshal_deviceEvent(message, &event)) { - return droute_invalid_arguments_error (message); + return invalid_arguments_error (message); } #ifdef SPI_DEBUG g_print ("notifylistening listeners synchronously: controller %p, event id %d\n", @@ -2588,7 +2956,7 @@ impl_notify_listeners_async (DBusConnection *bus, DBusMessage *message, void *us if (!spi_dbus_demarshal_deviceEvent(message, &event)) { - return droute_invalid_arguments_error (message); + return invalid_arguments_error (message); } #ifdef SPI_DEBUG g_print ("notifylistening listeners asynchronously: controller %p, event id %d\n", @@ -2644,6 +3012,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; @@ -2686,6 +3055,8 @@ 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 @@ -2742,43 +3113,178 @@ static void wait_for_release_event (XEvent *event, SpiDEController *controller) { pressed_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event); - saved_controller = controller; check_release_handler = g_timeout_add (CHECK_RELEASE_DELAY, check_release, &pressed_event); } -static DRouteMethod dev_methods[] = +/*---------------------------------------------------------------------------*/ + +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) { - { impl_register_keystroke_listener, "registerKeystrokeListener" }, - { impl_register_device_event_listener, "registerDeviceEventListener" }, - { impl_deregister_keystroke_listener, "deregisterKeystrokeListener" }, - { impl_deregister_device_event_listener, "deregisterDeviceEventListener" }, - { impl_generate_keyboard_event, "generateKeyboardEvent" }, - { impl_generate_mouse_event, "generateMouseEvent" }, - { impl_notify_listeners_sync, "notifyListenersSync" }, - { impl_notify_listeners_async, "notifyListenersAsync" }, - { NULL, NULL } + 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_registry_dec_new (SpiRegistry *reg, DBusConnection *bus, DRouteContext *droute) +spi_registry_dec_new (SpiRegistry *reg, DBusConnection *bus) { SpiDEController *dec = g_object_new (SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL); - DRoutePath *path; dec->registry = g_object_ref (reg); + reg->dec = g_object_ref (dec); dec->bus = bus; - path = droute_add_one (droute, - SPI_DBUS_PATH_DEC, - dec); - - droute_path_add_interface (path, - SPI_DBUS_INTERFACE_DEC, - dev_methods, - NULL); + dbus_connection_register_object_path (bus, SPI_DBUS_PATH_DEC, &dec_vtable, dec); spi_dec_init_mouse_listener (dec); - /* TODO: kill mouse listener on finalize */ 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); + } +} + +void +spi_device_event_controller_stop_poll_mouse (void) +{ + have_mouse_event_listener = FALSE; +}