[Stackless-checkins] CVS: slpdev/src/2.2/src/Lib/plat-mac Audio_mac.py, NONE, 1.1 EasyDialogs.py, NONE, 1.1 FrameWork.py, NONE, 1.1 MiniAEFrame.py, NONE, 1.1 PixMapWrapper.py, NONE, 1.1 WASTEconst.py, NONE, 1.1 aepack.py, NONE, 1.1 aetools.py, NONE, 1.1 aetypes.py, NONE, 1.1 applesingle.py, NONE, 1.1 appletrawmain.py, NONE, 1.1 appletrunner.py, NONE, 1.1 argvemulator.py, NONE, 1.1 bgenlocations.py, NONE, 1.1 buildtools.py, NONE, 1.1 bundlebuilder.py, NONE, 1.1 cfmfile.py, NONE, 1.1 dialogs.rsrc, NONE, 1.1 errors.rsrc, NONE, 1.1 findertools.py, NONE, 1.1 gensuitemodule.py, NONE, 1.1 ic.py, NONE, 1.1 icopen.py, NONE, 1.1 macerrors.py, NONE, 1.1 macfs.py, NONE, 1.1 macostools.py, NONE, 1.1 macresource.py, NONE, 1.1 pimp.py, NONE, 1.1 plistlib.py, NONE, 1.1 terminalcommand.py, NONE, 1.1 videoreader.py, NONE, 1.1

Christian Tismer tismer at centera.de
Sat May 1 02:54:14 CEST 2004


Update of /home/cvs/slpdev/src/2.2/src/Lib/plat-mac
In directory centera.de:/home/tismer/slpdev/src/2.2/src/Lib/plat-mac

Added Files:
	Audio_mac.py EasyDialogs.py FrameWork.py MiniAEFrame.py 
	PixMapWrapper.py WASTEconst.py aepack.py aetools.py aetypes.py 
	applesingle.py appletrawmain.py appletrunner.py 
	argvemulator.py bgenlocations.py buildtools.py 
	bundlebuilder.py cfmfile.py dialogs.rsrc errors.rsrc 
	findertools.py gensuitemodule.py ic.py icopen.py macerrors.py 
	macfs.py macostools.py macresource.py pimp.py plistlib.py 
	terminalcommand.py videoreader.py 
Log Message:
added files

--- NEW FILE: Audio_mac.py ---
QSIZE = 100000
error='Audio_mac.error'

class Play_Audio_mac:

    def __init__(self, qsize=QSIZE):
        self._chan = None
        self._qsize = qsize
        self._outrate = 22254
        self._sampwidth = 1
        self._nchannels = 1
        self._gc = []
        self._usercallback = None

    def __del__(self):
        self.stop()
        self._usercallback = None

    def wait(self):
        import time
        while self.getfilled():
            time.sleep(0.1)
        self._chan = None
        self._gc = []

    def stop(self, quietNow = 1):
        ##chan = self._chan
        self._chan = None
        ##chan.SndDisposeChannel(1)
        self._gc = []

    def setoutrate(self, outrate):
        self._outrate = outrate

    def setsampwidth(self, sampwidth):
        self._sampwidth = sampwidth

    def setnchannels(self, nchannels):
        self._nchannels = nchannels

    def writeframes(self, data):
        import time
        from Carbon.Sound import bufferCmd, callBackCmd, extSH
        import struct
        import MacOS
        if not self._chan:
            from Carbon import Snd
            self._chan = Snd.SndNewChannel(5, 0, self._callback)
        nframes = len(data) / self._nchannels / self._sampwidth
        if len(data) != nframes * self._nchannels * self._sampwidth:
            raise error, 'data is not a whole number of frames'
        while self._gc and \
              self.getfilled() + nframes > \
                self._qsize / self._nchannels / self._sampwidth:
            time.sleep(0.1)
        if self._sampwidth == 1:
            import audioop
            data = audioop.add(data, '\x80'*len(data), 1)
        h1 = struct.pack('llHhllbbl',
            id(data)+MacOS.string_id_to_buffer,
            self._nchannels,
            self._outrate, 0,
            0,
            0,
            extSH,
            60,
            nframes)
        h2 = 22*'\0'
        h3 = struct.pack('hhlll',
            self._sampwidth*8,
            0,
            0,
            0,
            0)
        header = h1+h2+h3
        self._gc.append((header, data))
        self._chan.SndDoCommand((bufferCmd, 0, header), 0)
        self._chan.SndDoCommand((callBackCmd, 0, 0), 0)

    def _callback(self, *args):
        del self._gc[0]
        if self._usercallback:
            self._usercallback()
            
    def setcallback(self, callback):
        self._usercallback = callback

    def getfilled(self):
        filled = 0
        for header, data in self._gc:
            filled = filled + len(data)
        return filled / self._nchannels / self._sampwidth

    def getfillable(self):
        return (self._qsize / self._nchannels / self._sampwidth) - self.getfilled()

    def ulaw2lin(self, data):
        import audioop
        return audioop.ulaw2lin(data, 2)

def test():
    import aifc
    import EasyDialogs
    fn = EasyDialogs.AskFileForOpen(message="Select an AIFF soundfile", typeList=("AIFF",))
    if not fn: return
    af = aifc.open(fn, 'r')
    print af.getparams()
    p = Play_Audio_mac()
    p.setoutrate(af.getframerate())
    p.setsampwidth(af.getsampwidth())
    p.setnchannels(af.getnchannels())
    BUFSIZ = 10000
    while 1:
        data = af.readframes(BUFSIZ)
        if not data: break
        p.writeframes(data)
        print 'wrote', len(data), 'space', p.getfillable()
    p.wait()

if __name__ == '__main__':
    test()

--- NEW FILE: EasyDialogs.py ---
"""Easy to use dialogs.

Message(msg) -- display a message and an OK button.
AskString(prompt, default) -- ask for a string, display OK and Cancel buttons.
AskPassword(prompt, default) -- like AskString(), but shows text as bullets.
AskYesNoCancel(question, default) -- display a question and Yes, No and Cancel buttons.
GetArgv(optionlist, commandlist) -- fill a sys.argv-like list using a dialog
AskFileForOpen(...) -- Ask the user for an existing file
AskFileForSave(...) -- Ask the user for an output file
AskFolder(...) -- Ask the user to select a folder
bar = Progress(label, maxvalue) -- Display a progress bar
bar.set(value) -- Set value
bar.inc( *amount ) -- increment value by amount (default=1)
bar.label( *newlabel ) -- get or set text label.

More documentation in each function.
This module uses DLOG resources 260 and on.
Based upon STDWIN dialogs with the same names and functions.
"""

from Carbon.Dlg import GetNewDialog, SetDialogItemText, GetDialogItemText, ModalDialog
from Carbon import Qd
from Carbon import QuickDraw
from Carbon import Dialogs
from Carbon import Windows
from Carbon import Dlg,Win,Evt,Events # sdm7g
from Carbon import Ctl
from Carbon import Controls
from Carbon import Menu
from Carbon import AE
import Nav
import MacOS
import string
from Carbon.ControlAccessor import *    # Also import Controls constants
import Carbon.File
import macresource
import os
import sys

__all__ = ['Message', 'AskString', 'AskPassword', 'AskYesNoCancel',
    'GetArgv', 'AskFileForOpen', 'AskFileForSave', 'AskFolder',
    'ProgressBar']

_initialized = 0

def _initialize():
    global _initialized
    if _initialized: return
    macresource.need("DLOG", 260, "dialogs.rsrc", __name__)

def _interact():
    """Make sure the application is in the foreground"""
    AE.AEInteractWithUser(50000000)

def cr2lf(text):
    if '\r' in text:
        text = string.join(string.split(text, '\r'), '\n')
    return text

def lf2cr(text):
    if '\n' in text:
        text = string.join(string.split(text, '\n'), '\r')
    if len(text) > 253:
        text = text[:253] + '\311'
    return text

def Message(msg, id=260, ok=None):
    """Display a MESSAGE string.

    Return when the user clicks the OK button or presses Return.

    The MESSAGE string can be at most 255 characters long.
    """
    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
    h = d.GetDialogItemAsControl(2)
    SetDialogItemText(h, lf2cr(msg))
    if ok != None:
        h = d.GetDialogItemAsControl(1)
        h.SetControlTitle(ok)
    d.SetDialogDefaultItem(1)
    d.AutoSizeDialog()
    d.GetDialogWindow().ShowWindow()
    while 1:
        n = ModalDialog(None)
        if n == 1:
            return


def AskString(prompt, default = "", id=261, ok=None, cancel=None):
    """Display a PROMPT string and a text entry field with a DEFAULT string.

    Return the contents of the text entry field when the user clicks the
    OK button or presses Return.
    Return None when the user clicks the Cancel button.

    If omitted, DEFAULT is empty.

    The PROMPT and DEFAULT strings, as well as the return value,
    can be at most 255 characters long.
    """

    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
    h = d.GetDialogItemAsControl(3)
    SetDialogItemText(h, lf2cr(prompt))
    h = d.GetDialogItemAsControl(4)
    SetDialogItemText(h, lf2cr(default))
    d.SelectDialogItemText(4, 0, 999)
#       d.SetDialogItem(4, 0, 255)
    if ok != None:
        h = d.GetDialogItemAsControl(1)
        h.SetControlTitle(ok)
    if cancel != None:
        h = d.GetDialogItemAsControl(2)
        h.SetControlTitle(cancel)
    d.SetDialogDefaultItem(1)
    d.SetDialogCancelItem(2)
    d.AutoSizeDialog()
    d.GetDialogWindow().ShowWindow()
    while 1:
        n = ModalDialog(None)
        if n == 1:
            h = d.GetDialogItemAsControl(4)
            return cr2lf(GetDialogItemText(h))
        if n == 2: return None

def AskPassword(prompt,  default='', id=264, ok=None, cancel=None):
    """Display a PROMPT string and a text entry field with a DEFAULT string.
    The string is displayed as bullets only.

    Return the contents of the text entry field when the user clicks the
    OK button or presses Return.
    Return None when the user clicks the Cancel button.

    If omitted, DEFAULT is empty.

    The PROMPT and DEFAULT strings, as well as the return value,
    can be at most 255 characters long.
    """
    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
    h = d.GetDialogItemAsControl(3)
    SetDialogItemText(h, lf2cr(prompt))
    pwd = d.GetDialogItemAsControl(4)
    bullets = '\245'*len(default)
##      SetControlData(pwd, kControlEditTextPart, kControlEditTextTextTag, bullets)
    SetControlData(pwd, kControlEditTextPart, kControlEditTextPasswordTag, default)
    d.SelectDialogItemText(4, 0, 999)
    Ctl.SetKeyboardFocus(d.GetDialogWindow(), pwd, kControlEditTextPart)
    if ok != None:
        h = d.GetDialogItemAsControl(1)
        h.SetControlTitle(ok)
    if cancel != None:
        h = d.GetDialogItemAsControl(2)
        h.SetControlTitle(cancel)
    d.SetDialogDefaultItem(Dialogs.ok)
    d.SetDialogCancelItem(Dialogs.cancel)
    d.AutoSizeDialog()
    d.GetDialogWindow().ShowWindow()
    while 1:
        n = ModalDialog(None)
        if n == 1:
            h = d.GetDialogItemAsControl(4)
            return cr2lf(GetControlData(pwd, kControlEditTextPart, kControlEditTextPasswordTag))
        if n == 2: return None

def AskYesNoCancel(question, default = 0, yes=None, no=None, cancel=None, id=262):
    """Display a QUESTION string which can be answered with Yes or No.

    Return 1 when the user clicks the Yes button.
    Return 0 when the user clicks the No button.
    Return -1 when the user clicks the Cancel button.

    When the user presses Return, the DEFAULT value is returned.
    If omitted, this is 0 (No).

    The QUESTION string can be at most 255 characters.
    """

    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
    # Button assignments:
    # 1 = default (invisible)
    # 2 = Yes
    # 3 = No
    # 4 = Cancel
    # The question string is item 5
    h = d.GetDialogItemAsControl(5)
    SetDialogItemText(h, lf2cr(question))
    if yes != None:
        if yes == '':
            d.HideDialogItem(2)
        else:
            h = d.GetDialogItemAsControl(2)
            h.SetControlTitle(yes)
    if no != None:
        if no == '':
            d.HideDialogItem(3)
        else:
            h = d.GetDialogItemAsControl(3)
            h.SetControlTitle(no)
    if cancel != None:
        if cancel == '':
            d.HideDialogItem(4)
        else:
            h = d.GetDialogItemAsControl(4)
            h.SetControlTitle(cancel)
    d.SetDialogCancelItem(4)
    if default == 1:
        d.SetDialogDefaultItem(2)
    elif default == 0:
        d.SetDialogDefaultItem(3)
    elif default == -1:
        d.SetDialogDefaultItem(4)
    d.AutoSizeDialog()
    d.GetDialogWindow().ShowWindow()
    while 1:
        n = ModalDialog(None)
        if n == 1: return default
        if n == 2: return 1
        if n == 3: return 0
        if n == 4: return -1




screenbounds = Qd.GetQDGlobalsScreenBits().bounds
screenbounds = screenbounds[0]+4, screenbounds[1]+4, \
    screenbounds[2]-4, screenbounds[3]-4

kControlProgressBarIndeterminateTag = 'inde'    # from Controls.py


