diff options
author | Ned Deily <nad@acm.org> | 2014-03-28 03:49:14 (GMT) |
---|---|---|
committer | Ned Deily <nad@acm.org> | 2014-03-28 03:49:14 (GMT) |
commit | b7601676b07c7c8e79af9e7818a783b966612c34 (patch) | |
tree | 7a3d48649890a9901747b98df2a9ed13ac13d2db /Lib | |
parent | e7d532fbc9c13e00b1e5c6c0db2dba31d1212de7 (diff) | |
download | cpython-b7601676b07c7c8e79af9e7818a783b966612c34.zip cpython-b7601676b07c7c8e79af9e7818a783b966612c34.tar.gz cpython-b7601676b07c7c8e79af9e7818a783b966612c34.tar.bz2 |
Issue #17654: Ensure IDLE menus are customized properly on OS X for
non-framework builds and for all variants of Tk.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/idlelib/Bindings.py | 32 | ||||
-rw-r--r-- | Lib/idlelib/Debugger.py | 2 | ||||
-rw-r--r-- | Lib/idlelib/EditorWindow.py | 14 | ||||
-rw-r--r-- | Lib/idlelib/MultiCall.py | 3 | ||||
-rwxr-xr-x | Lib/idlelib/PyShell.py | 4 | ||||
-rw-r--r-- | Lib/idlelib/ScriptBinding.py | 4 | ||||
-rw-r--r-- | Lib/idlelib/ZoomHeight.py | 2 | ||||
-rw-r--r-- | Lib/idlelib/configDialog.py | 2 | ||||
-rw-r--r-- | Lib/idlelib/configHandler.py | 12 | ||||
-rw-r--r-- | Lib/idlelib/keybindingDialog.py | 5 | ||||
-rw-r--r-- | Lib/idlelib/macosxSupport.py | 136 |
11 files changed, 123 insertions, 93 deletions
diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py index 65c0317..df2b251 100644 --- a/Lib/idlelib/Bindings.py +++ b/Lib/idlelib/Bindings.py @@ -8,9 +8,14 @@ the PythonShell window, and a Format menu which is only present in the Editor windows. """ -import sys from idlelib.configHandler import idleConf -from idlelib import macosxSupport + +# Warning: menudefs is altered in macosxSupport.overrideRootMenu() +# after it is determined that an OS X Aqua Tk is in use, +# which cannot be done until after Tk() is first called. +# Do not alter the 'file', 'options', or 'help' cascades here +# without altering overrideRootMenu() as well. +# TODO: Make this more robust menudefs = [ # underscore prefixes character to underscore @@ -81,27 +86,4 @@ menudefs = [ ]), ] -if macosxSupport.runningAsOSXApp(): - # Running as a proper MacOS application bundle. This block restructures - # the menus a little to make them conform better to the HIG. - - quitItem = menudefs[0][1][-1] - closeItem = menudefs[0][1][-2] - - # Remove the last 3 items of the file menu: a separator, close window and - # quit. Close window will be reinserted just above the save item, where - # it should be according to the HIG. Quit is in the application menu. - del menudefs[0][1][-3:] - menudefs[0][1].insert(6, closeItem) - - # Remove the 'About' entry from the help menu, it is in the application - # menu - del menudefs[-1][1][0:2] - - # Remove the 'Configure' entry from the options menu, it is in the - # application menu as 'Preferences' - del menudefs[-2][1][0:2] - default_keydefs = idleConf.GetCurrentKeySet() - -del sys diff --git a/Lib/idlelib/Debugger.py b/Lib/idlelib/Debugger.py index d4872ed..ca98b10 100644 --- a/Lib/idlelib/Debugger.py +++ b/Lib/idlelib/Debugger.py @@ -322,7 +322,7 @@ class Debugger: class StackViewer(ScrolledList): def __init__(self, master, flist, gui): - if macosxSupport.runningAsOSXApp(): + if macosxSupport.isAquaTk(): # At least on with the stock AquaTk version on OSX 10.4 you'll # get an shaking GUI that eventually kills IDLE if the width # argument is specified. diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py index d183057..cdb6775 100644 --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -109,8 +109,8 @@ class EditorWindow(object): 'Python%s.chm' % _sphinx_version()) if os.path.isfile(chmfile): dochome = chmfile - elif macosxSupport.runningAsOSXApp(): - # documentation is stored inside the python framework + elif sys.platform == 'darwin': + # documentation may be stored inside a python framework dochome = os.path.join(sys.base_prefix, 'Resources/English.lproj/Documentation/index.html') dochome = os.path.normpath(dochome) @@ -166,7 +166,7 @@ class EditorWindow(object): self.top.protocol("WM_DELETE_WINDOW", self.close) self.top.bind("<<close-window>>", self.close_event) - if macosxSupport.runningAsOSXApp(): + if macosxSupport.isAquaTk(): # Command-W on editorwindows doesn't work without this. text.bind('<<close-window>>', self.close_event) # Some OS X systems have only one mouse button, @@ -409,7 +409,7 @@ class EditorWindow(object): def set_status_bar(self): self.status_bar = self.MultiStatusBar(self.top) - if macosxSupport.runningAsOSXApp(): + if sys.platform == "darwin": # Insert some padding to avoid obscuring some of the statusbar # by the resize widget. self.status_bar.set_label('_padding1', ' ', side=RIGHT) @@ -436,7 +436,7 @@ class EditorWindow(object): ("help", "_Help"), ] - if macosxSupport.runningAsOSXApp(): + if sys.platform == "darwin": menu_specs[-2] = ("windows", "_Window") @@ -447,7 +447,7 @@ class EditorWindow(object): underline, label = prepstr(label) menudict[name] = menu = Menu(mbar, name=name) mbar.add_cascade(label=label, menu=menu, underline=underline) - if macosxSupport.isCarbonAquaTk(self.root): + if macosxSupport.isCarbonTk(): # Insert the application menu menudict['application'] = menu = Menu(mbar, name='apple') mbar.add_cascade(label='IDLE', menu=menu) @@ -1673,7 +1673,7 @@ def get_accelerator(keydefs, eventname): keylist = keydefs.get(eventname) # issue10940: temporary workaround to prevent hang with OS X Cocoa Tk 8.5 # if not keylist: - if (not keylist) or (macosxSupport.runningAsOSXApp() and eventname in { + if (not keylist) or (macosxSupport.isCocoaTk() and eventname in { "<<open-module>>", "<<goto-line>>", "<<change-indentwidth>>"}): diff --git a/Lib/idlelib/MultiCall.py b/Lib/idlelib/MultiCall.py index 25105dc..cc6bffd 100644 --- a/Lib/idlelib/MultiCall.py +++ b/Lib/idlelib/MultiCall.py @@ -32,7 +32,6 @@ Each function will be called at most once for each event. import sys import re import tkinter -from idlelib import macosxSupport # the event type constants, which define the meaning of mc_type MC_KEYPRESS=0; MC_KEYRELEASE=1; MC_BUTTONPRESS=2; MC_BUTTONRELEASE=3; @@ -45,7 +44,7 @@ MC_SHIFT = 1<<0; MC_CONTROL = 1<<2; MC_ALT = 1<<3; MC_META = 1<<5 MC_OPTION = 1<<6; MC_COMMAND = 1<<7 # define the list of modifiers, to be used in complex event types. -if macosxSupport.runningAsOSXApp(): +if sys.platform == "darwin": _modifiers = (("Shift",), ("Control",), ("Option",), ("Command",)) _modifier_masks = (MC_SHIFT, MC_CONTROL, MC_OPTION, MC_COMMAND) else: diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py index e8890d1..c23b62a 100755 --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -844,7 +844,7 @@ class PyShell(OutputWindow): ("help", "_Help"), ] - if macosxSupport.runningAsOSXApp(): + if sys.platform == "darwin": menu_specs[-2] = ("windows", "_Window") @@ -1560,7 +1560,7 @@ def main(): shell = flist.open_shell() if not shell: return # couldn't open shell - if macosxSupport.runningAsOSXApp() and flist.dict: + if macosxSupport.isAquaTk() and flist.dict: # On OSX: when the user has double-clicked on a file that causes # IDLE to be launched the shell window will open just in front of # the file she wants to see. Lower the interpreter window when diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py index 6bfe128..b783637 100644 --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -53,7 +53,7 @@ class ScriptBinding: self.flist = self.editwin.flist self.root = self.editwin.root - if macosxSupport.runningAsOSXApp(): + if macosxSupport.isCocoaTk(): self.editwin.text_frame.bind('<<run-module-event-2>>', self._run_module_event) def check_module_event(self, event): @@ -114,7 +114,7 @@ class ScriptBinding: shell.set_warning_stream(saved_stream) def run_module_event(self, event): - if macosxSupport.runningAsOSXApp(): + if macosxSupport.isCocoaTk(): # Tk-Cocoa in MacOSX is broken until at least # Tk 8.5.9, and without this rather # crude workaround IDLE would hang when a user diff --git a/Lib/idlelib/ZoomHeight.py b/Lib/idlelib/ZoomHeight.py index e8d1710..a5d679e 100644 --- a/Lib/idlelib/ZoomHeight.py +++ b/Lib/idlelib/ZoomHeight.py @@ -32,7 +32,7 @@ def zoom_height(top): newy = 0 newheight = newheight - 72 - elif macosxSupport.runningAsOSXApp(): + elif macosxSupport.isAquaTk(): # The '88' below is a magic number that avoids placing the bottom # of the window below the panel on my machine. I don't know how # to calculate the correct value for this with tkinter. diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py index efe5c43..fefe42b 100644 --- a/Lib/idlelib/configDialog.py +++ b/Lib/idlelib/configDialog.py @@ -74,7 +74,7 @@ class ConfigDialog(Toplevel): frameActionButtons = Frame(self,pady=2) #action buttons - if macosxSupport.runningAsOSXApp(): + if macosxSupport.isAquaTk(): # Surpress the padx and pady arguments when # running as IDLE.app, otherwise the text # on these buttons will not be readable. diff --git a/Lib/idlelib/configHandler.py b/Lib/idlelib/configHandler.py index ea2010e..8608f7c 100644 --- a/Lib/idlelib/configHandler.py +++ b/Lib/idlelib/configHandler.py @@ -20,7 +20,6 @@ configuration problem notification and resolution. import os import sys -from idlelib import macosxSupport from configparser import ConfigParser, NoOptionError, NoSectionError class InvalidConfigType(Exception): pass @@ -527,10 +526,13 @@ class IdleConf: def GetCurrentKeySet(self): result = self.GetKeySet(self.CurrentKeys()) - if macosxSupport.runningAsOSXApp(): - # We're using AquaTk, replace all keybingings that use the - # Alt key by ones that use the Option key because the former - # don't work reliably. + if sys.platform == "darwin": + # OS X Tk variants do not support the "Alt" keyboard modifier. + # So replace all keybingings that use "Alt" with ones that + # use the "Option" keyboard modifier. + # TO DO: the "Option" modifier does not work properly for + # Cocoa Tk and XQuartz Tk so we should not use it + # in default OS X KeySets. for k, v in result.items(): v2 = [ x.replace('<Alt-', '<Option-') for x in v ] if v != v2: diff --git a/Lib/idlelib/keybindingDialog.py b/Lib/idlelib/keybindingDialog.py index 0f0da8c..db88cb4 100644 --- a/Lib/idlelib/keybindingDialog.py +++ b/Lib/idlelib/keybindingDialog.py @@ -4,7 +4,7 @@ Dialog for building Tkinter accelerator key bindings from tkinter import * import tkinter.messagebox as tkMessageBox import string -from idlelib import macosxSupport +import sys class GetKeysDialog(Toplevel): def __init__(self,parent,title,action,currentKeySequences): @@ -133,8 +133,7 @@ class GetKeysDialog(Toplevel): order is also important: key binding equality depends on it, so config-keys.def must use the same ordering. """ - import sys - if macosxSupport.runningAsOSXApp(): + if sys.platform == "darwin": self.modifiers = ['Shift', 'Control', 'Option', 'Command'] else: self.modifiers = ['Control', 'Alt', 'Shift'] diff --git a/Lib/idlelib/macosxSupport.py b/Lib/idlelib/macosxSupport.py index 67069fa..b6488f8 100644 --- a/Lib/idlelib/macosxSupport.py +++ b/Lib/idlelib/macosxSupport.py @@ -1,48 +1,70 @@ """ -A number of function that enhance IDLE on MacOSX when it used as a normal -GUI application (as opposed to an X11 application). +A number of functions that enhance IDLE on Mac OSX. """ import sys import tkinter from os import path +import warnings +def runningAsOSXApp(): + warnings.warn("runningAsOSXApp() is deprecated, use isAquaTk()", + DeprecationWarning, stacklevel=2) + return isAquaTk() -_appbundle = None +def isCarbonAquaTk(root): + warnings.warn("isCarbonAquaTk(root) is deprecated, use isCarbonTk()", + DeprecationWarning, stacklevel=2) + return isCarbonTk() -def runningAsOSXApp(): +_tk_type = None + +def _initializeTkVariantTests(root): + """ + Initializes OS X Tk variant values for + isAquaTk(), isCarbonTk(), isCocoaTk(), and isXQuartz(). """ - Returns True if Python is running from within an app on OSX. - If so, the various OS X customizations will be triggered later (menu - fixup, et al). (Originally, this test was supposed to condition - behavior on whether IDLE was running under Aqua Tk rather than - under X11 Tk but that does not work since a framework build - could be linked with X11. For several releases, this test actually - differentiates between whether IDLE is running from a framework or - not. As a future enhancement, it should be considered whether there - should be a difference based on framework and any needed X11 adaptions - should be made dependent on a new function that actually tests for X11.) - """ - global _appbundle - if _appbundle is None: - _appbundle = sys.platform == 'darwin' - if _appbundle: - import sysconfig - _appbundle = bool(sysconfig.get_config_var('PYTHONFRAMEWORK')) - return _appbundle - -_carbonaquatk = None + global _tk_type + if sys.platform == 'darwin': + 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" + else: + _tk_type = "other" -def isCarbonAquaTk(root): +def isAquaTk(): + """ + Returns True if IDLE is using a native OS X Tk (Cocoa or Carbon). + """ + assert _tk_type is not None + 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). """ - global _carbonaquatk - if _carbonaquatk is None: - _carbonaquatk = (runningAsOSXApp() and - 'aqua' in root.tk.call('tk', 'windowingsystem') and - 'AppKit' not in root.tk.call('winfo', 'server', '.')) - return _carbonaquatk + assert _tk_type is not None + return _tk_type == "carbon" + +def isCocoaTk(): + """ + Returns True if IDLE is using a Cocoa Aqua Tk. + """ + assert _tk_type is not None + return _tk_type == "cocoa" + +def isXQuartz(): + """ + Returns True if IDLE is using an OS X X11 Tk. + """ + assert _tk_type is not None + return _tk_type == "xquartz" def tkVersionWarning(root): """ @@ -53,8 +75,7 @@ def tkVersionWarning(root): can still crash unexpectedly. """ - if (runningAsOSXApp() and - ('AppKit' in root.tk.call('winfo', 'server', '.')) ): + if isCocoaTk(): patchlevel = root.tk.call('info', 'patchlevel') if patchlevel not in ('8.5.7', '8.5.9'): return False @@ -88,8 +109,8 @@ def hideTkConsole(root): def overrideRootMenu(root, flist): """ - Replace the Tk root menu by something that's more appropriate for - IDLE. + Replace the Tk root menu by something that is more appropriate for + IDLE with an Aqua Tk. """ # The menu that is attached to the Tk root (".") is also used by AquaTk for # all windows that don't specify a menu of their own. The default menubar @@ -108,6 +129,22 @@ def overrideRootMenu(root, flist): from idlelib import WindowList from idlelib.MultiCall import MultiCallCreator + closeItem = Bindings.menudefs[0][1][-2] + + # Remove the last 3 items of the file menu: a separator, close window and + # quit. Close window will be reinserted just above the save item, where + # it should be according to the HIG. Quit is in the application menu. + del Bindings.menudefs[0][1][-3:] + Bindings.menudefs[0][1].insert(6, closeItem) + + # Remove the 'About' entry from the help menu, it is in the application + # menu + del Bindings.menudefs[-1][1][0:2] + + # Remove the 'Configure' entry from the options menu, it is in the + # application menu as 'Preferences' + del Bindings.menudefs[-2][1][0:2] + menubar = Menu(root) root.configure(menu=menubar) menudict = {} @@ -156,7 +193,7 @@ def overrideRootMenu(root, flist): # right thing for now. root.createcommand('exit', flist.close_all_callback) - if isCarbonAquaTk(root): + if isCarbonTk(): # for Carbon AquaTk, replace the default Tk apple menu menudict['application'] = menu = Menu(menubar, name='apple') menubar.add_cascade(label='IDLE', menu=menu) @@ -171,8 +208,7 @@ def overrideRootMenu(root, flist): Bindings.menudefs[0][1].append( ('_Preferences....', '<<open-config-dialog>>'), ) - else: - # assume Cocoa AquaTk + if isCocoaTk(): # replace default About dialog with About IDLE one root.createcommand('tkAboutDialog', about_dialog) # replace default "Help" item in Help menu @@ -182,10 +218,22 @@ def overrideRootMenu(root, flist): def setupApp(root, flist): """ - Perform setup for the OSX application bundle. + 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 not runningAsOSXApp(): return - - hideTkConsole(root) - overrideRootMenu(root, flist) - addOpenEventSupport(root, flist) + _initializeTkVariantTests(root) + if isAquaTk(): + hideTkConsole(root) + overrideRootMenu(root, flist) + addOpenEventSupport(root, flist) |