[Python-checkins] python/dist/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 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 plistlib.py,NONE,1.1 videoreader.py,NONE,1.1
jackjansen@users.sourceforge.net
jackjansen@users.sourceforge.net
Mon, 30 Dec 2002 14:04:23 -0800
- Previous message: [Python-checkins] python/dist/src/Mac/Lib/lib-scriptpackages/_builtinSuites __init__.py,1.1,NONE builtin_Suite.py,1.2,NONE
- Next message: [Python-checkins] python/dist/src/Lib/plat-mac/Carbon AE.py,NONE,1.1 AH.py,NONE,1.1 Alias.py,NONE,1.1 Aliases.py,NONE,1.1 App.py,NONE,1.1 Appearance.py,NONE,1.1 AppleEvents.py,NONE,1.1 AppleHelp.py,NONE,1.1 CF.py,NONE,1.1 CG.py,NONE,1.1 CarbonEvents.py,NONE,1.1 CarbonEvt.py,NONE,1.1 Cm.py,NONE,1.1 Components.py,NONE,1.1 ControlAccessor.py,NONE,1.1 Controls.py,NONE,1.1 CoreFoundation.py,NONE,1.1 CoreGraphics.py,NONE,1.1 Ctl.py,NONE,1.1 Dialogs.py,NONE,1.1 Dlg.py,NONE,1.1 Drag.py,NONE,1.1 Dragconst.py,NONE,1.1 Events.py,NONE,1.1 Evt.py,NONE,1.1 File.py,NONE,1.1 Files.py,NONE,1.1 Fm.py,NONE,1.1 Folder.py,NONE,1.1 Folders.py,NONE,1.1 Fonts.py,NONE,1.1 Help.py,NONE,1.1 IBCarbon.py,NONE,1.1 IBCarbonRuntime.py,NONE,1.1 Icn.py,NONE,1.1 Icons.py,NONE,1.1 List.py,NONE,1.1 Lists.py,NONE,1.1 MacHelp.py,NONE,1.1 MacTextEditor.py,NONE,1.1 MediaDescr.py,NONE,1.1 Menu.py,NONE,1.1 Menus.py,NONE,1.1 Mlte.py,NONE,1.1 QDOffscreen.py,NONE,1.1 Qd.py,NONE,1.1 Qdoffs.py,NONE,1.1 Qt.py,NONE,1.1 QuickDraw.py,NONE,1.1 QuickTime.py,NONE,1.1 Res.py,NONE,1.1 Resources.py,NONE,1.1 Scrap.py,NONE,1.1 Snd.py,NONE,1.1 Sndihooks.py,NONE,1.1 Sound.py,NONE,1.1 TE.py,NONE,1.1 TextEdit.py,NONE,1.1 WASTEconst.py,NONE,1.1 Win.py,NONE,1.1 Windows.py,NONE,1.1 __init__.py,NONE,1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvsroot/python/python/dist/src/Lib/plat-mac
In directory sc8-pr-cvs1:/tmp/cvs-serv29062/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 ic.py icopen.py macerrors.py macfs.py
macostools.py macresource.py plistlib.py videoreader.py
Log Message:
Moved most of Mac/Lib hierarchy to Lib/plat-mac: it can be used both
in MacPython-OS9 and MacPython-OSX (or the equivalent unix Python on
Mac OS X). The only items remaining in Mac/Lib are modules that are
meaningful only for MacPython-OS9 (CFM stuff, MacPython preferences
in resources, etc).
--- 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 macfs
fss, ok = macfs.PromptGetFile("Select an AIFF soundfile", "AIFF")
if not ok: return
fn = fss.as_pathname()
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.
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
import MacOS
import string
from Carbon.ControlAccessor import * # Also import Controls constants
import macfs
import macresource
_initialized = 0
def _initialize():
global _initialized
if _initialized: return
macresource.need("DLOG", 260, "dialogs.rsrc", __name__)
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()
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()
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()
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()
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
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()
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:
fss, ok = macfs.StandardGetFile()
if ok:
stringstoadd = [fss.as_pathname()]
elif n == ARGV_ADD_NEWFILE:
fss, ok = macfs.StandardPutFile('')
if ok:
stringstoadd = [fss.as_pathname()]
elif n == ARGV_ADD_FOLDER:
fss, ok = macfs.GetDirectory()
if ok:
stringstoadd = [fss.as_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 = `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'):
apply(MacOS.SchedParams, appsw)
del d
def test():
import time, sys
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)
for i in range(len(argv)):
print 'arg[%d] = %s'%(i, `argv[i]`)
print 'Type return to continue - ',
sys.stdin.readline()
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))
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'):
apply(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 *
[...1081 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: %s %s" % \
(`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 = apply(_function, (_object,), _parameters)
else:
#Same try/except comment as above
rv = apply(_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@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 macfs
import Image
fsspec, ok = macfs.PromptGetFile("Image File:")
if not ok: return
path = fsspec.as_pathname()
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 macfs
import StringIO
import aetypes
from aetypes import mkenum, mktype
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 = macfs.FSSpecType
AliasType = macfs.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', '')
t = type(x)
if t == AEDescType:
return x
if t == FSSType:
return AE.AECreateDesc('fss ', x.data)
if t == AliasType:
return AE.AECreateDesc('alis', x.data)
if t == IntType:
return AE.AECreateDesc('long', struct.pack('l', x))
if t == FloatType:
return AE.AECreateDesc('doub', struct.pack('d', x))
if t == StringType:
return AE.AECreateDesc('TEXT', x)
if t == UnicodeType:
data = t.encode('utf16')
if data[:2] == '\xfe\xff':
data = data[2:]
return AE.AECreateDesc('utxt', data)
if t == ListType:
list = AE.AECreateList('', 0)
for item in x:
list.AEPutDesc(0, pack(item))
return list
if t == DictionaryType:
record = AE.AECreateList('', 1)
for key, value in x.items():
packkey(record, key, value)
#record.AEPutParamDesc(key, pack(value))
return record
if t == InstanceType and 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 macfs.RawAlias(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 macfs.RawFSSpec(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)
#
# 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):
want = dict['want'].type
module = __import__(modulename)
codenamemapper = module._classdeclarations
classtype = codenamemapper.get(want, None)
newobj = mkobject(dict)
if classtype:
newobj.__class__ = classtype
return newobj
def _test():
"""Test program. Pack and unpack various things"""
objs = [
'a string',
12,
12.0,
None,
['a', 'list', 'of', 'strings'],
{'key1': 'value1', 'key2':'value2'},
macfs.FSSpec(':'),
macfs.FSSpec(':').NewAliasMinimal(),
aetypes.Enum('enum'),
aetypes.Type('type'),
aetypes.Keyword('kwrd'),
aetypes.Range(1, 10),
aetypes.Comparison(1, '< ', 10),
aetypes.Logical('not ', 1),
# Cannot do StyledText
# Cannot do AEText
aetypes.IntlText(0, 0, 'international text'),
aetypes.IntlWritingCode(0,0),
aetypes.QDPoint(50,100),
aetypes.QDRectangle(50,100,150,200),
aetypes.RGBColor(0x7000, 0x6000, 0x5000),
aetypes.Unknown('xxxx', 'unknown type data'),
aetypes.Character(1),
aetypes.Character(2, aetypes.Line(2)),
]
for o in objs:
print 'BEFORE', o, `o`
packed = pack(o)
unpacked = unpack(packed)
print 'AFTER ', unpacked, `unpacked`
import sys
sys.exit(1)
if __name__ == '__main__':
_test()
--- 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 AppleEvents
import MacOS
import sys
from aetypes import *
from aepack import packkey, pack, unpack, coerce, AEDescType
Error = 'aetools.Error'
# Special code to unpack an AppleEvent (which is *not* a disguised record!)
# Note by Jack: No??!? If I read the docs correctly it *is*....
aekeywords = [
'tran',
'rtid',
'evcl',
'evid',
'addr',
'optk',
'timo',
'inte', # this attribute is read only - will be set in AESend
'esrc', # this attribute is read only
'miss', # this attribute is read only
'from' # new in 1.0.1
]
def missed(ae):
try:
desc = ae.AEGetAttributeDesc('miss', 'keyw')
except AE.Error, msg:
return None
return desc.data
def unpackevent(ae, formodulename=""):
parameters = {}
try:
dirobj = ae.AEGetParamDesc('----', '****')
except AE.Error:
pass
else:
parameters['----'] = unpack(dirobj, formodulename)
del dirobj
# Workaround for what I feel is a bug in OSX 10.2: 'errn' won't show up in missed...
try:
dirobj = ae.AEGetParamDesc('errn', '****')
except AE.Error:
pass
else:
parameters['errn'] = unpack(dirobj, formodulename)
del dirobj
while 1:
key = missed(ae)
if not key: break
parameters[key] = unpack(ae.AEGetParamDesc(key, '****'), formodulename)
attributes = {}
for key in aekeywords:
try:
desc = ae.AEGetAttributeDesc(key, '****')
except (AE.Error, MacOS.Error), msg:
if msg[0] != -1701 and msg[0] != -1704:
raise sys.exc_type, sys.exc_value
continue
attributes[key] = unpack(desc, formodulename)
return parameters, attributes
def packevent(ae, parameters = {}, attributes = {}):
for key, value in parameters.items():
packkey(ae, key, value)
for key, value in attributes.items():
packkey(ae, key, value)
#
# Support routine for automatically generated Suite interfaces
# These routines are also useable for the reverse function.
#
def keysubst(arguments, keydict):
"""Replace long name keys by their 4-char counterparts, and check"""
ok = keydict.values()
for k in arguments.keys():
if keydict.has_key(k):
v = arguments[k]
del arguments[k]
arguments[keydict[k]] = v
elif k != '----' and k not in ok:
raise TypeError, 'Unknown keyword argument: %s'%k
def enumsubst(arguments, key, edict):
"""Substitute a single enum keyword argument, if it occurs"""
if not arguments.has_key(key) or edict is None:
return
v = arguments[key]
ok = edict.values()
if edict.has_key(v):
arguments[key] = edict[v]
elif not v in ok:
raise TypeError, 'Unknown enumerator: %s'%v
def decodeerror(arguments):
"""Create the 'best' argument for a raise MacOS.Error"""
errn = arguments['errn']
err_a1 = errn
if arguments.has_key('errs'):
err_a2 = arguments['errs']
else:
err_a2 = MacOS.GetErrorString(errn)
if arguments.has_key('erob'):
err_a3 = arguments['erob']
else:
err_a3 = None
return (err_a1, err_a2, err_a3)
class TalkTo:
"""An AE connection to an application"""
_signature = None # Can be overridden by subclasses
_moduleName = None # Can be overridden by subclasses
def __init__(self, signature=None, start=0, timeout=0):
"""Create a communication channel with a particular application.
Addressing the application is done by specifying either a
4-byte signature, an AEDesc or an object that will __aepack__
to an AEDesc.
"""
self.target_signature = None
if signature is None:
signature = self._signature
if type(signature) == AEDescType:
self.target = signature
elif type(signature) == InstanceType and hasattr(signature, '__aepack__'):
self.target = signature.__aepack__()
elif type(signature) == StringType and len(signature) == 4:
self.target = AE.AECreateDesc(AppleEvents.typeApplSignature, signature)
self.target_signature = signature
else:
raise TypeError, "signature should be 4-char string or AEDesc"
self.send_flags = AppleEvents.kAEWaitReply
self.send_priority = AppleEvents.kAENormalPriority
if timeout:
self.send_timeout = timeout
else:
self.send_timeout = AppleEvents.kAEDefaultTimeout
if start:
self._start()
def _start(self):
"""Start the application, if it is not running yet"""
try:
self.send('ascr', 'noop')
except AE.Error:
_launch(self.target_signature)
def start(self):
"""Deprecated, used _start()"""
self._start()
def newevent(self, code, subcode, parameters = {}, attributes = {}):
"""Create a complete structure for an apple event"""
event = AE.AECreateAppleEvent(code, subcode, self.target,
AppleEvents.kAutoGenerateReturnID, AppleEvents.kAnyTransactionID)
packevent(event, parameters, attributes)
return event
def sendevent(self, event):
"""Send a pre-created appleevent, await the reply and unpack it"""
reply = event.AESend(self.send_flags, self.send_priority,
self.send_timeout)
parameters, attributes = unpackevent(reply, self._moduleName)
return reply, parameters, attributes
def send(self, code, subcode, parameters = {}, attributes = {}):
"""Send an appleevent given code/subcode/pars/attrs and unpack the reply"""
return self.sendevent(self.newevent(code, subcode, parameters, attributes))
#
# The following events are somehow "standard" and don't seem to appear in any
# suite...
#
def activate(self):
"""Send 'activate' command"""
self.send('misc', 'actv')
def _get(self, _object, as=None, _attributes={}):
"""_get: get data from an object
Required argument: the object
Keyword argument _attributes: AppleEvent attribute dictionary
Returns: the data
"""
_code = 'core'
_subcode = 'getd'
_arguments = {'----':_object}
if as:
_arguments['rtyp'] = mktype(as)
_reply, _arguments, _attributes = self.send(_code, _subcode,
_arguments, _attributes)
if _arguments.has_key('errn'):
raise Error, decodeerror(_arguments)
if _arguments.has_key('----'):
return _arguments['----']
if as:
item.__class__ = as
return item
def _set(self, _object, _arguments = {}, _attributes = {}):
""" _set: set data for an object
Required argument: the object
Keyword argument _parameters: Parameter dictionary for the set operation
Keyword argument _attributes: AppleEvent attribute dictionary
Returns: the data
"""
_code = 'core'
_subcode = 'setd'
_arguments['----'] = _object
_reply, _arguments, _attributes = self.send(_code, _subcode,
_arguments, _attributes)
if _arguments.has_key('errn'):
raise Error, decodeerror(_arguments)
if _arguments.has_key('----'):
return _arguments['----']
# Tiny Finder class, for local use only
class _miniFinder(TalkTo):
def open(self, _object, _attributes={}, **_arguments):
"""open: Open the specified object(s)
Required argument: list of objects to open
Keyword argument _attributes: AppleEvent attribute dictionary
"""
_code = 'aevt'
_subcode = 'odoc'
if _arguments: raise TypeError, 'No optional args expected'
_arguments['----'] = _object
_reply, _arguments, _attributes = self.send(_code, _subcode,
_arguments, _attributes)
if _arguments.has_key('errn'):
raise Error, decodeerror(_arguments)
# XXXX Optionally decode result
if _arguments.has_key('----'):
return _arguments['----']
#pass
_finder = _miniFinder('MACS')
def _launch(appfile):
"""Open a file thru the finder. Specify file by name or fsspec"""
_finder.open(_application_file(('ID ', appfile)))
class _application_file(ComponentItem):
"""application file - An application's file on disk"""
want = 'appf'
_application_file._propdict = {
}
_application_file._elemdict = {
}
# Test program
# XXXX Should test more, really...
def test():
target = AE.AECreateDesc('sign', 'quil')
ae = AE.AECreateAppleEvent('aevt', 'oapp', target, -1, 0)
print unpackevent(ae)
raw_input(":")
ae = AE.AECreateAppleEvent('core', 'getd', target, -1, 0)
obj = Character(2, Word(1, Document(1)))
print obj
print repr(obj)
packevent(ae, {'----': obj})
params, attrs = unpackevent(ae)
print params['----']
raw_input(":")
if __name__ == '__main__':
test()
sys.exit(1)
--- 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 apply(pack, args, kwargs)
def IsSubclass(cls, base):
"""Test whether CLASS1 is the same as or a subclass of CLASS2"""
# Loop to optimize for single inheritance
while 1:
if cls is base: return 1
if len(cls.__bases__) <> 1: break
cls = cls.__bases__[0]
# Recurse to cope with multiple inheritance
for c in cls.__bases__:
if IsSubclass(c, base): return 1
return 0
def IsInstance(x, cls):
"""Test whether OBJECT is an instance of (a subclass of) CLASS"""
return type(x) is InstanceType and IsSubclass(x.__class__, cls)
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(%s, %s)" % (`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(%s)" % `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(%s, %s)" % (`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(%s)" % `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(%s)" % `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(%s)" % `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(%s, %s)" % (`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(%s, %s, %s)" % (`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(%s)" % (`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(%s, %s)" % (`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(%s, %s)" % (`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(%s, %s, %s)" % (`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(%s, %s, %s)" % (`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(%s, %s)" % (`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(%s, %s)" % (`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(%s, %s, %s, %s)" % (`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(%s, %s, %s)" % (`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(%s, %s, %s" % (`self.want`, `self.form`, `self.seld`)
if self.fr:
s = s + ", %s)" % `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(%s, %s)" % (`self.seld.type`, `self.fr`)
else:
return "Property(%s)" % `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(%s"%`self.seld.type`
if self.fr:
rv = rv + ", fr=%s" % `self.fr`
if self.want != 'prop':
rv = rv + ", want=%s" % `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
def __init__(self, which, fr = None):
SelectableItem.__init__(self, self.want, which, fr)
def __repr__(self):
if not self.fr:
return "%s(%s)" % (self.__class__.__name__, `self.seld`)
return "%s(%s, %s)" % (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(???, %s)" % (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 ---
# applesingle - a module to decode AppleSingle files
import struct
import MacOS
import sys
Error="applesingle.Error"
verbose=0
# 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)
def decode(input, output, resonly=0):
if type(input) == type(''):
input = open(input, 'rb')
# Should we also test for FSSpecs or FSRefs?
header = input.read(AS_HEADER_LENGTH)
try:
magic, version, dummy, 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 = [input.read(AS_ENTRY_LENGTH) for i in range(nentry)]
didwork = 0
for hdr in headers:
try:
id, 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'%(id, offset, length)
input.seek(offset)
if length == 0:
data = ''
else:
data = input.read(length)
if len(data) != length:
raise Error, 'Short read: expected %d bytes got %d'%(length, len(data))
if id == AS_DATAFORK:
if verbose:
print ' (data fork)'
if not resonly:
didwork = 1
fp = open(output, 'wb')
fp.write(data)
fp.close()
elif id == AS_RESOURCEFORK:
didwork = 1
if verbose:
print ' (resource fork)'
if resonly:
fp = open(output, 'wb')
else:
fp = MacOS.openrf(output, 'wb')
fp.write(data)
fp.close()
elif id in AS_IGNORE:
if verbose:
print ' (ignored)'
else:
raise Error, 'Unknown fork type %d'%id
if not didwork:
raise Error, 'No useful forks found'
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 = 1
del sys.argv[1]
else:
resonly = 0
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: %s %s" % \
(`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 = apply(_function, (_object,), _parameters)
else:
#Same try/except comment as above
rv = apply(_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:
fss = alias.Resolve()[0]
pathname = fss.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.
if sys.platform == 'mac':
# For MacPython we know where it is
def _pardir(p): return os.path.split(p)[0]
BGENDIR=os.path.join(sys.prefix, "Tools", "bgen", "bgen")
else:
# for unix-Python we don't know, please set it yourself.
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.
#
if sys.platform == 'mac':
_MWERKSDIR="Macintosh HD:Applications (Mac OS 9):Metrowerks CodeWarrior 7.0:Metrowerks CodeWarrior"
else:
_MWERKSDIR="/Volumes/Moes/Applications (Mac OS 9)/Metrowerks CodeWarrior 7.0/Metrowerks CodeWarrior/"
INCLUDEDIR=os.path.join(_MWERKSDIR, "MacOS Support", "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.
#
if sys.platform == 'mac':
TOOLBOXDIR=os.path.join(sys.prefix, "Mac", "Lib", "Carbon")
else:
TOOLBOXDIR="/Users/jack/src/python/Mac/Lib/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
import macfs
from Carbon import Res
import MACFS
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
def findtemplate(template=None):
"""Locate the applet template along sys.path"""
if MacOS.runtimemodel == 'macho':
if template:
return template
return findtemplate_macho()
if not template:
template=TEMPLATE
for p in sys.path:
file = os.path.join(p, template)
try:
file, d1, d2 = macfs.ResolveAliasFile(file)
break
except (macfs.error, ValueError):
continue
else:
raise BuildError, "Template %s not found on sys.path" % `template`
file = file.as_pathname()
return file
def findtemplate_macho():
execpath = sys.executable.split('/')
if not 'Contents' in execpath:
raise BuildError, "Not running from a .app bundle: %s" % sys.executable
i = execpath.index('Contents')
return '/'.join(execpath[:i])
def process(template, filename, destname, copy_codefragment,
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, 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)
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=[]):
if MacOS.runtimemodel == 'macho':
return process_common_macho(template, progress, code, rsrcname, destname,
is_update, raw, others)
if others:
raise BuildError, "Extra files only allowed for MachoPython applets"
# Create FSSpecs for the various files
template_fss = macfs.FSSpec(template)
template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
dest_fss = macfs.FSSpec(destname)
# 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.FSpOpenResFile(dest_fss, WRITE)
except MacOS.Error:
Res.FSpCreateResFile(destname, '????', 'APPL', MACFS.smAllScripts)
output = Res.FSpOpenResFile(dest_fss, WRITE)
# Copy the resources from the target specific resource template, if any
typesfound, ownertype = [], None
try:
input = Res.FSpOpenResFile(rsrcname, 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.FSpOpenResFile(template_fss, 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
dest_finfo = dest_fss.GetFInfo()
dest_finfo.Creator = ownertype
dest_finfo.Type = 'APPL'
dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle | MACFS.kIsShared
dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
dest_fss.SetFInfo(dest_finfo)
macostools.touched(dest_fss)
if progress:
progress.label("Done.")
progress.inc(0)
def process_common_macho(template, progress, code, rsrcname, destname, is_update, raw=0, others=[]):
# First make sure the name ends in ".app"
if destname[-4:] != '.app':
destname = destname + '.app'
# Now deduce the short name
shortname = os.path.split(destname)[1]
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
# Start with copying the .app framework
if not is_update:
exceptlist = ["Contents/Info.plist",
"Contents/Resources/English.lproj/InfoPlist.strings",
"Contents/Resources/English.lproj/Documentation",
"Contents/Resources/python.rsrc",
]
copyapptree(template, destname, exceptlist, progress)
# SERIOUS HACK. If we've just copied a symlink as the
# executable we assume we're running from the MacPython addon
# to 10.2 python. We remove the symlink again and install
# the appletrunner script.
executable = os.path.join(destname, "Contents/MacOS/python")
if os.path.islink(executable):
os.remove(executable)
dummyfp, appletrunner, d2 = imp.find_module('appletrunner')
del dummyfp
shutil.copy2(appletrunner, executable)
os.chmod(executable, 0775)
# Now either use the .plist file or the default
if progress:
progress.label('Create info.plist')
progress.inc(0)
if plistname:
shutil.copy2(plistname, os.path.join(destname, 'Contents', 'Info.plist'))
if icnsname:
icnsdest = os.path.split(icnsname)[1]
icnsdest = os.path.join(destname,
os.path.join('Contents', 'Resources', icnsdest))
shutil.copy2(icnsname, icnsdest)
# XXXX Wrong. This should be parsed from plist file. Also a big hack:-)
if shortname == 'PythonIDE':
ownertype = 'Pide'
else:
ownertype = 'PytA'
# XXXX Should copy .icns file
else:
cocoainfo = ''
for o in others:
if o[-4:] == '.nib':
nibname = os.path.split(o)[1][:-4]
cocoainfo = """
<key>NSMainNibFile</key>
<string>%s</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>""" % nibname
elif o[-6:] == '.lproj':
files = os.listdir(o)
for f in files:
if f[-4:] == '.nib':
nibname = os.path.split(f)[1][:-4]
cocoainfo = """
<key>NSMainNibFile</key>
<string>%s</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>""" % nibname
plistname = os.path.join(template, 'Contents', 'Resources', 'Applet-Info.plist')
plistdata = open(plistname).read()
plistdata = plistdata % {'appletname':shortname, 'cocoainfo':cocoainfo}
ofp = open(os.path.join(destname, 'Contents', 'Info.plist'), 'w')
ofp.write(plistdata)
ofp.close()
ownertype = 'PytA'
# Create the PkgInfo file
if progress:
progress.label('Create PkgInfo')
progress.inc(0)
ofp = open(os.path.join(destname, 'Contents', 'PkgInfo'), 'wb')
ofp.write('APPL' + ownertype)
ofp.close()
# Copy the resources from the target specific resource template, if any
typesfound, ownertype = [], None
try:
input = macresource.open_pathname(rsrcname)
except (MacOS.Error, ValueError):
if progress:
progress.inc(50)
else:
if progress:
progress.label("Copy resources...")
progress.set(20)
resfilename = 'python.rsrc' # XXXX later: '%s.rsrc' % shortname
try:
output = Res.FSOpenResourceFile(
os.path.join(destname, 'Contents', 'Resources', resfilename),
u'', WRITE)
except MacOS.Error:
fsr, dummy = Res.FSCreateResourceFile(
os.path.join(destname, 'Contents', 'Resources'),
unicode(resfilename), '')
output = Res.FSOpenResourceFile(fsr, u'', WRITE)
typesfound, ownertype = copyres(input, output, [], 0, progress)
Res.CloseResFile(input)
Res.CloseResFile(output)
if code:
if raw:
pycname = '__rawmain__.pyc'
else:
pycname = '__main__.pyc'
# And we also create __rawmain__.pyc
outputfilename = os.path.join(destname, 'Contents', 'Resources', '__rawmain__.pyc')
if progress:
progress.label('Creating __rawmain__.pyc')
progress.inc(0)
rawsourcefp, rawsourcefile, d2 = imp.find_module('appletrawmain')
rawsource = rawsourcefp.read()
rawcode = compile(rawsource, rawsourcefile, 'exec')
writepycfile(rawcode, outputfilename)
outputfilename = os.path.join(destname, 'Contents', 'Resources', pycname)
if progress:
progress.label('Creating '+pycname)
progress.inc(0)
writepycfile(code, outputfilename)
# Copy other files the user asked for
for osrc in others:
oname = os.path.split(osrc)[1]
odst = os.path.join(destname, 'Contents', 'Resources', oname)
if progress:
progress.label('Copy ' + oname)
progress.inc(0)
if os.path.isdir(osrc):
copyapptree(osrc, odst)
else:
shutil.copy2(osrc, odst)
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=None):
ctor = None
alltypes = []
Res.UseResFile(input)
ntypes = Res.Count1Types()
progress_type_inc = 50/ntypes
for itype in range(1, 1+ntypes):
type = Res.Get1IndType(itype)
if type in skiptypes:
continue
alltypes.append(type)
nresources = Res.Count1Resources(type)
progress_cur_inc = progress_type_inc/nresources
for ires in range(1, 1+nresources):
res = Res.Get1IndResource(type, ires)
id, type, name = res.GetResInfo()
lcname = string.lower(name)
if lcname == OWNERNAME and id == 0:
if skipowner:
continue # Skip this one
else:
ctor = type
size = res.size
attrs = res.GetResAttrs()
if progress:
progress.label("Copy %s %d %s"%(type, id, name))
progress.inc(progress_cur_inc)
res.LoadResource()
res.DetachResource()
Res.UseResFile(output)
try:
res2 = Res.Get1Resource(type, id)
except MacOS.Error:
res2 = None
if res2:
if progress:
progress.label("Overwrite %s %d %s"%(type, id, name))
progress.inc(0)
res2.RemoveResource()
res.AddResource(type, id, name)
res.WriteResource()
attrs = attrs | res.GetResAttrs()
res.SetResAttrs(attrs)
Res.UseResFile(input)
return alltypes, ctor
def copyapptree(srctree, dsttree, exceptlist=[], progress=None):
names = []
if os.path.exists(dsttree):
shutil.rmtree(dsttree)
os.mkdir(dsttree)
todo = os.listdir(srctree)
while todo:
this, todo = todo[0], todo[1:]
if this in exceptlist:
continue
thispath = os.path.join(srctree, this)
if os.path.isdir(thispath):
thiscontent = os.listdir(thispath)
for t in thiscontent:
todo.append(os.path.join(this, t))
names.append(this)
for this in names:
srcpath = os.path.join(srctree, this)
dstpath = os.path.join(dsttree, this)
if os.path.isdir(srcpath):
os.mkdir(dstpath)
elif os.path.islink(srcpath):
endpoint = os.readlink(srcpath)
os.symlink(endpoint, dstpath)
else:
if progress:
progress.label('Copy '+this)
progress.inc(0)
shutil.copy2(srcpath, dstpath)
def writepycfile(codeobject, cfile):
import marshal
fc = open(cfile, 'wb')
fc.write('\0\0\0\0') # MAGIC placeholder, written later
fc.write('\0\0\0\0') # Timestap placeholder, not needed
marshal.dump(codeobject, fc)
fc.flush()
fc.seek(0, 0)
fc.write(MAGIC)
fc.close()
--- NEW FILE: bundlebuilder.py ---
#! /usr/bin/env python
"""\
bundlebuilder.py -- Tools to assemble MacOS X (application) bundles.
This module contains two classes to build so called "bundles" for
MacOS X. BundleBuilder is a general tool, AppBuilder is a subclass
specialized in building application bundles.
[Bundle|App]Builder objects are instantiated with a bunch of keyword
arguments, and have a build() method that will do all the work. See
the class doc strings for a description of the constructor arguments.
The module contains a main program that can be used in two ways:
% python bundlebuilder.py [options] build
% python buildapp.py [options] build
Where "buildapp.py" is a user-supplied setup.py-like script following
this model:
from bundlebuilder import buildapp
buildapp(<lots-of-keyword-args>)
"""
__all__ = ["BundleBuilder", "BundleBuilderError", "AppBuilder", "buildapp"]
import sys
import os, errno, shutil
import imp, marshal
import re
from copy import deepcopy
import getopt
from plistlib import Plist
from types import FunctionType as function
class BundleBuilderError(Exception): pass
class Defaults:
"""Class attributes that don't start with an underscore and are
not functions or classmethods are (deep)copied to self.__dict__.
This allows for mutable default values.
"""
def __init__(self, **kwargs):
defaults = self._getDefaults()
defaults.update(kwargs)
self.__dict__.update(defaults)
def _getDefaults(cls):
defaults = {}
for name, value in cls.__dict__.items():
if name[0] != "_" and not isinstance(value,
(function, classmethod)):
defaults[name] = deepcopy(value)
for base in cls.__bases__:
if hasattr(base, "_getDefaults"):
defaults.update(base._getDefaults())
return defaults
_getDefaults = classmethod(_getDefaults)
class BundleBuilder(Defaults):
"""BundleBuilder is a barebones class for assembling bundles. It
knows nothing about executables or icons, it only copies files
and creates the PkgInfo and Info.plist files.
"""
# (Note that Defaults.__init__ (deep)copies these values to
# instance variables. Mutable defaults are therefore safe.)
# Name of the bundle, with or without extension.
name = None
# The property list ("plist")
plist = Plist(CFBundleDevelopmentRegion = "English",
CFBundleInfoDictionaryVersion = "6.0")
# The type of the bundle.
type = "APPL"
# The creator code of the bundle.
creator = None
# List of files that have to be copied to <bundle>/Contents/Resources.
resources = []
# List of (src, dest) tuples; dest should be a path relative to the bundle
# (eg. "Contents/Resources/MyStuff/SomeFile.ext).
files = []
# Directory where the bundle will be assembled.
builddir = "build"
# platform, name of the subfolder of Contents that contains the executable.
platform = "MacOS"
# Make symlinks instead copying files. This is handy during debugging, but
# makes the bundle non-distributable.
symlink = 0
# Verbosity level.
verbosity = 1
def setup(self):
# XXX rethink self.name munging, this is brittle.
self.name, ext = os.path.splitext(self.name)
if not ext:
ext = ".bundle"
bundleextension = ext
# misc (derived) attributes
self.bundlepath = pathjoin(self.builddir, self.name + bundleextension)
self.execdir = pathjoin("Contents", self.platform)
plist = self.plist
plist.CFBundleName = self.name
plist.CFBundlePackageType = self.type
if self.creator is None:
if hasattr(plist, "CFBundleSignature"):
self.creator = plist.CFBundleSignature
else:
self.creator = "????"
plist.CFBundleSignature = self.creator
def build(self):
"""Build the bundle."""
builddir = self.builddir
if builddir and not os.path.exists(builddir):
os.mkdir(builddir)
self.message("Building %s" % repr(self.bundlepath), 1)
if os.path.exists(self.bundlepath):
shutil.rmtree(self.bundlepath)
os.mkdir(self.bundlepath)
self.preProcess()
self._copyFiles()
self._addMetaFiles()
self.postProcess()
self.message("Done.", 1)
def preProcess(self):
"""Hook for subclasses."""
pass
def postProcess(self):
"""Hook for subclasses."""
pass
def _addMetaFiles(self):
contents = pathjoin(self.bundlepath, "Contents")
makedirs(contents)
#
# Write Contents/PkgInfo
assert len(self.type) == len(self.creator) == 4, \
"type and creator must be 4-byte strings."
pkginfo = pathjoin(contents, "PkgInfo")
f = open(pkginfo, "wb")
f.write(self.type + self.creator)
f.close()
#
# Write Contents/Info.plist
infoplist = pathjoin(contents, "Info.plist")
self.plist.write(infoplist)
def _copyFiles(self):
files = self.files[:]
for path in self.resources:
files.append((path, pathjoin("Contents", "Resources",
os.path.basename(path))))
if self.symlink:
self.message("Making symbolic links", 1)
msg = "Making symlink from"
else:
self.message("Copying files", 1)
msg = "Copying"
files.sort()
for src, dst in files:
if os.path.isdir(src):
self.message("%s %s/ to %s/" % (msg, src, dst), 2)
else:
self.message("%s %s to %s" % (msg, src, dst), 2)
dst = pathjoin(self.bundlepath, dst)
if self.symlink:
symlink(src, dst, mkdirs=1)
else:
copy(src, dst, mkdirs=1)
def message(self, msg, level=0):
if level <= self.verbosity:
indent = ""
if level > 1:
indent = (level - 1) * " "
sys.stderr.write(indent + msg + "\n")
def report(self):
# XXX something decent
pass
if __debug__:
PYC_EXT = ".pyc"
else:
PYC_EXT = ".pyo"
MAGIC = imp.get_magic()
USE_FROZEN = hasattr(imp, "set_frozenmodules")
# For standalone apps, we have our own minimal site.py. We don't need
# all the cruft of the real site.py.
SITE_PY = """\
import sys
del sys.path[1:] # sys.path[0] is Contents/Resources/
"""
if USE_FROZEN:
FROZEN_ARCHIVE = "FrozenModules.marshal"
SITE_PY += """\
# bootstrapping
import imp, marshal
f = open(sys.path[0] + "/%s", "rb")
imp.set_frozenmodules(marshal.load(f))
f.close()
""" % FROZEN_ARCHIVE
SITE_CO = compile(SITE_PY, "<-bundlebuilder.py->", "exec")
EXT_LOADER = """\
import imp, sys, os
for p in sys.path:
path = os.path.join(p, "%(filename)s")
if os.path.exists(path):
break
else:
assert 0, "file not found: %(filename)s"
mod = imp.load_dynamic("%(name)s", path)
sys.modules["%(name)s"] = mod
"""
MAYMISS_MODULES = ['mac', 'os2', 'nt', 'ntpath', 'dos', 'dospath',
'win32api', 'ce', '_winreg', 'nturl2path', 'sitecustomize',
'org.python.core', 'riscos', 'riscosenviron', 'riscospath'
]
STRIP_EXEC = "/usr/bin/strip"
BOOTSTRAP_SCRIPT = """\
#!/bin/sh
execdir=$(dirname ${0})
executable=${execdir}/%(executable)s
resdir=$(dirname ${execdir})/Resources
main=${resdir}/%(mainprogram)s
PYTHONPATH=$resdir
export PYTHONPATH
exec ${executable} ${main} ${1}
"""
class AppBuilder(BundleBuilder):
# A Python main program. If this argument is given, the main
# executable in the bundle will be a small wrapper that invokes
# the main program. (XXX Discuss why.)
mainprogram = None
# The main executable. If a Python main program is specified
# the executable will be copied to Resources and be invoked
# by the wrapper program mentioned above. Otherwise it will
# simply be used as the main executable.
executable = None
# The name of the main nib, for Cocoa apps. *Must* be specified
# when building a Cocoa app.
nibname = None
# Symlink the executable instead of copying it.
symlink_exec = 0
# If True, build standalone app.
standalone = 0
# The following attributes are only used when building a standalone app.
# Exclude these modules.
excludeModules = []
# Include these modules.
includeModules = []
# Include these packages.
includePackages = []
# Strip binaries.
strip = 0
# Found Python modules: [(name, codeobject, ispkg), ...]
pymodules = []
# Modules that modulefinder couldn't find:
missingModules = []
maybeMissingModules = []
# List of all binaries (executables or shared libs), for stripping purposes
binaries = []
def setup(self):
if self.standalone and self.mainprogram is None:
raise BundleBuilderError, ("must specify 'mainprogram' when "
"building a standalone application.")
if self.mainprogram is None and self.executable is None:
raise BundleBuilderError, ("must specify either or both of "
"'executable' and 'mainprogram'")
if self.name is not None:
pass
elif self.mainprogram is not None:
self.name = os.path.splitext(os.path.basename(self.mainprogram))[0]
elif executable is not None:
self.name = os.path.splitext(os.path.basename(self.executable))[0]
if self.name[-4:] != ".app":
self.name += ".app"
if self.executable is None:
if not self.standalone:
self.symlink_exec = 1
self.executable = sys.executable
if self.nibname:
self.plist.NSMainNibFile = self.nibname
if not hasattr(self.plist, "NSPrincipalClass"):
self.plist.NSPrincipalClass = "NSApplication"
BundleBuilder.setup(self)
self.plist.CFBundleExecutable = self.name
if self.standalone:
self.findDependencies()
def preProcess(self):
resdir = "Contents/Resources"
if self.executable is not None:
if self.mainprogram is None:
execname = self.name
else:
execname = os.path.basename(self.executable)
execpath = pathjoin(self.execdir, execname)
if not self.symlink_exec:
self.files.append((self.executable, execpath))
self.binaries.append(execpath)
self.execpath = execpath
if self.mainprogram is not None:
mainprogram = os.path.basename(self.mainprogram)
self.files.append((self.mainprogram, pathjoin(resdir, mainprogram)))
# Write bootstrap script
executable = os.path.basename(self.executable)
execdir = pathjoin(self.bundlepath, self.execdir)
bootstrappath = pathjoin(execdir, self.name)
makedirs(execdir)
open(bootstrappath, "w").write(BOOTSTRAP_SCRIPT % locals())
os.chmod(bootstrappath, 0775)
def postProcess(self):
if self.standalone:
self.addPythonModules()
if self.strip and not self.symlink:
self.stripBinaries()
if self.symlink_exec and self.executable:
self.message("Symlinking executable %s to %s" % (self.executable,
self.execpath), 2)
dst = pathjoin(self.bundlepath, self.execpath)
makedirs(os.path.dirname(dst))
os.symlink(os.path.abspath(self.executable), dst)
if self.missingModules or self.maybeMissingModules:
self.reportMissing()
def addPythonModules(self):
self.message("Adding Python modules", 1)
if USE_FROZEN:
# This anticipates the acceptance of this patch:
# http://www.python.org/sf/642578
# Create a file containing all modules, frozen.
frozenmodules = []
for name, code, ispkg in self.pymodules:
if ispkg:
self.message("Adding Python package %s" % name, 2)
else:
self.message("Adding Python module %s" % name, 2)
frozenmodules.append((name, marshal.dumps(code), ispkg))
frozenmodules = tuple(frozenmodules)
relpath = pathjoin("Contents", "Resources", FROZEN_ARCHIVE)
abspath = pathjoin(self.bundlepath, relpath)
f = open(abspath, "wb")
marshal.dump(frozenmodules, f)
f.close()
# add site.pyc
sitepath = pathjoin(self.bundlepath, "Contents", "Resources",
"site" + PYC_EXT)
writePyc(SITE_CO, sitepath)
else:
# Create individual .pyc files.
for name, code, ispkg in self.pymodules:
if ispkg:
name += ".__init__"
path = name.split(".")
path = pathjoin("Contents", "Resources", *path) + PYC_EXT
if ispkg:
self.message("Adding Python package %s" % path, 2)
else:
self.message("Adding Python module %s" % path, 2)
abspath = pathjoin(self.bundlepath, path)
makedirs(os.path.dirname(abspath))
writePyc(code, abspath)
def stripBinaries(self):
if not os.path.exists(STRIP_EXEC):
self.message("Error: can't strip binaries: no strip program at "
"%s" % STRIP_EXEC, 0)
else:
self.message("Stripping binaries", 1)
for relpath in self.binaries:
self.message("Stripping %s" % relpath, 2)
abspath = pathjoin(self.bundlepath, relpath)
assert not os.path.islink(abspath)
rv = os.system("%s -S \"%s\"" % (STRIP_EXEC, abspath))
def findDependencies(self):
self.message("Finding module dependencies", 1)
import modulefinder
mf = modulefinder.ModuleFinder(excludes=self.excludeModules)
# manually add our own site.py
site = mf.add_module("site")
site.__code__ = SITE_CO
mf.scan_code(SITE_CO, site)
includeModules = self.includeModules[:]
for name in self.includePackages:
includeModules.extend(findPackageContents(name).keys())
for name in includeModules:
try:
mf.import_hook(name)
except ImportError:
self.missingModules.append(name)
mf.run_script(self.mainprogram)
modules = mf.modules.items()
modules.sort()
for name, mod in modules:
if mod.__file__ and mod.__code__ is None:
# C extension
path = mod.__file__
filename = os.path.basename(path)
if USE_FROZEN:
# "proper" freezing, put extensions in Contents/Resources/,
# freeze a tiny "loader" program. Due to Thomas Heller.
dstpath = pathjoin("Contents", "Resources", filename)
source = EXT_LOADER % {"name": name, "filename": filename}
code = compile(source, "<dynloader for %s>" % name, "exec")
mod.__code__ = code
else:
# just copy the file
dstpath = name.split(".")[:-1] + [filename]
dstpath = pathjoin("Contents", "Resources", *dstpath)
self.files.append((path, dstpath))
self.binaries.append(dstpath)
if mod.__code__ is not None:
ispkg = mod.__path__ is not None
if not USE_FROZEN or name != "site":
# Our site.py is doing the bootstrapping, so we must
# include a real .pyc file if USE_FROZEN is True.
self.pymodules.append((name, mod.__code__, ispkg))
if hasattr(mf, "any_missing_maybe"):
missing, maybe = mf.any_missing_maybe()
else:
missing = mf.any_missing()
maybe = []
self.missingModules.extend(missing)
self.maybeMissingModules.extend(maybe)
def reportMissing(self):
missing = [name for name in self.missingModules
if name not in MAYMISS_MODULES]
if self.maybeMissingModules:
maybe = self.maybeMissingModules
else:
maybe = [name for name in missing if "." in name]
missing = [name for name in missing if "." not in name]
missing.sort()
maybe.sort()
if maybe:
self.message("Warning: couldn't find the following submodules:", 1)
self.message(" (Note that these could be false alarms -- "
"it's not always", 1)
self.message(" possible to distinguish between \"from package "
"import submodule\" ", 1)
self.message(" and \"from package import name\")", 1)
for name in maybe:
self.message(" ? " + name, 1)
if missing:
self.message("Warning: couldn't find the following modules:", 1)
for name in missing:
self.message(" ? " + name, 1)
def report(self):
# XXX something decent
import pprint
pprint.pprint(self.__dict__)
if self.standalone:
self.reportMissing()
#
# Utilities.
#
SUFFIXES = [_suf for _suf, _mode, _tp in imp.get_suffixes()]
identifierRE = re.compile(r"[_a-zA-z][_a-zA-Z0-9]*$")
def findPackageContents(name, searchpath=None):
head = name.split(".")[-1]
if identifierRE.match(head) is None:
return {}
try:
fp, path, (ext, mode, tp) = imp.find_module(head, searchpath)
except ImportError:
return {}
modules = {name: None}
if tp == imp.PKG_DIRECTORY and path:
files = os.listdir(path)
for sub in files:
sub, ext = os.path.splitext(sub)
fullname = name + "." + sub
if sub != "__init__" and fullname not in modules:
modules.update(findPackageContents(fullname, [path]))
return modules
def writePyc(code, path):
f = open(path, "wb")
f.write("\0" * 8) # don't bother about a time stamp
marshal.dump(code, f)
f.seek(0, 0)
f.write(MAGIC)
f.close()
def copy(src, dst, mkdirs=0):
"""Copy a file or a directory."""
if mkdirs:
makedirs(os.path.dirname(dst))
if os.path.isdir(src):
shutil.copytree(src, dst)
else:
shutil.copy2(src, dst)
def copytodir(src, dstdir):
"""Copy a file or a directory to an existing directory."""
dst = pathjoin(dstdir, os.path.basename(src))
copy(src, dst)
def makedirs(dir):
"""Make all directories leading up to 'dir' including the leaf
directory. Don't moan if any path element already exists."""
try:
os.makedirs(dir)
except OSError, why:
if why.errno != errno.EEXIST:
raise
def symlink(src, dst, mkdirs=0):
"""Copy a file or a directory."""
if mkdirs:
makedirs(os.path.dirname(dst))
os.symlink(os.path.abspath(src), dst)
def pathjoin(*args):
"""Safe wrapper for os.path.join: asserts that all but the first
argument are relative paths."""
for seg in args[1:]:
assert seg[0] != "/"
return os.path.join(*args)
cmdline_doc = """\
Usage:
python bundlebuilder.py [options] command
python mybuildscript.py [options] command
Commands:
build build the application
report print a report
Options:
-b, --builddir=DIR the build directory; defaults to "build"
-n, --name=NAME application name
-r, --resource=FILE extra file or folder to be copied to Resources
-e, --executable=FILE the executable to be used
-m, --mainprogram=FILE the Python main program
-p, --plist=FILE .plist file (default: generate one)
--nib=NAME main nib name
-c, --creator=CCCC 4-char creator code (default: '????')
-l, --link symlink files/folder instead of copying them
--link-exec symlink the executable instead of copying it
--standalone build a standalone application, which is fully
independent of a Python installation
-x, --exclude=MODULE exclude module (with --standalone)
-i, --include=MODULE include module (with --standalone)
--package=PACKAGE include a whole package (with --standalone)
--strip strip binaries (remove debug info)
-v, --verbose increase verbosity level
-q, --quiet decrease verbosity level
-h, --help print this message
"""
def usage(msg=None):
if msg:
print msg
print cmdline_doc
sys.exit(1)
def main(builder=None):
if builder is None:
builder = AppBuilder(verbosity=1)
shortopts = "b:n:r:e:m:c:p:lx:i:hvq"
longopts = ("builddir=", "name=", "resource=", "executable=",
"mainprogram=", "creator=", "nib=", "plist=", "link",
"link-exec", "help", "verbose", "quiet", "standalone",
"exclude=", "include=", "package=", "strip")
try:
options, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
except getopt.error:
usage()
for opt, arg in options:
if opt in ('-b', '--builddir'):
builder.builddir = arg
elif opt in ('-n', '--name'):
builder.name = arg
elif opt in ('-r', '--resource'):
builder.resources.append(arg)
elif opt in ('-e', '--executable'):
builder.executable = arg
elif opt in ('-m', '--mainprogram'):
builder.mainprogram = arg
elif opt in ('-c', '--creator'):
builder.creator = arg
elif opt == "--nib":
builder.nibname = arg
elif opt in ('-p', '--plist'):
builder.plist = Plist.fromFile(arg)
elif opt in ('-l', '--link'):
builder.symlink = 1
elif opt == '--link-exec':
builder.symlink_exec = 1
elif opt in ('-h', '--help'):
usage()
elif opt in ('-v', '--verbose'):
builder.verbosity += 1
elif opt in ('-q', '--quiet'):
builder.verbosity -= 1
elif opt == '--standalone':
builder.standalone = 1
elif opt in ('-x', '--exclude'):
builder.excludeModules.append(arg)
elif opt in ('-i', '--include'):
builder.includeModules.append(arg)
elif opt == '--package':
builder.includePackages.append(arg)
elif opt == '--strip':
builder.strip = 1
if len(args) != 1:
usage("Must specify one command ('build', 'report' or 'help')")
command = args[0]
if command == "build":
builder.setup()
builder.build()
elif command == "report":
builder.setup()
builder.report()
elif command == "help":
usage()
else:
usage("Unknown command '%s'" % command)
def buildapp(**kwargs):
builder = AppBuilder(**kwargs)
main(builder)
if __name__ == "__main__":
main()
--- NEW FILE: cfmfile.py ---
"""codefragments.py -- wrapper to modify code fragments."""
# (c) 1998, Just van Rossum, Letterror
__version__ = "0.8b3"
__author__ = "jvr"
import macfs
import struct
from Carbon import Res
import os
import sys
DEBUG = 0
error = "cfm.error"
BUFSIZE = 0x80000
def mergecfmfiles(srclist, dst, architecture = 'fat'):
"""Merge all files in srclist into a new file dst.
If architecture is given, only code fragments of that type will be used:
"pwpc" for PPC, "m68k" for cfm68k. This does not work for "classic"
68k code, since it does not use code fragments to begin with.
If architecture is None, all fragments will be used, enabling FAT binaries.
"""
srclist = list(srclist)
for i in range(len(srclist)):
if type(srclist[i]) == macfs.FSSpecType:
srclist[i] = srclist[i].as_pathname()
if type(dst) == macfs.FSSpecType:
dst = dst.as_pathname()
dstfile = open(dst, "wb")
rf = Res.FSpOpenResFile(dst, 3)
try:
dstcfrg = CfrgResource()
for src in srclist:
srccfrg = CfrgResource(src)
for frag in srccfrg.fragments:
if frag.architecture == 'pwpc' and architecture == 'm68k':
continue
if frag.architecture == 'm68k' and architecture == 'pwpc':
continue
dstcfrg.append(frag)
frag.copydata(dstfile)
cfrgres = Res.Resource(dstcfrg.build())
Res.UseResFile(rf)
cfrgres.AddResource('cfrg', 0, "")
finally:
dstfile.close()
rf = Res.CloseResFile(rf)
class CfrgResource:
def __init__(self, path = None):
self.version = 1
self.fragments = []
self.path = path
if path is not None and os.path.exists(path):
currentresref = Res.CurResFile()
resref = Res.FSpOpenResFile(path, 1)
Res.UseResFile(resref)
try:
try:
data = Res.Get1Resource('cfrg', 0).data
except Res.Error:
raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback
finally:
Res.CloseResFile(resref)
Res.UseResFile(currentresref)
self.parse(data)
if self.version <> 1:
raise error, "unknown 'cfrg' resource format"
def parse(self, data):
(res1, res2, self.version,
res3, res4, res5, res6,
self.memberCount) = struct.unpack("8l", data[:32])
data = data[32:]
while data:
frag = FragmentDescriptor(self.path, data)
data = data[frag.memberSize:]
self.fragments.append(frag)
def build(self):
self.memberCount = len(self.fragments)
data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount)
for frag in self.fragments:
data = data + frag.build()
return data
def append(self, frag):
self.fragments.append(frag)
class FragmentDescriptor:
def __init__(self, path, data = None):
self.path = path
if data is not None:
self.parse(data)
def parse(self, data):
self.architecture = data[:4]
( self.updatelevel,
self.currentVersion,
self.oldDefVersion,
self.stacksize,
self.applibdir,
self.fragtype,
self.where,
self.offset,
self.length,
self.res1, self.res2,
self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42])
pname = data[42:self.memberSize]
self.name = pname[1:1+ord(pname[0])]
def build(self):
data = self.architecture
data = data + struct.pack("4lhBB4l",
self.updatelevel,
self.currentVersion,
self.oldDefVersion,
self.stacksize,
self.applibdir,
self.fragtype,
self.where,
self.offset,
self.length,
self.res1, self.res2)
self.memberSize = len(data) + 2 + 1 + len(self.name)
# pad to 4 byte boundaries
if self.memberSize % 4:
self.memberSize = self.memberSize + 4 - (self.memberSize % 4)
data = data + struct.pack("hb", self.memberSize, len(self.name))
data = data + self.name
data = data + '\000' * (self.memberSize - len(data))
return data
def getfragment(self):
if self.where <> 1:
raise error, "can't read fragment, unsupported location"
f = open(self.path, "rb")
f.seek(self.offset)
if self.length:
frag = f.read(self.length)
else:
frag = f.read()
f.close()
return frag
def copydata(self, outfile):
if self.where <> 1:
raise error, "can't read fragment, unsupported location"
infile = open(self.path, "rb")
if self.length == 0:
infile.seek(0, 2)
self.length = infile.tell()
# Position input file and record new offset from output file
infile.seek(self.offset)
# pad to 16 byte boundaries
offset = outfile.tell()
if offset % 16:
offset = offset + 16 - (offset % 16)
outfile.seek(offset)
self.offset = offset
l = self.length
while l:
if l > BUFSIZE:
outfile.write(infile.read(BUFSIZE))
l = l - BUFSIZE
else:
outfile.write(infile.read(l))
l = 0
infile.close()
--- NEW FILE: dialogs.rsrc ---
(This appears to be a binary file; contents omitted.)
--- NEW FILE: errors.rsrc ---
(This appears to be a binary file; contents omitted.)
--- NEW FILE: findertools.py ---
"""Utility routines depending on the finder,
a combination of code by Jack Jansen and erik@letterror.com.
Most events have been captured from
Lasso Capture AE and than translated to python code.
IMPORTANT
Note that the processes() function returns different values
depending on the OS version it is running on. On MacOS 9
the Finder returns the process *names* which can then be
used to find out more about them. On MacOS 8.6 and earlier
the Finder returns a code which does not seem to work.
So bottom line: the processes() stuff does not work on < MacOS9
Mostly written by erik@letterror.com
"""
import Finder
from Carbon import AppleEvents
import aetools
import MacOS
import sys
import macfs
import aetypes
from types import *
__version__ = '1.1'
Error = 'findertools.Error'
_finder_talker = None
def _getfinder():
"""returns basic (recyclable) Finder AE interface object"""
global _finder_talker
if not _finder_talker:
_finder_talker = Finder.Finder()
_finder_talker.send_flags = ( _finder_talker.send_flags |
AppleEvents.kAECanInteract | AppleEvents.kAECanSwitchLayer)
return _finder_talker
def launch(file):
"""Open a file thru the finder. Specify file by name or fsspec"""
finder = _getfinder()
fss = macfs.FSSpec(file)
return finder.open(fss)
def Print(file):
"""Print a file thru the finder. Specify file by name or fsspec"""
finder = _getfinder()
fss = macfs.FSSpec(file)
return finder._print(fss)
def copy(src, dstdir):
"""Copy a file to a folder"""
finder = _getfinder()
if type(src) == type([]):
src_fss = []
for s in src:
src_fss.append(macfs.FSSpec(s))
else:
src_fss = macfs.FSSpec(src)
dst_fss = macfs.FSSpec(dstdir)
return finder.duplicate(src_fss, to=dst_fss)
def move(src, dstdir):
"""Move a file to a folder"""
finder = _getfinder()
if type(src) == type([]):
src_fss = []
for s in src:
src_fss.append(macfs.FSSpec(s))
else:
src_fss = macfs.FSSpec(src)
dst_fss = macfs.FSSpec(dstdir)
return finder.move(src_fss, to=dst_fss)
def sleep():
"""Put the mac to sleep"""
finder = _getfinder()
finder.sleep()
def shutdown():
"""Shut the mac down"""
finder = _getfinder()
finder.shut_down()
def restart():
"""Restart the mac"""
finder = _getfinder()
finder.restart()
#---------------------------------------------------
# Additional findertools
#
def reveal(file):
"""Reveal a file in the finder. Specify file by name or fsspec."""
finder = _getfinder()
fss = macfs.FSSpec(file)
file_alias = fss.NewAlias()
return finder.reveal(file_alias)
def select(file):
"""select a file in the finder. Specify file by name or fsspec."""
finder = _getfinder()
fss = macfs.FSSpec(file)
file_alias = fss.NewAlias()
return finder.select(file_alias)
def update(file):
"""Update the display of the specified object(s) to match
their on-disk representation. Specify file by name or fsspec."""
finder = _getfinder()
fss = macfs.FSSpec(file)
file_alias = fss.NewAlias()
return finder.update(file_alias)
#---------------------------------------------------
# More findertools
#
def comment(object, comment=None):
"""comment: get or set the Finder-comment of the item, displayed in the –Get Info” window."""
object = macfs.FSSpec(object)
fss = macfs.FSSpec(object)
object_alias = fss.NewAlias()
if comment == None:
return _getcomment(object_alias)
else:
return _setcomment(object_alias, comment)
def _setcomment(object_alias, comment):
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'), form="alis", seld=object_alias, fr=None)
aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('comt'), fr=aeobj_00)
args['----'] = aeobj_01
args["data"] = comment
_reply, args, attrs = finder.send("core", "setd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def _getcomment(object_alias):
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'), form="alis", seld=object_alias, fr=None)
aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('comt'), fr=aeobj_00)
args['----'] = aeobj_01
_reply, args, attrs = finder.send("core", "getd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
#---------------------------------------------------
# Get information about current processes in the Finder.
def processes():
"""processes returns a list of all active processes running on this computer and their creators."""
finder = _getfinder()
args = {}
attrs = {}
processnames = []
processnumbers = []
creators = []
partitions = []
used = []
## get the processnames or else the processnumbers
args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('prcs'), form="indx", seld=aetypes.Unknown('abso', "all "), fr=None)
_reply, args, attrs = finder.send('core', 'getd', args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
p = []
if args.has_key('----'):
p = args['----']
for proc in p:
if hasattr(proc, 'seld'):
# it has a real name
processnames.append(proc.seld)
elif hasattr(proc, 'type'):
if proc.type == "psn ":
# it has a process number
processnumbers.append(proc.data)
## get the creators
args = {}
attrs = {}
aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('prcs'), form="indx", seld=aetypes.Unknown('abso', "all "), fr=None)
args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('fcrt'), fr=aeobj_0)
_reply, args, attrs = finder.send('core', 'getd', args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(_arg)
if args.has_key('----'):
p = args['----']
creators = p[:]
## concatenate in one dict
result = []
if len(processnames) > len(processnumbers):
data = processnames
else:
data = processnumbers
for i in range(len(creators)):
result.append((data[i], creators[i]))
return result
class _process:
pass
def isactiveprocess(processname):
"""Check of processname is active. MacOS9"""
all = processes()
ok = 0
for n, c in all:
if n == processname:
return 1
return 0
def processinfo(processname):
"""Return an object with all process properties as attributes for processname. MacOS9"""
p = _process()
if processname == "Finder":
p.partition = None
p.used = None
else:
p.partition = _processproperty(processname, 'appt')
p.used = _processproperty(processname, 'pusd')
p.visible = _processproperty(processname, 'pvis') #Is the process' layer visible?
p.frontmost = _processproperty(processname, 'pisf') #Is the process the frontmost process?
p.file = _processproperty(processname, 'file') #the file from which the process was launched
p.filetype = _processproperty(processname, 'asty') #the OSType of the file type of the process
p.creatortype = _processproperty(processname, 'fcrt') #the OSType of the creator of the process (the signature)
p.accepthighlevel = _processproperty(processname, 'revt') #Is the process high-level event aware (accepts open application, open document, print document, and quit)?
p.hasscripting = _processproperty(processname, 'hscr') #Does the process have a scripting terminology, i.e., can it be scripted?
return p
def _processproperty(processname, property):
"""return the partition size and memory used for processname"""
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('prcs'), form="name", seld=processname, fr=None)
aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type(property), fr=aeobj_00)
args['----'] = aeobj_01
_reply, args, attrs = finder.send("core", "getd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
#---------------------------------------------------
# Mess around with Finder windows.
def openwindow(object):
"""Open a Finder window for object, Specify object by name or fsspec."""
finder = _getfinder()
object = macfs.FSSpec(object)
fss = macfs.FSSpec(object)
object_alias = fss.NewAlias()
args = {}
attrs = {}
_code = 'aevt'
_subcode = 'odoc'
aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=object_alias, fr=None)
args['----'] = aeobj_0
_reply, args, attrs = finder.send(_code, _subcode, args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
def closewindow(object):
"""Close a Finder window for folder, Specify by path."""
finder = _getfinder()
fss = macfs.FSSpec(object)
object_alias = fss.NewAlias()
args = {}
attrs = {}
_code = 'core'
_subcode = 'clos'
aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=object_alias, fr=None)
args['----'] = aeobj_0
_reply, args, attrs = finder.send(_code, _subcode, args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
def location(object, pos=None):
"""Set the position of a Finder window for folder to pos=(w, h). Specify file by name or fsspec.
If pos=None, location will return the current position of the object."""
fss = macfs.FSSpec(object)
object_alias = fss.NewAlias()
if not pos:
return _getlocation(object_alias)
return _setlocation(object_alias, pos)
def _setlocation(object_alias, (x, y)):
"""_setlocation: Set the location of the icon for the object."""
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=object_alias, fr=None)
aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('posn'), fr=aeobj_00)
args['----'] = aeobj_01
args["data"] = [x, y]
_reply, args, attrs = finder.send("core", "setd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
return (x,y)
def _getlocation(object_alias):
"""_getlocation: get the location of the icon for the object."""
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=object_alias, fr=None)
aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('posn'), fr=aeobj_00)
args['----'] = aeobj_01
_reply, args, attrs = finder.send("core", "getd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
pos = args['----']
return pos.h, pos.v
def label(object, index=None):
"""label: set or get the label of the item. Specify file by name or fsspec."""
fss = macfs.FSSpec(object)
object_alias = fss.NewAlias()
if index == None:
return _getlabel(object_alias)
if index < 0 or index > 7:
index = 0
return _setlabel(object_alias, index)
def _getlabel(object_alias):
"""label: Get the label for the object."""
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'), form="alis", seld=object_alias, fr=None)
aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('labi'), fr=aeobj_00)
args['----'] = aeobj_01
_reply, args, attrs = finder.send("core", "getd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def _setlabel(object_alias, index):
"""label: Set the label for the object."""
finder = _getfinder()
args = {}
attrs = {}
_code = 'core'
_subcode = 'setd'
aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="alis", seld=object_alias, fr=None)
aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('labi'), fr=aeobj_0)
args['----'] = aeobj_1
args["data"] = index
_reply, args, attrs = finder.send(_code, _subcode, args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
return index
def windowview(folder, view=None):
"""windowview: Set the view of the window for the folder. Specify file by name or fsspec.
0 = by icon (default)
1 = by name
2 = by button
"""
fss = macfs.FSSpec(folder)
folder_alias = fss.NewAlias()
if view == None:
return _getwindowview(folder_alias)
return _setwindowview(folder_alias, view)
def _setwindowview(folder_alias, view=0):
"""set the windowview"""
attrs = {}
args = {}
if view == 1:
_v = aetypes.Type('pnam')
elif view == 2:
_v = aetypes.Type('lgbu')
else:
_v = aetypes.Type('iimg')
finder = _getfinder()
aeobj_0 = aetypes.ObjectSpecifier(want = aetypes.Type('cfol'),
form = 'alis', seld = folder_alias, fr=None)
aeobj_1 = aetypes.ObjectSpecifier(want = aetypes.Type('prop'),
form = 'prop', seld = aetypes.Type('cwnd'), fr=aeobj_0)
aeobj_2 = aetypes.ObjectSpecifier(want = aetypes.Type('prop'),
form = 'prop', seld = aetypes.Type('pvew'), fr=aeobj_1)
aeobj_3 = aetypes.ObjectSpecifier(want = aetypes.Type('prop'),
form = 'prop', seld = _v, fr=None)
_code = 'core'
_subcode = 'setd'
args['----'] = aeobj_2
args['data'] = aeobj_3
_reply, args, attrs = finder.send(_code, _subcode, args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def _getwindowview(folder_alias):
"""get the windowview"""
attrs = {}
args = {}
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=folder_alias, fr=None)
aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_00)
aeobj_02 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('pvew'), fr=aeobj_01)
args['----'] = aeobj_02
_reply, args, attrs = finder.send("core", "getd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
views = {'iimg':0, 'pnam':1, 'lgbu':2}
if args.has_key('----'):
return views[args['----'].enum]
def windowsize(folder, size=None):
"""Set the size of a Finder window for folder to size=(w, h), Specify by path.
If size=None, windowsize will return the current size of the window.
Specify file by name or fsspec.
"""
fss = macfs.FSSpec(folder)
folder_alias = fss.NewAlias()
openwindow(fss)
if not size:
return _getwindowsize(folder_alias)
return _setwindowsize(folder_alias, size)
def _setwindowsize(folder_alias, (w, h)):
"""Set the size of a Finder window for folder to (w, h)"""
finder = _getfinder()
args = {}
attrs = {}
_code = 'core'
_subcode = 'setd'
aevar00 = [w, h]
aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'),
form="alis", seld=folder_alias, fr=None)
aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_0)
aeobj_2 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('ptsz'), fr=aeobj_1)
args['----'] = aeobj_2
args["data"] = aevar00
_reply, args, attrs = finder.send(_code, _subcode, args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
return (w, h)
def _getwindowsize(folder_alias):
"""Set the size of a Finder window for folder to (w, h)"""
finder = _getfinder()
args = {}
attrs = {}
aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'),
form="alis", seld=folder_alias, fr=None)
aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_0)
aeobj_2 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('posn'), fr=aeobj_1)
args['----'] = aeobj_2
_reply, args, attrs = finder.send('core', 'getd', args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def windowposition(folder, pos=None):
"""Set the position of a Finder window for folder to pos=(w, h)."""
fss = macfs.FSSpec(folder)
folder_alias = fss.NewAlias()
openwindow(fss)
if not pos:
return _getwindowposition(folder_alias)
if type(pos) == InstanceType:
# pos might be a QDPoint object as returned by _getwindowposition
pos = (pos.h, pos.v)
return _setwindowposition(folder_alias, pos)
def _setwindowposition(folder_alias, (x, y)):
"""Set the size of a Finder window for folder to (w, h)."""
finder = _getfinder()
args = {}
attrs = {}
aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'),
form="alis", seld=folder_alias, fr=None)
aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_0)
aeobj_2 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('posn'), fr=aeobj_1)
args['----'] = aeobj_2
args["data"] = [x, y]
_reply, args, attrs = finder.send('core', 'setd', args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def _getwindowposition(folder_alias):
"""Get the size of a Finder window for folder, Specify by path."""
finder = _getfinder()
args = {}
attrs = {}
aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'),
form="alis", seld=folder_alias, fr=None)
aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_0)
aeobj_2 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('ptsz'), fr=aeobj_1)
args['----'] = aeobj_2
_reply, args, attrs = finder.send('core', 'getd', args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def icon(object, icondata=None):
"""icon sets the icon of object, if no icondata is given,
icon will return an AE object with binary data for the current icon.
If left untouched, this data can be used to paste the icon on another file.
Development opportunity: get and set the data as PICT."""
fss = macfs.FSSpec(object)
object_alias = fss.NewAlias()
if icondata == None:
return _geticon(object_alias)
return _seticon(object_alias, icondata)
def _geticon(object_alias):
"""get the icondata for object. Binary data of some sort."""
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'),
form="alis", seld=object_alias, fr=None)
aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('iimg'), fr=aeobj_00)
args['----'] = aeobj_01
_reply, args, attrs = finder.send("core", "getd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def _seticon(object_alias, icondata):
"""set the icondata for object, formatted as produced by _geticon()"""
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'),
form="alis", seld=object_alias, fr=None)
aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
form="prop", seld=aetypes.Type('iimg'), fr=aeobj_00)
args['----'] = aeobj_01
args["data"] = icondata
_reply, args, attrs = finder.send("core", "setd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----'].data
#---------------------------------------------------
# Volumes and servers.
def mountvolume(volume, server=None, username=None, password=None):
"""mount a volume, local or on a server on AppleTalk.
Note: mounting a ASIP server requires a different operation.
server is the name of the server where the volume belongs
username, password belong to a registered user of the volume."""
finder = _getfinder()
args = {}
attrs = {}
if password:
args["PASS"] = password
if username:
args["USER"] = username
if server:
args["SRVR"] = server
args['----'] = volume
_reply, args, attrs = finder.send("aevt", "mvol", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def unmountvolume(volume):
"""unmount a volume that's on the desktop"""
putaway(volume)
def putaway(object):
"""puth the object away, whereever it came from."""
finder = _getfinder()
args = {}
attrs = {}
args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('cdis'), form="name", seld=object, fr=None)
_reply, args, attrs = talker.send("fndr", "ptwy", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
#---------------------------------------------------
# Miscellaneous functions
#
def volumelevel(level):
"""set the audio output level, parameter between 0 (silent) and 7 (full blast)"""
finder = _getfinder()
args = {}
attrs = {}
if level < 0:
level = 0
elif level > 7:
level = 7
args['----'] = level
_reply, args, attrs = finder.send("aevt", "stvl", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def OSversion():
"""return the version of the system software"""
finder = _getfinder()
args = {}
attrs = {}
aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('ver2'), fr=None)
args['----'] = aeobj_00
_reply, args, attrs = finder.send("core", "getd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
return args['----']
def filesharing():
"""return the current status of filesharing and whether it is starting up or not:
-1 file sharing is off and not starting up
0 file sharing is off and starting up
1 file sharing is on"""
status = -1
finder = _getfinder()
# see if it is on
args = {}
attrs = {}
args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('fshr'), fr=None)
_reply, args, attrs = finder.send("core", "getd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
if args['----'] == 0:
status = -1
else:
status = 1
# is it starting up perchance?
args = {}
attrs = {}
args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('fsup'), fr=None)
_reply, args, attrs = finder.send("core", "getd", args, attrs)
if args.has_key('errn'):
raise Error, aetools.decodeerror(args)
if args.has_key('----'):
if args['----'] == 1:
status = 0
return status
def movetotrash(path):
"""move the object to the trash"""
fss = macfs.FSSpec(path)
trashfolder = macfs.FSSpec(macfs.FindFolder(fss.as_tuple()[0], 'trsh', 0) + ("",)).as_pathname()
move(path, trashfolder)
def emptytrash():
"""empty the trash"""
finder = _getfinder()
args = {}
attrs = {}
args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('trsh'), fr=None)
_reply, args, attrs = finder.send("fndr", "empt", args, attrs)
if args.has_key('errn'):
raise aetools.Error, aetools.decodeerror(args)
def _test():
print 'Original findertools functionality test...'
print 'Testing launch...'
fss, ok = macfs.PromptGetFile('File to launch:')
if ok:
result = launch(fss)
if result:
print 'Result: ', result
print 'Press return-',
sys.stdin.readline()
print 'Testing print...'
fss, ok = macfs.PromptGetFile('File to print:')
if ok:
result = Print(fss)
if result:
print 'Result: ', result
print 'Press return-',
sys.stdin.readline()
print 'Testing copy...'
fss, ok = macfs.PromptGetFile('File to copy:')
if ok:
dfss, ok = macfs.GetDirectory()
if ok:
result = copy(fss, dfss)
if result:
print 'Result:', result
print 'Press return-',
sys.stdin.readline()
print 'Testing move...'
fss, ok = macfs.PromptGetFile('File to move:')
if ok:
dfss, ok = macfs.GetDirectory()
if ok:
result = move(fss, dfss)
if result:
print 'Result:', result
print 'Press return-',
sys.stdin.readline()
import EasyDialogs
print 'Testing sleep...'
if EasyDialogs.AskYesNoCancel('Sleep?') > 0:
result = sleep()
if result:
print 'Result:', result
print 'Press return-',
sys.stdin.readline()
print 'Testing shutdown...'
if EasyDialogs.AskYesNoCancel('Shut down?') > 0:
result = shutdown()
if result:
print 'Result:', result
print 'Press return-',
sys.stdin.readline()
print 'Testing restart...'
if EasyDialogs.AskYesNoCancel('Restart?') > 0:
result = restart()
if result:
print 'Result:', result
print 'Press return-',
sys.stdin.readline()
def _test2():
print '\nmorefindertools version %s\nTests coming upƒ' %__version__
import os
import random
# miscellaneous
print '\tfilesharing on?', filesharing() # is file sharing on, off, starting up?
print '\tOS version', OSversion() # the version of the system software
# set the soundvolume in a simple way
print '\tSystem beep volume'
for i in range(0, 7):
volumelevel(i)
MacOS.SysBeep()
# Finder's windows, file location, file attributes
open("@findertoolstest", "w")
f = macfs.FSSpec("@findertoolstest").as_pathname()
reveal(f) # reveal this file in a Finder window
select(f) # select this file
base, file = os.path.split(f)
closewindow(base) # close the window this file is in (opened by reveal)
openwindow(base) # open it again
windowview(base, 1) # set the view by list
label(f, 2) # set the label of this file to something orange
print '\tlabel', label(f) # get the label of this file
# the file location only works in a window with icon view!
print 'Random locations for an icon'
windowview(base, 0) # set the view by icon
windowsize(base, (600, 600))
for i in range(50):
location(f, (random.randint(10, 590), random.randint(10, 590)))
windowsize(base, (200, 400))
windowview(base, 1) # set the view by icon
orgpos = windowposition(base)
print 'Animated window location'
for i in range(10):
pos = (100+i*10, 100+i*10)
windowposition(base, pos)
print '\twindow position', pos
windowposition(base, orgpos) # park it where it was beforeƒ
print 'Put a comment in file', f, ':'
print '\t', comment(f) # print the Finder comment this file has
s = 'This is a comment no one reads!'
comment(f, s) # set the Finder comment
def _test3():
print 'MacOS9 or better specific functions'
# processes
pr = processes() # return a list of tuples with (active_processname, creatorcode)
print 'Return a list of current active processes:'
for p in pr:
print '\t', p
# get attributes of the first process in the list
print 'Attributes of the first process in the list:'
pinfo = processinfo(pr[0][0])
print '\t', pr[0][0]
print '\t\tmemory partition', pinfo.partition # the memory allocated to this process
print '\t\tmemory used', pinfo.used # the memory actuall used by this process
print '\t\tis visible', pinfo.visible # is the process visible to the user
print '\t\tis frontmost', pinfo.frontmost # is the process the front most one?
print '\t\thas scripting', pinfo.hasscripting # is the process scriptable?
print '\t\taccepts high level events', pinfo.accepthighlevel # does the process accept high level appleevents?
if __name__ == '__main__':
_test()
_test2()
_test3()
--- NEW FILE: ic.py ---
"""IC wrapper module, based on Internet Config 1.3"""
import icglue
import string
import sys
from Carbon import Res
import macfs
import macostools
error=icglue.error
# From ictypes.h:
icPrefNotFoundErr = -666 # preference not found (duh!)
icPermErr = -667 # cannot set preference
icPrefDataErr = -668 # problem with preference data
icInternalErr = -669 # hmm, this is not good
icTruncatedErr = -670 # more data was present than was returned
icNoMoreWritersErr = -671 # you cannot begin a write session because someone else is already doing it */
icNothingToOverrideErr = -672 # no component for the override component to capture
icNoURLErr = -673 # no URL found
icConfigNotFoundErr = -674 # no configuration was found
icConfigInappropriateErr = -675 # incorrect manufacturer code
ICattr_no_change = -1
icNoPerm = 0
icReadOnlyPerm = 1
icReadWritePerm = 2
# End of ictypes.h
class ICOpaqueData:
"""An unparseable IC entry"""
def __init__(self, data):
self.data = data
def __repr__(self):
return "ICOpaqueData(%s)"%`self.data`
_ICOpaqueDataType=type(ICOpaqueData(''))
def _decode_default(data, key):
if len(data) == 0:
return data
if ord(data[0]) == len(data)-1:
# Assume Pstring
return data[1:]
return ICOpaqueData(data)
def _decode_multistr(data, key):
numstr = ord(data[0]) << 8 | ord(data[1])
rv = []
ptr = 2
for i in range(numstr):
strlen = ord(data[ptr])
str = data[ptr+1:ptr+strlen+1]
rv.append(str)
ptr = ptr + strlen + 1
return rv
def _decode_fontrecord(data, key):
size = ord(data[0]) << 8 | ord(data[1])
face = ord(data[2])
namelen = ord(data[4])
return size, face, data[5:5+namelen]
def _decode_boolean(data, key):
return ord(data[0])
def _decode_text(data, key):
return data
def _decode_charset(data, key):
return data[:256], data[256:]
def _decode_appspec(data, key):
namelen = ord(data[4])
return data[0:4], data[5:5+namelen]
def _code_default(data, key):
return chr(len(data)) + data
def _code_multistr(data, key):
numstr = len(data)
rv = chr((numstr>>8) & 0xff) + chr(numstr & 0xff)
for i in data:
rv = rv + _code_default(i)
return rv
def _code_fontrecord(data, key):
size, face, name = data
return chr((size>>8) & 0xff) + chr(size & 0xff) + chr(face & 0xff) + \
chr(0) + _code_default(name)
def _code_boolean(data, key):
print 'XXXX boolean:', `data`
return chr(data)
def _code_text(data, key):
return data
def _code_charset(data, key):
return data[0] + data[1]
def _code_appspec(data, key):
return data[0] + _code_default(data[1])
_decoder_table = {
"ArchieAll" : (_decode_multistr , _code_multistr),
"UMichAll" : (_decode_multistr , _code_multistr),
"InfoMacAll" : (_decode_multistr , _code_multistr),
"ListFont" : (_decode_fontrecord , _code_fontrecord),
"ScreenFont" : (_decode_fontrecord , _code_fontrecord),
"PrinterFont" : (_decode_fontrecord , _code_fontrecord),
# "DownloadFolder" : (_decode_filespec , _code_filespec),
"Signature": (_decode_text , _code_text),
"Plan" : (_decode_text , _code_text),
"MailHeaders" : (_decode_text , _code_text),
"NewsHeaders" : (_decode_text , _code_text),
# "Mapping"
"CharacterSet" : (_decode_charset , _code_charset),
"Helper\245" : (_decode_appspec , _code_appspec),
# "Services" : (_decode_services, ????),
"NewMailFlashIcon" : (_decode_boolean , _code_boolean),
"NewMailDialog" : (_decode_boolean , _code_boolean),
"NewMailPlaySound" : (_decode_boolean , _code_boolean),
# "WebBackgroundColor" : _decode_color,
"NoProxyDomains" : (_decode_multistr , _code_multistr),
"UseHTTPProxy" : (_decode_boolean , _code_boolean),
"UseGopherProxy": (_decode_boolean , _code_boolean),
"UseFTPProxy" : (_decode_boolean , _code_boolean),
"UsePassiveFTP" : (_decode_boolean , _code_boolean),
}
def _decode(data, key):
if '\245' in key:
key2 = key[:string.index(key, '\245')+1]
else:
key2 = key
if _decoder_table.has_key(key2):
decoder = _decoder_table[key2][0]
else:
decoder = _decode_default
return decoder(data, key)
def _code(data, key):
if type(data) == _ICOpaqueDataType:
return data.data
if '\245' in key:
key2 = key[:string.index(key, '\245')+1]
else:
key2 = key
if _decoder_table.has_key(key2):
coder = _decoder_table[key2][1]
else:
coder = _code_default
return coder(data, key)
class IC:
def __init__(self, signature='Pyth', ic=None):
if ic:
self.ic = ic
else:
self.ic = icglue.ICStart(signature)
if hasattr(self.ic, 'ICFindConfigFile'):
self.ic.ICFindConfigFile()
self.h = Res.Resource('')
def keys(self):
rv = []
self.ic.ICBegin(icReadOnlyPerm)
num = self.ic.ICCountPref()
for i in range(num):
rv.append(self.ic.ICGetIndPref(i+1))
self.ic.ICEnd()
return rv
def has_key(self, key):
return self.__contains__(key)
def __contains__(self, key):
try:
dummy = self.ic.ICFindPrefHandle(key, self.h)
except icglue.error:
return 0
return 1
def __getitem__(self, key):
attr = self.ic.ICFindPrefHandle(key, self.h)
return _decode(self.h.data, key)
def __setitem__(self, key, value):
value = _code(value, key)
self.ic.ICSetPref(key, ICattr_no_change, value)
def launchurl(self, url, hint=""):
self.ic.ICLaunchURL(hint, url, 0, len(url))
def parseurl(self, data, start=None, end=None, hint=""):
if start == None:
selStart = 0
selEnd = len(data)
else:
selStart = selEnd = start
if end != None:
selEnd = end
selStart, selEnd = self.ic.ICParseURL(hint, data, selStart, selEnd, self.h)
return self.h.data, selStart, selEnd
def mapfile(self, file):
if type(file) != type(''):
file = file.as_tuple()[2]
return self.ic.ICMapFilename(file)
def maptypecreator(self, type, creator, filename=""):
return self.ic.ICMapTypeCreator(type, creator, filename)
def settypecreator(self, file):
if type(file) == type(''):
fss = macfs.FSSpec(file)
else:
fss = file
name = fss.as_tuple()[2]
record = self.mapfile(name)
fss.SetCreatorType(record[2], record[1])
macostools.touched(fss)
# Convenience routines
_dft_ic = None
def launchurl(url, hint=""):
global _dft_ic
if _dft_ic == None: _dft_ic = IC()
return _dft_ic.launchurl(url, hint)
def parseurl(data, start=None, end=None, hint=""):
global _dft_ic
if _dft_ic == None: _dft_ic = IC()
return _dft_ic.parseurl(data, start, end, hint)
def mapfile(filename):
global _dft_ic
if _dft_ic == None: _dft_ic = IC()
return _dft_ic.mapfile(filename)
def maptypecreator(type, creator, filename=""):
global _dft_ic
if _dft_ic == None: _dft_ic = IC()
return _dft_ic.maptypecreator(type, creator, filename)
def settypecreator(file):
global _dft_ic
if _dft_ic == None: _dft_ic = IC()
return _dft_ic.settypecreator(file)
def _test():
ic = IC()
for k in ic.keys():
try:
v = ic[k]
except error:
v = '????'
print k, '\t', v
sys.exit(1)
if __name__ == '__main__':
_test()
--- NEW FILE: icopen.py ---
"""icopen patch
OVERVIEW
icopen patches MacOS Python to use the Internet Config file mappings to select
the type and creator for a file.
Version 1 released to the public domain 3 November 1999
by Oliver Steele (steele@cs.brandeis.edu).
DETAILS
This patch causes files created by Python's open(filename, 'w') command (and
by functions and scripts that call it) to set the type and creator of the file
to the type and creator associated with filename's extension (the
portion of the filename after the last period), according to Internet Config.
Thus, a script that creates a file foo.html will create one that opens in whatever
browser you've set to handle *.html files, and so on.
Python IDE uses its own algorithm to select the type and creator for saved
editor windows, so this patch won't effect their types.
As of System 8.6 at least, Internet Config is built into the system, and the
file mappings are accessed from the Advanced pane of the Internet control
panel. User Mode (in the Edit menu) needs to be set to Advanced in order to
access this pane.
INSTALLATION
Put this file in your Python path, and create a file named {Python}:sitecustomize.py
that contains:
import icopen
(If {Python}:sitecustomizer.py already exists, just add the 'import' line to it.)
The next time you launch PythonInterpreter or Python IDE, the patch will take
effect.
"""
import __builtin__
_builtin_open = globals().get('_builtin_open', __builtin__.open)
def _open_with_typer(*args):
file = apply(_builtin_open, args)
filename = args[0]
mode = 'r'
if args[1:]:
mode = args[1]
if mode[0] == 'w':
from ic import error, settypecreator
try:
settypecreator(filename)
except error:
pass
return file
__builtin__.open = _open_with_typer
"""
open('test.py')
_open_with_typer('test.py', 'w')
_open_with_typer('test.txt', 'w')
_open_with_typer('test.html', 'w')
_open_with_typer('test.foo', 'w')
"""
--- NEW FILE: macerrors.py ---
svTempDisable = -32768 #svTempDisable
svDisabled = -32640 #Reserve range -32640 to -32768 for Apple temp disables.
fontNotOutlineErr = -32615 #bitmap font passed to routine that does outlines only
kURL68kNotSupportedError = -30788 #kURL68kNotSupportedError
kURLAccessNotAvailableError = -30787 #kURLAccessNotAvailableError
kURLInvalidConfigurationError = -30786 #kURLInvalidConfigurationError
kURLExtensionFailureError = -30785 #kURLExtensionFailureError
kURLFileEmptyError = -30783 #kURLFileEmptyError
kURLInvalidCallError = -30781 #kURLInvalidCallError
kURLUnsettablePropertyError = -30780 #kURLUnsettablePropertyError
kURLPropertyBufferTooSmallError = -30779 #kURLPropertyBufferTooSmallError
kURLUnknownPropertyError = -30778 #kURLUnknownPropertyError
kURLPropertyNotYetKnownError = -30777 #kURLPropertyNotYetKnownError
kURLAuthenticationError = -30776 #kURLAuthenticationError
kURLServerBusyError = -30775 #kURLServerBusyError
kURLUnsupportedSchemeError = -30774 #kURLUnsupportedSchemeError
kURLInvalidURLError = -30773 #kURLInvalidURLError
kURLDestinationExistsError = -30772 #kURLDestinationExistsError
kURLProgressAlreadyDisplayedError = -30771 #kURLProgressAlreadyDisplayedError
[...1813 lines suppressed...]
ENETRESET = 52 #Network dropped connection on reset
ECONNABORTED = 53 #Software caused connection abort
ECONNRESET = 54 #Connection reset by peer
ENOBUFS = 55 #No buffer space available
EISCONN = 56 #Socket is already connected
ENOTCONN = 57 #Socket is not connected
ESHUTDOWN = 58 #Can't send after socket shutdown
ETOOMANYREFS = 59 #Too many references: can't splice
ETIMEDOUT = 60 #Operation timed out
ECONNREFUSED = 61 #Connection refused
ELOOP = 62 #Too many levels of symbolic links
ENAMETOOLONG = 63 #File name too long
EHOSTDOWN = 64 #Host is down
EHOSTUNREACH = 65 #No route to host
ENOTEMPTY = 66 #Directory not empty
ELOOK = 67 #Internal mapping for kOTLookErr, don't return to client
ENOLCK = 77 #No locks available
ENOSYS = 78 #Function not implemented
EILSEQ = 88 #Wide character encoding error
EUNKNOWN = 99 #Unknown error
--- NEW FILE: macfs.py ---
"""macfs - Pure Python module designed to be backward compatible with
macfs and MACFS.
"""
import sys
import struct
import Carbon.Res
import Carbon.File
import Nav
# First step: ensure we also emulate the MACFS module, which contained
# all the constants
sys.modules['MACFS'] = sys.modules[__name__]
# Import all those constants
from Carbon.Files import *
from Carbon.Folders import *
# For some obscure historical reason these are here too:
READ = 1
WRITE = 2
smAllScripts = -3
# The old name of the error object:
error = Carbon.File.Error
#
# The various objects macfs used to export. We override them here, because some
# of the method names are subtly different.
#
class FSSpec(Carbon.File.FSSpec):
def as_fsref(self):
return FSRef(self)
def NewAlias(self, src=None):
return Alias(Carbon.File.NewAlias(src, self))
def GetCreatorType(self):
finfo = self.FSpGetFInfo()
return finfo.Creator, finfo.Type
def SetCreatorType(self, ctor, tp):
finfo = self.FSpGetFInfo()
finfo.Creator = ctor
finfo.Type = tp
self.FSpSetFInfo(finfo)
def GetFInfo(self):
return self.FSpGetFInfo()
def SetFInfo(self, info):
return self.FSpSetFInfo(info)
def GetDates(self):
import os
statb = os.stat(self.as_pathname())
return statb.st_ctime, statb.st_mtime, 0
def SetDates(self, *dates):
print "FSSpec.SetDates no longer implemented"
class FSRef(Carbon.File.FSRef):
def as_fsspec(self):
return FSSpec(self)
class Alias(Carbon.File.Alias):
def GetInfo(self, index):
return self.GetAliasInfo(index)
def Update(self, *args):
print "Alias.Update not yet implemented"
def Resolve(self, src=None):
fss, changed = self.ResolveAlias(src)
return FSSpec(fss), changed
from Carbon.File import FInfo
# Backward-compatible type names:
FSSpecType = FSSpec
FSRefType = FSRef
AliasType = Alias
FInfoType = FInfo
# Global functions:
def ResolveAliasFile(fss, chain=1):
fss, isdir, isalias = Carbon.File.ResolveAliasFile(fss, chain)
return FSSpec(fss), isdir, isalias
def RawFSSpec(data):
return FSSpec(rawdata=data)
def RawAlias(data):
return Alias(rawdata=data)
def FindApplication(*args):
raise NotImplementedError, "FindApplication no longer implemented"
def NewAliasMinimalFromFullPath(path):
return Alias(Carbon.File.NewAliasMinimalFromFullPath(path, '', ''))
# Another global function:
from Carbon.Folder import FindFolder
#
# Finally the old Standard File routine emulators.
#
_movablemodal = 0
_curfolder = None
def _mktypelist(typelist):
# Workaround for OSX typeless files:
if 'TEXT' in typelist and not '\0\0\0\0' in typelist:
typelist = typelist + ('\0\0\0\0',)
if not typelist:
return None
data = 'Pyth' + struct.pack("hh", 0, len(typelist))
for type in typelist:
data = data+type
return Carbon.Res.Handle(data)
def StandardGetFile(*typelist):
"""Ask for an input file, optionally specifying 4-char file types that are
allowable"""
return apply(PromptGetFile, (None,)+typelist)
def PromptGetFile(prompt, *typelist):
"""Ask for an input file giving the user a prompt message. Optionally you can
specifying 4-char file types that are allowable"""
args = {}
flags = 0x56
typehandle = _mktypelist(typelist)
if typehandle:
args['typeList'] = typehandle
else:
flags = flags | 0x01
if prompt:
args['message'] = prompt
args['preferenceKey'] = 'PyMC'
if _movablemodal:
args['eventProc'] = None
args['dialogOptionFlags'] = flags
_handleSetFolder(args)
try:
rr = Nav.NavChooseFile(args)
good = 1
except Nav.error, arg:
if arg[0] != -128: # userCancelledErr
raise Nav.error, arg
good = 0
fss = None
else:
if rr.selection:
fss = FSSpec(rr.selection[0])
else:
fss = None
good = 0
## if typehandle:
## typehandle.DisposeHandle()
return fss, good
def StandardPutFile(prompt, default=None):
"""Ask the user for an output file, with a prompt. Optionally you cn supply a
default output filename"""
args = {}
flags = 0x07
if prompt:
args['message'] = prompt
args['preferenceKey'] = 'PyMC'
if _movablemodal:
args['eventProc'] = None
if default:
args['savedFileName'] = default
args['dialogOptionFlags'] = flags
_handleSetFolder(args)
try:
rr = Nav.NavPutFile(args)
good = 1
except Nav.error, arg:
if arg[0] != -128: # userCancelledErr
raise Nav.error, arg
good = 0
fss = None
else:
fss = FSSpec(rr.selection[0])
return fss, good
def SetFolder(folder):
global _curfolder
if _curfolder:
rv = _curfolder
else:
rv = None
_curfolder = FSSpec(folder)
return rv
def _handleSetFolder(args):
global _curfolder
if not _curfolder:
return
import aepack
fss = _curfolder
aedesc = aepack.pack(fss)
args['defaultLocation'] = aedesc
_curfolder = None
def GetDirectory(prompt=None):
"""Ask the user to select a folder. Optionally you can give a prompt."""
args = {}
flags = 0x17
if prompt:
args['message'] = prompt
args['preferenceKey'] = 'PyMC'
if _movablemodal:
args['eventProc'] = None
args['dialogOptionFlags'] = flags
_handleSetFolder(args)
try:
rr = Nav.NavChooseFolder(args)
good = 1
except Nav.error, arg:
if arg[0] != -128: # userCancelledErr
raise Nav.error, arg
good = 0
fss = None
else:
fss = FSSpec(rr.selection[0])
return fss, good
--- NEW FILE: macostools.py ---
"""macostools - Various utility functions for MacOS.
mkalias(src, dst) - Create a finder alias 'dst' pointing to 'src'
copy(src, dst) - Full copy of 'src' to 'dst'
"""
import macfs
from Carbon import Res
import os
from MACFS import *
import MacOS
import time
try:
openrf = MacOS.openrf
except AttributeError:
# Backward compatability
openrf = open
Error = 'macostools.Error'
BUFSIZ=0x80000 # Copy in 0.5Mb chunks
#
# Not guaranteed to be correct or stay correct (Apple doesn't tell you
# how to do this), but it seems to work.
#
def mkalias(src, dst, relative=None):
"""Create a finder alias"""
srcfss = macfs.FSSpec(src)
# The next line will fail under unix-Python if the destination
# doesn't exist yet. We should change this code to be fsref-based.
dstfss = macfs.FSSpec(dst)
if relative:
relativefss = macfs.FSSpec(relative)
# ik mag er geen None in stoppen :-(
alias = srcfss.NewAlias(relativefss)
else:
alias = srcfss.NewAlias()
if os.path.isdir(src):
cr, tp = 'MACS', 'fdrp'
else:
cr, tp = srcfss.GetCreatorType()
Res.FSpCreateResFile(dstfss, cr, tp, -1)
h = Res.FSpOpenResFile(dstfss, 3)
resource = Res.Resource(alias.data)
resource.AddResource('alis', 0, '')
Res.CloseResFile(h)
dstfinfo = dstfss.GetFInfo()
dstfinfo.Flags = dstfinfo.Flags|0x8000 # Alias flag
dstfss.SetFInfo(dstfinfo)
def mkdirs(dst):
"""Make directories leading to 'dst' if they don't exist yet"""
if dst == '' or os.path.exists(dst):
return
head, tail = os.path.split(dst)
if os.sep == ':' and not ':' in head:
head = head + ':'
mkdirs(head)
os.mkdir(dst, 0777)
def touched(dst):
"""Tell the finder a file has changed"""
file_fss = macfs.FSSpec(dst)
vRefNum, dirID, name = file_fss.as_tuple()
dir_fss = macfs.FSSpec((vRefNum, dirID, ''))
crdate, moddate, bkdate = dir_fss.GetDates()
now = time.time()
if now == moddate:
now = now + 1
try:
dir_fss.SetDates(crdate, now, bkdate)
except macfs.error:
pass
def touched_ae(dst):
"""Tell the finder a file has changed"""
import Finder
f = Finder.Finder()
file_fss = macfs.FSSpec(dst)
vRefNum, dirID, name = file_fss.as_tuple()
dir_fss = macfs.FSSpec((vRefNum, dirID, ''))
f.update(dir_fss)
def copy(src, dst, createpath=0, copydates=1, forcetype=None):
"""Copy a file, including finder info, resource fork, etc"""
if hasattr(src, 'as_pathname'):
src = src.as_pathname()
if hasattr(dst, 'as_pathname'):
dst = dst.as_pathname()
if createpath:
mkdirs(os.path.split(dst)[0])
ifp = open(src, 'rb')
ofp = open(dst, 'wb')
d = ifp.read(BUFSIZ)
while d:
ofp.write(d)
d = ifp.read(BUFSIZ)
ifp.close()
ofp.close()
ifp = openrf(src, '*rb')
ofp = openrf(dst, '*wb')
d = ifp.read(BUFSIZ)
while d:
ofp.write(d)
d = ifp.read(BUFSIZ)
ifp.close()
ofp.close()
srcfss = macfs.FSSpec(src)
dstfss = macfs.FSSpec(dst)
sf = srcfss.GetFInfo()
df = dstfss.GetFInfo()
df.Creator, df.Type = sf.Creator, sf.Type
if forcetype != None:
df.Type = forcetype
df.Flags = (sf.Flags & (kIsStationary|kNameLocked|kHasBundle|kIsInvisible|kIsAlias))
dstfss.SetFInfo(df)
if copydates:
crdate, mddate, bkdate = srcfss.GetDates()
dstfss.SetDates(crdate, mddate, bkdate)
touched(dstfss)
def copytree(src, dst, copydates=1):
"""Copy a complete file tree to a new destination"""
if os.path.isdir(src):
mkdirs(dst)
files = os.listdir(src)
for f in files:
copytree(os.path.join(src, f), os.path.join(dst, f), copydates)
else:
copy(src, dst, 1, copydates)
--- NEW FILE: macresource.py ---
"""macresource - Locate and open the resources needed for a script."""
from Carbon import Res
import os
import sys
class ArgumentError(TypeError): pass
class ResourceFileNotFoundError(ImportError): pass
def need(restype, resid, filename=None, modname=None):
"""Open a resource file, if needed. restype and resid
are required parameters, and identify the resource for which to test. If it
is available we are done. If it is not available we look for a file filename
(default: modname with .rsrc appended) either in the same folder as
where modname was loaded from, or otherwise across sys.path.
Returns the refno of the resource file opened (or None)"""
if modname is None and filename is None:
raise ArgumentError, "Either filename or modname argument (or both) must be given"
if type(resid) is type(1):
try:
h = Res.GetResource(restype, resid)
except Res.Error:
pass
else:
return None
else:
try:
h = Res.GetNamedResource(restype, resid)
except Res.Error:
pass
else:
return None
# Construct a filename if we don't have one
if not filename:
if '.' in modname:
filename = modname.split('.')[-1] + '.rsrc'
else:
filename = modname + '.rsrc'
# Now create a list of folders to search
searchdirs = []
if modname == '__main__':
# If we're main we look in the current directory
searchdirs = [os.curdir]
if sys.modules.has_key(modname):
mod = sys.modules[modname]
if hasattr(mod, '__file__'):
searchdirs = [os.path.split(mod.__file__)[0]]
if not searchdirs:
searchdirs = sys.path
# And look for the file
for dir in searchdirs:
pathname = os.path.join(dir, filename)
if os.path.exists(pathname):
break
else:
raise ResourceFileNotFoundError, filename
refno = open_pathname(pathname)
# And check that the resource exists now
if type(resid) is type(1):
h = Res.GetResource(restype, resid)
else:
h = Res.GetNamedResource(restype, resid)
return refno
def open_pathname(pathname, verbose=0):
"""Open a resource file given by pathname, possibly decoding an
AppleSingle file"""
try:
refno = Res.FSpOpenResFile(pathname, 1)
except Res.Error, arg:
if arg[0] in (-37, -39):
# No resource fork. We may be on OSX, and this may be either
# a data-fork based resource file or a AppleSingle file
# from the CVS repository.
try:
refno = Res.FSOpenResourceFile(pathname, u'', 1)
except Res.Error, arg:
if arg[0] != -199:
# -199 is "bad resource map"
raise
else:
return refno
# Finally try decoding an AppleSingle file
pathname = _decode(pathname, verbose=verbose)
refno = Res.FSOpenResourceFile(pathname, u'', 1)
else:
raise
return refno
def open_error_resource():
"""Open the resource file containing the error code to error message
mapping."""
need('Estr', 1, filename="errors.rsrc", modname=__name__)
def _decode(pathname, verbose=0):
# Decode an AppleSingle resource file, return the new pathname.
newpathname = pathname + '.df.rsrc'
if os.path.exists(newpathname) and \
os.stat(newpathname).st_mtime >= os.stat(pathname).st_mtime:
return newpathname
if verbose:
print 'Decoding', pathname
import applesingle
applesingle.decode(pathname, newpathname, resonly=1)
return newpathname
--- NEW FILE: plistlib.py ---
"""plistlib.py -- a tool to generate and parse MacOSX .plist files.
The main class in this module is Plist. It takes a set of arbitrary
keyword arguments, which will be the top level elements of the plist
dictionary. After instantiation you can add more elements by assigning
new attributes to the Plist instance.
To write out a plist file, call the write() method of the Plist
instance with a filename or a file object.
To parse a plist from a file, use the Plist.fromFile(pathOrFile)
classmethod, with a file name or a file object as the only argument.
(Warning: you need pyexpat installed for this to work, ie. it doesn't
work with a vanilla Python 2.2 as shipped with MacOS X.2.)
Values can be strings, integers, floats, booleans, tuples, lists,
dictionaries, Data or Date objects. String values (including dictionary
keys) may be unicode strings -- they will be written out as UTF-8.
For convenience, this module exports a class named Dict(), which
allows you to easily construct (nested) dicts using keyword arguments.
But regular dicts work, too.
To support Boolean values in plists with Python < 2.3, "bool", "True"
and "False" are exported. Use these symbols from this module if you
want to be compatible with Python 2.2.x (strongly recommended).
The <data> plist type is supported through the Data class. This is a
thin wrapper around a Python string.
The <date> plist data has (limited) support through the Date class.
(Warning: Dates are only supported if the PyXML package is installed.)
Generate Plist example:
pl = Plist(
aString="Doodah",
aList=["A", "B", 12, 32.1, [1, 2, 3]],
aFloat = 0.1,
anInt = 728,
aDict=Dict(
anotherString="<hello & hi there!>",
aUnicodeValue=u'M\xe4ssig, Ma\xdf',
aTrueValue=True,
aFalseValue=False,
),
someData = Data("<binary gunk>"),
someMoreData = Data("<lots of binary gunk>" * 10),
aDate = Date(time.mktime(time.gmtime())),
)
# unicode keys are possible, but a little awkward to use:
pl[u'\xc5benraa'] = "That was a unicode key."
pl.write(fileName)
Parse Plist example:
pl = Plist.fromFile(pathOrFile)
print pl.aKey
"""
# written by Just van Rossum (just@letterror.com), 2002-11-19
__all__ = ["Plist", "Data", "Date", "Dict", "False", "True", "bool"]
INDENT = "\t"
class DumbXMLWriter:
def __init__(self, file):
self.file = file
self.stack = []
self.indentLevel = 0
def beginElement(self, element):
self.stack.append(element)
self.writeln("<%s>" % element)
self.indentLevel += 1
def endElement(self, element):
assert self.indentLevel > 0
assert self.stack.pop() == element
self.indentLevel -= 1
self.writeln("</%s>" % element)
def simpleElement(self, element, value=None):
if value:
value = _encode(value)
self.writeln("<%s>%s</%s>" % (element, value, element))
else:
self.writeln("<%s/>" % element)
def writeln(self, line):
if line:
self.file.write(self.indentLevel * INDENT + line + "\n")
else:
self.file.write("\n")
def _encode(text):
text = text.replace("&", "&")
text = text.replace("<", "<")
return text.encode("utf-8")
PLISTHEADER = """\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
"""
class PlistWriter(DumbXMLWriter):
def __init__(self, file):
file.write(PLISTHEADER)
DumbXMLWriter.__init__(self, file)
def writeValue(self, value):
if isinstance(value, (str, unicode)):
self.simpleElement("string", value)
elif isinstance(value, bool):
# must switch for bool before int, as bool is a
# subclass of int...
if value:
self.simpleElement("true")
else:
self.simpleElement("false")
elif isinstance(value, int):
self.simpleElement("integer", str(value))
elif isinstance(value, float):
# should perhaps use repr() for better precision?
self.simpleElement("real", str(value))
elif isinstance(value, (dict, Dict)):
self.writeDict(value)
elif isinstance(value, Data):
self.writeData(value)
elif isinstance(value, Date):
self.simpleElement("date", value.toString())
elif isinstance(value, (tuple, list)):
self.writeArray(value)
else:
assert 0, "unsuported type: %s" % type(value)
def writeData(self, data):
self.beginElement("data")
for line in data.asBase64().split("\n"):
if line:
self.writeln(line)
self.endElement("data")
def writeDict(self, d):
self.beginElement("dict")
items = d.items()
items.sort()
for key, value in items:
assert isinstance(key, (str, unicode)), "keys must be strings"
self.simpleElement("key", key)
self.writeValue(value)
self.endElement("dict")
def writeArray(self, array):
self.beginElement("array")
for value in array:
self.writeValue(value)
self.endElement("array")
class Dict:
"""Dict wrapper for convenient access of values through attributes."""
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __cmp__(self, other):
if isinstance(other, self.__class__):
return cmp(self.__dict__, other.__dict__)
elif isinstance(other, dict):
return cmp(self.__dict__, other)
else:
return cmp(id(self), id(other))
def __str__(self):
return "%s(**%s)" % (self.__class__.__name__, self.__dict__)
__repr__ = __str__
def copy(self):
return self.__class__(**self.__dict__)
def __getattr__(self, attr):
"""Delegate everything else to the dict object."""
return getattr(self.__dict__, attr)
class Plist(Dict):
"""The main Plist object. Basically a dict (the toplevel object
of a plist is a dict) with two additional methods to read from
and write to files.
"""
def fromFile(cls, pathOrFile):
didOpen = 0
if not hasattr(pathOrFile, "write"):
pathOrFile = open(pathOrFile)
didOpen = 1
p = PlistParser()
plist = p.parse(pathOrFile)
if didOpen:
pathOrFile.close()
return plist
fromFile = classmethod(fromFile)
def write(self, pathOrFile):
if not hasattr(pathOrFile, "write"):
pathOrFile = open(pathOrFile, "w")
didOpen = 1
else:
didOpen = 0
writer = PlistWriter(pathOrFile)
writer.writeln("<plist version=\"1.0\">")
writer.writeDict(self.__dict__)
writer.writeln("</plist>")
if didOpen:
pathOrFile.close()
class Data:
"""Wrapper for binary data."""
def __init__(self, data):
self.data = data
def fromBase64(cls, data):
import base64
return cls(base64.decodestring(data))
fromBase64 = classmethod(fromBase64)
def asBase64(self):
import base64
return base64.encodestring(self.data)
def __cmp__(self, other):
if isinstance(other, self.__class__):
return cmp(self.data, other.data)
elif isinstance(other, str):
return cmp(self.data, other)
else:
return cmp(id(self), id(other))
def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self.data))
class Date:
"""Primitive date wrapper, uses time floats internally, is agnostic
about time zones.
"""
def __init__(self, date):
if isinstance(date, str):
from xml.utils.iso8601 import parse
date = parse(date)
self.date = date
def toString(self):
from xml.utils.iso8601 import tostring
return tostring(self.date)
def __cmp__(self, other):
if isinstance(other, self.__class__):
return cmp(self.date, other.date)
elif isinstance(other, (int, float)):
return cmp(self.date, other)
else:
return cmp(id(self), id(other))
def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self.toString()))
class PlistParser:
def __init__(self):
self.stack = []
self.currentKey = None
self.root = None
def parse(self, file):
from xml.parsers.expat import ParserCreate
parser = ParserCreate()
parser.StartElementHandler = self.handleBeginElement
parser.EndElementHandler = self.handleEndElement
parser.CharacterDataHandler = self.handleData
parser.ParseFile(file)
return self.root
def handleBeginElement(self, element, attrs):
self.data = []
handler = getattr(self, "begin_" + element, None)
if handler is not None:
handler(attrs)
def handleEndElement(self, element):
handler = getattr(self, "end_" + element, None)
if handler is not None:
handler()
def handleData(self, data):
self.data.append(data)
def addObject(self, value):
if self.currentKey is not None:
self.stack[-1][self.currentKey] = value
self.currentKey = None
elif not self.stack:
# this is the root object
assert self.root is value
else:
self.stack[-1].append(value)
def getData(self):
data = "".join(self.data)
try:
data = data.encode("ascii")
except UnicodeError:
pass
self.data = []
return data
# element handlers
def begin_dict(self, attrs):
if self.root is None:
self.root = d = Plist()
else:
d = Dict()
self.addObject(d)
self.stack.append(d)
def end_dict(self):
self.stack.pop()
def end_key(self):
self.currentKey = self.getData()
def begin_array(self, attrs):
a = []
self.addObject(a)
self.stack.append(a)
def end_array(self):
self.stack.pop()
def end_true(self):
self.addObject(True)
def end_false(self):
self.addObject(False)
def end_integer(self):
self.addObject(int(self.getData()))
def end_real(self):
self.addObject(float(self.getData()))
def end_string(self):
self.addObject(self.getData())
def end_data(self):
self.addObject(Data.fromBase64(self.getData()))
def end_date(self):
self.addObject(Date(self.getData()))
# cruft to support booleans in Python <= 2.3
import sys
if sys.version_info[:2] < (2, 3):
# Python 2.2 and earlier: no booleans
# Python 2.2.x: booleans are ints
class bool(int):
"""Imitation of the Python 2.3 bool object."""
def __new__(cls, value):
return int.__new__(cls, not not value)
def __repr__(self):
if self:
return "True"
else:
return "False"
True = bool(1)
False = bool(0)
else:
# Bind the boolean builtins to local names
True = True
False = False
bool = bool
if __name__ == "__main__":
from StringIO import StringIO
import time
if len(sys.argv) == 1:
pl = Plist(
aString="Doodah",
aList=["A", "B", 12, 32.1, [1, 2, 3]],
aFloat = 0.1,
anInt = 728,
aDict=Dict(
anotherString="<hello & hi there!>",
aUnicodeValue=u'M\xe4ssig, Ma\xdf',
aTrueValue=True,
aFalseValue=False,
),
someData = Data("<binary gunk>"),
someMoreData = Data("<lots of binary gunk>" * 10),
aDate = Date(time.mktime(time.gmtime())),
)
elif len(sys.argv) == 2:
pl = Plist.fromFile(sys.argv[1])
else:
print "Too many arguments: at most 1 plist file can be given."
sys.exit(1)
# unicode keys are possible, but a little awkward to use:
pl[u'\xc5benraa'] = "That was a unicode key."
f = StringIO()
pl.write(f)
xml = f.getvalue()
print xml
f.seek(0)
pl2 = Plist.fromFile(f)
assert pl == pl2
f = StringIO()
pl2.write(f)
assert xml == f.getvalue()
#print repr(pl2)
--- NEW FILE: videoreader.py ---
# Video file reader, using QuickTime
#
# This module was quickly ripped out of another software package, so there is a good
# chance that it does not work as-is and it needs some hacking.
#
# Jack Jansen, August 2000
#
import sys
from Carbon import Qt
from Carbon import QuickTime
from Carbon import Qd
from Carbon import Qdoffs
from Carbon import QDOffscreen
from Carbon import Res
import MediaDescr
import imgformat
import os
# import audio.format
import macfs
class VideoFormat:
def __init__(self, name, descr, width, height, format):
self.__name = name
self.__descr = descr
self.__width = width
self.__height = height
self.__format = format
def getname(self):
return self.__name
def getdescr(self):
return self.__descr
def getsize(self):
return self.__width, self.__height
def getformat(self):
return self.__format
class _Reader:
def __init__(self, path):
fsspec = macfs.FSSpec(path)
fd = Qt.OpenMovieFile(fsspec, 0)
self.movie, d1, d2 = Qt.NewMovieFromFile(fd, 0, 0)
self.movietimescale = self.movie.GetMovieTimeScale()
try:
self.audiotrack = self.movie.GetMovieIndTrackType(1,
QuickTime.AudioMediaCharacteristic, QuickTime.movieTrackCharacteristic)
self.audiomedia = self.audiotrack.GetTrackMedia()
except Qt.Error:
self.audiotrack = self.audiomedia = None
self.audiodescr = {}
else:
handle = Res.Handle('')
n = self.audiomedia.GetMediaSampleDescriptionCount()
self.audiomedia.GetMediaSampleDescription(1, handle)
self.audiodescr = MediaDescr.SoundDescription.decode(handle.data)
self.audiotimescale = self.audiomedia.GetMediaTimeScale()
del handle
try:
self.videotrack = self.movie.GetMovieIndTrackType(1,
QuickTime.VisualMediaCharacteristic, QuickTime.movieTrackCharacteristic)
self.videomedia = self.videotrack.GetTrackMedia()
except Qt.Error:
self.videotrack = self.videomedia = self.videotimescale = None
if self.videotrack:
self.videotimescale = self.videomedia.GetMediaTimeScale()
x0, y0, x1, y1 = self.movie.GetMovieBox()
self.videodescr = {'width':(x1-x0), 'height':(y1-y0)}
self._initgworld()
self.videocurtime = None
self.audiocurtime = None
def __del__(self):
self.audiomedia = None
self.audiotrack = None
self.videomedia = None
self.videotrack = None
self.movie = None
def _initgworld(self):
old_port, old_dev = Qdoffs.GetGWorld()
try:
movie_w = self.videodescr['width']
movie_h = self.videodescr['height']
movie_rect = (0, 0, movie_w, movie_h)
self.gworld = Qdoffs.NewGWorld(32, movie_rect, None, None, QDOffscreen.keepLocal)
self.pixmap = self.gworld.GetGWorldPixMap()
Qdoffs.LockPixels(self.pixmap)
Qdoffs.SetGWorld(self.gworld.as_GrafPtr(), None)
Qd.EraseRect(movie_rect)
self.movie.SetMovieGWorld(self.gworld.as_GrafPtr(), None)
self.movie.SetMovieBox(movie_rect)
self.movie.SetMovieActive(1)
self.movie.MoviesTask(0)
self.movie.SetMoviePlayHints(QuickTime.hintsHighQuality, QuickTime.hintsHighQuality)
# XXXX framerate
finally:
Qdoffs.SetGWorld(old_port, old_dev)
def _gettrackduration_ms(self, track):
tracktime = track.GetTrackDuration()
return self._movietime_to_ms(tracktime)
def _movietime_to_ms(self, time):
value, d1, d2 = Qt.ConvertTimeScale((time, self.movietimescale, None), 1000)
return value
def _videotime_to_ms(self, time):
value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), 1000)
return value
def _audiotime_to_ms(self, time):
value, d1, d2 = Qt.ConvertTimeScale((time, self.audiotimescale, None), 1000)
return value
def _videotime_to_movietime(self, time):
value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None),
self.movietimescale)
return value
def HasAudio(self):
return not self.audiotrack is None
def HasVideo(self):
return not self.videotrack is None
def GetAudioDuration(self):
if not self.audiotrack:
return 0
return self._gettrackduration_ms(self.audiotrack)
def GetVideoDuration(self):
if not self.videotrack:
return 0
return self._gettrackduration_ms(self.videotrack)
def GetAudioFormat(self):
bps = self.audiodescr['sampleSize']
nch = self.audiodescr['numChannels']
if nch == 1:
channels = ['mono']
elif nch == 2:
channels = ['left', 'right']
else:
channels = map(lambda x: str(x+1), range(nch))
if bps % 8:
# Funny bits-per sample. We pretend not to understand
blocksize = 0
fpb = 0
else:
# QuickTime is easy (for as far as we support it): samples are always a whole
# number of bytes, so frames are nchannels*samplesize, and there's one frame per block.
blocksize = (bps/8)*nch
fpb = 1
if self.audiodescr['dataFormat'] == 'raw ':
encoding = 'linear-excess'
elif self.audiodescr['dataFormat'] == 'twos':
encoding = 'linear-signed'
else:
encoding = 'quicktime-coding-%s'%self.audiodescr['dataFormat']
## return audio.format.AudioFormatLinear('quicktime_audio', 'QuickTime Audio Format',
## channels, encoding, blocksize=blocksize, fpb=fpb, bps=bps)
return channels, encoding, blocksize, fpb, bps
def GetAudioFrameRate(self):
return int(self.audiodescr['sampleRate'])
def GetVideoFormat(self):
width = self.videodescr['width']
height = self.videodescr['height']
return VideoFormat('dummy_format', 'Dummy Video Format', width, height, imgformat.macrgb)
def GetVideoFrameRate(self):
tv = self.videocurtime
if tv == None:
tv = 0
flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK
tv, dur = self.videomedia.GetMediaNextInterestingTime(flags, tv, 1.0)
dur = self._videotime_to_ms(dur)
return int((1000.0/dur)+0.5)
def ReadAudio(self, nframes, time=None):
if not time is None:
self.audiocurtime = time
flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK
if self.audiocurtime == None:
self.audiocurtime = 0
tv = self.audiomedia.GetMediaNextInterestingTimeOnly(flags, self.audiocurtime, 1.0)
if tv < 0 or (self.audiocurtime and tv < self.audiocurtime):
return self._audiotime_to_ms(self.audiocurtime), None
h = Res.Handle('')
desc_h = Res.Handle('')
size, actualtime, sampleduration, desc_index, actualcount, flags = \
self.audiomedia.GetMediaSample(h, 0, tv, desc_h, nframes)
self.audiocurtime = actualtime + actualcount*sampleduration
return self._audiotime_to_ms(actualtime), h.data
def ReadVideo(self, time=None):
if not time is None:
self.videocurtime = time
flags = QuickTime.nextTimeStep
if self.videocurtime == None:
flags = flags | QuickTime.nextTimeEdgeOK
self.videocurtime = 0
tv = self.videomedia.GetMediaNextInterestingTimeOnly(flags, self.videocurtime, 1.0)
if tv < 0 or (self.videocurtime and tv <= self.videocurtime):
return self._videotime_to_ms(self.videocurtime), None
self.videocurtime = tv
moviecurtime = self._videotime_to_movietime(self.videocurtime)
self.movie.SetMovieTimeValue(moviecurtime)
self.movie.MoviesTask(0)
return self._videotime_to_ms(self.videocurtime), self._getpixmapcontent()
def _getpixmapcontent(self):
"""Shuffle the offscreen PixMap data, because it may have funny stride values"""
rowbytes = Qdoffs.GetPixRowBytes(self.pixmap)
width = self.videodescr['width']
height = self.videodescr['height']
start = 0
rv = ''
for i in range(height):
nextline = Qdoffs.GetPixMapBytes(self.pixmap, start, width*4)
start = start + rowbytes
rv = rv + nextline
return rv
def reader(url):
try:
rdr = _Reader(url)
except IOError:
return None
return rdr
def _test():
import img
import MacOS
Qt.EnterMovies()
fss, ok = macfs.PromptGetFile('Video to convert')
if not ok: sys.exit(0)
path = fss.as_pathname()
rdr = reader(path)
if not rdr:
sys.exit(1)
dstfss, ok = macfs.StandardPutFile('Name for output folder')
if not ok: sys.exit(0)
dstdir = dstfss.as_pathname()
num = 0
os.mkdir(dstdir)
videofmt = rdr.GetVideoFormat()
imgfmt = videofmt.getformat()
imgw, imgh = videofmt.getsize()
timestamp, data = rdr.ReadVideo()
while data:
fname = 'frame%04.4d.jpg'%num
num = num+1
pname = os.path.join(dstdir, fname)
print 'Writing', fname, imgw, imgh, len(data)
wrt = img.writer(imgfmt, pname)
wrt.width = imgw
wrt.height = imgh
wrt.write(data)
timestamp, data = rdr.ReadVideo()
MacOS.SetCreatorAndType(pname, 'ogle', 'JPEG')
if num > 20:
print 'stopping at 20 frames so your disk does not fill up:-)'
break
print 'Total frames:', num
if __name__ == '__main__':
_test()
sys.exit(1)
- Previous message: [Python-checkins] python/dist/src/Mac/Lib/lib-scriptpackages/_builtinSuites __init__.py,1.1,NONE builtin_Suite.py,1.2,NONE
- Next message: [Python-checkins] python/dist/src/Lib/plat-mac/Carbon AE.py,NONE,1.1 AH.py,NONE,1.1 Alias.py,NONE,1.1 Aliases.py,NONE,1.1 App.py,NONE,1.1 Appearance.py,NONE,1.1 AppleEvents.py,NONE,1.1 AppleHelp.py,NONE,1.1 CF.py,NONE,1.1 CG.py,NONE,1.1 CarbonEvents.py,NONE,1.1 CarbonEvt.py,NONE,1.1 Cm.py,NONE,1.1 Components.py,NONE,1.1 ControlAccessor.py,NONE,1.1 Controls.py,NONE,1.1 CoreFoundation.py,NONE,1.1 CoreGraphics.py,NONE,1.1 Ctl.py,NONE,1.1 Dialogs.py,NONE,1.1 Dlg.py,NONE,1.1 Drag.py,NONE,1.1 Dragconst.py,NONE,1.1 Events.py,NONE,1.1 Evt.py,NONE,1.1 File.py,NONE,1.1 Files.py,NONE,1.1 Fm.py,NONE,1.1 Folder.py,NONE,1.1 Folders.py,NONE,1.1 Fonts.py,NONE,1.1 Help.py,NONE,1.1 IBCarbon.py,NONE,1.1 IBCarbonRuntime.py,NONE,1.1 Icn.py,NONE,1.1 Icons.py,NONE,1.1 List.py,NONE,1.1 Lists.py,NONE,1.1 MacHelp.py,NONE,1.1 MacTextEditor.py,NONE,1.1 MediaDescr.py,NONE,1.1 Menu.py,NONE,1.1 Menus.py,NONE,1.1 Mlte.py,NONE,1.1 QDOffscreen.py,NONE,1.1 Qd.py,NONE,1.1 Qdoffs.py,NONE,1.1 Qt.py,NONE,1.1 QuickDraw.py,NONE,1.1 QuickTime.py,NONE,1.1 Res.py,NONE,1.1 Resources.py,NONE,1.1 Scrap.py,NONE,1.1 Snd.py,NONE,1.1 Sndihooks.py,NONE,1.1 Sound.py,NONE,1.1 TE.py,NONE,1.1 TextEdit.py,NONE,1.1 WASTEconst.py,NONE,1.1 Win.py,NONE,1.1 Windows.py,NONE,1.1 __init__.py,NONE,1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]