diff options
author | Jack Jansen <jack.jansen@cwi.nl> | 2002-12-30 22:04:23 (GMT) |
---|---|---|
committer | Jack Jansen <jack.jansen@cwi.nl> | 2002-12-30 22:04:23 (GMT) |
commit | 60087fb45092d9c199cea162e58d9193c7c1558c (patch) | |
tree | 05f3343e7707c4a4179e409506b39601279f04c1 /Lib/plat-mac/aetools.py | |
parent | c262a1f51ce89dbea4aeb072cf631686c47ed97f (diff) | |
download | cpython-60087fb45092d9c199cea162e58d9193c7c1558c.zip cpython-60087fb45092d9c199cea162e58d9193c7c1558c.tar.gz cpython-60087fb45092d9c199cea162e58d9193c7c1558c.tar.bz2 |
Moved most of Mac/Lib hierarchy to Lib/plat-mac: it can be used both
in MacPython-OS9 and MacPython-OSX (or the equivalent unix Python on
Mac OS X). The only items remaining in Mac/Lib are modules that are
meaningful only for MacPython-OS9 (CFM stuff, MacPython preferences
in resources, etc).
Diffstat (limited to 'Lib/plat-mac/aetools.py')
-rw-r--r-- | Lib/plat-mac/aetools.py | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/Lib/plat-mac/aetools.py b/Lib/plat-mac/aetools.py new file mode 100644 index 0000000..8d9657e --- /dev/null +++ b/Lib/plat-mac/aetools.py @@ -0,0 +1,313 @@ +"""Tools for use in AppleEvent clients and servers. + +pack(x) converts a Python object to an AEDesc object +unpack(desc) does the reverse + +packevent(event, parameters, attributes) sets params and attrs in an AEAppleEvent record +unpackevent(event) returns the parameters and attributes from an AEAppleEvent record + +Plus... Lots of classes and routines that help representing AE objects, +ranges, conditionals, logicals, etc., so you can write, e.g.: + + x = Character(1, Document("foobar")) + +and pack(x) will create an AE object reference equivalent to AppleScript's + + character 1 of document "foobar" + +Some of the stuff that appears to be exported from this module comes from other +files: the pack stuff from aepack, the objects from aetypes. + +""" + + +from types import * +from Carbon import AE +from Carbon import AppleEvents +import MacOS +import sys + +from aetypes import * +from aepack import packkey, pack, unpack, coerce, AEDescType + +Error = 'aetools.Error' + +# Special code to unpack an AppleEvent (which is *not* a disguised record!) +# Note by Jack: No??!? If I read the docs correctly it *is*.... + +aekeywords = [ + 'tran', + 'rtid', + 'evcl', + 'evid', + 'addr', + 'optk', + 'timo', + 'inte', # this attribute is read only - will be set in AESend + 'esrc', # this attribute is read only + 'miss', # this attribute is read only + 'from' # new in 1.0.1 +] + +def missed(ae): + try: + desc = ae.AEGetAttributeDesc('miss', 'keyw') + except AE.Error, msg: + return None + return desc.data + +def unpackevent(ae, formodulename=""): + parameters = {} + try: + dirobj = ae.AEGetParamDesc('----', '****') + except AE.Error: + pass + else: + parameters['----'] = unpack(dirobj, formodulename) + del dirobj + # Workaround for what I feel is a bug in OSX 10.2: 'errn' won't show up in missed... + try: + dirobj = ae.AEGetParamDesc('errn', '****') + except AE.Error: + pass + else: + parameters['errn'] = unpack(dirobj, formodulename) + del dirobj + while 1: + key = missed(ae) + if not key: break + parameters[key] = unpack(ae.AEGetParamDesc(key, '****'), formodulename) + attributes = {} + for key in aekeywords: + try: + desc = ae.AEGetAttributeDesc(key, '****') + except (AE.Error, MacOS.Error), msg: + if msg[0] != -1701 and msg[0] != -1704: + raise sys.exc_type, sys.exc_value + continue + attributes[key] = unpack(desc, formodulename) + return parameters, attributes + +def packevent(ae, parameters = {}, attributes = {}): + for key, value in parameters.items(): + packkey(ae, key, value) + for key, value in attributes.items(): + packkey(ae, key, value) + +# +# Support routine for automatically generated Suite interfaces +# These routines are also useable for the reverse function. +# +def keysubst(arguments, keydict): + """Replace long name keys by their 4-char counterparts, and check""" + ok = keydict.values() + for k in arguments.keys(): + if keydict.has_key(k): + v = arguments[k] + del arguments[k] + arguments[keydict[k]] = v + elif k != '----' and k not in ok: + raise TypeError, 'Unknown keyword argument: %s'%k + +def enumsubst(arguments, key, edict): + """Substitute a single enum keyword argument, if it occurs""" + if not arguments.has_key(key) or edict is None: + return + v = arguments[key] + ok = edict.values() + if edict.has_key(v): + arguments[key] = edict[v] + elif not v in ok: + raise TypeError, 'Unknown enumerator: %s'%v + +def decodeerror(arguments): + """Create the 'best' argument for a raise MacOS.Error""" + errn = arguments['errn'] + err_a1 = errn + if arguments.has_key('errs'): + err_a2 = arguments['errs'] + else: + err_a2 = MacOS.GetErrorString(errn) + if arguments.has_key('erob'): + err_a3 = arguments['erob'] + else: + err_a3 = None + + return (err_a1, err_a2, err_a3) + +class TalkTo: + """An AE connection to an application""" + _signature = None # Can be overridden by subclasses + _moduleName = None # Can be overridden by subclasses + + def __init__(self, signature=None, start=0, timeout=0): + """Create a communication channel with a particular application. + + Addressing the application is done by specifying either a + 4-byte signature, an AEDesc or an object that will __aepack__ + to an AEDesc. + """ + self.target_signature = None + if signature is None: + signature = self._signature + if type(signature) == AEDescType: + self.target = signature + elif type(signature) == InstanceType and hasattr(signature, '__aepack__'): + self.target = signature.__aepack__() + elif type(signature) == StringType and len(signature) == 4: + self.target = AE.AECreateDesc(AppleEvents.typeApplSignature, signature) + self.target_signature = signature + else: + raise TypeError, "signature should be 4-char string or AEDesc" + self.send_flags = AppleEvents.kAEWaitReply + self.send_priority = AppleEvents.kAENormalPriority + if timeout: + self.send_timeout = timeout + else: + self.send_timeout = AppleEvents.kAEDefaultTimeout + if start: + self._start() + + def _start(self): + """Start the application, if it is not running yet""" + try: + self.send('ascr', 'noop') + except AE.Error: + _launch(self.target_signature) + + def start(self): + """Deprecated, used _start()""" + self._start() + + def newevent(self, code, subcode, parameters = {}, attributes = {}): + """Create a complete structure for an apple event""" + + event = AE.AECreateAppleEvent(code, subcode, self.target, + AppleEvents.kAutoGenerateReturnID, AppleEvents.kAnyTransactionID) + packevent(event, parameters, attributes) + return event + + def sendevent(self, event): + """Send a pre-created appleevent, await the reply and unpack it""" + + reply = event.AESend(self.send_flags, self.send_priority, + self.send_timeout) + parameters, attributes = unpackevent(reply, self._moduleName) + return reply, parameters, attributes + + def send(self, code, subcode, parameters = {}, attributes = {}): + """Send an appleevent given code/subcode/pars/attrs and unpack the reply""" + return self.sendevent(self.newevent(code, subcode, parameters, attributes)) + + # + # The following events are somehow "standard" and don't seem to appear in any + # suite... + # + def activate(self): + """Send 'activate' command""" + self.send('misc', 'actv') + + def _get(self, _object, as=None, _attributes={}): + """_get: get data from an object + Required argument: the object + Keyword argument _attributes: AppleEvent attribute dictionary + Returns: the data + """ + _code = 'core' + _subcode = 'getd' + + _arguments = {'----':_object} + if as: + _arguments['rtyp'] = mktype(as) + + _reply, _arguments, _attributes = self.send(_code, _subcode, + _arguments, _attributes) + if _arguments.has_key('errn'): + raise Error, decodeerror(_arguments) + + if _arguments.has_key('----'): + return _arguments['----'] + if as: + item.__class__ = as + return item + + def _set(self, _object, _arguments = {}, _attributes = {}): + """ _set: set data for an object + Required argument: the object + Keyword argument _parameters: Parameter dictionary for the set operation + Keyword argument _attributes: AppleEvent attribute dictionary + Returns: the data + """ + _code = 'core' + _subcode = 'setd' + + _arguments['----'] = _object + + _reply, _arguments, _attributes = self.send(_code, _subcode, + _arguments, _attributes) + if _arguments.has_key('errn'): + raise Error, decodeerror(_arguments) + + if _arguments.has_key('----'): + return _arguments['----'] + +# Tiny Finder class, for local use only + +class _miniFinder(TalkTo): + def open(self, _object, _attributes={}, **_arguments): + """open: Open the specified object(s) + Required argument: list of objects to open + Keyword argument _attributes: AppleEvent attribute dictionary + """ + _code = 'aevt' + _subcode = 'odoc' + + if _arguments: raise TypeError, 'No optional args expected' + _arguments['----'] = _object + + + _reply, _arguments, _attributes = self.send(_code, _subcode, + _arguments, _attributes) + if _arguments.has_key('errn'): + raise Error, decodeerror(_arguments) + # XXXX Optionally decode result + if _arguments.has_key('----'): + return _arguments['----'] +#pass + +_finder = _miniFinder('MACS') + +def _launch(appfile): + """Open a file thru the finder. Specify file by name or fsspec""" + _finder.open(_application_file(('ID ', appfile))) + + +class _application_file(ComponentItem): + """application file - An application's file on disk""" + want = 'appf' + +_application_file._propdict = { +} +_application_file._elemdict = { +} + +# Test program +# XXXX Should test more, really... + +def test(): + target = AE.AECreateDesc('sign', 'quil') + ae = AE.AECreateAppleEvent('aevt', 'oapp', target, -1, 0) + print unpackevent(ae) + raw_input(":") + ae = AE.AECreateAppleEvent('core', 'getd', target, -1, 0) + obj = Character(2, Word(1, Document(1))) + print obj + print repr(obj) + packevent(ae, {'----': obj}) + params, attrs = unpackevent(ae) + print params['----'] + raw_input(":") + +if __name__ == '__main__': + test() + sys.exit(1) |