summaryrefslogtreecommitdiffstats
path: root/Lib/plat-mac/aetools.py
diff options
context:
space:
mode:
authorJack Jansen <jack.jansen@cwi.nl>2002-12-30 22:04:23 (GMT)
committerJack Jansen <jack.jansen@cwi.nl>2002-12-30 22:04:23 (GMT)
commit60087fb45092d9c199cea162e58d9193c7c1558c (patch)
tree05f3343e7707c4a4179e409506b39601279f04c1 /Lib/plat-mac/aetools.py
parentc262a1f51ce89dbea4aeb072cf631686c47ed97f (diff)
downloadcpython-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.py313
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)