[pyatspi2] Event ordering fixes
- From: Mike Gorse <mgorse src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pyatspi2] Event ordering fixes
- Date: Fri, 16 Apr 2010 17:47:57 +0000 (UTC)
commit 4b71fd9c3ad169d46f9425382c243872f1973f19
Author: Mike Gorse <mgorse novell com>
Date: Mon Apr 5 16:50:18 2010 -0400
Event ordering fixes
Add partial synchronous support; allow events to be queued so that they
are delivered in the correct order and data is cached appropriately once
they are delivered
Cache toolkitName as a work-around for Orca requesting it before
deciding whether to queue an event; fixes some out-of-order issues with Orca.
pyatspi/accessible.py | 16 ++++++++++++++++
pyatspi/appevent.py | 9 ++++++++-
pyatspi/application.py | 2 +-
pyatspi/cache.py | 12 +++++++++++-
pyatspi/registry.py | 48 ++++++++++++++++++++++++++++++++++++++++++++----
5 files changed, 80 insertions(+), 7 deletions(-)
---
diff --git a/pyatspi/accessible.py b/pyatspi/accessible.py
index 373d3ff..831f5d7 100644
--- a/pyatspi/accessible.py
+++ b/pyatspi/accessible.py
@@ -486,4 +486,20 @@ class Accessible(BaseProxy):
"""
interfaces = property(fget=_get_interfaces, doc=_interfacesDoc)
+ def _getConstantProperty(self, interface, name):
+ if self.cached:
+ try:
+ getattr(self, "extraData")
+ except (attributeError):
+ self.extraData = dit()
+ try:
+ return self.extraData[name]
+ except (attributeError):
+ r = registry.Registry()
+ r.freezeEvents()
+ self.extraData[name] = dbus.String(self._pgetter(interface, name))
+ r.thawEvents()
+ return self.extraData[name]
+ return dbus.String(self._pgetter(interface, name))
+
#END----------------------------------------------------------------------------
diff --git a/pyatspi/appevent.py b/pyatspi/appevent.py
index d530e8c..bee0333 100644
--- a/pyatspi/appevent.py
+++ b/pyatspi/appevent.py
@@ -13,12 +13,14 @@
#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import string
+import gobject
import interfaces
from accessible import BoundingBox
from exceptions import *
from factory import AccessibleFactory
from busutils import *
+import registry
__all__ = [
"Event",
@@ -216,7 +218,12 @@ def event_type_to_signal_reciever(bus, factory, event_handler, event_type):
any_data,
source_application,
source)
- return event_handler(event)
+ depth = gobject.main_depth()
+ r = registry.Registry()
+ if (r.asyncInternal() or depth <= 1):
+ return event_handler(event)
+ else:
+ r.enqueueEvent(event_handler, event)
return bus.add_signal_receiver(handler_wrapper, **kwargs)
diff --git a/pyatspi/application.py b/pyatspi/application.py
index 1b608da..aaa9b02 100644
--- a/pyatspi/application.py
+++ b/pyatspi/application.py
@@ -52,7 +52,7 @@ class Application(Accessible):
id = property(fget=get_id, doc=_idDoc)
def get_toolkitName(self):
- return dbus.String(self._pgetter(ATSPI_APPLICATION, "ToolkitName"))
+ return self.getConstantProperty(ATSPI_APPLICATION, "ToolkitName")
_toolkitNameDoc = \
"""
A string indicating the type of user interface toolkit which
diff --git a/pyatspi/cache.py b/pyatspi/cache.py
index 1c2a683..a110948 100644
--- a/pyatspi/cache.py
+++ b/pyatspi/cache.py
@@ -14,6 +14,8 @@
import os
import dbus
+import registry
+import traceback # tmp. for dbg.
from interfaces import *
from role import ROLE_UNKNOWN
@@ -42,6 +44,7 @@ class _CacheData(object):
'name',
'description',
'state',
+ 'toolkitName', # TODO; do this differently
]
def __init__(self, data):
@@ -126,6 +129,7 @@ class DesktopCacheManager (object):
if interface==_ATSPI_EVENT_OBJECT_INTERFACE and sender == self._unique_name and path == ATSPI_ROOT_PATH:
if minor == "add":
bus_name, object_path = any_data
+ r = registry.Registry()
self._application_list[bus_name] = ApplicationCacheManager(self._cache, bus_name)
elif minor == "remove":
bus_name, object_path = any_data
@@ -163,7 +167,10 @@ class ApplicationCacheManager (object):
cache_obj = bus.get_object (bus_name, _ATSPI_CACHE_PATH, introspect=False)
cache_itf = dbus.Interface (cache_obj, _ATSPI_CACHE_INTERFACE)
+ r = registry.Registry()
+ r.freezeEvents()
self._add_objects(cache_itf.GetItems())
+ r.thawEvents()
self._property_change = \
bus.add_signal_receiver(self._property_change_handler,
@@ -207,7 +214,10 @@ class ApplicationCacheManager (object):
def _remove_object(self, reference):
bus_name, object_path = reference
- del(self._cache[(bus_name, object_path)])
+ try:
+ del(self._cache[(bus_name, object_path)])
+ except KeyError:
+ pass
def _add_objects (self, objects):
for data in objects:
diff --git a/pyatspi/registry.py b/pyatspi/registry.py
index 7bb9bda..d252581 100644
--- a/pyatspi/registry.py
+++ b/pyatspi/registry.py
@@ -23,6 +23,8 @@
import dbus
import os as _os
+import Queue
+import traceback
from busutils import *
@@ -80,6 +82,12 @@ class Registry(object):
def __init__(self):
self.__dict__ = self.__shared_state
+ try:
+ if (self.has_implementations):
+ return
+ except (AttributeError):
+ pass
+
self.has_implementations = False
self.device_event_register = None
@@ -116,6 +124,8 @@ class Registry(object):
@param app_name: D-Bus name of the application to connect to when not using the registry daemon.
"""
+ self.queue = Queue.Queue()
+ self.frozen = 0
# Set up the cache
cache = None
@@ -163,6 +173,7 @@ class Registry(object):
"""
if not self.has_implementations:
self._set_default_registry ()
+ self.async = True # not fully supported yet
try:
self.main_loop.run()
except KeyboardInterrupt:
@@ -322,17 +333,46 @@ class Registry(object):
# -------------------------------------------------------------------------------
+ def enqueueEvent (self, handler, event):
+ """
+ Queue an event for later delivery.
+ """
+ self.queue.put((handler, event))
+
def pumpQueuedEvents (self):
"""
- No Longer needed all application events are asyncronous.
+ Dispatch events that have been queued.
"""
- pass
+ while (not(self.queue.empty())):
+ (handler, event) = self.queue.get()
+ handler(event)
def flushEvents (self):
"""
- No Longer needed all application events are asyncronous.
+ Empty the event queue.
+ """
+ self.queue = Queue.QUeue()
+
+ def asyncInternal (self):
+ """
+ Tests whether events should currently be delivered
+ asynchronously
+ """
+ return self.async and not(self.frozen)
+
+ def freezeEvents (self):
+ """
+ Temporarily stop delivering events, queueing them until thaw() is called
+ """
+ self.frozen = self.frozen + 1
+
+ def thawEvents (self):
+ """
+ Start delivering events again
"""
- pass
+ self.frozen = self.frozen - 1
+ if (self.frozen == 0):
+ self.pumpQueuedEvents ()
# -------------------------------------------------------------------------------
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]