class ProgressBar:
    def __init__(self, title="Working...", maxval=0, label="", id=263):
        self.w = None
        self.d = None
        _initialize()
        self.d = GetNewDialog(id, -1)
        self.w = self.d.GetDialogWindow()
        self.label(label)
        self.title(title)
        self.set(0, maxval)
        self.d.AutoSizeDialog()
        self.w.ShowWindow()
        self.d.DrawDialog()

    def __del__( self ):
        if self.w:
            self.w.BringToFront()
            self.w.HideWindow()
        del self.w
        del self.d

    def title(self, newstr=""):
        """title(text) - Set title of progress window"""
        self.w.BringToFront()
        self.w.SetWTitle(newstr)

    def label( self, *newstr ):
        """label(text) - Set text in progress box"""
        self.w.BringToFront()
        if newstr:
            self._label = lf2cr(newstr[0])
        text_h = self.d.GetDialogItemAsControl(2)
        SetDialogItemText(text_h, self._label)

    def _update(self, value):
        maxval = self.maxval
        if maxval == 0:     # an indeterminate bar
            Ctl.IdleControls(self.w)    # spin the barber pole
        else:               # a determinate bar
            if maxval > 32767:
                value = int(value/(maxval/32767.0))
                maxval = 32767
            maxval = int(maxval)
            value = int(value)
            progbar = self.d.GetDialogItemAsControl(3)
            progbar.SetControlMaximum(maxval)
            progbar.SetControlValue(value)  # set the bar length

        # Test for cancel button
        ready, ev = Evt.WaitNextEvent( Events.mDownMask, 1  )
        if ready :
            what,msg,when,where,mod = ev
            part = Win.FindWindow(where)[0]
            if Dlg.IsDialogEvent(ev):
                ds = Dlg.DialogSelect(ev)
                if ds[0] and ds[1] == self.d and ds[-1] == 1:
                    self.w.HideWindow()
                    self.w = None
                    self.d = None
                    raise KeyboardInterrupt, ev
            else:
                if part == 4:   # inDrag
                    self.w.DragWindow(where, screenbounds)
                else:
                    MacOS.HandleEvent(ev)


    def set(self, value, max=None):
        """set(value) - Set progress bar position"""
        if max != None:
            self.maxval = max
            bar = self.d.GetDialogItemAsControl(3)
            if max <= 0:    # indeterminate bar
                bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x01')
            else:           # determinate bar
                bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x00')
        if value < 0:
            value = 0
        elif value > self.maxval:
            value = self.maxval
        self.curval = value
        self._update(value)

    def inc(self, n=1):
        """inc(amt) - Increment progress bar position"""
        self.set(self.curval + n)

ARGV_ID=265
ARGV_ITEM_OK=1
ARGV_ITEM_CANCEL=2
ARGV_OPTION_GROUP=3
ARGV_OPTION_EXPLAIN=4
ARGV_OPTION_VALUE=5
ARGV_OPTION_ADD=6
ARGV_COMMAND_GROUP=7
ARGV_COMMAND_EXPLAIN=8
ARGV_COMMAND_ADD=9
ARGV_ADD_OLDFILE=10
ARGV_ADD_NEWFILE=11
ARGV_ADD_FOLDER=12
ARGV_CMDLINE_GROUP=13
ARGV_CMDLINE_DATA=14

##def _myModalDialog(d):
##      while 1:
##          ready, ev = Evt.WaitNextEvent(0xffff, -1)
##          print 'DBG: WNE', ready, ev
##          if ready :
##              what,msg,when,where,mod = ev
##              part, window = Win.FindWindow(where)
##              if Dlg.IsDialogEvent(ev):
##                  didit, dlgdone, itemdone = Dlg.DialogSelect(ev)
##                  print 'DBG: DialogSelect', didit, dlgdone, itemdone, d
##                  if didit and dlgdone == d:
##                      return itemdone
##              elif window == d.GetDialogWindow():
##                  d.GetDialogWindow().SelectWindow()
##                  if part == 4:   # inDrag
##                          d.DragWindow(where, screenbounds)
##                  else:
##                      MacOS.HandleEvent(ev)
##              else:
##                  MacOS.HandleEvent(ev)
##
def _setmenu(control, items):
        mhandle = control.GetControlData_Handle(Controls.kControlMenuPart,
                Controls.kControlPopupButtonMenuHandleTag)
        menu = Menu.as_Menu(mhandle)
        for item in items:
            if type(item) == type(()):
                label = item[0]
            else:
                label = item
            if label[-1] == '=' or label[-1] == ':':
                label = label[:-1]
            menu.AppendMenu(label)
##          mhandle, mid = menu.getpopupinfo()
##          control.SetControlData_Handle(Controls.kControlMenuPart,
##                  Controls.kControlPopupButtonMenuHandleTag, mhandle)
        control.SetControlMinimum(1)
        control.SetControlMaximum(len(items)+1)

def _selectoption(d, optionlist, idx):
    if idx < 0 or idx >= len(optionlist):
        MacOS.SysBeep()
        return
    option = optionlist[idx]
    if type(option) == type(()):
        if len(option) == 4:
            help = option[2]
        elif len(option) > 1:
            help = option[-1]
        else:
            help = ''
    else:
        help = ''
    h = d.GetDialogItemAsControl(ARGV_OPTION_EXPLAIN)
    if help and len(help) > 250:
        help = help[:250] + '...'
    Dlg.SetDialogItemText(h, help)
    hasvalue = 0
    if type(option) == type(()):
        label = option[0]
    else:
        label = option
    if label[-1] == '=' or label[-1] == ':':
        hasvalue = 1
    h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
    Dlg.SetDialogItemText(h, '')
    if hasvalue:
        d.ShowDialogItem(ARGV_OPTION_VALUE)
        d.SelectDialogItemText(ARGV_OPTION_VALUE, 0, 0)
    else:
        d.HideDialogItem(ARGV_OPTION_VALUE)


def GetArgv(optionlist=None, commandlist=None, addoldfile=1, addnewfile=1, addfolder=1, id=ARGV_ID):
    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
#       h = d.GetDialogItemAsControl(3)
#       SetDialogItemText(h, lf2cr(prompt))
#       h = d.GetDialogItemAsControl(4)
#       SetDialogItemText(h, lf2cr(default))
#       d.SelectDialogItemText(4, 0, 999)
#       d.SetDialogItem(4, 0, 255)
    if optionlist:
        _setmenu(d.GetDialogItemAsControl(ARGV_OPTION_GROUP), optionlist)
        _selectoption(d, optionlist, 0)
    else:
        d.GetDialogItemAsControl(ARGV_OPTION_GROUP).DeactivateControl()
    if commandlist:
        _setmenu(d.GetDialogItemAsControl(ARGV_COMMAND_GROUP), commandlist)
        if type(commandlist[0]) == type(()) and len(commandlist[0]) > 1:
            help = commandlist[0][-1]
            h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
            Dlg.SetDialogItemText(h, help)
    else:
        d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).DeactivateControl()
    if not addoldfile:
        d.GetDialogItemAsControl(ARGV_ADD_OLDFILE).DeactivateControl()
    if not addnewfile:
        d.GetDialogItemAsControl(ARGV_ADD_NEWFILE).DeactivateControl()
    if not addfolder:
        d.GetDialogItemAsControl(ARGV_ADD_FOLDER).DeactivateControl()
    d.SetDialogDefaultItem(ARGV_ITEM_OK)
    d.SetDialogCancelItem(ARGV_ITEM_CANCEL)
    d.GetDialogWindow().ShowWindow()
    d.DrawDialog()
    if hasattr(MacOS, 'SchedParams'):
        appsw = MacOS.SchedParams(1, 0)
    try:
        while 1:
            stringstoadd = []
            n = ModalDialog(None)
            if n == ARGV_ITEM_OK:
                break
            elif n == ARGV_ITEM_CANCEL:
                raise SystemExit
            elif n == ARGV_OPTION_GROUP:
                idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
                _selectoption(d, optionlist, idx)
            elif n == ARGV_OPTION_VALUE:
                pass
            elif n == ARGV_OPTION_ADD:
                idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
                if 0 <= idx < len(optionlist):
                    option = optionlist[idx]
                    if type(option) == type(()):
                        option = option[0]
                    if option[-1] == '=' or option[-1] == ':':
                        option = option[:-1]
                        h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
                        value = Dlg.GetDialogItemText(h)
                    else:
                        value = ''
                    if len(option) == 1:
                        stringtoadd = '-' + option
                    else:
                        stringtoadd = '--' + option
                    stringstoadd = [stringtoadd]
                    if value:
                        stringstoadd.append(value)
                else:
                    MacOS.SysBeep()
            elif n == ARGV_COMMAND_GROUP:
                idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
                if 0 <= idx < len(commandlist) and type(commandlist[idx]) == type(()) and \
                        len(commandlist[idx]) > 1:
                    help = commandlist[idx][-1]
                    h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
                    Dlg.SetDialogItemText(h, help)
            elif n == ARGV_COMMAND_ADD:
                idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
                if 0 <= idx < len(commandlist):
                    command = commandlist[idx]
                    if type(command) == type(()):
                        command = command[0]
                    stringstoadd = [command]
                else:
                    MacOS.SysBeep()
            elif n == ARGV_ADD_OLDFILE:
                pathname = AskFileForOpen()
                if pathname:
                    stringstoadd = [pathname]
            elif n == ARGV_ADD_NEWFILE:
                pathname = AskFileForSave()
                if pathname:
                    stringstoadd = [pathname]
            elif n == ARGV_ADD_FOLDER:
                pathname = AskFolder()
                if pathname:
                    stringstoadd = [pathname]
            elif n == ARGV_CMDLINE_DATA:
                pass # Nothing to do
            else:
                raise RuntimeError, "Unknown dialog item %d"%n

            for stringtoadd in stringstoadd:
                if '"' in stringtoadd or "'" in stringtoadd or " " in stringtoadd:
                    stringtoadd = repr(stringtoadd)
                h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
                oldstr = GetDialogItemText(h)
                if oldstr and oldstr[-1] != ' ':
                    oldstr = oldstr + ' '
                oldstr = oldstr + stringtoadd
                if oldstr[-1] != ' ':
                    oldstr = oldstr + ' '
                SetDialogItemText(h, oldstr)
                d.SelectDialogItemText(ARGV_CMDLINE_DATA, 0x7fff, 0x7fff)
        h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
        oldstr = GetDialogItemText(h)
        tmplist = string.split(oldstr)
        newlist = []
        while tmplist:
            item = tmplist[0]
            del tmplist[0]
            if item[0] == '"':
                while item[-1] != '"':
                    if not tmplist:
                        raise RuntimeError, "Unterminated quoted argument"
                    item = item + ' ' + tmplist[0]
                    del tmplist[0]
                item = item[1:-1]
            if item[0] == "'":
                while item[-1] != "'":
                    if not tmplist:
                        raise RuntimeError, "Unterminated quoted argument"
                    item = item + ' ' + tmplist[0]
                    del tmplist[0]
                item = item[1:-1]
            newlist.append(item)
        return newlist
    finally:
        if hasattr(MacOS, 'SchedParams'):
            MacOS.SchedParams(*appsw)
        del d

def _process_Nav_args(dftflags, **args):
    import aepack
    import Carbon.AE
    import Carbon.File
    for k in args.keys():
        if args[k] is None:
            del args[k]
    # Set some defaults, and modify some arguments
    if not args.has_key('dialogOptionFlags'):
        args['dialogOptionFlags'] = dftflags
    if args.has_key('defaultLocation') and \
            not isinstance(args['defaultLocation'], Carbon.AE.AEDesc):
        defaultLocation = args['defaultLocation']
        if isinstance(defaultLocation, (Carbon.File.FSSpec, Carbon.File.FSRef)):
            args['defaultLocation'] = aepack.pack(defaultLocation)
        else:
            defaultLocation = Carbon.File.FSRef(defaultLocation)
            args['defaultLocation'] = aepack.pack(defaultLocation)
    if args.has_key('typeList') and not isinstance(args['typeList'], Carbon.Res.ResourceType):
        typeList = args['typeList'][:]
        # Workaround for OSX typeless files:
        if 'TEXT' in typeList and not '\0\0\0\0' in typeList:
            typeList = typeList + ('\0\0\0\0',)
        data = 'Pyth' + struct.pack("hh", 0, len(typeList))
        for type in typeList:
            data = data+type
        args['typeList'] = Carbon.Res.Handle(data)
    tpwanted = str
    if args.has_key('wanted'):
        tpwanted = args['wanted']
        del args['wanted']
    return args, tpwanted

def _dummy_Nav_eventproc(msg, data):
    pass

_default_Nav_eventproc = _dummy_Nav_eventproc

def SetDefaultEventProc(proc):
    global _default_Nav_eventproc
    rv = _default_Nav_eventproc
    if proc is None:
        proc = _dummy_Nav_eventproc
    _default_Nav_eventproc = proc
    return rv

def AskFileForOpen(
        message=None,
        typeList=None,
        # From here on the order is not documented
        version=None,
        defaultLocation=None,
        dialogOptionFlags=None,
        location=None,
        clientName=None,
        windowTitle=None,
        actionButtonLabel=None,
        cancelButtonLabel=None,
        preferenceKey=None,
        popupExtension=None,
        eventProc=_dummy_Nav_eventproc,
        previewProc=None,
        filterProc=None,
        wanted=None,
        multiple=None):
    """Display a dialog asking the user for a file to open.

    wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
    the other arguments can be looked up in Apple's Navigation Services documentation"""

    default_flags = 0x56 # Or 0xe4?
    args, tpwanted = _process_Nav_args(default_flags, version=version,
        defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
        location=location,clientName=clientName,windowTitle=windowTitle,
        actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
        message=message,preferenceKey=preferenceKey,
        popupExtension=popupExtension,eventProc=eventProc,previewProc=previewProc,
        filterProc=filterProc,typeList=typeList,wanted=wanted,multiple=multiple)
    _interact()
    try:
        rr = Nav.NavChooseFile(args)
        good = 1
    except Nav.error, arg:
        if arg[0] != -128: # userCancelledErr
            raise Nav.error, arg
        return None
    if not rr.validRecord or not rr.selection:
        return None
    if issubclass(tpwanted, Carbon.File.FSRef):
        return tpwanted(rr.selection_fsr[0])
    if issubclass(tpwanted, Carbon.File.FSSpec):
        return tpwanted(rr.selection[0])
    if issubclass(tpwanted, str):
        return tpwanted(rr.selection_fsr[0].as_pathname())
    if issubclass(tpwanted, unicode):
        return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
    raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)

