blob: 10a06bb0d5e39271067a240a9bd07177b5fb6d96 [file] [log] [blame]
Tim Peters231c3c82006-06-11 19:43:49 +00001"""
Ned Deily57847df2014-03-27 20:47:04 -07002A number of functions that enhance IDLE on Mac OSX.
Tim Peters231c3c82006-06-11 19:43:49 +00003"""
4import sys
Georg Brandl6634bf22008-05-20 07:13:37 +00005import Tkinter
Ned Deily4a705502011-01-18 04:33:22 +00006from os import path
Tim Peters231c3c82006-06-11 19:43:49 +00007
Ronald Oussoren92919a62009-12-24 13:30:58 +00008
Ned Deily57847df2014-03-27 20:47:04 -07009import warnings
Ronald Oussoren92919a62009-12-24 13:30:58 +000010
Tim Peters231c3c82006-06-11 19:43:49 +000011def runningAsOSXApp():
Ned Deily57847df2014-03-27 20:47:04 -070012 warnings.warn("runningAsOSXApp() is deprecated, use isAquaTk()",
13 DeprecationWarning, stacklevel=2)
14 return isAquaTk()
Ned Deily4a705502011-01-18 04:33:22 +000015
16def isCarbonAquaTk(root):
Ned Deily57847df2014-03-27 20:47:04 -070017 warnings.warn("isCarbonAquaTk(root) is deprecated, use isCarbonTk()",
18 DeprecationWarning, stacklevel=2)
19 return isCarbonTk()
20
21_tk_type = None
22
23def _initializeTkVariantTests(root):
24 """
25 Initializes OS X Tk variant values for
26 isAquaTk(), isCarbonTk(), isCocoaTk(), and isXQuartz().
27 """
28 global _tk_type
29 if sys.platform == 'darwin':
30 ws = root.tk.call('tk', 'windowingsystem')
31 if 'x11' in ws:
32 _tk_type = "xquartz"
33 elif 'aqua' not in ws:
34 _tk_type = "other"
35 elif 'AppKit' in root.tk.call('winfo', 'server', '.'):
36 _tk_type = "cocoa"
37 else:
38 _tk_type = "carbon"
39 else:
40 _tk_type = "other"
41
42def isAquaTk():
43 """
44 Returns True if IDLE is using a native OS X Tk (Cocoa or Carbon).
45 """
46 assert _tk_type is not None
47 return _tk_type == "cocoa" or _tk_type == "carbon"
48
49def isCarbonTk():
Ned Deily4a705502011-01-18 04:33:22 +000050 """
51 Returns True if IDLE is using a Carbon Aqua Tk (instead of the
52 newer Cocoa Aqua Tk).
53 """
Ned Deily57847df2014-03-27 20:47:04 -070054 assert _tk_type is not None
55 return _tk_type == "carbon"
56
57def isCocoaTk():
58 """
59 Returns True if IDLE is using a Cocoa Aqua Tk.
60 """
61 assert _tk_type is not None
62 return _tk_type == "cocoa"
63
64def isXQuartz():
65 """
66 Returns True if IDLE is using an OS X X11 Tk.
67 """
68 assert _tk_type is not None
69 return _tk_type == "xquartz"
Ned Deily4a705502011-01-18 04:33:22 +000070
Ned Deily2a6f4b32011-01-30 00:18:47 +000071def tkVersionWarning(root):
72 """
73 Returns a string warning message if the Tk version in use appears to
Ned Deily38df5142012-07-30 03:28:22 -070074 be one known to cause problems with IDLE.
75 1. Apple Cocoa-based Tk 8.5.7 shipped with Mac OS X 10.6 is unusable.
76 2. Apple Cocoa-based Tk 8.5.9 in OS X 10.7 and 10.8 is better but
77 can still crash unexpectedly.
Ned Deily2a6f4b32011-01-30 00:18:47 +000078 """
79
Ned Deily57847df2014-03-27 20:47:04 -070080 if isCocoaTk():
Ned Deily38df5142012-07-30 03:28:22 -070081 patchlevel = root.tk.call('info', 'patchlevel')
82 if patchlevel not in ('8.5.7', '8.5.9'):
83 return False
84 return (r"WARNING: The version of Tcl/Tk ({0}) in use may"
Ned Deily2a6f4b32011-01-30 00:18:47 +000085 r" be unstable.\n"
86 r"Visit http://www.python.org/download/mac/tcltk/"
Ned Deily38df5142012-07-30 03:28:22 -070087 r" for current information.".format(patchlevel))
Ned Deily2a6f4b32011-01-30 00:18:47 +000088 else:
89 return False
90
Tim Peters231c3c82006-06-11 19:43:49 +000091def addOpenEventSupport(root, flist):
92 """
Ezio Melottic2077b02011-03-16 12:34:31 +020093 This ensures that the application will respond to open AppleEvents, which
94 makes is feasible to use IDLE as the default application for python files.
Tim Peters231c3c82006-06-11 19:43:49 +000095 """
96 def doOpenFile(*args):
97 for fn in args:
98 flist.open(fn)
99
100 # The command below is a hook in aquatk that is called whenever the app
101 # receives a file open event. The callback can have multiple arguments,
102 # one for every file that should be opened.
103 root.createcommand("::tk::mac::OpenDocument", doOpenFile)
104
105def hideTkConsole(root):
Ronald Oussoren9b0bcc12007-07-09 06:02:21 +0000106 try:
107 root.tk.call('console', 'hide')
Georg Brandl6634bf22008-05-20 07:13:37 +0000108 except Tkinter.TclError:
Ronald Oussoren9b0bcc12007-07-09 06:02:21 +0000109 # Some versions of the Tk framework don't have a console object
110 pass
Tim Peters231c3c82006-06-11 19:43:49 +0000111
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000112def overrideRootMenu(root, flist):
113 """
Ned Deily57847df2014-03-27 20:47:04 -0700114 Replace the Tk root menu by something that is more appropriate for
115 IDLE with an Aqua Tk.
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000116 """
Tim Peters0bbfd832006-07-24 21:02:15 +0000117 # The menu that is attached to the Tk root (".") is also used by AquaTk for
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000118 # all windows that don't specify a menu of their own. The default menubar
119 # contains a number of menus, none of which are appropriate for IDLE. The
120 # Most annoying of those is an 'About Tck/Tk...' menu in the application
121 # menu.
122 #
123 # This function replaces the default menubar by a mostly empty one, it
124 # should only contain the correct application menu and the window menu.
125 #
126 # Due to a (mis-)feature of TkAqua the user will also see an empty Help
127 # menu.
Georg Brandl6634bf22008-05-20 07:13:37 +0000128 from Tkinter import Menu, Text, Text
Florent Xiclunad630c042010-04-02 07:24:52 +0000129 from idlelib.EditorWindow import prepstr, get_accelerator
130 from idlelib import Bindings
131 from idlelib import WindowList
132 from idlelib.MultiCall import MultiCallCreator
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000133
Ned Deily57847df2014-03-27 20:47:04 -0700134 closeItem = Bindings.menudefs[0][1][-2]
135
136 # Remove the last 3 items of the file menu: a separator, close window and
137 # quit. Close window will be reinserted just above the save item, where
138 # it should be according to the HIG. Quit is in the application menu.
139 del Bindings.menudefs[0][1][-3:]
140 Bindings.menudefs[0][1].insert(6, closeItem)
141
142 # Remove the 'About' entry from the help menu, it is in the application
143 # menu
144 del Bindings.menudefs[-1][1][0:2]
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400145 # Remove the 'Configure Idle' entry from the options menu, it is in the
Ned Deily57847df2014-03-27 20:47:04 -0700146 # application menu as 'Preferences'
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400147 del Bindings.menudefs[-2][1][0]
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000148 menubar = Menu(root)
149 root.configure(menu=menubar)
150 menudict = {}
151
152 menudict['windows'] = menu = Menu(menubar, name='windows')
153 menubar.add_cascade(label='Window', menu=menu, underline=0)
154
155 def postwindowsmenu(menu=menu):
156 end = menu.index('end')
157 if end is None:
158 end = -1
159
160 if end > 0:
161 menu.delete(0, end)
162 WindowList.add_windows_to_menu(menu)
163 WindowList.register_callback(postwindowsmenu)
164
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000165 def about_dialog(event=None):
Florent Xiclunad630c042010-04-02 07:24:52 +0000166 from idlelib import aboutDialog
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000167 aboutDialog.AboutDialog(root, 'About IDLE')
168
169 def config_dialog(event=None):
Florent Xiclunad630c042010-04-02 07:24:52 +0000170 from idlelib import configDialog
Ronald Oussoren55d88282009-05-26 18:44:48 +0000171 root.instance_dict = flist.inversedict
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000172 configDialog.ConfigDialog(root, 'Settings')
173
Ned Deily4a705502011-01-18 04:33:22 +0000174 def help_dialog(event=None):
175 from idlelib import textView
176 fn = path.join(path.abspath(path.dirname(__file__)), 'help.txt')
177 textView.view_file(root, 'Help', fn)
Ronald Oussoren9b0bcc12007-07-09 06:02:21 +0000178
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000179 root.bind('<<about-idle>>', about_dialog)
180 root.bind('<<open-config-dialog>>', config_dialog)
Ned Deily4a705502011-01-18 04:33:22 +0000181 root.createcommand('::tk::mac::ShowPreferences', config_dialog)
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000182 if flist:
183 root.bind('<<close-all-windows>>', flist.close_all_callback)
184
Ronald Oussoren8ec374c2010-12-07 16:02:59 +0000185 # The binding above doesn't reliably work on all versions of Tk
186 # on MacOSX. Adding command definition below does seem to do the
187 # right thing for now.
188 root.createcommand('exit', flist.close_all_callback)
189
Ned Deily57847df2014-03-27 20:47:04 -0700190 if isCarbonTk():
Ned Deily4a705502011-01-18 04:33:22 +0000191 # for Carbon AquaTk, replace the default Tk apple menu
192 menudict['application'] = menu = Menu(menubar, name='apple')
193 menubar.add_cascade(label='IDLE', menu=menu)
194 Bindings.menudefs.insert(0,
195 ('application', [
Ronald Oussoren9b0bcc12007-07-09 06:02:21 +0000196 ('About IDLE', '<<about-idle>>'),
Ned Deily4a705502011-01-18 04:33:22 +0000197 None,
198 ]))
199 tkversion = root.tk.eval('info patchlevel')
200 if tuple(map(int, tkversion.split('.'))) < (8, 4, 14):
201 # for earlier AquaTk versions, supply a Preferences menu item
202 Bindings.menudefs[0][1].append(
203 ('_Preferences....', '<<open-config-dialog>>'),
204 )
Ned Deily57847df2014-03-27 20:47:04 -0700205 if isCocoaTk():
Ned Deily4a705502011-01-18 04:33:22 +0000206 # replace default About dialog with About IDLE one
207 root.createcommand('tkAboutDialog', about_dialog)
208 # replace default "Help" item in Help menu
209 root.createcommand('::tk::mac::ShowHelp', help_dialog)
210 # remove redundant "IDLE Help" from menu
211 del Bindings.menudefs[-1][1][0]
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000212
Tim Peters231c3c82006-06-11 19:43:49 +0000213def setupApp(root, flist):
214 """
Ned Deily57847df2014-03-27 20:47:04 -0700215 Perform initial OS X customizations if needed.
216 Called from PyShell.main() after initial calls to Tk()
Tim Peters231c3c82006-06-11 19:43:49 +0000217
Ned Deily57847df2014-03-27 20:47:04 -0700218 There are currently three major versions of Tk in use on OS X:
219 1. Aqua Cocoa Tk (native default since OS X 10.6)
220 2. Aqua Carbon Tk (original native, 32-bit only, deprecated)
221 3. X11 (supported by some third-party distributors, deprecated)
222 There are various differences among the three that affect IDLE
223 behavior, primarily with menus, mouse key events, and accelerators.
224 Some one-time customizations are performed here.
225 Others are dynamically tested throughout idlelib by calls to the
226 isAquaTk(), isCarbonTk(), isCocoaTk(), isXQuartz() functions which
227 are initialized here as well.
228 """
229 _initializeTkVariantTests(root)
230 if isAquaTk():
231 hideTkConsole(root)
232 overrideRootMenu(root, flist)
233 addOpenEventSupport(root, flist)