1 #Copyright (C) 2008 Codethink Ltd
3 #This library is free software; you can redistribute it and/or
4 #modify it under the terms of the GNU Lesser General Public
5 #License version 2 as published by the Free Software Foundation.
7 #This program is distributed in the hope that it will be useful,
8 #but WITHOUT ANY WARRANTY; without even the implied warranty of
9 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 #GNU General Public License for more details.
11 #You should have received a copy of the GNU Lesser General Public License
12 #along with this program; if not, write to the Free Software
13 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 from factory import create_accessible, add_accessible_class
17 from accessible import BoundingBox
22 "event_type_to_signal_reciever",
25 #------------------------------------------------------------------------------
27 _interface_to_klass = {
28 "org.freedesktop.atspi.Event.Object":"object",
29 "org.freedesktop.atspi.Event.Window":"window",
30 "org.freedesktop.atspi.Event.Mouse":"mouse",
31 "org.freedesktop.atspi.Event.Terminal":"terminal",
32 "org.freedesktop.atspi.Event.Document":"document",
33 "org.freedesktop.atspi.Event.Focus":"focus",
36 _klass_to_interface = {
37 "object":"org.freedesktop.atspi.Event.Object",
38 "window":"org.freedesktop.atspi.Event.Window",
39 "mouse":"org.freedesktop.atspi.Event.Mouse",
40 "terminal":"org.freedesktop.atspi.Event.Terminal",
41 "document":"org.freedesktop.atspi.Event.Document",
42 "focus":"org.freedesktop.atspi.Event.Focus",
45 #------------------------------------------------------------------------------
47 class _ELessList(list):
48 def __getitem__(self, index):
50 return list.__getitem__(self, index)
56 Wraps the AT-SPI event type string so its components can be accessed
57 individually as klass (can't use the keyword class), major, minor, and detail
58 (klass_major_minor_detail).
60 @note: All attributes of an instance of this class should be considered
61 public readable as it is acting a a struct.
62 @ivar klass: Most general event type identifier (object, window, mouse, etc.)
64 @ivar major: Second level event type description
66 @ivar minor: Third level event type description
68 @ivar detail: Lowest level event type description
70 @ivar name: Full, unparsed event name as received from AT-SPI
72 @cvar format: Names of the event string components
73 @type format: 4-tuple of string
78 def __init__(self, name):
80 Parses the full AT-SPI event name into its components
81 (klass:major:minor:detail). If the provided event name is an integer
82 instead of a string, then the event is really a device event.
84 @param name: Full AT-SPI event name
86 @raise AttributeError: When the given event name is not a valid string
88 stripped = name.strip(self._SEPARATOR)
89 separated = stripped.split(self._SEPARATOR, 3)
90 self._separated = _ELessList(separated)
92 self.klass = self._separated[0]
93 self.major = self._separated[1]
94 self.minor = self._separated[2]
95 self.detail = self._separated[3]
97 self._name = ":".join(separated)
99 def is_subtype(self, event_type):
101 Determines if the passed event type is a subtype
104 if event_type.klass and event_type.klass != self.klass:
107 if event_type.major and event_type.major != self.major:
110 if event_type.minor and event_type.minor != self.minor:
122 #------------------------------------------------------------------------------
124 def event_type_to_signal_reciever(bus, cache, event_handler, event_type):
126 'sender_keyword':'sender',
127 'interface_keyword':'interface',
128 'member_keyword':'member',
129 'path_keyword':'path',
132 major = event_type.major.replace('-', '_')
134 kwargs['dbus_interface'] = _klass_to_interface[event_type.klass]
136 kwargs['signal_name'] = major
138 kwargs['arg0'] = event_type.minor
140 def handler_wrapper(minor, detail1, detail2, any_data,
141 sender=None, interface=None, member=None, path=None):
142 event = Event(cache, path, sender, interface, member, (minor, detail1, detail2, any_data))
143 return event_handler(event)
145 return bus.add_signal_receiver(handler_wrapper, **kwargs)
147 #------------------------------------------------------------------------------
151 Wraps an AT-SPI event with a more Pythonic interface managing exceptions,
152 the differences in any_data across versions, and the reference counting of
153 accessibles provided with the event.
155 @note: All unmarked attributes of this class should be considered public
156 readable and writable as the class is acting as a record object.
158 @ivar type: The type of the AT-SPI event
159 @type type: L{EventType}
160 @ivar detail1: First AT-SPI event parameter
161 @type detail1: integer
162 @ivar detail2: Second AT-SPI event parameter
163 @type detail2: integer
164 @ivar any_data: Extra AT-SPI data payload
165 @type any_data: object
166 @ivar host_application: Application owning the event source
167 @type host_application: Accessibility.Application
168 @ivar source_name: Name of the event source at the time of event dispatch
169 @type source_name: string
170 @ivar source_role: Role of the event source at the time of event dispatch
171 @type source_role: Accessibility.Role
172 @ivar source: Source of the event
173 @type source: Accessibility.Accessible
175 def __init__(self, cache, source_path, source_application, interface, name, event):
177 Extracts information from the provided event. If the event is a "normal"
178 event, pulls the detail1, detail2, any_data, and source values out of the
179 given object and stores it in this object. If the event is a device event,
180 key ID is stored in detail1, scan code is stored in detail2, key name,
181 key modifiers (e.g. ALT, CTRL, etc.), is text flag, and timestamp are
182 stored as a 4-tuple in any_data, and source is None (since key events are
185 @param event: Event from an AT-SPI callback
186 @type event: Accessibility.Event or Accessibility.DeviceEvent
189 self._source_path = source_path
190 self._source_application = source_application
193 self._application = None
195 self._klass = _interface_to_klass[interface]
196 # The replace is neccessary as '-' not legal as signal name
197 # so translated on the server side.
198 self._major = name.replace('_', '-')
199 self._minor = event[0]
200 self.type = EventType(':'.join([self._klass, self._major, self._minor]))
201 self.detail1 = event[1]
202 self.detail2 = event[2]
205 if name == "object_bounds_changed":
206 self.any_data = BoundingBox(*data)
211 def host_application(self):
212 if not self._application:
213 application_root = self._cache[self._source_application]._get_root()
214 return create_accessible(self._cache,
215 self._source_application,
217 interfaces.ATSPI_APPLICATION,
218 connection=self._cache._connection)
219 return self._application
224 self._source = create_accessible(self._cache,
225 self._source_application,
227 interfaces.ATSPI_ACCESSIBLE,
228 connection=self._cache._connection)
232 def source_name(self):
236 def source_role(self):
237 return source.getRole()
241 Builds a human readable representation of the event including event type,
242 parameters, and source info.
244 @return: Event description
247 return '%s(%s, %s, %s)\n\tsource: %s\n\thost_application: %s' % \
248 (self.type, self.detail1, self.detail2, self.any_data,
249 self.source, self.host_application)
251 #END----------------------------------------------------------------------------