cpython/Mac/Tools/IDE/Wapplication.py
Jack Jansen 8d562e6b4f Very large scripts folders could crash the IDE, because it runs out
of Menu IDs (of which there are only 255 in Carbon). Fixed by stopping
examining the scripts folder when we allocate menu ID 200.

Fixes #959291. Need to backport.
2004-06-03 13:31:51 +00:00

482 lines
14 KiB
Python

import FrameWork
from Carbon import Win
from Carbon import Qd
from Carbon import Evt
import MacOS
from Carbon import Events
import traceback
from types import *
from Carbon import Menu; MenuToolbox = Menu; del Menu
import macresource
from Carbon import File
if hasattr(Win, "FrontNonFloatingWindow"):
MyFrontWindow = Win.FrontNonFloatingWindow
else:
MyFrontWindow = Win.FrontWindow
KILLUNKNOWNWINDOWS = 0 # Set to 0 for debugging.
class Application(FrameWork.Application):
def __init__(self, signature='Pyth'):
# Open our resource file, if it is not open yet
macresource.need('CURS', 468, "Widgets.rsrc")
import W
W.setapplication(self, signature)
FrameWork.Application.__init__(self)
self._suspended = 0
self.quitting = 0
self.debugger_quitting = 1
self.DebuggerQuit = 'DebuggerQuitDummyException'
self._idlefuncs = []
# map certain F key codes to equivalent command-letter combos (JJS)
self.fkeymaps = {122:"z", 120:"x", 99:"c", 118:"v"}
def mainloop(self, mask=FrameWork.everyEvent, wait=None):
import W
self.quitting = 0
if hasattr(MacOS, 'EnableAppswitch'):
saveyield = MacOS.EnableAppswitch(-1)
try:
while not self.quitting:
try:
self.do1event(mask, wait)
except W.AlertError, detail:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(-1)
W.Message(detail)
except self.DebuggerQuit:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(-1)
except:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(-1)
import PyEdit
PyEdit.tracebackwindow.traceback()
finally:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(1)
def debugger_mainloop(self, mask=FrameWork.everyEvent, wait=None):
import W
self.debugger_quitting = 0
if hasattr(MacOS, 'EnableAppswitch'):
saveyield = MacOS.EnableAppswitch(-1)
try:
while not self.quitting and not self.debugger_quitting:
try:
self.do1event(mask, wait)
except W.AlertError, detail:
W.Message(detail)
except:
import PyEdit
PyEdit.tracebackwindow.traceback()
finally:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(saveyield)
def breathe(self, wait=1):
import W
ok, event = Evt.WaitNextEvent(FrameWork.updateMask |
FrameWork.mDownMask | FrameWork.osMask |
FrameWork.activMask,
wait)
if ok:
(what, message, when, where, modifiers) = event
#print FrameWork.eventname[what]
if FrameWork.eventname[what] == 'mouseDown':
partcode, wid = Win.FindWindow(where)
if FrameWork.partname[partcode] <> 'inDesk':
return
else:
W.SetCursor('watch')
self.dispatch(event)
def refreshwindows(self, wait=1):
import W
while 1:
ok, event = Evt.WaitNextEvent(FrameWork.updateMask, wait)
if not ok:
break
self.dispatch(event)
def addidlefunc(self, func):
self._idlefuncs.append(func)
def removeidlefunc(self, func):
self._idlefuncs.remove(func)
def idle(self, event):
if not self._suspended:
if not self.do_frontWindowMethod("idle", event):
Qd.InitCursor()
if self._idlefuncs:
for func in self._idlefuncs:
try:
func()
except:
import sys
sys.stderr.write("exception in idle function %r; killed:\n" % (func,))
traceback.print_exc()
self._idlefuncs.remove(func)
break
def do_frontWindowMethod(self, attr, *args):
wid = MyFrontWindow()
if wid and self._windows.has_key(wid):
window = self._windows[wid]
if hasattr(window, attr):
handler = getattr(window, attr)
apply(handler, args)
return 1
def getfrontwindow(self):
wid = MyFrontWindow()
if wid and self._windows.has_key(wid):
return self._windows[wid]
return None
def appendwindow(self, wid, window):
self._windows[wid] = window
self.makeopenwindowsmenu()
def removewindow(self, wid):
del self._windows[wid]
self.makeopenwindowsmenu()
def makeopenwindowsmenu(self):
# dummy; could be the full version from PythonIDEMain.py
self._openwindows = {}
self._openwindowscheckmark = 0
if not hasattr(self, "_menustocheck"):
self._menustocheck = []
def do_key(self, event):
(what, message, when, where, modifiers) = event
ch = chr(message & FrameWork.charCodeMask)
rest = message & ~FrameWork.charCodeMask
keycode = (message & FrameWork.keyCodeMask) >> 8
if keycode in self.fkeymaps.keys(): # JJS
ch = self.fkeymaps[keycode]
modifiers = modifiers | FrameWork.cmdKey
wid = MyFrontWindow()
if modifiers & FrameWork.cmdKey and not modifiers & FrameWork.shiftKey:
if wid and self._windows.has_key(wid):
self.checkmenus(self._windows[wid])
else:
self.checkmenus(None)
event = (what, ord(ch) | rest, when, where, modifiers)
result = MenuToolbox.MenuKey(ord(ch))
id = (result>>16) & 0xffff # Hi word
item = result & 0xffff # Lo word
if id:
self.do_rawmenu(id, item, None, event)
return # here! we had a menukey!
#else:
# print "XXX Command-%r" % ch
# See whether the front window wants it
if wid and self._windows.has_key(wid):
window = self._windows[wid]
try:
do_char = window.do_char
except AttributeError:
do_char = self.do_char
do_char(ch, event)
# else it wasn't for us, sigh...
def do_inMenuBar(self, partcode, window, event):
Qd.InitCursor()
(what, message, when, where, modifiers) = event
self.checkopenwindowsmenu()
wid = MyFrontWindow()
if wid and self._windows.has_key(wid):
self.checkmenus(self._windows[wid])
else:
self.checkmenus(None)
result = MenuToolbox.MenuSelect(where)
id = (result>>16) & 0xffff # Hi word
if id >= 0x8000:
id = -0x10000 + id
item = result & 0xffff # Lo word
self.do_rawmenu(id, item, window, event)
def do_updateEvt(self, event):
(what, message, when, where, modifiers) = event
wid = Win.WhichWindow(message)
if wid and self._windows.has_key(wid):
window = self._windows[wid]
window.do_rawupdate(wid, event)
else:
if KILLUNKNOWNWINDOWS and wid:
wid.HideWindow()
import sys
sys.stderr.write("XXX killed unknown (crashed?) Python window.\n")
else:
if hasattr(MacOS, 'HandleEvent'):
MacOS.HandleEvent(event)
else:
print 'Unexpected updateEvent:', event
def suspendresume(self, onoff):
pass
def do_suspendresume(self, event):
self._suspended = not event[1] & 1
FrameWork.Application.do_suspendresume(self, event)
def checkopenwindowsmenu(self):
if self._openwindowscheckmark:
self.openwindowsmenu.menu.CheckMenuItem(self._openwindowscheckmark, 0)
window = MyFrontWindow()
if window:
for item, wid in self._openwindows.items():
if wid == window:
#self.pythonwindowsmenuitem.check(1)
self.openwindowsmenu.menu.CheckMenuItem(item, 1)
self._openwindowscheckmark = item
break
else:
self._openwindowscheckmark = 0
#if self._openwindows:
# self.pythonwindowsmenuitem.enable(1)
#else:
# self.pythonwindowsmenuitem.enable(0)
def checkmenus(self, window):
for item in self._menustocheck:
callback = item.menu.items[item.item-1][2]
if type(callback) <> StringType:
item.enable(1)
elif hasattr(window, "domenu_" + callback):
if hasattr(window, "can_" + callback):
canhandler = getattr(window, "can_" + callback)
if canhandler(item):
item.enable(1)
else:
item.enable(0)
else:
item.enable(1)
else:
item.enable(0)
def enablemenubar(self, onoff):
for m in self.menubar.menus.values():
if onoff:
m.menu.EnableMenuItem(0)
elif m.menu.GetMenuItemText(3) <> 'Cut': # ew...
m.menu.DisableMenuItem(0)
MenuToolbox.DrawMenuBar()
def makemenubar(self):
self.menubar = MenuBar(self)
FrameWork.AppleMenu(self.menubar, self.getabouttext(), self.do_about)
self.makeusermenus()
def scriptswalk(self, top, menu, done=None):
if menu.id > 200:
import W
W.Message("Scripts folder not completely traversed: running out of menus")
return False
if done is None:
done = {}
if done.has_key(top):
return True
done[top] = 1
import os, string
try:
names = os.listdir(top)
except os.error:
FrameWork.MenuItem(menu, '(Scripts Folder not found)', None, None)
return True
savedir = os.getcwd()
os.chdir(top)
for name in names:
if name == "CVS":
continue
try:
fsr, isdir, isalias = File.FSResolveAliasFile(name, 1)
except:
# maybe a broken alias
continue
path = fsr.as_pathname()
if done.has_key(path):
continue
name = string.strip(name)
if os.name == "posix":
name = unicode(name, "utf-8")
if name[-3:] == '---':
menu.addseparator()
elif isdir:
submenu = FrameWork.SubMenu(menu, name)
if not self.scriptswalk(path, submenu, done):
return False
else:
creator, type = MacOS.GetCreatorAndType(path)
if type == 'TEXT':
if name[-3:] == '.py':
name = name[:-3]
item = FrameWork.MenuItem(menu, name, None, self.domenu_script)
self._scripts[(menu.id, item.item)] = path
done[path] = 1
os.chdir(savedir)
return True
def domenu_script(self, id, item, window, event):
(what, message, when, where, modifiers) = event
path = self._scripts[(id, item)]
import os
if not os.path.exists(path):
self.makescriptsmenu()
import W
raise W.AlertError, "File not found."
if ord(Evt.GetKeys()[7]) & 4:
self.openscript(path)
else:
import W, MacOS, sys
W.SetCursor("watch")
sys.argv = [path]
#cwd = os.getcwd()
#os.chdir(os.path.dirname(path) + ':')
try:
# xxx if there is a script window for this file,
# exec in that window's namespace.
# xxx what to do when it's not saved???
# promt to save?
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(0)
execfile(path, {'__name__': '__main__', '__file__': path})
except W.AlertError, detail:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(-1)
raise W.AlertError, detail
except KeyboardInterrupt:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(-1)
except:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(-1)
import PyEdit
PyEdit.tracebackwindow.traceback(1)
else:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(-1)
#os.chdir(cwd)
def openscript(self, filename, lineno=None, charoffset=0, modname=""):
import os, PyEdit, W
editor = self.getscript(filename)
if editor:
editor.select()
elif os.path.exists(filename):
editor = PyEdit.Editor(filename)
elif filename[-3:] == '.py' or filename[-4:] == '.pyc':
import imp
if not modname:
if filename[-1] == 'c':
modname = os.path.basename(filename)[:-4]
else:
modname = os.path.basename(filename)[:-3]
try:
# XXX This does not work correctly with packages!
# XXX The docs say we should do it manually, pack, then sub, then sub2 etc.
# XXX It says we should use imp.load_module(), but that *reloads* a package,
# XXX and that's the last thing we want here.
f, filename, (suff, mode, dummy) = imp.find_module(modname)
except ImportError:
raise W.AlertError, "Can't find file for \"%s\"" % modname
else:
if not f:
raise W.AlertError, "Can't find file for \"%s\"" % modname
f.close()
if suff == '.py':
self.openscript(filename, lineno, charoffset)
return
else:
raise W.AlertError, "Can't find file for \"%s\"" % modname
else:
raise W.AlertError, "Can't find file \"%s\"" % filename
if lineno is not None:
editor.selectline(lineno, charoffset)
return editor
def getscript(self, filename):
if filename[:1] == '<' and filename[-1:] == '>':
filename = filename[1:-1]
import string
lowpath = string.lower(filename)
for wid, window in self._windows.items():
if hasattr(window, "path") and type(window.path) == StringType and \
lowpath == string.lower(window.path):
return window
elif hasattr(window, "path") and filename == wid.GetWTitle():
return window
def getprefs(self):
import MacPrefs
return MacPrefs.GetPrefs(self.preffilepath)
def do_editorprefs(self, *args):
import PyEdit
PyEdit.EditorDefaultSettings()
def do_setwindowfont(self, *args):
import FontSettings, W
prefs = self.getprefs()
settings = FontSettings.FontDialog(prefs.defaultfont)
if settings:
prefs.defaultfont, tabsettings = settings
raise W.AlertError, "Note that changes will only affect new windows!"
class MenuBar(FrameWork.MenuBar):
possibleIDs = range(10, 256)
def getnextid(self):
id = self.possibleIDs[0]
del self.possibleIDs[0]
return id
def __init__(self, parent = None):
self.bar = MenuToolbox.GetMenuBar()
MenuToolbox.ClearMenuBar()
self.menus = {}
self.parent = parent
def dispatch(self, id, item, window, event):
if self.menus.has_key(id):
self.menus[id].dispatch(id, item, window, event)
def delmenu(self, id):
MenuToolbox.DeleteMenu(id)
if id in self.possibleIDs:
print "XXX duplicate menu ID!", id
self.possibleIDs.append(id)
class Menu(FrameWork.Menu):
def dispatch(self, id, item, window, event):
title, shortcut, callback, kind = self.items[item-1]
if type(callback) == StringType:
callback = self._getmenuhandler(callback)
if callback:
import W
W.CallbackCall(callback, 0, id, item, window, event)
def _getmenuhandler(self, callback):
menuhandler = None
wid = MyFrontWindow()
if wid and self.bar.parent._windows.has_key(wid):
window = self.bar.parent._windows[wid]
if hasattr(window, "domenu_" + callback):
menuhandler = getattr(window, "domenu_" + callback)
elif hasattr(self.bar.parent, "domenu_" + callback):
menuhandler = getattr(self.bar.parent, "domenu_" + callback)
elif hasattr(self.bar.parent, "domenu_" + callback):
menuhandler = getattr(self.bar.parent, "domenu_" + callback)
return menuhandler