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 kwargs['dbus_interface'] = _klass_to_interface[event_type.klass]
134 kwargs['signal_name'] = event_type.major
136 kwargs['arg0'] = event_type.minor
138 def handler_wrapper(minor, detail1, detail2, any_data,
139 sender=None, interface=None, member=None, path=None):
140 event = Event(cache, path, sender, interface, member, (minor, detail1, detail2, any_data))
141 return event_handler(event)
143 return bus.add_signal_receiver(handler_wrapper, **kwargs)
145 #------------------------------------------------------------------------------
149 Wraps an AT-SPI event with a more Pythonic interface managing exceptions,
150 the differences in any_data across versions, and the reference counting of
151 accessibles provided with the event.
153 @note: All unmarked attributes of this class should be considered public
154 readable and writable as the class is acting as a record object.
156 @ivar type: The type of the AT-SPI event
157 @type type: L{EventType}
158 @ivar detail1: First AT-SPI event parameter
159 @type detail1: integer
160 @ivar detail2: Second AT-SPI event parameter
161 @type detail2: integer
162 @ivar any_data: Extra AT-SPI data payload
163 @type any_data: object
164 @ivar host_application: Application owning the event source
165 @type host_application: Accessibility.Application
166 @ivar source_name: Name of the event source at the time of event dispatch
167 @type source_name: string
168 @ivar source_role: Role of the event source at the time of event dispatch
169 @type source_role: Accessibility.Role
170 @ivar source: Source of the event
171 @type source: Accessibility.Accessible
173 def __init__(self, cache, source_path, source_application, interface, name, event):
175 Extracts information from the provided event. If the event is a "normal"
176 event, pulls the detail1, detail2, any_data, and source values out of the
177 given object and stores it in this object. If the event is a device event,
178 key ID is stored in detail1, scan code is stored in detail2, key name,
179 key modifiers (e.g. ALT, CTRL, etc.), is text flag, and timestamp are
180 stored as a 4-tuple in any_data, and source is None (since key events are
183 @param event: Event from an AT-SPI callback
184 @type event: Accessibility.Event or Accessibility.DeviceEvent
187 self._source_path = source_path
188 self._source_application = source_application
191 self._application = None
193 self._klass = _interface_to_klass[interface]
194 # The replace is neccessary as '-' not legal as signal name
195 # so translated on the server side.
196 self._major = name.replace('_', '-')
197 self._minor = event[0]
198 self.type = EventType(':'.join([self._klass, self._major, self._minor]))
199 self.detail1 = event[1]
200 self.detail2 = event[2]
203 if name == "object_bounds_changed":
204 self.any_data = BoundingBox(*data)
209 def host_application(self):
210 if not self._application:
211 application_root = self._cache[self._source_application]._get_root()
212 return create_accessible(self._cache,
213 self._source_application,
215 interfaces.ATSPI_APPLICATION,
216 connection=self._cache._connection)
217 return self._application
222 self._source = create_accessible(self._cache,
223 self._source_application,
225 interfaces.ATSPI_ACCESSIBLE,
226 connection=self._cache._connection)
230 def source_name(self):
234 def source_role(self):
235 return source.getRole()
239 Builds a human readable representation of the event including event type,
240 parameters, and source info.
242 @return: Event description
245 return '%s(%s, %s, %s)\n\tsource: %s\n\thost_application: %s' % \
246 (self.type, self.detail1, self.detail2, self.any_data,
247 self.source, self.host_application)
249 #END----------------------------------------------------------------------------