blob: 59e0e0c059f385b9ee4a528911ab5223128008bb [file] [log] [blame]
Guido van Rossum31559231995-02-05 16:59:27 +00001"""Tools for use in AppleEvent clients and servers.
2
3pack(x) converts a Python object to an AEDesc object
4unpack(desc) does the reverse
5
6packevent(event, parameters, attributes) sets params and attrs in an AEAppleEvent record
7unpackevent(event) returns the parameters and attributes from an AEAppleEvent record
8
9Plus... Lots of classes and routines that help representing AE objects,
10ranges, conditionals, logicals, etc., so you can write, e.g.:
11
12 x = Character(1, Document("foobar"))
13
14and pack(x) will create an AE object reference equivalent to AppleScript's
15
16 character 1 of document "foobar"
17
Jack Jansen40775ba1995-07-17 11:42:23 +000018Some of the stuff that appears to be exported from this module comes from other
19files: the pack stuff from aepack, the objects from aetypes.
20
Guido van Rossum31559231995-02-05 16:59:27 +000021"""
22
23
Guido van Rossum31559231995-02-05 16:59:27 +000024from types import *
Guido van Rossum17448e21995-01-30 11:53:55 +000025import AE
Jack Jansen40775ba1995-07-17 11:42:23 +000026import AppleEvents
Guido van Rossum17448e21995-01-30 11:53:55 +000027import MacOS
Jack Jansen20989e81998-01-16 14:40:10 +000028import sys
Guido van Rossum17448e21995-01-30 11:53:55 +000029
Jack Jansen40775ba1995-07-17 11:42:23 +000030from aetypes import *
31from aepack import pack, unpack, coerce, AEDescType
Guido van Rossum31559231995-02-05 16:59:27 +000032
Jack Jansenc46f56e1996-09-20 15:28:28 +000033Error = 'aetools.Error'
34
Guido van Rossum31559231995-02-05 16:59:27 +000035# Special code to unpack an AppleEvent (which is *not* a disguised record!)
Jack Jansen40775ba1995-07-17 11:42:23 +000036# Note by Jack: No??!? If I read the docs correctly it *is*....
Guido van Rossum31559231995-02-05 16:59:27 +000037
Guido van Rossum17448e21995-01-30 11:53:55 +000038aekeywords = [
39 'tran',
40 'rtid',
41 'evcl',
42 'evid',
43 'addr',
44 'optk',
45 'timo',
46 'inte', # this attribute is read only - will be set in AESend
47 'esrc', # this attribute is read only
48 'miss', # this attribute is read only
49 'from' # new in 1.0.1
50]
51
52def missed(ae):
53 try:
54 desc = ae.AEGetAttributeDesc('miss', 'keyw')
55 except AE.Error, msg:
56 return None
57 return desc.data
58
59def unpackevent(ae):
60 parameters = {}
61 while 1:
62 key = missed(ae)
63 if not key: break
64 parameters[key] = unpack(ae.AEGetParamDesc(key, '****'))
65 attributes = {}
66 for key in aekeywords:
67 try:
68 desc = ae.AEGetAttributeDesc(key, '****')
69 except (AE.Error, MacOS.Error), msg:
Jack Jansen20989e81998-01-16 14:40:10 +000070 if msg[0] != -1701 and msg[0] != -1704:
Guido van Rossum17448e21995-01-30 11:53:55 +000071 raise sys.exc_type, sys.exc_value
72 continue
73 attributes[key] = unpack(desc)
74 return parameters, attributes
75
76def packevent(ae, parameters = {}, attributes = {}):
77 for key, value in parameters.items():
78 ae.AEPutParamDesc(key, pack(value))
79 for key, value in attributes.items():
80 ae.AEPutAttributeDesc(key, pack(value))
81
Jack Jansen40775ba1995-07-17 11:42:23 +000082#
83# Support routine for automatically generated Suite interfaces
Jack Jansen84264771995-10-03 14:35:58 +000084# These routines are also useable for the reverse function.
Jack Jansen40775ba1995-07-17 11:42:23 +000085#
86def keysubst(arguments, keydict):
87 """Replace long name keys by their 4-char counterparts, and check"""
88 ok = keydict.values()
89 for k in arguments.keys():
90 if keydict.has_key(k):
91 v = arguments[k]
92 del arguments[k]
93 arguments[keydict[k]] = v
94 elif k != '----' and k not in ok:
95 raise TypeError, 'Unknown keyword argument: %s'%k
96
97def enumsubst(arguments, key, edict):
98 """Substitute a single enum keyword argument, if it occurs"""
99 if not arguments.has_key(key):
100 return
101 v = arguments[key]
102 ok = edict.values()
103 if edict.has_key(v):
104 arguments[key] = edict[v]
105 elif not v in ok:
106 raise TypeError, 'Unknown enumerator: %s'%v
107
108def decodeerror(arguments):
109 """Create the 'best' argument for a raise MacOS.Error"""
110 errn = arguments['errn']
Jack Jansen756a69f1997-08-08 15:00:03 +0000111 err_a1 = errn
Jack Jansen40775ba1995-07-17 11:42:23 +0000112 if arguments.has_key('errs'):
Jack Jansen756a69f1997-08-08 15:00:03 +0000113 err_a2 = arguments['errs']
114 else:
115 err_a2 = MacOS.GetErrorString(errn)
Jack Jansen40775ba1995-07-17 11:42:23 +0000116 if arguments.has_key('erob'):
Jack Jansen756a69f1997-08-08 15:00:03 +0000117 err_a3 = arguments['erob']
118 else:
119 err_a3 = None
120
121 return (err_a1, err_a2, err_a3)
Guido van Rossum31559231995-02-05 16:59:27 +0000122
Jack Jansen40775ba1995-07-17 11:42:23 +0000123class TalkTo:
124 """An AE connection to an application"""
125
Jack Jansen20989e81998-01-16 14:40:10 +0000126 def __init__(self, signature, start=0, timeout=0):
Jack Jansen40775ba1995-07-17 11:42:23 +0000127 """Create a communication channel with a particular application.
128
129 Addressing the application is done by specifying either a
130 4-byte signature, an AEDesc or an object that will __aepack__
131 to an AEDesc.
132 """
Jack Jansenc46f56e1996-09-20 15:28:28 +0000133 self.target_signature = None
Jack Jansen40775ba1995-07-17 11:42:23 +0000134 if type(signature) == AEDescType:
135 self.target = signature
136 elif type(signature) == InstanceType and hasattr(signature, '__aepack__'):
137 self.target = signature.__aepack__()
Jack Jansen7874b5d1995-07-29 15:31:10 +0000138 elif type(signature) == StringType and len(signature) == 4:
Jack Jansen40775ba1995-07-17 11:42:23 +0000139 self.target = AE.AECreateDesc(AppleEvents.typeApplSignature, signature)
Jack Jansenc46f56e1996-09-20 15:28:28 +0000140 self.target_signature = signature
Jack Jansen40775ba1995-07-17 11:42:23 +0000141 else:
142 raise TypeError, "signature should be 4-char string or AEDesc"
143 self.send_flags = AppleEvents.kAEWaitReply
144 self.send_priority = AppleEvents.kAENormalPriority
Jack Jansen20989e81998-01-16 14:40:10 +0000145 if timeout:
146 self.send_timeout = timeout
147 else:
148 self.send_timeout = AppleEvents.kAEDefaultTimeout
Jack Jansenc46f56e1996-09-20 15:28:28 +0000149 if start:
150 self.start()
151
152 def start(self):
153 """Start the application, if it is not running yet"""
Jack Jansen20989e81998-01-16 14:40:10 +0000154 self.send_flags = AppleEvents.kAENoReply
155 _launch(self.target_signature)
Jack Jansenc46f56e1996-09-20 15:28:28 +0000156
Jack Jansen40775ba1995-07-17 11:42:23 +0000157 def newevent(self, code, subcode, parameters = {}, attributes = {}):
158 """Create a complete structure for an apple event"""
159
160 event = AE.AECreateAppleEvent(code, subcode, self.target,
161 AppleEvents.kAutoGenerateReturnID, AppleEvents.kAnyTransactionID)
162 packevent(event, parameters, attributes)
163 return event
164
165 def sendevent(self, event):
166 """Send a pre-created appleevent, await the reply and unpack it"""
167
168 reply = event.AESend(self.send_flags, self.send_priority,
169 self.send_timeout)
170 parameters, attributes = unpackevent(reply)
171 return reply, parameters, attributes
172
173 def send(self, code, subcode, parameters = {}, attributes = {}):
174 """Send an appleevent given code/subcode/pars/attrs and unpack the reply"""
175 return self.sendevent(self.newevent(code, subcode, parameters, attributes))
176
Jack Jansen7e156a71996-01-29 15:45:09 +0000177 #
178 # The following events are somehow "standard" and don't seem to appear in any
179 # suite...
180 #
Jack Jansen40775ba1995-07-17 11:42:23 +0000181 def activate(self):
182 """Send 'activate' command"""
183 self.send('misc', 'actv')
Jack Jansen7e156a71996-01-29 15:45:09 +0000184
Jack Jansen756a69f1997-08-08 15:00:03 +0000185 def _get(self, _object, as=None, _attributes={}):
186 """_get: get data from an object
Jack Jansen7e156a71996-01-29 15:45:09 +0000187 Required argument: the object
188 Keyword argument _attributes: AppleEvent attribute dictionary
189 Returns: the data
190 """
191 _code = 'core'
192 _subcode = 'getd'
193
194 _arguments = {'----':_object}
Jack Jansen756a69f1997-08-08 15:00:03 +0000195 if as:
196 _arguments['rtyp'] = mktype(as)
Jack Jansen7e156a71996-01-29 15:45:09 +0000197
198 _reply, _arguments, _attributes = self.send(_code, _subcode,
199 _arguments, _attributes)
200 if _arguments.has_key('errn'):
Jack Jansenc46f56e1996-09-20 15:28:28 +0000201 raise Error, decodeerror(_arguments)
Jack Jansen7e156a71996-01-29 15:45:09 +0000202
203 if _arguments.has_key('----'):
204 return _arguments['----']
Jack Jansen20989e81998-01-16 14:40:10 +0000205
206# Tiny Finder class, for local use only
207
208class _miniFinder(TalkTo):
209 def open(self, _object, _attributes={}, **_arguments):
210 """open: Open the specified object(s)
211 Required argument: list of objects to open
212 Keyword argument _attributes: AppleEvent attribute dictionary
213 """
214 _code = 'aevt'
215 _subcode = 'odoc'
216
217 if _arguments: raise TypeError, 'No optional args expected'
218 _arguments['----'] = _object
219
220
221 _reply, _arguments, _attributes = self.send(_code, _subcode,
222 _arguments, _attributes)
223 if _arguments.has_key('errn'):
224 raise aetools.Error, aetools.decodeerror(_arguments)
225 # XXXX Optionally decode result
226 if _arguments.has_key('----'):
227 return _arguments['----']
228#pass
Jack Jansen40775ba1995-07-17 11:42:23 +0000229
Jack Jansen20989e81998-01-16 14:40:10 +0000230_finder = _miniFinder('MACS')
231
232def _launch(appfile):
233 """Open a file thru the finder. Specify file by name or fsspec"""
234 _finder.open(_application_file(('ID ', appfile)))
235
236
237class _application_file(ComponentItem):
238 """application file - An application's file on disk"""
239 want = 'appf'
240
241_application_file._propdict = {
242}
243_application_file._elemdict = {
244}
Jack Jansen40775ba1995-07-17 11:42:23 +0000245
Guido van Rossum31559231995-02-05 16:59:27 +0000246# Test program
Jack Jansen40775ba1995-07-17 11:42:23 +0000247# XXXX Should test more, really...
Guido van Rossum31559231995-02-05 16:59:27 +0000248
Guido van Rossum17448e21995-01-30 11:53:55 +0000249def test():
Jack Jansen20989e81998-01-16 14:40:10 +0000250 target = AE.AECreateDesc('sign', 'quil')
Guido van Rossum17448e21995-01-30 11:53:55 +0000251 ae = AE.AECreateAppleEvent('aevt', 'oapp', target, -1, 0)
252 print unpackevent(ae)
Guido van Rossum31559231995-02-05 16:59:27 +0000253 raw_input(":")
254 ae = AE.AECreateAppleEvent('core', 'getd', target, -1, 0)
255 obj = Character(2, Word(1, Document(1)))
256 print obj
257 print repr(obj)
258 packevent(ae, {'----': obj})
259 params, attrs = unpackevent(ae)
260 print params['----']
261 raw_input(":")
Guido van Rossum17448e21995-01-30 11:53:55 +0000262
263if __name__ == '__main__':
264 test()
Jack Jansen20989e81998-01-16 14:40:10 +0000265 sys.exit(1)