1 | """
|
---|
2 | A number of function that enhance IDLE on MacOSX when it used as a normal
|
---|
3 | GUI application (as opposed to an X11 application).
|
---|
4 | """
|
---|
5 | import sys
|
---|
6 | import Tkinter
|
---|
7 | from os import path
|
---|
8 |
|
---|
9 |
|
---|
10 | _appbundle = None
|
---|
11 |
|
---|
12 | def runningAsOSXApp():
|
---|
13 | """
|
---|
14 | Returns True if Python is running from within an app on OSX.
|
---|
15 | If so, assume that Python was built with Aqua Tcl/Tk rather than
|
---|
16 | X11 Tcl/Tk.
|
---|
17 | """
|
---|
18 | global _appbundle
|
---|
19 | if _appbundle is None:
|
---|
20 | _appbundle = (sys.platform == 'darwin' and '.app' in sys.executable)
|
---|
21 | return _appbundle
|
---|
22 |
|
---|
23 | _carbonaquatk = None
|
---|
24 |
|
---|
25 | def isCarbonAquaTk(root):
|
---|
26 | """
|
---|
27 | Returns True if IDLE is using a Carbon Aqua Tk (instead of the
|
---|
28 | newer Cocoa Aqua Tk).
|
---|
29 | """
|
---|
30 | global _carbonaquatk
|
---|
31 | if _carbonaquatk is None:
|
---|
32 | _carbonaquatk = (runningAsOSXApp() and
|
---|
33 | 'aqua' in root.tk.call('tk', 'windowingsystem') and
|
---|
34 | 'AppKit' not in root.tk.call('winfo', 'server', '.'))
|
---|
35 | return _carbonaquatk
|
---|
36 |
|
---|
37 | def tkVersionWarning(root):
|
---|
38 | """
|
---|
39 | Returns a string warning message if the Tk version in use appears to
|
---|
40 | be one known to cause problems with IDLE.
|
---|
41 | 1. Apple Cocoa-based Tk 8.5.7 shipped with Mac OS X 10.6 is unusable.
|
---|
42 | 2. Apple Cocoa-based Tk 8.5.9 in OS X 10.7 and 10.8 is better but
|
---|
43 | can still crash unexpectedly.
|
---|
44 | """
|
---|
45 |
|
---|
46 | if (runningAsOSXApp() and
|
---|
47 | ('AppKit' in root.tk.call('winfo', 'server', '.')) ):
|
---|
48 | patchlevel = root.tk.call('info', 'patchlevel')
|
---|
49 | if patchlevel not in ('8.5.7', '8.5.9'):
|
---|
50 | return False
|
---|
51 | return (r"WARNING: The version of Tcl/Tk ({0}) in use may"
|
---|
52 | r" be unstable.\n"
|
---|
53 | r"Visit http://www.python.org/download/mac/tcltk/"
|
---|
54 | r" for current information.".format(patchlevel))
|
---|
55 | else:
|
---|
56 | return False
|
---|
57 |
|
---|
58 | def addOpenEventSupport(root, flist):
|
---|
59 | """
|
---|
60 | This ensures that the application will respond to open AppleEvents, which
|
---|
61 | makes is feasible to use IDLE as the default application for python files.
|
---|
62 | """
|
---|
63 | def doOpenFile(*args):
|
---|
64 | for fn in args:
|
---|
65 | flist.open(fn)
|
---|
66 |
|
---|
67 | # The command below is a hook in aquatk that is called whenever the app
|
---|
68 | # receives a file open event. The callback can have multiple arguments,
|
---|
69 | # one for every file that should be opened.
|
---|
70 | root.createcommand("::tk::mac::OpenDocument", doOpenFile)
|
---|
71 |
|
---|
72 | def hideTkConsole(root):
|
---|
73 | try:
|
---|
74 | root.tk.call('console', 'hide')
|
---|
75 | except Tkinter.TclError:
|
---|
76 | # Some versions of the Tk framework don't have a console object
|
---|
77 | pass
|
---|
78 |
|
---|
79 | def overrideRootMenu(root, flist):
|
---|
80 | """
|
---|
81 | Replace the Tk root menu by something that's more appropriate for
|
---|
82 | IDLE.
|
---|
83 | """
|
---|
84 | # The menu that is attached to the Tk root (".") is also used by AquaTk for
|
---|
85 | # all windows that don't specify a menu of their own. The default menubar
|
---|
86 | # contains a number of menus, none of which are appropriate for IDLE. The
|
---|
87 | # Most annoying of those is an 'About Tck/Tk...' menu in the application
|
---|
88 | # menu.
|
---|
89 | #
|
---|
90 | # This function replaces the default menubar by a mostly empty one, it
|
---|
91 | # should only contain the correct application menu and the window menu.
|
---|
92 | #
|
---|
93 | # Due to a (mis-)feature of TkAqua the user will also see an empty Help
|
---|
94 | # menu.
|
---|
95 | from Tkinter import Menu, Text, Text
|
---|
96 | from idlelib.EditorWindow import prepstr, get_accelerator
|
---|
97 | from idlelib import Bindings
|
---|
98 | from idlelib import WindowList
|
---|
99 | from idlelib.MultiCall import MultiCallCreator
|
---|
100 |
|
---|
101 | menubar = Menu(root)
|
---|
102 | root.configure(menu=menubar)
|
---|
103 | menudict = {}
|
---|
104 |
|
---|
105 | menudict['windows'] = menu = Menu(menubar, name='windows')
|
---|
106 | menubar.add_cascade(label='Window', menu=menu, underline=0)
|
---|
107 |
|
---|
108 | def postwindowsmenu(menu=menu):
|
---|
109 | end = menu.index('end')
|
---|
110 | if end is None:
|
---|
111 | end = -1
|
---|
112 |
|
---|
113 | if end > 0:
|
---|
114 | menu.delete(0, end)
|
---|
115 | WindowList.add_windows_to_menu(menu)
|
---|
116 | WindowList.register_callback(postwindowsmenu)
|
---|
117 |
|
---|
118 | def about_dialog(event=None):
|
---|
119 | from idlelib import aboutDialog
|
---|
120 | aboutDialog.AboutDialog(root, 'About IDLE')
|
---|
121 |
|
---|
122 | def config_dialog(event=None):
|
---|
123 | from idlelib import configDialog
|
---|
124 | root.instance_dict = flist.inversedict
|
---|
125 | configDialog.ConfigDialog(root, 'Settings')
|
---|
126 |
|
---|
127 | def help_dialog(event=None):
|
---|
128 | from idlelib import textView
|
---|
129 | fn = path.join(path.abspath(path.dirname(__file__)), 'help.txt')
|
---|
130 | textView.view_file(root, 'Help', fn)
|
---|
131 |
|
---|
132 | root.bind('<<about-idle>>', about_dialog)
|
---|
133 | root.bind('<<open-config-dialog>>', config_dialog)
|
---|
134 | root.createcommand('::tk::mac::ShowPreferences', config_dialog)
|
---|
135 | if flist:
|
---|
136 | root.bind('<<close-all-windows>>', flist.close_all_callback)
|
---|
137 |
|
---|
138 | # The binding above doesn't reliably work on all versions of Tk
|
---|
139 | # on MacOSX. Adding command definition below does seem to do the
|
---|
140 | # right thing for now.
|
---|
141 | root.createcommand('exit', flist.close_all_callback)
|
---|
142 |
|
---|
143 | if isCarbonAquaTk(root):
|
---|
144 | # for Carbon AquaTk, replace the default Tk apple menu
|
---|
145 | menudict['application'] = menu = Menu(menubar, name='apple')
|
---|
146 | menubar.add_cascade(label='IDLE', menu=menu)
|
---|
147 | Bindings.menudefs.insert(0,
|
---|
148 | ('application', [
|
---|
149 | ('About IDLE', '<<about-idle>>'),
|
---|
150 | None,
|
---|
151 | ]))
|
---|
152 | tkversion = root.tk.eval('info patchlevel')
|
---|
153 | if tuple(map(int, tkversion.split('.'))) < (8, 4, 14):
|
---|
154 | # for earlier AquaTk versions, supply a Preferences menu item
|
---|
155 | Bindings.menudefs[0][1].append(
|
---|
156 | ('_Preferences....', '<<open-config-dialog>>'),
|
---|
157 | )
|
---|
158 | else:
|
---|
159 | # assume Cocoa AquaTk
|
---|
160 | # replace default About dialog with About IDLE one
|
---|
161 | root.createcommand('tkAboutDialog', about_dialog)
|
---|
162 | # replace default "Help" item in Help menu
|
---|
163 | root.createcommand('::tk::mac::ShowHelp', help_dialog)
|
---|
164 | # remove redundant "IDLE Help" from menu
|
---|
165 | del Bindings.menudefs[-1][1][0]
|
---|
166 |
|
---|
167 | def setupApp(root, flist):
|
---|
168 | """
|
---|
169 | Perform setup for the OSX application bundle.
|
---|
170 | """
|
---|
171 | if not runningAsOSXApp(): return
|
---|
172 |
|
---|
173 | hideTkConsole(root)
|
---|
174 | overrideRootMenu(root, flist)
|
---|
175 | addOpenEventSupport(root, flist)
|
---|