blob: 4cfc77b8f9c663e2c6c5e7cabe1bee88488632b1 [file] [log] [blame]
Just van Rossum40f9b7b1999-01-30 22:39:17 +00001import FrameWork
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00002from Carbon import Win
3from Carbon import Qd
4from Carbon import Evt
Just van Rossum40f9b7b1999-01-30 22:39:17 +00005import MacOS
Jack Jansendc4d9252001-08-27 10:55:41 +00006from Carbon import Events
Just van Rossum40f9b7b1999-01-30 22:39:17 +00007import traceback
8from types import *
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00009from Carbon import Menu; MenuToolbox = Menu; del Menu
Jack Jansene9c03582002-04-03 21:52:10 +000010import macresource
Jack Jansene7ee17c2003-02-06 22:32:35 +000011from Carbon import File
Just van Rossum40f9b7b1999-01-30 22:39:17 +000012
Just van Rossum40144012002-02-04 12:52:44 +000013if hasattr(Win, "FrontNonFloatingWindow"):
Tim Peters182b5ac2004-07-18 06:16:08 +000014 MyFrontWindow = Win.FrontNonFloatingWindow
Just van Rossum40144012002-02-04 12:52:44 +000015else:
Tim Peters182b5ac2004-07-18 06:16:08 +000016 MyFrontWindow = Win.FrontWindow
Just van Rossum40144012002-02-04 12:52:44 +000017
18
Just van Rossumf376ef02001-11-18 14:12:43 +000019KILLUNKNOWNWINDOWS = 0 # Set to 0 for debugging.
Just van Rossum40f9b7b1999-01-30 22:39:17 +000020
21class Application(FrameWork.Application):
Tim Peters182b5ac2004-07-18 06:16:08 +000022
23 def __init__(self, signature='Pyth'):
24 # Open our resource file, if it is not open yet
25 macresource.need('CURS', 468, "Widgets.rsrc")
26 import W
27 W.setapplication(self, signature)
28 FrameWork.Application.__init__(self)
29 self._suspended = 0
30 self.quitting = 0
31 self.debugger_quitting = 1
32 self.DebuggerQuit = 'DebuggerQuitDummyException'
33 self._idlefuncs = []
34 # map certain F key codes to equivalent command-letter combos (JJS)
35 self.fkeymaps = {122:"z", 120:"x", 99:"c", 118:"v"}
36
37 def mainloop(self, mask=FrameWork.everyEvent, wait=None):
38 import W
39 self.quitting = 0
40 if hasattr(MacOS, 'EnableAppswitch'):
41 saveyield = MacOS.EnableAppswitch(-1)
42 try:
43 while not self.quitting:
44 try:
45 self.do1event(mask, wait)
46 except W.AlertError, detail:
47 if hasattr(MacOS, 'EnableAppswitch'):
48 MacOS.EnableAppswitch(-1)
49 W.Message(detail)
50 except self.DebuggerQuit:
51 if hasattr(MacOS, 'EnableAppswitch'):
52 MacOS.EnableAppswitch(-1)
53 except:
54 if hasattr(MacOS, 'EnableAppswitch'):
55 MacOS.EnableAppswitch(-1)
56 import PyEdit
57 PyEdit.tracebackwindow.traceback()
58 finally:
59 if hasattr(MacOS, 'EnableAppswitch'):
60 MacOS.EnableAppswitch(1)
61
62 def debugger_mainloop(self, mask=FrameWork.everyEvent, wait=None):
63 import W
64 self.debugger_quitting = 0
65 if hasattr(MacOS, 'EnableAppswitch'):
66 saveyield = MacOS.EnableAppswitch(-1)
67 try:
68 while not self.quitting and not self.debugger_quitting:
69 try:
70 self.do1event(mask, wait)
71 except W.AlertError, detail:
72 W.Message(detail)
73 except:
74 import PyEdit
75 PyEdit.tracebackwindow.traceback()
76 finally:
77 if hasattr(MacOS, 'EnableAppswitch'):
78 MacOS.EnableAppswitch(saveyield)
79
80 def breathe(self, wait=1):
81 import W
82 ok, event = Evt.WaitNextEvent(FrameWork.updateMask |
83 FrameWork.mDownMask | FrameWork.osMask |
84 FrameWork.activMask,
85 wait)
86 if ok:
87 (what, message, when, where, modifiers) = event
88 #print FrameWork.eventname[what]
89 if FrameWork.eventname[what] == 'mouseDown':
90 partcode, wid = Win.FindWindow(where)
91 if FrameWork.partname[partcode] <> 'inDesk':
92 return
93 else:
94 W.SetCursor('watch')
95 self.dispatch(event)
96
97 def refreshwindows(self, wait=1):
98 import W
99 while 1:
100 ok, event = Evt.WaitNextEvent(FrameWork.updateMask, wait)
101 if not ok:
102 break
103 self.dispatch(event)
104
105 def addidlefunc(self, func):
106 self._idlefuncs.append(func)
107
108 def removeidlefunc(self, func):
109 self._idlefuncs.remove(func)
110
111 def idle(self, event):
112 if not self._suspended:
113 if not self.do_frontWindowMethod("idle", event):
114 Qd.InitCursor()
115 if self._idlefuncs:
116 for func in self._idlefuncs:
117 try:
118 func()
119 except:
120 import sys
121 sys.stderr.write("exception in idle function %r; killed:\n" % (func,))
122 traceback.print_exc()
123 self._idlefuncs.remove(func)
124 break
125
126 def do_frontWindowMethod(self, attr, *args):
127 wid = MyFrontWindow()
128 if wid and self._windows.has_key(wid):
129 window = self._windows[wid]
130 if hasattr(window, attr):
131 handler = getattr(window, attr)
132 apply(handler, args)
133 return 1
134
135 def getfrontwindow(self):
136 wid = MyFrontWindow()
137 if wid and self._windows.has_key(wid):
138 return self._windows[wid]
139 return None
140
141 def appendwindow(self, wid, window):
142 self._windows[wid] = window
143 self.makeopenwindowsmenu()
144
145 def removewindow(self, wid):
146 del self._windows[wid]
147 self.makeopenwindowsmenu()
148
149 def makeopenwindowsmenu(self):
150 # dummy; could be the full version from PythonIDEMain.py
151 self._openwindows = {}
152 self._openwindowscheckmark = 0
153 if not hasattr(self, "_menustocheck"):
154 self._menustocheck = []
155
156 def do_key(self, event):
157 (what, message, when, where, modifiers) = event
158 ch = chr(message & FrameWork.charCodeMask)
159 rest = message & ~FrameWork.charCodeMask
160 keycode = (message & FrameWork.keyCodeMask) >> 8
161 if keycode in self.fkeymaps.keys(): # JJS
162 ch = self.fkeymaps[keycode]
163 modifiers = modifiers | FrameWork.cmdKey
164 wid = MyFrontWindow()
165 if modifiers & FrameWork.cmdKey and not modifiers & FrameWork.shiftKey:
166 if wid and self._windows.has_key(wid):
167 self.checkmenus(self._windows[wid])
168 else:
169 self.checkmenus(None)
170 event = (what, ord(ch) | rest, when, where, modifiers)
171 result = MenuToolbox.MenuKey(ord(ch))
172 id = (result>>16) & 0xffff # Hi word
173 item = result & 0xffff # Lo word
174 if id:
175 self.do_rawmenu(id, item, None, event)
176 return # here! we had a menukey!
177 #else:
178 # print "XXX Command-%r" % ch
179 # See whether the front window wants it
180 if wid and self._windows.has_key(wid):
181 window = self._windows[wid]
182 try:
183 do_char = window.do_char
184 except AttributeError:
185 do_char = self.do_char
186 do_char(ch, event)
187 # else it wasn't for us, sigh...
188
189 def do_inMenuBar(self, partcode, window, event):
190 Qd.InitCursor()
191 (what, message, when, where, modifiers) = event
192 self.checkopenwindowsmenu()
193 wid = MyFrontWindow()
194 if wid and self._windows.has_key(wid):
195 self.checkmenus(self._windows[wid])
196 else:
197 self.checkmenus(None)
198 result = MenuToolbox.MenuSelect(where)
199 id = (result>>16) & 0xffff # Hi word
200 if id >= 0x8000:
201 id = -0x10000 + id
202 item = result & 0xffff # Lo word
203 self.do_rawmenu(id, item, window, event)
204
205 def do_updateEvt(self, event):
206 (what, message, when, where, modifiers) = event
207 wid = Win.WhichWindow(message)
208 if wid and self._windows.has_key(wid):
209 window = self._windows[wid]
210 window.do_rawupdate(wid, event)
211 else:
212 if KILLUNKNOWNWINDOWS and wid:
213 wid.HideWindow()
214 import sys
215 sys.stderr.write("XXX killed unknown (crashed?) Python window.\n")
216 else:
217 if hasattr(MacOS, 'HandleEvent'):
218 MacOS.HandleEvent(event)
219 else:
220 print 'Unexpected updateEvent:', event
221
222 def suspendresume(self, onoff):
223 pass
224
225 def do_suspendresume(self, event):
226 self._suspended = not event[1] & 1
227 FrameWork.Application.do_suspendresume(self, event)
228
229 def checkopenwindowsmenu(self):
230 if self._openwindowscheckmark:
231 self.openwindowsmenu.menu.CheckMenuItem(self._openwindowscheckmark, 0)
232 window = MyFrontWindow()
233 if window:
234 for item, wid in self._openwindows.items():
235 if wid == window:
236 #self.pythonwindowsmenuitem.check(1)
237 self.openwindowsmenu.menu.CheckMenuItem(item, 1)
238 self._openwindowscheckmark = item
239 break
240 else:
241 self._openwindowscheckmark = 0
242 #if self._openwindows:
243 # self.pythonwindowsmenuitem.enable(1)
244 #else:
245 # self.pythonwindowsmenuitem.enable(0)
246
247 def checkmenus(self, window):
248 for item in self._menustocheck:
249 callback = item.menu.items[item.item-1][2]
250 if type(callback) <> StringType:
251 item.enable(1)
252 elif hasattr(window, "domenu_" + callback):
253 if hasattr(window, "can_" + callback):
254 canhandler = getattr(window, "can_" + callback)
255 if canhandler(item):
256 item.enable(1)
257 else:
258 item.enable(0)
259 else:
260 item.enable(1)
261 else:
262 item.enable(0)
263
264 def enablemenubar(self, onoff):
265 for m in self.menubar.menus.values():
266 if onoff:
267 m.menu.EnableMenuItem(0)
268 elif m.menu.GetMenuItemText(3) <> 'Cut': # ew...
269 m.menu.DisableMenuItem(0)
270 MenuToolbox.DrawMenuBar()
271
272 def makemenubar(self):
273 self.menubar = MenuBar(self)
274 FrameWork.AppleMenu(self.menubar, self.getabouttext(), self.do_about)
275 self.makeusermenus()
276
277 def scriptswalk(self, top, menu, done=None):
278 if menu.id > 200:
279 import W
280 W.Message("Scripts folder not completely traversed: running out of menus")
281 return False
282 if done is None:
283 done = {}
284 if done.has_key(top):
285 return True
286 done[top] = 1
287 import os, string
288 try:
289 names = os.listdir(top)
290 except os.error:
291 FrameWork.MenuItem(menu, '(Scripts Folder not found)', None, None)
292 return True
293 savedir = os.getcwd()
294 os.chdir(top)
295 for name in names:
296 if name == "CVS":
297 continue
298 try:
299 fsr, isdir, isalias = File.FSResolveAliasFile(name, 1)
300 except:
301 # maybe a broken alias
302 continue
303 path = fsr.as_pathname()
304 if done.has_key(path):
305 continue
306 name = string.strip(name)
307 if os.name == "posix":
308 name = unicode(name, "utf-8")
309 if name[-3:] == '---':
310 menu.addseparator()
311 elif isdir:
312 submenu = FrameWork.SubMenu(menu, name)
313 if not self.scriptswalk(path, submenu, done):
314 return False
315 else:
316 creator, type = MacOS.GetCreatorAndType(path)
317 if type == 'TEXT':
318 if name[-3:] == '.py':
319 name = name[:-3]
320 item = FrameWork.MenuItem(menu, name, None, self.domenu_script)
321 self._scripts[(menu.id, item.item)] = path
322 done[path] = 1
323 os.chdir(savedir)
324 return True
325
326 def domenu_script(self, id, item, window, event):
327 (what, message, when, where, modifiers) = event
328 path = self._scripts[(id, item)]
329 import os
330 if not os.path.exists(path):
331 self.makescriptsmenu()
332 import W
333 raise W.AlertError, "File not found."
334 if ord(Evt.GetKeys()[7]) & 4:
335 self.openscript(path)
336 else:
337 import W, MacOS, sys
338 W.SetCursor("watch")
339 sys.argv = [path]
340 #cwd = os.getcwd()
341 #os.chdir(os.path.dirname(path) + ':')
342 try:
343 # xxx if there is a script window for this file,
344 # exec in that window's namespace.
345 # xxx what to do when it's not saved???
346 # promt to save?
347 if hasattr(MacOS, 'EnableAppswitch'):
348 MacOS.EnableAppswitch(0)
349 execfile(path, {'__name__': '__main__', '__file__': path})
350 except W.AlertError, detail:
351 if hasattr(MacOS, 'EnableAppswitch'):
352 MacOS.EnableAppswitch(-1)
353 raise W.AlertError, detail
354 except KeyboardInterrupt:
355 if hasattr(MacOS, 'EnableAppswitch'):
356 MacOS.EnableAppswitch(-1)
357 except:
358 if hasattr(MacOS, 'EnableAppswitch'):
359 MacOS.EnableAppswitch(-1)
360 import PyEdit
361 PyEdit.tracebackwindow.traceback(1)
362 else:
363 if hasattr(MacOS, 'EnableAppswitch'):
364 MacOS.EnableAppswitch(-1)
365 #os.chdir(cwd)
366
367 def openscript(self, filename, lineno=None, charoffset=0, modname=""):
368 import os, PyEdit, W
369 editor = self.getscript(filename)
370 if editor:
371 editor.select()
372 elif os.path.exists(filename):
373 editor = PyEdit.Editor(filename)
374 elif filename[-3:] == '.py' or filename[-4:] == '.pyc':
375 import imp
376 if not modname:
377 if filename[-1] == 'c':
378 modname = os.path.basename(filename)[:-4]
379 else:
380 modname = os.path.basename(filename)[:-3]
381 try:
382 # XXX This does not work correctly with packages!
383 # XXX The docs say we should do it manually, pack, then sub, then sub2 etc.
384 # XXX It says we should use imp.load_module(), but that *reloads* a package,
385 # XXX and that's the last thing we want here.
386 f, filename, (suff, mode, dummy) = imp.find_module(modname)
387 except ImportError:
388 raise W.AlertError, "Can't find file for \"%s\"" % modname
389 else:
390 if not f:
391 raise W.AlertError, "Can't find file for \"%s\"" % modname
392 f.close()
393 if suff == '.py':
394 self.openscript(filename, lineno, charoffset)
395 return
396 else:
397 raise W.AlertError, "Can't find file for \"%s\"" % modname
398 else:
399 raise W.AlertError, "Can't find file \"%s\"" % filename
400 if lineno is not None:
401 editor.selectline(lineno, charoffset)
402 return editor
403
404 def getscript(self, filename):
405 if filename[:1] == '<' and filename[-1:] == '>':
406 filename = filename[1:-1]
407 import string
408 lowpath = string.lower(filename)
409 for wid, window in self._windows.items():
410 if hasattr(window, "path") and type(window.path) == StringType and \
411 lowpath == string.lower(window.path):
412 return window
413 elif hasattr(window, "path") and filename == wid.GetWTitle():
414 return window
415
416 def getprefs(self):
417 import MacPrefs
418 return MacPrefs.GetPrefs(self.preffilepath)
419
420 def do_editorprefs(self, *args):
421 import PyEdit
422 PyEdit.EditorDefaultSettings()
423
424 def do_setwindowfont(self, *args):
425 import FontSettings, W
426 prefs = self.getprefs()
427 settings = FontSettings.FontDialog(prefs.defaultfont)
428 if settings:
429 prefs.defaultfont, tabsettings = settings
430 raise W.AlertError, "Note that changes will only affect new windows!"
Just van Rossum2a759091999-09-26 12:18:19 +0000431
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000432
433
434class MenuBar(FrameWork.MenuBar):
Tim Peters182b5ac2004-07-18 06:16:08 +0000435
436 possibleIDs = range(10, 256)
437
438 def getnextid(self):
439 id = self.possibleIDs[0]
440 del self.possibleIDs[0]
441 return id
442
443 def __init__(self, parent = None):
444 self.bar = MenuToolbox.GetMenuBar()
445 MenuToolbox.ClearMenuBar()
446 self.menus = {}
447 self.parent = parent
448
449 def dispatch(self, id, item, window, event):
450 if self.menus.has_key(id):
451 self.menus[id].dispatch(id, item, window, event)
452
453 def delmenu(self, id):
454 MenuToolbox.DeleteMenu(id)
455 if id in self.possibleIDs:
456 print "XXX duplicate menu ID!", id
457 self.possibleIDs.append(id)
458
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000459
460class Menu(FrameWork.Menu):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000461
Tim Peters182b5ac2004-07-18 06:16:08 +0000462 def dispatch(self, id, item, window, event):
463 title, shortcut, callback, kind = self.items[item-1]
464 if type(callback) == StringType:
465 callback = self._getmenuhandler(callback)
466 if callback:
467 import W
468 W.CallbackCall(callback, 0, id, item, window, event)
469
470 def _getmenuhandler(self, callback):
471 menuhandler = None
472 wid = MyFrontWindow()
473 if wid and self.bar.parent._windows.has_key(wid):
474 window = self.bar.parent._windows[wid]
475 if hasattr(window, "domenu_" + callback):
476 menuhandler = getattr(window, "domenu_" + callback)
477 elif hasattr(self.bar.parent, "domenu_" + callback):
478 menuhandler = getattr(self.bar.parent, "domenu_" + callback)
479 elif hasattr(self.bar.parent, "domenu_" + callback):
480 menuhandler = getattr(self.bar.parent, "domenu_" + callback)
481 return menuhandler