Move menu/key binding code from Bindings.py to EditorWindow.py,
with changed APIs -- it makes much more sense there.
Also add a new feature: if the first character of a menu label is
a '!', it gets a checkbox.  Checkboxes are bound to Boolean Tcl variables
that can be accessed through the new getvar/setvar/getrawvar API;
the variable is named after the event to which the menu is bound.
diff --git a/Tools/idle/Bindings.py b/Tools/idle/Bindings.py
index e365032..e0a2570 100644
--- a/Tools/idle/Bindings.py
+++ b/Tools/idle/Bindings.py
@@ -7,7 +7,6 @@
 
 import sys
 import string
-import re
 from keydefs import *
 
 menudefs = [
@@ -42,9 +41,9 @@
   ]),
  ('debug', [
    ('_Go to file/line', '<<goto-file-line>>'),
-   ('_Open stack viewer', '<<open-stack-viewer>>'),
-   ('_Debugger toggle', '<<toggle-debugger>>'),
-   ('_JIT Stack viewer toggle', '<<toggle-jit-stack-viewer>>' ),
+   ('_Stack viewer', '<<open-stack-viewer>>'),
+   ('!_Debugger', '<<toggle-debugger>>'),
+   ('!_Auto-open stack viewer', '<<toggle-jit-stack-viewer>>' ),
   ]),
  ('help', [
    ('_Help...', '<<help>>'),
@@ -53,62 +52,7 @@
   ]),
 ]
 
-def prepstr(s):
-    # Helper to extract the underscore from a string,
-    # e.g. prepstr("Co_py") returns (2, "Copy").
-    i = string.find(s, '_')
-    if i >= 0:
-        s = s[:i] + s[i+1:]
-    return i, s
-
-keynames = {
- 'bracketleft': '[',
- 'bracketright': ']',
- 'slash': '/',
-}
-
-def get_accelerator(keydefs, event):
-    keylist = keydefs.get(event)
-    if not keylist:
-        return ""
-    s = keylist[0]
-    s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s)
-    s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s)
-    s = re.sub("Key-", "", s)
-    s = re.sub("Control-", "Ctrl-", s)
-    s = re.sub("-", "+", s)
-    s = re.sub("><", " ", s)
-    s = re.sub("<", "", s)
-    s = re.sub(">", "", s)
-    return s
-
 if sys.platform == 'win32':
     default_keydefs = windows_keydefs
 else:
     default_keydefs = unix_keydefs
-
-def apply_bindings(text, keydefs=default_keydefs):
-    text.keydefs = keydefs
-    for event, keylist in keydefs.items():
-        if keylist:
-            apply(text.event_add, (event,) + tuple(keylist))
-
-def fill_menus(text, menudict, defs=menudefs, keydefs=default_keydefs):
-    # Fill the menus for the given text widget.  The menudict argument is
-    # a dictionary containing the menus, keyed by their lowercased name.
-    # Menus that are absent or None are ignored.
-    for mname, itemlist in defs:
-        menu = menudict.get(mname)
-        if not menu:
-            continue
-        for item in itemlist:
-            if not item:
-                menu.add_separator()
-            else:
-                label, event = item
-                underline, label = prepstr(label)
-                accelerator = get_accelerator(keydefs, event)
-                def command(text=text, event=event):
-                    text.event_generate(event)
-                menu.add_command(label=label, underline=underline,
-                                 command=command, accelerator=accelerator)
diff --git a/Tools/idle/EditorWindow.py b/Tools/idle/EditorWindow.py
index 96a56de..17f23ca 100644
--- a/Tools/idle/EditorWindow.py
+++ b/Tools/idle/EditorWindow.py
@@ -1,6 +1,7 @@
 import sys
 import os
 import string
+import re
 import imp
 from Tkinter import *
 import tkSimpleDialog
@@ -93,7 +94,7 @@
                                 background="white", wrap="none")
 
         self.createmenubar()
-        self.Bindings.apply_bindings(text)
+        self.apply_bindings()
 
         self.top.protocol("WM_DELETE_WINDOW", self.close)
         self.top.bind("<<close-window>>", self.close_event)
@@ -172,15 +173,19 @@
 
     def createmenubar(self):
         mbar = self.menubar
-        self.menudict = mdict = {}
+        self.menudict = menudict = {}
         for name, label in self.menu_specs:
-            underline, label = self.Bindings.prepstr(label)
-            mdict[name] = menu = Menu(mbar, name=name)
+            underline, label = prepstr(label)
+            menudict[name] = menu = Menu(mbar, name=name)
             mbar.add_cascade(label=label, menu=menu, underline=underline)
-        self.Bindings.fill_menus(self.text, mdict)
+        self.fill_menus()
 
     def postwindowsmenu(self):
         # Only called when Windows menu exists
+        # XXX Actually, this Just-In-Time updating interferes
+        # XXX badly with the tear-off feature.  It would be better
+        # XXX to update all Windows menus whenever the list of windows
+        # XXX changes.
         menu = self.menudict['windows']
         end = menu.index("end")
         if end is None:
@@ -477,7 +482,7 @@
             if hasattr(ins, kdname):
                 keydefs.update(getattr(ins, kdname))
         if keydefs:
-            self.Bindings.apply_bindings(self.text, keydefs)
+            self.apply_bindings(keydefs)
             for vevent in keydefs.keys():
                 methodname = string.replace(vevent, "-", "_")
                 while methodname[:1] == '<':
@@ -488,10 +493,104 @@
                 if hasattr(ins, methodname):
                     self.text.bind(vevent, getattr(ins, methodname))
         if hasattr(ins, "menudefs"):
