X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=cspi%2Fspi_event.c;h=d20161a5ff06643f023e8bd3771c784a7d3eaea7;hb=f70112b3ebb4b50efed40c97eab02554652866b8;hp=695f1a2147f35d718ba61130f15480135d83779c;hpb=b7b8c5ec58a241e524435db41cbe798109f175dc;p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git diff --git a/cspi/spi_event.c b/cspi/spi_event.c index 695f1a2..d20161a 100644 --- a/cspi/spi_event.c +++ b/cspi/spi_event.c @@ -22,7 +22,6 @@ */ #include -#include static GSList *_cspi_event_queue = NULL; @@ -332,38 +331,147 @@ AccessibleDeviceListener_unref (AccessibleDeviceListener *listener) static char * cspi_internal_event_get_text (const InternalEvent *e) { - CORBA_any *any; g_return_val_if_fail (e, NULL); - g_return_val_if_fail (e->data, NULL); - any = (CORBA_any *) e->data; - if (CORBA_TypeCode_equivalent (any->_type, TC_CORBA_string, NULL)) + if (e->event.v_type == EVENT_DATA_STRING) { - return CORBA_string_dup (* (char **) any->_value); - } - else - { -#ifdef EVENT_CONTEXT_DEBUG - fprintf (stderr, "requested string, TC is not TC_CORBA_string! (%u)\n", - (unsigned) any->_type); -#endif - return NULL; + return g_strdup (e->event.v.text? e->event.v.text: ""); } + return NULL; } static Accessible * cspi_internal_event_get_object (const InternalEvent *e) { - CORBA_any *any; + g_return_val_if_fail (e, NULL); + if (e->event.v_type == EVENT_DATA_OBJECT) + { + cspi_object_ref (e->event.v.accessible); + return e->event.v.accessible; + } + return NULL; +} +static SPIRect * +cspi_internal_event_get_rect (const InternalEvent *e) +{ g_return_val_if_fail (e, NULL); - g_return_val_if_fail (e->data, NULL); + if (e->event.v_type == EVENT_DATA_RECT) + { + SPIRect *rect = g_new (SPIRect, 1); + if (rect) memcpy (rect, &e->event.v.rect, sizeof(*rect)); + return rect; + } + return NULL; +} - any = (CORBA_any *) e->data; - if (CORBA_TypeCode_equal (any->_type, TC_CORBA_Object, cspi_ev())) - return cspi_object_take (* (CORBA_Object *) any->_value); - else - return NULL; +/** + * AccessibleEvent_getSourceName: + * @e: an #AccessibleEvent to be queried. + * + * Get the 'accessible-name' of the object emitting the event. + * + * Returns: The name of the event source, or NULL if the event source cannot be identified + * or does not report a name. + */ +char* AccessibleEvent_getSourceName (const AccessibleEvent *e) +{ + if (e && e->source) + { + return Accessible_getName (e->source); + } + return NULL; +} + +/** + * AccessibleEvent_getSourceRole: + * @e: an #AccessibleEvent to be queried. + * + * Get the #AccessibleRole of the object emitting the event. + * + * Returns: #AccessibleRole of the event source, or SPI_ROLE_UNKNOWN + * if the event source's role is unknown or unspecified. + * (Some kinds of events, such as 'mouse:' events or + * toolkit events, don't have associated object roles.) + */ +AccessibleRole AccessibleEvent_getSourceRole (const AccessibleEvent *e) +{ + if (e && e->source) + { + return Accessible_getRole (e->source); + } + return SPI_ROLE_UNKNOWN; +} + +/** + * AccessibleEvent_getSourceApplication: + * @e: an #AccessibleEvent to be queried. + * + * Get the #Application hosting the object which emitted the event. + * + * Returns: A pointer to the host #Application contining the event source + * component. + */ +#if 0 +AccessibleApplication* AccessibleEvent_getSourceApplication (const AccessibleEvent *e) +{ +xyzzy + InternalEvent *ie = (InternalEvent *)e; + CORBA_any *any = ((ie && ie->data) ? (CORBA_any *)ie->data : NULL); + if (any && + CORBA_TypeCode_equivalent (any->_type, + TC_Accessibility_EventDetails, NULL)) + { + Accessibility_EventDetails *details = (Accessibility_EventDetails *) any->_value; + return cspi_object_take (details->host_application); + } + else + return NULL; +} +#endif + +/** + * AccessibleEvent_getSourceDetails: + * @e: an #AccessibleEvent to be queried. + * @name: a pointer to a character string which will point to the name of the event source + * on successful completion of the call. + * @role: a pointer to an #AccessibleRole which will point to the role of the event source + * on successful completion of the call. + * @app: A pointer to an #AccessibleApplication which points to the host application for this event + * on successful completion of the call. + * + * Get the host #Application, "accessible name", and #AccessibleRole + * of the object which emitted the event. + * + * Returns: TRUE if the source details were successfully retrieved, + * FALSE if they were not, either due to error, incomplete data, + * or the fact that the event did not encapsulate the required data. + */ +#if 0 +SPIBoolean AccessibleEvent_getSourceDetails (const AccessibleEvent *e, + char **name, AccessibleRole *role, + AccessibleApplication **app) +{ + InternalEvent *ie = (InternalEvent *)e; + CORBA_any *any = ((ie && ie->data) ? (CORBA_any *)ie->data : NULL); + if (any && + CORBA_TypeCode_equivalent (any->_type, + TC_Accessibility_EventDetails, NULL)) + { + Accessibility_EventDetails *details = (Accessibility_EventDetails *) any->_value; + *name = CORBA_string_dup (details->source_name); + *role = cspi_role_from_spi_role (details->source_role); + *app = cspi_object_take (details->host_application); + return TRUE; + } + else + { + *name = NULL; + *role = SPI_ROLE_UNKNOWN; + *app = NULL; + return FALSE; + } } +#endif /** * AccessibleTextChangedEvent_getChangeString: @@ -593,6 +701,28 @@ AccessibleDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e return cspi_internal_event_get_text (foo); } +/** + * AccessibleBoundsChangedEvent_getNewBounds: + * @e: a pointer to the #AccessibleEvent being queried. + * + * Queries an #AccessibleEvent of type "object:bounds-changed", + * returning a pointer to an SPIRect structure containing the + * new bounds, or NULL on error. + * The returned structure should be freed with SPI_freeRect when + * the caller has finished referencing it. + * + * @Since: AT-SPI 1.6 + * + * Returns: a pointer to an SPIRect defining the new object bounds. + **/ +SPIRect * +AccessibleBoundsChangedEvent_getNewBounds (const AccessibleEvent *e) +{ + const InternalEvent *foo = (InternalEvent *) e; + /* TODO: check the event type. */ + return cspi_internal_event_get_rect (foo); +} + static gint cspi_event_compare (gconstpointer p1, gconstpointer p2) { @@ -708,9 +838,409 @@ AccessibleEvent_unref (const AccessibleEvent *e) cspi_internal_event_remove (event); g_free ((gpointer)e->type); Accessible_unref (e->source); - CORBA_free (event->data); + if (event->event.v_type == EVENT_DATA_OBJECT) + { + Accessible_unref (event->event.v.accessible); + } g_free ((gpointer)e); } } } } + +typedef struct +{ + CSpiEventListener *listener; + char *event; + char *detail; +} CSpiEventListenerEntry; + +static GList *event_listeners = NULL; + +static dbus_bool_t +demarshal_rect (DBusMessageIter *iter, SPIRect *rect) +{ + dbus_int32_t x, y, width, height; + DBusMessageIter iter_struct; + + dbus_message_iter_recurse (iter, &iter_struct); + if (dbus_message_iter_get_arg_type (&iter_struct) != DBUS_TYPE_INT32) return FALSE; + dbus_message_iter_get_basic (&iter_struct, &x); + dbus_message_iter_next (&iter_struct); + if (dbus_message_iter_get_arg_type (&iter_struct) != DBUS_TYPE_INT32) return FALSE; + dbus_message_iter_get_basic (&iter_struct, &y); + dbus_message_iter_next (&iter_struct); + if (dbus_message_iter_get_arg_type (&iter_struct) != DBUS_TYPE_INT32) return FALSE; + dbus_message_iter_get_basic (&iter_struct, &width); + dbus_message_iter_next (&iter_struct); + if (dbus_message_iter_get_arg_type (&iter_struct) != DBUS_TYPE_INT32) return FALSE; + dbus_message_iter_get_basic (&iter_struct, &height); + rect->x = x; + rect->y = y; + rect->width = width; + rect->height = height; + return TRUE; +} + +static gboolean +parse_eventType (const char *eventType, char **type, char **detail, char **matchrule) +{ + char *p, *q; + char *t, *d; + + p = strchr (eventType, ':'); + if (p) p = strchr (p + 1, ':'); + if (!p) p = eventType + strlen (eventType); + t = g_malloc (p - eventType + 1); + if (t) + { + memcpy (t, eventType, p - eventType); + t[p - eventType] = '\0'; + if (!strchr (t, ':')) + { + char *q = g_strconcat (t, ":", NULL); + if (1) + { + g_free (t); + t = q; + } + } + } + else return FALSE; + if (*p == ':') + { + d = g_strdup (p + 1); + if (!d) + { + g_free (t); + return FALSE; + } + } + else d = NULL; + if ((p = strchr (t, ':'))) + { + *p = (p[1] == '\0'? '\0': '_'); + } + while ((p = strchr (t, '-'))) *p = '_'; + if (matchrule) + { + *matchrule = g_strdup_printf ("type='signal',interface='%s',member='%s'", spi_interface_accessible, t); + if (!*matchrule) + { + g_free (t); + if (d) g_free (d); + return FALSE; + } + } + if (type) *type = t; + if (detail) *detail = d; + return TRUE; +} + +static void listener_data_free (CSpiEventListenerEntry *e) +{ + g_free (e->event); + if (e->detail) g_free (e->detail); + g_free (e); +} + +/** + * SPI_registerGlobalEventListener: + * @listener: the #AccessibleEventListener to be registered against an + * event type. + * @eventType: a character string indicating the type of events for which + * notification is requested. Format is + * EventClass:major_type:minor_type:detail + * where all subfields other than EventClass are optional. + * EventClasses include "object", "window", "mouse", + * and toolkit events (e.g. "Gtk", "AWT"). + * Examples: "focus:", "Gtk:GtkWidget:button_press_event". + * + * Legal object event types: + * + * (property change events) + * + * object:property-change + * object:property-change:accessible-name + * object:property-change:accessible-description + * object:property-change:accessible-parent + * object:property-change:accessible-value + * object:property-change:accessible-role + * object:property-change:accessible-table-caption + * object:property-change:accessible-table-column-description + * object:property-change:accessible-table-column-header + * object:property-change:accessible-table-row-description + * object:property-change:accessible-table-row-header + * object:property-change:accessible-table-summary + * + * (other object events) + * + * object:state-changed + * object:children-changed + * object:visible-data-changed + * object:selection-changed + * object:text-selection-changed + * object:text-changed + * object:text-caret-moved + * object:row-inserted + * object:row-reordered + * object:row-deleted + * object:column-inserted + * object:column-reordered + * object:column-deleted + * object:model-changed + * object:active-descendant-changed + * + * (window events) + * + * window:minimize + * window:maximize + * window:restore + * window:close + * window:create + * window:reparent + * window:desktop-create + * window:desktop-destroy + * window:activate + * window:deactivate + * window:raise + * window:lower + * window:move + * window:resize + * window:shade + * window:unshade + * window:restyle + * + * (other events) + * + * focus: + * mouse:abs + * mouse:rel + * mouse:b1p + * mouse:b1r + * mouse:b2p + * mouse:b2r + * mouse:b3p + * mouse:b3r + * + * NOTE: this string may be UTF-8, but should not contain byte value 56 + * (ascii ':'), except as a delimiter, since non-UTF-8 string + * delimiting functions are used internally. + * In general, listening to + * toolkit-specific events is not recommended. + * + * Add an in-process callback function to an existing AccessibleEventListener. + * + * Returns: #TRUE if successful, otherwise #FALSE. + **/ +SPIBoolean +SPI_registerGlobalEventListener (AccessibleEventListener *listener, + const char *eventType) +{ + CSpiEventListenerEntry *e; + char *matchrule; + DBusError error; + GList *new_list; + + if (!listener) + { + return FALSE; + } + + e = g_new (CSpiEventListenerEntry, 1); + if (!e) return FALSE; + e->listener = listener; + if (!parse_eventType (eventType, &e->event, &e->detail, &matchrule)) + { + g_free (e); + return FALSE; + } + new_list = g_list_prepend (event_listeners, e); + if (!new_list) + { + listener_data_free (e); + return FALSE; + } + event_listeners = new_list; + dbus_error_init (&error); + dbus_bus_add_match (cspi_bus(), matchrule, &error); + if (error.message) + { + g_warning ("Adding match: %s", error.message); + } + return TRUE; +} + +/** + * SPI_deregisterGlobalEventListenerAll: + * @listener: the #AccessibleEventListener to be registered against + * an event type. + * + * deregisters an AccessibleEventListener from the registry, for all + * event types it may be listening to. Use + * AccessibleEventListener_unref to release the + * listener reference. + * + * Returns: #TRUE if successful, otherwise #FALSE. + **/ +SPIBoolean +SPI_deregisterGlobalEventListenerAll (AccessibleEventListener *listener) +{ + GList *l; + + if (!listener) + { + return FALSE; + } + + for (l = event_listeners; l;) + { + CSpiEventListenerEntry *e = l->data; + if (e->listener == listener) + { + listener_data_free (e); + l = g_list_remove (l, e); + } + else l = g_list_next (l); + } + return TRUE; +} + +/** + * SPI_deregisterGlobalEventListener: + * @listener: the #AccessibleEventListener registered against an event type. + * @eventType: a string specifying the event type for which this + * listener is to be deregistered. + * + * deregisters an AccessibleEventListener from the registry, for a specific + * event type. + * + * Returns: #TRUE if successful, otherwise #FALSE. + **/ +SPIBoolean +SPI_deregisterGlobalEventListener (AccessibleEventListener *listener, + const char *eventType) +{ + char *type, *detail, *matchrule; + GList *l; + + if (!parse_eventType (eventType, &type, &detail, &matchrule)) + { + return FALSE; + } + if (!listener) + { + return FALSE; + } + + for (l = event_listeners; l;) + { + CSpiEventListenerEntry *e = l->data; + if (e->listener == listener && !strcmp (e->event, type) && (e->detail == detail || !strcmp (e->detail, detail))) + { + DBusError error; + listener_data_free (e); + l = g_list_remove (l, e); + dbus_error_init (&error); + dbus_bus_remove_match (cspi_bus(), matchrule, &error); + } + else l = g_list_next (l); + } + g_free (type); + if (detail) g_free (detail); + g_free (matchrule); + return TRUE; +} + +void +cspi_dispatch_event (AccessibleEvent *e) +{ + char *event, *detail; + GList *l; + + if (!parse_eventType (e->type, &event, &detail, NULL)) + { + g_warning ("Couldn't parse event: %s\n", e->type); + return; + } + for (l = event_listeners; l; l = g_list_next (l)) + { + CSpiEventListenerEntry *entry = l->data; + if (!strcmp (event, entry->event) && + (entry->detail == NULL || !strcmp (detail, entry->detail))) + { + CSpiEventListenerClass *klass = CSPI_EVENT_LISTENER_GET_CLASS (entry->listener); + if (klass->event) (*klass->event)(entry->listener, e); + } + } + if (detail) g_free (detail); + g_free (event); +} + +DBusHandlerResult +cspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data) +{ + char *detail = NULL; + const char *event = dbus_message_get_member (message); + DBusMessageIter iter, iter_variant; + dbus_message_iter_init (message, &iter); + AccessibleEvent e; + dbus_int32_t detail1, detail2; + char *p; + + g_return_if_fail (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING); + dbus_message_iter_get_basic (&iter, &detail); + dbus_message_iter_next (&iter); + g_return_if_fail (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_INT32); + dbus_message_iter_get_basic (&iter, &detail1); + e.detail1 = detail1; + dbus_message_iter_next (&iter); + g_return_if_fail (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_INT32); + dbus_message_iter_get_basic (&iter, &detail2); + e.detail2 = detail2; + dbus_message_iter_next (&iter); + e.type = g_strdup (event); + p = strchr (e.type, '_'); + if (p) *p = ':'; + if (detail[0] != '\0') + { + p = g_strconcat (e.type, ":", detail, NULL); + if (p) + { + g_free (e.type); + e.type = p; + } + } + while ((p = strchr (e.type, '_'))) *p = '-'; + e.source = cspi_ref_accessible (dbus_message_get_sender(message), dbus_message_get_path(message)); + dbus_message_iter_recurse (&iter, &iter_variant); + switch (dbus_message_iter_get_arg_type (&iter_variant)) + { + case DBUS_TYPE_OBJECT_PATH: + { + dbus_message_iter_get_basic (&iter_variant, &p); + e.v_type = EVENT_DATA_OBJECT; + e.v.accessible = cspi_ref_accessible (dbus_message_get_sender(message), p); + break; + } + case DBUS_TYPE_STRING: + { + dbus_message_iter_get_basic (&iter_variant, &p); + e.v_type = EVENT_DATA_STRING; + e.v.text = g_strdup (p); + break; + } + case DBUS_TYPE_STRUCT: + { + if (demarshal_rect (&iter_variant, &e.v.rect)) + { + e.v_type = EVENT_DATA_RECT; + } + break; + } + default: + break; + } + cspi_dispatch_event (&e); + return DBUS_HANDLER_RESULT_HANDLED; +}