*
* Copyright 2002 Ximian Inc.
* Copyright 2002 Sun Microsystems, Inc.
+ * Copyright 2010, 2011 Novell, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
*/
#include "atspi-private.h"
+#include <stdio.h>
typedef struct
{
AtspiDeviceListenerCB callback;
gpointer user_data;
+ GDestroyNotify callback_destroyed;
} DeviceEventHandler;
GObjectClass *device_parent_class;
-static guint32 _e_id = 0;
-
/*
* Misc. helpers.
*/
static DeviceEventHandler *
-device_event_handler_new (AtspiDeviceListenerCB callback, gpointer user_data)
+device_event_handler_new (AtspiDeviceListenerCB callback,
+ GDestroyNotify callback_destroyed,
+ gpointer user_data)
{
DeviceEventHandler *eh = g_new0 (DeviceEventHandler, 1);
eh->callback = callback;
+ eh->callback_destroyed = callback_destroyed;
eh->user_data = user_data;
return eh;
}
+static gboolean
+device_remove_datum (const AtspiDeviceEvent *event, void *user_data)
+{
+ AtspiDeviceListenerSimpleCB cb = user_data;
+ return cb (event);
+}
+
+static void
+device_event_handler_free (DeviceEventHandler *eh)
+{
+#if 0
+ /* TODO; Test this; it will probably crash with pyatspi for unknown reasons */
+ if (eh->callback_destroyed)
+ {
+ gpointer rea_callback = (eh->callback == device_remove_datum ?
+ eh->user_data : eh->callback);
+ (*eh->callback_destroyed) (real_callback);
+ }
+#endif
+ g_free (eh);
+}
+
static GList *
event_list_remove_by_cb (GList *list, AtspiDeviceListenerCB callback)
{
if (eh->callback == callback)
{
list = g_list_delete_link (list, l);
- g_free (eh);
+ device_event_handler_free (eh);
}
}
return TRUE;
}
-static void
-remove_listener (GObject *obj, gpointer data)
+static AtspiDeviceEvent *
+atspi_device_event_copy (const AtspiDeviceEvent *src)
+{
+ AtspiDeviceEvent *dst = g_new0 (AtspiDeviceEvent, 1);
+ dst->type = src->type;
+ dst->id = src->id;
+ dst->hw_code = src->hw_code;
+ dst->modifiers = src->modifiers;
+ dst->timestamp = src->timestamp;
+ if (src->event_string)
+ dst->event_string = g_strdup (src->event_string);
+ dst->is_text = src->is_text;
+ return dst;
+}
+
+void
+atspi_device_event_free (AtspiDeviceEvent *event)
{
- device_listeners = g_list_remove (device_listeners, obj);
+ if (event->event_string)
+ g_free (event->event_string);
+ g_free (event);
}
/*
const AtspiDeviceEvent *event)
{
GList *l;
- AtspiDeviceEvent anevent;
gboolean handled = FALSE;
/* FIXME: re-enterancy hazard on this list */
{
DeviceEventHandler *eh = l->data;
- if ((handled = eh->callback (&anevent, eh->user_data)))
+ if ((handled = eh->callback (atspi_device_event_copy (event), eh->user_data)))
{
break;
}
static void
atspi_device_listener_init (AtspiDeviceListener *listener)
{
- GList *new_list;
do
{
listener->id = listener_id++;
} while (!id_is_free (listener->id));
- new_list = g_list_append (device_listeners, listener);
- if (new_list) device_listeners = new_list;
+ device_listeners = g_list_append (device_listeners, listener);
}
static void
for (l = listener->callbacks; l; l = l->next)
{
- g_free (l->data);
+ device_event_handler_free (l->data);
}
g_list_free (listener->callbacks);
/**
* atspi_device_listener_new:
- * @callback: (scope call): an #AtspiDeviceListenerCB callback function,
+ * @callback: (scope notified): an #AtspiDeviceListenerCB callback function,
* or NULL.
* @user_data: (closure): a pointer to data which will be passed to the
* callback when invoked.
+ * @callback_destroyed: A #GDestroyNotify called when the listener is freed
+ * and data associated with the callback should be freed. It can be NULL.
*
- * Create a new #AtspiDeviceListener with a specified callback function.
+ * Creates a new #AtspiDeviceListener with a specified callback function.
*
- * Returns: a pointer to a newly-created #AtspiDeviceListener.
+ * Returns: (transfer full): a pointer to a newly-created #AtspiDeviceListener.
*
**/
AtspiDeviceListener *
-atspi_device_listener_new (AtspiDeviceListenerCB callback)
+atspi_device_listener_new (AtspiDeviceListenerCB callback,
+ void *user_data,
+ GDestroyNotify callback_destroyed)
{
AtspiDeviceListener *listener = g_object_new (atspi_device_listener_get_type (), NULL);
+ if (callback)
+ atspi_device_listener_add_callback (listener, callback, callback_destroyed,
+ user_data);
return listener;
}
/**
+ * atspi_device_listener_new_simple: (skip)
+ * @callback: (scope notified): an #AtspiDeviceListenerCB callback function,
+ * or NULL.
+ * @callback_destroyed: A #GDestroyNotify called when the listener is freed
+ * and data associated with the callback should be freed. It an be NULL.
+ *
+ * Creates a new #AtspiDeviceListener with a specified callback function.
+ * This method is similar to #atspi_device_listener_new, but callback
+ * takes no user data.
+ *
+ * Returns: a pointer to a newly-created #AtspiDeviceListener.
+ *
+ **/
+AtspiDeviceListener *
+atspi_device_listener_new_simple (AtspiDeviceListenerSimpleCB callback,
+ GDestroyNotify callback_destroyed)
+{
+ return atspi_device_listener_new (device_remove_datum, callback, callback_destroyed);
+}
+
+/**
* atspi_device_listener_add_callback:
* @listener: the #AtspiDeviceListener instance to modify.
- * @callback: (scope call): an #AtspiDeviceListenerCB function pointer.
+ * @callback: (scope notified): an #AtspiDeviceListenerCB function pointer.
+ * @callback_destroyed: A #GDestroyNotify called when the listener is freed
+ * and data associated with the callback should be freed. It can be NULL.
* @user_data: (closure): a pointer to data which will be passed to the
- * callback when invoked.
- *
- * Add an in-process callback function to an existing #AtspiDeviceListener.
+ * callback when invoked.
*
- * Returns: #TRUE if successful, otherwise #FALSE.
+ * Adds an in-process callback function to an existing #AtspiDeviceListener.
*
**/
void
atspi_device_listener_add_callback (AtspiDeviceListener *listener,
AtspiDeviceListenerCB callback,
+ GDestroyNotify callback_destroyed,
void *user_data)
{
g_return_if_fail (ATSPI_IS_DEVICE_LISTENER (listener));
+ DeviceEventHandler *new_handler;
- listener->callbacks = g_list_prepend (listener->callbacks,
- device_event_handler_new ((void *)callback, user_data));
+ new_handler = device_event_handler_new (callback,
+ callback_destroyed, user_data);
+
+ listener->callbacks = g_list_prepend (listener->callbacks, new_handler);
}
/**
* @listener: the #AtspiDeviceListener instance to modify.
* @callback: (scope call): an #AtspiDeviceListenerCB function pointer.
*
- * Remove an in-process callback function from an existing #AtspiDeviceListener.
- *
- * Returns: #TRUE if successful, otherwise #FALSE.
+ * Removes an in-process callback function from an existing
+ * #AtspiDeviceListener.
*
**/
void
listener->callbacks = event_list_remove_by_cb (listener->callbacks, (void *) callback);
}
-static const char *device_event_type = "(uinnisb)";
-
static void
read_device_event_from_iter (DBusMessageIter *iter, AtspiDeviceEvent *event)
{
dbus_uint32_t type;
dbus_int32_t id;
- dbus_int16_t hw_code;
- dbus_int16_t modifiers;
+ dbus_int32_t hw_code;
+ dbus_int32_t modifiers;
dbus_int32_t timestamp;
- char *event_string;
dbus_bool_t is_text;
DBusMessageIter iter_struct;
event->id = id;
dbus_message_iter_next (&iter_struct);
+ /* TODO: Remove cast from next two on ABI break */
dbus_message_iter_get_basic (&iter_struct, &hw_code);
- event->hw_code = hw_code;
+ event->hw_code = (gushort) hw_code;
dbus_message_iter_next (&iter_struct);
dbus_message_iter_get_basic (&iter_struct, &modifiers);
- event->modifiers = modifiers;
+ event->modifiers = (gushort) modifiers;
dbus_message_iter_next (&iter_struct);
dbus_message_iter_get_basic (&iter_struct, ×tamp);
event->is_text = is_text;
}
-/*
- * atspi_dbus_handle_DeviceEvent: (skip)
- */
DBusHandlerResult
-atspi_dbus_handle_DeviceEvent (DBusConnection *bus, DBusMessage *message, void *data)
+_atspi_dbus_handle_DeviceEvent (DBusConnection *bus, DBusMessage *message, void *data)
{
const char *path = dbus_message_get_path (message);
int id;
dbus_bool_t retval = FALSE;
GList *l;
DBusMessage *reply;
- void *p = &event;
- if (strcmp (dbus_message_get_signature (message), "(uinnisb)") != 0)
+ if (strcmp (dbus_message_get_signature (message), "(uiuuisb)") != 0)
{
g_warning ("Atspi: Unknown signature for an event");
goto done;
if (klass->device_event)
{
retval = (*klass->device_event) (listener, &event);
+ if (retval != 0 && retval != 1)
+ {
+ g_warning ("at-spi: device event handler returned %d; should be 0 or 1", retval);
+ retval = 0;
+ }
}
done:
reply = dbus_message_new_method_return (message);
gchar *
_atspi_device_listener_get_path (AtspiDeviceListener *listener)
-{
- return g_strdup_printf ("/org/a11y/atspi/listeners/%d", listener->id);
+{ return g_strdup_printf ("/org/a11y/atspi/listeners/%d", listener->id);
}
+
+G_DEFINE_BOXED_TYPE (AtspiDeviceEvent,
+ atspi_device_event,
+ atspi_device_event_copy,
+ atspi_device_event_free)