def AskFileForSave(
        message=None,
        savedFileName=None,
        # From here on the order is not documented
        version=None,
        defaultLocation=None,
        dialogOptionFlags=None,
        location=None,
        clientName=None,
        windowTitle=None,
        actionButtonLabel=None,
        cancelButtonLabel=None,
        preferenceKey=None,
        popupExtension=None,
        eventProc=_dummy_Nav_eventproc,
        fileType=None,
        fileCreator=None,
        wanted=None,
        multiple=None):
    """Display a dialog asking the user for a filename to save to.

    wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
    the other arguments can be looked up in Apple's Navigation Services documentation"""


    default_flags = 0x07
    args, tpwanted = _process_Nav_args(default_flags, version=version,
        defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
        location=location,clientName=clientName,windowTitle=windowTitle,
        actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
        savedFileName=savedFileName,message=message,preferenceKey=preferenceKey,
        popupExtension=popupExtension,eventProc=eventProc,fileType=fileType,
        fileCreator=fileCreator,wanted=wanted,multiple=multiple)
    _interact()
    try:
        rr = Nav.NavPutFile(args)
        good = 1
    except Nav.error, arg:
        if arg[0] != -128: # userCancelledErr
            raise Nav.error, arg
        return None
    if not rr.validRecord or not rr.selection:
        return None
    if issubclass(tpwanted, Carbon.File.FSRef):
        raise TypeError, "Cannot pass wanted=FSRef to AskFileForSave"
    if issubclass(tpwanted, Carbon.File.FSSpec):
        return tpwanted(rr.selection[0])
    if issubclass(tpwanted, (str, unicode)):
        if sys.platform == 'mac':
            fullpath = rr.selection[0].as_pathname()
        else:
            # This is gross, and probably incorrect too
            vrefnum, dirid, name = rr.selection[0].as_tuple()
            pardir_fss = Carbon.File.FSSpec((vrefnum, dirid, ''))
            pardir_fsr = Carbon.File.FSRef(pardir_fss)
            pardir_path = pardir_fsr.FSRefMakePath()  # This is utf-8
            name_utf8 = unicode(name, 'macroman').encode('utf8')
            fullpath = os.path.join(pardir_path, name_utf8)
        if issubclass(tpwanted, unicode):
            return unicode(fullpath, 'utf8')
        return tpwanted(fullpath)
    raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)

def AskFolder(
        message=None,
        # From here on the order is not documented
        version=None,
        defaultLocation=None,
        dialogOptionFlags=None,
        location=None,
        clientName=None,
        windowTitle=None,
        actionButtonLabel=None,
        cancelButtonLabel=None,
        preferenceKey=None,
        popupExtension=None,
        eventProc=_dummy_Nav_eventproc,
        filterProc=None,
        wanted=None,
        multiple=None):
    """Display a dialog asking the user for select a folder.

    wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
    the other arguments can be looked up in Apple's Navigation Services documentation"""

    default_flags = 0x17
    args, tpwanted = _process_Nav_args(default_flags, version=version,
        defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
        location=location,clientName=clientName,windowTitle=windowTitle,
        actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
        message=message,preferenceKey=preferenceKey,
        popupExtension=popupExtension,eventProc=eventProc,filterProc=filterProc,
        wanted=wanted,multiple=multiple)
    _interact()
    try:
        rr = Nav.NavChooseFolder(args)
        good = 1
    except Nav.error, arg:
        if arg[0] != -128: # userCancelledErr
            raise Nav.error, arg
        return None
    if not rr.validRecord or not rr.selection:
        return None
    if issubclass(tpwanted, Carbon.File.FSRef):
        return tpwanted(rr.selection_fsr[0])
    if issubclass(tpwanted, Carbon.File.FSSpec):
        return tpwanted(rr.selection[0])
    if issubclass(tpwanted, str):
        return tpwanted(rr.selection_fsr[0].as_pathname())
    if issubclass(tpwanted, unicode):
        return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
    raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)


def test():
    import time

    Message("Testing EasyDialogs.")
    optionlist = (('v', 'Verbose'), ('verbose', 'Verbose as long option'),
                ('flags=', 'Valued option'), ('f:', 'Short valued option'))
    commandlist = (('start', 'Start something'), ('stop', 'Stop something'))
    argv = GetArgv(optionlist=optionlist, commandlist=commandlist, addoldfile=0)
    Message("Command line: %s"%' '.join(argv))
    for i in range(len(argv)):
        print 'arg[%d] = %r' % (i, argv[i])
    ok = AskYesNoCancel("Do you want to proceed?")
    ok = AskYesNoCancel("Do you want to identify?", yes="Identify", no="No")
    if ok > 0:
        s = AskString("Enter your first name", "Joe")
        s2 = AskPassword("Okay %s, tell us your nickname"%s, s, cancel="None")
        if not s2:
            Message("%s has no secret nickname"%s)
        else:
            Message("Hello everybody!!\nThe secret nickname of %s is %s!!!"%(s, s2))
    else:
        s = 'Anonymous'
    rv = AskFileForOpen(message="Gimme a file, %s"%s, wanted=Carbon.File.FSSpec)
    Message("rv: %s"%rv)
    rv = AskFileForSave(wanted=Carbon.File.FSRef, savedFileName="%s.txt"%s)
    Message("rv.as_pathname: %s"%rv.as_pathname())
    rv = AskFolder()
    Message("Folder name: %s"%rv)
    text = ( "Working Hard...", "Hardly Working..." ,
            "So far, so good!", "Keep on truckin'" )
    bar = ProgressBar("Progress, progress...", 0, label="Ramping up...")
    try:
        if hasattr(MacOS, 'SchedParams'):
            appsw = MacOS.SchedParams(1, 0)
        for i in xrange(20):
            bar.inc()
            time.sleep(0.05)
        bar.set(0,100)
        for i in xrange(100):
            bar.set(i)
            time.sleep(0.05)
            if i % 10 == 0:
                bar.label(text[(i/10) % 4])
        bar.label("Done.")
        time.sleep(1.0)     # give'em a chance to see "Done."
    finally:
        del bar
        if hasattr(MacOS, 'SchedParams'):
            MacOS.SchedParams(*appsw)

if __name__ == '__main__':
    try:
        test()
    except KeyboardInterrupt:
        Message("Operation Canceled.")


--- NEW FILE: FrameWork.py ---
"A sort of application framework for the Mac"

DEBUG=0

import MacOS
import traceback

from Carbon.AE import *
from Carbon.AppleEvents import *
from Carbon.Ctl import *
from Carbon.Controls import *
from Carbon.Dlg import *
from Carbon.Dialogs import *
from Carbon.Evt import *
from Carbon.Events import *
from Carbon.Help import *
from Carbon.Menu import *
from Carbon.Menus import *
from Carbon.Qd import *
[...1084 lines suppressed...]
    def enablehelp(self, *args):
        hm = self.gethelpmenu()
        self.nohelpitem = MenuItem(hm, "There isn't any", None, self.nohelp)

    def nohelp(self, *args):
        print "I told you there isn't any!"

    def debug(self, *args):
        import pdb
        pdb.set_trace()


def test():
    "Test program"
    app = TestApp()
    app.mainloop()


if __name__ == '__main__':
    test()

--- NEW FILE: MiniAEFrame.py ---
"""MiniAEFrame - A minimal AppleEvent Application framework.

There are two classes:
    AEServer -- a mixin class offering nice AE handling.
    MiniApplication -- a very minimal alternative to FrameWork.py,
        only suitable for the simplest of AppleEvent servers.
"""

import sys
import traceback
import MacOS
from Carbon import AE
from Carbon.AppleEvents import *
from Carbon import Evt
from Carbon.Events import *
from Carbon import Menu
from Carbon import Win
from Carbon.Windows import *
from Carbon import Qd

import aetools
import EasyDialogs

kHighLevelEvent = 23                # Not defined anywhere for Python yet?


class MiniApplication:

    """A minimal FrameWork.Application-like class"""

    def __init__(self):
        self.quitting = 0
        # Initialize menu
        self.appleid = 1
        self.quitid = 2
        Menu.ClearMenuBar()
        self.applemenu = applemenu = Menu.NewMenu(self.appleid, "\024")
        applemenu.AppendMenu("%s;(-" % self.getaboutmenutext())
        if MacOS.runtimemodel == 'ppc':
            applemenu.AppendResMenu('DRVR')
        applemenu.InsertMenu(0)
        self.quitmenu = Menu.NewMenu(self.quitid, "File")
        self.quitmenu.AppendMenu("Quit")
        self.quitmenu.SetItemCmd(1, ord("Q"))
        self.quitmenu.InsertMenu(0)
        Menu.DrawMenuBar()

    def __del__(self):
        self.close()

    def close(self):
        pass

    def mainloop(self, mask = everyEvent, timeout = 60*60):
        while not self.quitting:
            self.dooneevent(mask, timeout)

    def _quit(self):
        self.quitting = 1

    def dooneevent(self, mask = everyEvent, timeout = 60*60):
            got, event = Evt.WaitNextEvent(mask, timeout)
            if got:
                self.lowlevelhandler(event)

    def lowlevelhandler(self, event):
        what, message, when, where, modifiers = event
        h, v = where
        if what == kHighLevelEvent:
            msg = "High Level Event: %r %r" % (code(message), code(h | (v<<16)))
            try:
                AE.AEProcessAppleEvent(event)
            except AE.Error, err:
                print 'AE error: ', err
                print 'in', msg
                traceback.print_exc()
            return
        elif what == keyDown:
            c = chr(message & charCodeMask)
            if modifiers & cmdKey:
                if c == '.':
                    raise KeyboardInterrupt, "Command-period"
                if c == 'q':
                    if hasattr(MacOS, 'OutputSeen'):
                        MacOS.OutputSeen()
                    self.quitting = 1
                    return
        elif what == mouseDown:
            partcode, window = Win.FindWindow(where)
            if partcode == inMenuBar:
                result = Menu.MenuSelect(where)
                id = (result>>16) & 0xffff      # Hi word
                item = result & 0xffff      # Lo word
                if id == self.appleid:
                    if item == 1:
                        EasyDialogs.Message(self.getabouttext())
                    elif item > 1 and hasattr(Menu, 'OpenDeskAcc'):
                        name = self.applemenu.GetMenuItemText(item)
                        Menu.OpenDeskAcc(name)
                elif id == self.quitid and item == 1:
                    if hasattr(MacOS, 'OutputSeen'):
                        MacOS.OutputSeen()
                    self.quitting = 1
                Menu.HiliteMenu(0)
                return
        # Anything not handled is passed to Python/SIOUX
        if hasattr(MacOS, 'HandleEvent'):
            MacOS.HandleEvent(event)
        else:
            print "Unhandled event:", event

    def getabouttext(self):
        return self.__class__.__name__

    def getaboutmenutext(self):
        return "About %s\311" % self.__class__.__name__


class AEServer:

    def __init__(self):
        self.ae_handlers = {}

    def installaehandler(self, classe, type, callback):
        AE.AEInstallEventHandler(classe, type, self.callback_wrapper)
        self.ae_handlers[(classe, type)] = callback

    def close(self):
        for classe, type in self.ae_handlers.keys():
            AE.AERemoveEventHandler(classe, type)

    def callback_wrapper(self, _request, _reply):
        _parameters, _attributes = aetools.unpackevent(_request)
        _class = _attributes['evcl'].type
        _type = _attributes['evid'].type

        if self.ae_handlers.has_key((_class, _type)):
            _function = self.ae_handlers[(_class, _type)]
        elif self.ae_handlers.has_key((_class, '****')):
            _function = self.ae_handlers[(_class, '****')]
        elif self.ae_handlers.has_key(('****', '****')):
            _function = self.ae_handlers[('****', '****')]
        else:
            raise 'Cannot happen: AE callback without handler', (_class, _type)

        # XXXX Do key-to-name mapping here

        _parameters['_attributes'] = _attributes
        _parameters['_class'] = _class
        _parameters['_type'] = _type
        if _parameters.has_key('----'):
            _object = _parameters['----']
            del _parameters['----']
            # The try/except that used to be here can mask programmer errors.
            # Let the program crash, the programmer can always add a **args
            # to the formal parameter list.
            rv = _function(_object, **_parameters)
        else:
            #Same try/except comment as above
            rv = _function(**_parameters)

        if rv == None:
            aetools.packevent(_reply, {})
        else:
            aetools.packevent(_reply, {'----':rv})


def code(x):
    "Convert a long int to the 4-character code it really is"
    s = ''
    for i in range(4):
        x, c = divmod(x, 256)
        s = chr(c) + s
    return s

class _Test(AEServer, MiniApplication):
    """Mini test application, handles required events"""

    def __init__(self):
        MiniApplication.__init__(self)
        AEServer.__init__(self)
        self.installaehandler('aevt', 'oapp', self.open_app)
        self.installaehandler('aevt', 'quit', self.quit)
        self.installaehandler('****', '****', self.other)
        self.mainloop()

    def quit(self, **args):
        self._quit()

    def open_app(self, **args):
        pass

    def other(self, _object=None, _class=None, _type=None, **args):
        print 'AppleEvent', (_class, _type), 'for', _object, 'Other args:', args


if __name__ == '__main__':
    _Test()

--- NEW FILE: PixMapWrapper.py ---
"""PixMapWrapper - defines the PixMapWrapper class, which wraps an opaque
QuickDraw PixMap data structure in a handy Python class.  Also provides 
methods to convert to/from pixel data (from, e.g., the img module) or a
Python Imaging Library Image object.

J. Strout <joe at strout.net>  February 1999"""

from Carbon import Qd
from Carbon import QuickDraw
import struct
import MacOS
import img
import imgformat

# PixMap data structure element format (as used with struct)
_pmElemFormat = {
    'baseAddr':'l',     # address of pixel data
    'rowBytes':'H',     # bytes per row, plus 0x8000
    'bounds':'hhhh',    # coordinates imposed over pixel data
        'top':'h',
        'left':'h',
        'bottom':'h',
        'right':'h',
    'pmVersion':'h',    # flags for Color QuickDraw
    'packType':'h',     # format of compression algorithm
    'packSize':'l',     # size after compression
    'hRes':'l',         # horizontal pixels per inch
    'vRes':'l',         # vertical pixels per inch
    'pixelType':'h',    # pixel format
    'pixelSize':'h',    # bits per pixel
    'cmpCount':'h',     # color components per pixel
    'cmpSize':'h',      # bits per component
    'planeBytes':'l',   # offset in bytes to next plane
    'pmTable':'l',      # handle to color table
    'pmReserved':'l'    # reserved for future use
}

