[Python-checkins] cpython (2.7): Issue #17654: Ensure IDLE menus are customized properly on OS X for

ned.deily python-checkins at python.org
Fri Mar 28 04:52:04 CET 2014


http://hg.python.org/cpython/rev/f551740c26b6
changeset:   90005:f551740c26b6
branch:      2.7
parent:      90002:74faca1ac59c
user:        Ned Deily <nad at acm.org>
date:        Thu Mar 27 20:47:04 2014 -0700
summary:
  Issue #17654: Ensure IDLE menus are customized properly on OS X for
non-framework builds and for all variants of Tk.

files:
  Lib/idlelib/Bindings.py         |   32 +---
  Lib/idlelib/Debugger.py         |    2 +-
  Lib/idlelib/EditorWindow.py     |   14 +-
  Lib/idlelib/MultiCall.py        |    3 +-
  Lib/idlelib/PyShell.py          |    4 +-
  Lib/idlelib/ScriptBinding.py    |    4 +-
  Lib/idlelib/ZoomHeight.py       |    2 +-
  Lib/idlelib/configDialog.py     |    2 +-
  Lib/idlelib/configHandler.py    |   12 +-
  Lib/idlelib/keybindingDialog.py |    4 +-
  Lib/idlelib/macosxSupport.py    |  126 ++++++++++++++-----
  Misc/NEWS                       |    3 +
  12 files changed, 127 insertions(+), 81 deletions(-)


diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py
--- a/Lib/idlelib/Bindings.py
+++ b/Lib/idlelib/Bindings.py
@@ -8,9 +8,14 @@
 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 @@
    ]),
 ]
 
-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
--- a/Lib/idlelib/Debugger.py
+++ b/Lib/idlelib/Debugger.py
@@ -323,7 +323,7 @@
 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
--- a/Lib/idlelib/EditorWindow.py
+++ b/Lib/idlelib/EditorWindow.py
@@ -138,8 +138,8 @@
                                        '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.prefix,
                         'Resources/English.lproj/Documentation/index.html')
             dochome = os.path.normpath(dochome)
@@ -193,7 +193,7 @@
 
         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,
@@ -440,7 +440,7 @@
 
     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)
@@ -467,7 +467,7 @@
         ("help", "_Help"),
     ]
 
-    if macosxSupport.runningAsOSXApp():
+    if sys.platform == "darwin":
         menu_specs[-2] = ("windows", "_Window")
 
 
@@ -479,7 +479,7 @@
             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)
@@ -1682,7 +1682,7 @@
     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
--- a/Lib/idlelib/MultiCall.py
+++ b/Lib/idlelib/MultiCall.py
@@ -33,7 +33,6 @@
 import string
 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;
@@ -46,7 +45,7 @@
 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
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -866,7 +866,7 @@
         ("help", "_Help"),
     ]
 
-    if macosxSupport.runningAsOSXApp():
+    if sys.platform == "darwin":
         menu_specs[-2] = ("windows", "_Window")
 
 
@@ -1566,7 +1566,7 @@
         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
--- a/Lib/idlelib/ScriptBinding.py
+++ b/Lib/idlelib/ScriptBinding.py
@@ -54,7 +54,7 @@
         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):
@@ -168,7 +168,7 @@
         interp.runcode(code)
         return 'break'
 
-    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
--- a/Lib/idlelib/ZoomHeight.py
+++ b/Lib/idlelib/ZoomHeight.py
@@ -32,7 +32,7 @@
         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
--- a/Lib/idlelib/configDialog.py
+++ b/Lib/idlelib/configDialog.py
@@ -71,7 +71,7 @@
                 page_names=['Fonts/Tabs','Highlighting','Keys','General'])
         frameActionButtons = Frame(self,pady=2)
         #action buttons
-        if macosxSupport.runningAsOSXApp():
+        if macosxSupport.isAquaTk():
             # Changing the default padding on OSX results in unreadable
             # text in the buttons
             paddingArgs={}
diff --git a/Lib/idlelib/configHandler.py b/Lib/idlelib/configHandler.py
--- a/Lib/idlelib/configHandler.py
+++ b/Lib/idlelib/configHandler.py
@@ -20,7 +20,6 @@
 import os
 import sys
 import string
-from idlelib import macosxSupport
 from ConfigParser import ConfigParser, NoOptionError, NoSectionError
 
 class InvalidConfigType(Exception): pass
@@ -526,10 +525,13 @@
     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
--- a/Lib/idlelib/keybindingDialog.py
+++ b/Lib/idlelib/keybindingDialog.py
@@ -4,6 +4,7 @@
 from Tkinter import *
 import tkMessageBox
 import string
+import sys
 
 class GetKeysDialog(Toplevel):
     def __init__(self,parent,title,action,currentKeySequences):
@@ -132,8 +133,7 @@
         order is also important: key binding equality depends on it, so
         config-keys.def must use the same ordering.
         """
-        from idlelib import macosxSupport
-        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
--- a/Lib/idlelib/macosxSupport.py
+++ b/Lib/idlelib/macosxSupport.py
@@ -1,38 +1,72 @@
 """
-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, assume that Python was built with Aqua Tcl/Tk rather than
-    X11 Tcl/Tk.
-    """
-    global _appbundle
-    if _appbundle is None:
-        _appbundle = (sys.platform == 'darwin' and '.app' in sys.executable)
-    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):
     """
@@ -43,8 +77,7 @@
         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
@@ -78,8 +111,8 @@
 
 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
@@ -98,6 +131,22 @@
     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 = {}
@@ -140,7 +189,7 @@
         # 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)
@@ -155,8 +204,7 @@
             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
@@ -166,10 +214,22 @@
 
 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)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -279,6 +279,9 @@
 - Issue #18270: Prevent possible IDLE AttributeError on OS X when no initial
   shell window is present.
 
+- Issue #17654: Ensure IDLE menus are customized properly on OS X for
+  non-framework builds and for all variants of Tk.
+
 Tests
 -----
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list