blob: 0da46ea55b518f124501298b61ac5825e7b8f4d4 [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.
Terry Jan Reedy28489252015-05-15 23:03:11 -0400128 from Tkinter import Menu
Florent Xiclunad630c042010-04-02 07:24:52 +0000129 from idlelib import Bindings
130 from idlelib import WindowList
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000131
Ned Deily57847df2014-03-27 20:47:04 -0700132 closeItem = Bindings.menudefs[0][1][-2]
133
134 # Remove the last 3 items of the file menu: a separator, close window and
135 # quit. Close window will be reinserted just above the save item, where
136 # it should be according to the HIG. Quit is in the application menu.
137 del Bindings.menudefs[0][1][-3:]
138 Bindings.menudefs[0][1].insert(6, closeItem)
139
140 # Remove the 'About' entry from the help menu, it is in the application
141 # menu
142 del Bindings.menudefs[-1][1][0:2]
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400143 # Remove the 'Configure Idle' entry from the options menu, it is in the
Ned Deily57847df2014-03-27 20:47:04 -0700144 # application menu as 'Preferences'
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400145 del Bindings.menudefs[-2][1][0]
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000146 menubar = Menu(root)
147 root.configure(menu=menubar)
148 menudict = {}
149
Terry Jan Reedyfa002d42015-07-30 16:44:09 -0400150 menudict['windows'] = menu = Menu(menubar, name='windows', tearoff=0)
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000151 menubar.add_cascade(label='Window', menu=menu, underline=0)
152
153 def postwindowsmenu(menu=menu):
154 end = menu.index('end')
155 if end is None:
156 end = -1
157
158 if end > 0:
159 menu.delete(0, end)
160 WindowList.add_windows_to_menu(menu)
161 WindowList.register_callback(postwindowsmenu)
162
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000163 def about_dialog(event=None):
Florent Xiclunad630c042010-04-02 07:24:52 +0000164 from idlelib import aboutDialog
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000165 aboutDialog.AboutDialog(root, 'About IDLE')
166
167 def config_dialog(event=None):
Florent Xiclunad630c042010-04-02 07:24:52 +0000168 from idlelib import configDialog
Ronald Oussoren55d88282009-05-26 18:44:48 +0000169 root.instance_dict = flist.inversedict
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000170 configDialog.ConfigDialog(root, 'Settings')
171
Ned Deily4a705502011-01-18 04:33:22 +0000172 def help_dialog(event=None):
Terry Jan Reedy70e763c2015-09-20 19:55:44 -0400173 from idlelib import help
174 help.show_idlehelp(root)
Ronald Oussoren9b0bcc12007-07-09 06:02:21 +0000175
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000176 root.bind('<<about-idle>>', about_dialog)
177 root.bind('<<open-config-dialog>>', config_dialog)
Ned Deily4a705502011-01-18 04:33:22 +0000178 root.createcommand('::tk::mac::ShowPreferences', config_dialog)
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000179 if flist:
180 root.bind('<<close-all-windows>>', flist.close_all_callback)
181
Ronald Oussoren8ec374c2010-12-07 16:02:59 +0000182 # The binding above doesn't reliably work on all versions of Tk
183 # on MacOSX. Adding command definition below does seem to do the
184 # right thing for now.
185 root.createcommand('exit', flist.close_all_callback)
186
Ned Deily57847df2014-03-27 20:47:04 -0700187 if isCarbonTk():
Ned Deily4a705502011-01-18 04:33:22 +0000188 # for Carbon AquaTk, replace the default Tk apple menu
Terry Jan Reedyfa002d42015-07-30 16:44:09 -0400189 menudict['application'] = menu = Menu(menubar, name='apple',
190 tearoff=0)
Ned Deily4a705502011-01-18 04:33:22 +0000191 menubar.add_cascade(label='IDLE', menu=menu)
192 Bindings.menudefs.insert(0,
193 ('application', [
Ronald Oussoren9b0bcc12007-07-09 06:02:21 +0000194 ('About IDLE', '<<about-idle>>'),
Ned Deily4a705502011-01-18 04:33:22 +0000195 None,
196 ]))
197 tkversion = root.tk.eval('info patchlevel')
198 if tuple(map(int, tkversion.split('.'))) < (8, 4, 14):
199 # for earlier AquaTk versions, supply a Preferences menu item
200 Bindings.menudefs[0][1].append(
201 ('_Preferences....', '<<open-config-dialog>>'),
202 )
Ned Deily57847df2014-03-27 20:47:04 -0700203 if isCocoaTk():
Ned Deily4a705502011-01-18 04:33:22 +0000204 # replace default About dialog with About IDLE one
205 root.createcommand('tkAboutDialog', about_dialog)
206 # replace default "Help" item in Help menu
207 root.createcommand('::tk::mac::ShowHelp', help_dialog)
208 # remove redundant "IDLE Help" from menu
209 del Bindings.menudefs[-1][1][0]
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000210
Tim Peters231c3c82006-06-11 19:43:49 +0000211def setupApp(root, flist):
212 """
Ned Deily57847df2014-03-27 20:47:04 -0700213 Perform initial OS X customizations if needed.
214 Called from PyShell.main() after initial calls to Tk()
Tim Peters231c3c82006-06-11 19:43:49 +0000215
Ned Deily57847df2014-03-27 20:47:04 -0700216 There are currently three major versions of Tk in use on OS X:
217 1. Aqua Cocoa Tk (native default since OS X 10.6)
218 2. Aqua Carbon Tk (original native, 32-bit only, deprecated)
219 3. X11 (supported by some third-party distributors, deprecated)
220 There are various differences among the three that affect IDLE
221 behavior, primarily with menus, mouse key events, and accelerators.
222 Some one-time customizations are performed here.
223 Others are dynamically tested throughout idlelib by calls to the
224 isAquaTk(), isCarbonTk(), isCocoaTk(), isXQuartz() functions which
225 are initialized here as well.
226 """
227 _initializeTkVariantTests(root)
228 if isAquaTk():
229 hideTkConsole(root)
230 overrideRootMenu(root, flist)
231 addOpenEventSupport(root, flist)