Issue #17654: Ensure IDLE menus are customized properly on OS X for

non-framework builds and for all variants of Tk.
This commit is contained in:
Ned Deily 2014-03-27 20:49:14 -07:00
parent e7d532fbc9
commit b7601676b0
12 changed files with 130 additions and 94 deletions

View file

@ -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
_appbundle = None
import warnings
def runningAsOSXApp():
"""
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
warnings.warn("runningAsOSXApp() is deprecated, use isAquaTk()",
DeprecationWarning, stacklevel=2)
return isAquaTk()
def isCarbonAquaTk(root):
warnings.warn("isCarbonAquaTk(root) is deprecated, use isCarbonTk()",
DeprecationWarning, stacklevel=2)
return isCarbonTk()
_tk_type = None
def _initializeTkVariantTests(root):
"""
Initializes OS X Tk variant values for
isAquaTk(), isCarbonTk(), isCocoaTk(), and isXQuartz().
"""
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 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.
"""
if not runningAsOSXApp(): return
Perform initial OS X customizations if needed.
Called from PyShell.main() after initial calls to Tk()
hideTkConsole(root)
overrideRootMenu(root, flist)
addOpenEventSupport(root, flist)
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.
"""
_initializeTkVariantTests(root)
if isAquaTk():
hideTkConsole(root)
overrideRootMenu(root, flist)
addOpenEventSupport(root, flist)