Commit 57847df4 authored by Ned Deily's avatar Ned Deily

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

non-framework builds and for all variants of Tk.
parent b693e9fc
......@@ -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
......@@ -323,7 +323,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.
......
......@@ -138,8 +138,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.prefix,
'Resources/English.lproj/Documentation/index.html')
dochome = os.path.normpath(dochome)
......@@ -193,7 +193,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,
......@@ -440,7 +440,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)
......@@ -467,7 +467,7 @@ class EditorWindow(object):
("help", "_Help"),
]
if macosxSupport.runningAsOSXApp():
if sys.platform == "darwin":
menu_specs[-2] = ("windows", "_Window")
......@@ -479,7 +479,7 @@ class EditorWindow(object):
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 @@ 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>>"}):
......
......@@ -33,7 +33,6 @@ import sys
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_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:
......
......@@ -866,7 +866,7 @@ class PyShell(OutputWindow):
("help", "_Help"),
]
if macosxSupport.runningAsOSXApp():
if sys.platform == "darwin":
menu_specs[-2] = ("windows", "_Window")
......@@ -1566,7 +1566,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
......
......@@ -54,7 +54,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):
......@@ -168,7 +168,7 @@ class ScriptBinding:
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
......
......@@ -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.
......
......@@ -71,7 +71,7 @@ class ConfigDialog(Toplevel):
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={}
......
......@@ -20,7 +20,6 @@ configuration problem notification and resolution.
import os
import sys
import string
from idlelib import macosxSupport
from ConfigParser import ConfigParser, NoOptionError, NoSectionError
class InvalidConfigType(Exception): pass
......@@ -526,10 +525,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:
......
......@@ -4,6 +4,7 @@ Dialog for building Tkinter accelerator key bindings
from Tkinter import *
import tkMessageBox
import string
import sys
class GetKeysDialog(Toplevel):
def __init__(self,parent,title,action,currentKeySequences):
......@@ -132,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.
"""
from idlelib import macosxSupport
if macosxSupport.runningAsOSXApp():
if sys.platform == "darwin":
self.modifiers = ['Shift', 'Control', 'Option', 'Command']
else:
self.modifiers = ['Control', 'Alt', 'Shift']
......
"""
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():
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):
"""
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.
Initializes OS X Tk variant values for
isAquaTk(), isCarbonTk(), isCocoaTk(), and isXQuartz().
"""
global _appbundle
if _appbundle is None:
_appbundle = (sys.platform == 'darwin' and '.app' in sys.executable)
return _appbundle
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"
_carbonaquatk = None
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 isCarbonAquaTk(root):
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 @@ 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
......@@ -78,8 +111,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
......@@ -98,6 +131,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 = {}
......@@ -140,7 +189,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)
......@@ -155,8 +204,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
......@@ -166,10 +214,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)
......@@ -279,6 +279,9 @@ IDLE
- 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
-----
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment