| """ |
| A number of functions that enhance IDLE on macOS. |
| """ |
| from os.path import expanduser |
| import plistlib |
| from sys import platform |
|
|
| import tkinter |
|
|
|
|
| |
| |
|
|
| _tk_type = None |
|
|
| def _init_tk_type(): |
| """ Initialize _tk_type for isXyzTk functions. |
| |
| This function is only called once, when _tk_type is still None. |
| """ |
| global _tk_type |
| if platform == 'darwin': |
|
|
| |
| |
| |
| from idlelib.__init__ import testing |
| if testing: |
| from test.support import requires, ResourceDenied |
| try: |
| requires('gui') |
| except ResourceDenied: |
| _tk_type = "cocoa" |
| return |
|
|
| root = tkinter.Tk() |
| ws = root.tk.call('tk', 'windowingsystem') |
| if 'x11' in ws: |
| _tk_type = "xquartz" |
| elif 'aqua' not in ws: |
| _tk_type = "other" |
| elif 'AppKit' in root.tk.call('winfo', 'server', '.'): |
| _tk_type = "cocoa" |
| else: |
| _tk_type = "carbon" |
| root.destroy() |
| else: |
| _tk_type = "other" |
| return |
|
|
| def isAquaTk(): |
| """ |
| Returns True if IDLE is using a native OS X Tk (Cocoa or Carbon). |
| """ |
| if not _tk_type: |
| _init_tk_type() |
| return _tk_type == "cocoa" or _tk_type == "carbon" |
|
|
| def isCarbonTk(): |
| """ |
| Returns True if IDLE is using a Carbon Aqua Tk (instead of the |
| newer Cocoa Aqua Tk). |
| """ |
| if not _tk_type: |
| _init_tk_type() |
| return _tk_type == "carbon" |
|
|
| def isCocoaTk(): |
| """ |
| Returns True if IDLE is using a Cocoa Aqua Tk. |
| """ |
| if not _tk_type: |
| _init_tk_type() |
| return _tk_type == "cocoa" |
|
|
| def isXQuartz(): |
| """ |
| Returns True if IDLE is using an OS X X11 Tk. |
| """ |
| if not _tk_type: |
| _init_tk_type() |
| return _tk_type == "xquartz" |
|
|
|
|
| def readSystemPreferences(): |
| """ |
| Fetch the macOS system preferences. |
| """ |
| if platform != 'darwin': |
| return None |
|
|
| plist_path = expanduser('~/Library/Preferences/.GlobalPreferences.plist') |
| try: |
| with open(plist_path, 'rb') as plist_file: |
| return plistlib.load(plist_file) |
| except OSError: |
| return None |
|
|
|
|
| def preferTabsPreferenceWarning(): |
| """ |
| Warn if "Prefer tabs when opening documents" is set to "Always". |
| """ |
| if platform != 'darwin': |
| return None |
|
|
| prefs = readSystemPreferences() |
| if prefs and prefs.get('AppleWindowTabbingMode') == 'always': |
| return ( |
| 'WARNING: The system preference "Prefer tabs when opening' |
| ' documents" is set to "Always". This will cause various problems' |
| ' with IDLE. For the best experience, change this setting when' |
| ' running IDLE (via System Preferences -> Dock).' |
| ) |
| return None |
|
|
|
|
| |
|
|
| def addOpenEventSupport(root, flist): |
| """ |
| This ensures that the application will respond to open AppleEvents, which |
| makes is feasible to use IDLE as the default application for python files. |
| """ |
| def doOpenFile(*args): |
| for fn in args: |
| flist.open(fn) |
|
|
| |
| |
| |
| root.createcommand("::tk::mac::OpenDocument", doOpenFile) |
|
|
| def hideTkConsole(root): |
| try: |
| root.tk.call('console', 'hide') |
| except tkinter.TclError: |
| |
| pass |
|
|
| def overrideRootMenu(root, flist): |
| """ |
| Replace the Tk root menu by something that is more appropriate for |
| IDLE with an Aqua Tk. |
| """ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| from tkinter import Menu |
| from idlelib import mainmenu |
| from idlelib import window |
|
|
| closeItem = mainmenu.menudefs[0][1][-2] |
|
|
| |
| |
| |
| del mainmenu.menudefs[0][1][-3:] |
| mainmenu.menudefs[0][1].insert(6, closeItem) |
|
|
| |
| |
| del mainmenu.menudefs[-1][1][0:2] |
| |
| |
| del mainmenu.menudefs[-3][1][0:2] |
| menubar = Menu(root) |
| root.configure(menu=menubar) |
| menudict = {} |
|
|
| menudict['window'] = menu = Menu(menubar, name='window', tearoff=0) |
| menubar.add_cascade(label='Window', menu=menu, underline=0) |
|
|
| def postwindowsmenu(menu=menu): |
| end = menu.index('end') |
| if end is None: |
| end = -1 |
|
|
| if end > 0: |
| menu.delete(0, end) |
| window.add_windows_to_menu(menu) |
| window.register_callback(postwindowsmenu) |
|
|
| def about_dialog(event=None): |
| "Handle Help 'About IDLE' event." |
| |
| from idlelib import help_about |
| help_about.AboutDialog(root) |
|
|
| def config_dialog(event=None): |
| "Handle Options 'Configure IDLE' event." |
| |
| from idlelib import configdialog |
|
|
| |
| |
| |
| |
| root.instance_dict = flist.inversedict |
| configdialog.ConfigDialog(root, 'Settings') |
|
|
| def help_dialog(event=None): |
| "Handle Help 'IDLE Help' event." |
| |
| from idlelib import help |
| help.show_idlehelp(root) |
|
|
| root.bind('<<about-idle>>', about_dialog) |
| root.bind('<<open-config-dialog>>', config_dialog) |
| root.createcommand('::tk::mac::ShowPreferences', config_dialog) |
| if flist: |
| root.bind('<<close-all-windows>>', flist.close_all_callback) |
|
|
| |
| |
| |
| root.createcommand('::tk::mac::Quit', flist.close_all_callback) |
|
|
| if isCarbonTk(): |
| |
| menudict['application'] = menu = Menu(menubar, name='apple', |
| tearoff=0) |
| menubar.add_cascade(label='IDLE', menu=menu) |
| mainmenu.menudefs.insert(0, |
| ('application', [ |
| ('About IDLE', '<<about-idle>>'), |
| None, |
| ])) |
| if isCocoaTk(): |
| |
| root.createcommand('tkAboutDialog', about_dialog) |
| |
| root.createcommand('::tk::mac::ShowHelp', help_dialog) |
| |
| del mainmenu.menudefs[-1][1][0] |
|
|
| def fixb2context(root): |
| '''Removed bad AquaTk Button-2 (right) and Paste bindings. |
| |
| They prevent context menu access and seem to be gone in AquaTk8.6. |
| See issue #24801. |
| ''' |
| root.unbind_class('Text', '<B2>') |
| root.unbind_class('Text', '<B2-Motion>') |
| root.unbind_class('Text', '<<PasteSelection>>') |
|
|
| def setupApp(root, flist): |
| """ |
| Perform initial OS X customizations if needed. |
| Called from pyshell.main() after initial calls to Tk() |
| |
| There are currently three major versions of Tk in use on OS X: |
| 1. Aqua Cocoa Tk (native default since OS X 10.6) |
| 2. Aqua Carbon Tk (original native, 32-bit only, deprecated) |
| 3. X11 (supported by some third-party distributors, deprecated) |
| There are various differences among the three that affect IDLE |
| behavior, primarily with menus, mouse key events, and accelerators. |
| Some one-time customizations are performed here. |
| Others are dynamically tested throughout idlelib by calls to the |
| isAquaTk(), isCarbonTk(), isCocoaTk(), isXQuartz() functions which |
| are initialized here as well. |
| """ |
| if isAquaTk(): |
| hideTkConsole(root) |
| overrideRootMenu(root, flist) |
| addOpenEventSupport(root, flist) |
| fixb2context(root) |
|
|
|
|
| if __name__ == '__main__': |
| from unittest import main |
| main('idlelib.idle_test.test_macosx', verbosity=2) |
|
|