GNOME Bugzilla – Bug 377253
Make it possible to implement AtkObjectFactory vtable functions
Last modified: 2018-08-17 13:35:18 UTC
Make it possible to implement AtkObjectFactory vtable functions. It's a bit tricky and should probably not be done by the code generator since they are not normal methods: struct _AtkObjectFactoryClass { GObjectClass parent_class; AtkObject* (* create_accessible) (GObject *obj); void (* invalidate) (AtkObjectFactory *factory); GType (* get_accessible_type) (void); AtkFunction pad1; AtkFunction pad2; }; invalidate is already working fine, the important ones are create_accessible and get_accessible_type. There's a macro in gail which we can probably port over, which seems to be the easiest way to do this: http://cvs.gnome.org/viewcvs/gail/gail/gailfactory.h?rev=1.1&view=markup
Where is that struct defined? It doesn't seem to match http://cvs.gnome.org/viewcvs/atk/atk/atkobjectfactory.c?rev=1.9&view=markup which defines create_accessible and get_accessible_type differently: AtkObject* atk_object_factory_create_accessible (AtkObjectFactory *factory, GObject *obj) GType atk_object_factory_get_accessible_type (AtkObjectFactory *factory)
(In reply to comment #1) > Where is that struct defined? It doesn't seem to match > http://cvs.gnome.org/viewcvs/atk/atk/atkobjectfactory.c?rev=1.9&view=markup > which defines create_accessible and get_accessible_type differently: > > AtkObject* atk_object_factory_create_accessible (AtkObjectFactory *factory, > GObject *obj) > > GType > atk_object_factory_get_accessible_type (AtkObjectFactory *factory) > It's something else, eg helper functions to call the vtable methods.
I see it now in atkobjectfactory.h. I'm trying to learn a bit about the pygtk code generation so I can work on a patch myself. Do you have any pointers to get me started? I'm looking at atk.override and see the following statements in an ignore section: AtkObjectFactory__do_create_accessible AtkObjectFactory__proxy_do_create_accessible Is this file I would incorporate the code into? The format of the file looks vaguely SWIG like. Is there doc on what these sections mean? How do the do_* methods come into existence?
I think I see how things are working in the override file now. I'll take at this bug. But, by all means, step on my toes if you find the time. I'm sure you can do it much more quickly. :)
I don't want to discourage you, but I believe but 377382 must be fixed before this bug can be properly solved.
I think the common case can be implemented now. You can get a reference to a factory instance in the default Registry using atk_registry_get_factory. I can implement a partial solution now. If they agree to make changes to atk, we can implement a more general solution later.
I've got code for proxy_do_create_accessible that works. Apparently the get_accessible_type method is never used in practice. With the attached patch, I can define an atk.ObjectFactory in Python, override do_create_accessible, return a atk.GObjectAccessible, and see the result in a tool like at-poke. Of course, you still want bug #377382 fixed, especially since there is a push to make some of the accessibility modules part of the LSB.
Created attachment 76959 [details] [review] adds do_create_accessible proxy to atk.ObjectFactory
Any chance of getting this patch applied?
Hi Gustavo, Can I get a review of the patch I created for this bug? It works well enough locally so that I can implement atkGObjects for pycairo and have the accessibility information show up in Accerciser. If you approve, can you commit it please? Without it, there's no way to implement accessibility support for custom widgets in pygtk.
Comment on attachment 76959 [details] [review] adds do_create_accessible proxy to atk.ObjectFactory I don't think PyGTK has branched for development yet, so you have to convince jdahlin, not me :) I detected a small refcount bug in the patch, see inline: >Index: atk.override >=================================================================== >RCS file: /cvs/gnome/pygtk/atk.override,v >retrieving revision 1.18 >diff -u -p -r1.18 atk.override >--- atk.override 3 Oct 2006 17:49:11 -0000 1.18 >+++ atk.override 21 Nov 2006 04:09:59 -0000 >@@ -39,7 +39,6 @@ import gobject.GObject as PyGObject_Type > ignore > atk_text_free_ranges > AtkObjectFactory__do_create_accessible >- AtkObjectFactory__proxy_do_create_accessible > AtkUtil__do_add_global_event_listener > AtkUtil__proxy_do_add_global_event_listener > AtkUtil__do_remove_global_event_listener >@@ -51,6 +50,94 @@ ignore > %% > ignore-glob > *_get_type >+%% >+override AtkObjectFactory__proxy_do_get_accessible_type noargs >+static GType >+_wrap_AtkObjectFactory__proxy_do_get_accessible_type(void) >+{ >+ // can't do anything here until bug #377382 is fixed >+ return NULL; >+} >+%% >+override AtkObjectFactory__proxy_do_create_accessible kwargs >+static AtkObject* >+_wrap_AtkObjectFactory__proxy_do_create_accessible(GObject *obj) >+{ >+ PyGILState_STATE __py_state; >+ GType obj_type; >+ AtkObjectFactory *self; >+ AtkRegistry *def_reg; >+ PyObject *py_self; >+ AtkObject* retval; >+ PyObject *py_args; >+ PyObject *py_retval; >+ PyObject *py_method; >+ PyObject *py_obj; >+ >+ __py_state = pyg_gil_state_ensure(); >+ // get the object type >+ obj_type = G_TYPE_FROM_INSTANCE(obj); //pyg_type_from_object(obj); >+ // use the default registry to find the factory >+ def_reg = atk_get_default_registry(); >+ self = atk_registry_get_factory(def_reg, obj_type); >+ >+ // proceed as usual >+ py_self = pygobject_new((GObject *) self); >+ if (!py_self) { >+ if (PyErr_Occurred()) >+ PyErr_Print(); >+ pyg_gil_state_release(__py_state); >+ return NULL; >+ } >+ >+ py_method = PyObject_GetAttrString(py_self, "do_create_accessible"); >+ if (!py_method) { >+ if (PyErr_Occurred()) >+ PyErr_Print(); >+ Py_DECREF(py_self); >+ pyg_gil_state_release(__py_state); >+ return NULL; >+ } >+ >+ // pass PyGObject as param >+ py_obj = pygobject_new(obj); >+ py_args = PyTuple_New(1); >+ PyTuple_SET_ITEM(py_args, 0, py_obj); PyTuple_SET_ITEM "steals" a reference to py_obj >+ >+ py_retval = PyObject_CallObject(py_method, py_args); >+ if (!py_retval) { >+ if (PyErr_Occurred()) >+ PyErr_Print(); >+ Py_DECREF(py_args); >+ Py_DECREF(py_obj); You no longer own py_obj, so don't DECREF it. >+ Py_DECREF(py_method); >+ Py_DECREF(py_self); >+ pyg_gil_state_release(__py_state); >+ return NULL; >+ } >+ if (!PyObject_TypeCheck(py_retval, &PyGObject_Type)) { >+ PyErr_SetString(PyExc_TypeError, "retval should be a GObject"); >+ PyErr_Print(); >+ Py_DECREF(py_args); >+ Py_DECREF(py_obj); Idem. >+ Py_DECREF(py_retval); >+ Py_DECREF(py_method); >+ Py_DECREF(py_self); >+ pyg_gil_state_release(__py_state); >+ return NULL; >+ } >+ retval = (AtkObject*) pygobject_get(py_retval); >+ g_object_ref((GObject *) retval); >+ >+ Py_DECREF(py_args); >+ Py_DECREF(py_obj); Idem. >+ Py_DECREF(py_retval); >+ Py_DECREF(py_method); >+ Py_DECREF(py_self); >+ pyg_gil_state_release(__py_state); >+ >+ return retval; >+} > %% > override atk_relation_new kwargs > static int
> (From update of attachment 76959 [details] [review] [edit]) > I don't think PyGTK has branched for development yet, so you have to convince > jdahlin, not me :) Ah. No problem. This can wait until after the branch. I know nothing about the pygtk development cycle. > I detected a small refcount bug in the patch, see inline: Good catch. I forgot that the tuple borrows the ref. Surprised my test case doesn't bomb. I'll post a fixed patch. Thanks for the review.
Created attachment 88963 [details] [review] fixes ref. count issues from previous patch
pygtk is not under active development anymore and had its last code changes in 2013. Its codebase has been archived: https://gitlab.gnome.org/Archive/pygtk/commits/master PyGObject at https://gitlab.gnome.org/GNOME/pygobject is its successor. See https://pygobject.readthedocs.io/en/latest/guide/porting.html for porting info. Closing this report as WONTFIX as part of Bugzilla Housekeeping to reflect reality. Feel free to open a task in GNOME Gitlab if the issue described in this task still applies to a recent version of PyGObject. Thanks!