blob: 70ee8fb10792639fa19c64d8166ec641718b22a3 [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):
173 from idlelib import textView
174 fn = path.join(path.abspath(path.dirname(__file__)), 'help.txt')
175 textView.view_file(root, 'Help', fn)
Ronald Oussoren9b0bcc12007-07-09 06:02:21 +0000176
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000177 root.bind('<<about-idle>>', about_dialog)
178 root.bind('<<open-config-dialog>>', config_dialog)
Ned Deily4a705502011-01-18 04:33:22 +0000179 root.createcommand('::tk::mac::ShowPreferences', config_dialog)
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000180 if flist:
181 root.bind('<<close-all-windows>>', flist.close_all_callback)
182
Ronald Oussoren8ec374c2010-12-07 16:02:59 +0000183 # The binding above doesn't reliably work on all versions of Tk
184 # on MacOSX. Adding command definition below does seem to do the
185 # right thing for now.
186 root.createcommand('exit', flist.close_all_callback)
187
Ned Deily57847df2014-03-27 20:47:04 -0700188 if isCarbonTk():
Ned Deily4a705502011-01-18 04:33:22 +0000189 # for Carbon AquaTk, replace the default Tk apple menu
Terry Jan Reedyfa002d42015-07-30 16:44:09 -0400190 menudict['application'] = menu = Menu(menubar, name='apple',
191 tearoff=0)
Ned Deily4a705502011-01-18 04:33:22 +0000192 menubar.add_cascade(label='IDLE', menu=menu)
193 Bindings.menudefs.insert(0,
194 ('application', [
Ronald Oussoren9b0bcc12007-07-09 06:02:21 +0000195 ('About IDLE', '<<about-idle>>'),
Ned Deily4a705502011-01-18 04:33:22 +0000196 None,
197 ]))
198 tkversion = root.tk.eval('info patchlevel')
199 if tuple(map(int, tkversion.split('.'))) < (8, 4, 14):
200 # for earlier AquaTk versions, supply a Preferences menu item
201 Bindings.menudefs[0][1].append(
202 ('_Preferences....', '<<open-config-dialog>>'),
203 )
Ned Deily57847df2014-03-27 20:47:04 -0700204 if isCocoaTk():
Ned Deily4a705502011-01-18 04:33:22 +0000205 # replace default About dialog with About IDLE one
206 root.createcommand('tkAboutDialog', about_dialog)
207 # replace default "Help" item in Help menu
208 root.createcommand('::tk::mac::ShowHelp', help_dialog)
209 # remove redundant "IDLE Help" from menu
210 del Bindings.menudefs[-1][1][0]
Ronald Oussoren8133f9d2006-07-23 09:46:11 +0000211
Tim Peters231c3c82006-06-11 19:43:49 +0000212def setupApp(root, flist):
213 """
Ned Deily57847df2014-03-27 20:47:04 -0700214 Perform initial OS X customizations if needed.
215 Called from PyShell.main() after initial calls to Tk()
Tim Peters231c3c82006-06-11 19:43:49 +0000216
Ned Deily57847df2014-03-27 20:47:04 -0700217 There are currently three major versions of Tk in use on OS X:
218 1. Aqua Cocoa Tk (native default since OS X 10.6)
219 2. Aqua Carbon Tk (original native, 32-bit only, deprecated)
220 3. X11 (supported by some third-party distributors, deprecated)
221 There are various differences among the three that affect IDLE
222 behavior, primarily with menus, mouse key events, and accelerators.
223 Some one-time customizations are performed here.
224 Others are dynamically tested throughout idlelib by calls to the
225 isAquaTk(), isCarbonTk(), isCocoaTk(), isXQuartz() functions which
226 are initialized here as well.
227 """
228 _initializeTkVariantTests(root)
229 if isAquaTk():
230 hideTkConsole(root)
231 overrideRootMenu(root, flist)
232 addOpenEventSupport(root, flist)