/* $Id: papi_atkobject.c,v 1.19.2.3 2007/03/23 06:02:20 marcusva Exp $
*
* Copyright (c) 2006, Marcus von Appen
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "papi.h"
#include "papi_private.h"
/* Forward declarations for AtkObject bindings. */
static PyObject* _not_implemented_noargs (PyObject *self);
static PyObject* _atkobject_new (PyTypeObject *type, PyObject *args,
PyObject *kwds);
static int _atkobject_init (PyAtkObject *self, PyObject *args, PyObject *kwds);
static void _atkobject_dealloc (PyAtkObject *self);
static PyObject* _atkobject_get_dict (PyAtkObject *self, void *closure);
static PyObject* _atkobject_ref_accessible_child (PyAtkObject *self,
PyObject *args);
static PyObject* _atkobject_ref_relation_set (PyAtkObject *self);
static PyObject* _atkobject_connect_property_change_handler (PyAtkObject *self,
PyObject *args);
static PyObject* _atkobject_remove_property_change_handler (PyAtkObject *self,
PyObject *args);
static PyObject* _atkobject_notify_state_change (PyAtkObject *self,
PyObject *args);
static PyObject* _atkobject_add_relationship (PyAtkObject *self,
PyObject *args);
static PyObject* _atkobject_remove_relationship (PyAtkObject *self,
PyObject *args);
static PyObject* _atkobject_get_name (PyAtkObject *self, void *closure);
static int _atkobject_set_name (PyAtkObject *self, PyObject *value,
void *closure);
static PyObject* _atkobject_get_description (PyAtkObject *self, void *closure);
static int _atkobject_set_description (PyAtkObject *self, PyObject *value,
void *closure);
static PyObject* _atkobject_get_parent (PyAtkObject *self, void *closure);
static int _atkobject_set_parent (PyAtkObject *self, PyObject *value,
void *closure);
static PyObject* _atkobject_get_n_accessible_children (PyAtkObject *self,
void *closure);
static PyObject* _atkobject_get_layer (PyAtkObject *self, void *closure);
static PyObject* _atkobject_get_mdi_zorder (PyAtkObject *self, void *closure);
static PyObject* _atkobject_get_role (PyAtkObject *self, void *closure);
static int _atkobject_set_role (PyAtkObject *self, PyObject *value,
void *closure);
static PyObject* _atkobject_get_index_in_parent (PyAtkObject *self,
void *closure);
static PyObject* _atkobject_get_attributes (PyAtkObject *self, void *closure);
/* Nonstandard enhancements. */
static PyObject* _atkobject_emit (PyAtkObject *self, PyObject *args);
static int _class_get_n_children (AtkObject *obj);
static AtkObject* _class_ref_child (AtkObject *obj, int i);
static int _class_get_index_in_parent (AtkObject *obj);
/* Signal handler for the property changes. */
static void _atkobject_handle_property_change (AtkObject *obj,
AtkPropertyValues *value);
/**
* Methods, which are bound to the PyAtkObject type.
*/
static PyMethodDef _atkobject_methods[] =
{
{ "ref_accessible_child", (PyCFunction) _atkobject_ref_accessible_child,
METH_VARARGS,
"O.ref_accessible_child (index) -> AtkObject\n\n"
"Gets a reference to the specified accessible child of the object.\n\n"
"The accessible children are 0-based so the first accessible child\n"
"is at index 0, the second at index 1 and so on." },
{ "ref_relation_set", (PyCFunction) _atkobject_ref_relation_set,
METH_NOARGS,
"O.ref_relation_set () -> AtkRelationSet\n\n"
"Gets the AtkRelationSet associated with the object." },
{ "ref_state_set", (PyCFunction) _not_implemented_noargs, METH_NOARGS,
"O.ref_state_set () -> AtkStateSet\n\n"
"Gets a reference to the state set of the accessible." },
{ "connect_property_change_handler",
(PyCFunction) _atkobject_connect_property_change_handler, METH_VARARGS,
"O.connect_property_change_handler (...) -> None\n\n"
"Specifies a function to be called when a property changes value.\n\n"
"Currently not implemented."},
{ "remove_property_change_handler",
(PyCFunction) _atkobject_remove_property_change_handler, METH_VARARGS,
"O.remove_property_change_handler (...) -> None\n\n"
"Removes a property change handler.\n\n"
"Currently not implemented."},
{ "notify_state_change", (PyCFunction) _atkobject_notify_state_change,
METH_VARARGS,
"O.notify_state_change (state, value) -> None\n\n"
"Emits a state-change signal for the specified state." },
{ "add_relationship", (PyCFunction) _atkobject_add_relationship,
METH_VARARGS,
"O.add_relationship (type, obj) -> None\n\n"
"Adds a relationship of a specific type with the specified target." },
{ "remove_relationship", (PyCFunction) _atkobject_remove_relationship,
METH_VARARGS,
"O.remove_relationship (type, obj) -> None\n\n"
"Removes a relationship of a specific type with the specified target." },
/* Nonstandard enhancement. */
{ "emit", (PyCFunction) _atkobject_emit, METH_VARARGS,
"O.emit (type) -> None\n\n"
"Emits a specific signal on the underlying AT-SPI implementation." },
{ NULL, NULL, 0, NULL }
};
/**
* Getters and setters for the PyAtkObject.
*/
static PyGetSetDef _atkobject_getsets[] = {
{ "__dict__", (getter) _atkobject_get_dict, NULL, NULL, NULL },
{ "name", (getter) _atkobject_get_name, (setter) _atkobject_set_name,
"The name of the accessible.", NULL },
{ "description", (getter) _atkobject_get_description,
(setter) _atkobject_set_description,
"The description of the accessible.", NULL },
{ "parent", (getter) _atkobject_get_parent, (setter) _atkobject_set_parent,
"The parent of the accessible.", NULL },
{ "n_accessible_children", (getter) _atkobject_get_n_accessible_children,
NULL, "The number of accessible children of the accessible.", NULL },
{ "layer", (getter) _atkobject_get_layer, NULL,
"The layer of the accessible.", NULL },
{ "mdi_zorder", (getter) _atkobject_get_mdi_zorder, NULL,
"The z-order of the accessible. The value None will be returned if\n"
"the layer of the accessible is not ATK_LAYER_MDI.", NULL },
{ "role", (getter) _atkobject_get_role, (setter) _atkobject_set_role,
"The role of the accessible.", NULL },
{ "index_in_parent", (getter) _atkobject_get_index_in_parent, NULL,
"The 0-based index of this accessible in its parent or -1\n"
"if the accessible does not have an accessible parent.", NULL },
{ "attributes", (getter) _atkobject_get_attributes, NULL,
"A list of AtkAttributes applied to this AtkObject as a whole.", NULL },
{ NULL, NULL, NULL, NULL, NULL }
};
/**
* PyAtkObject wrapper type, that encapsulates the AtkObject.
*/
PyTypeObject PyAtkObject_Type =
{
PyObject_HEAD_INIT(NULL)
0,
"papi.AtkObject", /* tp_name */
sizeof (PyAtkObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor) _atkobject_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
"AtkObject (interfaces) -> AtkObject\n\n"
"ATK accessibility object.\n\n",
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
offsetof (PyAtkObject, weakrefs), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
_atkobject_methods, /* tp_methods */
0, /* tp_members */
_atkobject_getsets, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof (PyAtkObject, dict), /* tp_dictoffset */
(initproc) _atkobject_init, /* tp_init */
0, /* tp_alloc */
_atkobject_new, /* tp_new */
0, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
0, /* tp_cache */
0, /* tp_subclasses */
0, /* tp_weaklist */
0 /* tp_del */
};
static inline PyObject*
_construct_object (AtkObject *val)
{
PyObject *retval;
debug ("Constructing object...\n");
if (val)
{
retval = g_object_get_data (G_OBJECT (val), PAPI_PYOBJECT);
if (!retval) /* Not constructed by Papi. */
{
AtkInterfaceType ifaces;
GType *types;
retval = PyAtkObject_Type.tp_new (&PyAtkObject_Type, NULL, NULL);
((PyAtkObject *) retval)->obj = g_object_ref (val);
/* Prepare some data slots for the references. */
g_object_set_data (G_OBJECT (val), PAPI_CHILDREN, NULL);
g_object_set_data (G_OBJECT (val), PAPI_PYOBJECT, retval);
/* Set up the interfaces for the type. */
types = g_type_interfaces (G_TYPE_FROM_INSTANCE (val), NULL);
ifaces = atktype_get_num (types);
g_free (types);
atktype_add_interface_methods (retval, ifaces);
}
else
Py_INCREF (retval);
return retval;
}
Py_RETURN_NONE;
}
/**
* Creates a new PyAtkObject.
*/
static PyObject*
_atkobject_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
{
debug ("_atkobject_new\n");
return PyType_GenericNew (type, args, kwds);
}
/**
* Initializes the PyAtkObject members, such as the AtkObject.
*/
static int
_atkobject_init (PyAtkObject *self, PyObject *args, PyObject *kwds)
{
debug ("_atkobject_init\n");
AtkInterfaceType ifaces = 0;
if (!PyArg_ParseTuple (args, "|l:init", &ifaces))
return -1;
/* No interfaces provided, create default AtkObject. */
if (!self->obj)
{
if (ifaces == IFACE_INVALID)
self->obj = g_object_new (ATK_TYPE_OBJECT, NULL);
else
self->obj = g_object_new (atktype_get_type (ifaces), NULL);
/* Prepare some data slots for the references. */
g_object_set_data (G_OBJECT (self->obj), PAPI_CHILDREN, NULL);
g_object_set_data (G_OBJECT (self->obj), PAPI_PYOBJECT, self);
atktype_add_interface_methods ((PyObject *) self, ifaces);
}
/* Update the interface bindings. */
return 0;
}
/**
* Deallocates the PyAtkObject and its members.
*/
static void
_atkobject_dealloc (PyAtkObject *self)
{
debug ("_atkobject_dealloc\n");
if (self->obj)
g_object_unref (self->obj);
Py_XDECREF (self->dict);
Py_XDECREF (self->prop_handlers);
if (self->weakrefs)
PyObject_ClearWeakRefs ((PyObject *) self);
self->ob_type->tp_free ((PyObject *) self);
}
/**
* Getter for AtkObject.__dict__.
*/
static PyObject*
_atkobject_get_dict (PyAtkObject *self, void *closure)
{
if (!self->dict)
{
self->dict = PyDict_New ();
if (!self->dict)
return NULL;
}
Py_INCREF (self->dict);
return self->dict;
}
/**
* Default implementation for the interfaces.
*/
static PyObject*
_not_implemented_noargs (PyObject *self)
{
PyErr_SetString (PyExc_NotImplementedError, "method not implemented");
return NULL;
}
/**
* Wrapper for atk_object_get_name().
*/
static PyObject*
_atkobject_get_name (PyAtkObject *self, void *closure)
{
const gchar *val;
debug ("_atkobject_get_name\n");
val = atk_object_get_name (ATKOBJECT (self));
if (val)
return PyString_FromString (val);
Py_RETURN_NONE;
}
/**
* Wrapper for atk_object_set_name().
*/
static int
_atkobject_set_name (PyAtkObject *self, PyObject *value, void *closure)
{
char *val;
debug ("_atkobject_set_name\n");
if (!value)
{
PyErr_SetString (PyExc_TypeError, "Cannot delete the name attribute");
return -1;
}
val = PyString_AsString (value);
if (!val)
return -1;
atk_object_set_name (ATKOBJECT (self), val);
return 0;
}
/**
* Wrapper for atk_object_get_description().
*/
static PyObject*
_atkobject_get_description (PyAtkObject *self, void *closure)
{
const gchar *val;
debug ("_atkobject_get_description\n");
val = atk_object_get_description (ATKOBJECT (self));
if (val)
return PyString_FromString (val);
Py_RETURN_NONE;
}
/**
* Wrapper for atk_object_set_description().
*/
static int
_atkobject_set_description (PyAtkObject *self, PyObject *value, void *closure)
{
char *val;
debug ("_atkobject_set_description\n");
if (!value)
{
PyErr_SetString (PyExc_TypeError,
"Cannot delete the description attribute");
return -1;
}
val = PyString_AsString (value);
if (!val)
return -1;
atk_object_set_description (ATKOBJECT (self), val);
return 0;
}
/**
* Wrapper for atk_object_get_parent().
*/
static PyObject*
_atkobject_get_parent (PyAtkObject *self, void *closure)
{
AtkObject *val;
debug ("_atkobject_get_parent\n");
val = atk_object_get_parent (ATKOBJECT (self));
return _construct_object (val);
}
/**
* Wrapper for atk_object_set_parent().
*/
static int
_atkobject_set_parent (PyAtkObject *self, PyObject *value, void *closure)
{
gpointer data;
debug ("_atkobject_set_parent\n");
if (!value)
{
PyErr_SetString (PyExc_TypeError,
"Cannot delete the parent attribute");
return -1;
}
/* Nullify parent. */
if (value == Py_None)
{
AtkObject *parent = ATKOBJECT (self)->accessible_parent;
if (parent)
{
data = g_object_get_data (G_OBJECT (parent), PAPI_CHILDREN);
data = g_list_remove (data, self->obj);
ATKOBJECT (self)->accessible_parent = NULL;
g_object_set_data (G_OBJECT (parent), PAPI_CHILDREN, data);
}
return 0;
}
else if (!PyObject_TypeCheck (value, &PyAtkObject_Type))
{
PyErr_SetString (PyExc_TypeError, "parameter must be an AtkObject");
return -1;
}
else
atk_object_set_parent (ATKOBJECT (self), ATKOBJECT (value));
/* Add the object to the list of children of the parent. */
data = g_object_get_data (G_OBJECT (ATKOBJECT (value)), PAPI_CHILDREN);
data = g_list_append (data, self->obj);
g_object_set_data (G_OBJECT (ATKOBJECT (value)), PAPI_CHILDREN, data);
return 0;
}
/**
* Wrapper for atk_object_get_n_accessible_children().
*/
static PyObject*
_atkobject_get_n_accessible_children (PyAtkObject *self, void *closure)
{
gint val;
debug ("_atkobject_get_n_accessible_children\n");
val = atk_object_get_n_accessible_children (ATKOBJECT (self));
return PyInt_FromLong ((long) val);
}
/**
* Wrapper for atk_object_ref_accessible_child().
*/
static PyObject*
_atkobject_ref_accessible_child (PyAtkObject *self, PyObject *args)
{
AtkObject *val;
int i;
debug ("_atkobject_ref_accessible_child\n");
if (!PyArg_ParseTuple (args, "i:ref_accessible_child", &i))
return NULL;
val = atk_object_ref_accessible_child (ATKOBJECT (self), i);
return _construct_object (val);
}
/**
* Wrapper for atk_object_ref_relation_set().
*/
static PyObject*
_atkobject_ref_relation_set (PyAtkObject *self)
{
PyAtkRelationSet *set;
AtkRelationSet *aset;
debug ("_atkobject_ref_relationset\n");
aset = atk_object_ref_relation_set (ATKOBJECT (self));
if (!aset)
Py_RETURN_NONE;
set = PyObject_New (PyAtkRelationSet, &PyAtkRelationSet_Type);
set->obj = aset;
return (PyObject *) set;
}
/**
* Wrapper for atk_object_get_layer().
*/
static PyObject*
_atkobject_get_layer (PyAtkObject *self, void *closure)
{
AtkLayer layer;
debug ("_atkobject_get_layer\n");
layer = atk_object_get_layer (ATKOBJECT (self));
return PyInt_FromLong ((long) layer);
}
/**
* Wrapper for atk_object_get_mdi_zorder().
*/
static PyObject*
_atkobject_get_mdi_zorder (PyAtkObject *self, void *closure)
{
int z;
debug ("_atkobject_get_mdi_zorder\n");
z = atk_object_get_mdi_zorder (ATKOBJECT (self));
return PyInt_FromLong ((long) z);
}
/**
* Wrapper for atk_object_get_role().
*/
static PyObject*
_atkobject_get_role (PyAtkObject *self, void *closure)
{
AtkRole role;
debug ("_atkobject_get_role\n");
role = atk_object_get_role (ATKOBJECT (self));
return PyInt_FromLong ((long) role);
}
/**
* Wrapper for atk_object_set_role().
*/
static int
_atkobject_set_role (PyAtkObject *self, PyObject *value, void *closure)
{
debug ("_atkobject_set_role\n");
if (!value)
{
PyErr_SetString (PyExc_TypeError, "Cannot delete the role attribute");
return -1;
}
atk_object_set_role (ATKOBJECT (self), PyInt_AsLong (value));
return 0;
}
/**
* Wrapper for atk_object_get_index_in_parent().
*/
static PyObject*
_atkobject_get_index_in_parent (PyAtkObject *self, void *closure)
{
int val;
debug ("_atkobject_index_in_parent\n");
val = atk_object_get_index_in_parent (ATKOBJECT (self));
return PyInt_FromLong ((long) val);
}
/**
* Wrapper for atk_object_get_attributes().
*/
static PyObject*
_atkobject_get_attributes (PyAtkObject *self, void *closure)
{
PyObject *list;
PyAtkAttribute *attr;
AtkAttributeSet *set;
guint amount = 0;
int i = 0;
debug ("_atkobject_get_attributes\n");
set = atk_object_get_attributes (ATKOBJECT (self));
amount = g_slist_length (set);
if (amount == 0)
{
Py_RETURN_NONE;
}
list = PyList_New ((int) g_slist_length (set));
if (!list)
return NULL;
do
{
attr = PyObject_New (PyAtkAttribute, &PyAtkAttribute_Type);
attr->obj = (AtkAttribute *) set->data;
PyList_SetItem (list, i++, (PyObject *) attr);
}
while ((set = g_slist_next (set)));
return list;
}
/**
* Wrapper for atk_object_connect_property_change_handler().
*/
static PyObject*
_atkobject_connect_property_change_handler (PyAtkObject *self, PyObject *args)
{
PyObject *callback;
guint id = 0;
debug ("_atkobject_connect_property_change_handler\n");
if (!PyArg_ParseTuple (args, "O:connect_property_change_handler",
&callback))
return NULL;
if (!PyCallable_Check (callback))
{
PyErr_SetString (PyExc_TypeError, "parameter must be callable");
return NULL;
}
/* No property change handler registered for now. Set up the list. */
if (!self->prop_handlers)
{
self->prop_handlers = PyDict_New ();
if (!self->prop_handlers)
return NULL;
/* Just bind our wrapper only once as it will cycle through
* the dict and invoke each connected hander function. */
id = atk_object_connect_property_change_handler
(ATKOBJECT (self),
(AtkPropertyChangeHandler *) _atkobject_handle_property_change);
}
/* Could not append to list. */
if (PyDict_SetItem (self->prop_handlers,
PyInt_FromLong (PyDict_Size (self->prop_handlers)),
callback) == -1)
{
atk_object_remove_property_change_handler (ATKOBJECT (self), id);
return NULL;
}
return PyInt_FromLong (PyDict_Size (self->prop_handlers));
}
/**
* Wrapper for atk_object_remove_property_change_handler().
*/
static PyObject*
_atkobject_remove_property_change_handler (PyAtkObject *self, PyObject *args)
{
int id = 0;
debug ("_atkobject_remove_property_change_handler\n");
if (!PyArg_ParseTuple (args, "i:remove_property_change_handler", &id))
return NULL;
if (PyDict_DelItem (self->prop_handlers, PyInt_FromLong (id)) == -1)
return NULL;
Py_RETURN_NONE;
}
/**
* Wrapper for atk_object_notify_state_change().
*/
static PyObject*
_atkobject_notify_state_change (PyAtkObject *self, PyObject *args)
{
AtkState state;
int val;
debug ("_atkobject_notify_state_change\n");
if (!PyArg_ParseTuple (args, "ii:notify_state_changed", &state, &val))
return NULL;
atk_object_notify_state_change (ATKOBJECT (self), state, val);
Py_RETURN_NONE;
}
/**
* Wrapper for atk_object_add_relationship().
*/
static PyObject*
_atkobject_add_relationship (PyAtkObject *self, PyObject *args)
{
PyObject *target;
AtkRelationType type;
debug ("_atkobject_add_relationship\n");
if (!PyArg_ParseTuple (args, "iO:add_relationship", &type, &target))
return NULL;
if (!PyObject_TypeCheck (target, &PyAtkObject_Type))
{
PyErr_SetString (PyExc_TypeError, "argument 2 must be an AtkObject");
return NULL;
}
if (atk_object_add_relationship (ATKOBJECT (self), type,
ATKOBJECT (target)))
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
/**
* Wrapper for atk_object_remove_relationship().
*/
static PyObject*
_atkobject_remove_relationship (PyAtkObject *self, PyObject *args)
{
PyObject *target;
AtkRelationType type;
debug ("_atkobject_remove_relationship\n");
if (!PyArg_ParseTuple (args, "iO:remove_relationship", &type, &target))
return NULL;
if (!PyObject_TypeCheck (target, &PyAtkObject_Type))
{
PyErr_SetString (PyExc_TypeError, "argument 2 must be an AtkObject");
return NULL;
}
if (atk_object_remove_relationship (ATKOBJECT (self), type,
ATKOBJECT (target)))
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
/**
* Emits signals on the registered listener hooks.
*/
static PyObject*
_atkobject_emit (PyAtkObject *self, PyObject *args)
{
PyObject *dict = NULL;
PyObject *obj = NULL;
PyObject *list = NULL;
int size = 0;
guint id = 0;
char *type = NULL;
GValue *value = NULL;
GSignalInvocationHint hint;
debug ("_atkobject_emit\n");
if (!PyArg_ParseTuple (args, "s:emit", &type))
return NULL;
#ifdef DEBUG
printf ("DEBUG: Received signal: %s\n", type);
#endif
id = atkutil_lookup_signal (type);
if (!id) /* id == 0 */
{
PyErr_Format (PyExc_KeyError, "Signal '%s' does not exist.", type);
return NULL;
}
dict = PyDict_GetItemString (atkutil_get_listeners (), type);
if (!dict)
{
PyErr_Format (PyExc_KeyError, "Key '%s' does not exist.", type);
return NULL;
}
list = PyDict_Values (dict);
size = PyList_Size (list);
/* Iterate over the attached emission hooks and invoke them. */
for (int i = 0; i < size; i++)
{
obj = PyList_GetItem (list, i);
/* Create the args for the GSignalEmissionHook. */
hint.signal_id = id;
hint.detail = g_quark_from_string (type);
hint.run_type = G_SIGNAL_RUN_FIRST;
/* Create the arguments for the hook. */
value = g_new0 (GValue, 1);
g_value_init (value, G_TYPE_FROM_INSTANCE (ATKOBJECT (self)));
g_value_set_instance (value, ATKOBJECT (self));
/* Invoke it. */
((GSignalEmissionHook) PyCObject_AsVoidPtr (obj)) (&hint, 1, value,
NULL);
g_free (value);
}
Py_DECREF (list);
Py_RETURN_NONE;
}
/**
* Interface for AtkObjectClass->get_n_children.
*/
static int
_class_get_n_children (AtkObject *obj)
{
debug ("_class_get_n_children\n");
GList *list = g_object_get_data (G_OBJECT (obj), PAPI_CHILDREN);
if (list)
return g_list_length (list);
return 0;
}
/**
* Interface for AtkObjectClass->ref_child.
*/
static AtkObject*
_class_ref_child (AtkObject *obj, int i)
{
AtkObject *val = NULL;
GList *list = NULL;
debug ("_class_ref_child\n");
list = g_object_get_data (G_OBJECT (obj), PAPI_CHILDREN);
if (list)
{
val = g_list_nth_data (list, (guint) i);
if (!val)
return NULL;
}
if (val)
g_object_ref (val);
return val;
}
/**
* Interface for AtkObjectClass->get_index_in_parent.
*/
static int
_class_get_index_in_parent (AtkObject *obj)
{
GList *list;
AtkObject *parent;
debug ("_class_get_index_in_parent\n");
parent = atk_object_get_parent (obj);
if (!parent)
return -1;
list = g_object_get_data (G_OBJECT (parent), PAPI_CHILDREN);
if (list)
return g_list_index (list, obj);
return -1;
}
/**
* Interface for AtkObjectClass->ref_state_set.
*/
static AtkStateSet*
_class_ref_state_set (AtkObject *obj)
{
PyObject *pyobj;
PyObject *result;
AtkStateSet *retval = NULL;
debug ("_class_ref_state_set\n");
pyobj = g_object_get_data (G_OBJECT (obj), PAPI_PYOBJECT);
result = PyObject_CallMethod (pyobj, "ref_state_set", NULL);
if (!result)
return atk_state_set_new (); /* Returning NULL crashes A11Y apps. */
if (PyObject_TypeCheck (result, &PyAtkStateSet_Type))
retval = ATKSTATESET (result);
g_object_ref (retval);
Py_DECREF (result);
return retval;
}
/**
* Generic callback handler for property changes, which invokes the
* user-defined python handlers.
*/
static void
_atkobject_handle_property_change (AtkObject *obj, AtkPropertyValues *value)
{
PyObject *callback = NULL;
PyObject *retval = NULL;
PyObject *name = NULL;
PyObject *oldval = NULL;
PyObject *newval = NULL;
int pos = 0;
PyAtkObject *atkobj = (PyAtkObject *) g_object_get_data (G_OBJECT (obj),
PAPI_PYOBJECT);
while (PyDict_Next (atkobj->prop_handlers, &pos, NULL, &callback))
{
name = PyString_FromString (value->property_name);
oldval = pyobject_from_gvalue (&(value->old_value));
newval = pyobject_from_gvalue (&(value->new_value));
retval = PyObject_CallFunctionObjArgs (callback, name, oldval, newval,
NULL);
Py_DECREF (name);
Py_DECREF (oldval);
Py_DECREF (newval);
Py_DECREF (retval);
}
}
/**
* Bind the different AtkObjectClass interfaces to their needed
* implementations.
*/
void
atkobjectclass_init (AtkObjectClass *class)
{
debug ("Hooking AtkObjectClass interfaces.\n");
class->get_n_children = _class_get_n_children;
class->ref_child = _class_ref_child;
class->get_index_in_parent = _class_get_index_in_parent;
class->ref_state_set = _class_ref_state_set;
}
syntax highlighted by Code2HTML, v. 0.9.1