# PixMap data structure element offset
_pmElemOffset = {
    'baseAddr':0,
    'rowBytes':4,
    'bounds':6,
        'top':6,
        'left':8,
        'bottom':10,
        'right':12,
    'pmVersion':14,
    'packType':16,
    'packSize':18,
    'hRes':22,
    'vRes':26,
    'pixelType':30,
    'pixelSize':32,
    'cmpCount':34,
    'cmpSize':36,
    'planeBytes':38,
    'pmTable':42,
    'pmReserved':46
}

class PixMapWrapper:
    """PixMapWrapper -- wraps the QD PixMap object in a Python class,
    with methods to easily get/set various pixmap fields.  Note: Use the
    PixMap() method when passing to QD calls."""

    def __init__(self):
        self.__dict__['data'] = ''
        self._header = struct.pack("lhhhhhhhlllhhhhlll",
            id(self.data)+MacOS.string_id_to_buffer,
            0,                      # rowBytes
            0, 0, 0, 0,             # bounds
            0,                      # pmVersion
            0, 0,                   # packType, packSize
            72<<16, 72<<16,         # hRes, vRes
            QuickDraw.RGBDirect,    # pixelType
            16,                     # pixelSize
            2, 5,                   # cmpCount, cmpSize,
            0, 0, 0)                # planeBytes, pmTable, pmReserved
        self.__dict__['_pm'] = Qd.RawBitMap(self._header)
    
    def _stuff(self, element, bytes):
        offset = _pmElemOffset[element]
        fmt = _pmElemFormat[element]
        self._header = self._header[:offset] \
            + struct.pack(fmt, bytes) \
            + self._header[offset + struct.calcsize(fmt):]
        self.__dict__['_pm'] = None
    
    def _unstuff(self, element):
        offset = _pmElemOffset[element]
        fmt = _pmElemFormat[element]
        return struct.unpack(fmt, self._header[offset:offset+struct.calcsize(fmt)])[0]

    def __setattr__(self, attr, val):
        if attr == 'baseAddr':
            raise 'UseErr', "don't assign to .baseAddr -- assign to .data instead"
        elif attr == 'data':
            self.__dict__['data'] = val
            self._stuff('baseAddr', id(self.data) + MacOS.string_id_to_buffer)
        elif attr == 'rowBytes':
            # high bit is always set for some odd reason
            self._stuff('rowBytes', val | 0x8000)
        elif attr == 'bounds':
            # assume val is in official Left, Top, Right, Bottom order!
            self._stuff('left',val[0])
            self._stuff('top',val[1])
            self._stuff('right',val[2])
            self._stuff('bottom',val[3])
        elif attr == 'hRes' or attr == 'vRes':
            # 16.16 fixed format, so just shift 16 bits
            self._stuff(attr, int(val) << 16)
        elif attr in _pmElemFormat.keys():
            # any other pm attribute -- just stuff
            self._stuff(attr, val)
        else:
            self.__dict__[attr] = val   

    def __getattr__(self, attr):
        if attr == 'rowBytes':
            # high bit is always set for some odd reason
            return self._unstuff('rowBytes') & 0x7FFF
        elif attr == 'bounds':
            # return bounds in official Left, Top, Right, Bottom order!
            return ( \
                self._unstuff('left'),
                self._unstuff('top'),
                self._unstuff('right'),
                self._unstuff('bottom') )
        elif attr == 'hRes' or attr == 'vRes':
            # 16.16 fixed format, so just shift 16 bits
            return self._unstuff(attr) >> 16
        elif attr in _pmElemFormat.keys():
            # any other pm attribute -- just unstuff
            return self._unstuff(attr)
        else:
            return self.__dict__[attr]  

        
    def PixMap(self):
        "Return a QuickDraw PixMap corresponding to this data."
        if not self.__dict__['_pm']:
            self.__dict__['_pm'] = Qd.RawBitMap(self._header)
        return self.__dict__['_pm']

    def blit(self, x1=0,y1=0,x2=None,y2=None, port=None):
        """Draw this pixmap into the given (default current) grafport.""" 
        src = self.bounds
        dest = [x1,y1,x2,y2]
        if x2 == None:
            dest[2] = x1 + src[2]-src[0]
        if y2 == None:
            dest[3] = y1 + src[3]-src[1]
        if not port: port = Qd.GetPort()
        Qd.CopyBits(self.PixMap(), port.GetPortBitMapForCopyBits(), src, tuple(dest),
                QuickDraw.srcCopy, None)
    
    def fromstring(self,s,width,height,format=imgformat.macrgb):
        """Stuff this pixmap with raw pixel data from a string.
        Supply width, height, and one of the imgformat specifiers."""
        # we only support 16- and 32-bit mac rgb...
        # so convert if necessary
        if format != imgformat.macrgb and format != imgformat.macrgb16:
            # (LATER!)
            raise "NotImplementedError", "conversion to macrgb or macrgb16"
        self.data = s
        self.bounds = (0,0,width,height)
        self.cmpCount = 3
        self.pixelType = QuickDraw.RGBDirect
        if format == imgformat.macrgb:
            self.pixelSize = 32
            self.cmpSize = 8
        else:
            self.pixelSize = 16
            self.cmpSize = 5
        self.rowBytes = width*self.pixelSize/8

    def tostring(self, format=imgformat.macrgb):
        """Return raw data as a string in the specified format."""
        # is the native format requested?  if so, just return data
        if (format == imgformat.macrgb and self.pixelSize == 32) or \
           (format == imgformat.macrgb16 and self.pixelsize == 16):
            return self.data
        # otherwise, convert to the requested format
        # (LATER!)
            raise "NotImplementedError", "data format conversion"

    def fromImage(self,im):
        """Initialize this PixMap from a PIL Image object."""
        # We need data in ARGB format; PIL can't currently do that,
        # but it can do RGBA, which we can use by inserting one null
        # up frontpm = 
        if im.mode != 'RGBA': im = im.convert('RGBA')
        data = chr(0) + im.tostring()
        self.fromstring(data, im.size[0], im.size[1])

    def toImage(self):
        """Return the contents of this PixMap as a PIL Image object."""
        import Image
        # our tostring() method returns data in ARGB format,
        # whereas Image uses RGBA; a bit of slicing fixes this...
        data = self.tostring()[1:] + chr(0)
        bounds = self.bounds
        return Image.fromstring('RGBA',(bounds[2]-bounds[0],bounds[3]-bounds[1]),data)

def test():
    import MacOS
    import EasyDialogs
    import Image
    path = EasyDialogs.AskFileForOpen("Image File:")
    if not path: return
    pm = PixMapWrapper()
    pm.fromImage( Image.open(path) )
    pm.blit(20,20)
    return pm


--- NEW FILE: WASTEconst.py ---
# Generated from 'WASTE.h'

kPascalStackBased = None # workaround for header parsing
def FOUR_CHAR_CODE(x): return x
weCantUndoErr = -10015
weEmptySelectionErr = -10013
weUnknownObjectTypeErr = -9478
weObjectNotFoundErr = -9477
weReadOnlyErr = -9476
weTextNotFoundErr = -9474
weInvalidTextEncodingErr = -9473
weDuplicateAttributeErr = -9472
weInvalidAttributeSizeErr = -9471
weReadOnlyAttributeErr = -9470
weOddByteCountErr = -9469
weHandlerNotFoundErr = -1717
weNotHandledErr = -1708
weNewerVersionErr = -1706
weCorruptDataErr = -1702
weProtocolErr = -603
weUndefinedSelectorErr = -50
weFlushLeft = -2
weFlushRight = -1
weFlushDefault = 0
weCenter = 1
weJustify = 2
weDirDefault = 1
weDirRightToLeft = -1
weDirLeftToRight = 0
weDoFont = 0x0001
weDoFace = 0x0002
weDoSize = 0x0004
weDoColor = 0x0008
weDoAll = weDoFont | weDoFace | weDoSize | weDoColor
weDoAddSize = 0x0010
weDoToggleFace = 0x0020
weDoReplaceFace = 0x0040
weDoPreserveScript = 0x0080
weDoExtractSubscript = 0x0100
weDoFaceMask = 0x0200
weDoDirection = 0x00000001
weDoAlignment = 0x00000002
weDoLeftIndent = 0x00000004
weDoRightIndent = 0x00000008
weDoFirstLineIndent = 0x00000010
weDoLineSpacing = 0x00000020
weDoSpaceBefore = 0x00000040
weDoSpaceAfter = 0x00000080
weDoBottomBorderStyle = 0x00000400
kLeadingEdge = -1
kTrailingEdge = 0
kObjectEdge = 2
weFAutoScroll = 0
weFOutlineHilite = 2
weFReadOnly = 5
weFUndo = 6
weFIntCutAndPaste = 7
weFDragAndDrop = 8
weFInhibitRecal = 9
weFUseTempMem = 10
weFDrawOffscreen = 11
weFInhibitRedraw = 12
weFMonoStyled = 13
weFMultipleUndo = 14
weFNoKeyboardSync = 29
weFInhibitICSupport = 30
weFInhibitColor = 31
weDoAutoScroll = 1 << weFAutoScroll
weDoOutlineHilite = 1 << weFOutlineHilite
weDoReadOnly = 1 << weFReadOnly
weDoUndo = 1 << weFUndo
weDoIntCutAndPaste = 1 << weFIntCutAndPaste
weDoDragAndDrop = 1 << weFDragAndDrop
weDoInhibitRecal = 1 << weFInhibitRecal
weDoUseTempMem = 1 << weFUseTempMem
weDoDrawOffscreen = 1 << weFDrawOffscreen
weDoInhibitRedraw = 1 << weFInhibitRedraw
weDoMonoStyled = 1 << weFMonoStyled
weDoMultipleUndo = 1 << weFMultipleUndo
weDoNoKeyboardSync = 1 << weFNoKeyboardSync
weDoInhibitICSupport = 1 << weFInhibitICSupport
# weDoInhibitColor = 1 << weFInhibitColor
weBitToggle = -2
weBitTest = -1
weBitClear = 0
weBitSet = 1
weLowerCase = 0
weUpperCase = 1
weFindWholeWords = 0x00000001
weFindCaseInsensitive = 0x00000002
weFindDiacriticalInsensitive = 0x00000004
wePutIntCutAndPaste = 0x00000001
wePutAddToTypingSequence = 0x00000002
wePutDetectUnicodeBOM = 0x00000200
weStreamDestinationKindMask = 0x000000FF
weStreamIncludeObjects = 0x00000100
weGetAddUnicodeBOM = 0x00000200
weGetLittleEndian = 0x00000400
weTagFontFamily = FOUR_CHAR_CODE('font')
weTagFontSize = FOUR_CHAR_CODE('ptsz')
weTagPlain = FOUR_CHAR_CODE('plan')
weTagBold = FOUR_CHAR_CODE('bold')
weTagItalic = FOUR_CHAR_CODE('ital')
weTagUnderline = FOUR_CHAR_CODE('undl')
weTagOutline = FOUR_CHAR_CODE('outl')
weTagShadow = FOUR_CHAR_CODE('shad')
weTagCondensed = FOUR_CHAR_CODE('cond')
weTagExtended = FOUR_CHAR_CODE('pexp')
weTagStrikethrough = FOUR_CHAR_CODE('strk')
weTagTextColor = FOUR_CHAR_CODE('colr')
weTagBackgroundColor = FOUR_CHAR_CODE('pbcl')
weTagTransferMode = FOUR_CHAR_CODE('pptm')
weTagVerticalShift = FOUR_CHAR_CODE('xshf')
weTagAlignment = FOUR_CHAR_CODE('pjst')
weTagDirection = FOUR_CHAR_CODE('LDIR')
weTagLineSpacing = FOUR_CHAR_CODE('ledg')
weTagLeftIndent = FOUR_CHAR_CODE('lein')
weTagRightIndent = FOUR_CHAR_CODE('riin')
weTagFirstLineIndent = FOUR_CHAR_CODE('fidt')
weTagSpaceBefore = FOUR_CHAR_CODE('spbe')
weTagSpaceAfter = FOUR_CHAR_CODE('spaf')
weTagBottomBorderStyle = FOUR_CHAR_CODE('BBRD')
weTagForceFontFamily = FOUR_CHAR_CODE('ffnt')
weTagAddFontSize = FOUR_CHAR_CODE('+siz')
weTagAddVerticalShift = FOUR_CHAR_CODE('+shf')
weTagTextEncoding = FOUR_CHAR_CODE('ptxe')
weTagQDStyles = FOUR_CHAR_CODE('qdst')
weTagTETextStyle = FOUR_CHAR_CODE('tets')
weTagAlignmentDefault = FOUR_CHAR_CODE('deft')
weTagAlignmentLeft = FOUR_CHAR_CODE('left')
weTagAlignmentCenter = FOUR_CHAR_CODE('cent')
weTagAlignmentRight = FOUR_CHAR_CODE('rght')
weTagAlignmentFull = FOUR_CHAR_CODE('full')
weTagDirectionDefault = FOUR_CHAR_CODE('deft')
weTagDirectionLeftToRight = FOUR_CHAR_CODE('L->R')
weTagDirectionRightToLeft = FOUR_CHAR_CODE('R->L')
weTagBorderStyleNone = FOUR_CHAR_CODE('NONE')
weTagBorderStyleThin = FOUR_CHAR_CODE('SLDL')
weTagBorderStyleDotted = FOUR_CHAR_CODE('DTDL')
weTagBorderStyleThick = FOUR_CHAR_CODE('THKL')
weLineSpacingSingle = 0x00000000
weLineSpacingOneAndHalf = 0x00008000
weLineSpacingDouble = 0x00010000
weCharByteHook = FOUR_CHAR_CODE('cbyt')
weCharToPixelHook = FOUR_CHAR_CODE('c2p ')
weCharTypeHook = FOUR_CHAR_CODE('ctyp')
weClickLoop = FOUR_CHAR_CODE('clik')
weCurrentDrag = FOUR_CHAR_CODE('drag')
weDrawTextHook = FOUR_CHAR_CODE('draw')
weDrawTSMHiliteHook = FOUR_CHAR_CODE('dtsm')
weEraseHook = FOUR_CHAR_CODE('eras')
weFontFamilyToNameHook = FOUR_CHAR_CODE('ff2n')
weFontNameToFamilyHook = FOUR_CHAR_CODE('fn2f')
weFluxProc = FOUR_CHAR_CODE('flux')
weHiliteDropAreaHook = FOUR_CHAR_CODE('hidr')
weLineBreakHook = FOUR_CHAR_CODE('lbrk')
wePixelToCharHook = FOUR_CHAR_CODE('p2c ')
wePort = FOUR_CHAR_CODE('port')
wePreTrackDragHook = FOUR_CHAR_CODE('ptrk')
weRefCon = FOUR_CHAR_CODE('refc')
weScrollProc = FOUR_CHAR_CODE('scrl')
weText = FOUR_CHAR_CODE('text')
weTranslateDragHook = FOUR_CHAR_CODE('xdrg')
weTranslucencyThreshold = FOUR_CHAR_CODE('tluc')
weTSMDocumentID = FOUR_CHAR_CODE('tsmd')
weTSMPreUpdate = FOUR_CHAR_CODE('pre ')
weTSMPostUpdate = FOUR_CHAR_CODE('post')
weURLHint = FOUR_CHAR_CODE('urlh')
weWordBreakHook = FOUR_CHAR_CODE('wbrk')
weNewHandler = FOUR_CHAR_CODE('new ')
weDisposeHandler = FOUR_CHAR_CODE('free')
weDrawHandler = FOUR_CHAR_CODE('draw')
weClickHandler = FOUR_CHAR_CODE('clik')
weStreamHandler = FOUR_CHAR_CODE('strm')
weHoverHandler = FOUR_CHAR_CODE('hovr')
kTypeText = FOUR_CHAR_CODE('TEXT')
kTypeStyles = FOUR_CHAR_CODE('styl')
kTypeSoup = FOUR_CHAR_CODE('SOUP')
kTypeFontTable = FOUR_CHAR_CODE('FISH')
kTypeParaFormat = FOUR_CHAR_CODE('WEpf')
kTypeRulerScrap = FOUR_CHAR_CODE('WEru')
kTypeCharFormat = FOUR_CHAR_CODE('WEcf')
kTypeStyleScrap = FOUR_CHAR_CODE('WEst')
kTypeUnicodeText = FOUR_CHAR_CODE('utxt')
kTypeUTF8Text = FOUR_CHAR_CODE('UTF8')
kTypeStyledText = FOUR_CHAR_CODE('STXT')
weAKNone = 0
weAKUnspecified = 1
weAKTyping = 2
weAKCut = 3
weAKPaste = 4
weAKClear = 5
weAKDrag = 6
weAKSetStyle = 7
weAKSetRuler = 8
weAKBackspace = 9
weAKFwdDelete = 10
weAKCaseChange = 11
weAKObjectChange = 12
weToScrap = 0
weToDrag = 1
weToSoup = 2
weMouseEnter = 0
weMouseWithin = 1
weMouseLeave = 2
kCurrentSelection = -1
kNullStyle = -2

