[Pythonmac-SIG] AppleEvents and AEPutParamDesc
Phil Christensen
phil at bubblehouse.org
Tue Jul 26 05:38:30 CEST 2005
So I'm in the process of trying to implement the BBEdit ODB suite
functionality in a PyObjC app, and I've run into some weirdness, and
I hope someone here might be able to help me.
I've been hacking on the MiniAEFrame.py module that is distributed
with python, and I've had success receiving the BBEdit's response
(when a file is saved) through this script. All I did was add a call
to the following function, just before the call to the _Test()
constructor
def openInExternalEditor(_filePath, _lnnum=0, _editor = '/
Applications/BBEdit.app'):
from aem.send import Application
import struct
from Carbon.File import FSSpec
SelectionRange = struct.pack('hhllll', 0, int(_lnnum)-1,
1,1,0,0)
Application(_editor).event('aevtodoc',{'----':FSSpec
(_filePath),'kpos':SelectionRange}).send()
BBEdit opens the requested document, and when I save the file, this
event prints to the console:
AppleEvent ('R*ch', 'FMod') for <Carbon.File.Alias object at
0x3e2b0> Other args: {...
which is definitely what I want.
However, when I bring all this into my PyObjC app, I no longer seem
to receive events properly. Obviously, I had to make some changes,
since the MiniApplication class in the MiniAEFrame module also
implements event handling for menus, about boxes, etc, and this is
already taken care of by the PyObjC app. This is what my event loop
looks like now:
def eventLoop():
# we poll for apple events here
got, event = Evt.WaitNextEvent(Events.highLevelEventMask, 1)
if got:
print 'got: ' + str(got) + ' event: ' + str(event)
what, message, when, where, modifiers = event
if what == MiniAEFrame.kHighLevelEvent:
AE.AEProcessAppleEvent(event)
elif hasattr(MacOS, 'HandleEvent'):
MacOS.HandleEvent(event)
else:
print "Unhandled event:", event
# an instance of the twisted python threadedselectreactor
reactor.callLater(1, eventLoop)
The event registration is taken care of by a trial subclass of
MiniAEFrame.AEServer:
class EventServer(MiniAEFrame.AEServer):
def __init__(self):
MiniAEFrame.AEServer.__init__(self)
# these are more than necessary, but in an attempt to
# mimic MiniAEFrame as much as possible
self.installaehandler('aevt', 'oapp', self.other)
self.installaehandler('aevt', 'quit', self.other)
self.installaehandler('****', '****', self.other)
def other(self, _object=None, _class=None, _type=None, **args):
print 'AppleEvent', (_class, _type), 'for', _object,
'Other args:', args
However, now this gets various events (usually things like the 'rapp'
event when the app goes into the background, etc), but definitely
nothing from BBEdit. I thought perhaps it was because the ODB
specification says you should pass along a 'keyServerID' parameter to
the 'odoc' event that signifies a 4-byte char OSType. I wasn't sure
about how this works under OS X, but I set the 'CFBundleSignature'
property to 'Phil' in the .app bundle's Info.plist, and tried the
following when I sent the event:
def openInExternalEditor(_filePath, _lnnum=0, _editor = '/
Applications/BBEdit.app'):
from aem.send import Application
import struct
from Carbon.File import FSSpec
SelectionRange = struct.pack('hhllll', 0, int(_lnnum)-1,
1,1,0,0)
Application(_editor).event('aevtodoc',{'----':FSSpec
(_filePath),
'kpos':SelectionRange, 'keyServerID':'Phil'}).send()
but this constantly generates the following error:
Traceback (most recent call last):
[snipped cocoa-related garbage]
File "/Users/phil/Workspace/InnerSpace/cocoa/client/dist/
controller.app/Contents/Resources/__boot__.py", line 47, in _run
execfile(path, globals(), globals())
File "/Users/phil/Workspace/InnerSpace/cocoa/client/
controller.py", line 167, in ?
openInExternalEditor('/tmp/test-12345')
File "/Users/phil/Workspace/InnerSpace/cocoa/client/
controller.py", line 162, in openInExternalEditor
Application(_editor).event('aevtodoc',{'----':FSSpec
(_filePath),'kpos':SelectionRange, 'keyServerID':'Phil'}).send()
File "/Library/Frameworks/Python.framework/Versions/2.4/lib/
python2.4/site-packages/aem/send/__init__.py", line 83, in event
return self._Event(self._address, event, params, atts,
resulttype, self._transaction, returnid, self._codecs)
File "/Library/Frameworks/Python.framework/Versions/2.4/lib/
python2.4/site-packages/aem/send/send.py", line 87, in __init__
self._event.AEPutParamDesc(key, codecs.pack(value))
TypeError: OSType arg must be string of 4 chars
I've tried everything at this point to get it to accept 'Phil', such
as converting it to an int, or packing it into a 4-byte struct, but
to no avail. In reality, that shouldn't even be necessary, as I
grepped the Python source tree, and found that the only function that
generates a TypeError with that string is in mactoolboxglue.c, and it
should accept the string 'Phil':
/* Convert a 4-char string object argument to an OSType value */
int
PyMac_GetOSType(PyObject *v, OSType *pr)
{
if (!PyString_Check(v) || PyString_Size(v) != 4) {
PyErr_SetString(PyExc_TypeError,
"OSType arg must be string of 4 chars");
return 0;
}
memcpy((char *)pr, PyString_AsString(v), 4);
return 1;
}
At any rate, sorry this email is so long, but any help would be
appreciated. It'd be really great to get this external editor feature
working...
Incidentally, here are some relevant links:
ODB Suite:
http://www.barebones.com/support/develop/odbsuite.shtml
MiniAEFrame.py:
http://cvs.sourceforge.net/viewcvs.py/python/python/dist/src/Lib/
plat-mac/MiniAEFrame.py?rev=1.5&view=log
Thanks in advance,
-phil christensen
More information about the Pythonmac-SIG
mailing list