blob: 98d7887b5c08f45d331a49dbd0dd2919ff64cb00 [file] [log] [blame]
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001"""
Ned Deilyb7601672014-03-27 20:49:14 -07002A number of functions that enhance IDLE on Mac OSX.
Thomas Wouters0e3f5912006-08-11 14:57:12 +00003"""
4import sys
Georg Brandl14fc4272008-05-17 18:39:55 +00005import tkinter
Ned Deilyb7601672014-03-27 20:49:14 -07006import warnings
Ronald Oussoren6f6c5622009-12-24 14:03:19 +00007
Ned Deilyb7601672014-03-27 20:49:14 -07008_tk_type = None
9
Terry Jan Reedyfb51e652016-06-08 18:09:22 -040010def _init_tk_type(idleroot=None):
Ned Deilyb7601672014-03-27 20:49:14 -070011 """
12 Initializes OS X Tk variant values for
13 isAquaTk(), isCarbonTk(), isCocoaTk(), and isXQuartz().
14 """
15 global _tk_type
16 if sys.platform == 'darwin':
Terry Jan Reedyfb51e652016-06-08 18:09:22 -040017 root = idleroot or tkinter.Tk()
Ned Deilyb7601672014-03-27 20:49:14 -070018 ws = root.tk.call('tk', 'windowingsystem')
19 if 'x11' in ws:
20 _tk_type = "xquartz"
21 elif 'aqua' not in ws:
22 _tk_type = "other"
23 elif 'AppKit' in root.tk.call('winfo', 'server', '.'):
24 _tk_type = "cocoa"
25 else:
26 _tk_type = "carbon"
Terry Jan Reedyfb51e652016-06-08 18:09:22 -040027 if not idleroot:
28 root.destroy
Ned Deilyb7601672014-03-27 20:49:14 -070029 else:
30 _tk_type = "other"
31
32def isAquaTk():
33 """
34 Returns True if IDLE is using a native OS X Tk (Cocoa or Carbon).
35 """
Terry Jan Reedyfb51e652016-06-08 18:09:22 -040036 if not _tk_type:
37 _init_tk_type()
Ned Deilyb7601672014-03-27 20:49:14 -070038 return _tk_type == "cocoa" or _tk_type == "carbon"
39
40def isCarbonTk():
Georg Brandlaedd2892010-12-19 10:10:32 +000041 """
42 Returns True if IDLE is using a Carbon Aqua Tk (instead of the
43 newer Cocoa Aqua Tk).
44 """
Terry Jan Reedyfb51e652016-06-08 18:09:22 -040045 if not _tk_type:
46 _init_tk_type()
Ned Deilyb7601672014-03-27 20:49:14 -070047 return _tk_type == "carbon"
48
49def isCocoaTk():
50 """
51 Returns True if IDLE is using a Cocoa Aqua Tk.
52 """
Terry Jan Reedyfb51e652016-06-08 18:09:22 -040053 if not _tk_type:
54 _init_tk_type()
Ned Deilyb7601672014-03-27 20:49:14 -070055 return _tk_type == "cocoa"
56
57def isXQuartz():
58 """
59 Returns True if IDLE is using an OS X X11 Tk.
60 """
Terry Jan Reedyfb51e652016-06-08 18:09:22 -040061 if not _tk_type:
62 _init_tk_type()
Ned Deilyb7601672014-03-27 20:49:14 -070063 return _tk_type == "xquartz"
Georg Brandlaedd2892010-12-19 10:10:32 +000064
Ned Deily4ce92b22011-01-15 04:37:12 +000065def tkVersionWarning(root):
66 """
67 Returns a string warning message if the Tk version in use appears to
Ned Deilyc556c642012-07-30 03:31:21 -070068 be one known to cause problems with IDLE.
69 1. Apple Cocoa-based Tk 8.5.7 shipped with Mac OS X 10.6 is unusable.
70 2. Apple Cocoa-based Tk 8.5.9 in OS X 10.7 and 10.8 is better but
71 can still crash unexpectedly.
Ned Deily4ce92b22011-01-15 04:37:12 +000072 """
73
Ned Deilyb7601672014-03-27 20:49:14 -070074 if isCocoaTk():
Ned Deilyc556c642012-07-30 03:31:21 -070075 patchlevel = root.tk.call('info', 'patchlevel')
76 if patchlevel not in ('8.5.7', '8.5.9'):
77 return False
78 return (r"WARNING: The version of Tcl/Tk ({0}) in use may"
Ned Deily4ce92b22011-01-15 04:37:12 +000079 r" be unstable.\n"
80 r"Visit http://www.python.org/download/mac/tcltk/"
Ned Deilyc556c642012-07-30 03:31:21 -070081 r" for current information.".format(patchlevel))
Ned Deily4ce92b22011-01-15 04:37:12 +000082 else:
83 return False
84
Thomas Wouters0e3f5912006-08-11 14:57:12 +000085def addOpenEventSupport(root, flist):
86 """
Ezio Melotti13925002011-03-16 11:05:33 +020087 This ensures that the application will respond to open AppleEvents, which
88 makes is feasible to use IDLE as the default application for python files.
Thomas Wouters0e3f5912006-08-11 14:57:12 +000089 """
90 def doOpenFile(*args):
91 for fn in args:
92 flist.open(fn)
93
94 # The command below is a hook in aquatk that is called whenever the app
95 # receives a file open event. The callback can have multiple arguments,
96 # one for every file that should be opened.
97 root.createcommand("::tk::mac::OpenDocument", doOpenFile)
98
99def hideTkConsole(root):
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000100 try:
101 root.tk.call('console', 'hide')
Georg Brandl14fc4272008-05-17 18:39:55 +0000102 except tkinter.TclError:
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000103 # Some versions of the Tk framework don't have a console object
104 pass
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000105
106def overrideRootMenu(root, flist):
107 """
Ned Deilyb7601672014-03-27 20:49:14 -0700108 Replace the Tk root menu by something that is more appropriate for
109 IDLE with an Aqua Tk.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000110 """
111 # The menu that is attached to the Tk root (".") is also used by AquaTk for
112 # all windows that don't specify a menu of their own. The default menubar
113 # contains a number of menus, none of which are appropriate for IDLE. The
114 # Most annoying of those is an 'About Tck/Tk...' menu in the application
115 # menu.
116 #
117 # This function replaces the default menubar by a mostly empty one, it
118 # should only contain the correct application menu and the window menu.
119 #
120 # Due to a (mis-)feature of TkAqua the user will also see an empty Help
121 # menu.
Terry Jan Reedy038c16b2015-05-15 23:03:17 -0400122 from tkinter import Menu
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400123 from idlelib import mainmenu
124 from idlelib import windows
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000125
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400126 closeItem = mainmenu.menudefs[0][1][-2]
Ned Deilyb7601672014-03-27 20:49:14 -0700127
128 # Remove the last 3 items of the file menu: a separator, close window and
129 # quit. Close window will be reinserted just above the save item, where
130 # it should be according to the HIG. Quit is in the application menu.
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400131 del mainmenu.menudefs[0][1][-3:]
132 mainmenu.menudefs[0][1].insert(6, closeItem)
Ned Deilyb7601672014-03-27 20:49:14 -0700133
134 # Remove the 'About' entry from the help menu, it is in the application
135 # menu
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400136 del mainmenu.menudefs[-1][1][0:2]
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400137 # Remove the 'Configure Idle' entry from the options menu, it is in the
Ned Deilyb7601672014-03-27 20:49:14 -0700138 # application menu as 'Preferences'
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400139 del mainmenu.menudefs[-2][1][0]
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000140 menubar = Menu(root)
141 root.configure(menu=menubar)
142 menudict = {}
143
Terry Jan Reedy30f1f672015-07-30 16:44:22 -0400144 menudict['windows'] = menu = Menu(menubar, name='windows', tearoff=0)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000145 menubar.add_cascade(label='Window', menu=menu, underline=0)
146
147 def postwindowsmenu(menu=menu):
148 end = menu.index('end')
149 if end is None:
150 end = -1
151
152 if end > 0:
153 menu.delete(0, end)
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400154 windows.add_windows_to_menu(menu)
Ned Deily622b2f62016-06-03 17:50:44 -0700155 windows.register_callback(postwindowsmenu)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000156
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000157 def about_dialog(event=None):
Terry Jan Reedyb50c6372015-09-20 22:55:39 -0400158 "Handle Help 'About IDLE' event."
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400159 # Synchronize with editor.EditorWindow.about_dialog.
160 from idlelib import help_about
161 help_about.AboutDialog(root, 'About IDLE')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000162
163 def config_dialog(event=None):
Terry Jan Reedyb50c6372015-09-20 22:55:39 -0400164 "Handle Options 'Configure IDLE' event."
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400165 # Synchronize with editor.EditorWindow.config_dialog.
166 from idlelib import configdialog
Ronald Oussoren220a9fb2009-05-26 18:41:00 +0000167
168 # Ensure that the root object has an instance_dict attribute,
169 # mirrors code in EditorWindow (although that sets the attribute
170 # on an EditorWindow instance that is then passed as the first
171 # argument to ConfigDialog)
172 root.instance_dict = flist.inversedict
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400173 configdialog.ConfigDialog(root, 'Settings')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000174
Georg Brandlaedd2892010-12-19 10:10:32 +0000175 def help_dialog(event=None):
Terry Jan Reedyb50c6372015-09-20 22:55:39 -0400176 "Handle Help 'IDLE Help' event."
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400177 # Synchronize with editor.EditorWindow.help_dialog.
Terry Jan Reedy5d46ab12015-09-20 19:57:13 -0400178 from idlelib import help
179 help.show_idlehelp(root)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000180
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000181 root.bind('<<about-idle>>', about_dialog)
182 root.bind('<<open-config-dialog>>', config_dialog)
Georg Brandlaedd2892010-12-19 10:10:32 +0000183 root.createcommand('::tk::mac::ShowPreferences', config_dialog)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000184 if flist:
185 root.bind('<<close-all-windows>>', flist.close_all_callback)
186
Ronald Oussoren10e05e12010-12-07 15:28:10 +0000187 # The binding above doesn't reliably work on all versions of Tk
188 # on MacOSX. Adding command definition below does seem to do the
189 # right thing for now.
190 root.createcommand('exit', flist.close_all_callback)
191
Ned Deilyb7601672014-03-27 20:49:14 -0700192 if isCarbonTk():
Georg Brandlaedd2892010-12-19 10:10:32 +0000193 # for Carbon AquaTk, replace the default Tk apple menu
Terry Jan Reedy30f1f672015-07-30 16:44:22 -0400194 menudict['application'] = menu = Menu(menubar, name='apple',
195 tearoff=0)
Georg Brandlaedd2892010-12-19 10:10:32 +0000196 menubar.add_cascade(label='IDLE', menu=menu)
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400197 mainmenu.menudefs.insert(0,
Georg Brandlaedd2892010-12-19 10:10:32 +0000198 ('application', [
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000199 ('About IDLE', '<<about-idle>>'),
Georg Brandlaedd2892010-12-19 10:10:32 +0000200 None,
201 ]))
Ned Deilyb7601672014-03-27 20:49:14 -0700202 if isCocoaTk():
Georg Brandlaedd2892010-12-19 10:10:32 +0000203 # replace default About dialog with About IDLE one
204 root.createcommand('tkAboutDialog', about_dialog)
205 # replace default "Help" item in Help menu
206 root.createcommand('::tk::mac::ShowHelp', help_dialog)
207 # remove redundant "IDLE Help" from menu
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400208 del mainmenu.menudefs[-1][1][0]
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000209
Terry Jan Reedy24f3a182016-06-08 14:37:05 -0400210def fixb2context(root):
211 '''Removed bad AquaTk Button-2 (right) and Paste bindings.
212
213 They prevent context menu access and seem to be gone in AquaTk8.6.
214 See issue #24801.
215 '''
216 root.unbind_class('Text', '<B2>')
217 root.unbind_class('Text', '<B2-Motion>')
218 root.unbind_class('Text', '<<PasteSelection>>')
219
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000220def setupApp(root, flist):
221 """
Ned Deilyb7601672014-03-27 20:49:14 -0700222 Perform initial OS X customizations if needed.
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -0400223 Called from pyshell.main() after initial calls to Tk()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000224
Ned Deilyb7601672014-03-27 20:49:14 -0700225 There are currently three major versions of Tk in use on OS X:
226 1. Aqua Cocoa Tk (native default since OS X 10.6)
227 2. Aqua Carbon Tk (original native, 32-bit only, deprecated)
228 3. X11 (supported by some third-party distributors, deprecated)
229 There are various differences among the three that affect IDLE
230 behavior, primarily with menus, mouse key events, and accelerators.
231 Some one-time customizations are performed here.
232 Others are dynamically tested throughout idlelib by calls to the
233 isAquaTk(), isCarbonTk(), isCocoaTk(), isXQuartz() functions which
234 are initialized here as well.
235 """
Terry Jan Reedyfb51e652016-06-08 18:09:22 -0400236 _init_tk_type(root)
Ned Deilyb7601672014-03-27 20:49:14 -0700237 if isAquaTk():
238 hideTkConsole(root)
239 overrideRootMenu(root, flist)
240 addOpenEventSupport(root, flist)
Ned Deily139fb7c2016-06-11 02:57:56 -0400241 fixb2context(root)