--- NEW FILE: aepack.py ---
"""Tools for use in AppleEvent clients and servers:
conversion between AE types and python types

pack(x) converts a Python object to an AEDesc object
unpack(desc) does the reverse
coerce(x, wanted_sample) coerces a python object to another python object
"""

#
# This code was originally written by Guido, and modified/extended by Jack
# to include the various types that were missing. The reference used is
# Apple Event Registry, chapter 9.
#

import struct
import string
import types
from string import strip
from types import *
from Carbon import AE
from Carbon.AppleEvents import *
import MacOS
import Carbon.File
import StringIO
import aetypes
from aetypes import mkenum, ObjectSpecifier
import os

# These ones seem to be missing from AppleEvents
# (they're in AERegistry.h)

#typeColorTable = 'clrt'
#typeDrawingArea = 'cdrw'
#typePixelMap = 'cpix'
#typePixelMapMinus = 'tpmm'
#typeRotation = 'trot'
#typeTextStyles = 'tsty'
#typeStyledText = 'STXT'
#typeAEText = 'tTXT'
#typeEnumeration = 'enum'

#
# Some AE types are immedeately coerced into something
# we like better (and which is equivalent)
#
unpacker_coercions = {
    typeComp : typeFloat,
    typeColorTable : typeAEList,
    typeDrawingArea : typeAERecord,
    typeFixed : typeFloat,
    typeExtended : typeFloat,
    typePixelMap : typeAERecord,
    typeRotation : typeAERecord,
    typeStyledText : typeAERecord,
    typeTextStyles : typeAERecord,
};

#
# Some python types we need in the packer:
#
AEDescType = AE.AEDescType
FSSType = Carbon.File.FSSpecType
FSRefType = Carbon.File.FSRefType
AliasType = Carbon.File.AliasType

def packkey(ae, key, value):
    if hasattr(key, 'which'):
        keystr = key.which
    elif hasattr(key, 'want'):
        keystr = key.want
    else:
        keystr = key
    ae.AEPutParamDesc(keystr, pack(value))

def pack(x, forcetype = None):
    """Pack a python object into an AE descriptor"""
    
    if forcetype:
        if type(x) is StringType:
            return AE.AECreateDesc(forcetype, x)
        else:
            return pack(x).AECoerceDesc(forcetype)
            
    if x == None:
        return AE.AECreateDesc('null', '')
        
    if isinstance(x, AEDescType):
        return x
    if isinstance(x, FSSType):
        return AE.AECreateDesc('fss ', x.data)
    if isinstance(x, FSRefType):
        return AE.AECreateDesc('fsrf', x.data)
    if isinstance(x, AliasType):
        return AE.AECreateDesc('alis', x.data)
    if isinstance(x, IntType):
        return AE.AECreateDesc('long', struct.pack('l', x))
    if isinstance(x, FloatType):
        return AE.AECreateDesc('doub', struct.pack('d', x))
    if isinstance(x, StringType):
        return AE.AECreateDesc('TEXT', x)
    if isinstance(x, UnicodeType):
        data = x.encode('utf16')
        if data[:2] == '\xfe\xff':
            data = data[2:]
        return AE.AECreateDesc('utxt', data)
    if isinstance(x, ListType):
        list = AE.AECreateList('', 0)
        for item in x:
            list.AEPutDesc(0, pack(item))
        return list
    if isinstance(x, DictionaryType):
        record = AE.AECreateList('', 1)
        for key, value in x.items():
            packkey(record, key, value)
            #record.AEPutParamDesc(key, pack(value))
        return record
    if type(x) == types.ClassType and issubclass(x, ObjectSpecifier):
        # Note: we are getting a class object here, not an instance
        return AE.AECreateDesc('type', x.want)
    if hasattr(x, '__aepack__'):
        return x.__aepack__()
    if hasattr(x, 'which'):
        return AE.AECreateDesc('TEXT', x.which)
    if hasattr(x, 'want'):
        return AE.AECreateDesc('TEXT', x.want)
    return AE.AECreateDesc('TEXT', repr(x)) # Copout

def unpack(desc, formodulename=""):
    """Unpack an AE descriptor to a python object"""
    t = desc.type
    
    if unpacker_coercions.has_key(t):
        desc = desc.AECoerceDesc(unpacker_coercions[t])
        t = desc.type # This is a guess by Jack....
    
    if t == typeAEList:
        l = []
        for i in range(desc.AECountItems()):
            keyword, item = desc.AEGetNthDesc(i+1, '****')
            l.append(unpack(item, formodulename))
        return l
    if t == typeAERecord:
        d = {}
        for i in range(desc.AECountItems()):
            keyword, item = desc.AEGetNthDesc(i+1, '****')
            d[keyword] = unpack(item, formodulename)
        return d
    if t == typeAEText:
        record = desc.AECoerceDesc('reco')
        return mkaetext(unpack(record, formodulename))
    if t == typeAlias:
        return Carbon.File.Alias(rawdata=desc.data)
    # typeAppleEvent returned as unknown
    if t == typeBoolean:
        return struct.unpack('b', desc.data)[0]
    if t == typeChar:
        return desc.data
    if t == typeUnicodeText:
        return unicode(desc.data, 'utf16')
    # typeColorTable coerced to typeAEList
    # typeComp coerced to extended
    # typeData returned as unknown
    # typeDrawingArea coerced to typeAERecord
    if t == typeEnumeration:
        return mkenum(desc.data)
    # typeEPS returned as unknown
    if t == typeFalse:
        return 0
    if t == typeFloat:
        data = desc.data
        return struct.unpack('d', data)[0]
    if t == typeFSS:
        return Carbon.File.FSSpec(rawdata=desc.data)
    if t == typeFSRef:
        return Carbon.File.FSRef(rawdata=desc.data)
    if t == typeInsertionLoc:
        record = desc.AECoerceDesc('reco')
        return mkinsertionloc(unpack(record, formodulename))
    # typeInteger equal to typeLongInteger
    if t == typeIntlText:
        script, language = struct.unpack('hh', desc.data[:4])
        return aetypes.IntlText(script, language, desc.data[4:])
    if t == typeIntlWritingCode:
        script, language = struct.unpack('hh', desc.data)
        return aetypes.IntlWritingCode(script, language)
    if t == typeKeyword:
        return mkkeyword(desc.data)
    if t == typeLongInteger:
        return struct.unpack('l', desc.data)[0]
    if t == typeLongDateTime:
        a, b = struct.unpack('lL', desc.data)
        return (long(a) << 32) + b
    if t == typeNull:
        return None
    if t == typeMagnitude:
        v = struct.unpack('l', desc.data)
        if v < 0:
            v = 0x100000000L + v
        return v
    if t == typeObjectSpecifier:
        record = desc.AECoerceDesc('reco')
        # If we have been told the name of the module we are unpacking aedescs for,
        # we can attempt to create the right type of python object from that module.
        if formodulename:
            return mkobjectfrommodule(unpack(record, formodulename), formodulename)
        return mkobject(unpack(record, formodulename))
    # typePict returned as unknown
    # typePixelMap coerced to typeAERecord
    # typePixelMapMinus returned as unknown
    # typeProcessSerialNumber returned as unknown
    if t == typeQDPoint:
        v, h = struct.unpack('hh', desc.data)
        return aetypes.QDPoint(v, h)
    if t == typeQDRectangle:
        v0, h0, v1, h1 = struct.unpack('hhhh', desc.data)
        return aetypes.QDRectangle(v0, h0, v1, h1)
    if t == typeRGBColor:
        r, g, b = struct.unpack('hhh', desc.data)
        return aetypes.RGBColor(r, g, b)
    # typeRotation coerced to typeAERecord
    # typeScrapStyles returned as unknown
    # typeSessionID returned as unknown
    if t == typeShortFloat:
        return struct.unpack('f', desc.data)[0]
    if t == typeShortInteger:
        return struct.unpack('h', desc.data)[0]
    # typeSMFloat identical to typeShortFloat
    # typeSMInt indetical to typeShortInt
    # typeStyledText coerced to typeAERecord
    if t == typeTargetID:
        return mktargetid(desc.data)
    # typeTextStyles coerced to typeAERecord
    # typeTIFF returned as unknown
    if t == typeTrue:
        return 1
    if t == typeType:
        return mktype(desc.data, formodulename)
    #
    # The following are special
    #
    if t == 'rang':
        record = desc.AECoerceDesc('reco')
        return mkrange(unpack(record, formodulename))
    if t == 'cmpd':
        record = desc.AECoerceDesc('reco')
        return mkcomparison(unpack(record, formodulename))
    if t == 'logi':
        record = desc.AECoerceDesc('reco')
        return mklogical(unpack(record, formodulename))
    return mkunknown(desc.type, desc.data)
    
def coerce(data, egdata):
    """Coerce a python object to another type using the AE coercers"""
    pdata = pack(data)
    pegdata = pack(egdata)
    pdata = pdata.AECoerceDesc(pegdata.type)
    return unpack(pdata)

#
# Helper routines for unpack
#
def mktargetid(data):
    sessionID = getlong(data[:4])
    name = mkppcportrec(data[4:4+72])
    location = mklocationnamerec(data[76:76+36])
    rcvrName = mkppcportrec(data[112:112+72])
    return sessionID, name, location, rcvrName

def mkppcportrec(rec):
    namescript = getword(rec[:2])
    name = getpstr(rec[2:2+33])
    portkind = getword(rec[36:38])
    if portkind == 1:
        ctor = rec[38:42]
        type = rec[42:46]
        identity = (ctor, type)
    else:
        identity = getpstr(rec[38:38+33])
    return namescript, name, portkind, identity

def mklocationnamerec(rec):
    kind = getword(rec[:2])
    stuff = rec[2:]
    if kind == 0: stuff = None
    if kind == 2: stuff = getpstr(stuff)
    return kind, stuff

def mkunknown(type, data):
    return aetypes.Unknown(type, data)

def getpstr(s):
    return s[1:1+ord(s[0])]

def getlong(s):
    return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])

def getword(s):
    return (ord(s[0])<<8) | (ord(s[1])<<0)

def mkkeyword(keyword):
    return aetypes.Keyword(keyword)

def mkrange(dict):
    return aetypes.Range(dict['star'], dict['stop'])

def mkcomparison(dict):
    return aetypes.Comparison(dict['obj1'], dict['relo'].enum, dict['obj2'])

def mklogical(dict):
    return aetypes.Logical(dict['logc'], dict['term'])

def mkstyledtext(dict):
    return aetypes.StyledText(dict['ksty'], dict['ktxt'])
    
def mkaetext(dict):
    return aetypes.AEText(dict[keyAEScriptTag], dict[keyAEStyles], dict[keyAEText])
    
def mkinsertionloc(dict):
    return aetypes.InsertionLoc(dict[keyAEObject], dict[keyAEPosition])

