comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/macosx.py @ 68:5028fdace37b

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 16:23:26 -0400
parents
children
comparison
equal deleted inserted replaced
67:0e9998148a16 68:5028fdace37b
1 """
2 A number of functions that enhance IDLE on macOS.
3 """
4 from os.path import expanduser
5 import plistlib
6 from sys import platform # Used in _init_tk_type, changed by test.
7
8 import tkinter
9
10
11 ## Define functions that query the Mac graphics type.
12 ## _tk_type and its initializer are private to this section.
13
14 _tk_type = None
15
16 def _init_tk_type():
17 """
18 Initializes OS X Tk variant values for
19 isAquaTk(), isCarbonTk(), isCocoaTk(), and isXQuartz().
20 """
21 global _tk_type
22 if platform == 'darwin':
23 root = tkinter.Tk()
24 ws = root.tk.call('tk', 'windowingsystem')
25 if 'x11' in ws:
26 _tk_type = "xquartz"
27 elif 'aqua' not in ws:
28 _tk_type = "other"
29 elif 'AppKit' in root.tk.call('winfo', 'server', '.'):
30 _tk_type = "cocoa"
31 else:
32 _tk_type = "carbon"
33 root.destroy()
34 else:
35 _tk_type = "other"
36
37 def isAquaTk():
38 """
39 Returns True if IDLE is using a native OS X Tk (Cocoa or Carbon).
40 """
41 if not _tk_type:
42 _init_tk_type()
43 return _tk_type == "cocoa" or _tk_type == "carbon"
44
45 def isCarbonTk():
46 """
47 Returns True if IDLE is using a Carbon Aqua Tk (instead of the
48 newer Cocoa Aqua Tk).
49 """
50 if not _tk_type:
51 _init_tk_type()
52 return _tk_type == "carbon"
53
54 def isCocoaTk():
55 """
56 Returns True if IDLE is using a Cocoa Aqua Tk.
57 """
58 if not _tk_type:
59 _init_tk_type()
60 return _tk_type == "cocoa"
61
62 def isXQuartz():
63 """
64 Returns True if IDLE is using an OS X X11 Tk.
65 """
66 if not _tk_type:
67 _init_tk_type()
68 return _tk_type == "xquartz"
69
70
71 def tkVersionWarning(root):
72 """
73 Returns a string warning message if the Tk version in use appears to
74 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.
78 """
79
80 if isCocoaTk():
81 patchlevel = root.tk.call('info', 'patchlevel')
82 if patchlevel not in ('8.5.7', '8.5.9'):
83 return False
84 return ("WARNING: The version of Tcl/Tk ({0}) in use may"
85 " be unstable.\n"
86 "Visit http://www.python.org/download/mac/tcltk/"
87 " for current information.".format(patchlevel))
88 else:
89 return False
90
91
92 def readSystemPreferences():
93 """
94 Fetch the macOS system preferences.
95 """
96 if platform != 'darwin':
97 return None
98
99 plist_path = expanduser('~/Library/Preferences/.GlobalPreferences.plist')
100 try:
101 with open(plist_path, 'rb') as plist_file:
102 return plistlib.load(plist_file)
103 except OSError:
104 return None
105
106
107 def preferTabsPreferenceWarning():
108 """
109 Warn if "Prefer tabs when opening documents" is set to "Always".
110 """
111 if platform != 'darwin':
112 return None
113
114 prefs = readSystemPreferences()
115 if prefs and prefs.get('AppleWindowTabbingMode') == 'always':
116 return (
117 'WARNING: The system preference "Prefer tabs when opening'
118 ' documents" is set to "Always". This will cause various problems'
119 ' with IDLE. For the best experience, change this setting when'
120 ' running IDLE (via System Preferences -> Dock).'
121 )
122 return None
123
124
125 ## Fix the menu and related functions.
126
127 def addOpenEventSupport(root, flist):
128 """
129 This ensures that the application will respond to open AppleEvents, which
130 makes is feasible to use IDLE as the default application for python files.
131 """
132 def doOpenFile(*args):
133 for fn in args:
134 flist.open(fn)
135
136 # The command below is a hook in aquatk that is called whenever the app
137 # receives a file open event. The callback can have multiple arguments,
138 # one for every file that should be opened.
139 root.createcommand("::tk::mac::OpenDocument", doOpenFile)
140
141 def hideTkConsole(root):
142 try:
143 root.tk.call('console', 'hide')
144 except tkinter.TclError:
145 # Some versions of the Tk framework don't have a console object
146 pass
147
148 def overrideRootMenu(root, flist):
149 """
150 Replace the Tk root menu by something that is more appropriate for
151 IDLE with an Aqua Tk.
152 """
153 # The menu that is attached to the Tk root (".") is also used by AquaTk for
154 # all windows that don't specify a menu of their own. The default menubar
155 # contains a number of menus, none of which are appropriate for IDLE. The
156 # Most annoying of those is an 'About Tck/Tk...' menu in the application
157 # menu.
158 #
159 # This function replaces the default menubar by a mostly empty one, it
160 # should only contain the correct application menu and the window menu.
161 #
162 # Due to a (mis-)feature of TkAqua the user will also see an empty Help
163 # menu.
164 from tkinter import Menu
165 from idlelib import mainmenu
166 from idlelib import window
167
168 closeItem = mainmenu.menudefs[0][1][-2]
169
170 # Remove the last 3 items of the file menu: a separator, close window and
171 # quit. Close window will be reinserted just above the save item, where
172 # it should be according to the HIG. Quit is in the application menu.
173 del mainmenu.menudefs[0][1][-3:]
174 mainmenu.menudefs[0][1].insert(6, closeItem)
175
176 # Remove the 'About' entry from the help menu, it is in the application
177 # menu
178 del mainmenu.menudefs[-1][1][0:2]
179 # Remove the 'Configure Idle' entry from the options menu, it is in the
180 # application menu as 'Preferences'
181 del mainmenu.menudefs[-3][1][0:2]
182 menubar = Menu(root)
183 root.configure(menu=menubar)
184 menudict = {}
185
186 menudict['window'] = menu = Menu(menubar, name='window', tearoff=0)
187 menubar.add_cascade(label='Window', menu=menu, underline=0)
188
189 def postwindowsmenu(menu=menu):
190 end = menu.index('end')
191 if end is None:
192 end = -1
193
194 if end > 0:
195 menu.delete(0, end)
196 window.add_windows_to_menu(menu)
197 window.register_callback(postwindowsmenu)
198
199 def about_dialog(event=None):
200 "Handle Help 'About IDLE' event."
201 # Synchronize with editor.EditorWindow.about_dialog.
202 from idlelib import help_about
203 help_about.AboutDialog(root)
204
205 def config_dialog(event=None):
206 "Handle Options 'Configure IDLE' event."
207 # Synchronize with editor.EditorWindow.config_dialog.
208 from idlelib import configdialog
209
210 # Ensure that the root object has an instance_dict attribute,
211 # mirrors code in EditorWindow (although that sets the attribute
212 # on an EditorWindow instance that is then passed as the first
213 # argument to ConfigDialog)
214 root.instance_dict = flist.inversedict
215 configdialog.ConfigDialog(root, 'Settings')
216
217 def help_dialog(event=None):
218 "Handle Help 'IDLE Help' event."
219 # Synchronize with editor.EditorWindow.help_dialog.
220 from idlelib import help
221 help.show_idlehelp(root)
222
223 root.bind('<<about-idle>>', about_dialog)
224 root.bind('<<open-config-dialog>>', config_dialog)
225 root.createcommand('::tk::mac::ShowPreferences', config_dialog)
226 if flist:
227 root.bind('<<close-all-windows>>', flist.close_all_callback)
228
229 # The binding above doesn't reliably work on all versions of Tk
230 # on macOS. Adding command definition below does seem to do the
231 # right thing for now.
232 root.createcommand('exit', flist.close_all_callback)
233
234 if isCarbonTk():
235 # for Carbon AquaTk, replace the default Tk apple menu
236 menudict['application'] = menu = Menu(menubar, name='apple',
237 tearoff=0)
238 menubar.add_cascade(label='IDLE', menu=menu)
239 mainmenu.menudefs.insert(0,
240 ('application', [
241 ('About IDLE', '<<about-idle>>'),
242 None,
243 ]))
244 if isCocoaTk():
245 # replace default About dialog with About IDLE one
246 root.createcommand('tkAboutDialog', about_dialog)
247 # replace default "Help" item in Help menu
248 root.createcommand('::tk::mac::ShowHelp', help_dialog)
249 # remove redundant "IDLE Help" from menu
250 del mainmenu.menudefs[-1][1][0]
251
252 def fixb2context(root):
253 '''Removed bad AquaTk Button-2 (right) and Paste bindings.
254
255 They prevent context menu access and seem to be gone in AquaTk8.6.
256 See issue #24801.
257 '''
258 root.unbind_class('Text', '<B2>')
259 root.unbind_class('Text', '<B2-Motion>')
260 root.unbind_class('Text', '<<PasteSelection>>')
261
262 def setupApp(root, flist):
263 """
264 Perform initial OS X customizations if needed.
265 Called from pyshell.main() after initial calls to Tk()
266
267 There are currently three major versions of Tk in use on OS X:
268 1. Aqua Cocoa Tk (native default since OS X 10.6)
269 2. Aqua Carbon Tk (original native, 32-bit only, deprecated)
270 3. X11 (supported by some third-party distributors, deprecated)
271 There are various differences among the three that affect IDLE
272 behavior, primarily with menus, mouse key events, and accelerators.
273 Some one-time customizations are performed here.
274 Others are dynamically tested throughout idlelib by calls to the
275 isAquaTk(), isCarbonTk(), isCocoaTk(), isXQuartz() functions which
276 are initialized here as well.
277 """
278 if isAquaTk():
279 hideTkConsole(root)
280 overrideRootMenu(root, flist)
281 addOpenEventSupport(root, flist)
282 fixb2context(root)
283
284
285 if __name__ == '__main__':
286 from unittest import main
287 main('idlelib.idle_test.test_macosx', verbosity=2)