-            self.Bindings.fill_menus(self.text, self. menudict,
-                                     ins.menudefs, keydefs)
+            self.fill_menus(ins.menudefs, keydefs)
         return ins
 
+    def apply_bindings(self, keydefs=None):
+        if keydefs is None:
+            keydefs = self.Bindings.default_keydefs
+        text = self.text
+        text.keydefs = keydefs
+        for event, keylist in keydefs.items():
+            if keylist:
+                apply(text.event_add, (event,) + tuple(keylist))
+
+    def fill_menus(self, defs=None, keydefs=None):
+        # Fill the menus.
+        # Menus that are absent or None in self.menudict are ignored.
+        if defs is None:
+            defs = self.Bindings.menudefs
+        if keydefs is None:
+            keydefs = self.Bindings.default_keydefs
+        menudict = self.menudict
+        text = self.text
+        for mname, itemlist in defs:
+            menu = menudict.get(mname)
+            if not menu:
+                continue
+            for item in itemlist:
+                if not item:
+                    menu.add_separator()
+                else:
+                    label, event = item
+                    checkbutton = (label[:1] == '!')
+                    if checkbutton:
+                        label = label[1:]
+                    underline, label = prepstr(label)
+                    accelerator = get_accelerator(keydefs, event)
+                    def command(text=text, event=event):
+                        text.event_generate(event)
+                    if checkbutton:
+                        var = self.getrawvar(event, BooleanVar)
+                        menu.add_checkbutton(label=label, underline=underline,
+                            command=command, accelerator=accelerator,
+                            variable=var)
+                    else:
+                        menu.add_command(label=label, underline=underline,
+                            command=command, accelerator=accelerator)
+    
+    def getvar(self, name):
+        var = self.getrawvar(name)
+        if var:
+            return var.get()
+    
+    def setvar(self, name, value, vartype=None):
+        var = self.getrawvar(name, vartype)
+        if var:
+            var.set(value)
+    
+    def getrawvar(self, name, vartype=None):
+        key = ".VARS."
+        vars = self.menudict.get(key)
+        if not vars and vartype:
+            self.menudict[key] = vars = {}
+        if vars is not None:
+            var = vars.get(name)
+            if not var and vartype:
+                vars[name] = var = vartype(self.text)
+            return var
+
+
+def prepstr(s):
+    # Helper to extract the underscore from a string,
+    # e.g. prepstr("Co_py") returns (2, "Copy").
+    i = string.find(s, '_')
+    if i >= 0:
+        s = s[:i] + s[i+1:]
+    return i, s
+
+
+keynames = {
+ 'bracketleft': '[',
+ 'bracketright': ']',
+ 'slash': '/',
+}
+
+def get_accelerator(keydefs, event):
+    keylist = keydefs.get(event)
+    if not keylist:
+        return ""
+    s = keylist[0]
+    s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s)
+    s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s)
+    s = re.sub("Key-", "", s)
+    s = re.sub("Control-", "Ctrl-", s)
+    s = re.sub("-", "+", s)
+    s = re.sub("><", " ", s)
+    s = re.sub("<", "", s)
+    s = re.sub(">", "", s)
+    return s
+
 
 def fixwordbreaks(root):
     # Make sure that Tk's double-click and next/previous word
diff --git a/Tools/idle/PyShell.py b/Tools/idle/PyShell.py
index f484fb8..115d96f 100644
--- a/Tools/idle/PyShell.py
+++ b/Tools/idle/PyShell.py
@@ -217,11 +217,11 @@
                     raise
                 else:
                     self.showtraceback()
-                    if self.tkconsole.jit_stack_view:
+                    if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
                         self.tkconsole.open_stack_viewer()
             except:
                 self.showtraceback()
-                if self.tkconsole.jit_stack_view:
+                if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
                     self.tkconsole.open_stack_viewer()
 
         finally:
@@ -289,17 +289,20 @@
             tkMessageBox.showerror("Don't debug now",
                 "You can only toggle the debugger when idle",
                 master=self.text)
+            self.set_debugger_indicator()
             return "break"
-        db = self.interp.getdebugger()
-        if db:
-            self.close_debugger()
         else:
-            self.open_debugger()
-
-    jit_stack_view = 0
-
+            db = self.interp.getdebugger()
+            if db:
+                self.close_debugger()
+            else:
+                self.open_debugger()
+    
+    def set_debugger_indicator(self):
+        db = self.interp.getdebugger()
+        self.setvar("<<toggle-debugger>>", not not db)
     def toggle_jit_stack_viewer( self, event=None):
-        self.jit_stack_view = not self.jit_stack_view
+        pass # All we need is the variable
 
     def close_debugger(self):
         db = self.interp.getdebugger()
@@ -310,12 +313,14 @@
             self.console.write("[DEBUG OFF]\n")
             sys.ps1 = ">>> "
             self.showprompt()
+        self.set_debugger_indicator()
 
     def open_debugger(self):
         import Debugger
         self.interp.setdebugger(Debugger.Debugger(self))
         sys.ps1 = "[DEBUG ON]\n>>> "
         self.showprompt()
+        self.set_debugger_indicator()
 
     def beginexecuting(self):
         # Helper for ModifiedInterpreter
@@ -335,8 +340,8 @@
         if self.executing:
             # XXX Need to ask a question here
             if not tkMessageBox.askokcancel(
-                "Cancel?",
-                "The program is still running; do you want to cancel it?",
+                "Kill?",
+                "The program is still running; do you want to kill it?",
                 default="ok",
                 master=self.text):
                 return "cancel"