def mkobject(dict):
    want = dict['want'].type
    form = dict['form'].enum
    seld = dict['seld']
    fr   = dict['from']
    if form in ('name', 'indx', 'rang', 'test'):
        if want == 'text': return aetypes.Text(seld, fr)
        if want == 'cha ': return aetypes.Character(seld, fr)
        if want == 'cwor': return aetypes.Word(seld, fr)
        if want == 'clin': return aetypes.Line(seld, fr)
        if want == 'cpar': return aetypes.Paragraph(seld, fr)
        if want == 'cwin': return aetypes.Window(seld, fr)
        if want == 'docu': return aetypes.Document(seld, fr)
        if want == 'file': return aetypes.File(seld, fr)
        if want == 'cins': return aetypes.InsertionPoint(seld, fr)
    if want == 'prop' and form == 'prop' and aetypes.IsType(seld):
        return aetypes.Property(seld.type, fr)
    return aetypes.ObjectSpecifier(want, form, seld, fr)

# Note by Jack: I'm not 100% sure of the following code. This was
# provided by Donovan Preston, but I wonder whether the assignment
# to __class__ is safe. Moreover, shouldn't there be a better
# initializer for the classes in the suites?
def mkobjectfrommodule(dict, modulename):
    if type(dict['want']) == types.ClassType and issubclass(dict['want'], ObjectSpecifier):
        # The type has already been converted to Python. Convert back:-(
        classtype = dict['want']
        dict['want'] = aetypes.mktype(classtype.want)
    want = dict['want'].type
    module = __import__(modulename)
    codenamemapper = module._classdeclarations
    classtype = codenamemapper.get(want, None)
    newobj = mkobject(dict)
    if classtype:
        assert issubclass(classtype, ObjectSpecifier)
        newobj.__class__ = classtype
    return newobj
    
def mktype(typecode, modulename=None):
    if modulename:
        module = __import__(modulename)
        codenamemapper = module._classdeclarations
        classtype = codenamemapper.get(typecode, None)
        if classtype:
            return classtype
    return aetypes.mktype(typecode)

--- NEW FILE: aetools.py ---
"""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 Evt
from Carbon import AppleEvents
import MacOS
import sys
import time

from aetypes import *
from aepack import packkey, pack, unpack, coerce, AEDescType

Error = 'aetools.Error'

# Amount of time to wait for program to be launched
LAUNCH_MAX_WAIT_TIME=10

# 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
            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():
        ae.AEPutAttributeDesc(key, pack(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] = Enum(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
    _elemdict = {}      # Can be overridden by subclasses
    _propdict = {}      # Can be overridden by subclasses
    
    __eventloop_initialized = 0
    def __ensure_WMAvailable(klass):
        if klass.__eventloop_initialized: return 1
        if not MacOS.WMAvailable(): return 0
        # Workaround for a but in MacOSX 10.2: we must have an event
        # loop before we can call AESend.
        Evt.WaitNextEvent(0,0)
        return 1
    __ensure_WMAvailable = classmethod(__ensure_WMAvailable)
    
    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)
            for i in range(LAUNCH_MAX_WAIT_TIME):
                try:
                    self.send('ascr', 'noop')
                except AE.Error:
                    pass
                else:
                    break
                time.sleep(1)
            
    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"""
        if not self.__ensure_WMAvailable():
            raise RuntimeError, "No window manager access, cannot send AppleEvent"
        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
    
    get = _get
            
    _argmap_set = {
        'to' : 'data',
    }

    def _set(self, _object, _attributes={}, **_arguments):
        """set: Set an object's data.
        Required argument: the object for the command
        Keyword argument to: The new value.
        Keyword argument _attributes: AppleEvent attribute dictionary
        """
        _code = 'core'
        _subcode = 'setd'

        keysubst(_arguments, self._argmap_set)
        _arguments['----'] = _object


        _reply, _arguments, _attributes = self.send(_code, _subcode,
                _arguments, _attributes)
        if _arguments.get('errn', 0):
            raise Error, decodeerror(_arguments)
        # XXXX Optionally decode result
        if _arguments.has_key('----'):
            return _arguments['----']
            
    set = _set

    # Magic glue to allow suite-generated classes to function somewhat
    # like the "application" class in OSA.
    
    def __getattr__(self, name):
        if self._elemdict.has_key(name):
            cls = self._elemdict[name]
            return DelayedComponentItem(cls, None)
        if self._propdict.has_key(name):
            cls = self._propdict[name]
            return cls()
        raise AttributeError, name
        
# 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)

--- NEW FILE: aetypes.py ---
"""aetypes - Python objects representing various AE types."""

from Carbon.AppleEvents import *
import struct
from types import *
import string

#
# convoluted, since there are cyclic dependencies between this file and
# aetools_convert.
#
def pack(*args, **kwargs):
    from aepack import pack
    return pack( *args, **kwargs)
    
def nice(s):
    """'nice' representation of an object"""
    if type(s) is StringType: return repr(s)
    else: return str(s)

class Unknown:
    """An uninterpreted AE object"""
    
    def __init__(self, type, data):
        self.type = type
        self.data = data
    
    def __repr__(self):
        return "Unknown(%r, %r)" % (self.type, self.data)
    
    def __aepack__(self):
        return pack(self.data, self.type)

class Enum:
    """An AE enumeration value"""
    
    def __init__(self, enum):
        self.enum = "%-4.4s" % str(enum)
    
    def __repr__(self):
        return "Enum(%r)" % (self.enum,)
    
    def __str__(self):
        return string.strip(self.enum)
    
    def __aepack__(self):
        return pack(self.enum, typeEnumeration)

def IsEnum(x):
    return isinstance(x, Enum)

def mkenum(enum):
    if IsEnum(enum): return enum
    return Enum(enum)

# Jack changed the way this is done
class InsertionLoc:
    def __init__(self, of, pos):
        self.of = of
        self.pos = pos
    
    def __repr__(self):
        return "InsertionLoc(%r, %r)" % (self.of, self.pos)
        
    def __aepack__(self):
        rec = {'kobj': self.of, 'kpos': self.pos}
        return pack(rec, forcetype='insl')
        
# Convenience functions for dsp:
def beginning(of):
    return InsertionLoc(of, Enum('bgng'))
    
def end(of):
    return InsertionLoc(of, Enum('end '))

class Boolean:
    """An AE boolean value"""
    
    def __init__(self, bool):
        self.bool = (not not bool)
    
    def __repr__(self):
        return "Boolean(%r)" % (self.bool,)
    
    def __str__(self):
        if self.bool:
            return "True"
        else:
            return "False"
    
    def __aepack__(self):
        return pack(struct.pack('b', self.bool), 'bool')

def IsBoolean(x):
    return isinstance(x, Boolean)

def mkboolean(bool):
    if IsBoolean(bool): return bool
    return Boolean(bool)

class Type:
    """An AE 4-char typename object"""
    
    def __init__(self, type):
        self.type = "%-4.4s" % str(type)
    
    def __repr__(self):
        return "Type(%r)" % (self.type,)
    
    def __str__(self):
        return string.strip(self.type)
    
    def __aepack__(self):
        return pack(self.type, typeType)

def IsType(x):
    return isinstance(x, Type)

def mktype(type):
    if IsType(type): return type
    return Type(type)


class Keyword:
    """An AE 4-char keyword object"""
    
    def __init__(self, keyword):
        self.keyword = "%-4.4s" % str(keyword)
    
    def __repr__(self):
        return "Keyword(%r)" % `self.keyword`
    
    def __str__(self):
        return string.strip(self.keyword)
    
    def __aepack__(self):
        return pack(self.keyword, typeKeyword)

def IsKeyword(x):
    return isinstance(x, Keyword)

class Range:
    """An AE range object"""
    
    def __init__(self, start, stop):
        self.start = start
        self.stop = stop
    
    def __repr__(self):
        return "Range(%r, %r)" % (self.start, self.stop)
    
    def __str__(self):
        return "%s thru %s" % (nice(self.start), nice(self.stop))
    
    def __aepack__(self):
        return pack({'star': self.start, 'stop': self.stop}, 'rang')

def IsRange(x):
    return isinstance(x, Range)

class Comparison:
    """An AE Comparison"""
    
    def __init__(self, obj1, relo, obj2):
        self.obj1 = obj1
        self.relo = "%-4.4s" % str(relo)
        self.obj2 = obj2
    
    def __repr__(self):
        return "Comparison(%r, %r, %r)" % (self.obj1, self.relo, self.obj2)
    
    def __str__(self):
        return "%s %s %s" % (nice(self.obj1), string.strip(self.relo), nice(self.obj2))
    
    def __aepack__(self):
        return pack({'obj1': self.obj1,
                 'relo': mkenum(self.relo),
                 'obj2': self.obj2},
                'cmpd')

def IsComparison(x):
    return isinstance(x, Comparison)
    
class NComparison(Comparison):
    # The class attribute 'relo' must be set in a subclass
    
    def __init__(self, obj1, obj2):
        Comparison.__init__(obj1, self.relo, obj2)

class Ordinal:
    """An AE Ordinal"""
    
    def __init__(self, abso):
#       self.obj1 = obj1
        self.abso = "%-4.4s" % str(abso)
    
    def __repr__(self):
        return "Ordinal(%r)" % (self.abso,)
    
    def __str__(self):
        return "%s" % (string.strip(self.abso))
    
    def __aepack__(self):
        return pack(self.abso, 'abso')

def IsOrdinal(x):
    return isinstance(x, Ordinal)
    
class NOrdinal(Ordinal):
    # The class attribute 'abso' must be set in a subclass
    
    def __init__(self):
        Ordinal.__init__(self, self.abso)

class Logical:
    """An AE logical expression object"""
    
    def __init__(self, logc, term):
        self.logc = "%-4.4s" % str(logc)
        self.term = term
    
    def __repr__(self):
        return "Logical(%r, %r)" % (self.logc, self.term)
    
    def __str__(self):
        if type(self.term) == ListType and len(self.term) == 2:
            return "%s %s %s" % (nice(self.term[0]),
                                 string.strip(self.logc),
                                 nice(self.term[1]))
        else:
            return "%s(%s)" % (string.strip(self.logc), nice(self.term))
    
    def __aepack__(self):
        return pack({'logc': mkenum(self.logc), 'term': self.term}, 'logi')

def IsLogical(x):
    return isinstance(x, Logical)

class StyledText:
    """An AE object respresenting text in a certain style"""
    
    def __init__(self, style, text):
        self.style = style
        self.text = text
    
    def __repr__(self):
        return "StyledText(%r, %r)" % (self.style, self.text)
    
    def __str__(self):
        return self.text
    
    def __aepack__(self):
        return pack({'ksty': self.style, 'ktxt': self.text}, 'STXT')

def IsStyledText(x):
    return isinstance(x, StyledText)

class AEText:
    """An AE text object with style, script and language specified"""
    
    def __init__(self, script, style, text):
        self.script = script
        self.style = style
        self.text = text
    
    def __repr__(self):
        return "AEText(%r, %r, %r)" % (self.script, self.style, self.text)
    
    def __str__(self):
        return self.text
    
    def __aepack__(self):
        return pack({keyAEScriptTag: self.script, keyAEStyles: self.style,
                 keyAEText: self.text}, typeAEText)

def IsAEText(x):
    return isinstance(x, AEText)

class IntlText:
    """A text object with script and language specified"""
    
    def __init__(self, script, language, text):
        self.script = script
        self.language = language
        self.text = text
    
    def __repr__(self):
        return "IntlText(%r, %r, %r)" % (self.script, self.language, self.text)
    
    def __str__(self):
        return self.text
    
    def __aepack__(self):
        return pack(struct.pack('hh', self.script, self.language)+self.text,
            typeIntlText)

def IsIntlText(x):
    return isinstance(x, IntlText)

class IntlWritingCode:
    """An object representing script and language"""
    
    def __init__(self, script, language):
        self.script = script
        self.language = language
    
    def __repr__(self):
        return "IntlWritingCode(%r, %r)" % (self.script, self.language)
    
    def __str__(self):
        return "script system %d, language %d"%(self.script, self.language)
    
    def __aepack__(self):
        return pack(struct.pack('hh', self.script, self.language),
            typeIntlWritingCode)

def IsIntlWritingCode(x):
    return isinstance(x, IntlWritingCode)

class QDPoint:
    """A point"""
    
    def __init__(self, v, h):
        self.v = v
        self.h = h
    
    def __repr__(self):
        return "QDPoint(%r, %r)" % (self.v, self.h)
    
    def __str__(self):
        return "(%d, %d)"%(self.v, self.h)
    
    def __aepack__(self):
        return pack(struct.pack('hh', self.v, self.h),
            typeQDPoint)

def IsQDPoint(x):
    return isinstance(x, QDPoint)

class QDRectangle:
    """A rectangle"""
    
    def __init__(self, v0, h0, v1, h1):
        self.v0 = v0
        self.h0 = h0
        self.v1 = v1
        self.h1 = h1
    
    def __repr__(self):
        return "QDRectangle(%r, %r, %r, %r)" % (self.v0, self.h0, self.v1, self.h1)
    
    def __str__(self):
        return "(%d, %d)-(%d, %d)"%(self.v0, self.h0, self.v1, self.h1)
    
    def __aepack__(self):
        return pack(struct.pack('hhhh', self.v0, self.h0, self.v1, self.h1),
            typeQDRectangle)

def IsQDRectangle(x):
    return isinstance(x, QDRectangle)

class RGBColor:
    """An RGB color"""
    
    def __init__(self, r, g, b):
        self.r = r
        self.g = g
        self.b = b
            
    def __repr__(self):
        return "RGBColor(%r, %r, %r)" % (self.r, self.g, self.b)
    
    def __str__(self):
        return "0x%x red, 0x%x green, 0x%x blue"% (self.r, self.g, self.b)
    
    def __aepack__(self):
        return pack(struct.pack('hhh', self.r, self.g, self.b),
            typeRGBColor)

def IsRGBColor(x):
    return isinstance(x, RGBColor)

