Mercurial > repos > rliterman > csp2
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) |