Re: libatspi and event processing
Lukasz Stanislawski <[email protected]>
| Newsgroups | gmane.comp.gnome.accessibility.general |
|---|---|
| Message-ID | <[email protected]> |
On 05.03.2015 05:14, Mike Gorse wrote: > Not really an answer, but the call to process_deferred_messages() is the > interesting bit here. When an AT-SPI event is received, it is queued for > later processing via process_deferred_messages, which is executed either > in an idle handler or at the end of a method call. Iirc this is done in > order to control the order in which events are sent, as it will not > recurse. > Yes, I also think that events order is essential for capturing proper application state. However I have a feeling that this order has to be kept only for dbus signals messages (like state-changed, children-changes, value-change etc). Messages that are response to method calls can be processed beforehead dbus signals with, I suppose, no harm to atspi object tree state. But its only a guess :) > I'm not sure if the process_deferred_messages() calls at the ends of > these AT-SPI functions need to be there. Perhaps they should be removed, > although I'd be hesitant to remove them for 3.16 this late in the > cycle--the code has worked that way for a long time... Feel free to file > a bug if you'd like it to be tracked that way. > I'm not really in position of pointing that it is a bug or not. It's just an issue I have encountered in my code, which causes very rare, hard to reproduce and to debug bugs. It just changed flow of my program in a way that I was not expecting. There is no single sentence in documentation that says about triggering events in atspi functions, so I considered it must just block and wait for response - however not only. So my final thought is: 1. Just fix a docs and let accessibility apps programmers deal with it. 2. Rearrange dbus message processing order (it might break something, but I don't know atspi so well to deduced what) > On Tue, 3 Mar 2015, Lukasz Stanislawski wrote: > >> Hey, thank Tou for quick answer. >> >> On 02.03.2015 18:39, Alejandro Piñeiro wrote: >>> On 02/03/15 18:08, Lukasz Stanislawski wrote: >>>> Hello everyone, >>>> >>>> Currently, I'm developing small C application using libatspi and >>>> encountered some problems with event processing. >>>> >>>> What I have is two event listeners A and B registered with >>>> atspi_event_listener_register() on different at-spi events. Inside >>>> main loop assume that A listener can invoke callback a() on some atspi >>>> event. Inside a() callback there are some calls to >>>> atspi_accessible_get_* functions. >>>> >>>> What I have noticed is that calling functins like. >>>> atspi_accessible_get_name() triggers further dbus events processing >>>> what result in different listeners to be invoked. >>> >>> Those get functions need to trigger those dbus events, as the >>> information is usually not stored (except if it is already cached) at >>> libatspi. It needs to be requested to the client (the application). So >>> it is not possible to avoid that dbus triggering, as is the only way to >>> get the info you request. >>> >> Yeah, it is not possible to avoid dbus triggering when method is >> invoked, however is it possible not to process mismatching events? >> (eg. whem atspi_accessibile_get_name method is invoked only dbus >> message matching returning name will be processed) Can rest of events >> gathered while waiting for answer be queued and processed when main >> loop enters idle state? >> >>>> As the result code of b() callback can be invoked (and sometimes is in >>>> my application) during execution of a() callback code.called >>> >>> About getting the other callback called because a different listener is >>> invoked: it is complicated to understand your problem at a so abstract >>> level. Could you give a example of what event is triggered when >>> atspi_accessible_get_<something> that invokes the second callback? >>> >> My real life example is a bit different and more complex however I >> will try to explain it in details. I have an accessibility application >> allowing users to navigate only over specific type of widgets etc, >> with some various policies. >> >> To do this, first of all I have to be able to track what window have >> currently input focus. I'm doing it by registering listener on >> "window:active" and "object:state-changed:focused". When any of these >> events occurs on_window_activate callback is called. >> >> Secondly. when window receives focus I have to gather all interesting >> information from accessibility tree and build my own cache from data >> that is not cached by atspi like positions and sizes. It occurred that >> there are some performance issues with it, (main loop is blocked too >> long not allowing other events to be processed), so I have decided to >> fetch data partially using idlers. >> >> When my own data cache is done I start to process it and through the >> processing of data a call to atspi_accessibile_get_role is made. This >> causes the issues which I have mentioned earlier. When new >> "window:active" signal was send, it will process it and call >> on_window_activate callback which in my code - invalidates my cache. >> >> When atspi_accessible_get_role returns my cache is already invalid. >> This resulted in cache errors and I couldn't find out what is >> happening unless i have looked into atspi source code. >> >> This situations mostly happens when application right after gaining >> focus on window creates new window and focuses. This is a result >> backtrace, please check frame #14, #9 and #0 : >> >> #0 on_window_activate (data=0x0, window=0xaf560) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/navigator.c:822 >> #1 0x0000e4f4 in _on_atspi_window_cb (event=0xd1ff8) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/window_tracker.c:18 >> #2 0xb6d9a638 in remove_datum (event=<optimized out>, >> user_data=<optimized out>) at atspi-event-listener.c:56 >> #3 0xb6d9afd0 in _atspi_send_event (e=0xbefff8d8) >> at atspi-event-listener.c:849 >> #4 0xb6d9b1c2 in _atspi_dbus_handle_event (bus=<optimized out>, >> message=<optimized out>, data=<optimized out>) >> at atspi-event-listener.c:979 >> #5 0xb6d9d2e0 in process_deferred_message (closure=0xc65a8) >> at atspi-misc.c:748 >> #6 process_deferred_messages () at atspi-misc.c:787 >> #7 process_deferred_messages () at atspi-misc.c:777 >> #8 0xb6d9d6f2 in _atspi_dbus_call (obj=<optimized out>, >> interface=<optimized out>, method=0xb6da4fc0 "GetRole", error=0x0, >> type=0xb6da4fc8 "=>u") at atspi-misc.c:1152 >> #9 0xb6d98c3a in atspi_accessible_get_role (obj=0xc2718, >> error=<optimized out>) at atspi-accessible.c:473 >> #10 0x0000dae0 in _filter_role_cb (container=<optimized out>, >> data=<optimized out>, fdata=0x_on_cache_buildedc2718) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/flat_navi.c:153 >> --Type <return> to continue, or q <return> to quit-- >> #11 0x0000da92 in _accessible_list_split_with_filter (list=0x5a8e8, >> cb=0xdac5 <_filter_role_cb>, user_data=0x11e0c <interesting_roles>) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/flat_navi.c:112 >> #12 0x0000dc34 in _flat_review_candidates_get (root=<optimized out>) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/flat_navi.c:213 >> #13 flat_navi_context_create (root=<optimized out>) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/flat_navi.c:257 >> #14 0x0000fa4e in _on_cache_builded (data=<optimized out>) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/navigator.c:802 >> #15 0x0000e878 in _do_cache (data=<optimized out>) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/object_cache.c:173 >> #16 _do_cache (data=<optimized out>) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/object_cache.c:163 >> #17 0xb6e05860 in _ecore_call_task_cb (data=<optimized out>, >> func=<optimized out>) at ecore_private.h:272 >> #18 _ecore_idler_all_call () at ecore_idler.c:119 >> #19 0xb6e067c6 in _ecore_main_loop_spin_core () at ecore_main.c:1746 >> #20 0xb6e069d8 in _ecore_main_loop_spin_timers () at ecore_main.c:1780 >> #21 _ecore_main_loop_iterate_internal (once_only=0) at ecore_main.c:1903 >> #22 0xb6e06dc0 in ecore_main_loop_begin () at ecore_main.c:956 >> #23 0xb6fa5ab6 in appcore_efl_main () from /usr/lib/libappcore-efl.so.1 >> #24 0x0000bfcc in main (argc=1, argv=0xbefffdc4) >> at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/main.c:71 >> >> I have managed to solve my issues by simple removing all calls to >> atspi_accessible_get_* in my cache processing code. However I was >> carious if I'm doing something wrong or just atspi programmer have to >> be aware that this can happen. Maybe shouldn't it be better if it >> worked as I wrote in first at the begining, What do You think? >> >>>> >>>> I find this very inconvenient because every atspi_accessible_get_* >>>> related call in callback a() have to be wrapped with some 'rollback' >>>> logic in my application, because events of listener B can occur. >>>> >>>> So my questions are: >>>> >>>> 1. What is a preferred way of handling such cases? I want every >>>> callback to process sequentially and not to introduce new race >>>> conditions in my application. Such APIs makes my code hard to write >>>> because "everything can happen everywhere". >>> >>> As mentioned, if in your callback you call new atspi methods, they would >>> need to use dbus to get that info. But it would be good to have a real >>> example in order to know why this is problematic. >>> >>>> 2. Shouldn't it be better to dispatch all deferred events when main >>>> loop enters idle state? Mayby there is a reasoning for such design >>>> that I'm not familiar of. >>> >>> You seem to suggest the addition of an asynchronous API. If that is the >>> case, it is true that there are some attempts to include an asynchronous >>> API in order to solve some issues of the classic libatspi synchronous >>> API. But in most cases, libatspi is still an asynchronous API. >>> >>> BR >>> >> _______________________________________________ >> gnome-accessibility-list mailing list >> [email protected] >> https://mail.gnome.org/mailman/listinfo/gnome-accessibility-list >>