class ObjectSpecifier:
    
    """A class for constructing and manipulation AE object specifiers in python.
    
    An object specifier is actually a record with four fields:
    
    key type    description
    --- ----    -----------
    
    'want'  type    4-char class code of thing we want,
            e.g. word, paragraph or property
    
    'form'  enum    how we specify which 'want' thing(s) we want,
            e.g. by index, by range, by name, or by property specifier
    
    'seld'  any which thing(s) we want,
            e.g. its index, its name, or its property specifier
    
    'from'  object  the object in which it is contained,
            or null, meaning look for it in the application
    
    Note that we don't call this class plain "Object", since that name
    is likely to be used by the application.
    """
    
    def __init__(self, want, form, seld, fr = None):
        self.want = want
        self.form = form
        self.seld = seld
        self.fr = fr
    
    def __repr__(self):
        s = "ObjectSpecifier(%r, %r, %r" % (self.want, self.form, self.seld)
        if self.fr:
            s = s + ", %r)" % (self.fr,)
        else:
            s = s + ")"
        return s
    
    def __aepack__(self):
        return pack({'want': mktype(self.want),
                 'form': mkenum(self.form),
                 'seld': self.seld,
                 'from': self.fr},
                'obj ')

def IsObjectSpecifier(x):
    return isinstance(x, ObjectSpecifier)


# Backwards compatability, sigh...
class Property(ObjectSpecifier):

    def __init__(self, which, fr = None, want='prop'):
        ObjectSpecifier.__init__(self, want, 'prop', mktype(which), fr)

    def __repr__(self):
        if self.fr:
            return "Property(%r, %r)" % (self.seld.type, self.fr)
        else:
            return "Property(%r)" % (self.seld.type,)
    
    def __str__(self):
        if self.fr:
            return "Property %s of %s" % (str(self.seld), str(self.fr))
        else:
            return "Property %s" % str(self.seld)


class NProperty(ObjectSpecifier):
    # Subclasses *must* self baseclass attributes:
    # want is the type of this property
    # which is the property name of this property

    def __init__(self, fr = None):
        #try:
        #   dummy = self.want
        #except:
        #   self.want = 'prop'
        self.want = 'prop'
        ObjectSpecifier.__init__(self, self.want, 'prop', 
                    mktype(self.which), fr)

    def __repr__(self):
        rv = "Property(%r" % (self.seld.type,)
        if self.fr:
            rv = rv + ", fr=%r" % (self.fr,)
        if self.want != 'prop':
            rv = rv + ", want=%r" % (self.want,)
        return rv + ")"
    
    def __str__(self):
        if self.fr:
            return "Property %s of %s" % (str(self.seld), str(self.fr))
        else:
            return "Property %s" % str(self.seld)


class SelectableItem(ObjectSpecifier):
    
    def __init__(self, want, seld, fr = None):
        t = type(seld)
        if t == StringType:
            form = 'name'
        elif IsRange(seld):
            form = 'rang'
        elif IsComparison(seld) or IsLogical(seld):
            form = 'test'
        elif t == TupleType:
            # Breakout: specify both form and seld in a tuple
            # (if you want ID or rele or somesuch)
            form, seld = seld
        else:
            form = 'indx'
        ObjectSpecifier.__init__(self, want, form, seld, fr)


class ComponentItem(SelectableItem):
    # Derived classes *must* set the *class attribute* 'want' to some constant
    # Also, dictionaries _propdict and _elemdict must be set to map property
    # and element names to the correct classes

    _propdict = {}
    _elemdict = {}
    def __init__(self, which, fr = None):
        SelectableItem.__init__(self, self.want, which, fr)
    
    def __repr__(self):
        if not self.fr:
            return "%s(%r)" % (self.__class__.__name__, self.seld)
        return "%s(%r, %r)" % (self.__class__.__name__, self.seld, self.fr)
    
    def __str__(self):
        seld = self.seld
        if type(seld) == StringType:
            ss = repr(seld)
        elif IsRange(seld):
            start, stop = seld.start, seld.stop
            if type(start) == InstanceType == type(stop) and \
               start.__class__ == self.__class__ == stop.__class__:
                ss = str(start.seld) + " thru " + str(stop.seld)
            else:
                ss = str(seld)
        else:
            ss = str(seld)
        s = "%s %s" % (self.__class__.__name__, ss)
        if self.fr: s = s + " of %s" % str(self.fr)
        return s
        
    def __getattr__(self, name):
        if self._elemdict.has_key(name):
            cls = self._elemdict[name]
            return DelayedComponentItem(cls, self)
        if self._propdict.has_key(name):
            cls = self._propdict[name]
            return cls(self)
        raise AttributeError, name
        
        
class DelayedComponentItem:
    def __init__(self, compclass, fr):
        self.compclass = compclass
        self.fr = fr
        
    def __call__(self, which):
        return self.compclass(which, self.fr)
        
    def __repr__(self):
        return "%s(???, %r)" % (self.__class__.__name__, self.fr)
        
    def __str__(self):
        return "selector for element %s of %s"%(self.__class__.__name__, str(self.fr))

template = """
class %s(ComponentItem): want = '%s'
"""

exec template % ("Text", 'text')
exec template % ("Character", 'cha ')
exec template % ("Word", 'cwor')
exec template % ("Line", 'clin')
exec template % ("paragraph", 'cpar')
exec template % ("Window", 'cwin')
exec template % ("Document", 'docu')
exec template % ("File", 'file')
exec template % ("InsertionPoint", 'cins')


--- NEW FILE: applesingle.py ---
r"""Routines to decode AppleSingle files
"""
import struct
import sys
try:
    import MacOS
    import Carbon.File
except:
    class MacOS:
        def openrf(path, mode):
            return open(path + '.rsrc', mode)
        openrf = classmethod(openrf)
    class Carbon:
        class File:
            class FSSpec:
                pass
            class FSRef:
                pass
            class Alias:
                pass

# all of the errors in this module are really errors in the input
# so I think it should test positive against ValueError.
class Error(ValueError):
    pass

# File header format: magic, version, unused, number of entries
AS_HEADER_FORMAT="LL16sh"
AS_HEADER_LENGTH=26
# The flag words for AppleSingle
AS_MAGIC=0x00051600
AS_VERSION=0x00020000

# Entry header format: id, offset, length
AS_ENTRY_FORMAT="lll"
AS_ENTRY_LENGTH=12

# The id values
AS_DATAFORK=1
AS_RESOURCEFORK=2
AS_IGNORE=(3,4,5,6,8,9,10,11,12,13,14,15)

class AppleSingle(object):
    datafork = None
    resourcefork = None

    def __init__(self, fileobj, verbose=False):
        header = fileobj.read(AS_HEADER_LENGTH)
        try:
            magic, version, ig, nentry = struct.unpack(AS_HEADER_FORMAT, header)
        except ValueError, arg:
            raise Error, "Unpack header error: %s" % (arg,)
        if verbose:
            print 'Magic:   0x%8.8x' % (magic,)
            print 'Version: 0x%8.8x' % (version,)
            print 'Entries: %d' % (nentry,)
        if magic != AS_MAGIC:
            raise Error, "Unknown AppleSingle magic number 0x%8.8x" % (magic,)
        if version != AS_VERSION:
            raise Error, "Unknown AppleSingle version number 0x%8.8x" % (version,)
        if nentry <= 0:
            raise Error, "AppleSingle file contains no forks"
        headers = [fileobj.read(AS_ENTRY_LENGTH) for i in xrange(nentry)]
        self.forks = []
        for hdr in headers:
            try:
                restype, offset, length = struct.unpack(AS_ENTRY_FORMAT, hdr)
            except ValueError, arg:
                raise Error, "Unpack entry error: %s" % (arg,)
            if verbose:
                print "Fork %d, offset %d, length %d" % (restype, offset, length)
            fileobj.seek(offset)
            data = fileobj.read(length)
            if len(data) != length:
                raise Error, "Short read: expected %d bytes got %d" % (length, len(data))
            self.forks.append((restype, data))
            if restype == AS_DATAFORK:
                self.datafork = data
            elif restype == AS_RESOURCEFORK:
                self.resourcefork = data
        
    def tofile(self, path, resonly=False):
        outfile = open(path, 'wb')
        data = False
        if resonly:
            if self.resourcefork is None:
                raise Error, "No resource fork found"
            fp = open(path, 'wb')
            fp.write(self.resourcefork)
            fp.close()
        elif (self.resourcefork is None and self.datafork is None):
            raise Error, "No useful forks found"
        else:
            if self.datafork is not None:
                fp = open(path, 'wb')
                fp.write(self.datafork)
                fp.close()
            if self.resourcefork is not None:
                fp = MacOS.openrf(path, '*wb')
                fp.write(self.resourcefork)
                fp.close()
    
def decode(infile, outpath, resonly=False, verbose=False):
    """decode(infile, outpath [, resonly=False, verbose=False])

    Creates a decoded file from an AppleSingle encoded file.
    If resonly is True, then it will create a regular file at 
    outpath containing only the resource fork from infile.
    Otherwise it will create an AppleDouble file at outpath
    with the data and resource forks from infile.  On platforms 
    without the MacOS module, it will create inpath and inpath+'.rsrc'
    with the data and resource forks respectively.

    """
    if not hasattr(infile, 'read'):
        if isinstance(infile, Carbon.File.Alias):
            infile = infile.ResolveAlias()[0]
        if isinstance(infile, (Carbon.File.FSSpec, Carbon.File.FSRef)):
            infile = infile.as_pathname()
        infile = open(infile, 'rb')

    as = AppleSingle(infile, verbose=verbose)
    as.tofile(outpath, resonly=resonly)
    
def _test():
    if len(sys.argv) < 3 or sys.argv[1] == '-r' and len(sys.argv) != 4:
        print 'Usage: applesingle.py [-r] applesinglefile decodedfile'
        sys.exit(1)
    if sys.argv[1] == '-r':
        resonly = True
        del sys.argv[1]
    else:
        resonly = False
    decode(sys.argv[1], sys.argv[2], resonly=resonly)
    
if __name__ == '__main__':
    _test()

--- NEW FILE: appletrawmain.py ---
# Emulate sys.argv and run __main__.py or __main__.pyc in an environment that
# is as close to "normal" as possible.
#
# This script is put into __rawmain__.pyc for applets that need argv
# emulation, by BuildApplet and friends.
#
import argvemulator
import os
import sys
import marshal

#
# Make sure we have an argv[0], and make _dir point to the Resources
# directory.
#
if not sys.argv or sys.argv[0][:1] == '-':
    # Insert our (guessed) name.
    _dir = os.path.split(sys.executable)[0] # removes "python"
    _dir = os.path.split(_dir)[0] # Removes "MacOS"
    _dir = os.path.join(_dir, 'Resources')
    sys.argv.insert(0, '__rawmain__')
else:
    _dir = os.path.split(sys.argv[0])[0]
#
# Add the Resources directory to the path. This is where files installed
# by BuildApplet.py with the --extra option show up, and if those files are 
# modules this sys.path modification is necessary to be able to import them.
#
sys.path.insert(0, _dir)
#
# Create sys.argv
#
argvemulator.ArgvCollector().mainloop()
#
# Find the real main program to run
#
__file__ = os.path.join(_dir, '__main__.py')
if os.path.exists(__file__):
    #
    # Setup something resembling a normal environment and go.
    #
    sys.argv[0] = __file__
    del argvemulator, os, sys, _dir
    execfile(__file__)
else:
    __file__ = os.path.join(_dir, '__main__.pyc')
    if os.path.exists(__file__):
        #
        # If we have only a .pyc file we read the code object from that
        #
        sys.argv[0] = __file__
        _fp = open(__file__, 'rb')
        _fp.read(8)
        __code__ = marshal.load(_fp)
        #
        # Again, we create an almost-normal environment (only __code__ is
        # funny) and go.
        #
        del argvemulator, os, sys, marshal, _dir, _fp
        exec __code__
    else:
        sys.stderr.write("%s: neither __main__.py nor __main__.pyc found\n"%sys.argv[0])
        sys.exit(1)

--- NEW FILE: appletrunner.py ---
#!/usr/bin/env python
# This file is meant as an executable script for running applets.
# BuildApplet will use it as the main executable in the .app bundle if
# we are not running in a framework build.

import os
import sys
for name in ["__rawmain__.py", "__rawmain__.pyc", "__main__.py", "__main__.pyc"]:
    realmain = os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])),
                      "Resources", name)
    if os.path.exists(realmain):
        break
else:
    sys.stderr.write("%s: cannot find applet main program\n" % sys.argv[0])
    sys.exit(1)
sys.argv.insert(1, realmain)
os.execve(sys.executable, sys.argv, os.environ)

--- NEW FILE: argvemulator.py ---
"""argvemulator - create sys.argv from OSA events. Used by applets that
want unix-style arguments.
"""

import sys
import traceback
from Carbon import AE
from Carbon.AppleEvents import *
from Carbon import Evt
from Carbon.Events import *
import aetools

class ArgvCollector:

    """A minimal FrameWork.Application-like class"""

    def __init__(self):
        self.quitting = 0
        self.ae_handlers = {}
        # Remove the funny -psn_xxx_xxx argument
        if len(sys.argv) > 1 and sys.argv[1][:4] == '-psn':
            del sys.argv[1]
        self.installaehandler('aevt', 'oapp', self.open_app)
        self.installaehandler('aevt', 'odoc', self.open_file)

    def installaehandler(self, classe, type, callback):
        AE.AEInstallEventHandler(classe, type, self.callback_wrapper)
        self.ae_handlers[(classe, type)] = callback

    def close(self):
        for classe, type in self.ae_handlers.keys():
            AE.AERemoveEventHandler(classe, type)

    def mainloop(self, mask = highLevelEventMask, timeout = 1*60):
        stoptime = Evt.TickCount() + timeout
        while not self.quitting and Evt.TickCount() < stoptime:
            self.dooneevent(mask, timeout)
        self.close()

    def _quit(self):
        self.quitting = 1

    def dooneevent(self, mask = highLevelEventMask, timeout = 1*60):
        got, event = Evt.WaitNextEvent(mask, timeout)
        if got:
            self.lowlevelhandler(event)

    def lowlevelhandler(self, event):
        what, message, when, where, modifiers = event
        h, v = where
        if what == kHighLevelEvent:
            try:
                AE.AEProcessAppleEvent(event)
            except AE.Error, err:
                msg = "High Level Event: %r %r" % (hex(message), hex(h | (v<<16)))
                print 'AE error: ', err
                print 'in', msg
                traceback.print_exc()
            return
        else:
            print "Unhandled event:", event

    def callback_wrapper(self, _request, _reply):
        _parameters, _attributes = aetools.unpackevent(_request)
        _class = _attributes['evcl'].type
        _type = _attributes['evid'].type

        if self.ae_handlers.has_key((_class, _type)):
            _function = self.ae_handlers[(_class, _type)]
        elif self.ae_handlers.has_key((_class, '****')):
            _function = self.ae_handlers[(_class, '****')]
        elif self.ae_handlers.has_key(('****', '****')):
            _function = self.ae_handlers[('****', '****')]
        else:
            raise 'Cannot happen: AE callback without handler', (_class, _type)

        # XXXX Do key-to-name mapping here

        _parameters['_attributes'] = _attributes
        _parameters['_class'] = _class
        _parameters['_type'] = _type
        if _parameters.has_key('----'):
            _object = _parameters['----']
            del _parameters['----']
            # The try/except that used to be here can mask programmer errors.
            # Let the program crash, the programmer can always add a **args
            # to the formal parameter list.
            rv = _function(_object, **_parameters)
        else:
            #Same try/except comment as above
            rv = _function(**_parameters)

        if rv == None:
            aetools.packevent(_reply, {})
        else:
            aetools.packevent(_reply, {'----':rv})

    def open_app(self, **args):
        self._quit()

    def open_file(self, _object=None, **args):
        for alias in _object:
            fsr = alias.FSResolveAlias(None)[0]
            pathname = fsr.as_pathname()
            sys.argv.append(pathname)
        self._quit()

    def other(self, _object=None, _class=None, _type=None, **args):
        print 'Ignore AppleEvent', (_class, _type), 'for', _object, 'Other args:', args

if __name__ == '__main__':
    ArgvCollector().mainloop()
    print "sys.argv=", sys.argv

--- NEW FILE: bgenlocations.py ---
#
# Local customizations for generating the Carbon interface modules.
# Edit this file to reflect where things should be on your system.
# Note that pathnames are unix-style for OSX MachoPython/unix-Python,
# but mac-style for MacPython, whether running on OS9 or OSX.
#

import sys, os

Error = "bgenlocations.Error"
#
# Where bgen is. For unix-Python bgen isn't installed, so you have to refer to
# the source tree here.
BGENDIR="/Users/jack/src/python/Tools/bgen/bgen"

#
# Where to find the Universal Header include files. If you have CodeWarrior
# installed you can use the Universal Headers from there, otherwise you can
# download them from the Apple website. Bgen can handle both unix- and mac-style
# end of lines, so don't worry about that.
#
INCLUDEDIR="/Users/jack/src/Universal/Interfaces/CIncludes"

#
# Where to put the python definitions files. Note that, on unix-Python,
# if you want to commit your changes to the CVS repository this should refer to
# your source directory, not your installed directory.
#
TOOLBOXDIR="/Users/jack/src/python/Lib/plat-mac/Carbon"

# Creator for C files:
CREATOR="CWIE"

if not os.path.exists(BGENDIR):
    raise Error, "Please fix bgenlocations.py, BGENDIR does not exist: %s" % BGENDIR
if not os.path.exists(INCLUDEDIR):
    raise Error, "Please fix bgenlocations.py, INCLUDEDIR does not exist: %s" % INCLUDEDIR
if not os.path.exists(TOOLBOXDIR):
    raise Error, "Please fix bgenlocations.py, TOOLBOXDIR does not exist: %s" % TOOLBOXDIR
    
# Sigh, due to the way these are used make sure they end with : or /.
if BGENDIR[-1] != os.sep:
    BGENDIR = BGENDIR + os.sep
if INCLUDEDIR[-1] != os.sep:
    INCLUDEDIR = INCLUDEDIR + os.sep
if TOOLBOXDIR[-1] != os.sep:
    TOOLBOXDIR = TOOLBOXDIR + os.sep
    

--- NEW FILE: buildtools.py ---
"""tools for BuildApplet and BuildApplication"""

import sys
import os
import string
import imp
import marshal
from Carbon import Res
import Carbon.Files
import Carbon.File
import MacOS
import macostools
import macresource
import EasyDialogs
import shutil


BuildError = "BuildError"

# .pyc file (and 'PYC ' resource magic number)
MAGIC = imp.get_magic()

# Template file (searched on sys.path)
TEMPLATE = "PythonInterpreter"

# Specification of our resource
RESTYPE = 'PYC '
RESNAME = '__main__'

# A resource with this name sets the "owner" (creator) of the destination
# It should also have ID=0. Either of these alone is not enough.
OWNERNAME = "owner resource"

# Default applet creator code
DEFAULT_APPLET_CREATOR="Pyta"

# OpenResFile mode parameters
READ = 1
WRITE = 2

# Parameter for FSOpenResourceFile
RESOURCE_FORK_NAME=Carbon.File.FSGetResourceForkName()

def findtemplate(template=None):
    """Locate the applet template along sys.path"""
    if MacOS.runtimemodel == 'macho':
        return None
    if not template:
        template=TEMPLATE
    for p in sys.path:
        file = os.path.join(p, template)
        try:
            file, d1, d2 = Carbon.File.FSResolveAliasFile(file, 1)
            break
        except (Carbon.File.Error, ValueError):
            continue
    else:
        raise BuildError, "Template %r not found on sys.path" % (template,)
    file = file.as_pathname()
    return file
    
def process(template, filename, destname, copy_codefragment=0, 
        rsrcname=None, others=[], raw=0, progress="default"):
    
    if progress == "default":
        progress = EasyDialogs.ProgressBar("Processing %s..."%os.path.split(filename)[1], 120)
        progress.label("Compiling...")
        progress.inc(0)
    # check for the script name being longer than 32 chars. This may trigger a bug
    # on OSX that can destroy your sourcefile.
    if '#' in os.path.split(filename)[1]:
        raise BuildError, "BuildApplet could destroy your sourcefile on OSX, please rename: %s" % filename
    # Read the source and compile it
    # (there's no point overwriting the destination if it has a syntax error)
    
    fp = open(filename, 'rU')
    text = fp.read()
    fp.close()
    try:
        code = compile(text + '\n', filename, "exec")
    except SyntaxError, arg:
        raise BuildError, "Syntax error in script %s: %s" % (filename, arg)
    except EOFError:
        raise BuildError, "End-of-file in script %s" % (filename,)
    
    # Set the destination file name. Note that basename
    # does contain the whole filepath, only a .py is stripped.
    
    if string.lower(filename[-3:]) == ".py":
        basename = filename[:-3]
        if MacOS.runtimemodel != 'macho' and not destname:
            destname = basename
    else:
        basename = filename
        
    if not destname:
        if MacOS.runtimemodel == 'macho':
            destname = basename + '.app'
        else:
            destname = basename + '.applet'
    if not rsrcname:
        rsrcname = basename + '.rsrc'
        
    # Try removing the output file. This fails in MachO, but it should
    # do any harm.
    try:
        os.remove(destname)
    except os.error:
        pass
    process_common(template, progress, code, rsrcname, destname, 0, 
        copy_codefragment, raw, others, filename)
    

def update(template, filename, output):
    if MacOS.runtimemodel == 'macho':
        raise BuildError, "No updating yet for MachO applets"
    if progress:
        progress = EasyDialogs.ProgressBar("Updating %s..."%os.path.split(filename)[1], 120)
    else:
        progress = None
    if not output:
        output = filename + ' (updated)'
    
    # Try removing the output file
    try:
        os.remove(output)
    except os.error:
        pass
    process_common(template, progress, None, filename, output, 1, 1)


def process_common(template, progress, code, rsrcname, destname, is_update, 
        copy_codefragment, raw=0, others=[], filename=None):
    if MacOS.runtimemodel == 'macho':
        return process_common_macho(template, progress, code, rsrcname, destname,
            is_update, raw, others, filename)
    if others:
        raise BuildError, "Extra files only allowed for MachoPython applets"
    # Create FSSpecs for the various files
    template_fsr, d1, d2 = Carbon.File.FSResolveAliasFile(template, 1)
    template = template_fsr.as_pathname()
    
    # Copy data (not resources, yet) from the template
    if progress:
        progress.label("Copy data fork...")
        progress.set(10)
    
    if copy_codefragment:
        tmpl = open(template, "rb")
        dest = open(destname, "wb")
        data = tmpl.read()
        if data:
            dest.write(data)
        dest.close()
        tmpl.close()
        del dest
        del tmpl
    
    # Open the output resource fork
    
    if progress:
        progress.label("Copy resources...")
        progress.set(20)
    try:
        output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE)
    except MacOS.Error:
        destdir, destfile = os.path.split(destname)
        Res.FSCreateResourceFile(destdir, unicode(destfile), RESOURCE_FORK_NAME)
        output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE)
    
    # Copy the resources from the target specific resource template, if any
    typesfound, ownertype = [], None
    try:
        input = Res.FSOpenResourceFile(rsrcname, RESOURCE_FORK_NAME, READ)
    except (MacOS.Error, ValueError):
        pass
        if progress:
            progress.inc(50)
    else:
        if is_update:
            skip_oldfile = ['cfrg']
        else:
            skip_oldfile = []
        typesfound, ownertype = copyres(input, output, skip_oldfile, 0, progress)
        Res.CloseResFile(input)
    
    # Check which resource-types we should not copy from the template
    skiptypes = []
    if 'vers' in typesfound: skiptypes.append('vers')
    if 'SIZE' in typesfound: skiptypes.append('SIZE')
    if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4', 
            'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
    if not copy_codefragment:
        skiptypes.append('cfrg')
##  skipowner = (ownertype <> None)
    
    # Copy the resources from the template
    
    input = Res.FSOpenResourceFile(template, RESOURCE_FORK_NAME, READ)
    dummy, tmplowner = copyres(input, output, skiptypes, 1, progress)
        
    Res.CloseResFile(input)
##  if ownertype == None:
##      raise BuildError, "No owner resource found in either resource file or template"
    # Make sure we're manipulating the output resource file now
    
    Res.UseResFile(output)

    if ownertype == None:
        # No owner resource in the template. We have skipped the
        # Python owner resource, so we have to add our own. The relevant
        # bundle stuff is already included in the interpret/applet template.
        newres = Res.Resource('\0')
        newres.AddResource(DEFAULT_APPLET_CREATOR, 0, "Owner resource")
        ownertype = DEFAULT_APPLET_CREATOR
    
    if code:
        # Delete any existing 'PYC ' resource named __main__
        
        try:
            res = Res.Get1NamedResource(RESTYPE, RESNAME)
            res.RemoveResource()
        except Res.Error:
            pass
        
        # Create the raw data for the resource from the code object
        if progress:
            progress.label("Write PYC resource...")
            progress.set(120)
        
        data = marshal.dumps(code)
        del code
        data = (MAGIC + '\0\0\0\0') + data
        
        # Create the resource and write it
        
        id = 0
        while id < 128:
            id = Res.Unique1ID(RESTYPE)
        res = Res.Resource(data)
        res.AddResource(RESTYPE, id, RESNAME)
        attrs = res.GetResAttrs()
        attrs = attrs | 0x04    # set preload
        res.SetResAttrs(attrs)
        res.WriteResource()
        res.ReleaseResource()
    
    # Close the output file
    
    Res.CloseResFile(output)
    
    # Now set the creator, type and bundle bit of the destination.
    # Done with FSSpec's, FSRef FInfo isn't good enough yet (2.3a1+)
    dest_fss = Carbon.File.FSSpec(destname)
    dest_finfo = dest_fss.FSpGetFInfo()
    dest_finfo.Creator = ownertype
    dest_finfo.Type = 'APPL'
    dest_finfo.Flags = dest_finfo.Flags | Carbon.Files.kHasBundle | Carbon.Files.kIsShared
    dest_finfo.Flags = dest_finfo.Flags & ~Carbon.Files.kHasBeenInited
    dest_fss.FSpSetFInfo(dest_finfo)
    
    macostools.touched(destname)
    if progress:
        progress.label("Done.")
        progress.inc(0)

def process_common_macho(template, progress, code, rsrcname, destname, is_update, 
        raw=0, others=[], filename=None):
    # Check that we have a filename
    if filename is None:
        raise BuildError, "Need source filename on MacOSX"
    # First make sure the name ends in ".app"
    if destname[-4:] != '.app':
        destname = destname + '.app'
    # Now deduce the short name
    destdir, shortname = os.path.split(destname)
    if shortname[-4:] == '.app':
        # Strip the .app suffix
        shortname = shortname[:-4]
    # And deduce the .plist and .icns names
    plistname = None
    icnsname = None
    if rsrcname and rsrcname[-5:] == '.rsrc':
        tmp = rsrcname[:-5]
        plistname = tmp + '.plist'
        if os.path.exists(plistname):
            icnsname = tmp + '.icns'
            if not os.path.exists(icnsname):
                icnsname = None
        else:
            plistname = None
    if not icnsname:
        dft_icnsname = os.path.join(sys.prefix, 'Resources/Python.app/Contents/Resources/PythonApplet.icns')
        if os.path.exists(dft_icnsname):
            icnsname = dft_icnsname
    if not os.path.exists(rsrcname):
        rsrcname = None
    if progress:
        progress.label('Creating bundle...')
    import bundlebuilder
    builder = bundlebuilder.AppBuilder(verbosity=0)
    builder.mainprogram = filename
    builder.builddir = destdir
    builder.name = shortname
    if rsrcname:
        realrsrcname = macresource.resource_pathname(rsrcname)
        builder.files.append((realrsrcname, 
            os.path.join('Contents/Resources', os.path.basename(rsrcname))))
    for o in others:
        if type(o) == str:
            builder.resources.append(o)
        else:
            builder.files.append(o)
    if plistname:
        import plistlib
        builder.plist = plistlib.Plist.fromFile(plistname)
    if icnsname:
        builder.iconfile = icnsname
    if not raw:
        builder.argv_emulation = 1
    builder.setup()
    builder.build()
    if progress: 
        progress.label('Done.')
        progress.inc(0)
    
##  macostools.touched(dest_fss)

# Copy resources between two resource file descriptors.
# skip a resource named '__main__' or (if skipowner is set) with ID zero.
# Also skip resources with a type listed in skiptypes.
#
def copyres(input, output, skiptypes, skipowner, progress=No